Skip to content

Commit 18c8f36

Browse files
andrew-09Andrew1031
andauthored
Automatically pin first message in projects forum (#1167)
* Automatically pin first message in project forum * Fixes: 1. used config file for "projects" channel name 2. Created new listener "ProjectsThreadCreatedListener.java" under new package name called "projects" * Fix comments in projects package package-info.java file * Suggested changes - More reliable way to verify parent message of channel * pass the event and thread channel to this method isPostMessage, get the message ID from that MessageRecievedEvent and get thread channel ID from thread channel --------- Co-authored-by: Andrew1031 <andrewyee67@gmail.com>
1 parent 817e044 commit 18c8f36

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

application/config.json.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"discordGuildInvite": "https://discord.com/invite/XXFUXzK",
77
"modAuditLogChannelPattern": "mod-audit-log",
88
"modMailChannelPattern": "modmail",
9+
"projectsChannelPattern": "projects"
910
"mutedRolePattern": "Muted",
1011
"heavyModerationRolePattern": "Moderator",
1112
"softModerationRolePattern": "Moderator|Community Ambassador",

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public final class Config {
2323
private final String discordGuildInvite;
2424
private final String modAuditLogChannelPattern;
2525
private final String modMailChannelPattern;
26+
private final String projectsChannelPattern;
2627
private final String mutedRolePattern;
2728
private final String heavyModerationRolePattern;
2829
private final String softModerationRolePattern;
@@ -58,6 +59,8 @@ private Config(@JsonProperty(value = "token", required = true) String token,
5859
required = true) String modAuditLogChannelPattern,
5960
@JsonProperty(value = "modMailChannelPattern",
6061
required = true) String modMailChannelPattern,
62+
@JsonProperty(value = "projectsChannelPattern",
63+
required = true) String projectsChannelPattern,
6164
@JsonProperty(value = "mutedRolePattern", required = true) String mutedRolePattern,
6265
@JsonProperty(value = "heavyModerationRolePattern",
6366
required = true) String heavyModerationRolePattern,
@@ -103,6 +106,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
103106
this.discordGuildInvite = Objects.requireNonNull(discordGuildInvite);
104107
this.modAuditLogChannelPattern = Objects.requireNonNull(modAuditLogChannelPattern);
105108
this.modMailChannelPattern = Objects.requireNonNull(modMailChannelPattern);
109+
this.projectsChannelPattern = Objects.requireNonNull(projectsChannelPattern);
106110
this.mutedRolePattern = Objects.requireNonNull(mutedRolePattern);
107111
this.heavyModerationRolePattern = Objects.requireNonNull(heavyModerationRolePattern);
108112
this.softModerationRolePattern = Objects.requireNonNull(softModerationRolePattern);
@@ -170,6 +174,16 @@ public String getModMailChannelPattern() {
170174
return modMailChannelPattern;
171175
}
172176

177+
/**
178+
* Gets the REGEX pattern used to identify the channel that is supposed to contain information
179+
* about user projects
180+
*
181+
* @return the channel name pattern
182+
*/
183+
public String getProjectsChannelPattern() {
184+
return projectsChannelPattern;
185+
}
186+
173187
/**
174188
* Gets the token of the Discord bot to connect this application to.
175189
*

application/src/main/java/org/togetherjava/tjbot/features/Features.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.togetherjava.tjbot.features.moderation.scam.ScamHistoryPurgeRoutine;
6363
import org.togetherjava.tjbot.features.moderation.scam.ScamHistoryStore;
6464
import org.togetherjava.tjbot.features.moderation.temp.TemporaryModerationRoutine;
65+
import org.togetherjava.tjbot.features.projects.ProjectsThreadCreatedListener;
6566
import org.togetherjava.tjbot.features.reminder.RemindRoutine;
6667
import org.togetherjava.tjbot.features.reminder.ReminderCommand;
6768
import org.togetherjava.tjbot.features.system.BotCore;
@@ -157,6 +158,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
157158
features.add(new LeftoverBookmarksListener(bookmarksSystem));
158159
features.add(new HelpThreadCreatedListener(helpSystemHelper));
159160
features.add(new HelpThreadLifecycleListener(helpSystemHelper, database));
161+
features.add(new ProjectsThreadCreatedListener(config));
160162

161163
// Message context commands
162164
features.add(new TransferQuestionCommand(config, chatGptService));
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.togetherjava.tjbot.features.projects;
2+
3+
import com.github.benmanes.caffeine.cache.Cache;
4+
import com.github.benmanes.caffeine.cache.Caffeine;
5+
import net.dv8tion.jda.api.entities.channel.Channel;
6+
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
7+
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
8+
import net.dv8tion.jda.api.hooks.ListenerAdapter;
9+
10+
import org.togetherjava.tjbot.config.Config;
11+
import org.togetherjava.tjbot.features.EventReceiver;
12+
13+
import java.time.Instant;
14+
import java.time.temporal.ChronoUnit;
15+
import java.util.concurrent.TimeUnit;
16+
17+
/**
18+
* Listens for new threads being created in the "projects" forum and pins the first message. *
19+
* {@link Config#getProjectsChannelPattern()}.
20+
*/
21+
public final class ProjectsThreadCreatedListener extends ListenerAdapter implements EventReceiver {
22+
private final String configProjectsChannelPattern;
23+
private final Cache<Long, Instant> threadIdToCreatedAtCache = Caffeine.newBuilder()
24+
.maximumSize(1_000)
25+
.expireAfterAccess(2, TimeUnit.of(ChronoUnit.MINUTES))
26+
.build();
27+
28+
public ProjectsThreadCreatedListener(Config config) {
29+
configProjectsChannelPattern = config.getProjectsChannelPattern();
30+
}
31+
32+
@Override
33+
public void onMessageReceived(MessageReceivedEvent event) {
34+
if (event.isFromThread()) {
35+
ThreadChannel threadChannel = event.getChannel().asThreadChannel();
36+
Channel parentChannel = threadChannel.getParentChannel();
37+
boolean isPost = isPostMessage(threadChannel, event);
38+
39+
if (parentChannel.getName().equals(configProjectsChannelPattern) && isPost) {
40+
pinParentMessage(event);
41+
}
42+
}
43+
}
44+
45+
private boolean wasThreadAlreadyHandled(long threadChannelId) {
46+
Instant now = Instant.now();
47+
Instant createdAt = threadIdToCreatedAtCache.get(threadChannelId, any -> now);
48+
return createdAt != now;
49+
}
50+
51+
private boolean isPostMessage(ThreadChannel threadChannel, MessageReceivedEvent event) {
52+
int messageCount = threadChannel.getMessageCount();
53+
if (messageCount <= 1 && !wasThreadAlreadyHandled(threadChannel.getIdLong())) {
54+
return event.getMessageId().equals(threadChannel.getId());
55+
}
56+
return false;
57+
}
58+
59+
private void pinParentMessage(MessageReceivedEvent event) {
60+
event.getMessage().pin().queue();
61+
}
62+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* This packages offers all the functionality for the projects channel. The core class is
3+
* {@link org.togetherjava.tjbot.features.projects.ProjectsThreadCreatedListener}.
4+
*/
5+
@MethodsReturnNonnullByDefault
6+
@ParametersAreNonnullByDefault
7+
package org.togetherjava.tjbot.features.projects;
8+
9+
import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault;
10+
11+
import javax.annotation.ParametersAreNonnullByDefault;

0 commit comments

Comments
 (0)