Skip to content

Commit db36d3f

Browse files
Started work on /help experience-leaderboard
1 parent 636cb70 commit db36d3f

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed

src/main/java/net/javadiscord/javabot/listener/InteractionListener.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import net.dv8tion.jda.api.hooks.ListenerAdapter;
88
import net.javadiscord.javabot.command.Responses;
99
import net.javadiscord.javabot.systems.help.HelpChannelInteractionManager;
10+
import net.javadiscord.javabot.systems.help.commands.subcommands.ExperienceLeaderboardSubcommand;
1011
import net.javadiscord.javabot.systems.moderation.ReportCommand;
1112
import net.javadiscord.javabot.systems.qotw.submissions.SubmissionInteractionManager;
1213
import net.javadiscord.javabot.systems.staff.self_roles.SelfRoleInteractionManager;
@@ -60,6 +61,7 @@ public void onButtonInteraction(ButtonInteractionEvent event) {
6061
if (event.getUser().isBot()) return;
6162
String[] id = event.getComponentId().split(":");
6263
switch (id[0]) {
64+
case "experience-leaderboard" -> ExperienceLeaderboardSubcommand.handleButtons(event, id);
6365
case "qotw-submission" -> SubmissionInteractionManager.handleButton(event, id);
6466
case "resolve-report" -> new ReportCommand().markAsResolved(event, id[1]);
6567
case "self-role" -> SelfRoleInteractionManager.handleButton(event, id);

src/main/java/net/javadiscord/javabot/systems/help/commands/HelpCommandHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.javadiscord.javabot.systems.help.commands;
22

33
import net.javadiscord.javabot.command.DelegatingCommandHandler;
4+
import net.javadiscord.javabot.systems.help.commands.subcommands.ExperienceLeaderboardSubcommand;
45
import net.javadiscord.javabot.systems.help.commands.subcommands.HelpAccountSubcommand;
56
import net.javadiscord.javabot.systems.help.commands.subcommands.ThanksLeaderboardSubcommand;
67

@@ -15,5 +16,6 @@ public class HelpCommandHandler extends DelegatingCommandHandler {
1516
public HelpCommandHandler() {
1617
this.addSubcommand("account", new HelpAccountSubcommand());
1718
this.addSubcommand("thanks-leaderboard", new ThanksLeaderboardSubcommand());
19+
this.addSubcommand("experience-leaderboard", new ExperienceLeaderboardSubcommand());
1820
}
1921
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package net.javadiscord.javabot.systems.help.commands.subcommands;
2+
3+
import net.dv8tion.jda.api.EmbedBuilder;
4+
import net.dv8tion.jda.api.entities.Emoji;
5+
import net.dv8tion.jda.api.entities.Guild;
6+
import net.dv8tion.jda.api.entities.MessageEmbed;
7+
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
8+
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
9+
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
10+
import net.dv8tion.jda.api.interactions.components.ActionRow;
11+
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
12+
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
13+
import net.dv8tion.jda.internal.interactions.component.ButtonImpl;
14+
import net.javadiscord.javabot.Bot;
15+
import net.javadiscord.javabot.command.ResponseException;
16+
import net.javadiscord.javabot.command.interfaces.SlashCommand;
17+
import net.javadiscord.javabot.data.h2db.DbHelper;
18+
import net.javadiscord.javabot.systems.help.dao.HelpAccountRepository;
19+
import net.javadiscord.javabot.systems.help.model.HelpAccount;
20+
21+
import java.sql.SQLException;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
/**
26+
* Command that generates a leaderboard based on the help channel experience.
27+
*/
28+
public class ExperienceLeaderboardSubcommand implements SlashCommand {
29+
30+
private static final int PAGE_SIZE = 5;
31+
32+
@Override
33+
public ReplyCallbackAction handleSlashCommandInteraction(SlashCommandInteractionEvent event) throws ResponseException {
34+
int page = event.getOption("page", 1, OptionMapping::getAsInt);
35+
DbHelper.doDaoAction(HelpAccountRepository::new, dao ->
36+
event.getHook().sendMessageEmbeds(buildExperienceLeaderboard(event.getGuild(), dao, page))
37+
.addActionRows(buildPageControls(page))
38+
.queue());
39+
return event.deferReply(false);
40+
}
41+
42+
/**
43+
* Handles all Button Interactions that regard this command.
44+
*
45+
* @param event The {@link ButtonInteractionEvent} that was fired upon use.
46+
* @param id The component's id, split by ":".
47+
*/
48+
public static void handleButtons(ButtonInteractionEvent event, String[] id) {
49+
event.deferEdit().queue();
50+
DbHelper.doDaoAction(HelpAccountRepository::new, dao -> {
51+
int page = Integer.parseInt(id[2]);
52+
switch (id[1]) {
53+
case "left" -> page--;
54+
case "right" -> page++;
55+
}
56+
int maxPage = dao.getTotalRankedAccounts() / PAGE_SIZE;
57+
if (page <= 0) page = maxPage;
58+
if (page > maxPage) page = 1;
59+
event.getHook().editOriginalEmbeds(buildExperienceLeaderboard(event.getGuild(), dao, page))
60+
.setActionRows(buildPageControls(page))
61+
.queue();
62+
});
63+
}
64+
65+
private static MessageEmbed buildExperienceLeaderboard(Guild guild, HelpAccountRepository dao, int page) throws SQLException {
66+
int maxPage = dao.getTotalRankedAccounts() / PAGE_SIZE;
67+
List<HelpAccount> accounts = dao.getAccountsWithRank(Math.min(page, maxPage), PAGE_SIZE);
68+
EmbedBuilder builder = new EmbedBuilder()
69+
.setTitle("Experience Leaderboard")
70+
.setColor(Bot.config.get(guild).getSlashCommand().getDefaultColor())
71+
.setFooter(String.format("Page %s/%s", Math.min(page, maxPage), maxPage));
72+
accounts.forEach(account -> {
73+
Map.Entry<Long, Double> currentRole = account.getCurrentExperienceGoal(guild);
74+
builder.addField(
75+
// TODO: implement without using blocking complete calls
76+
String.format("**%s.** %s", (accounts.indexOf(account) + 1) + (page - 1) * PAGE_SIZE, guild.getJDA().retrieveUserById(account.getUserId()).complete().getAsTag()),
77+
String.format("<@&%s>: `%.0f XP`\n", currentRole.getKey(), account.getExperience()),
78+
false);
79+
});
80+
return builder.build();
81+
}
82+
83+
private static ActionRow buildPageControls(int currentPage) {
84+
return ActionRow.of(
85+
new ButtonImpl("experience-leaderboard:left:" + currentPage, "", ButtonStyle.SECONDARY, false, Emoji.fromUnicode("⬅")),
86+
new ButtonImpl("experience-leaderboard:right:" + currentPage, "", ButtonStyle.SECONDARY, false, Emoji.fromUnicode("➡"))
87+
);
88+
}
89+
}

src/main/java/net/javadiscord/javabot/systems/help/dao/HelpAccountRepository.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
import lombok.RequiredArgsConstructor;
44
import lombok.extern.slf4j.Slf4j;
5+
import net.dv8tion.jda.api.entities.Guild;
6+
import net.javadiscord.javabot.Bot;
7+
import net.javadiscord.javabot.data.config.guild.HelpConfig;
58
import net.javadiscord.javabot.systems.help.model.HelpAccount;
69

710
import java.sql.Connection;
811
import java.sql.PreparedStatement;
912
import java.sql.ResultSet;
1013
import java.sql.SQLException;
14+
import java.util.ArrayList;
15+
import java.util.List;
1116
import java.util.Optional;
1217

1318
/**
@@ -66,6 +71,40 @@ public Optional<HelpAccount> getByUserId(long userId) throws SQLException {
6671
}
6772
}
6873

74+
/**
75+
* Gets as many Accounts as specified.
76+
*
77+
* @param page The page.
78+
* @param size The amount of account to return.
79+
* @return A {@link List} containing the specified amount of {@link HelpAccount}s.
80+
* @throws SQLException If an error occurs.
81+
*/
82+
public List<HelpAccount> getAccountsWithRank(int page, int size) throws SQLException {
83+
String sql = "SELECT * FROM help_account WHERE experience > 0 ORDER BY experience DESC LIMIT %d OFFSET %d";
84+
PreparedStatement stmt = con.prepareStatement(String.format(sql, size, (page * size) - size));
85+
ResultSet rs = stmt.executeQuery();
86+
List<HelpAccount> accounts = new ArrayList<>(size);
87+
while (rs.next()) {
88+
accounts.add(this.read(rs));
89+
}
90+
stmt.close();
91+
return accounts;
92+
}
93+
94+
/**
95+
* Gets the total amount of {@link HelpAccount}s stored in the database, that have more than 0 experience.
96+
*
97+
* @return The amount, as an {@link Integer}.
98+
* @throws SQLException If an error occurs.
99+
*/
100+
public int getTotalRankedAccounts() throws SQLException {
101+
try (PreparedStatement s = con.prepareStatement("SELECT COUNT(*) FROM help_account WHERE experience > 0")) {
102+
ResultSet rs = s.executeQuery();
103+
if (rs.next()) return rs.getInt(1);
104+
return 0;
105+
}
106+
}
107+
69108
/**
70109
* Removes the specified amount of experience from all {@link HelpAccount}s.
71110
*

src/main/resources/commands/slash/help.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
- name: thanks-leaderboard
2626
description: Show a leaderboard of the most thanked users.
2727

28+
# /help experience-leaderboard
29+
- name: experience-leaderboard
30+
description: Show a leaderboard of the users with the most help-experience.
31+
options:
32+
- name: page
33+
description: The page of results to show. By default it starts at 1.
34+
type: INTEGER
35+
required: false
36+
2837
handler: net.javadiscord.javabot.systems.help.commands.HelpCommandHandler
2938

3039

0 commit comments

Comments
 (0)