Skip to content

Commit f48a0c4

Browse files
Merge pull request #377 from danthe1st/qotw-leaderboard
QOTW leaderboard improvements
2 parents 9c504a1 + 8fa028b commit f48a0c4

File tree

14 files changed

+159
-131
lines changed

14 files changed

+159
-131
lines changed

src/main/java/net/javadiscord/javabot/data/config/guild/QOTWConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class QOTWConfig extends GuildConfigItem {
2222
private long submissionsForumChannelId;
2323
private long questionRoleId;
2424
private long qotwReviewRoleId;
25+
private long qotwChampionRoleId;
2526
private String submissionForumOngoingReviewTagName = "";
2627

2728
public NewsChannel getQuestionChannel() {
@@ -44,6 +45,10 @@ public Role getQOTWReviewRole() {
4445
return this.getGuild().getRoleById(this.qotwReviewRoleId);
4546
}
4647

48+
public Role getQOTWChampionRole() {
49+
return this.getGuild().getRoleById(this.qotwChampionRoleId);
50+
}
51+
4752
/**
4853
* Gets a {@link ForumTag} based on the specified name.
4954
*

src/main/java/net/javadiscord/javabot/systems/notification/QOTWNotificationService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void sendSubmissionDeclinedEmbed() {
6565
.setDescription(String.format(
6666
"""
6767
Your submission was marked as the best answer!
68-
You've been granted **`1 extra QOTW-Point`**! (total: %s)""", points))
68+
You've been granted **`1 extra QOTW-Point`**! (monthly total: %s)""", points))
6969
.build();
7070
}
7171

@@ -75,7 +75,7 @@ public void sendSubmissionDeclinedEmbed() {
7575
.setDescription(String.format(
7676
"""
7777
Your submission was accepted! %s
78-
You've been granted **`1 QOTW-Point`**! (total: %s)""",
78+
You've been granted **`1 QOTW-Point`**! (monthly total: %s)""",
7979
systemsConfig.getEmojiConfig().getSuccessEmote(guild.getJDA()), points))
8080
.build();
8181
}

src/main/java/net/javadiscord/javabot/systems/qotw/QOTWPointsService.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import org.springframework.stereotype.Service;
1313
import org.springframework.transaction.annotation.Transactional;
1414

15+
import java.time.LocalDate;
16+
import java.time.YearMonth;
1517
import java.util.List;
1618
import java.util.Optional;
1719

@@ -33,14 +35,13 @@ public class QOTWPointsService {
3335
@Transactional
3436
public QOTWAccount getOrCreateAccount(long userId) throws DataAccessException {
3537
QOTWAccount account;
36-
Optional<QOTWAccount> optional = pointsRepository.getByUserId(userId);
38+
Optional<QOTWAccount> optional = pointsRepository.getByUserId(userId, getCurrentMonth());
3739
if (optional.isPresent()) {
3840
account = optional.get();
3941
} else {
4042
account = new QOTWAccount();
4143
account.setUserId(userId);
4244
account.setPoints(0);
43-
pointsRepository.insert(account);
4445
}
4546
return account;
4647
}
@@ -53,7 +54,7 @@ public QOTWAccount getOrCreateAccount(long userId) throws DataAccessException {
5354
*/
5455
public int getQOTWRank(long userId) {
5556
try{
56-
List<QOTWAccount> accounts = pointsRepository.sortByPoints();
57+
List<QOTWAccount> accounts = pointsRepository.sortByPoints(getCurrentMonth());
5758
return accounts.stream()
5859
.map(QOTWAccount::getUserId)
5960
.toList()
@@ -88,9 +89,10 @@ public long getPoints(long userId) {
8889
*/
8990
public List<Pair<QOTWAccount, Member>> getTopMembers(int n, Guild guild) {
9091
try {
91-
List<QOTWAccount> accounts = pointsRepository.sortByPoints();
92+
List<QOTWAccount> accounts = pointsRepository.sortByPoints(getCurrentMonth());
9293
return accounts.stream()
9394
.map(s -> new Pair<>(s, guild.getMemberById(s.getUserId())))
95+
.filter(p->p.first().getPoints() > 0)
9496
.filter(p -> p.second() != null)
9597
.limit(n)
9698
.toList();
@@ -109,7 +111,7 @@ public List<Pair<QOTWAccount, Member>> getTopMembers(int n, Guild guild) {
109111
*/
110112
public List<QOTWAccount> getTopAccounts(int amount, int page) {
111113
try {
112-
return pointsRepository.getTopAccounts(page, amount);
114+
return pointsRepository.getTopAccounts(getCurrentMonth(), page, amount);
113115
} catch (DataAccessException e) {
114116
ExceptionLogger.capture(e, getClass().getSimpleName());
115117
return List.of();
@@ -119,21 +121,24 @@ public List<QOTWAccount> getTopAccounts(int amount, int page) {
119121
/**
120122
* Increments a single user's QOTW-Points.
121123
*
122-
* @param userId The discord Id of the user.
124+
* @param userId The ID of the user whose points shall be incremented
123125
* @return The total points after the update.
124126
*/
125127
public long increment(long userId) {
126128
try {
127-
QOTWAccount account = getOrCreateAccount(userId);
128-
account.setPoints(account.getPoints() + 1);
129-
if (pointsRepository.update(account)) {
130-
return account.getPoints();
131-
} else {
132-
return 0;
133-
}
129+
LocalDate date=LocalDate.now();
130+
int points = pointsRepository.getPointsAtDate(userId, date)+1;
131+
pointsRepository.setPointsAtDate(userId, date, points);
132+
LocalDate month = getCurrentMonth();
133+
long newScore = pointsRepository.getByUserId(userId, month).map(QOTWAccount::getPoints).orElse(0L);
134+
return newScore;
134135
} catch (DataAccessException e) {
135136
ExceptionLogger.capture(e, getClass().getSimpleName());
136137
return 0;
137138
}
138139
}
140+
141+
public static LocalDate getCurrentMonth() {
142+
return YearMonth.from(LocalDate.now()).atDay(1);
143+
}
139144
}

src/main/java/net/javadiscord/javabot/systems/qotw/commands/QOTWAdminCommand.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import net.dv8tion.jda.api.interactions.commands.build.Commands;
55
import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData;
66
import net.javadiscord.javabot.systems.qotw.commands.qotw_points.IncrementPointsSubcommand;
7-
import net.javadiscord.javabot.systems.qotw.commands.qotw_points.SetPointsSubcommand;
87
import net.javadiscord.javabot.systems.qotw.commands.questions_queue.AddQuestionSubcommand;
98
import net.javadiscord.javabot.systems.qotw.commands.questions_queue.ListQuestionsSubcommand;
109
import net.javadiscord.javabot.systems.qotw.commands.questions_queue.RemoveQuestionSubcommand;
@@ -23,18 +22,17 @@ public class QOTWAdminCommand extends SlashCommand {
2322
* @param addQuestionSubcommand /qotw-admin questions-queue add
2423
* @param removeQuestionSubcommand /qotw-admin questions-queue remove
2524
* @param incrementPointsSubcommand /qotw-admin account increment
26-
* @param setPointsSubcommand /qotw-admin account set
2725
* @param reviewSubcommand /qotw-admin submissions review
2826
*/
29-
public QOTWAdminCommand(ListQuestionsSubcommand listQuestionsSubcommand, AddQuestionSubcommand addQuestionSubcommand, RemoveQuestionSubcommand removeQuestionSubcommand, IncrementPointsSubcommand incrementPointsSubcommand, SetPointsSubcommand setPointsSubcommand, QOTWReviewSubcommand reviewSubcommand) {
27+
public QOTWAdminCommand(ListQuestionsSubcommand listQuestionsSubcommand, AddQuestionSubcommand addQuestionSubcommand, RemoveQuestionSubcommand removeQuestionSubcommand, IncrementPointsSubcommand incrementPointsSubcommand, QOTWReviewSubcommand reviewSubcommand) {
3028
setCommandData(Commands.slash("qotw-admin", "Administrative tools for managing the Question of the Week.")
3129
.setDefaultPermissions(DefaultMemberPermissions.DISABLED)
3230
.setGuildOnly(true)
3331
);
3432
addSubcommands(reviewSubcommand);
3533
addSubcommandGroups(
3634
SubcommandGroup.of(new SubcommandGroupData("questions-queue", "Commands for interacting with the set of QOTW questions that are in queue."), listQuestionsSubcommand, addQuestionSubcommand, removeQuestionSubcommand),
37-
SubcommandGroup.of(new SubcommandGroupData("account", "Commands for interaction with Users Question of the Week points."), incrementPointsSubcommand, setPointsSubcommand),
35+
SubcommandGroup.of(new SubcommandGroupData("account", "Commands for interaction with Users Question of the Week points."), incrementPointsSubcommand),
3836
SubcommandGroup.of(new SubcommandGroupData("submissions", "Commands for managing QOTW Submissions."), reviewSubcommand)
3937
);
4038
}

src/main/java/net/javadiscord/javabot/systems/qotw/commands/qotw_points/SetPointsSubcommand.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/main/java/net/javadiscord/javabot/systems/qotw/dao/QuestionPointsRepository.java

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,89 +2,117 @@
22

33
import java.sql.ResultSet;
44
import java.sql.SQLException;
5+
import java.time.LocalDate;
56
import java.util.List;
67
import java.util.Optional;
78

8-
import org.jetbrains.annotations.NotNull;
99
import org.springframework.dao.DataAccessException;
1010
import org.springframework.dao.EmptyResultDataAccessException;
1111
import org.springframework.jdbc.core.JdbcTemplate;
1212
import org.springframework.stereotype.Repository;
1313

1414
import lombok.RequiredArgsConstructor;
15-
import lombok.extern.slf4j.Slf4j;
1615
import net.javadiscord.javabot.systems.qotw.model.QOTWAccount;
1716

1817
/**
1918
* Dao class that represents the QOTW_POINTS SQL Table.
2019
*/
21-
@Slf4j
2220
@RequiredArgsConstructor
2321
@Repository
2422
public class QuestionPointsRepository {
2523
private final JdbcTemplate jdbcTemplate;
2624

2725
/**
28-
* Inserts a new {@link QOTWAccount} if none exists.
26+
* Returns a {@link QOTWAccount} based on the given user Id.
2927
*
30-
* @param account The account to insert.
28+
* @param userId The discord Id of the user.
29+
* @param startDate The earliest date where points are counted
30+
* @return The {@link QOTWAccount} object.
3131
* @throws DataAccessException If an error occurs.
3232
*/
33-
public void insert(QOTWAccount account) throws DataAccessException {
34-
int rows = jdbcTemplate.update("INSERT INTO qotw_points (user_id, points) VALUES (?, ?)",
35-
account.getUserId(),account.getPoints());
36-
if (rows == 0) throw new DataAccessException("User was not inserted.") {};
37-
log.info("Inserted new QOTW-Account: {}", account);
33+
public Optional<QOTWAccount> getByUserId(long userId, LocalDate startDate) throws DataAccessException {
34+
try {
35+
return Optional.of(jdbcTemplate.queryForObject("SELECT SUM(points) AS points FROM qotw_points WHERE user_id = ? AND obtained_at >= ?",
36+
(rs, row)->{
37+
QOTWAccount acc=new QOTWAccount();
38+
acc.setUserId(userId);
39+
acc.setPoints(rs.getLong(1));
40+
return acc;
41+
},
42+
userId, startDate));
43+
}catch (EmptyResultDataAccessException e) {
44+
return Optional.empty();
45+
}
3846
}
3947

4048
/**
41-
* Returns a {@link QOTWAccount} based on the given user Id.
49+
* Gets the number points given to a user at a certain date.
4250
*
43-
* @param userId The discord Id of the user.
44-
* @return The {@link QOTWAccount} object.
45-
* @throws DataAccessException If an error occurs.
51+
* @param userId the ID of the user
52+
* @param date the date where the points are given to that user
53+
* @return the number of points the user obtained at the given date
4654
*/
47-
public Optional<QOTWAccount> getByUserId(long userId) throws DataAccessException {
55+
public int getPointsAtDate(long userId, LocalDate date) {
4856
try {
49-
return Optional.of(jdbcTemplate.queryForObject("SELECT * FROM qotw_points WHERE user_id = ?", (rs, row)->this.read(rs),userId));
57+
return jdbcTemplate.queryForObject("SELECT SUM(points) FROM qotw_points WHERE user_id = ? AND obtained_at >= ?",
58+
(rs, row) -> rs.getInt(1),
59+
userId, date);
5060
}catch (EmptyResultDataAccessException e) {
51-
return Optional.empty();
61+
return 0;
5262
}
5363
}
5464

5565
/**
56-
* Updates a single QOTW Account.
66+
* Sets the points of a user at a certain date.
5767
*
58-
* @param account The updated QOTW Account.
59-
* @return Whether the update affected rows.
60-
* @throws DataAccessException If an error occurs.
68+
* @param userId the id of the user to set to points of
69+
* @param date the date when the points should be marked as set
70+
* @param points the (new) number of points the user got at that date
71+
* @return {@code true} if a change was made, else {@code false}
6172
*/
62-
public boolean update(@NotNull QOTWAccount account) throws DataAccessException {
63-
return jdbcTemplate.update("UPDATE qotw_points SET points = ? WHERE user_id = ?",
64-
account.getPoints(), account.getUserId()) > 0;
73+
public boolean setPointsAtDate(long userId, LocalDate date, long points) {
74+
return jdbcTemplate.update("MERGE INTO qotw_points (user_id,obtained_at,points) KEY(user_id,obtained_at) VALUES (?,?,?)",
75+
userId, date, points) > 0;
6576
}
6677

6778
/**
6879
* Gets all {@link QOTWAccount} and sorts them by their points.
6980
*
81+
* @param startDate the minimum date points are considered
7082
* @return A {@link List} that contains all {@link QOTWAccount}s sorted by their points.
7183
* @throws DataAccessException If an error occurs.
7284
*/
73-
public List<QOTWAccount> sortByPoints() throws DataAccessException {
74-
return jdbcTemplate.query("SELECT * FROM qotw_points ORDER BY points DESC", (rs, row)->this.read(rs));
85+
public List<QOTWAccount> sortByPoints(LocalDate startDate) throws DataAccessException {
86+
return jdbcTemplate.query("SELECT user_id, SUM(points) FROM qotw_points WHERE obtained_at >= ? GROUP BY user_id ORDER BY SUM(points) DESC",
87+
(rs, row)->this.read(rs),
88+
startDate);
7589
}
7690

7791
/**
7892
* Gets a specified amount of {@link QOTWAccount}s.
7993
*
80-
* @param page The page.
81-
* @param size The amount of {@link QOTWAccount}s to return.
94+
* @param startDate the minimum date points are considered
95+
* @param page The page.
96+
* @param size The amount of {@link QOTWAccount}s to return.
8297
* @return A {@link List} containing the specified amount of {@link QOTWAccount}s.
8398
* @throws DataAccessException If an error occurs.
8499
*/
85-
public List<QOTWAccount> getTopAccounts(int page, int size) throws DataAccessException {
86-
return jdbcTemplate.query("SELECT * FROM qotw_points WHERE points > 0 ORDER BY points DESC LIMIT ? OFFSET ?", (rs,row)->this.read(rs),
87-
size, Math.max(0, (page * size) - size));
100+
public List<QOTWAccount> getTopAccounts(LocalDate startDate, int page, int size) throws DataAccessException {
101+
return jdbcTemplate.query("SELECT user_id, SUM(points) FROM qotw_points WHERE obtained_at >= ? AND points > 0 GROUP BY user_id ORDER BY SUM(points) DESC LIMIT ? OFFSET ?",
102+
(rs,row)->this.read(rs),
103+
startDate, size, Math.max(0, (page * size) - size));
104+
}
105+
106+
/**
107+
* Gets all users with a specific score starting from a specific date.
108+
* @param startDate the minimum date points are considered
109+
* @param score the score users should have in order to be considered
110+
* @return A {@link List} of all users with a specific total QOTW score
111+
*/
112+
public List<Long> getUsersWithSpecificScore(LocalDate startDate, long score){
113+
return jdbcTemplate.query("SELECT user_id FROM qotw_points WHERE obtained_at >= ? GROUP BY user_id HAVING SUM(points)=?",
114+
(rs,row)->rs.getLong(1),
115+
startDate, score);
88116
}
89117

90118
/**
@@ -96,8 +124,8 @@ public List<QOTWAccount> getTopAccounts(int page, int size) throws DataAccessExc
96124
*/
97125
private QOTWAccount read(ResultSet rs) throws SQLException {
98126
QOTWAccount account = new QOTWAccount();
99-
account.setUserId(rs.getLong("user_id"));
100-
account.setPoints(rs.getLong("points"));
127+
account.setUserId(rs.getLong(1));
128+
account.setPoints(rs.getLong(2));
101129
return account;
102130
}
103131
}

0 commit comments

Comments
 (0)