forked from Fascinated/Bat
Compare commits
129 Commits
087ab99b44
...
master
Author | SHA1 | Date | |
---|---|---|---|
34102e9b22 | |||
7083bebef1 | |||
c81835cb2d | |||
80e7afedea | |||
285a0ca00a | |||
f07e30d843 | |||
bd9ac1e138 | |||
3878d3029b | |||
831bc934b4 | |||
938005f6d9 | |||
5959b814a7 | |||
5f75302f3a | |||
a7a7bc784b | |||
2b4980fb10 | |||
655662c6f8 | |||
642185f8c5 | |||
c2e447f416 | |||
271a1cf88d | |||
11e7ca4aa6 | |||
f6834db9cb | |||
90aaf5422f | |||
e4183b4882 | |||
f62a022ed5 | |||
50b8b4b2c1 | |||
920755eae0 | |||
2255b02a60 | |||
f30697d1a6 | |||
83250d2c08 | |||
d7916ad24a | |||
295d673d06 | |||
da06a01097 | |||
6202aa6691 | |||
82a87c79b2 | |||
e795d542b9 | |||
162d7af46b | |||
821190a144 | |||
cb35182c6a | |||
ac499898e3 | |||
35596b720b | |||
048d2856f9 | |||
5f654f9ca6 | |||
4540bdef99 | |||
eda4eb5973 | |||
68a9a6dc48 | |||
ff23ea1d6c | |||
982c038b07 | |||
52223b5233 | |||
45755503a7 | |||
194a5d8119 | |||
120afee73b | |||
8b7340715c | |||
38bde93d16 | |||
a3ffaf1ab9 | |||
86c147f359 | |||
deb93e442c | |||
6eca92b4cf | |||
3f93df131d | |||
1028dca15a | |||
e03aef0ad5 | |||
8ce3a5d25c | |||
0b8caf3e25 | |||
317eaaec8a | |||
4f975ab07a | |||
1a69bce9dd | |||
37c69597be | |||
3146ed7d6d | |||
69281d113c | |||
c6289d1c8e | |||
3082265ec6 | |||
a057853cbd | |||
8b451c6ee5 | |||
727a4c9a6f | |||
4bf099d25e | |||
20c5f71cd4 | |||
a6e490dbe5 | |||
87bf0b9f67 | |||
419bdf1fea | |||
f2b2dbc794 | |||
8361f3c784 | |||
52349a17c3 | |||
c1f9bfec6a | |||
be7f8a9057 | |||
c93e112ebf | |||
7485bd2ec8 | |||
ed83175a39 | |||
a001f2dd4c | |||
b1785ce373 | |||
b1f5db9b2d | |||
d372c41c98 | |||
f566c3bcb5 | |||
6403c57db5 | |||
22d4558d84 | |||
ea546f02ca | |||
5b1ddb145f | |||
5ce5ef6898 | |||
729e0b482b | |||
5aa56c2955 | |||
ee6456e4d8 | |||
93350f1506 | |||
702aead53a | |||
b7f2b6a3d7 | |||
b66114503c | |||
50391e5344 | |||
91ecc9882c | |||
06a2584e63 | |||
29affe2f12 | |||
86c7afac42 | |||
b0949d17e6 | |||
df44ae90b9 | |||
4821e2a4fa | |||
4cb34fbb9a | |||
d824f957fe | |||
d2d898a5b8 | |||
320eab34a3 | |||
433dfb4693 | |||
71158fd477 | |||
eb8408eb8f | |||
20905a7962 | |||
827e1bed4f | |||
f4d3752de7 | |||
f737b7d571 | |||
dc18c9fe7a | |||
107ec43149 | |||
e17c8a08c2 | |||
fa205d7ff2 | |||
290c25ee43 | |||
4fc3431213 | |||
ac7c94031a | |||
f3e5116708 |
49
pom.xml
49
pom.xml
@ -85,6 +85,45 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.sentry</groupId>
|
||||
<artifactId>sentry-spring-boot-starter-jakarta</artifactId>
|
||||
<version>7.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mongock</groupId>
|
||||
<artifactId>mongock-bom</artifactId>
|
||||
<version>5.2.4</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mongock</groupId>
|
||||
<artifactId>mongock-springboot-v3</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.mongock</groupId>
|
||||
<artifactId>mongodb-springdata-v4-driver</artifactId>
|
||||
<version>5.2.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis for caching -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Libraries -->
|
||||
<dependency>
|
||||
@ -120,6 +159,16 @@
|
||||
<artifactId>spotify-web-api-java</artifactId>
|
||||
<version>8.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>3.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>uk.co.conoregan</groupId>
|
||||
<artifactId>themoviedbapi</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Dependencies -->
|
||||
<dependency>
|
||||
|
34
privacy-policy.txt
Normal file
34
privacy-policy.txt
Normal file
@ -0,0 +1,34 @@
|
||||
Privacy Policy
|
||||
|
||||
1. Introduction
|
||||
|
||||
This Privacy Policy explains how Bat ("we", "us", "our") collects, uses, and protects your information when you use our Discord bot (the "Service").
|
||||
2. Information We Collect
|
||||
|
||||
User Data: When you interact with our bot, we may collect your Discord user ID, server ID, and any messages or commands you send to the bot.
|
||||
Usage Data: We may collect data on how you interact with the bot, such as commands used and features accessed.
|
||||
|
||||
3. How We Use Your Information
|
||||
|
||||
Service Operation: To provide, maintain, and improve the Service.
|
||||
Communication: To respond to your inquiries and provide customer support.
|
||||
Analytics: To analyze usage trends and improve the Service.
|
||||
|
||||
4. Data Sharing
|
||||
|
||||
We do not sell or rent your information to third parties. We may share your information with third-party service providers who assist us in operating the Service, under confidentiality agreements.
|
||||
5. Data Security
|
||||
|
||||
We implement appropriate technical and organizational measures to protect your information from unauthorized access, loss, or misuse.
|
||||
6. Data Retention
|
||||
|
||||
We retain your information for as long as necessary to fulfill the purposes outlined in this Privacy Policy, unless a longer retention period is required or permitted by law.
|
||||
7. Your Rights
|
||||
|
||||
You have the right to access, correct, or delete your personal information. To exercise these rights, please contact us at bat@fascinated.cc.
|
||||
8. Changes to This Privacy Policy
|
||||
|
||||
We may update this Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on our https://discord.gg/yjj2U3ctEG.
|
||||
9. Contact Us
|
||||
|
||||
If you have any questions about this Privacy Policy, please contact us at bat@fascinated.cc.
|
6
renovate.json
Normal file
6
renovate.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"local>Fascinated/renovate-config"
|
||||
]
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
package cc.fascinated.bat;
|
||||
|
||||
import cc.fascinated.bat.config.Config;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.service.EventService;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.mongock.runner.springboot.EnableMongock;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
@ -15,7 +20,8 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.util.Objects;
|
||||
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackages = "cc.fascinated.bat")
|
||||
@EnableMongock
|
||||
@Log4j2(topic = "Bat")
|
||||
public class BatApplication {
|
||||
public static Gson GSON = new GsonBuilder().create();
|
||||
@ -35,5 +41,14 @@ public class BatApplication {
|
||||
|
||||
// Start the app
|
||||
SpringApplication.run(BatApplication.class, args);
|
||||
log.info("APP IS RUNNING IN %s MODE!!!!!!!!!".formatted(Config.isProduction() ? "PRODUCTION" : "DEVELOPMENT"));
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void onShutdown() {
|
||||
log.info("Shutting down...");
|
||||
for (EventListener listener : EventService.LISTENERS) {
|
||||
listener.onSpringShutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ package cc.fascinated.bat;
|
||||
public class Consts {
|
||||
public static final String INVITE_URL = "https://discord.com/oauth2/authorize?client_id=1254161119975833652&permissions=8&integration_type=0&scope=bot+applications.commands";
|
||||
public static final String SUPPORT_INVITE_URL = "https://discord.gg/invite/yjj2U3ctEG";
|
||||
public static String BOT_OWNER = "474221560031608833";
|
||||
public static String ADMIN_GUILD = "1203163422498361404";
|
||||
public static final String BOT_OWNER = "474221560031608833";
|
||||
public static final String PRIVACY_POLICY_URL = "https://git.fascinated.cc/Fascinated/Bat/raw/branch/master/privacy-policy.txt";
|
||||
public static final String TERMS_OF_SERVICE_URL = "https://git.fascinated.cc/Fascinated/Bat/raw/branch/master/terms-of-service.txt";
|
||||
}
|
||||
|
45
src/main/java/cc/fascinated/bat/Emojis.java
Normal file
45
src/main/java/cc/fascinated/bat/Emojis.java
Normal file
@ -0,0 +1,45 @@
|
||||
package cc.fascinated.bat;
|
||||
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.emoji.Emoji;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Log4j2
|
||||
public class Emojis {
|
||||
public static final Emoji SPOTIFY_EMOJI;
|
||||
public static final Emoji CHECK_MARK_EMOJI;
|
||||
public static final Emoji CROSS_MARK_EMOJI;
|
||||
public static final Emoji SAD_FACE_EMOJI;
|
||||
public static final Emoji PAUSE_EMOJI;
|
||||
public static final Emoji PLAY_EMOJI;
|
||||
public static final Emoji SKIP_EMOJI;
|
||||
|
||||
/**
|
||||
* Presence Status Emojis
|
||||
*/
|
||||
public static final Emoji ONLINE_EMOJI;
|
||||
public static final Emoji IDLE_EMOJI;
|
||||
public static final Emoji DND_EMOJI;
|
||||
public static final Emoji OFFLINE_EMOJI;
|
||||
|
||||
static {
|
||||
log.info("Loading emojis...");
|
||||
JDA jda = DiscordService.JDA;
|
||||
SPOTIFY_EMOJI = jda.getEmojiById("1256629771975266479");
|
||||
CHECK_MARK_EMOJI = jda.getEmojiById("1256633734065557676");
|
||||
CROSS_MARK_EMOJI = jda.getEmojiById("1256634487429922897");
|
||||
SAD_FACE_EMOJI = jda.getEmojiById("1256636078258131055");
|
||||
ONLINE_EMOJI = jda.getEmojiById("1256662465668710430");
|
||||
IDLE_EMOJI = jda.getEmojiById("1256662632203685991");
|
||||
DND_EMOJI = jda.getEmojiById("1256662572933845032");
|
||||
OFFLINE_EMOJI = jda.getEmojiById("1256662679402053662");
|
||||
PAUSE_EMOJI = Emoji.fromUnicode("⏸");
|
||||
PLAY_EMOJI = Emoji.fromUnicode("▶");
|
||||
SKIP_EMOJI = Emoji.fromUnicode("⏭");
|
||||
log.info("Loaded emojis!");
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cc.fascinated.bat.command;
|
||||
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
@ -38,6 +39,11 @@ public abstract class BatCommand implements BatCommandExecutor {
|
||||
*/
|
||||
private Category category;
|
||||
|
||||
/**
|
||||
* The feature that the command belongs to
|
||||
*/
|
||||
private Feature feature;
|
||||
|
||||
/**
|
||||
* Whether the command can only be used by the bot owner
|
||||
*/
|
||||
|
@ -12,20 +12,20 @@ import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
*/
|
||||
public interface BatCommandExecutor {
|
||||
/**
|
||||
* Executes the command using a slash command interaction.
|
||||
* Executes the command using a slash command event.
|
||||
*
|
||||
* @param guild the bat guild the command was executed in (null if the command was executed in a DM)
|
||||
* @param user the bat user that executed the command
|
||||
* @param channel the channel the command was executed in
|
||||
* @param member the member that executed the command
|
||||
* @param interaction the slash command interaction
|
||||
* @param event the slash command event
|
||||
*/
|
||||
default void execute(
|
||||
BatGuild guild,
|
||||
@NonNull BatUser user,
|
||||
@NonNull MessageChannel channel,
|
||||
Member member,
|
||||
@NonNull SlashCommandInteraction interaction
|
||||
@NonNull SlashCommandInteraction event
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,12 @@ public enum Category {
|
||||
GENERAL(Emoji.fromUnicode("U+2699"), "General", false),
|
||||
FUN(Emoji.fromFormatted("U+1F973"), "Fun", false),
|
||||
SERVER(Emoji.fromFormatted("U+1F5A5"), "Server", false),
|
||||
MODERATION(Emoji.fromFormatted("U+1F6E0"), "Moderation", false),
|
||||
UTILITY(Emoji.fromFormatted("U+1F6E0"), "Utility", false),
|
||||
MUSIC(Emoji.fromFormatted("U+1F3B5"), "Music", false),
|
||||
MOVIES_TV(Emoji.fromFormatted("U+1F3A5"), "Movies & TV", false),
|
||||
MESSAGES(Emoji.fromFormatted("U+1F4A3"), "Snipe", false),
|
||||
LOGS(Emoji.fromFormatted("U+1F4D1"), "Logs", false),
|
||||
BEAT_SABER(Emoji.fromFormatted("U+1FA84"), "Beat Saber", false),
|
||||
BOT_ADMIN(null, null, true);
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
package cc.fascinated.bat.command.impl.server;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "membercount", description = "View the member count of the server!")
|
||||
public class MemberCountCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
EmbedBuilder embed = EmbedUtils.genericEmbed().setAuthor("Member Count");
|
||||
Guild discordGuild = guild.getDiscordGuild();
|
||||
embed.setDescription(discordGuild.getName() + " has a total of " + discordGuild.getMembers().size() + " members.");
|
||||
interaction.replyEmbeds(embed.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class EmbedDescriptionBuilder {
|
||||
/**
|
||||
* Where the description is stored
|
||||
*/
|
||||
private final StringBuilder builder = new StringBuilder();
|
||||
|
||||
public EmbedDescriptionBuilder(String title) {
|
||||
builder.append("**").append(title).append("**").append("\n");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public EmbedDescriptionBuilder appendLine(@NonNull String line, boolean arrow) {
|
||||
builder.append(arrow ? "➜ " : "").append(line).append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public EmbedDescriptionBuilder appendSubtitle(@NonNull String title) {
|
||||
builder.append("**").append(title).append("**").append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public EmbedDescriptionBuilder emptyLine() {
|
||||
builder.append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String build() {
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
21
src/main/java/cc/fascinated/bat/common/EnumUtils.java
Normal file
21
src/main/java/cc/fascinated/bat/common/EnumUtils.java
Normal file
@ -0,0 +1,21 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class EnumUtils {
|
||||
/**
|
||||
* Gets the name of the enum
|
||||
*
|
||||
* @param e the enum
|
||||
* @return the name
|
||||
*/
|
||||
public static String getEnumName(Enum<?> e) {
|
||||
String[] split = e.name().split("_");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String s : split) {
|
||||
builder.append(s.substring(0, 1).toUpperCase()).append(s.substring(1).toLowerCase()).append(" ");
|
||||
}
|
||||
return builder.toString().trim();
|
||||
}
|
||||
}
|
83
src/main/java/cc/fascinated/bat/common/NumberFormatter.java
Normal file
83
src/main/java/cc/fascinated/bat/common/NumberFormatter.java
Normal file
@ -0,0 +1,83 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class NumberFormatter {
|
||||
/**
|
||||
* The suffixes for the numbers
|
||||
*/
|
||||
private static final String[] SUFFIXES = new String[] { "K", "M", "B", "T", "Q", "QT", "S", "SP", "O", "N", "D", "UD", "DD", "TD" };
|
||||
private static final DecimalFormat FORMAT = new DecimalFormat("###.##");
|
||||
|
||||
/**
|
||||
* Format the provided double
|
||||
*
|
||||
* @param input the value to format
|
||||
* @return the formatted double, in the format of xx.xx[suffix]
|
||||
*/
|
||||
public static String format(double input) {
|
||||
if (Double.isNaN(input)) {
|
||||
return "ERROR";
|
||||
}
|
||||
if (Double.isInfinite(input) || input == Double.MAX_VALUE) {
|
||||
return "∞";
|
||||
}
|
||||
if (1000 > input) {
|
||||
return FORMAT.format(input);
|
||||
}
|
||||
double power = (int) Math.log10(input);
|
||||
int index = (int) Math.floor(power / 3) - 1;
|
||||
double factor = input / Math.pow(10, 3 + index * 3);
|
||||
if (index >= SUFFIXES.length) {
|
||||
return "ERROR";
|
||||
}
|
||||
return FORMAT.format(factor) + SUFFIXES[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the provided double with commas
|
||||
*
|
||||
* @param input the value to format
|
||||
* @return the formatted double, in the format of xx,xxx,xxx
|
||||
*/
|
||||
public static String formatCommas(double input) {
|
||||
return String.format("%,.0f", input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a provided string into a double, for example 1M -> 1000000.00
|
||||
* Accepts decimal and negative values and is not case-sensitive
|
||||
*
|
||||
* @param input the string to convert
|
||||
* @return the value the string represents
|
||||
*/
|
||||
public static double fromString(String input) {
|
||||
if ((input = input.trim()).isEmpty()) {
|
||||
return -1D;
|
||||
}
|
||||
try {
|
||||
double value = Double.parseDouble(input); // parse pure numbers
|
||||
if (Double.isNaN(value) || Double.isInfinite(value)) {
|
||||
return -1;
|
||||
}
|
||||
return value;
|
||||
} catch (NumberFormatException ignored) {
|
||||
input = input.toUpperCase(Locale.UK);
|
||||
for (int i = SUFFIXES.length - 1; i > 0; i--) {
|
||||
String suffix = SUFFIXES[i];
|
||||
if (!input.endsWith(suffix)) {
|
||||
continue;
|
||||
}
|
||||
String amount = input.substring(0, input.length() - suffix.length());
|
||||
if (!amount.isEmpty()) {
|
||||
return Double.parseDouble(amount) * Math.pow(10, 3 + i * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@UtilityClass
|
||||
public class NumberUtils {
|
||||
/**
|
||||
* Formats a number with commas.
|
||||
* <p>
|
||||
* Example: 1000 -> 1,000 | Example: 1000.5 -> 1,000.5
|
||||
* </p>
|
||||
*
|
||||
* @param number the number to format
|
||||
* @return the formatted number
|
||||
*/
|
||||
public static String formatNumberCommas(double number) {
|
||||
NumberFormat format = NumberFormat.getNumberInstance();
|
||||
format.setGroupingUsed(true);
|
||||
format.setMaximumFractionDigits(2);
|
||||
return format.format(number);
|
||||
}
|
||||
}
|
39
src/main/java/cc/fascinated/bat/common/PasteUtils.java
Normal file
39
src/main/java/cc/fascinated/bat/common/PasteUtils.java
Normal file
@ -0,0 +1,39 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import cc.fascinated.bat.BatApplication;
|
||||
import cc.fascinated.bat.model.token.paste.PasteUploadToken;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Log4j2
|
||||
public class PasteUtils {
|
||||
private static final String PASTE_URL = "https://paste.fascinated.cc/";
|
||||
private static final String PASTE_UPLOAD_URL = PASTE_URL + "api/upload";
|
||||
private static final HttpClient httpClient = HttpClient.newHttpClient();
|
||||
|
||||
/**
|
||||
* Uploads a paste to the paste server
|
||||
*
|
||||
* @param content the content of the paste
|
||||
* @return the paste upload token
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static PasteUploadToken uploadPaste(String content) {
|
||||
HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder()
|
||||
.uri(URI.create(PASTE_UPLOAD_URL))
|
||||
.POST(HttpRequest.BodyPublishers.ofString(content))
|
||||
.build(), HttpResponse.BodyHandlers.ofString());
|
||||
PasteUploadToken paste = BatApplication.GSON.fromJson(response.body(), PasteUploadToken.class);
|
||||
paste.setUrl(PASTE_URL + paste.getKey());
|
||||
log.info("Created paste with key \"{}\" ({})", paste.getKey(), paste.getUrl());
|
||||
return paste;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class Profile {
|
||||
/**
|
||||
* The key of the profile.
|
||||
*/
|
||||
private String profileKey;
|
||||
|
||||
public Profile() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the profile
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import cc.fascinated.bat.BatApplication;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bson.Document;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -9,11 +14,12 @@ import java.util.Map;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
public class ProfileHolder {
|
||||
public abstract class ProfileHolder {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProfileHolder.class);
|
||||
/**
|
||||
* The profiles for the holder
|
||||
*/
|
||||
private Map<String, Profile> profiles;
|
||||
private final Map<String, Serializable> profiles = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Gets a profile for the holder
|
||||
@ -22,19 +28,25 @@ public class ProfileHolder {
|
||||
* @param <T> The type of the profile
|
||||
* @return The profile
|
||||
*/
|
||||
public <T extends Profile> T getProfile(Class<T> clazz) {
|
||||
if (profiles == null) {
|
||||
profiles = new HashMap<>();
|
||||
}
|
||||
public abstract <T extends Serializable> T getProfile(Class<T> clazz);
|
||||
|
||||
Profile profile = profiles.values().stream().filter(p -> p.getClass().equals(clazz)).findFirst().orElse(null);
|
||||
/**
|
||||
* Gets the profiles for the holder
|
||||
* using the provided document
|
||||
*
|
||||
* @return the profiles
|
||||
*/
|
||||
@SneakyThrows
|
||||
protected <T extends Serializable> T getProfileFromDocument(Class<T> clazz, Document document) {
|
||||
Serializable profile = getProfiles().get(clazz.getSimpleName());
|
||||
if (profile == null) {
|
||||
try {
|
||||
profile = clazz.newInstance();
|
||||
profiles.put(profile.getProfileKey(), profile);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
T newProfile = clazz.cast(clazz.getDeclaredConstructors()[0].newInstance());
|
||||
Document profiles = document.get("profiles", new org.bson.Document());
|
||||
Document profileDocument = (Document) profiles.get(clazz.getSimpleName());
|
||||
|
||||
newProfile.load(profileDocument == null ? new Document() : profileDocument, BatApplication.GSON);
|
||||
getProfiles().put(clazz.getSimpleName(), newProfile);
|
||||
return newProfile;
|
||||
}
|
||||
return clazz.cast(profile);
|
||||
}
|
||||
|
36
src/main/java/cc/fascinated/bat/common/Serializable.java
Normal file
36
src/main/java/cc/fascinated/bat/common/Serializable.java
Normal file
@ -0,0 +1,36 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public abstract class Serializable {
|
||||
/**
|
||||
* Load data from the provided document into this profile
|
||||
*
|
||||
* @param document the document to load data from
|
||||
* @param gson the GSON instance to use
|
||||
*/
|
||||
public abstract void load(Document document, Gson gson);
|
||||
|
||||
/**
|
||||
* Serialize this profile into a Bson document
|
||||
*
|
||||
* @param gson the GSON instance to use
|
||||
* @return the serialized document
|
||||
*/
|
||||
public abstract Document serialize(Gson gson);
|
||||
|
||||
/**
|
||||
* Resets the profile to its default state
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
69
src/main/java/cc/fascinated/bat/common/SpotifyUtils.java
Normal file
69
src/main/java/cc/fascinated/bat/common/SpotifyUtils.java
Normal file
@ -0,0 +1,69 @@
|
||||
package cc.fascinated.bat.common;
|
||||
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.SpotifyService;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import se.michaelthelin.spotify.model_objects.miscellaneous.CurrentlyPlaying;
|
||||
import se.michaelthelin.spotify.model_objects.specification.Track;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Log4j2
|
||||
public class SpotifyUtils {
|
||||
/**
|
||||
* Gets the URL of the track that is currently playing.
|
||||
*
|
||||
* @param currentlyPlaying The currently playing object.
|
||||
* @return The URL of the track that is currently playing.
|
||||
*/
|
||||
public static String getTrackUrl(CurrentlyPlaying currentlyPlaying) {
|
||||
return "https://open.spotify.com/track/" + currentlyPlaying.getItem().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatted time of the currently playing track
|
||||
*
|
||||
* @param currentlyPlaying the currently playing track
|
||||
* @return the formatted time
|
||||
*/
|
||||
public static String getFormattedTime(@NonNull CurrentlyPlaying currentlyPlaying) {
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
int currentMinutes = currentlyPlaying.getProgress_ms() / 1000 / 60;
|
||||
int currentSeconds = currentlyPlaying.getProgress_ms() / 1000 % 60;
|
||||
int totalMinutes = track.getDurationMs() / 1000 / 60;
|
||||
int totalSeconds = track.getDurationMs() / 1000 % 60;
|
||||
|
||||
return "`%02d:%02d`/`%02d:%02d`".formatted(currentMinutes, currentSeconds, totalMinutes, totalSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next track that is playing
|
||||
*
|
||||
* @param user The user to get the track for
|
||||
* @param oldName The name of the old track
|
||||
* @return The new track
|
||||
*/
|
||||
public static CurrentlyPlaying getNewTrack(@NonNull SpotifyService spotifyService, @NonNull BatUser user, @NonNull String oldName) {
|
||||
int checks = 0;
|
||||
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
while (checks < 10) {
|
||||
CurrentlyPlaying currentlyPlaying = spotifyService.getCurrentlyPlayingTrack(user);
|
||||
Track track = (Track) currentlyPlaying.getItem();
|
||||
if (track.getName().equals(oldName)) {
|
||||
Thread.sleep(250);
|
||||
checks++;
|
||||
} else {
|
||||
log.info("Found new track \"{}\" in {} check{}", track.getName(), checks, checks == 1 ? "" : "s");
|
||||
return currentlyPlaying;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -17,4 +17,21 @@ public class StringUtils {
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes meta characters in a string
|
||||
*
|
||||
* @param inputString the input string
|
||||
* @return the string with escaped meta characters
|
||||
*/
|
||||
public static String escapeMetaCharacters(String inputString){
|
||||
final String[] metaCharacters = {"\\","^","$","{","}","[","]","(",")",".","*","+","?","|","<",">","-","&","%"};
|
||||
|
||||
for (String metaCharacter : metaCharacters) {
|
||||
if (inputString.contains(metaCharacter)) {
|
||||
inputString = inputString.replace(metaCharacter, "\\" + metaCharacter);
|
||||
}
|
||||
}
|
||||
return inputString;
|
||||
}
|
||||
}
|
||||
|
@ -31,20 +31,26 @@ public class WebRequest {
|
||||
* @return the response
|
||||
*/
|
||||
public static <T> T getAsEntity(String url, Class<T> clazz) throws RateLimitException {
|
||||
ResponseEntity<T> responseEntity = CLIENT.get()
|
||||
.uri(url)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatusCode::isError, (request, response) -> {
|
||||
}) // Don't throw exceptions on error
|
||||
.toEntity(clazz);
|
||||
try {
|
||||
ResponseEntity<T> responseEntity = CLIENT.get()
|
||||
.uri(url)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatusCode::isError, (request, response) -> {
|
||||
}) // Don't throw exceptions on error
|
||||
.toEntity(clazz);
|
||||
|
||||
if (responseEntity.getStatusCode().isError()) {
|
||||
if (responseEntity.getStatusCode().isError()) {
|
||||
return null;
|
||||
}
|
||||
if (responseEntity.getStatusCode().isSameCodeAs(HttpStatus.TOO_MANY_REQUESTS)) {
|
||||
throw new RateLimitException("Rate limit reached");
|
||||
}
|
||||
return responseEntity.getBody();
|
||||
} catch (RateLimitException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
if (responseEntity.getStatusCode().isSameCodeAs(HttpStatus.TOO_MANY_REQUESTS)) {
|
||||
throw new RateLimitException("Rate limit reached");
|
||||
}
|
||||
return responseEntity.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
|
37
src/main/java/cc/fascinated/bat/config/Config.java
Normal file
37
src/main/java/cc/fascinated/bat/config/Config.java
Normal file
@ -0,0 +1,37 @@
|
||||
package cc.fascinated.bat.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component @Getter
|
||||
public class Config {
|
||||
public static Config INSTANCE;
|
||||
|
||||
/**
|
||||
* Is the app running in a production environment?
|
||||
*/
|
||||
@Getter
|
||||
private static final boolean production;
|
||||
|
||||
/**
|
||||
* The ID of the admin guild
|
||||
*/
|
||||
private final String adminGuild;
|
||||
|
||||
static {
|
||||
// Are we running on production?
|
||||
String appEnv = System.getenv("APP_ENV");
|
||||
production = appEnv != null && (appEnv.equals("production"));
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public Config(@Value("${bat.admin-guild}") String adminGuild) {
|
||||
INSTANCE = this;
|
||||
this.adminGuild = adminGuild;
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package cc.fascinated.bat.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Configuration
|
||||
public class MongoConfig {
|
||||
@Bean
|
||||
public MappingMongoConverter mongoConverter(MongoDatabaseFactory mongoFactory, MongoMappingContext mongoMappingContext) {
|
||||
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoFactory);
|
||||
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
|
||||
mongoConverter.setMapKeyDotReplacement("-DOT");
|
||||
return mongoConverter;
|
||||
}
|
||||
}
|
73
src/main/java/cc/fascinated/bat/config/RedisConfig.java
Normal file
73
src/main/java/cc/fascinated/bat/config/RedisConfig.java
Normal file
@ -0,0 +1,73 @@
|
||||
package cc.fascinated.bat.config;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Configuration
|
||||
@Log4j2(topic = "Redis")
|
||||
public class RedisConfig {
|
||||
/**
|
||||
* The Redis server host.
|
||||
*/
|
||||
@Value("${spring.data.redis.host}")
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* The Redis server port.
|
||||
*/
|
||||
@Value("${spring.data.redis.port}")
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* The Redis database index.
|
||||
*/
|
||||
@Value("${spring.data.redis.database}")
|
||||
private int database;
|
||||
|
||||
/**
|
||||
* The optional Redis password.
|
||||
*/
|
||||
@Value("${spring.data.redis.auth}")
|
||||
private String auth;
|
||||
|
||||
/**
|
||||
* Build the config to use for Redis.
|
||||
*
|
||||
* @return the config
|
||||
* @see RedisTemplate for config
|
||||
*/
|
||||
@Bean @NonNull
|
||||
public RedisTemplate<String, Object> redisTemplate() {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(jedisConnectionFactory());
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the connection factory to use
|
||||
* when making connections to Redis.
|
||||
*
|
||||
* @return the built factory
|
||||
* @see JedisConnectionFactory for factory
|
||||
*/
|
||||
@Bean @NonNull
|
||||
public JedisConnectionFactory jedisConnectionFactory() {
|
||||
log.info("Connecting to Redis at {}:{}/{}", host, port, database);
|
||||
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
|
||||
config.setDatabase(database);
|
||||
if (!auth.trim().isEmpty()) { // Auth with our provided password
|
||||
log.info("Using auth...");
|
||||
config.setPassword(auth);
|
||||
}
|
||||
return new JedisConnectionFactory(config);
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ public class SpotifyController {
|
||||
* @return the response entity
|
||||
*/
|
||||
@GetMapping(value = "/callback")
|
||||
public ResponseEntity<String> authorizationCallback(@RequestParam String code) {
|
||||
public ResponseEntity<String> authorizationCallback(@RequestParam(required = false) String code) {
|
||||
return ResponseEntity.ok(spotifyService.authorize(code));
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,35 @@ package cc.fascinated.bat.event;
|
||||
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.model.DiscordMessage;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberLeaderboardToken;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberPlayerScoreToken;
|
||||
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberScoreToken;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.events.channel.ChannelCreateEvent;
|
||||
import net.dv8tion.jda.api.events.channel.ChannelDeleteEvent;
|
||||
import net.dv8tion.jda.api.events.channel.update.GenericChannelUpdateEvent;
|
||||
import net.dv8tion.jda.api.events.guild.GuildBanEvent;
|
||||
import net.dv8tion.jda.api.events.guild.GuildUnbanEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateTimeOutEvent;
|
||||
import net.dv8tion.jda.api.events.guild.voice.GenericGuildVoiceEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateAvatarEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateNameEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
@ -43,7 +62,7 @@ public interface EventListener {
|
||||
* @param guild the guild the user left
|
||||
* @param user the user that left the guild
|
||||
*/
|
||||
default void onGuildMemberLeave(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberRemoveEvent event) {
|
||||
default void onGuildMemberLeave(@NonNull BatGuild guild, BatUser user, @NonNull GuildMemberRemoveEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,6 +74,25 @@ public interface EventListener {
|
||||
default void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates a message
|
||||
*
|
||||
* @param guild the guild that the message was updated in
|
||||
* @param user the user that updated the message
|
||||
*/
|
||||
default void onGuildMessageEdit(@NonNull BatGuild guild, @NonNull BatUser user, DiscordMessage oldMessage,
|
||||
@NonNull DiscordMessage newMessage, @NonNull MessageUpdateEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user deletes a message
|
||||
*
|
||||
* @param guild the guild that the message was deleted in
|
||||
* @param user the user that deleted the message
|
||||
*/
|
||||
default void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user selects a string
|
||||
*
|
||||
@ -81,4 +119,132 @@ public interface EventListener {
|
||||
*/
|
||||
default void onModalInteraction(BatGuild guild, @NonNull BatUser user, @NonNull ModalInteractionEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates their global name
|
||||
*
|
||||
* @param user the user that updated their global name
|
||||
* @param oldName the old global name
|
||||
* @param newName the new global name
|
||||
*/
|
||||
default void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates their nickname in a guild
|
||||
*
|
||||
* @param guild the guild that the user updated their nickname in
|
||||
* @param user the user that updated their nickname
|
||||
* @param oldName the old nickname
|
||||
* @param newName the new nickname
|
||||
*/
|
||||
default void onGuildMemberUpdateNickname(@NonNull BatGuild guild, @NonNull BatUser user, String oldName, String newName, @NonNull GuildMemberUpdateNicknameEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user gets roles added to them
|
||||
*
|
||||
* @param guild the guild that the user added the role in
|
||||
* @param user the user that added the role
|
||||
* @param rolesAdded the roles that were added
|
||||
*/
|
||||
default void onGuildMemberRoleAdd(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull List<Role> rolesAdded, @NonNull GuildMemberRoleAddEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user gets roles removed from them
|
||||
*
|
||||
* @param guild the guild that the user removed the role in
|
||||
* @param user the user that removed the role
|
||||
* @param rolesAdded the roles that were removed
|
||||
*/
|
||||
default void onGuildMemberRoleRemove(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull List<Role> rolesAdded, @NonNull GuildMemberRoleRemoveEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a channel is created
|
||||
*
|
||||
* @param guild the guild that the channel was created in
|
||||
*/
|
||||
default void onChannelCreate(@NonNull BatGuild guild, @NonNull ChannelCreateEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a channel is deleted
|
||||
*
|
||||
* @param guild the guild that the channel was deleted in
|
||||
*/
|
||||
default void onChannelDelete(@NonNull BatGuild guild, @NonNull ChannelDeleteEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user is banned from a guild
|
||||
*
|
||||
* @param guild the guild that the user was banned from
|
||||
* @param user the user that was banned
|
||||
*/
|
||||
default void onGuildMemberBan(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildBanEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user is unbanned from a guild
|
||||
*
|
||||
* @param guild the guild that the user was unbanned from
|
||||
* @param user the user that was unbanned
|
||||
*/
|
||||
default void onGuildMemberUnban(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildUnbanEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user gets timed out in a guild (gets muted)
|
||||
*
|
||||
* @param guild the guild that the user timed out in
|
||||
* @param user the user that timed out
|
||||
*/
|
||||
default void onGuildMemberTimeout(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberUpdateTimeOutEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a channels state is updated
|
||||
*
|
||||
* @param guild the guild that the channel was updated in
|
||||
* @param event the event that was fired
|
||||
*/
|
||||
default void onGenericChannelUpdate(@NonNull BatGuild guild, @NonNull GenericChannelUpdateEvent<?> event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates their username
|
||||
*
|
||||
* @param user the user that updated their name
|
||||
* @param oldName the old username
|
||||
* @param newName the new username
|
||||
*/
|
||||
default void onUserUpdateName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateNameEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user updates their avatar
|
||||
*
|
||||
* @param user the user that updated their avatar
|
||||
* @param oldAvatarUrl the old avatar url
|
||||
* @param newAvatarUrl the new avatar url
|
||||
*/
|
||||
default void onUserUpdateAvatar(@NonNull BatUser user, String oldAvatarUrl, String newAvatarUrl, @NonNull UserUpdateAvatarEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user joins or leaves a voice channel
|
||||
*
|
||||
* @param guild the guild that the user joined or left the voice channel in
|
||||
* @param user the user that joined or left the voice channel
|
||||
*/
|
||||
default void onGuildVoiceUpdate(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GenericGuildVoiceEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Spring is shutting down
|
||||
*/
|
||||
default void onSpringShutdown() {
|
||||
}
|
||||
}
|
||||
|
10
src/main/java/cc/fascinated/bat/exception/BatException.java
Normal file
10
src/main/java/cc/fascinated/bat/exception/BatException.java
Normal file
@ -0,0 +1,10 @@
|
||||
package cc.fascinated.bat.exception;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class BatException extends Exception {
|
||||
public BatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
|
||||
public class RateLimitException extends RuntimeException {
|
||||
|
||||
public RateLimitException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package cc.fascinated.bat.exception.spotify;
|
||||
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@StandardException
|
||||
public class SpotifyTokenRefreshException extends RuntimeException {
|
||||
public SpotifyTokenRefreshException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -20,6 +20,11 @@ public abstract class Feature {
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The description of the feature
|
||||
*/
|
||||
public final boolean canBeDisabled;
|
||||
|
||||
/**
|
||||
* The category of the feature
|
||||
*/
|
||||
@ -32,7 +37,11 @@ public abstract class Feature {
|
||||
* @param command The command to register
|
||||
*/
|
||||
public void registerCommand(@NonNull CommandService commandService, @NonNull BatCommand command) {
|
||||
command.setCategory(category);
|
||||
// If the command using the default category then set the category to the feature's category
|
||||
if (command.getCategory() == Category.GENERAL) {
|
||||
command.setCategory(this.category);
|
||||
}
|
||||
command.setFeature(this);
|
||||
commandService.registerCommand(command);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class AfkFeature extends Feature {
|
||||
public AfkFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("AFK", Category.GENERAL);
|
||||
super("AFK", true, Category.GENERAL);
|
||||
|
||||
registerCommand(commandService, context.getBean(AfkCommand.class));
|
||||
}
|
||||
|
@ -4,10 +4,8 @@ import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.afk.profile.AfkProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -15,13 +13,6 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
public class AfkReturnListener implements EventListener {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public AfkReturnListener(@NonNull GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) {
|
||||
AfkProfile profile = guild.getProfile(AfkProfile.class);
|
||||
@ -29,7 +20,6 @@ public class AfkReturnListener implements EventListener {
|
||||
return;
|
||||
}
|
||||
profile.removeAfkUser(guild, user.getId());
|
||||
guildService.saveGuild(guild);
|
||||
event.getMessage().reply("Welcome back, %s! You are no longer AFK.".formatted(user.getDiscordUser().getAsMention())).queue();
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,12 @@ import cc.fascinated.bat.common.MemberUtils;
|
||||
import cc.fascinated.bat.features.afk.profile.AfkProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -22,26 +20,21 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
@CommandInfo(name = "afk", description = "Sets your AFK status")
|
||||
public class AfkCommand extends BatCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public AfkCommand(@NonNull GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
public AfkCommand() {
|
||||
super.addOption(OptionType.STRING, "reason", "The reason for being AFK", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AfkProfile profile = guild.getProfile(AfkProfile.class);
|
||||
String reason = null;
|
||||
OptionMapping reasonOption = interaction.getOption("reason");
|
||||
OptionMapping reasonOption = event.getOption("reason");
|
||||
if (reasonOption != null) {
|
||||
reason = reasonOption.getAsString();
|
||||
}
|
||||
|
||||
profile.addAfkUser(guild, member.getId(), reason);
|
||||
guildService.saveGuild(guild);
|
||||
interaction.reply("You are now AFK: %s%s".formatted(
|
||||
event.reply("You are now AFK: %s%s".formatted(
|
||||
profile.getAfkReason(member.getId()),
|
||||
MemberUtils.hasPermissionToEdit(guild, user) ? "" :
|
||||
"\n\n*I do not have enough permissions to edit your user, and therefore cannot update your nickname*"
|
||||
|
@ -1,9 +1,12 @@
|
||||
package cc.fascinated.bat.features.afk.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.bson.Document;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -13,7 +16,8 @@ import java.util.Map;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class AfkProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class AfkProfile extends Serializable {
|
||||
private static final String DEFAULT_REASON = "Away";
|
||||
|
||||
/**
|
||||
@ -98,4 +102,21 @@ public class AfkProfile extends Profile {
|
||||
public void reset() {
|
||||
afkUsers = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
afkUsers = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
afkUsers.put(key, document.getString(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : afkUsers.keySet()) {
|
||||
document.put(key, afkUsers.get(key));
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import org.springframework.stereotype.Component;
|
||||
public class AutoRoleFeature extends Feature {
|
||||
@Autowired
|
||||
public AutoRoleFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("AutoRole", Category.SERVER);
|
||||
super("Auto Role",true, Category.SERVER);
|
||||
|
||||
registerCommand(commandService, context.getBean(AutoRoleCommand.class));
|
||||
}
|
||||
|
@ -4,10 +4,12 @@ import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -19,8 +21,20 @@ import java.util.List;
|
||||
@Component
|
||||
@Log4j2
|
||||
public class AutoRoleListener implements EventListener {
|
||||
private final FeatureService featureService;
|
||||
|
||||
@Autowired
|
||||
public AutoRoleListener(@NonNull FeatureService featureService) {
|
||||
this.featureService = featureService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberJoin(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberJoinEvent event) {
|
||||
AutoRoleFeature autoRoleFeature = featureService.getFeature(AutoRoleFeature.class);
|
||||
if (!guild.getFeatureProfile().isFeatureEnabled(autoRoleFeature)) { // Check if the feature is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
if (profile.getRoles().isEmpty()) {
|
||||
return;
|
||||
@ -35,7 +49,11 @@ public class AutoRoleListener implements EventListener {
|
||||
event.getGuild().addRoleToMember(event.getMember(), role).queue();
|
||||
}
|
||||
toRemove.forEach(profile::removeRole);
|
||||
log.info("Gave user \"{}\" {} auto roles{}", user.getId(), profile.getRoles().size(), toRemove.isEmpty() ? ""
|
||||
: " and removed %s invalid roles".formatted(toRemove.size()));
|
||||
log.info("Gave user \"{}\" {} auto roles in guild \"{}\"{}",
|
||||
user.getId(),
|
||||
profile.getRoles().size(),
|
||||
guild.getName(),
|
||||
toRemove.isEmpty() ? "" : " and removed %s invalid roles from the profile".formatted(toRemove.size())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import cc.fascinated.bat.common.RoleUtils;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
@ -24,30 +23,27 @@ import org.springframework.stereotype.Component;
|
||||
@Component("autoroles:add.sub")
|
||||
@CommandInfo(name = "add", description = "Adds a role to the auto roles list")
|
||||
public class AddSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public AddSubCommand(@NonNull GuildService guildService) {
|
||||
public AddSubCommand() {
|
||||
super.addOption(OptionType.ROLE, "role", "The role to add", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
// Check if the guild has reached the maximum auto roles count
|
||||
int maxRoleSlots = AutoRoleProfile.getMaxRoleSlots(guild);
|
||||
if (profile.getRoleSlotsInUse() >= maxRoleSlots) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The guild can only have a maximum of %d auto roles"
|
||||
.formatted(maxRoleSlots))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping option = interaction.getOption("role");
|
||||
OptionMapping option = event.getOption("role");
|
||||
if (option == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Please provide a role to add")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -56,7 +52,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Check if the role is already in the auto roles list
|
||||
if (profile.hasRole(role.getId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The role %s is already in the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -64,7 +60,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Check if the bot has permission to give the role
|
||||
if (!RoleUtils.hasPermissionToGiveRole(guild, guild.getDiscordGuild().getSelfMember(), role)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("I do not have permission to give the role %s".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -72,7 +68,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Check if the role is higher than the user adding the role
|
||||
if (!RoleUtils.hasPermissionToGiveRole(guild, member, role)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You cannot add a role that is higher than you")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -80,8 +76,7 @@ public class AddSubCommand extends BatSubCommand {
|
||||
|
||||
// Add the role to the auto roles list
|
||||
profile.addRole(role.getId());
|
||||
guildService.saveGuild(guild);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have added %s to the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -20,20 +18,12 @@ import org.springframework.stereotype.Component;
|
||||
@Component("autoroles:clear.sub")
|
||||
@CommandInfo(name = "clear", description = "Clears all auto roles")
|
||||
public class ClearSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ClearSubCommand(GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
|
||||
profile.reset();
|
||||
guildService.saveGuild(guild);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully cleared all auto roles")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "list", description = "Lists all auto roles")
|
||||
public class ListSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
if (profile.getRoles().isEmpty()) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There are no auto roles set")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -41,6 +41,6 @@ public class ListSubCommand extends BatSubCommand {
|
||||
EmbedBuilder embed = EmbedUtils.genericEmbed();
|
||||
embed.setAuthor("Auto Role List");
|
||||
embed.setDescription(roles.toString());
|
||||
interaction.replyEmbeds(embed.build()).queue();
|
||||
event.replyEmbeds(embed.build()).queue();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
@ -23,20 +22,17 @@ import org.springframework.stereotype.Component;
|
||||
@Component("autoroles:remove.sub")
|
||||
@CommandInfo(name = "remove", description = "Removes a role from the auto roles list")
|
||||
public class RemoveSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public RemoveSubCommand(GuildService guildService) {
|
||||
public RemoveSubCommand() {
|
||||
super.addOption(OptionType.ROLE, "role", "The role to remove", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
|
||||
OptionMapping option = interaction.getOption("role");
|
||||
OptionMapping option = event.getOption("role");
|
||||
if (option == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Please provide a role to remove")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -44,15 +40,14 @@ public class RemoveSubCommand extends BatSubCommand {
|
||||
|
||||
Role role = option.getAsRole();
|
||||
if (!profile.hasRole(role.getId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The role %s is not in the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.removeRole(role.getId());
|
||||
guildService.saveGuild(guild);
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed the role %s from the auto roles list".formatted(role.getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package cc.fascinated.bat.features.autorole.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -15,7 +18,8 @@ import java.util.List;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AutoRoleProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class AutoRoleProfile extends Serializable {
|
||||
private static final int DEFAULT_MAX_ROLES = 10;
|
||||
private static final int PREMIUM_MAX_ROLES = 25;
|
||||
|
||||
@ -24,10 +28,6 @@ public class AutoRoleProfile extends Profile {
|
||||
*/
|
||||
private List<String> roleIds;
|
||||
|
||||
public AutoRoleProfile() {
|
||||
super("auto-role");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum amount of roles that can be set in the guild
|
||||
*
|
||||
@ -35,7 +35,7 @@ public class AutoRoleProfile extends Profile {
|
||||
* @return the amount of role slots
|
||||
*/
|
||||
public static int getMaxRoleSlots(BatGuild guild) {
|
||||
if (guild.getPremium().hasPremium()) {
|
||||
if (guild.getPremiumProfile().hasPremium()) {
|
||||
return PREMIUM_MAX_ROLES;
|
||||
}
|
||||
return DEFAULT_MAX_ROLES;
|
||||
@ -110,4 +110,16 @@ public class AutoRoleProfile extends Profile {
|
||||
public void reset() {
|
||||
roleIds.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
roleIds = document.getList("roleIds", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("roleIds", roleIds);
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package cc.fascinated.bat.features.base;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.commands.botadmin.premium.PremiumAdminCommand;
|
||||
import cc.fascinated.bat.features.base.commands.fun.EightBallCommand;
|
||||
import cc.fascinated.bat.features.base.commands.fun.image.ImageCommand;
|
||||
import cc.fascinated.bat.features.base.commands.general.*;
|
||||
import cc.fascinated.bat.features.base.commands.general.avatar.AvatarCommand;
|
||||
import cc.fascinated.bat.features.base.commands.general.banner.BannerCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.MemberCountCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.PremiumCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.channel.ChannelCommand;
|
||||
import cc.fascinated.bat.features.base.commands.server.feature.FeatureCommand;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class BaseFeature extends Feature {
|
||||
@Autowired
|
||||
public BaseFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("Base", false, Category.GENERAL);
|
||||
|
||||
super.registerCommand(commandService, context.getBean(PremiumCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(PremiumAdminCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(MemberCountCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(ChannelCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(VoteCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(PingCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(InviteCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(HelpCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(BotStatsCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(BannerCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(AvatarCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(ImageCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(FeatureCommand.class));
|
||||
super.registerCommand(commandService, context.getBean(EightBallCommand.class));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.botadmin.premium;
|
||||
package cc.fascinated.bat.features.base.commands.botadmin.premium;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
@ -1,9 +1,10 @@
|
||||
package cc.fascinated.bat.command.impl.botadmin.premium;
|
||||
package cc.fascinated.bat.features.base.commands.botadmin.premium;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.premium.PremiumProfile;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -29,26 +30,25 @@ public class RemoveSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping guildOption = interaction.getOption("guild");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping guildOption = event.getOption("guild");
|
||||
if (guildOption == null) {
|
||||
interaction.reply("Please provide a guild id").queue();
|
||||
event.reply("Please provide a guild id").queue();
|
||||
return;
|
||||
}
|
||||
String guildId = guildOption.getAsString();
|
||||
BatGuild batGuild = guildService.getGuild(guildId);
|
||||
if (batGuild == null) {
|
||||
interaction.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
BatGuild targetGuild = guildService.getGuild(guildId);
|
||||
if (targetGuild == null) {
|
||||
event.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
return;
|
||||
}
|
||||
BatGuild.Premium premium = batGuild.getPremium();
|
||||
PremiumProfile premium = targetGuild.getPremiumProfile();
|
||||
if (!premium.hasPremium()) {
|
||||
interaction.reply("The guild does not have premium").queue();
|
||||
event.reply("The guild does not have premium").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
premium.removePremium();
|
||||
guildService.saveGuild(batGuild);
|
||||
interaction.reply("The guild **%s** has had its premium removed".formatted(guild.getName())).queue();
|
||||
event.reply("The guild **%s** has had its premium removed".formatted(targetGuild.getName())).queue();
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
package cc.fascinated.bat.command.impl.botadmin.premium;
|
||||
package cc.fascinated.bat.features.base.commands.botadmin.premium;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.premium.PremiumProfile;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -23,43 +24,42 @@ public class SetSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public SetSubCommand(GuildService guildService) {
|
||||
public SetSubCommand(@NonNull GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
super.addOption(OptionType.STRING, "guild", "The guild id to set as premium", true);
|
||||
super.addOption(OptionType.BOOLEAN, "infinite", "Whether the premium length should be infinite", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping guildOption = interaction.getOption("guild");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping guildOption = event.getOption("guild");
|
||||
if (guildOption == null) {
|
||||
interaction.reply("Please provide a guild id").queue();
|
||||
event.reply("Please provide a guild id").queue();
|
||||
return;
|
||||
}
|
||||
String guildId = guildOption.getAsString();
|
||||
OptionMapping infiniteOption = interaction.getOption("infinite");
|
||||
OptionMapping infiniteOption = event.getOption("infinite");
|
||||
if (infiniteOption == null) {
|
||||
interaction.reply("Please provide whether the premium length should be infinite").queue();
|
||||
event.reply("Please provide whether the premium length should be infinite").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean infinite = infiniteOption.getAsBoolean();
|
||||
BatGuild batGuild = guildService.getGuild(guildId);
|
||||
if (batGuild == null) {
|
||||
interaction.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
BatGuild targetGuild = guildService.getGuild(guildId);
|
||||
if (targetGuild == null) {
|
||||
event.reply("The guild with the id %s does not exist".formatted(guildId)).queue();
|
||||
return;
|
||||
}
|
||||
BatGuild.Premium premium = batGuild.getPremium();
|
||||
PremiumProfile premium = targetGuild.getPremiumProfile();
|
||||
if (!infinite) {
|
||||
premium.addTime();
|
||||
} else {
|
||||
premium.addInfiniteTime();
|
||||
}
|
||||
guildService.saveGuild(batGuild);
|
||||
if (!infinite) {
|
||||
interaction.reply("The guild **%s** has been set as premium until <t:%s>".formatted(guild.getName(), premium.getExpiresAt().toInstant().toEpochMilli() / 1000)).queue();
|
||||
event.reply("The guild **%s** has been set as premium until <t:%s>".formatted(targetGuild.getName(), premium.getExpiresAt().toInstant().toEpochMilli() / 1000)).queue();
|
||||
} else {
|
||||
interaction.reply("The guild **%s** has been set as premium indefinitely".formatted(guild.getName())).queue();
|
||||
event.reply("The guild **%s** has been set as premium indefinitely".formatted(targetGuild.getName())).queue();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cc.fascinated.bat.features.base.commands.fun;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "8ball", description = "Ask the magic 8ball a question")
|
||||
public class EightBallCommand extends BatCommand {
|
||||
private final String[] responses = new String[]{
|
||||
"It is certain",
|
||||
"It is decidedly so",
|
||||
"Without a doubt",
|
||||
"Yes, definitely",
|
||||
"You may rely on it",
|
||||
"As I see it, yes",
|
||||
"Most likely",
|
||||
"Outlook good",
|
||||
"Yes",
|
||||
"Signs point to yes",
|
||||
"Reply hazy, try again",
|
||||
"Ask again later",
|
||||
"Better not tell you now",
|
||||
"Cannot predict now",
|
||||
"Concentrate and ask again",
|
||||
"Don't count on it",
|
||||
"My reply is no",
|
||||
"My sources say no",
|
||||
"Outlook not so good",
|
||||
"Very doubtful"
|
||||
};
|
||||
|
||||
public EightBallCommand() {
|
||||
super.addOption(OptionType.STRING, "question", "The question you want to ask the 8ball", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping questionOption = event.getOption("question");
|
||||
if (questionOption == null) {
|
||||
return;
|
||||
}
|
||||
String question = questionOption.getAsString();
|
||||
String response = responses[(int) (Math.random() * responses.length)];
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You asked: `%s`\n\n:8ball: The magic 8ball says: `%s`".formatted(question, response))
|
||||
.build())
|
||||
.queue();
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package cc.fascinated.bat.command.impl.fun;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.WebRequest;
|
||||
@ -18,17 +17,17 @@ import org.springframework.stereotype.Component;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "cat", description = "Get a random cat image", category = Category.FUN, guildOnly = false)
|
||||
public class CatCommand extends BatCommand {
|
||||
@CommandInfo(name = "cat", description = "Get a random cat image")
|
||||
public class CatSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
CatImageToken[] responseEntity = WebRequest.getAsEntity("https://api.thecatapi.com/v1/images/search", CatImageToken[].class);
|
||||
if (responseEntity == null || responseEntity.length == 0) {
|
||||
interaction.reply("Failed to get a cat image!").queue();
|
||||
event.reply("Failed to get a cat image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random cat image!")
|
||||
.setImage(responseEntity[0].getUrl())
|
||||
.build()).queue();
|
@ -1,7 +1,6 @@
|
||||
package cc.fascinated.bat.command.impl.fun;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.WebRequest;
|
||||
@ -18,17 +17,17 @@ import org.springframework.stereotype.Component;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "dog", description = "Get a random dog image", category = Category.FUN, guildOnly = false)
|
||||
public class DogCommand extends BatCommand {
|
||||
@CommandInfo(name = "dog", description = "Get a random dog image")
|
||||
public class DogSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
RandomImage responseEntity = WebRequest.getAsEntity("https://dog.ceo/api/breeds/image/random", RandomImage.class);
|
||||
if (responseEntity == null) {
|
||||
interaction.reply("Failed to get a dog image!").queue();
|
||||
event.reply("Failed to get a dog image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random dog image!")
|
||||
.setImage(responseEntity.getMessage())
|
||||
.build()).queue();
|
@ -0,0 +1,35 @@
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.WebRequest;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.model.token.randomd.RandomDuck;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "duck", description = "Get a random duck image")
|
||||
public class DuckSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
RandomDuck responseEntity = WebRequest.getAsEntity("https://random-d.uk/api/v2/random", RandomDuck.class);
|
||||
if (responseEntity == null) {
|
||||
event.reply("Failed to get a duck image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random duck image!")
|
||||
.setImage(responseEntity.getUrl())
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package cc.fascinated.bat.command.impl.fun;
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.WebRequest;
|
||||
@ -18,17 +17,17 @@ import org.springframework.stereotype.Component;
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "fox", description = "Get a random fox image", category = Category.FUN, guildOnly = false)
|
||||
public class FoxCommand extends BatCommand {
|
||||
@CommandInfo(name = "fox", description = "Get a random fox image")
|
||||
public class FoxSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
RandomFoxToken responseEntity = WebRequest.getAsEntity("https://randomfox.ca/floof/", RandomFoxToken.class);
|
||||
if (responseEntity == null) {
|
||||
interaction.reply("Failed to get a fox image!").queue();
|
||||
event.reply("Failed to get a fox image!").queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("Here's a random fox image!")
|
||||
.setImage(responseEntity.getImage())
|
||||
.build()).queue();
|
@ -0,0 +1,24 @@
|
||||
package cc.fascinated.bat.features.base.commands.fun.image;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "image", description = "View a random image", guildOnly = false, category = Category.FUN)
|
||||
public class ImageCommand extends BatCommand {
|
||||
@Autowired
|
||||
public ImageCommand(@NonNull ApplicationContext context) {
|
||||
super.addSubCommand(context.getBean(CatSubCommand.class));
|
||||
super.addSubCommand(context.getBean(DogSubCommand.class));
|
||||
super.addSubCommand(context.getBean(FoxSubCommand.class));
|
||||
super.addSubCommand(context.getBean(DuckSubCommand.class));
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.common.TimeUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
@ -37,19 +39,20 @@ public class BotStatsCommand extends BatCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
JDA jda = DiscordService.JDA;
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed().setDescription(
|
||||
"**Bot Statistics**\n" +
|
||||
"➜ Guilds: **%s**\n".formatted(jda.getGuilds().size()) +
|
||||
"➜ Users: **%s**\n".formatted(jda.getUsers().size()) +
|
||||
"➜ Gateway Ping: **%sms**\n".formatted(jda.getGatewayPing()) +
|
||||
"\n" +
|
||||
"**Bat Statistics**\n" +
|
||||
"➜ Uptime: **%s**\n".formatted(TimeUtils.format(bean.getUptime())) +
|
||||
"➜ Cached Guilds: **%s**\n".formatted(guildService.getGuilds().size()) +
|
||||
"➜ Cached Users: **%s**".formatted(userService.getUsers().size())
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed().setDescription(
|
||||
new EmbedDescriptionBuilder("Bat Statistics")
|
||||
.appendLine("Guilds: **%s**".formatted(NumberFormatter.format(jda.getGuilds().size())), true)
|
||||
.appendLine("Users: **%s**".formatted(NumberFormatter.format(jda.getUsers().size())), true)
|
||||
.appendLine("Gateway Ping: **%sms**".formatted(jda.getGatewayPing()), true)
|
||||
.emptyLine()
|
||||
.appendSubtitle("Bot Statistics")
|
||||
.appendLine("Uptime: **%s**".formatted(TimeUtils.format(bean.getUptime())), true)
|
||||
.appendLine("Cached Guilds: **%s**".formatted(NumberFormatter.format(guildService.getGuilds().size())), true)
|
||||
.appendLine("Cached Users: **%s**".formatted(NumberFormatter.format(userService.getUsers().size())), true)
|
||||
.build()
|
||||
).build()).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.Consts;
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
@ -45,8 +45,8 @@ public class HelpCommand extends BatCommand implements EventListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
interaction.replyEmbeds(createHomeEmbed()).addComponents(createHomeActions()).queue();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
event.replyEmbeds(createHomeEmbed()).addComponents(createHomeActions()).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,30 +63,30 @@ public class HelpCommand extends BatCommand implements EventListener {
|
||||
return;
|
||||
}
|
||||
|
||||
String commands = "";
|
||||
StringBuilder commands = new StringBuilder();
|
||||
List<BatCommand> categoryCommands = commandService.getCommandsByCategory(category, true);
|
||||
if (categoryCommands.isEmpty()) {
|
||||
commands = "No commands available in this category.";
|
||||
commands = new StringBuilder("No commands available in this category.");
|
||||
} else {
|
||||
for (BatCommand command : categoryCommands) {
|
||||
if (!command.getSubCommands().isEmpty()) {
|
||||
for (Map.Entry<String, BatSubCommand> entry : command.getSubCommands().entrySet()) {
|
||||
BatSubCommand subCommand = entry.getValue();
|
||||
SubcommandData commandData = subCommand.getCommandData();
|
||||
commands += "</%s %s:%s> - %s\n".formatted(
|
||||
commands.append("</%s %s:%s> - %s\n".formatted(
|
||||
command.getCommandInfo().name(),
|
||||
commandData.getName(),
|
||||
subCommand.getCommandSnowflake(),
|
||||
commandData.getDescription()
|
||||
);
|
||||
));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
commands += "</%s:%s> - %s\n".formatted(
|
||||
commands.append("</%s:%s> - %s\n".formatted(
|
||||
command.getCommandInfo().name(),
|
||||
command.getCommandSnowflake(),
|
||||
command.getCommandInfo().description()
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ public class HelpCommand extends BatCommand implements EventListener {
|
||||
categoryCommands.size() == 1 ? "" : "s",
|
||||
subCommands,
|
||||
subCommands == 1 ? "" : "s",
|
||||
commands
|
||||
commands.toString()
|
||||
)).build()).queue();
|
||||
}
|
||||
|
||||
@ -108,18 +108,27 @@ public class HelpCommand extends BatCommand implements EventListener {
|
||||
* @return The home embed
|
||||
*/
|
||||
private MessageEmbed createHomeEmbed() {
|
||||
String categories = "";
|
||||
StringBuilder categories = new StringBuilder();
|
||||
for (Category category : Category.getCategories()) {
|
||||
long commandCount = commandService.getCommandsByCategory(category, true).size();
|
||||
categories += "➜ %s - **%s Command%s**\n".formatted(
|
||||
categories.append("➜ %s - **%s Command%s**\n".formatted(
|
||||
category.getName(),
|
||||
commandCount,
|
||||
commandCount == 1 ? "" : "s"
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
return EmbedUtils.genericEmbed()
|
||||
.setDescription("Here are the available command categories: \n\n" + categories)
|
||||
.setDescription("""
|
||||
**Welcome to the Bat Help Menu!**
|
||||
|
||||
%s
|
||||
*View our [TOS](%s) and [Privacy Policy](%s) for more information.*
|
||||
""".formatted(
|
||||
categories.toString(),
|
||||
Consts.TERMS_OF_SERVICE_URL,
|
||||
Consts.PRIVACY_POLICY_URL
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.Consts;
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
@ -19,8 +19,8 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "invite", description = "Invite the bot to your server!", guildOnly = false)
|
||||
public class InviteCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("You can invite the bot to your server by clicking [here](%s)".formatted(Consts.INVITE_URL))
|
||||
.build())
|
||||
.setEphemeral(true)
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl;
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -18,9 +18,9 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "ping", description = "Gets the ping of the bot", guildOnly = false)
|
||||
public class PingCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
long time = System.currentTimeMillis();
|
||||
interaction.reply("Pinging...").queue(response -> {
|
||||
event.reply("Pinging...").queue(response -> {
|
||||
response.editOriginal("Gateway response time: `%sms`\nAPI response time `%sms`".formatted(
|
||||
DiscordService.JDA.getGatewayPing(),
|
||||
System.currentTimeMillis() - time
|
@ -0,0 +1,38 @@
|
||||
package cc.fascinated.bat.features.base.commands.general;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "vote", description = "Vote for the bot", guildOnly = false)
|
||||
public class VoteCommand extends BatCommand {
|
||||
private static final String[] VOTE_LINKS = new String[]{
|
||||
"https://top.gg/bot/1254161119975833652/vote",
|
||||
"https://discordbotlist.com/bots/bat/upvote"
|
||||
};
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Vote Links");
|
||||
description.appendLine("Vote for the bot on the following websites to support us!", false);
|
||||
for (String link : VOTE_LINKS) {
|
||||
description.appendLine(link, true);
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription(description.build())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.avatar;
|
||||
package cc.fascinated.bat.features.base.commands.general.avatar;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "avatar", description = "View the avatar of the guild or a user")
|
||||
@CommandInfo(name = "avatar", description = "View the avatar of the guild or a user", guildOnly = false)
|
||||
public class AvatarCommand extends BatCommand {
|
||||
@Autowired
|
||||
public AvatarCommand(@NonNull ApplicationContext context) {
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.avatar;
|
||||
package cc.fascinated.bat.features.base.commands.general.avatar;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -19,18 +19,18 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "guild", description = "View the avatar of the guild")
|
||||
public class GuildSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
ImageProxy icon = guild.getDiscordGuild().getIcon();
|
||||
|
||||
if (icon == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s does not have an avatar!".formatted(guild.getName()))
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("**%s** does not have an avatar!".formatted(guild.getName()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Avatar".formatted(guild.getName()), null, guild.getDiscordGuild().getIconUrl())
|
||||
.setImage(icon.getUrl(4096))
|
||||
.build()
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.avatar;
|
||||
package cc.fascinated.bat.features.base.commands.general.avatar;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -25,10 +25,10 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping userOption = interaction.getOption("user");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
if (userOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a user to view the avatar of!")
|
||||
.build())
|
||||
.queue();
|
||||
@ -36,9 +36,9 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
User target = userOption.getAsUser();
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Avatar".formatted(target.getName()), null, target.getEffectiveAvatarUrl())
|
||||
.setImage(target.getAvatar().getUrl(4096))
|
||||
.setImage(target.getEffectiveAvatarUrl())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.banner;
|
||||
package cc.fascinated.bat.features.base.commands.general.banner;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "banner", description = "View the banner of the guild or a user")
|
||||
@CommandInfo(name = "banner", description = "View the banner of the guild or a user", guildOnly = false)
|
||||
public class BannerCommand extends BatCommand {
|
||||
@Autowired
|
||||
public BannerCommand(@NonNull ApplicationContext context) {
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.banner;
|
||||
package cc.fascinated.bat.features.base.commands.general.banner;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -19,18 +19,17 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "guild", description = "View the banner of the guild")
|
||||
public class GuildSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
ImageProxy banner = guild.getDiscordGuild().getBanner();
|
||||
|
||||
if (banner == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s does not have a banner!".formatted(guild.getName()))
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("**%s** does not have a banner!".formatted(guild.getName()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Banner".formatted(guild.getName()))
|
||||
.setImage(banner.getUrl(512))
|
||||
.build()
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.banner;
|
||||
package cc.fascinated.bat.features.base.commands.general.banner;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -26,10 +26,10 @@ public class UserSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
OptionMapping userOption = interaction.getOption("user");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
if (userOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a user to view the banner of!")
|
||||
.build())
|
||||
.queue();
|
||||
@ -38,16 +38,15 @@ public class UserSubCommand extends BatSubCommand {
|
||||
|
||||
User target = userOption.getAsUser();
|
||||
ImageProxy banner = target.retrieveProfile().complete().getBanner();
|
||||
|
||||
if (banner == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s does not have a banner!".formatted(target.getName()))
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("**%s** does not have a banner!".formatted(target.getName()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setAuthor("%s's Banner".formatted(target.getName()))
|
||||
.setImage(banner.getUrl(512))
|
||||
.build()
|
@ -0,0 +1,68 @@
|
||||
package cc.fascinated.bat.features.base.commands.server;
|
||||
|
||||
import cc.fascinated.bat.Emojis;
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.NumberFormatter;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.OnlineStatus;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Nick (okNick)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "membercount", description = "View the member count of the server!")
|
||||
public class MemberCountCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Guild discordGuild = guild.getDiscordGuild();
|
||||
int totalMembers = 0, totalUsers = 0, totalBots = 0;
|
||||
Map<OnlineStatus, Integer> memberCounts = new HashMap<>();
|
||||
for (Member guildMember : discordGuild.getMembers()) {
|
||||
OnlineStatus status = guildMember.getOnlineStatus();
|
||||
memberCounts.put(status, memberCounts.getOrDefault(status, 0) + 1);
|
||||
|
||||
if (guildMember.getUser().isBot()) {
|
||||
totalBots++;
|
||||
} else {
|
||||
totalUsers++;
|
||||
}
|
||||
totalMembers++;
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("""
|
||||
**Member Count**
|
||||
Total Members: `%s`
|
||||
Total Users: `%s`
|
||||
Total Bots: `%s`
|
||||
\s
|
||||
**Member Presence**
|
||||
%s Online: `%s`
|
||||
%s Idle: `%s`
|
||||
%s Do Not Disturb: `%s`
|
||||
%s Offline: `%s`""".formatted(
|
||||
NumberFormatter.format(totalMembers),
|
||||
NumberFormatter.format(totalUsers),
|
||||
NumberFormatter.format(totalBots),
|
||||
Emojis.ONLINE_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.ONLINE, 0)),
|
||||
Emojis.IDLE_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.IDLE, 0)),
|
||||
Emojis.DND_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.DO_NOT_DISTURB, 0)),
|
||||
Emojis.OFFLINE_EMOJI,
|
||||
NumberFormatter.format(memberCounts.getOrDefault(OnlineStatus.OFFLINE, 0))))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package cc.fascinated.bat.command.impl.server;
|
||||
package cc.fascinated.bat.features.base.commands.server;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.premium.PremiumProfile;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
@ -20,17 +21,17 @@ import org.springframework.stereotype.Component;
|
||||
@CommandInfo(name = "premium", description = "View the premium information for the guild", requiredPermissions = Permission.ADMINISTRATOR)
|
||||
public class PremiumCommand extends BatCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BatGuild.Premium premium = guild.getPremium();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
PremiumProfile premium = guild.getPremiumProfile();
|
||||
EmbedBuilder embed = EmbedUtils.genericEmbed().setAuthor("Premium Information");
|
||||
if (premium.hasPremium()) {
|
||||
embed.addField("Premium", premium.hasPremium() ? "Yes" : "No", true);
|
||||
embed.addField("Started", "<t:%d>".formatted(premium.getActivatedAt().toInstant().toEpochMilli() / 1000), true);
|
||||
embed.addField("Started", "<t:%d>".formatted(premium.getActivatedAt().toInstant().getEpochSecond()), true);
|
||||
embed.addField("Expires", premium.isInfinite() ? "Never" : "<t:%d>"
|
||||
.formatted(premium.getExpiresAt().toInstant().toEpochMilli() / 1000), true);
|
||||
} else {
|
||||
embed.setDescription("The guild does not have premium");
|
||||
}
|
||||
interaction.replyEmbeds(embed.build()).queue();
|
||||
event.replyEmbeds(embed.build()).queue();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -26,10 +26,10 @@ public class RemoveTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
Channel target = interaction.getOption("channel") == null ? channel : interaction.getOption("channel").getAsChannel();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Channel target = event.getOption("channel") == null ? channel : event.getOption("channel").getAsChannel();
|
||||
if (!(target instanceof TextChannel textChannel)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> is not a text channel!".formatted(target.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
@ -37,7 +37,7 @@ public class RemoveTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
if (textChannel.getTopic() == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> does not have a topic!".formatted(textChannel.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
@ -45,7 +45,7 @@ public class RemoveTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
textChannel.getManager().setTopic(null).queue();
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed the topic of <#%s>".formatted(textChannel.getId()))
|
||||
.build()
|
||||
).queue();
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -27,19 +27,19 @@ public class SetTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
Channel target = interaction.getOption("channel") == null ? channel : interaction.getOption("channel").getAsChannel();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Channel target = event.getOption("channel") == null ? channel : event.getOption("channel").getAsChannel();
|
||||
if (!(target instanceof TextChannel textChannel)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> is not a text channel!".formatted(target.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
String topic = interaction.getOption("topic").getAsString();
|
||||
String topic = event.getOption("topic").getAsString();
|
||||
if (topic.length() > 1024) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The topic must be 1024 characters or less!")
|
||||
.build())
|
||||
.queue();
|
||||
@ -47,7 +47,7 @@ public class SetTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
textChannel.getManager().setTopic(topic).queue();
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the topic of <#%s> to: \"%s\"".formatted(textChannel.getId(), topic))
|
||||
.build()
|
||||
).queue();
|
@ -1,4 +1,4 @@
|
||||
package cc.fascinated.bat.command.impl.server.channel;
|
||||
package cc.fascinated.bat.features.base.commands.server.channel;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
@ -25,10 +25,10 @@ public class ViewTopicSubCommand extends BatSubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
Channel target = interaction.getOption("channel") == null ? channel : interaction.getOption("channel").getAsChannel();
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
Channel target = event.getOption("channel") == null ? channel : event.getOption("channel").getAsChannel();
|
||||
if (!(target instanceof TextChannel textChannel)) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> is not a text channel!".formatted(target.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
@ -37,14 +37,14 @@ public class ViewTopicSubCommand extends BatSubCommand {
|
||||
|
||||
String topic = textChannel.getTopic();
|
||||
if (topic == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("<#%s> does not have a topic!".formatted(textChannel.getId()))
|
||||
.build())
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The topic of <#%s> is: \"%s\"".formatted(textChannel.getId(), topic))
|
||||
.build()
|
||||
).queue();
|
@ -0,0 +1,61 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("feature:disable.sub")
|
||||
@CommandInfo(name = "disable", description = "Disables a feature")
|
||||
public class DisableSubCommand extends BatSubCommand {
|
||||
@Autowired
|
||||
public DisableSubCommand() {
|
||||
super.addOption(OptionType.STRING, "feature", "The feature to disable", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
OptionMapping featureOption = event.getOption("feature");
|
||||
if (featureOption == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a feature to enabled")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
String featureName = featureOption.getAsString();
|
||||
if (!FeatureService.INSTANCE.isFeature(featureName)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("That feature does not exist")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
Feature feature = FeatureService.INSTANCE.getFeature(featureName);
|
||||
if (featureProfile.isFeatureDisabled(feature)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The feature `%s` is already disabled".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
featureProfile.disableFeature(feature);
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Successfully disabled the `%s` feature".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("feature:enable.sub")
|
||||
@CommandInfo(name = "enable", description = "Enables a feature")
|
||||
public class EnableSubCommand extends BatSubCommand {
|
||||
@Autowired
|
||||
public EnableSubCommand() {
|
||||
super.addOption(OptionType.STRING, "feature", "The feature to enable", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
OptionMapping featureOption = event.getOption("feature");
|
||||
if (featureOption == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a feature to enabled")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
String featureName = featureOption.getAsString();
|
||||
if (!FeatureService.INSTANCE.isFeature(featureName)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("That feature does not exist")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
Feature feature = FeatureService.INSTANCE.getFeature(featureName);
|
||||
if (featureProfile.isFeatureEnabled(feature)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The feature `%s` is already enabled".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
featureProfile.enableFeature(feature);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully enabled the `%s` feature".formatted(feature.getName()))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "feature", description = "Configure features in your guild", requiredPermissions = Permission.ADMINISTRATOR, category = Category.SERVER)
|
||||
public class FeatureCommand extends BatCommand {
|
||||
@Autowired
|
||||
public FeatureCommand(@NonNull ApplicationContext context) {
|
||||
super.addSubCommand(context.getBean(EnableSubCommand.class));
|
||||
super.addSubCommand(context.getBean(DisableSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ListSubCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package cc.fascinated.bat.features.base.commands.server.feature;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.FeatureService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("feature:list.sub")
|
||||
@CommandInfo(name = "list", description = "Lists the features and their states")
|
||||
public class ListSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
StringBuilder featureStates = new StringBuilder();
|
||||
for (Feature feature : FeatureService.INSTANCE.getFeaturesSorted()) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
featureStates.append("%s `%s`\n".formatted(
|
||||
featureProfile.getFeatureState(feature).getEmoji(),
|
||||
feature.getName()
|
||||
));
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setTitle("Feature List")
|
||||
.setDescription(featureStates.toString())
|
||||
.build()
|
||||
).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package cc.fascinated.bat.features.base.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class FeatureProfile extends Serializable {
|
||||
private static final FeatureState DEFAULT_STATE = FeatureState.ENABLED;
|
||||
|
||||
/**
|
||||
* The feature states
|
||||
*/
|
||||
private Map<String, FeatureState> featureStates;
|
||||
|
||||
/**
|
||||
* Gets the feature states
|
||||
*
|
||||
* @return the feature states
|
||||
*/
|
||||
public FeatureState getFeatureState(Feature feature) {
|
||||
if (feature == null) {
|
||||
return DEFAULT_STATE;
|
||||
}
|
||||
String featureName = feature.getName().toUpperCase();
|
||||
if (!this.featureStates.containsKey(featureName)) {
|
||||
this.featureStates.put(featureName, DEFAULT_STATE);
|
||||
}
|
||||
return this.featureStates.get(featureName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the feature is enabled
|
||||
*
|
||||
* @return the feature state
|
||||
*/
|
||||
public boolean isFeatureEnabled(Feature feature) {
|
||||
return this.getFeatureState(feature) == FeatureState.ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the feature is disabled
|
||||
*
|
||||
* @return the feature state
|
||||
*/
|
||||
public boolean isFeatureDisabled(Feature feature) {
|
||||
return this.getFeatureState(feature) == FeatureState.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the feature
|
||||
*
|
||||
* @param feature the feature to enable
|
||||
*/
|
||||
public void enableFeature(Feature feature) {
|
||||
this.setFeatureState(feature, FeatureState.ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the feature
|
||||
*
|
||||
* @param feature the feature to disable
|
||||
*/
|
||||
public void disableFeature(Feature feature) {
|
||||
this.setFeatureState(feature, FeatureState.DISABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the feature state
|
||||
*
|
||||
* @param feature the feature to set the state for
|
||||
* @param state the state to set
|
||||
*/
|
||||
public void setFeatureState(Feature feature, FeatureState state) {
|
||||
this.featureStates.put(feature.getName().toUpperCase(), state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.featureStates = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.featureStates = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
this.featureStates.put(key, FeatureState.valueOf(document.getString(key)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : this.featureStates.keySet()) {
|
||||
document.put(key, this.featureStates.get(key).name());
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
@AllArgsConstructor @Getter
|
||||
public enum FeatureState {
|
||||
ENABLED(":white_check_mark:"),
|
||||
DISABLED(":x:");
|
||||
|
||||
/**
|
||||
* The emoji for the feature state
|
||||
*/
|
||||
private final String emoji;
|
||||
}
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
package cc.fascinated.bat.features.birthday;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.birthday.command.BirthdayCommand;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -16,11 +19,11 @@ import org.springframework.stereotype.Component;
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class BirthdayFeature extends Feature {
|
||||
public class BirthdayFeature extends Feature implements EventListener {
|
||||
private final GuildService guildService;
|
||||
|
||||
public BirthdayFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService, @NonNull GuildService guildService) {
|
||||
super("Birthday", Category.UTILITY);
|
||||
super("Birthday", true, Category.UTILITY);
|
||||
this.guildService = guildService;
|
||||
|
||||
registerCommand(commandService, context.getBean(BirthdayCommand.class));
|
||||
@ -29,11 +32,15 @@ public class BirthdayFeature extends Feature {
|
||||
/**
|
||||
* Check birthdays every day at midnight
|
||||
*/
|
||||
@Scheduled(cron = "0 0 0 * * *")
|
||||
@Scheduled(cron = "0 1 0 * * *")
|
||||
private void checkBirthdays() {
|
||||
for (BatGuild guild : guildService.getAllGuilds()) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
profile.checkBirthdays(guild);
|
||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||
BatGuild batGuild = guildService.getGuild(guild.getId());
|
||||
if (batGuild == null) {
|
||||
continue;
|
||||
}
|
||||
BirthdayProfile profile = batGuild.getBirthdayProfile();
|
||||
profile.checkBirthdays(batGuild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
package cc.fascinated.bat.features.birthday;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class UserBirthday extends Serializable {
|
||||
/**
|
||||
* The user's birthday
|
||||
*/
|
||||
private Date birthday;
|
||||
|
||||
/**
|
||||
* If the birthday should be hidden
|
||||
*/
|
||||
private boolean hidden;
|
||||
|
||||
/**
|
||||
* Calculates the age of the user
|
||||
*
|
||||
* @return the age of the user
|
||||
*/
|
||||
public int calculateAge() {
|
||||
Calendar birthdayCalendar = Calendar.getInstance();
|
||||
birthdayCalendar.setTime(this.getBirthday());
|
||||
Calendar today = Calendar.getInstance();
|
||||
int age = today.get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR);
|
||||
|
||||
// Check if the birthday hasn't occurred yet this year
|
||||
if (today.get(Calendar.DAY_OF_YEAR) < birthdayCalendar.get(Calendar.DAY_OF_YEAR)) {
|
||||
age--;
|
||||
}
|
||||
return age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
this.birthday = document.getDate("birthday");
|
||||
this.hidden = document.getBoolean("hidden", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
document.put("birthday", this.birthday);
|
||||
document.put("hidden", this.hidden);
|
||||
return document;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
}
|
@ -19,5 +19,7 @@ public class BirthdayCommand extends BatCommand {
|
||||
super.addSubCommand(context.getBean(RemoveSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ChannelSubCommand.class));
|
||||
super.addSubCommand(context.getBean(MessageSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ViewSubCommand.class));
|
||||
super.addSubCommand(context.getBean(PrivateSubCommand.class));
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import cc.fascinated.bat.common.TextChannelUtils;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -26,26 +25,23 @@ import org.springframework.stereotype.Component;
|
||||
@Component("birthday:channel.sub")
|
||||
@CommandInfo(name = "channel", description = "Sets the birthday notification channel", requiredPermissions = Permission.MANAGE_SERVER)
|
||||
public class ChannelSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public ChannelSubCommand(GuildService guildService) {
|
||||
public ChannelSubCommand() {
|
||||
super.addOption(OptionType.CHANNEL, "channel", "The channel birthdays will be sent in", false);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
OptionMapping option = interaction.getOption("channel");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
OptionMapping option = event.getOption("channel");
|
||||
if (option == null) {
|
||||
if (!TextChannelUtils.isValidChannel(profile.getChannelId())) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("There is no channel set for birthday notifications. Please provide a channel to set the birthday channel to")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
interaction.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed()
|
||||
.setDescription("The current birthday channel is %s".formatted(TextChannelUtils.getChannelMention(profile.getChannelId())))
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -53,16 +49,14 @@ public class ChannelSubCommand extends BatSubCommand {
|
||||
|
||||
GuildChannelUnion targetChannel = option.getAsChannel();
|
||||
if (targetChannel.getType() != ChannelType.TEXT) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid channel type, please provide a text channel")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setChannelId(targetChannel.getId());
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the birthday channel to %s".formatted(targetChannel.asTextChannel().getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@ -17,10 +16,6 @@ import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
@ -28,22 +23,17 @@ import java.util.Date;
|
||||
@Component("birthday:message.sub")
|
||||
@CommandInfo(name = "message", description = "Changes the message that is sent when it is a user's birthday", requiredPermissions = Permission.MANAGE_SERVER)
|
||||
public class MessageSubCommand extends BatSubCommand {
|
||||
private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("dd/MM/yyyy");
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public MessageSubCommand(GuildService guildService) {
|
||||
public MessageSubCommand() {
|
||||
super.addOption(OptionType.STRING, "message", "The message that is sent. (Placeholders: {user}, {age})", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
|
||||
OptionMapping messageOption = interaction.getOption("message");
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
OptionMapping messageOption = event.getOption("message");
|
||||
if (messageOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a message")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -51,37 +41,21 @@ public class MessageSubCommand extends BatSubCommand {
|
||||
|
||||
String message = messageOption.getAsString();
|
||||
if (message.length() > 2000) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The message must be less than 2000 characters")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
if (!message.contains("{user}") || !message.contains("{age}")) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The message must contain the placeholders {user} and {age}")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setMessage(message);
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have updated the birthday message!\n\n**Message:** %s".formatted(profile.getBirthdayMessage(user.getDiscordUser())))
|
||||
.build()).queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a birthday from the string
|
||||
*
|
||||
* @param birthday the date to parse
|
||||
* @return the birthday
|
||||
*/
|
||||
private Date parseBirthday(String birthday) {
|
||||
try {
|
||||
return FORMATTER.parse(birthday);
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package cc.fascinated.bat.features.birthday.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("birthday:private.sub")
|
||||
@CommandInfo(name = "private", description = "Changes whether your birthday is private or not")
|
||||
public class PrivateSubCommand extends BatSubCommand {
|
||||
@Autowired
|
||||
public PrivateSubCommand() {
|
||||
super.addOption(OptionType.BOOLEAN, "enabled", "Whether your birthday is private or not", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
OptionMapping enabledOption = event.getOption("enabled");
|
||||
if (enabledOption == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide whether your birthday is private or not")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean enabled = enabledOption.getAsBoolean();
|
||||
UserBirthday birthday = profile.getBirthday(user.getId());
|
||||
if (birthday == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You have not set your birthday yet")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
birthday.setHidden(enabled);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Your birthday privacy settings have been updated\n\n**Private:** " + (enabled ? "Yes" : "No"))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@ -21,21 +19,12 @@ import org.springframework.stereotype.Component;
|
||||
@Component("birthday:remove.sub")
|
||||
@CommandInfo(name = "remove", description = "Remove your birthday from this guild")
|
||||
public class RemoveSubCommand extends BatSubCommand {
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public RemoveSubCommand(GuildService guildService) {
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
|
||||
profile.removeBirthday(user.getId());
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Your birthday has been removed from this guild")
|
||||
.build()).queue();
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ package cc.fascinated.bat.features.birthday.command;
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
@ -28,28 +28,25 @@ import java.util.Date;
|
||||
@CommandInfo(name = "set", description = "Add your birthday to this guild")
|
||||
public class SetSubCommand extends BatSubCommand {
|
||||
private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("dd/MM/yyyy");
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public SetSubCommand(GuildService guildService) {
|
||||
public SetSubCommand() {
|
||||
super.addOption(OptionType.STRING, "birthday", "Your birthday (format: DAY/MONTH/YEAR - 01/05/2004)", true);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) {
|
||||
BirthdayProfile profile = guild.getProfile(BirthdayProfile.class);
|
||||
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
if (!profile.hasChannelSetup()) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping birthdayOption = interaction.getOption("birthday");
|
||||
OptionMapping birthdayOption = event.getOption("birthday");
|
||||
if (birthdayOption == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a birthday")
|
||||
.build()).queue();
|
||||
return;
|
||||
@ -57,16 +54,20 @@ public class SetSubCommand extends BatSubCommand {
|
||||
String birthdayString = birthdayOption.getAsString();
|
||||
Date birthday = parseBirthday(birthdayString);
|
||||
if (birthday == null) {
|
||||
interaction.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid birthday format. Please use the format: DAY/MONTH/YEAR - 01/05/2004")
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("""
|
||||
Invalid birthday format. Please use the following format:
|
||||
DAY/MONTH/YEAR - 01/05/2004
|
||||
""")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.addBirthday(member.getId(), birthday);
|
||||
guildService.saveGuild(guild);
|
||||
|
||||
interaction.replyEmbeds(EmbedUtils.successEmbed()
|
||||
UserBirthday userBirthday = new UserBirthday();
|
||||
userBirthday.setBirthday(birthday);
|
||||
userBirthday.setHidden(false);
|
||||
profile.addBirthday(member.getId(), userBirthday);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have updated your birthday!")
|
||||
.build()).queue();
|
||||
}
|
||||
@ -79,9 +80,16 @@ public class SetSubCommand extends BatSubCommand {
|
||||
*/
|
||||
private Date parseBirthday(String birthday) {
|
||||
try {
|
||||
return FORMATTER.parse(birthday);
|
||||
Date date = FORMATTER.parse(birthday);
|
||||
if (date.after(new Date())) {
|
||||
return null;
|
||||
}
|
||||
if (date.toInstant().toEpochMilli() < 0) {
|
||||
return null;
|
||||
}
|
||||
return date;
|
||||
} catch (ParseException ignored) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
package cc.fascinated.bat.features.birthday.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.features.birthday.profile.BirthdayProfile;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.UserService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("birthday:view.sub")
|
||||
@CommandInfo(name = "view", description = "Add your birthday to this guild")
|
||||
public class ViewSubCommand extends BatSubCommand {
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public ViewSubCommand(@NonNull UserService userService) {
|
||||
this.userService = userService;
|
||||
super.addOption(OptionType.USER, "user", "The user to view the birthday of", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
BirthdayProfile profile = guild.getBirthdayProfile();
|
||||
if (!profile.hasChannelSetup()) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping birthdayOption = event.getOption("user");
|
||||
BatUser target = birthdayOption == null ? user : userService.getUser(birthdayOption.getAsUser().getId());
|
||||
if (target == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You must provide a valid user")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
UserBirthday birthday = profile.getBirthday(target.getId());
|
||||
if (birthday == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s does not have a birthday set".formatted(target.getDiscordUser().getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
if (birthday.isHidden() && !user.getId().equals(target.getId())) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s has their birthday set to private".formatted(target.getDiscordUser().getAsMention()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("%s was born on <t:%s:D> they are `%s` years old!".formatted(
|
||||
target.getDiscordUser().getAsMention(), birthday.getBirthday().toInstant().toEpochMilli()/1000,
|
||||
birthday.calculateAge()
|
||||
))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -1,28 +1,36 @@
|
||||
package cc.fascinated.bat.features.birthday.profile;
|
||||
|
||||
import cc.fascinated.bat.common.Profile;
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.features.birthday.UserBirthday;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BirthdayProfile extends Profile {
|
||||
@NoArgsConstructor
|
||||
public class BirthdayProfile extends Serializable {
|
||||
private static final String DEFAULT_MESSAGE = "Happy Birthday {user} :tada: :birthday: You are now {age} years old!";
|
||||
|
||||
/**
|
||||
* The list of birthdays that are being tracked
|
||||
*/
|
||||
private Map<String, Date> birthdays;
|
||||
private Map<String, UserBirthday> birthdays;
|
||||
|
||||
/**
|
||||
* The channel ID of the birthday feed
|
||||
@ -34,17 +42,13 @@ public class BirthdayProfile extends Profile {
|
||||
*/
|
||||
private String message = DEFAULT_MESSAGE;
|
||||
|
||||
public BirthdayProfile() {
|
||||
super("birthday");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a birthday to be tracked
|
||||
*
|
||||
* @param userId the id of the user to track
|
||||
* @param birthday the birthday of the user
|
||||
*/
|
||||
public void addBirthday(String userId, Date birthday) {
|
||||
public void addBirthday(String userId, UserBirthday birthday) {
|
||||
if (birthdays == null) {
|
||||
birthdays = new HashMap<>();
|
||||
}
|
||||
@ -69,7 +73,7 @@ public class BirthdayProfile extends Profile {
|
||||
* @param userId the id of the user
|
||||
* @return the birthday of the user
|
||||
*/
|
||||
public Date getBirthday(String userId) {
|
||||
public UserBirthday getBirthday(String userId) {
|
||||
if (birthdays == null) {
|
||||
birthdays = new HashMap<>();
|
||||
}
|
||||
@ -85,33 +89,6 @@ public class BirthdayProfile extends Profile {
|
||||
return channelId != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the age of a user
|
||||
*
|
||||
* @param userId the id of the user
|
||||
* @return the age of the user
|
||||
*/
|
||||
public int calculateAge(String userId) {
|
||||
Date birthday = getBirthday(userId);
|
||||
if (birthday == null) {
|
||||
return 0; // or throw an exception
|
||||
}
|
||||
|
||||
Calendar birthdayCalendar = Calendar.getInstance();
|
||||
birthdayCalendar.setTime(birthday);
|
||||
|
||||
Calendar today = Calendar.getInstance();
|
||||
|
||||
int age = today.get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR);
|
||||
|
||||
// Check if the birthday hasn't occurred yet this year
|
||||
if (today.get(Calendar.DAY_OF_YEAR) < birthdayCalendar.get(Calendar.DAY_OF_YEAR)) {
|
||||
age--;
|
||||
}
|
||||
|
||||
return age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the profiles configuration
|
||||
*
|
||||
@ -122,33 +99,10 @@ public class BirthdayProfile extends Profile {
|
||||
if (birthdays == null) {
|
||||
birthdays = new HashMap<>();
|
||||
}
|
||||
|
||||
List<String> toRemove = new ArrayList<>();
|
||||
Guild discordGuild = guild.getDiscordGuild();
|
||||
for (Map.Entry<String, Date> entry : birthdays.entrySet()) {
|
||||
String userId = entry.getKey();
|
||||
Date birthday = entry.getValue();
|
||||
|
||||
if (userId == null || birthday == null) { // this should never happen
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the user is still in the guild, if not remove them
|
||||
Member member = discordGuild.getMemberById(userId);
|
||||
if (member == null) {
|
||||
toRemove.add(userId);
|
||||
}
|
||||
}
|
||||
|
||||
for (String userId : toRemove) {
|
||||
birthdays.remove(userId);
|
||||
}
|
||||
|
||||
if (channelId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (discordGuild.getTextChannelById(channelId) == null) {
|
||||
if (guild.getDiscordGuild().getTextChannelById(channelId) == null) {
|
||||
channelId = null;
|
||||
return false;
|
||||
}
|
||||
@ -170,13 +124,10 @@ public class BirthdayProfile extends Profile {
|
||||
int todayDay = today.get(Calendar.DAY_OF_MONTH);
|
||||
int todayMonth = today.get(Calendar.MONTH); // Note: January is 0
|
||||
|
||||
Iterator<Map.Entry<String, Date>> iterator = birthdays.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Date> entry = iterator.next();
|
||||
Date birthday = entry.getValue();
|
||||
for (Map.Entry<String, UserBirthday> entry : birthdays.entrySet()) {
|
||||
Date birthday = entry.getValue().getBirthday();
|
||||
|
||||
if (birthday == null) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -223,7 +174,7 @@ public class BirthdayProfile extends Profile {
|
||||
public String getBirthdayMessage(User user) {
|
||||
return message
|
||||
.replace("{user}", user.getAsMention())
|
||||
.replace("{age}", String.valueOf(calculateAge(user.getId())));
|
||||
.replace("{age}", String.valueOf(birthdays.get(user.getId()).calculateAge()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -231,4 +182,27 @@ public class BirthdayProfile extends Profile {
|
||||
birthdays.clear();
|
||||
channelId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
birthdays = new HashMap<>();
|
||||
for (String key : document.keySet()) {
|
||||
UserBirthday userBirthday = new UserBirthday();
|
||||
userBirthday.load((Document) document.get(key), gson);
|
||||
birthdays.put(key, userBirthday);
|
||||
}
|
||||
channelId = document.getString("channelId");
|
||||
message = (String) document.getOrDefault("message", DEFAULT_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (String key : birthdays.keySet()) {
|
||||
document.put(key, birthdays.get(key).serialize(gson));
|
||||
}
|
||||
document.put("channelId", channelId);
|
||||
document.put("message", message);
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package cc.fascinated.bat.features.drag;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.drag.command.DragCommand;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class DragFeature extends Feature {
|
||||
@Autowired
|
||||
public DragFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("Drag", true,Category.GENERAL);
|
||||
|
||||
super.registerCommand(commandService, context.getBean(DragCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package cc.fascinated.bat.features.drag;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter @Setter
|
||||
public class DragRequest {
|
||||
/**
|
||||
* The date the request was made
|
||||
*/
|
||||
private final Date requestDate = new Date();
|
||||
|
||||
/**
|
||||
* The user that wants to join the voice channel
|
||||
*/
|
||||
private final Member member;
|
||||
|
||||
/**
|
||||
* The user that the member wants to join
|
||||
*/
|
||||
private final Member target;
|
||||
|
||||
/**
|
||||
* The voice channel the user wants to join
|
||||
*/
|
||||
private final VoiceChannel voiceChannel;
|
||||
|
||||
/**
|
||||
* The interaction hook that the request was made from
|
||||
*/
|
||||
private final InteractionHook interactionHook;
|
||||
|
||||
/**
|
||||
* The request message sent in the voice channel
|
||||
*/
|
||||
private Message requestMessage;
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cc.fascinated.bat.features.drag.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import io.sentry.protocol.App;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "drag", description = "Drag command")
|
||||
public class DragCommand extends BatCommand {
|
||||
@Autowired
|
||||
public DragCommand(@NonNull ApplicationContext context) {
|
||||
super.addSubCommand(context.getBean(RequestSubCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package cc.fascinated.bat.features.drag.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.TimerUtils;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.drag.DragRequest;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.GuildVoiceState;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Handles requests to be moved to a voice channel.
|
||||
* Author: Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "request", description = "Request to be moved to a voice channel")
|
||||
public class RequestSubCommand extends BatSubCommand implements EventListener {
|
||||
/**
|
||||
* A list of join requests
|
||||
*/
|
||||
public static final Set<DragRequest> JOIN_REQUESTS = new HashSet<>();
|
||||
|
||||
private final long requestTimeout = Duration.ofMinutes(30).toMillis();
|
||||
private final long checkInterval = Duration.ofSeconds(10).toMillis();
|
||||
|
||||
public RequestSubCommand() {
|
||||
super.addOption(OptionType.USER, "user", "The user you want to join", true);
|
||||
|
||||
TimerUtils.scheduleRepeating(() -> {
|
||||
Set<DragRequest> toRemove = new HashSet<>();
|
||||
for (DragRequest joinRequest : JOIN_REQUESTS) {
|
||||
if (System.currentTimeMillis() - joinRequest.getRequestDate().getTime() < requestTimeout) {
|
||||
return;
|
||||
}
|
||||
// The request has timed out
|
||||
joinRequest.getInteractionHook().editOriginalEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The request to join %s's voice channel has timed out.".formatted(joinRequest.getTarget().getAsMention()))
|
||||
.build()).queue();
|
||||
joinRequest.getVoiceChannel().sendMessageEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s's request to join your voice channel has timed out.".formatted(joinRequest.getMember().getAsMention()))
|
||||
.build()).queue();
|
||||
joinRequest.getRequestMessage().delete().queue();
|
||||
toRemove.add(joinRequest);
|
||||
}
|
||||
JOIN_REQUESTS.removeAll(toRemove);
|
||||
}, checkInterval, checkInterval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
GuildVoiceState voiceState = member.getVoiceState();
|
||||
// Check if the user is in a voice channel
|
||||
if (voiceState == null || voiceState.getChannel() == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You are not in a voice channel.")
|
||||
.build())
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping userOption = event.getOption("user");
|
||||
if (userOption == null) return;
|
||||
|
||||
// Check if the user is in a voice channel
|
||||
Member target = userOption.getAsMember();
|
||||
if (target == null || target.getId().equals(member.getId())) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You cannot request to join your own voice channel.")
|
||||
.build())
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the target user is in a voice channel
|
||||
GuildVoiceState targetVoiceState = target.getVoiceState();
|
||||
if (targetVoiceState == null || targetVoiceState.getChannel() == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The user %s is not in a voice channel.".formatted(target.getAsMention()))
|
||||
.build())
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
VoiceChannel targetChannel = targetVoiceState.getChannel().asVoiceChannel();
|
||||
|
||||
// User is already in the target channel
|
||||
if (voiceState.getChannel().getId().equals(targetChannel.getId())) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You are already in the voice channel %s.".formatted(voiceState.getChannel().getAsMention()))
|
||||
.build())
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the user has already requested to join the target channel
|
||||
DragRequest existingRequest = JOIN_REQUESTS.stream()
|
||||
.filter(request -> request.getMember().getId().equals(member.getId()) && request.getVoiceChannel().getId().equals(targetChannel.getId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (existingRequest != null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You have already requested to join %s's voice channel.".formatted(target.getAsMention()))
|
||||
.build())
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the request to the list
|
||||
JOIN_REQUESTS.add(new DragRequest(member, target, targetChannel, event.getHook()));
|
||||
|
||||
// Send the request to the target user
|
||||
targetChannel.sendMessage(target.getAsMention()).queue();
|
||||
targetChannel.sendMessageEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("User %s has requested to join your voice channel.".formatted(member.getAsMention()))
|
||||
.build())
|
||||
.addComponents(ActionRow.of(
|
||||
Button.primary("drag-request-accept", "Accept"),
|
||||
Button.danger("drag-request-decline", "Decline")
|
||||
))
|
||||
.queue(message -> {
|
||||
JOIN_REQUESTS.stream()
|
||||
.filter(r -> r.getVoiceChannel().getId().equals(targetChannel.getId()))
|
||||
.findFirst().ifPresent(request -> request.setRequestMessage(message));
|
||||
});
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Request to join %s's voice channel has been sent.".formatted(target.getAsMention()))
|
||||
.build())
|
||||
.setComponents(ActionRow.of(Button.secondary("drag-request-cancel", "Cancel")))
|
||||
.queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package cc.fascinated.bat.features.drag.listeners.request;
|
||||
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.drag.DragRequest;
|
||||
import cc.fascinated.bat.features.drag.command.RequestSubCommand;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class RequestListener implements EventListener {
|
||||
@Override
|
||||
public void onButtonInteraction(BatGuild guild, @NonNull BatUser user, @NonNull ButtonInteractionEvent event) {
|
||||
if (!event.getComponentId().equals("drag-request-cancel")) {
|
||||
return;
|
||||
}
|
||||
Optional<DragRequest> optionalDragRequest = RequestSubCommand.JOIN_REQUESTS.stream()
|
||||
.filter(request -> request.getMember().getId().equals(event.getUser().getId()))
|
||||
.findFirst();
|
||||
if (optionalDragRequest.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
DragRequest dragRequest = optionalDragRequest.get();
|
||||
InteractionHook interactionHook = dragRequest.getInteractionHook();
|
||||
interactionHook.editOriginalEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You have cancelled your request to join %s's voice channel.".formatted(dragRequest.getTarget().getAsMention()))
|
||||
.build()).queue(message -> message.editMessageComponents().queue());
|
||||
dragRequest.getVoiceChannel().sendMessageEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s has cancelled their request to join your voice channel.".formatted(dragRequest.getMember().getAsMention()))
|
||||
.build()).queue();
|
||||
dragRequest.getRequestMessage().delete().queue();
|
||||
RequestSubCommand.JOIN_REQUESTS.remove(dragRequest);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package cc.fascinated.bat.features.drag.listeners.request;
|
||||
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.drag.DragRequest;
|
||||
import cc.fascinated.bat.features.drag.command.RequestSubCommand;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class TargetChannelListener implements EventListener {
|
||||
@Override
|
||||
public void onButtonInteraction(BatGuild guild, @NonNull BatUser user, @NonNull ButtonInteractionEvent event) {
|
||||
User buttonUser = event.getUser();
|
||||
Member member = guild.getDiscordGuild().getMember(buttonUser);
|
||||
if (member == null) return;
|
||||
|
||||
DragRequest joinRequest = RequestSubCommand.JOIN_REQUESTS.stream()
|
||||
.filter(request -> request.getVoiceChannel().getId().equals(event.getChannel().getId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (joinRequest == null) return;
|
||||
|
||||
if (event.getComponentId().equals("drag-request-accept")) {
|
||||
joinRequest.getVoiceChannel().getGuild().moveVoiceMember(joinRequest.getMember(), joinRequest.getVoiceChannel()).queue();
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("You have accepted %s's request to join your voice channel!".formatted(joinRequest.getMember().getAsMention()))
|
||||
.build())
|
||||
.queue();
|
||||
} else if (event.getComponentId().equals("drag-request-decline")) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("You have declined %s's request to join your voice channel!".formatted(joinRequest.getMember().getAsMention()))
|
||||
.build())
|
||||
.queue();
|
||||
joinRequest.getInteractionHook().retrieveOriginal().queue(message -> {
|
||||
message.editMessageEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("%s has declined your request to join their voice channel.".formatted(joinRequest.getTarget().getAsMention()))
|
||||
.build()).queue();
|
||||
message.editMessageComponents().queue();
|
||||
});
|
||||
}
|
||||
RequestSubCommand.JOIN_REQUESTS.remove(joinRequest);
|
||||
// Remove the buttons from the embed
|
||||
event.getInteraction().getMessage().editMessageComponents().queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package cc.fascinated.bat.features.logging;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@AllArgsConstructor @Getter
|
||||
public enum LogCategory {
|
||||
MESSAGE("Message"),
|
||||
MEMBER("Member"),
|
||||
CHANNEL("Channel");
|
||||
|
||||
/**
|
||||
* The name of the log category
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Gets the log category by the name
|
||||
*
|
||||
* @param name - the name
|
||||
* @return the log category, or null if it doesn't exist
|
||||
*/
|
||||
public static LogCategory getLogCategory(String name) {
|
||||
for (LogCategory logCategory : values()) {
|
||||
if (logCategory.getName().equalsIgnoreCase(name)) {
|
||||
return logCategory;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package cc.fascinated.bat.features.logging;
|
||||
|
||||
import cc.fascinated.bat.command.Category;
|
||||
import cc.fascinated.bat.common.PasteUtils;
|
||||
import cc.fascinated.bat.features.Feature;
|
||||
import cc.fascinated.bat.features.base.profile.FeatureProfile;
|
||||
import cc.fascinated.bat.features.logging.command.LogsCommand;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.service.CommandService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class LogFeature extends Feature {
|
||||
@Autowired
|
||||
public LogFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
|
||||
super("Logging", false, Category.LOGS);
|
||||
|
||||
super.registerCommand(commandService, context.getBean(LogsCommand.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a log to the log channel
|
||||
*
|
||||
* @param guild the guild to send the log in
|
||||
* @param type the type of log
|
||||
* @param embed the embed to send
|
||||
*/
|
||||
public void sendLog(BatGuild guild, LogType type, MessageEmbed embed) {
|
||||
FeatureProfile featureProfile = guild.getFeatureProfile();
|
||||
if (featureProfile.isFeatureDisabled(this)) { // The feature is disabled
|
||||
return;
|
||||
}
|
||||
LogProfile logProfile = guild.getLogProfile();
|
||||
if (!logProfile.hasLogChannel(type)) { // The guild has no log channel for this type
|
||||
return;
|
||||
}
|
||||
TextChannel logChannel = logProfile.getLogChannel(type);
|
||||
if (logChannel == null) { // The log channel has been removed
|
||||
return;
|
||||
}
|
||||
logChannel.sendMessageEmbeds(embed).queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the content to be sent in the log
|
||||
*
|
||||
* @param content the content to format
|
||||
* @return the formatted content
|
||||
*/
|
||||
public String formatContent(String content) {
|
||||
return content.length() > 512 ? PasteUtils.uploadPaste(content).getUrl() : "\n```\n%s\n```".formatted(content);
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package cc.fascinated.bat.features.logging;
|
||||
|
||||
import cc.fascinated.bat.common.Serializable;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import com.google.gson.Gson;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
public class LogProfile extends Serializable {
|
||||
/**
|
||||
* The log channels for this profile
|
||||
*/
|
||||
private final Map<LogType, TextChannel> logChannels = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Checks if the log channel for the specified log type exists
|
||||
*
|
||||
* @param logType - the log type
|
||||
* @return true if it exists, false otherwise
|
||||
*/
|
||||
public boolean hasLogChannel(LogType logType) {
|
||||
return this.logChannels.containsKey(logType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the log channel for the specified log type
|
||||
*
|
||||
* @param logType - the log type
|
||||
* @return the log channel, or null if it doesn't exist
|
||||
*/
|
||||
public TextChannel getLogChannel(LogType logType) {
|
||||
TextChannel textChannel = this.logChannels.get(logType);
|
||||
if (textChannel == null) {
|
||||
return null;
|
||||
}
|
||||
// Ensure the channel exists
|
||||
if (DiscordService.JDA.getTextChannelById(textChannel.getId()) == null) {
|
||||
this.logChannels.remove(logType);
|
||||
return null;
|
||||
}
|
||||
return textChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log channel for the specified log type
|
||||
*
|
||||
* @param logType - the log type
|
||||
* @param channel - the channel
|
||||
*/
|
||||
public void setLogChannel(LogType logType, TextChannel channel) {
|
||||
this.logChannels.put(logType, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the log channel for the specified log type
|
||||
*
|
||||
* @param logType - the log type
|
||||
*/
|
||||
public void removeLogChannel(LogType logType) {
|
||||
this.logChannels.remove(logType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Document document, Gson gson) {
|
||||
JDA jda = DiscordService.JDA;
|
||||
for (LogType logType : LogType.values()) {
|
||||
if (document.containsKey(logType.name())) {
|
||||
TextChannel channel = jda.getTextChannelById(document.getString(logType.name()));
|
||||
if (channel == null) {
|
||||
return;
|
||||
}
|
||||
this.logChannels.put(logType, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document serialize(Gson gson) {
|
||||
Document document = new Document();
|
||||
for (Map.Entry<LogType, TextChannel> entry : this.logChannels.entrySet()) {
|
||||
document.append(entry.getKey().name(), entry.getValue().getId());
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.logChannels.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package cc.fascinated.bat.features.logging;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@AllArgsConstructor @Getter
|
||||
public enum LogType {
|
||||
/**
|
||||
* Message Events
|
||||
*/
|
||||
MESSAGE_DELETE(LogCategory.MESSAGE, "Message Delete"),
|
||||
MESSAGE_EDIT(LogCategory.MESSAGE,"Message Edit"),
|
||||
|
||||
/**
|
||||
* Member Events
|
||||
*/
|
||||
MEMBER_JOIN(LogCategory.MEMBER, "Member Join"),
|
||||
MEMBER_LEAVE(LogCategory.MEMBER, "Member Leave"),
|
||||
MEMBER_NICKNAME_UPDATE(LogCategory.MEMBER, "Member Nickname Update"),
|
||||
MEMBER_GLOBAL_NAME_UPDATE(LogCategory.MEMBER, "Member Global Name Update"),
|
||||
MEMBER_USERNAME_UPDATE(LogCategory.MEMBER, "Member Username Update"),
|
||||
MEMBER_AVATAR_UPDATE(LogCategory.MEMBER, "Member Avatar Update"),
|
||||
MEMBER_ROLE_UPDATE(LogCategory.MEMBER, "Member Role Update"),
|
||||
MEMBER_BAN(LogCategory.MEMBER, "Member Ban"),
|
||||
MEMBER_UNBAN(LogCategory.MEMBER, "Member Unban"),
|
||||
MEMBER_TIMEOUT(LogCategory.MEMBER, "Member Timeout"),
|
||||
|
||||
/**
|
||||
* Channel Events
|
||||
*/
|
||||
CHANNEL_CREATE(LogCategory.CHANNEL, "Channel Create"),
|
||||
CHANNEL_DELETE(LogCategory.CHANNEL, "Channel Delete"),
|
||||
VOICE_CHANNEL_JOIN(LogCategory.CHANNEL, "Voice Channel Join"),
|
||||
VOICE_CHANNEL_LEAVE(LogCategory.CHANNEL, "Voice Channel Leave");
|
||||
|
||||
/**
|
||||
* The category of the log type
|
||||
*/
|
||||
private final LogCategory category;
|
||||
|
||||
/**
|
||||
* The name of the log type
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Gets the log type by the name
|
||||
*
|
||||
* @param name - the name
|
||||
* @return the log type, or null if it doesn't exist
|
||||
*/
|
||||
public static LogType getLogType(String name) {
|
||||
for (LogType logType : values()) {
|
||||
if (logType.getName().equalsIgnoreCase(name)) {
|
||||
return logType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the log types by the category
|
||||
*
|
||||
* @param category - the category
|
||||
* @return the log types
|
||||
*/
|
||||
public static List<LogType> getLogTypesByCategory(String category) {
|
||||
List<LogType> logTypes = new ArrayList<>();
|
||||
for (LogType logType : values()) {
|
||||
if (logType.getCategory().getName().equalsIgnoreCase(category)) {
|
||||
logTypes.add(logType);
|
||||
}
|
||||
}
|
||||
return logTypes;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package cc.fascinated.bat.features.logging.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.logging.LogCategory;
|
||||
import cc.fascinated.bat.features.logging.LogProfile;
|
||||
import cc.fascinated.bat.features.logging.LogType;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("logs:list.sub")
|
||||
@CommandInfo(name = "list", description = "See all the log types and their channels")
|
||||
public class ListSubCommand extends BatSubCommand {
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
LogProfile profile = guild.getLogProfile();
|
||||
EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Log Channels");
|
||||
description.appendLine("""
|
||||
Set the log channel for:
|
||||
- A specific event, use `/logs set <event> <channel>`
|
||||
- A specific category by using `/logs set <category> <channel>`
|
||||
- All log types by using `/logs set all <channel>`
|
||||
To remove a log channel, it's the same as setting it,
|
||||
but with `/logs remove` instead of `/logs set`""", false);
|
||||
description.emptyLine();
|
||||
for (int i = 0; i < LogCategory.values().length; i++) {
|
||||
LogCategory category = LogCategory.values()[i];
|
||||
if (i != 0) {
|
||||
description.emptyLine();
|
||||
}
|
||||
description.appendLine("**__%s__**".formatted(category.getName()), false);
|
||||
for (LogType logType : LogType.values()) {
|
||||
if (logType.getCategory() == category) {
|
||||
TextChannel logChannel = profile.getLogChannel(logType);
|
||||
description.appendLine("%s: %s".formatted(logType.getName(), logChannel == null ? "Not Set" : logChannel.getAsMention()), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
event.replyEmbeds(EmbedUtils.genericEmbed().setDescription(description.build()).build()).queue();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package cc.fascinated.bat.features.logging.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@CommandInfo(name = "logs", description = "Edit logging settings", requiredPermissions = Permission.MANAGE_SERVER)
|
||||
public class LogsCommand extends BatCommand {
|
||||
@Autowired
|
||||
public LogsCommand(@NonNull ApplicationContext context) {
|
||||
super.addSubCommand(context.getBean(SetSubCommand.class));
|
||||
super.addSubCommand(context.getBean(RemoveSubCommand.class));
|
||||
super.addSubCommand(context.getBean(ListSubCommand.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package cc.fascinated.bat.features.logging.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.logging.LogCategory;
|
||||
import cc.fascinated.bat.features.logging.LogProfile;
|
||||
import cc.fascinated.bat.features.logging.LogType;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("logs:remove.sub")
|
||||
@CommandInfo(name = "remove", description = "Remove the channel for a log type")
|
||||
public class RemoveSubCommand extends BatSubCommand {
|
||||
public RemoveSubCommand() {
|
||||
super.addOption(OptionType.STRING, "type", "The type of log to remove", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping typeOption = event.getOption("type");
|
||||
if (typeOption == null) {
|
||||
return;
|
||||
}
|
||||
String type = typeOption.getAsString();
|
||||
LogProfile profile = guild.getLogProfile();
|
||||
|
||||
// Remove the log channel for all log types
|
||||
if (type.equalsIgnoreCase("all")) {
|
||||
for (LogType logType : LogType.values()) {
|
||||
profile.removeLogChannel(logType);
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed the log channel for all log types")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the log channel for a specific log category
|
||||
LogCategory logCategory = LogCategory.getLogCategory(type);
|
||||
if (logCategory != null) {
|
||||
List<LogType> category = LogType.getLogTypesByCategory(type);
|
||||
EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Log Channel");
|
||||
description.appendLine("Successfully removed the log channel for the `%s` category"
|
||||
.formatted(logCategory.getName()), false);
|
||||
description.emptyLine();
|
||||
|
||||
int removed = 0;
|
||||
for (LogType logType : category) {
|
||||
if (!profile.hasLogChannel(logType)) {
|
||||
continue;
|
||||
}
|
||||
description.appendLine(logType.getName(), true);
|
||||
profile.removeLogChannel(logType);
|
||||
removed++;
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription(removed == 0 ? "No log channels were removed for the `%s` category".formatted(logCategory.getName()) : description.build())
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the log channel for a specific log type
|
||||
LogType logType = LogType.getLogType(type);
|
||||
if (logType == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid log type")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!profile.hasLogChannel(logType)) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("The log channel for `%s` is not set".formatted(logType.getName()))
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
profile.removeLogChannel(logType);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully removed the log channel for `%s`".formatted(logType.getName()))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package cc.fascinated.bat.features.logging.command;
|
||||
|
||||
import cc.fascinated.bat.command.BatSubCommand;
|
||||
import cc.fascinated.bat.command.CommandInfo;
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.features.logging.LogCategory;
|
||||
import cc.fascinated.bat.features.logging.LogProfile;
|
||||
import cc.fascinated.bat.features.logging.LogType;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component("logs:set.sub")
|
||||
@CommandInfo(name = "set", description = "Set the channel for a log type")
|
||||
public class SetSubCommand extends BatSubCommand {
|
||||
public SetSubCommand() {
|
||||
super.addOption(OptionType.STRING, "type", "The type of log to set", true);
|
||||
super.addOption(OptionType.CHANNEL, "channel", "The channel to set the log to", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
|
||||
OptionMapping typeOption = event.getOption("type");
|
||||
if (typeOption == null) {
|
||||
return;
|
||||
}
|
||||
OptionMapping channelOption = event.getOption("channel");
|
||||
if (channelOption == null) {
|
||||
return;
|
||||
}
|
||||
String type = typeOption.getAsString();
|
||||
TextChannel targetChannel = channelOption.getAsChannel().asTextChannel();
|
||||
LogProfile profile = guild.getLogProfile();
|
||||
|
||||
// Set the log channel for all log types
|
||||
if (type.equalsIgnoreCase("all")) {
|
||||
EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Log Channel");
|
||||
description.appendLine("Successfully set the log channel for all log types to %s".formatted(targetChannel.getAsMention()), false);
|
||||
description.emptyLine();
|
||||
for (int i = 0; i < LogCategory.values().length; i++) {
|
||||
LogCategory category = LogCategory.values()[i];
|
||||
if (i != 0) {
|
||||
description.emptyLine();
|
||||
}
|
||||
description.appendLine("**__%s__**".formatted(category.getName()), false);
|
||||
for (LogType logType : LogType.getLogTypesByCategory(category.getName())) {
|
||||
description.appendLine(logType.getName(), true);
|
||||
profile.setLogChannel(logType, targetChannel);
|
||||
}
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription(description.build())
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the log channel for a specific log category
|
||||
LogCategory logCategory = LogCategory.getLogCategory(type);
|
||||
if (logCategory != null) {
|
||||
List<LogType> category = LogType.getLogTypesByCategory(type);
|
||||
EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Log Channel");
|
||||
description.appendLine("Successfully set the log channel for the `%s` category to %s"
|
||||
.formatted(logCategory.getName(), targetChannel.getAsMention()), false);
|
||||
description.emptyLine();
|
||||
for (LogType logType : category) {
|
||||
description.appendLine(logType.getName(), true);
|
||||
profile.setLogChannel(logType, targetChannel);
|
||||
}
|
||||
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription(description.build())
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the log channel for a specific log type
|
||||
LogType logType = LogType.getLogType(type);
|
||||
if (logType == null) {
|
||||
event.replyEmbeds(EmbedUtils.errorEmbed()
|
||||
.setDescription("Invalid log type")
|
||||
.build()).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
profile.setLogChannel(logType, targetChannel);
|
||||
event.replyEmbeds(EmbedUtils.successEmbed()
|
||||
.setDescription("Successfully set the log channel for `%s` to %s".formatted(logType.getName(), targetChannel.getAsMention()))
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package cc.fascinated.bat.features.logging.listeners;
|
||||
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.common.EnumUtils;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.logging.LogFeature;
|
||||
import cc.fascinated.bat.features.logging.LogType;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
|
||||
import net.dv8tion.jda.api.entities.channel.unions.ChannelUnion;
|
||||
import net.dv8tion.jda.api.events.channel.ChannelCreateEvent;
|
||||
import net.dv8tion.jda.api.events.channel.ChannelDeleteEvent;
|
||||
import net.dv8tion.jda.api.events.guild.voice.GenericGuildVoiceEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@Log4j2
|
||||
public class ChannelListener implements EventListener {
|
||||
/**
|
||||
* A map of users and the last voice channel they were in
|
||||
*/
|
||||
private final Map<BatUser, VoiceChannel> lastVoiceChannel = new HashMap<>();
|
||||
private final LogFeature logFeature;
|
||||
|
||||
@Autowired
|
||||
public ChannelListener(@NonNull ApplicationContext context) {
|
||||
this.logFeature = context.getBean(LogFeature.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelCreate(@NonNull BatGuild guild, @NonNull ChannelCreateEvent event) {
|
||||
log.info("Channel \"{}\" was created in guild \"{}\"", event.getChannel().getName(), guild.getName());
|
||||
logFeature.sendLog(guild, LogType.CHANNEL_CREATE, EmbedUtils.successEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("%s Channel Created".formatted(EnumUtils.getEnumName(event.getChannel().getType())))
|
||||
.appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true)
|
||||
.appendLine("Name: %s".formatted(event.getChannel().getName()), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelDelete(@NonNull BatGuild guild, @NonNull ChannelDeleteEvent event) {
|
||||
log.info("Channel \"{}\" was deleted in guild \"{}\"", event.getChannel().getName(), guild.getName());
|
||||
ChannelUnion channel = event.getChannel();
|
||||
EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("%s Channel Deleted".formatted(EnumUtils.getEnumName(channel.getType())))
|
||||
.appendLine("Name: #%s".formatted(channel.getName()), true);
|
||||
if (channel.getType().isMessage()) {
|
||||
TextChannel textChannel = channel.asTextChannel();
|
||||
description.appendLine("Topic: %s".formatted(textChannel.getTopic()), true);
|
||||
}
|
||||
logFeature.sendLog(guild, LogType.CHANNEL_DELETE, EmbedUtils.errorEmbed().setDescription(description.build()).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildVoiceUpdate(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GenericGuildVoiceEvent event) {
|
||||
AudioChannelUnion channel = event.getVoiceState().getChannel();
|
||||
if (channel != null) {
|
||||
VoiceChannel voiceChannel = channel.asVoiceChannel();
|
||||
lastVoiceChannel.put(user, voiceChannel);
|
||||
}
|
||||
VoiceChannel voiceChannel = lastVoiceChannel.get(user);
|
||||
if (voiceChannel == null) {
|
||||
return;
|
||||
}
|
||||
boolean joined = voiceChannel.getMembers().contains(event.getMember());
|
||||
if (!joined) {
|
||||
lastVoiceChannel.remove(user);
|
||||
}
|
||||
log.info("User \"{}\" {} voice channel \"{}\" in guild \"{}\"", user.getId(), joined ? "joined" : "left", voiceChannel.getName(), guild.getName());
|
||||
String description = new EmbedDescriptionBuilder("User %s Voice Channel".formatted(joined ? "Joined" : "Left"))
|
||||
.appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Channel: %s".formatted(voiceChannel.getAsMention()), true)
|
||||
.build();
|
||||
if (joined) {
|
||||
logFeature.sendLog(guild, LogType.VOICE_CHANNEL_JOIN, EmbedUtils.successEmbed().setDescription(description).build());
|
||||
return;
|
||||
}
|
||||
logFeature.sendLog(guild, LogType.VOICE_CHANNEL_LEAVE, EmbedUtils.errorEmbed().setDescription(description).build());
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
package cc.fascinated.bat.features.logging.listeners;
|
||||
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.logging.LogFeature;
|
||||
import cc.fascinated.bat.features.logging.LogType;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.service.DiscordService;
|
||||
import cc.fascinated.bat.service.GuildService;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.events.guild.GuildBanEvent;
|
||||
import net.dv8tion.jda.api.events.guild.GuildUnbanEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateTimeOutEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateAvatarEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent;
|
||||
import net.dv8tion.jda.api.events.user.update.UserUpdateNameEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
public class MemberListener implements EventListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(MemberListener.class);
|
||||
private final LogFeature logFeature;
|
||||
private final GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
public MemberListener(@NonNull ApplicationContext context, @NonNull GuildService guildService) {
|
||||
this.logFeature = context.getBean(LogFeature.class);
|
||||
this.guildService = guildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberJoin(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberJoinEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" joined the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MEMBER_JOIN, EmbedUtils.successEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Joined")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Username: %s".formatted(user.getDiscordUser().getName()), true)
|
||||
.appendLine("Joined Discord: <t:%s:R>".formatted(user.getDiscordUser().getTimeCreated().toEpochSecond()), true)
|
||||
.build())
|
||||
.setThumbnail(user.getDiscordUser().getEffectiveAvatarUrl())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberLeave(@NonNull BatGuild guild, BatUser user, @NonNull GuildMemberRemoveEvent event) {
|
||||
if (user == null || user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" left the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MEMBER_LEAVE, EmbedUtils.errorEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Left")
|
||||
.appendLine("Member: <@%s>".formatted(user.getId()), true)
|
||||
.appendLine("Username: %s".formatted(user.getName()), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberUpdateNickname(@NonNull BatGuild guild, @NonNull BatUser user, String oldName, String newName, @NonNull GuildMemberUpdateNicknameEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" changed their nickname from \"{}\" to \"{}\" in the guild \"{}\"", user.getName(), oldName, newName, guild.getDiscordGuild().getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MEMBER_NICKNAME_UPDATE, EmbedUtils.genericEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Nickname Updated")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Old Nickname: `%s`".formatted(oldName == null ? user.getName() : oldName), true)
|
||||
.appendLine("New Nickname: `%s`".formatted(newName == null ? "Removed Nickname" : newName), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" changed their global name from \"{}\" to \"{}\"", user.getName(), oldName, newName);
|
||||
|
||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||
BatGuild batGuild = guildService.getGuild(guild.getId());
|
||||
if (batGuild == null) continue;
|
||||
if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild
|
||||
|
||||
logFeature.sendLog(batGuild, LogType.MEMBER_GLOBAL_NAME_UPDATE, EmbedUtils.genericEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Name Updated")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Old Name: `%s`".formatted(oldName == null ? user.getName() : oldName), true)
|
||||
.appendLine("New Name: `%s`".formatted(newName == null ? "Removed Name" : newName), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserUpdateName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateNameEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" changed their username from \"{}\" to \"{}\"", user.getName(), oldName, newName);
|
||||
|
||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||
BatGuild batGuild = guildService.getGuild(guild.getId());
|
||||
if (batGuild == null) continue;
|
||||
if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild
|
||||
|
||||
logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Username Updated")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Old Username: `%s`".formatted(oldName), true)
|
||||
.appendLine("New Username: `%s`".formatted(newName), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserUpdateAvatar(@NonNull BatUser user, String oldAvatarUrl, String newAvatarUrl, @NonNull UserUpdateAvatarEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" changed their avatar to \"{}\"", user.getName(), newAvatarUrl);
|
||||
|
||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||
BatGuild batGuild = guildService.getGuild(guild.getId());
|
||||
if (batGuild == null) continue;
|
||||
if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild
|
||||
|
||||
logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Avatar Updated")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Old Avatar: %s".formatted(oldAvatarUrl == null ? "None" : "[avatar](%s)".formatted(oldAvatarUrl)), true)
|
||||
.appendLine("New Avatar: [avatar](%s)".formatted(newAvatarUrl), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberRoleAdd(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull List<Role> rolesAdded, @NonNull GuildMemberRoleAddEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" was given {} roles in the guild \"{}\"", user.getName(), rolesAdded.size(), guild.getDiscordGuild().getName());
|
||||
|
||||
StringBuilder roles = new StringBuilder();
|
||||
for (Role role : rolesAdded) {
|
||||
roles.append(role.getAsMention()).append(", ");
|
||||
}
|
||||
|
||||
String s = rolesAdded.size() > 1 ? "s" : "";
|
||||
logFeature.sendLog(guild, LogType.MEMBER_ROLE_UPDATE, EmbedUtils.successEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Role%s Added".formatted(s))
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Role%s Added: %s".formatted(s, roles.substring(0, roles.length() - 2)), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberRoleRemove(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull List<Role> rolesAdded, @NonNull GuildMemberRoleRemoveEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" had {} roles removed in the guild \"{}\"", user.getName(), rolesAdded.size(), guild.getDiscordGuild().getName());
|
||||
|
||||
StringBuilder roles = new StringBuilder();
|
||||
for (Role role : rolesAdded) {
|
||||
roles.append(role.getAsMention()).append(", ");
|
||||
}
|
||||
|
||||
String s = rolesAdded.size() > 1 ? "s" : "";
|
||||
logFeature.sendLog(guild, LogType.MEMBER_ROLE_UPDATE, EmbedUtils.errorEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Role%s Removed".formatted(s))
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Role%s Removed: %s".formatted(s, roles.substring(0, roles.length() - 2)), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberBan(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildBanEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" was banned from the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MEMBER_BAN, EmbedUtils.errorEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Banned")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberUnban(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildUnbanEvent event) {
|
||||
if (user.getDiscordUser().isBot()) return;
|
||||
log.info("User \"{}\" was unbanned from the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MEMBER_UNBAN, EmbedUtils.successEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Unbanned")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMemberTimeout(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberUpdateTimeOutEvent event) {
|
||||
OffsetDateTime timeoutEnd = event.getNewTimeOutEnd();
|
||||
if (user.getDiscordUser().isBot() || timeoutEnd == null) return;
|
||||
log.info("User \"{}\" was timed out until \"{}\"", user.getName(), timeoutEnd);
|
||||
|
||||
long seconds = timeoutEnd.toInstant().getEpochSecond();
|
||||
logFeature.sendLog(guild, LogType.MEMBER_TIMEOUT, EmbedUtils.errorEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Member Timed Out")
|
||||
.appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true)
|
||||
.appendLine("Timeout End: <t:%s>".formatted(seconds), true)
|
||||
.appendLine("Relative End: <t:%s:R>".formatted(seconds), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cc.fascinated.bat.features.logging.listeners;
|
||||
|
||||
import cc.fascinated.bat.common.EmbedDescriptionBuilder;
|
||||
import cc.fascinated.bat.common.EmbedUtils;
|
||||
import cc.fascinated.bat.event.EventListener;
|
||||
import cc.fascinated.bat.features.logging.LogFeature;
|
||||
import cc.fascinated.bat.features.logging.LogType;
|
||||
import cc.fascinated.bat.model.BatGuild;
|
||||
import cc.fascinated.bat.model.BatUser;
|
||||
import cc.fascinated.bat.model.DiscordMessage;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Fascinated (fascinated7)
|
||||
*/
|
||||
@Component
|
||||
@Log4j2
|
||||
public class MessageListener implements EventListener {
|
||||
private final LogFeature logFeature;
|
||||
|
||||
@Autowired
|
||||
public MessageListener(@NonNull ApplicationContext context) {
|
||||
this.logFeature = context.getBean(LogFeature.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) {
|
||||
if (user == null || user.getDiscordUser().isBot() || message.getAuthor().isBot()) return;
|
||||
log.info("User \"{}\" deleted a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MESSAGE_DELETE, EmbedUtils.errorEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Message Deleted")
|
||||
.appendLine("Author: %s".formatted(message.getAuthor().getAsMention()), true)
|
||||
.appendLine("Channel: %s".formatted(message.getChannel().getAsMention()), true)
|
||||
.appendLine("Content: %s".formatted(logFeature.formatContent(message.getContent())), true)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageEdit(@NonNull BatGuild guild, @NonNull BatUser user, DiscordMessage oldMessage,
|
||||
@NonNull DiscordMessage newMessage, @NonNull MessageUpdateEvent event) {
|
||||
if (user.getDiscordUser().isBot() || newMessage.getAuthor().isBot() || oldMessage == null) return;
|
||||
log.info("User \"{}\" edited a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName());
|
||||
|
||||
logFeature.sendLog(guild, LogType.MESSAGE_EDIT, EmbedUtils.genericEmbed()
|
||||
.setDescription(new EmbedDescriptionBuilder("Message Edited")
|
||||
.appendLine("Author: %s".formatted(newMessage.getAuthor().getAsMention()), true)
|
||||
.appendLine("Channel: %s".formatted(newMessage.getChannel().getAsMention()), true)
|
||||
.appendLine("Old Content: %s".formatted(logFeature.formatContent(oldMessage.getContent())), true)
|
||||
.appendLine("New Content: %s".formatted(logFeature.formatContent(newMessage.getContent())), true)
|
||||
.appendLine("*[Jump to Message](%s)*".formatted(newMessage.getMessageUrl()), false)
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user