diff --git a/application/src/main/java/org/togetherjava/tjbot/config/CakeDayConfig.java b/application/src/main/java/org/togetherjava/tjbot/config/CakeDayConfig.java index 4596841055..e3f35818c7 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/CakeDayConfig.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/CakeDayConfig.java @@ -2,6 +2,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; +/** + * Configuration record for the Cake Day feature. + */ public record CakeDayConfig( @JsonProperty(value = "rolePattern", required = true) String rolePattern) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index cee7ffe7f8..d0c99d5151 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -409,7 +409,11 @@ public String getSelectRolesChannelPattern() { return selectRolesChannelPattern; } - // TODO: Add JavaDoc + /** + * Retrieves the Cake Day configuration. + * + * @return the cake-day feature configuration + */ public CakeDayConfig getCakeDayConfig() { return cakeDayConfig; } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/basic/CakeDayRoutine.java b/application/src/main/java/org/togetherjava/tjbot/features/basic/CakeDayRoutine.java index 86f91a1ef8..5702a0e821 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/basic/CakeDayRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/basic/CakeDayRoutine.java @@ -29,6 +29,12 @@ import static org.togetherjava.tjbot.db.generated.tables.CakeDays.CAKE_DAYS; +/** + * Represents a routine for managing cake day celebrations. + *

+ * This routine handles the assignment and removal of a designated cake day role to guild members + * based on their anniversary of joining the guild. + */ public class CakeDayRoutine implements Routine { private static final Logger logger = LoggerFactory.getLogger(CakeDayRoutine.class); @@ -39,6 +45,12 @@ public class CakeDayRoutine implements Routine { private final CakeDayConfig config; private final Database database; + /** + * Constructs a new {@link CakeDayRoutine} instance. + * + * @param config the configuration for cake day routines + * @param database the database for accessing cake day data + */ public CakeDayRoutine(Config config, Database database) { this.config = config.getCakeDayConfig(); this.database = database; @@ -46,24 +58,11 @@ public CakeDayRoutine(Config config, Database database) { this.cakeDayRolePredicate = Pattern.compile(this.config.rolePattern()).asPredicate(); } - /** - * Retrieves the schedule of this routine. Called by the core system once during the startup in - * order to execute the routine accordingly. - *

- * Changes on the schedule returned by this method afterwards will not be picked up. - * - * @return the schedule of this routine - */ @Override public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.DAYS); } - /** - * Triggered by the core system on the schedule defined by {@link #createSchedule()}. - * - * @param jda the JDA instance the bot is operating with - */ @Override public void runRoutine(JDA jda) { if (getCakeDayCount(this.database) == 0) { @@ -89,6 +88,14 @@ public void runRoutine(JDA jda) { jda.getGuilds().forEach(this::reassignCakeDayRole); } + /** + * Reassigns the cake day role for all members of the given guild. + *

+ * If the cake day role is not found based on the configured pattern, a warning message is + * logged, and no action is taken. + * + * @param guild the guild for which to reassign the cake day role + */ private void reassignCakeDayRole(Guild guild) { Role cakeDayRole = getCakeDayRoleFromGuild(guild).orElse(null); @@ -103,6 +110,16 @@ private void reassignCakeDayRole(Guild guild) { .join(); } + /** + * Asynchronously adds the specified cake day role to guild members who are celebrating their + * cake day today. + *

+ * The cake day role is added to members who have been in the guild for at least one year. + * + * @param cakeDayRole the cake day role to add to qualifying members + * @param guild the guild in which to add the cake day role to members + * @return a {@link CompletableFuture} representing the asynchronous operation + */ private CompletableFuture addTodayMembersCakeDayRole(Role cakeDayRole, Guild guild) { return CompletableFuture .runAsync(() -> findCakeDaysTodayFromDatabase().forEach(cakeDayRecord -> { @@ -115,11 +132,27 @@ private CompletableFuture addTodayMembersCakeDayRole(Role cakeDayRole, Gui })); } + /** + * Removes the specified cake day role from all members who possess it in the given guild + * asynchronously. + * + * @param cakeDayRole the cake day role to be removed from members + * @param guild the guild from which to remove the cake day role + * @return a {@link CompletableFuture} representing the asynchronous operation + */ private CompletableFuture removeMembersCakeDayRole(Role cakeDayRole, Guild guild) { return CompletableFuture.runAsync(() -> guild.findMembersWithRoles(cakeDayRole) .onSuccess(members -> removeRoleFromMembers(guild, cakeDayRole, members))); } + + /** + * Removes a specified role from a list of members in a guild. + * + * @param guild the guild from which to remove the role from members + * @param role the role to be removed from the members + * @param members the list of members from which the role will be removed + */ private void removeRoleFromMembers(Guild guild, Role role, List members) { members.forEach(member -> { UserSnowflake snowflake = UserSnowflake.fromId(member.getIdLong()); @@ -127,14 +160,39 @@ private void removeRoleFromMembers(Guild guild, Role role, List members) }); } + /** + * Retrieves the count of cake days from the provided database. + *

+ * This uses the table cake_days to find the answer. + * + * @param database the database from which to retrieve the count of cake days + * @return the count of cake days stored in the database + */ private int getCakeDayCount(Database database) { return database.read(context -> context.fetchCount(CAKE_DAYS)); } + /** + * Populates cake days for all guilds in the provided JDA instance. + *

+ * This method iterates through all guilds in the provided JDA instance and populates cake days + * for each guild. It is primarily used for batch populating the cake_days table once it + * is found to be empty. + * + * @param jda the JDA instance containing the guilds to populate cake days for + */ private void populateAllGuildCakeDays(JDA jda) { jda.getGuilds().forEach(this::batchPopulateGuildCakeDays); } + /** + * Batch populates guild cake days for the given guild. + *

+ * Uses a buffer for all the queries it makes and its size is determined by the + * {@code BULK_INSERT_SIZE} option. + * + * @param guild the guild for which to populate cake days + */ private void batchPopulateGuildCakeDays(Guild guild) { final List queriesBuffer = new ArrayList<>(); @@ -155,6 +213,18 @@ private void batchPopulateGuildCakeDays(Guild guild) { } } + /** + * Creates a query to insert a member's cake day information into the database. + *

+ * Primarily used for manually constructing queries for members' cake days which are called from + * {@link CakeDayRoutine#batchPopulateGuildCakeDays(Guild)} and added in a batch to be sent to + * the database. + * + * @param member the member whose cake day information is to be inserted + * @param guildId the ID of the guild to which the member belongs + * @return an Optional containing the query to insert cake day information if the member has a + * join time; empty Optional otherwise + */ private Optional createMemberCakeDayQuery(Member member, long guildId) { if (!member.hasTimeJoined()) { return Optional.empty(); @@ -170,6 +240,12 @@ private Optional createMemberCakeDayQuery(Member member, long guildId) { .set(CAKE_DAYS.USER_ID, member.getIdLong())); } + /** + * Retrieves the cake day {@link Role} from the specified guild. + * + * @param guild the guild from which to retrieve the cake day role + * @return an optional containing the cake day role if found, otherwise empty + */ private Optional getCakeDayRoleFromGuild(Guild guild) { return guild.getRoles() .stream() @@ -177,6 +253,11 @@ private Optional getCakeDayRoleFromGuild(Guild guild) { .findFirst(); } + /** + * Finds cake days records for today from the database. + * + * @return a list of {@link CakeDaysRecord} objects representing cake days for today + */ private List findCakeDaysTodayFromDatabase() { String todayMonthDay = OffsetDateTime.now().format(MONTH_DAY_FORMATTER);