Compare commits
	
		
			2 commits
		
	
	
		
			
				269c44c065
			
			...
			
				bf7aafad0c
			
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						
							
							
								
							
							
	
	
	bf7aafad0c | 
						
						
							||
| 
							 | 
						
							
							
								
							
							
	
	
	4fc3b58ad1 | 
						
						
							
					 10 changed files with 75 additions and 433 deletions
				
			
		| 
						 | 
					@ -13,7 +13,6 @@ public class Config {
 | 
				
			||||||
    @SuppressWarnings("unused") private String token;
 | 
					    @SuppressWarnings("unused") private String token;
 | 
				
			||||||
    @SuppressWarnings("unused") private String prefix;
 | 
					    @SuppressWarnings("unused") private String prefix;
 | 
				
			||||||
    @SuppressWarnings("unused") private DBConfig mariadb;
 | 
					    @SuppressWarnings("unused") private DBConfig mariadb;
 | 
				
			||||||
    @SuppressWarnings("unused") private boolean levelling = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns the configuration object for this bot
 | 
					     * Returns the configuration object for this bot
 | 
				
			||||||
| 
						 | 
					@ -37,7 +36,6 @@ public class Config {
 | 
				
			||||||
        return token;
 | 
					        return token;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public String getPrefix() { return prefix; }
 | 
					    public String getPrefix() { return prefix; }
 | 
				
			||||||
    public boolean getLevelling() { return levelling; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public DBConfig getDbConfig() {
 | 
					    public DBConfig getDbConfig() {
 | 
				
			||||||
        return mariadb;
 | 
					        return mariadb;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,8 +6,6 @@ import net.dv8tion.jda.api.JDA;
 | 
				
			||||||
import net.dv8tion.jda.api.JDABuilder;
 | 
					import net.dv8tion.jda.api.JDABuilder;
 | 
				
			||||||
import net.dv8tion.jda.api.entities.*;
 | 
					import net.dv8tion.jda.api.entities.*;
 | 
				
			||||||
import net.dv8tion.jda.api.requests.GatewayIntent;
 | 
					import net.dv8tion.jda.api.requests.GatewayIntent;
 | 
				
			||||||
import net.hypr.doki.listeners.LevellingListener;
 | 
					 | 
				
			||||||
import org.apache.commons.dbcp2.BasicDataSource;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
| 
						 | 
					@ -16,7 +14,6 @@ public class Doki {
 | 
				
			||||||
    private static final Logger log = Logging.getLogger();
 | 
					    private static final Logger log = Logging.getLogger();
 | 
				
			||||||
    private static JDA jda;
 | 
					    private static JDA jda;
 | 
				
			||||||
    private static Config config;
 | 
					    private static Config config;
 | 
				
			||||||
    private static final BasicDataSource dataSource = new BasicDataSource();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Doki(JDA jda, Config config) {
 | 
					    private Doki(JDA jda, Config config) {
 | 
				
			||||||
        Doki.jda = jda;
 | 
					        Doki.jda = jda;
 | 
				
			||||||
| 
						 | 
					@ -27,7 +24,6 @@ public class Doki {
 | 
				
			||||||
        return jda;
 | 
					        return jda;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public static String getPrefix() { return config.getPrefix(); }
 | 
					    public static String getPrefix() { return config.getPrefix(); }
 | 
				
			||||||
    public static BasicDataSource getDataSource() { return dataSource; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void start() throws IOException, InterruptedException {
 | 
					    public static void start() throws IOException, InterruptedException {
 | 
				
			||||||
        config = Config.readConfig();
 | 
					        config = Config.readConfig();
 | 
				
			||||||
| 
						 | 
					@ -38,19 +34,6 @@ public class Doki {
 | 
				
			||||||
                .build()
 | 
					                .build()
 | 
				
			||||||
                .awaitReady();
 | 
					                .awaitReady();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Connect to the DB
 | 
					 | 
				
			||||||
        if (config.getLevelling()) {
 | 
					 | 
				
			||||||
            Config.DBConfig dbConfig = config.getDbConfig();
 | 
					 | 
				
			||||||
            dataSource.setDriverClassName("org.mariadb.jdbc.Driver");
 | 
					 | 
				
			||||||
            dataSource.setUrl("jdbc:mariadb://" + dbConfig.getHost() + ":" + dbConfig.getPortNumber() + "/" + dbConfig.getDatabase());
 | 
					 | 
				
			||||||
            dataSource.setUsername(dbConfig.getUser());
 | 
					 | 
				
			||||||
            dataSource.setPassword(dbConfig.getPassword());
 | 
					 | 
				
			||||||
            dataSource.setMaxTotal(10);
 | 
					 | 
				
			||||||
            dataSource.setMaxIdle(5);
 | 
					 | 
				
			||||||
            dataSource.setMinIdle(2);
 | 
					 | 
				
			||||||
            dataSource.setInitialSize(10);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Print some information about the bot
 | 
					        // Print some information about the bot
 | 
				
			||||||
        log.info("Bot connected as {}", jda.getSelfUser().getAsTag());
 | 
					        log.info("Bot connected as {}", jda.getSelfUser().getAsTag());
 | 
				
			||||||
        log.info("The bot is present in the following guilds:");
 | 
					        log.info("The bot is present in the following guilds:");
 | 
				
			||||||
| 
						 | 
					@ -68,11 +51,6 @@ public class Doki {
 | 
				
			||||||
            CommandsBuilder.newBuilder(437970062922612737L)
 | 
					            CommandsBuilder.newBuilder(437970062922612737L)
 | 
				
			||||||
                    .textCommandBuilder(textCommandsBuilder -> textCommandsBuilder.addPrefix(getPrefix()))
 | 
					                    .textCommandBuilder(textCommandsBuilder -> textCommandsBuilder.addPrefix(getPrefix()))
 | 
				
			||||||
                    .build(jda, "net.hypr.doki.commands"); //Registering listeners is taken care of by the lib
 | 
					                    .build(jda, "net.hypr.doki.commands"); //Registering listeners is taken care of by the lib
 | 
				
			||||||
            if (config.getLevelling()) {
 | 
					 | 
				
			||||||
                jda.addEventListener(new LevellingListener());
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                log.info("Levelling is disabled");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            log.error("Failed to start the bot", e);
 | 
					            log.error("Failed to start the bot", e);
 | 
				
			||||||
            System.exit(-1);
 | 
					            System.exit(-1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,56 +0,0 @@
 | 
				
			||||||
package net.hypr.doki.commands.levelling;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.annotations.CommandMarker;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.CommandEvent;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.TextCommand;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.Category;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.Description;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.JDATextCommand;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.EmbedBuilder;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.JDA;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.entities.User;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.DBUtils;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.UserRecord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.awt.*;
 | 
					 | 
				
			||||||
import java.sql.SQLException;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@CommandMarker
 | 
					 | 
				
			||||||
@Category("Levelling")
 | 
					 | 
				
			||||||
@Description("Get the global leaderboard")
 | 
					 | 
				
			||||||
public class Leaderboard extends TextCommand {
 | 
					 | 
				
			||||||
    @JDATextCommand(name = "leaderboard", order = 1, aliases = { "lb" })
 | 
					 | 
				
			||||||
    public void execute(CommandEvent event) throws SQLException {
 | 
					 | 
				
			||||||
        List<UserRecord> userRecords = DBUtils.getAllUserRecords(event.getGuild().getIdLong());
 | 
					 | 
				
			||||||
        // Sort the leaderboard highest level first
 | 
					 | 
				
			||||||
        userRecords.sort((o1, o2) -> o2.totalXp - o1.totalXp);
 | 
					 | 
				
			||||||
        EmbedBuilder whoIsEmbed = buildLeaderboardEmbed(userRecords, event);
 | 
					 | 
				
			||||||
        event.reply(whoIsEmbed.build()).queue();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private EmbedBuilder buildLeaderboardEmbed(List<UserRecord> userRecords , CommandEvent event) {
 | 
					 | 
				
			||||||
        StringBuilder leaderboard = new StringBuilder();
 | 
					 | 
				
			||||||
        JDA jda = event.getJDA();
 | 
					 | 
				
			||||||
        int idx = 1;
 | 
					 | 
				
			||||||
        for (UserRecord record : userRecords) {
 | 
					 | 
				
			||||||
            User user = jda.retrieveUserById(record.user_id).complete();
 | 
					 | 
				
			||||||
            leaderboard
 | 
					 | 
				
			||||||
                    .append("**")
 | 
					 | 
				
			||||||
                    .append(idx)
 | 
					 | 
				
			||||||
                    .append(".** ")
 | 
					 | 
				
			||||||
                    .append(user.getName())
 | 
					 | 
				
			||||||
                    .append(" - ")
 | 
					 | 
				
			||||||
                    .append(record.level)
 | 
					 | 
				
			||||||
                    .append(" (")
 | 
					 | 
				
			||||||
                    .append(record.totalXp)
 | 
					 | 
				
			||||||
                    .append(" Total XP)\n");
 | 
					 | 
				
			||||||
            idx += 1;
 | 
					 | 
				
			||||||
            if (idx > 10) break; // Break out after 10 records is reached
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return new EmbedBuilder()
 | 
					 | 
				
			||||||
                .setTitle(event.getGuild().getName() + " Leaderboard")
 | 
					 | 
				
			||||||
                .setDescription(leaderboard)
 | 
					 | 
				
			||||||
                .setColor(new Color(210,138,39));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,46 +0,0 @@
 | 
				
			||||||
package net.hypr.doki.commands.levelling;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.annotations.CommandMarker;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.BaseCommandEvent;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.CommandEvent;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.TextCommand;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.Category;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.Description;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.JDATextCommand;
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.prefixed.annotations.TextOption;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.EmbedBuilder;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.entities.Member;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.DBUtils;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.UserRecord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.sql.SQLException;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@CommandMarker
 | 
					 | 
				
			||||||
@Category("Levelling")
 | 
					 | 
				
			||||||
@Description("Get a user's rank")
 | 
					 | 
				
			||||||
public class Rank extends TextCommand {
 | 
					 | 
				
			||||||
    @JDATextCommand(name = "rank", order = 1)
 | 
					 | 
				
			||||||
    public void execute(BaseCommandEvent event, @TextOption Member member) throws SQLException {
 | 
					 | 
				
			||||||
        UserRecord userRecord = DBUtils.getUserRecord(member.getIdLong(), event.getGuild().getIdLong());
 | 
					 | 
				
			||||||
        EmbedBuilder rankEmbed = buildRankEmbed(member, userRecord);
 | 
					 | 
				
			||||||
        event.reply(rankEmbed.build()).queue();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @JDATextCommand(name = "rank", order = 2)
 | 
					 | 
				
			||||||
    public void execute(CommandEvent event) throws SQLException {
 | 
					 | 
				
			||||||
        UserRecord userRecord = DBUtils.getUserRecord(event.getMember().getIdLong(), event.getGuild().getIdLong());
 | 
					 | 
				
			||||||
        EmbedBuilder whoIsEmbed = buildRankEmbed(event.getMember(), userRecord);
 | 
					 | 
				
			||||||
        event.reply(whoIsEmbed.build()).queue();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private EmbedBuilder buildRankEmbed(Member user, UserRecord userRecord) {
 | 
					 | 
				
			||||||
        int xpToNextLevel = (((userRecord.level + 1) * 5) * 40) - userRecord.xp;
 | 
					 | 
				
			||||||
        return new EmbedBuilder()
 | 
					 | 
				
			||||||
                .setAuthor(user.getUser().getName(), null, user.getEffectiveAvatarUrl())
 | 
					 | 
				
			||||||
                .setThumbnail(user.getEffectiveAvatarUrl())
 | 
					 | 
				
			||||||
                .addField("Level", String.valueOf(userRecord.level), true)
 | 
					 | 
				
			||||||
                .addField("XP", String.valueOf(userRecord.xp), true)
 | 
					 | 
				
			||||||
                .addField("XP Until level " + (userRecord.level + 1), String.valueOf(xpToNextLevel), true)
 | 
					 | 
				
			||||||
                .setColor(user.getColor());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										48
									
								
								src/main/java/net/hypr/doki/commands/moderation/Mute.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/main/java/net/hypr/doki/commands/moderation/Mute.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					package net.hypr.doki.commands.moderation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.annotations.CommandMarker;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.BaseCommandEvent;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.CommandEvent;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.TextCommand;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.annotations.Category;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.annotations.Description;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.annotations.JDATextCommand;
 | 
				
			||||||
 | 
					import com.freya02.botcommands.api.prefixed.annotations.TextOption;
 | 
				
			||||||
 | 
					import net.dv8tion.jda.api.Permission;
 | 
				
			||||||
 | 
					import net.dv8tion.jda.api.entities.Member;
 | 
				
			||||||
 | 
					import net.dv8tion.jda.api.entities.Message;
 | 
				
			||||||
 | 
					import net.dv8tion.jda.api.interactions.commands.Command;
 | 
				
			||||||
 | 
					import net.hypr.doki.utils.DurationUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.time.Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandMarker
 | 
				
			||||||
 | 
					@Category("Moderation")
 | 
				
			||||||
 | 
					@Description("Mutes a user for a specified amount of time")
 | 
				
			||||||
 | 
					public class Mute extends TextCommand {
 | 
				
			||||||
 | 
					    @JDATextCommand(name = "mute", order = 1)
 | 
				
			||||||
 | 
					    public void execute(BaseCommandEvent event, @TextOption(example = "<@437970062922612737>") Member member, @TextOption(example = "30m") String duration) {
 | 
				
			||||||
 | 
					        Member commandExecutor = event.getMember();
 | 
				
			||||||
 | 
					        if (!commandExecutor.hasPermission(Permission.KICK_MEMBERS)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Duration timeoutDuration;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					             timeoutDuration = DurationUtils.parseDuration(duration);
 | 
				
			||||||
 | 
					        } catch (IllegalArgumentException ex) {
 | 
				
			||||||
 | 
					            event.reply("Invalid duration format!").queue();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (Math.abs(timeoutDuration.toDays()) > 28) {
 | 
				
			||||||
 | 
					            event.reply("Duration must be less than 28 days!").queue();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        member.timeoutFor(timeoutDuration).queue();
 | 
				
			||||||
 | 
					        event.reply("Muted " + member.getAsMention() + " (" + member.getEffectiveName() + ") for " + duration).queue();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @JDATextCommand(name = "mute", order = 2)
 | 
				
			||||||
 | 
					    public void execute(CommandEvent event) {
 | 
				
			||||||
 | 
					        event.reply("You must specify a user and duration!").queue();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,74 +0,0 @@
 | 
				
			||||||
package net.hypr.doki.listeners;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.Logging;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.entities.Guild;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.entities.User;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
 | 
					 | 
				
			||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
 | 
					 | 
				
			||||||
import net.hypr.doki.Doki;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.DBUtils;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.LevellingUtils;
 | 
					 | 
				
			||||||
import net.hypr.doki.utils.UserRecord;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.sql.SQLException;
 | 
					 | 
				
			||||||
import java.time.Duration;
 | 
					 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class LevellingListener extends ListenerAdapter {
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void onMessageReceived(MessageReceivedEvent event) {
 | 
					 | 
				
			||||||
        Logger log = Logging.getLogger();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Ignore the message if one of the following conditions is met:
 | 
					 | 
				
			||||||
          - Message is from self user
 | 
					 | 
				
			||||||
          - Message is from a bot
 | 
					 | 
				
			||||||
          - Message is command (starts with bot prefix)
 | 
					 | 
				
			||||||
          - Message is a Direct Message to the bot
 | 
					 | 
				
			||||||
        */
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            event.getGuild();
 | 
					 | 
				
			||||||
        } catch (IllegalStateException ex) {
 | 
					 | 
				
			||||||
            log.debug("Ignoring direct message with ID {}", event.getMessageId());
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
                Doki.getJDA().getSelfUser().getId().equals(event.getAuthor().getId()) ||
 | 
					 | 
				
			||||||
                        event.getAuthor().isBot() ||
 | 
					 | 
				
			||||||
                        event.getMessage().getContentStripped().startsWith(Doki.getPrefix())
 | 
					 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
            log.debug("Ignoring self/bot message with ID {}", event.getMessageId());
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        User user = event.getAuthor();
 | 
					 | 
				
			||||||
        Guild guild = event.getGuild();
 | 
					 | 
				
			||||||
        boolean userIsInDb = DBUtils.doesUserRecordExist(user.getIdLong(), guild.getIdLong());
 | 
					 | 
				
			||||||
        if (userIsInDb) {
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                UserRecord rec = DBUtils.getUserRecord(user.getIdLong(), guild.getIdLong());
 | 
					 | 
				
			||||||
                Duration timeSinceLastMessage = Duration.between(
 | 
					 | 
				
			||||||
                        rec.lastMessage.toLocalDateTime(),
 | 
					 | 
				
			||||||
                        LocalDateTime.now()
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                if (timeSinceLastMessage.compareTo(Duration.ofHours(1)) > 0) {
 | 
					 | 
				
			||||||
                    // it has been over an hour since the user last sent a message that affected XP
 | 
					 | 
				
			||||||
                    LevellingUtils.incrementXp(log, rec);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    log.debug("Ignoring message ID {} as not enough time has passed", event.getMessageId());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } catch (SQLException e) {
 | 
					 | 
				
			||||||
                throw new RuntimeException(e);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            log.info("No record of user ID {} in server {}, creating blank record", user.getId(), guild.getId());
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                UserRecord rec = DBUtils.createUserRecord(user.getIdLong(), guild.getIdLong());
 | 
					 | 
				
			||||||
                LevellingUtils.incrementXp(log, rec);
 | 
					 | 
				
			||||||
            } catch (SQLException e) {
 | 
					 | 
				
			||||||
                throw new RuntimeException(e);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,154 +0,0 @@
 | 
				
			||||||
package net.hypr.doki.utils;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.freya02.botcommands.api.Logging;
 | 
					 | 
				
			||||||
import net.hypr.doki.Doki;
 | 
					 | 
				
			||||||
import org.apache.commons.dbcp2.BasicDataSource;
 | 
					 | 
				
			||||||
import org.apache.commons.dbutils.QueryRunner;
 | 
					 | 
				
			||||||
import org.apache.commons.dbutils.ResultSetHandler;
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.math.BigInteger;
 | 
					 | 
				
			||||||
import java.sql.*;
 | 
					 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.HashSet;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class DBUtils {
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Checks if the user record exists
 | 
					 | 
				
			||||||
     * @param user_id   User ID to search for
 | 
					 | 
				
			||||||
     * @param server_id Server ID to search for
 | 
					 | 
				
			||||||
     * @return Whether the record exists or not
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static boolean doesUserRecordExist(long user_id, long server_id) {
 | 
					 | 
				
			||||||
        Logger log = Logging.getLogger();
 | 
					 | 
				
			||||||
        BasicDataSource dataSource = Doki.getDataSource();
 | 
					 | 
				
			||||||
        QueryRunner qr = new QueryRunner(dataSource);
 | 
					 | 
				
			||||||
        ResultSetHandler<Set<BigInteger>> resultSetHandler = rs -> {
 | 
					 | 
				
			||||||
            Set<BigInteger> rows = new HashSet<>();
 | 
					 | 
				
			||||||
            while (rs.next()) {
 | 
					 | 
				
			||||||
                rows.add(BigInteger.valueOf(rs.getLong(1)));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return rows;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Find out if the user is already in the DB
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            log.debug("Searching DB for (usr{},srv:{})", user_id, server_id);
 | 
					 | 
				
			||||||
            Set<BigInteger> foundIds = qr.query("SELECT user_id FROM users WHERE user_id = " + user_id + " AND server_id = " + server_id, resultSetHandler);
 | 
					 | 
				
			||||||
            log.debug("Matching records: {}", foundIds.size());
 | 
					 | 
				
			||||||
            return !foundIds.isEmpty();
 | 
					 | 
				
			||||||
        } catch (SQLException ignored) {
 | 
					 | 
				
			||||||
            log.debug("An SQL error occurred");
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Creates a new user record
 | 
					 | 
				
			||||||
     * @param user_id   The users ID
 | 
					 | 
				
			||||||
     * @param server_id The server ID
 | 
					 | 
				
			||||||
     * @throws SQLException A SQL exception
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static UserRecord createUserRecord(long user_id, long server_id) throws SQLException {
 | 
					 | 
				
			||||||
        Logger log = Logging.getLogger();
 | 
					 | 
				
			||||||
        log.info("Creating record (usr:{},srv:{})", user_id, server_id);
 | 
					 | 
				
			||||||
        BasicDataSource dataSource = Doki.getDataSource();
 | 
					 | 
				
			||||||
        Connection conn = dataSource.getConnection();
 | 
					 | 
				
			||||||
        PreparedStatement stmt = conn.prepareStatement(
 | 
					 | 
				
			||||||
                "INSERT INTO users (user_id, server_id, last_message) VALUES (?, ?, ?)"
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        stmt.setLong(1, user_id);
 | 
					 | 
				
			||||||
        stmt.setLong(2, server_id);
 | 
					 | 
				
			||||||
        stmt.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now()));
 | 
					 | 
				
			||||||
        stmt.execute();
 | 
					 | 
				
			||||||
        log.info("Record (usr:{},srv:{}) created!", user_id, server_id);
 | 
					 | 
				
			||||||
        return new UserRecord(user_id, server_id);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Updates a user record
 | 
					 | 
				
			||||||
     * @param user_id   User ID of the record to update
 | 
					 | 
				
			||||||
     * @param server_id Server ID of the record to update
 | 
					 | 
				
			||||||
     * @param now The current time
 | 
					 | 
				
			||||||
     * @param xp The new XP count
 | 
					 | 
				
			||||||
     * @param totalXp The new total XP count
 | 
					 | 
				
			||||||
     * @param level The new level
 | 
					 | 
				
			||||||
     * @throws SQLException A SQL exception
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static void updateUserRecord(long user_id, long server_id, Timestamp now, int xp, int totalXp, int level) throws SQLException {
 | 
					 | 
				
			||||||
        Logger log = Logging.getLogger();
 | 
					 | 
				
			||||||
        log.info("Updating record (usr:{},srv:{})", user_id, server_id);
 | 
					 | 
				
			||||||
        BasicDataSource dataSource = Doki.getDataSource();
 | 
					 | 
				
			||||||
        Connection conn = dataSource.getConnection();
 | 
					 | 
				
			||||||
        PreparedStatement stmt = conn.prepareStatement(
 | 
					 | 
				
			||||||
                "UPDATE users SET last_message = ?, xp = ?, total_xp = ?, level = ? WHERE user_id = ? AND server_id = ?"
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        stmt.setTimestamp(1, now);
 | 
					 | 
				
			||||||
        stmt.setInt(2, xp);
 | 
					 | 
				
			||||||
        stmt.setInt(3, totalXp);
 | 
					 | 
				
			||||||
        stmt.setInt(4, level);
 | 
					 | 
				
			||||||
        stmt.setLong(5, user_id);
 | 
					 | 
				
			||||||
        stmt.setLong(6, server_id);
 | 
					 | 
				
			||||||
        stmt.executeQuery();
 | 
					 | 
				
			||||||
        log.info("Updated record (usr:{},srv:{})!", user_id, server_id);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Gets a user record
 | 
					 | 
				
			||||||
     * @param user_id   The User ID of the record to get
 | 
					 | 
				
			||||||
     * @param server_id The Server ID of the record to get
 | 
					 | 
				
			||||||
     * @return The found UserRecord
 | 
					 | 
				
			||||||
     * @throws SQLException A SQL exception
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static UserRecord getUserRecord(long user_id, long server_id) throws SQLException {
 | 
					 | 
				
			||||||
        BasicDataSource dataSource = Doki.getDataSource();
 | 
					 | 
				
			||||||
        Connection conn = dataSource.getConnection();
 | 
					 | 
				
			||||||
        PreparedStatement stmt = conn.prepareStatement(
 | 
					 | 
				
			||||||
                "SELECT user_id, server_id, last_message, xp, total_xp, level FROM users WHERE user_id = ? AND server_id = ?"
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        stmt.setLong(1, user_id);
 | 
					 | 
				
			||||||
        stmt.setLong(2, server_id);
 | 
					 | 
				
			||||||
        ResultSet rs = stmt.executeQuery();
 | 
					 | 
				
			||||||
        rs.next();
 | 
					 | 
				
			||||||
        return new UserRecord(
 | 
					 | 
				
			||||||
                rs.getLong("user_id"),
 | 
					 | 
				
			||||||
                rs.getLong("server_id"),
 | 
					 | 
				
			||||||
                rs.getTimestamp("last_message"),
 | 
					 | 
				
			||||||
                rs.getInt("xp"),
 | 
					 | 
				
			||||||
                rs.getInt("total_xp"),
 | 
					 | 
				
			||||||
                rs.getInt("level")
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Get all user records for a server
 | 
					 | 
				
			||||||
     * @param server_id The Server ID
 | 
					 | 
				
			||||||
     * @return A List of UserRecords
 | 
					 | 
				
			||||||
     * @throws SQLException A SQL exception
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static List<UserRecord> getAllUserRecords(long server_id) throws SQLException {
 | 
					 | 
				
			||||||
        BasicDataSource dataSource = Doki.getDataSource();
 | 
					 | 
				
			||||||
        Connection conn = dataSource.getConnection();
 | 
					 | 
				
			||||||
        PreparedStatement stmt = conn.prepareStatement(
 | 
					 | 
				
			||||||
                "SELECT user_id, last_message, xp, total_xp, level FROM users WHERE server_id = ?"
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        stmt.setLong(1, server_id);
 | 
					 | 
				
			||||||
        ResultSet rs = stmt.executeQuery();
 | 
					 | 
				
			||||||
        List<UserRecord> userRecordList = new ArrayList<>();
 | 
					 | 
				
			||||||
        while (rs.next()) {
 | 
					 | 
				
			||||||
            userRecordList.add(new UserRecord(
 | 
					 | 
				
			||||||
                    rs.getLong("user_id"),
 | 
					 | 
				
			||||||
                    server_id,
 | 
					 | 
				
			||||||
                    rs.getTimestamp("last_message"),
 | 
					 | 
				
			||||||
                    rs.getInt("xp"),
 | 
					 | 
				
			||||||
                    rs.getInt("total_xp"),
 | 
					 | 
				
			||||||
                    rs.getInt("level")
 | 
					 | 
				
			||||||
            ));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return userRecordList;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										27
									
								
								src/main/java/net/hypr/doki/utils/DurationUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/main/java/net/hypr/doki/utils/DurationUtils.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					package net.hypr.doki.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.time.Duration;
 | 
				
			||||||
 | 
					import java.util.regex.Matcher;
 | 
				
			||||||
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class DurationUtils {
 | 
				
			||||||
 | 
					    private static final Pattern timePattern = Pattern.compile("(\\d+)(?:([dhms]))?");
 | 
				
			||||||
 | 
					    public static Duration parseDuration(String input) throws IllegalArgumentException {
 | 
				
			||||||
 | 
					        Matcher matcher = timePattern.matcher(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!matcher.matches()) {
 | 
				
			||||||
 | 
					            throw new IllegalArgumentException("Invalid duration format");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int value = Integer.parseInt(matcher.group(1));
 | 
				
			||||||
 | 
					        String unit = matcher.group(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return switch (unit == null || unit.isEmpty() ? "m" : unit.toLowerCase()) {
 | 
				
			||||||
 | 
					            case "d" -> Duration.ofDays(value);
 | 
				
			||||||
 | 
					            case "h" -> Duration.ofHours(value);
 | 
				
			||||||
 | 
					            case "m" -> Duration.ofMinutes(value);
 | 
				
			||||||
 | 
					            case "s" -> Duration.ofSeconds(value);
 | 
				
			||||||
 | 
					            default -> throw new IllegalArgumentException("Invalid unit");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,35 +0,0 @@
 | 
				
			||||||
package net.hypr.doki.utils;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.sql.SQLException;
 | 
					 | 
				
			||||||
import java.sql.Timestamp;
 | 
					 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					 | 
				
			||||||
import java.util.Random;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class LevellingUtils {
 | 
					 | 
				
			||||||
    public static void incrementXp(Logger logger, UserRecord userRecord) throws SQLException {
 | 
					 | 
				
			||||||
        Random random = new Random();
 | 
					 | 
				
			||||||
        // Random increment between 15 and 25
 | 
					 | 
				
			||||||
        int xpInc = (random.nextInt(10) + 16) * 3;
 | 
					 | 
				
			||||||
        int xpNew = userRecord.xp + xpInc;
 | 
					 | 
				
			||||||
        int totalXp = userRecord.xp + xpInc;
 | 
					 | 
				
			||||||
        int levelNew = userRecord.level;
 | 
					 | 
				
			||||||
        if (xpNew >= ((userRecord.level + 1) * 5) * 40) {
 | 
					 | 
				
			||||||
            levelNew ++;
 | 
					 | 
				
			||||||
            xpNew = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        DBUtils.updateUserRecord(
 | 
					 | 
				
			||||||
                userRecord.user_id,
 | 
					 | 
				
			||||||
                userRecord.server_id,
 | 
					 | 
				
			||||||
                Timestamp.valueOf(LocalDateTime.now()),
 | 
					 | 
				
			||||||
                xpNew,
 | 
					 | 
				
			||||||
                totalXp,
 | 
					 | 
				
			||||||
                levelNew
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        logger.info("Incremented {}'s XP in {} ({} -> {})", userRecord.user_id, userRecord.server_id, userRecord.xp, xpNew);
 | 
					 | 
				
			||||||
        if (levelNew > userRecord.level) {
 | 
					 | 
				
			||||||
            logger.info("Incremented {}'s level in {} ({} -> {})", userRecord.user_id, userRecord.server_id, userRecord.level, levelNew);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,44 +0,0 @@
 | 
				
			||||||
package net.hypr.doki.utils;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.sql.Timestamp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class UserRecord {
 | 
					 | 
				
			||||||
    public final long user_id;
 | 
					 | 
				
			||||||
    public final long server_id;
 | 
					 | 
				
			||||||
    public final Timestamp lastMessage;
 | 
					 | 
				
			||||||
    public final int xp;
 | 
					 | 
				
			||||||
    public int totalXp;
 | 
					 | 
				
			||||||
    public final int level;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Instantiates a new UserRecord
 | 
					 | 
				
			||||||
     * @param user_id   The User ID
 | 
					 | 
				
			||||||
     * @param server_id The Server/Guild ID
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public UserRecord (long user_id, long server_id) {
 | 
					 | 
				
			||||||
        this.user_id = user_id;
 | 
					 | 
				
			||||||
        this.server_id = server_id;
 | 
					 | 
				
			||||||
        this.lastMessage = new Timestamp(0);
 | 
					 | 
				
			||||||
        this.xp = 0;
 | 
					 | 
				
			||||||
        this.level = 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Instantiates a new UserRecord
 | 
					 | 
				
			||||||
     * @param user_id     The User ID
 | 
					 | 
				
			||||||
     * @param server_id   The Server/Guild ID
 | 
					 | 
				
			||||||
     * @param lastMessage The timestamp of the user's last message
 | 
					 | 
				
			||||||
     * @param xp          The user's XP
 | 
					 | 
				
			||||||
     * @param totalXp     The user's total XP
 | 
					 | 
				
			||||||
     * @param level       The user's level
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public UserRecord (long user_id, long server_id, Timestamp lastMessage, int xp, int totalXp, int level) {
 | 
					 | 
				
			||||||
        this.user_id = user_id;
 | 
					 | 
				
			||||||
        this.server_id = server_id;
 | 
					 | 
				
			||||||
        this.lastMessage = lastMessage;
 | 
					 | 
				
			||||||
        this.xp = xp;
 | 
					 | 
				
			||||||
        this.totalXp = totalXp;
 | 
					 | 
				
			||||||
        this.level = level;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue