Skip to content
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
3 changes: 3 additions & 0 deletions application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,7 @@
"assignmentChannelPattern": "community-commands",
"announcementChannelPattern": "hall-of-fame"
}
"cakeDayConfig": {
"rolePattern": "Cake Day"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.togetherjava.tjbot.config;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;

/**
* Configuration record for the Cake Day feature.
*
* @see org.togetherjava.tjbot.features.cakeday.CakeDayService
*/
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 @@ -49,6 +49,7 @@ public final class Config {
private final String selectRolesChannelPattern;
private final String memberCountCategoryPattern;
private final TopHelpersConfig topHelpers;
private final CakeDayConfig cakeDayConfig;

@SuppressWarnings("ConstructorWithTooManyParameters")
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
Expand Down Expand Up @@ -102,7 +103,8 @@ private Config(@JsonProperty(value = "token", required = true) String token,
@JsonProperty(value = "rssConfig", required = true) RSSFeedsConfig rssFeedsConfig,
@JsonProperty(value = "selectRolesChannelPattern",
required = true) String selectRolesChannelPattern,
@JsonProperty(value = "topHelpers", required = true) TopHelpersConfig topHelpers) {
@JsonProperty(value = "topHelpers", required = true) TopHelpersConfig topHelpers,
@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 @@ -138,6 +140,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
this.rssFeedsConfig = Objects.requireNonNull(rssFeedsConfig);
this.selectRolesChannelPattern = Objects.requireNonNull(selectRolesChannelPattern);
this.topHelpers = Objects.requireNonNull(topHelpers);
this.cakeDayConfig = Objects.requireNonNull(cakeDayConfig);
}

/**
Expand Down Expand Up @@ -431,6 +434,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 @@ -119,6 +122,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);
HelpThreadLifecycleListener helpThreadLifecycleListener =
new HelpThreadLifecycleListener(helpSystemHelper, database);
TopHelpersService topHelpersService = new TopHelpersService(database);
Expand All @@ -144,6 +148,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new LeftoverBookmarksCleanupRoutine(bookmarksSystem));
features.add(new MarkHelpThreadCloseInDBRoutine(database, helpThreadLifecycleListener));
features.add(new MemberCountDisplayRoutine(config));
features.add(new CakeDayRoutine(cakeDayService));
features.add(new RSSHandlerRoutine(config, database));
features.add(topHelpersAssignmentRoutine);

Expand All @@ -166,6 +171,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));
features.add(new HelpThreadLifecycleListener(helpSystemHelper, database));
features.add(new ProjectsThreadCreatedListener(config));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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;

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should update our table on user join/leave events instead of onMessage, like i mentioned earlier onMessage only triggers for active users which means after few weeks. It's being triggered for 1000 messages from same users without adding any value(updating our table with joined dates).

User join event will add new entry to our table, user leaves will remove that entry.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to work on this

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use Optional#ifPresent here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can do it in a single statement. The only alternative to Optional#ifPresent for cleaner code is Optional#ifPresentOrElse, which will result in having to pass the first argument as null, which is not recommended as both parameters in the aforementioned method have a @NotNull annotation.

Let me know if you were thinking of something else other than Optional#ifPresent.

}

/**
* 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.removeUserCakeDay(user, guild);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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;

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the routine should start a seperate thread that will collect two different list of users

  • users with already cake day role, that needs to be removed on next day
  • users that are eligible for cake day role
    it will then perform these updates at a delay of 1-1.5 seconds to be cautious with API rate limits.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to work on this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By 2 threads, do you mean 2 different functions or literal java threads?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By 2 threads, do you mean 2 different functions or literal java threads?

I think he means literally a new Java thread.

}
}
Loading
Loading