Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Cake Day #1042

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,8 @@
"fallbackChannelPattern": "java-news-and-changes",
"pollIntervalInMinutes": 10
},
"memberCountCategoryPattern": "Info"
"memberCountCategoryPattern": "Info",
"cakeDayConfig": {
"rolePattern": "Cake Day"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.togetherjava.tjbot.config;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;

/**
* Configuration record for the Cake Day feature.
*/
public record CakeDayConfig(
@JsonProperty(value = "rolePattern", required = true) String rolePattern) {

/**
* Configuration constructor for the Cake Day feature.
*/
public CakeDayConfig {
Objects.requireNonNull(rolePattern);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public final class Config {
private final RSSFeedsConfig rssFeedsConfig;
private final String selectRolesChannelPattern;
private final String memberCountCategoryPattern;
private final CakeDayConfig cakeDayConfig;

@SuppressWarnings("ConstructorWithTooManyParameters")
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
Expand Down Expand Up @@ -94,7 +95,8 @@ private Config(@JsonProperty(value = "token", required = true) String token,
required = true) FeatureBlacklistConfig featureBlacklistConfig,
@JsonProperty(value = "rssConfig", required = true) RSSFeedsConfig rssFeedsConfig,
@JsonProperty(value = "selectRolesChannelPattern",
required = true) String selectRolesChannelPattern) {
required = true) String selectRolesChannelPattern,
@JsonProperty(value = "cakeDayConfig", required = true) CakeDayConfig cakeDayConfig) {
this.token = Objects.requireNonNull(token);
this.githubApiKey = Objects.requireNonNull(githubApiKey);
this.databasePath = Objects.requireNonNull(databasePath);
Expand Down Expand Up @@ -127,6 +129,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
this.featureBlacklistConfig = Objects.requireNonNull(featureBlacklistConfig);
this.rssFeedsConfig = Objects.requireNonNull(rssFeedsConfig);
this.selectRolesChannelPattern = Objects.requireNonNull(selectRolesChannelPattern);
this.cakeDayConfig = Objects.requireNonNull(cakeDayConfig);
}

/**
Expand Down Expand Up @@ -401,6 +404,15 @@ public String getSelectRolesChannelPattern() {
return selectRolesChannelPattern;
}

/**
* Retrieves the Cake Day configuration.
*
* @return the cake-day feature configuration
*/
public CakeDayConfig getCakeDayConfig() {
return cakeDayConfig;
}

/**
* Gets the pattern matching the category that is used to display the total member count.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import org.togetherjava.tjbot.features.bookmarks.BookmarksSystem;
import org.togetherjava.tjbot.features.bookmarks.LeftoverBookmarksCleanupRoutine;
import org.togetherjava.tjbot.features.bookmarks.LeftoverBookmarksListener;
import org.togetherjava.tjbot.features.cakeday.CakeDayListener;
import org.togetherjava.tjbot.features.cakeday.CakeDayRoutine;
import org.togetherjava.tjbot.features.cakeday.CakeDayService;
import org.togetherjava.tjbot.features.chatgpt.ChatGptCommand;
import org.togetherjava.tjbot.features.chatgpt.ChatGptService;
import org.togetherjava.tjbot.features.code.CodeMessageAutoDetection;
Expand Down Expand Up @@ -113,6 +116,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
new CodeMessageHandler(blacklistConfig.special(), jshellEval);
ChatGptService chatGptService = new ChatGptService(config);
HelpSystemHelper helpSystemHelper = new HelpSystemHelper(config, database, chatGptService);
CakeDayService cakeDayService = new CakeDayService(config, database);

// NOTE The system can add special system relevant commands also by itself,
// hence this list may not necessarily represent the full list of all commands actually
Expand All @@ -130,6 +134,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new HelpThreadAutoArchiver(helpSystemHelper));
features.add(new LeftoverBookmarksCleanupRoutine(bookmarksSystem));
features.add(new MemberCountDisplayRoutine(config));
features.add(new CakeDayRoutine(cakeDayService));
features.add(new RSSHandlerRoutine(config, database));

// Message receivers
Expand All @@ -151,6 +156,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new GuildLeaveCloseThreadListener(config));
features.add(new LeftoverBookmarksListener(bookmarksSystem));
features.add(new HelpThreadCreatedListener(helpSystemHelper));
features.add(new CakeDayListener(cakeDayService));

// Message context commands
features.add(new TransferQuestionCommand(config, chatGptService));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.togetherjava.tjbot.features.cakeday;

import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;

import org.togetherjava.tjbot.db.generated.tables.records.CakeDaysRecord;
import org.togetherjava.tjbot.features.EventReceiver;

import java.util.Optional;

/**
* A listener class responsible for handling cake day related events.
*/
public class CakeDayListener extends ListenerAdapter implements EventReceiver {

private final CakeDayService cakeDayService;

/**
* Constructs a new CakeDayListener with the given {@link CakeDayService}.
*
* @param cakeDayService the {@link CakeDayService} to be used by this listener
*/
public CakeDayListener(CakeDayService cakeDayService) {
this.cakeDayService = cakeDayService;
}

/**
* Handles the event of a message being received in a guild.
* <p>
* It caches the user's cake day and inserts the member's cake day into the database if not
* already present.
*
* @param event the {@link MessageReceivedEvent} representing the message received
*/
@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
tj-wazei marked this conversation as resolved.
Show resolved Hide resolved
User author = event.getAuthor();
Member member = event.getMember();
long authorId = author.getIdLong();
long guildId = event.getGuild().getIdLong();

if (member == null || author.isBot() || author.isSystem()) {
return;
}


if (cakeDayService.hasMemberCakeDayToday(member)) {
cakeDayService.addCakeDayRole(member);
return;
}

if (cakeDayService.isUserCached(author)) {
return;
}

cakeDayService.addToCache(author);
Optional<CakeDaysRecord> cakeDaysRecord =
cakeDayService.findUserCakeDayFromDatabase(authorId);
if (cakeDaysRecord.isPresent()) {
return;
}

cakeDayService.insertMemberCakeDayToDatabase(member, guildId);
}

/**
* Handles the event of a guild member being removed from the guild. It removes the user's cake
* day information from the database if present.
*
* @param event the {@link GuildMemberRemoveEvent} representing the member removal event
*/
@Override
public void onGuildMemberRemove(GuildMemberRemoveEvent event) {
User user = event.getUser();
Guild guild = event.getGuild();

cakeDayService.handleUserLeft(user, guild);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.togetherjava.tjbot.features.cakeday;

import net.dv8tion.jda.api.JDA;
import org.jetbrains.annotations.NotNull;

import org.togetherjava.tjbot.features.Routine;

import java.util.concurrent.TimeUnit;

/**
* Represents a routine for managing cake day celebrations.
* <p>
* 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 final CakeDayService cakeDayService;

/**
* Constructs a new {@link CakeDayRoutine} instance.
*
* @param cakeDayService an instance of the cake day service
*/
public CakeDayRoutine(CakeDayService cakeDayService) {
this.cakeDayService = cakeDayService;
}

@Override
@NotNull
public Schedule createSchedule() {
return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.DAYS);
}

@Override
public void runRoutine(@NotNull JDA jda) {
jda.getGuilds().forEach(cakeDayService::reassignCakeDayRole);
}
}
Loading
Loading