29
29
30
30
import static org .togetherjava .tjbot .db .generated .tables .CakeDays .CAKE_DAYS ;
31
31
32
+ /**
33
+ * Represents a routine for managing cake day celebrations.
34
+ * <p>
35
+ * This routine handles the assignment and removal of a designated cake day role to guild members
36
+ * based on their anniversary of joining the guild.
37
+ */
32
38
public class CakeDayRoutine implements Routine {
33
39
34
40
private static final Logger logger = LoggerFactory .getLogger (CakeDayRoutine .class );
@@ -39,31 +45,24 @@ public class CakeDayRoutine implements Routine {
39
45
private final CakeDayConfig config ;
40
46
private final Database database ;
41
47
48
+ /**
49
+ * Constructs a new {@link CakeDayRoutine} instance.
50
+ *
51
+ * @param config the configuration for cake day routines
52
+ * @param database the database for accessing cake day data
53
+ */
42
54
public CakeDayRoutine (Config config , Database database ) {
43
55
this .config = config .getCakeDayConfig ();
44
56
this .database = database ;
45
57
46
58
this .cakeDayRolePredicate = Pattern .compile (this .config .rolePattern ()).asPredicate ();
47
59
}
48
60
49
- /**
50
- * Retrieves the schedule of this routine. Called by the core system once during the startup in
51
- * order to execute the routine accordingly.
52
- * <p>
53
- * Changes on the schedule returned by this method afterwards will not be picked up.
54
- *
55
- * @return the schedule of this routine
56
- */
57
61
@ Override
58
62
public Schedule createSchedule () {
59
63
return new Schedule (ScheduleMode .FIXED_RATE , 0 , 1 , TimeUnit .DAYS );
60
64
}
61
65
62
- /**
63
- * Triggered by the core system on the schedule defined by {@link #createSchedule()}.
64
- *
65
- * @param jda the JDA instance the bot is operating with
66
- */
67
66
@ Override
68
67
public void runRoutine (JDA jda ) {
69
68
if (getCakeDayCount (this .database ) == 0 ) {
@@ -89,6 +88,14 @@ public void runRoutine(JDA jda) {
89
88
jda .getGuilds ().forEach (this ::reassignCakeDayRole );
90
89
}
91
90
91
+ /**
92
+ * Reassigns the cake day role for all members of the given guild.
93
+ * <p>
94
+ * If the cake day role is not found based on the configured pattern, a warning message is
95
+ * logged, and no action is taken.
96
+ *
97
+ * @param guild the guild for which to reassign the cake day role
98
+ */
92
99
private void reassignCakeDayRole (Guild guild ) {
93
100
Role cakeDayRole = getCakeDayRoleFromGuild (guild ).orElse (null );
94
101
@@ -103,6 +110,16 @@ private void reassignCakeDayRole(Guild guild) {
103
110
.join ();
104
111
}
105
112
113
+ /**
114
+ * Asynchronously adds the specified cake day role to guild members who are celebrating their
115
+ * cake day today.
116
+ * <p>
117
+ * The cake day role is added to members who have been in the guild for at least one year.
118
+ *
119
+ * @param cakeDayRole the cake day role to add to qualifying members
120
+ * @param guild the guild in which to add the cake day role to members
121
+ * @return a {@link CompletableFuture} representing the asynchronous operation
122
+ */
106
123
private CompletableFuture <Void > addTodayMembersCakeDayRole (Role cakeDayRole , Guild guild ) {
107
124
return CompletableFuture
108
125
.runAsync (() -> findCakeDaysTodayFromDatabase ().forEach (cakeDayRecord -> {
@@ -115,26 +132,67 @@ private CompletableFuture<Void> addTodayMembersCakeDayRole(Role cakeDayRole, Gui
115
132
}));
116
133
}
117
134
135
+ /**
136
+ * Removes the specified cake day role from all members who possess it in the given guild
137
+ * asynchronously.
138
+ *
139
+ * @param cakeDayRole the cake day role to be removed from members
140
+ * @param guild the guild from which to remove the cake day role
141
+ * @return a {@link CompletableFuture} representing the asynchronous operation
142
+ */
118
143
private CompletableFuture <Void > removeMembersCakeDayRole (Role cakeDayRole , Guild guild ) {
119
144
return CompletableFuture .runAsync (() -> guild .findMembersWithRoles (cakeDayRole )
120
145
.onSuccess (members -> removeRoleFromMembers (guild , cakeDayRole , members )));
121
146
}
122
147
148
+
149
+ /**
150
+ * Removes a specified role from a list of members in a guild.
151
+ *
152
+ * @param guild the guild from which to remove the role from members
153
+ * @param role the role to be removed from the members
154
+ * @param members the list of members from which the role will be removed
155
+ */
123
156
private void removeRoleFromMembers (Guild guild , Role role , List <Member > members ) {
124
157
members .forEach (member -> {
125
158
UserSnowflake snowflake = UserSnowflake .fromId (member .getIdLong ());
126
159
guild .removeRoleFromMember (snowflake , role ).complete ();
127
160
});
128
161
}
129
162
163
+ /**
164
+ * Retrieves the count of cake days from the provided database.
165
+ * <p>
166
+ * This uses the table <b>cake_days</b> to find the answer.
167
+ *
168
+ * @param database the database from which to retrieve the count of cake days
169
+ * @return the count of cake days stored in the database
170
+ */
130
171
private int getCakeDayCount (Database database ) {
131
172
return database .read (context -> context .fetchCount (CAKE_DAYS ));
132
173
}
133
174
175
+ /**
176
+ * Populates cake days for all guilds in the provided JDA instance.
177
+ * <p>
178
+ * This method iterates through all guilds in the provided JDA instance and populates cake days
179
+ * for each guild. It is primarily used for batch populating the <b>cake_days</b> table once it
180
+ * is found to be empty.
181
+ *
182
+ * @param jda the JDA instance containing the guilds to populate cake days for
183
+ */
134
184
private void populateAllGuildCakeDays (JDA jda ) {
135
185
jda .getGuilds ().forEach (this ::batchPopulateGuildCakeDays );
136
186
}
137
187
188
+ /**
189
+ * Batch populates guild cake days for the given guild.
190
+ * <p>
191
+ * Uses a buffer for all the queries it makes and its size is determined by the
192
+ * {@code BULK_INSERT_SIZE} option.
193
+ *
194
+ * @param guild the guild for which to populate cake days
195
+ */
138
196
private void batchPopulateGuildCakeDays (Guild guild ) {
139
197
final List <Query > queriesBuffer = new ArrayList <>();
140
198
@@ -155,6 +213,18 @@ private void batchPopulateGuildCakeDays(Guild guild) {
155
213
}
156
214
}
157
215
216
+ /**
217
+ * Creates a query to insert a member's cake day information into the database.
218
+ * <p>
219
+ * Primarily used for manually constructing queries for members' cake days which are called from
220
+ * {@link CakeDayRoutine#batchPopulateGuildCakeDays(Guild)} and added in a batch to be sent to
221
+ * the database.
222
+ *
223
+ * @param member the member whose cake day information is to be inserted
224
+ * @param guildId the ID of the guild to which the member belongs
225
+ * @return an Optional containing the query to insert cake day information if the member has a
226
+ * join time; empty Optional otherwise
227
+ */
158
228
private Optional <Query > createMemberCakeDayQuery (Member member , long guildId ) {
159
229
if (!member .hasTimeJoined ()) {
160
230
return Optional .empty ();
@@ -170,13 +240,24 @@ private Optional<Query> createMemberCakeDayQuery(Member member, long guildId) {
170
240
.set (CAKE_DAYS .USER_ID , member .getIdLong ()));
171
241
}
172
242
243
+ /**
244
+ * Retrieves the cake day {@link Role} from the specified guild.
245
+ *
246
+ * @param guild the guild from which to retrieve the cake day role
247
+ * @return an optional containing the cake day role if found, otherwise empty
248
+ */
173
249
private Optional <Role > getCakeDayRoleFromGuild (Guild guild ) {
174
250
return guild .getRoles ()
175
251
.stream ()
176
252
.filter (role -> cakeDayRolePredicate .test (role .getName ()))
177
253
.findFirst ();
178
254
}
179
255
256
+ /**
257
+ * Finds cake days records for today from the database.
258
+ *
259
+ * @return a list of {@link CakeDaysRecord} objects representing cake days for today
260
+ */
180
261
private List <CakeDaysRecord > findCakeDaysTodayFromDatabase () {
181
262
String todayMonthDay = OffsetDateTime .now ().format (MONTH_DAY_FORMATTER );
182
263
0 commit comments