Skip to content

Commit 2e4b90a

Browse files
committed
Address code review comments from @SquidXTV
- CakeDayListener.java: remove constructor JavaDoc - CakeDayRoutine.java: remove constructor JavaDoc - perf(findUserCakeDayFromDatabase): return one from DB - perf(CakeDayService): remove unnecessary call - Rename from handleUserLeft to removeUserCakeDay - perf(cakeDayRole): delegate role fetching to JDA - CakeDayService: make createMemberCakeDayQuery static - perf(CakeDayService): remove unneeded batch() call - CakeDayService: async insert member cake day to db - CakeDayService.java: rewrite removeRoleFromMembers() - perf: use Role that we have fetched for refreshing - CakeDayService: remove unnecessary call to get snowflake - perf: remove redundant check for if it's cake day - CakeDayService.java: simplify Optional unwrapping - CakeDayService.java: rename config to fullConfig - docs(CakeDayConfig): clarify with `@see` Signed-off-by: Chris Sdogkos <[email protected]>
1 parent 42ffceb commit 2e4b90a

File tree

4 files changed

+70
-102
lines changed

4 files changed

+70
-102
lines changed

application/src/main/java/org/togetherjava/tjbot/config/CakeDayConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
/**
88
* Configuration record for the Cake Day feature.
9+
*
10+
* @see org.togetherjava.tjbot.features.cakeday.CakeDayService
911
*/
1012
public record CakeDayConfig(
1113
@JsonProperty(value = "rolePattern", required = true) String rolePattern) {

application/src/main/java/org/togetherjava/tjbot/features/cakeday/CakeDayListener.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ public class CakeDayListener extends ListenerAdapter implements EventReceiver {
2020

2121
private final CakeDayService cakeDayService;
2222

23-
/**
24-
* Constructs a new CakeDayListener with the given {@link CakeDayService}.
25-
*
26-
* @param cakeDayService the {@link CakeDayService} to be used by this listener
27-
*/
2823
public CakeDayListener(CakeDayService cakeDayService) {
2924
this.cakeDayService = cakeDayService;
3025
}
@@ -79,6 +74,6 @@ public void onGuildMemberRemove(GuildMemberRemoveEvent event) {
7974
User user = event.getUser();
8075
Guild guild = event.getGuild();
8176

82-
cakeDayService.handleUserLeft(user, guild);
77+
cakeDayService.removeUserCakeDay(user, guild);
8378
}
8479
}

application/src/main/java/org/togetherjava/tjbot/features/cakeday/CakeDayRoutine.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ public class CakeDayRoutine implements Routine {
1717

1818
private final CakeDayService cakeDayService;
1919

20-
/**
21-
* Constructs a new {@link CakeDayRoutine} instance.
22-
*
23-
* @param cakeDayService an instance of the cake day service
24-
*/
2520
public CakeDayRoutine(CakeDayService cakeDayService) {
2621
this.cakeDayService = cakeDayService;
2722
}

application/src/main/java/org/togetherjava/tjbot/features/cakeday/CakeDayService.java

Lines changed: 67 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
import net.dv8tion.jda.api.entities.Member;
55
import net.dv8tion.jda.api.entities.Role;
66
import net.dv8tion.jda.api.entities.User;
7-
import net.dv8tion.jda.api.entities.UserSnowflake;
8-
import net.dv8tion.jda.api.requests.RestAction;
9-
import net.dv8tion.jda.api.utils.Result;
7+
import org.jetbrains.annotations.NotNull;
108
import org.jooq.Query;
119
import org.jooq.impl.DSL;
1210
import org.slf4j.Logger;
@@ -23,9 +21,6 @@
2321
import java.util.List;
2422
import java.util.Optional;
2523
import java.util.Set;
26-
import java.util.function.Predicate;
27-
import java.util.regex.Pattern;
28-
import java.util.stream.Collectors;
2924

3025
import static org.togetherjava.tjbot.db.generated.tables.CakeDays.CAKE_DAYS;
3126

@@ -37,29 +32,29 @@ public class CakeDayService {
3732
private static final DateTimeFormatter MONTH_DAY_FORMATTER =
3833
DateTimeFormatter.ofPattern("MM-dd");
3934
private final Set<String> cakeDaysCache = new HashSet<>();
40-
private final Predicate<String> cakeDayRolePredicate;
41-
private final CakeDayConfig config;
35+
private final String cakeDayRolePattern;
36+
private final CakeDayConfig fullConfig;
4237
private final Database database;
4338

4439
/**
4540
* Constructs a {@link CakeDayService} with the given configuration and database.
4641
*
47-
* @param config the configuration for cake day management
42+
* @param fullConfig the full configuration for cake day management
4843
* @param database the database for storing cake day information
4944
*/
50-
public CakeDayService(Config config, Database database) {
51-
this.config = config.getCakeDayConfig();
45+
public CakeDayService(Config fullConfig, Database database) {
46+
this.fullConfig = fullConfig.getCakeDayConfig();
5247
this.database = database;
5348

54-
this.cakeDayRolePredicate = Pattern.compile(this.config.rolePattern()).asPredicate();
49+
this.cakeDayRolePattern = this.fullConfig.rolePattern();
5550
}
5651

5752
private Optional<Role> getCakeDayRole(Guild guild) {
5853
Optional<Role> cakeDayRole = getCakeDayRoleFromGuild(guild);
5954

6055
if (cakeDayRole.isEmpty()) {
6156
logger.warn("Cake day role with pattern {} not found for guild: {}",
62-
config.rolePattern(), guild.getName());
57+
fullConfig.rolePattern(), guild.getName());
6358
}
6459

6560
return cakeDayRole;
@@ -74,13 +69,7 @@ private Optional<Role> getCakeDayRole(Guild guild) {
7469
* @param guild the guild for which to reassign the cake day role
7570
*/
7671
protected void reassignCakeDayRole(Guild guild) {
77-
Optional<Role> cakeDayRole = getCakeDayRole(guild);
78-
79-
if (cakeDayRole.isEmpty()) {
80-
return;
81-
}
82-
83-
refreshMembersCakeDayRoles(cakeDayRole.get(), guild);
72+
getCakeDayRole(guild).ifPresent(role -> refreshMembersCakeDayRoles(role, guild));
8473
}
8574

8675
/**
@@ -92,7 +81,7 @@ protected void reassignCakeDayRole(Guild guild) {
9281
private void refreshMembersCakeDayRoles(Role cakeDayRole, Guild guild) {
9382
guild.findMembersWithRoles(cakeDayRole).onSuccess(members -> {
9483
removeRoleFromMembers(guild, cakeDayRole, members);
95-
addTodayMembersCakeDayRole(guild);
84+
addTodayMembersCakeDayRole(guild, cakeDayRole);
9685
});
9786
}
9887

@@ -106,99 +95,96 @@ private void refreshMembersCakeDayRoles(Role cakeDayRole, Guild guild) {
10695
*
10796
* @param guild the guild to check for members celebrating their cake day today
10897
*/
109-
private void addTodayMembersCakeDayRole(Guild guild) {
98+
private void addTodayMembersCakeDayRole(Guild guild, Role cakeDayRole) {
11099
findCakeDaysTodayFromDatabase(guild).forEach(cakeDayRecord -> {
111100
Member member = guild.getMemberById(cakeDayRecord.getUserId());
112101

113102
if (member == null) {
114103
return;
115104
}
116105

117-
boolean isAnniversaryDay = hasMemberCakeDayToday(member);
118-
int yearsSinceJoin = OffsetDateTime.now().getYear() - cakeDayRecord.getJoinedYear();
119-
120-
if (yearsSinceJoin > 0 && isAnniversaryDay) {
121-
addCakeDayRole(member);
106+
if (!hasMemberCakeDayToday(member)) {
107+
return;
122108
}
109+
110+
addCakeDayRole(member, cakeDayRole);
123111
});
124112
}
125113

126114
/**
127-
* Adds the cake day role to the specified member if the cake day role exists in the guild.
115+
* Adds the cake day role supplied to the specified member if the cake day role exists in the
116+
* guild.
128117
*
129118
* @param member the {@link Member} to whom the cake day role will be added
130119
*/
131120
protected void addCakeDayRole(Member member) {
132121
Guild guild = member.getGuild();
133-
UserSnowflake snowflake = UserSnowflake.fromId(member.getId());
134122
Optional<Role> cakeDayRole = getCakeDayRole(guild);
135123

136124
if (cakeDayRole.isEmpty()) {
137125
return;
138126
}
139127

140-
guild.addRoleToMember(snowflake, cakeDayRole.get()).complete();
128+
addCakeDayRole(member, cakeDayRole.get());
141129
}
142130

143131
/**
144-
* Removes a specified role from a list of members in a {@link Guild}.
132+
* Adds the cake day role supplied to the specified member.
145133
*
146-
* @param guild the {@link Guild} from which to remove the role from members
147-
* @param role the {@link Role} to be removed from the members
148-
* @param members the {@link List} of members from which the {@link Role} will be removed
134+
* @param member the {@link Member} to whom the cake day role will be added
135+
* @param cakeDayRole the cake day {@link Role}
149136
*/
150-
private void removeRoleFromMembers(Guild guild, Role role, List<Member> members) {
151-
List<RestAction<Result<Void>>> chain = members.stream()
152-
.map(member -> guild.removeRoleFromMember(member, role).mapToResult())
153-
.toList();
154-
155-
if (chain.isEmpty()) {
156-
return;
157-
}
137+
private void addCakeDayRole(Member member, @NotNull Role cakeDayRole) {
138+
Guild guild = member.getGuild();
158139

159-
RestAction.allOf(chain).queue();
140+
guild.addRoleToMember(member, cakeDayRole).queue();
160141
}
161142

162143
/**
163-
* Creates a query to insert a member's cake day information into the database.
144+
* Removes a specified role from a list of members in a {@link Guild}.
164145
*
165-
* @param member the member whose cake day information is to be inserted
166-
* @param guildId the ID of the guild to which the member belongs
167-
* @return an Optional containing the query to insert cake day information if the member has a
168-
* join time; empty Optional otherwise
146+
* @param guild the {@link Guild} from which to remove the role from members
147+
* @param role the {@link Role} to be removed from the members
148+
* @param members the {@link List} of members from which the {@link Role} will be removed
169149
*/
170-
private Optional<Query> createMemberCakeDayQuery(Member member, long guildId) {
171-
if (!member.hasTimeJoined()) {
172-
return Optional.empty();
173-
}
174-
175-
OffsetDateTime cakeDay = member.getTimeJoined();
176-
String joinedMonthDay = cakeDay.format(MONTH_DAY_FORMATTER);
177-
178-
return Optional.of(DSL.insertInto(CAKE_DAYS)
179-
.set(CAKE_DAYS.JOINED_MONTH_DAY, joinedMonthDay)
180-
.set(CAKE_DAYS.JOINED_YEAR, cakeDay.getYear())
181-
.set(CAKE_DAYS.GUILD_ID, guildId)
182-
.set(CAKE_DAYS.USER_ID, member.getIdLong()));
150+
private void removeRoleFromMembers(Guild guild, Role role, List<Member> members) {
151+
members.forEach(member -> guild.removeRoleFromMember(member, role)
152+
.queue(null,
153+
failure -> logger.error("Could not remove role {} from {} ({}): {}",
154+
role.getName(), member.getEffectiveName(), member.getId(),
155+
failure.getMessage())));
183156
}
184157

185158
/**
186-
* Inserts the cake day of a member into the database.
159+
* Asynchronously inserts a member's cake day information into the database.
160+
*
161+
* <p>
162+
* This method retrieves the {@link Member} from the Discord API to obtain the member's join
163+
* timestamp, derives the month/day portion using {@code MONTH_DAY_FORMATTER}, and then inserts
164+
* a row into {@code CAKE_DAYS} with the join month-day, join year, guild id, and user id.
165+
*
187166
* <p>
188-
* If the member has no join date, nothing happens.
167+
* The Discord retrieval is performed asynchronously; on success the database write is executed.
168+
* If the Discord retrieval fails (e.g., member not found, missing permissions, network issues),
169+
* the insert is skipped and a warning is logged.
189170
*
190-
* @param member the member whose cake day is to be inserted into the database
191-
* @param guildId the ID of the guild to which the member belongs
171+
* @param member the member whose cake day information should be inserted
172+
* @param guildId the id of the guild associated with the cake day record
192173
*/
193174
protected void insertMemberCakeDayToDatabase(Member member, long guildId) {
194-
Query insertQuery = createMemberCakeDayQuery(member, guildId).orElse(null);
195-
196-
if (insertQuery == null) {
197-
logger.warn("Tried to add member {} to database but found no time joined",
198-
member.getId());
199-
}
200-
201-
database.write(context -> context.batch(insertQuery).execute());
175+
member.getGuild().retrieveMemberById(member.getIdLong()).queue(retrievedMember -> {
176+
OffsetDateTime timeJoined = retrievedMember.getTimeJoined();
177+
String joinedMonthDay = timeJoined.format(MONTH_DAY_FORMATTER);
178+
179+
Query query = DSL.insertInto(CAKE_DAYS)
180+
.set(CAKE_DAYS.JOINED_MONTH_DAY, joinedMonthDay)
181+
.set(CAKE_DAYS.JOINED_YEAR, timeJoined.getYear())
182+
.set(CAKE_DAYS.GUILD_ID, guildId)
183+
.set(CAKE_DAYS.USER_ID, member.getIdLong());
184+
185+
database.write(ctx -> ctx.execute(query));
186+
}, failure -> logger.warn("Could not insert member cake day into the database: {}",
187+
failure.getMessage()));
202188
}
203189

204190
/**
@@ -221,10 +207,7 @@ protected void removeMemberCakeDayFromDatabase(long userId, long guildId) {
221207
* @return an {@link Optional} containing the cake day role if found, otherwise empty
222208
*/
223209
private Optional<Role> getCakeDayRoleFromGuild(Guild guild) {
224-
return guild.getRoles()
225-
.stream()
226-
.filter(role -> cakeDayRolePredicate.test(role.getName()))
227-
.findFirst();
210+
return guild.getRolesByName(cakeDayRolePattern, true).stream().findFirst();
228211
}
229212

230213
/**
@@ -234,7 +217,7 @@ private Optional<Role> getCakeDayRoleFromGuild(Guild guild) {
234217
* @param user the {@link User} who left the guild
235218
* @param guild the {@link Guild} from which the user left
236219
*/
237-
protected void handleUserLeft(User user, Guild guild) {
220+
protected void removeUserCakeDay(User user, Guild guild) {
238221
removeMemberCakeDayFromDatabase(user.getIdLong(), guild.getIdLong());
239222
cakeDaysCache.remove(guild.getId());
240223
}
@@ -247,12 +230,10 @@ protected void handleUserLeft(User user, Guild guild) {
247230
private List<CakeDaysRecord> findCakeDaysTodayFromDatabase(Guild guild) {
248231
String todayMonthDay = OffsetDateTime.now().format(MONTH_DAY_FORMATTER);
249232

250-
return database
251-
.read(context -> context.selectFrom(CAKE_DAYS)
252-
.where(CAKE_DAYS.JOINED_MONTH_DAY.eq(todayMonthDay))
253-
.and(CAKE_DAYS.GUILD_ID.eq(guild.getIdLong()))
254-
.fetch())
255-
.collect(Collectors.toList());
233+
return database.read(context -> context.selectFrom(CAKE_DAYS)
234+
.where(CAKE_DAYS.JOINED_MONTH_DAY.eq(todayMonthDay))
235+
.and(CAKE_DAYS.GUILD_ID.eq(guild.getIdLong()))
236+
.fetch());
256237
}
257238

258239
/**
@@ -263,13 +244,8 @@ private List<CakeDaysRecord> findCakeDaysTodayFromDatabase(Guild guild) {
263244
* {@link Optional} if no record is found
264245
*/
265246
protected Optional<CakeDaysRecord> findUserCakeDayFromDatabase(long userId) {
266-
return database
267-
.read(context -> context.selectFrom(CAKE_DAYS)
268-
.where(CAKE_DAYS.USER_ID.eq(userId))
269-
.fetch())
270-
.collect(Collectors.toList())
271-
.stream()
272-
.findFirst();
247+
return database.read(ctx -> Optional
248+
.ofNullable(ctx.selectFrom(CAKE_DAYS).where(CAKE_DAYS.USER_ID.eq(userId)).fetchOne()));
273249
}
274250

275251
/**

0 commit comments

Comments
 (0)