Skip to content

Commit fecc79c

Browse files
Implemented Forum Button Controls & added Reminder to /close the post
1 parent c868df2 commit fecc79c

File tree

6 files changed

+120
-27
lines changed

6 files changed

+120
-27
lines changed

src/main/java/net/javadiscord/javabot/Bot.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ private static void addComponentHandler(@NotNull DIH4JDA dih4jda) {
213213
List.of("qotw-submission"), new SubmissionInteractionManager(),
214214
List.of("help-channel", "help-thank"), new HelpChannelInteractionManager(),
215215
List.of("qotw-list-questions"), new QOTWQuerySubcommand(),
216-
List.of(ForumHelpManager.HELP_THANKS_IDENTIFIER), new ForumHelpListener()
216+
List.of(ForumHelpManager.HELP_THANKS_IDENTIFIER, ForumHelpManager.HELP_CLOSE_IDENTIFIER, ForumHelpManager.HELP_GUIDELINES_IDENTIFIER), new ForumHelpListener()
217217
));
218218
dih4jda.addModalHandlers(Map.of(
219219
List.of("qotw-add-question"), new AddQuestionSubcommand(),

src/main/java/net/javadiscord/javabot/data/config/guild/HelpForumConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
@EqualsAndHashCode(callSuper = true)
1414
public class HelpForumConfig extends GuildConfigItem {
1515
private long helpForumChannelId = 0;
16+
private String closeReminderText = "Hey, %s!\nPlease remember to `/close` this post once your question has been answered!";
17+
private String helpThanksText = "Before your post will be closed, would you like to express your gratitude to any of the people who helped you? When you're done, click **I'm done here. Close this post!**.";
1618

1719
public ForumChannel getHelpForumChannel() {
1820
return getGuild().getForumChannelById(helpForumChannelId);

src/main/java/net/javadiscord/javabot/systems/help/commands/UnreserveCommand.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private void handleForumBasedHelp(SlashCommandInteractionEvent event, @NotNull T
5454
replyInvalidChannel(event);
5555
}
5656
ForumHelpManager manager = new ForumHelpManager(postThread);
57-
if (isForumEligibleToBeUnreserved(event, postThread)) {
57+
if (manager.isForumEligibleToBeUnreserved(event)) {
5858
manager.close(event, event.getUser().getIdLong() == postThread.getOwnerIdLong(),
5959
event.getOption("reason", null, OptionMapping::getAsString)
6060
);
@@ -82,10 +82,6 @@ private void replyInvalidChannel(CommandInteraction interaction) {
8282
.queue();
8383
}
8484

85-
private boolean isForumEligibleToBeUnreserved(@NotNull SlashCommandInteractionEvent event, @NotNull ThreadChannel postThread) {
86-
return event.getUser().getIdLong() == postThread.getOwnerIdLong() || memberHasHelperRole(event) || memberHasStaffRole(event);
87-
}
88-
8985
private boolean isTextEligibleToBeUnreserved(SlashCommandInteractionEvent event, TextChannel channel, HelpConfig config, User owner) {
9086
return channelIsInReservedCategory(channel, config) &&
9187
(isUserWhoReservedChannel(event, owner) || memberHasHelperRole(event) || memberHasStaffRole(event));

src/main/java/net/javadiscord/javabot/systems/help/forum/ForumHelpListener.java

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,32 @@
22

33
import com.dynxsty.dih4jda.interactions.ComponentIdBuilder;
44
import com.dynxsty.dih4jda.interactions.components.ButtonHandler;
5+
import net.dv8tion.jda.api.EmbedBuilder;
56
import net.dv8tion.jda.api.entities.Message;
7+
import net.dv8tion.jda.api.entities.UserSnowflake;
68
import net.dv8tion.jda.api.entities.channel.ChannelType;
79
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
810
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
11+
import net.dv8tion.jda.api.entities.channel.unions.ChannelUnion;
12+
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
13+
import net.dv8tion.jda.api.entities.emoji.Emoji;
14+
import net.dv8tion.jda.api.events.channel.ChannelCreateEvent;
915
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
1016
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
1117
import net.dv8tion.jda.api.hooks.ListenerAdapter;
18+
import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
1219
import net.dv8tion.jda.api.interactions.components.ActionComponent;
20+
import net.dv8tion.jda.api.interactions.components.ActionRow;
1321
import net.dv8tion.jda.api.interactions.components.buttons.Button;
1422
import net.javadiscord.javabot.Bot;
15-
import net.javadiscord.javabot.data.config.GuildConfig;
1623
import net.javadiscord.javabot.data.config.guild.HelpConfig;
24+
import net.javadiscord.javabot.data.config.guild.HelpForumConfig;
1725
import net.javadiscord.javabot.systems.help.HelpChannelManager;
1826
import net.javadiscord.javabot.systems.help.HelpExperienceService;
1927
import net.javadiscord.javabot.systems.help.model.HelpTransactionMessage;
28+
import net.javadiscord.javabot.systems.user_preferences.UserPreferenceService;
29+
import net.javadiscord.javabot.systems.user_preferences.model.Preference;
30+
import net.javadiscord.javabot.systems.user_preferences.model.UserPreference;
2031
import net.javadiscord.javabot.util.ExceptionLogger;
2132
import net.javadiscord.javabot.util.Responses;
2233
import org.jetbrains.annotations.NotNull;
@@ -39,19 +50,12 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
3950
if (event.getMessage().getAuthor().isSystem() || event.getMessage().getAuthor().isBot()) {
4051
return;
4152
}
42-
// check for guild & channel type
43-
if (!event.isFromGuild() || event.getChannelType() != ChannelType.GUILD_PUBLIC_THREAD) {
53+
// check for forum post
54+
if (isInvalidForumPost(event.getChannel())) {
4455
return;
4556
}
46-
// get post & check parent channel
4757
ThreadChannel post = event.getChannel().asThreadChannel();
48-
if (post.getParentChannel().getType() != ChannelType.FORUM) {
49-
return;
50-
}
51-
ForumChannel forum = post.getParentChannel().asForumChannel();
52-
GuildConfig config = Bot.getConfig().get(event.getGuild());
53-
// check for channel id
54-
if (forum.getIdLong() != config.getHelpForumConfig().getHelpForumChannelId()) {
58+
if (isInvalidHelpForumChannel(post.getParentChannel().asForumChannel())) {
5559
return;
5660
}
5761
// cache messages
@@ -63,20 +67,63 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
6367
HELP_POST_MESSAGES.put(post.getIdLong(), messages);
6468
}
6569

70+
@Override
71+
public void onChannelCreate(@NotNull ChannelCreateEvent event) {
72+
if (event.getGuild() == null || isInvalidForumPost(event.getChannel())) {
73+
return;
74+
}
75+
HelpForumConfig config = Bot.getConfig().get(event.getGuild()).getHelpForumConfig();
76+
ThreadChannel post = event.getChannel().asThreadChannel();
77+
if (isInvalidHelpForumChannel(post.getParentChannel().asForumChannel())) {
78+
return;
79+
}
80+
// send post buttons
81+
post.sendMessageComponents(ActionRow.of(
82+
Button.primary(ComponentIdBuilder.build(ForumHelpManager.HELP_CLOSE_IDENTIFIER, post.getIdLong()), "Close Post"),
83+
Button.secondary(ComponentIdBuilder.build(ForumHelpManager.HELP_GUIDELINES_IDENTIFIER), "Help Guidelines").withEmoji(Emoji.fromUnicode("📚"))
84+
)).queue(success -> {
85+
// send /close reminder (if enabled)
86+
UserPreferenceService service = new UserPreferenceService(Bot.getDataSource());
87+
UserPreference preference = service.getOrCreate(post.getOwnerIdLong(), Preference.FORUM_CLOSE_REMINDER);
88+
if (Boolean.parseBoolean(preference.getState())) {
89+
post.sendMessageFormat(config.getCloseReminderText(), UserSnowflake.fromId(post.getOwnerIdLong()).getAsMention()).queue();
90+
}
91+
});
92+
}
93+
6694
@Override
6795
public void handleButton(@NotNull ButtonInteractionEvent event, @NotNull Button button) {
6896
String[] id = ComponentIdBuilder.split(event.getComponentId());
69-
if (event.getChannelType() != ChannelType.GUILD_PUBLIC_THREAD
70-
|| event.getChannel().asThreadChannel().getParentChannel().getType() != ChannelType.FORUM) {
97+
if (isInvalidForumPost(event.getChannel()) ||
98+
isInvalidHelpForumChannel(event.getChannel().asThreadChannel().getParentChannel().asForumChannel())
99+
) {
71100
Responses.error(event, "This button may only be used inside help forum threads.").queue();
72101
return;
73102
}
74-
ForumHelpManager manager = new ForumHelpManager(event.getChannel().asThreadChannel());
103+
ThreadChannel post = event.getChannel().asThreadChannel();
104+
ForumHelpManager manager = new ForumHelpManager(post);
75105
switch (id[0]) {
76106
case ForumHelpManager.HELP_THANKS_IDENTIFIER -> handleHelpThanksInteraction(event, manager, id);
107+
case ForumHelpManager.HELP_GUIDELINES_IDENTIFIER -> handleReplyGuidelines(event, post.getParentChannel().asForumChannel());
108+
case ForumHelpManager.HELP_CLOSE_IDENTIFIER -> handlePostClose(event, manager);
77109
}
78110
}
79111

112+
private boolean isInvalidForumPost(@NotNull MessageChannelUnion union) {
113+
return union.getType() != ChannelType.GUILD_PUBLIC_THREAD ||
114+
union.asThreadChannel().getParentChannel().getType() != ChannelType.FORUM;
115+
}
116+
117+
private boolean isInvalidForumPost(@NotNull ChannelUnion union) {
118+
return union.getType() != ChannelType.GUILD_PUBLIC_THREAD ||
119+
union.asThreadChannel().getParentChannel().getType() != ChannelType.FORUM;
120+
}
121+
122+
private boolean isInvalidHelpForumChannel(@NotNull ForumChannel forum) {
123+
HelpForumConfig config = Bot.getConfig().get(forum.getGuild()).getHelpForumConfig();
124+
return config.getHelpForumChannelId() != forum.getIdLong();
125+
}
126+
80127
private void handleHelpThanksInteraction(@NotNull ButtonInteractionEvent event, @NotNull ForumHelpManager manager, String @NotNull [] id) {
81128
ThreadChannel post = manager.postThread();
82129
HelpConfig config = Bot.getConfig().get(event.getGuild()).getHelpConfig();
@@ -108,4 +155,21 @@ private void handleHelpThanksInteraction(@NotNull ButtonInteractionEvent event,
108155
default -> event.editButton(event.getButton().asDisabled()).queue();
109156
}
110157
}
158+
159+
private void handleReplyGuidelines(@NotNull IReplyCallback callback, @NotNull ForumChannel channel) {
160+
callback.replyEmbeds(new EmbedBuilder()
161+
.setTitle("Help Guidelines")
162+
.setDescription(channel.getTopic())
163+
.build()
164+
).setEphemeral(true)
165+
.queue();
166+
}
167+
168+
private void handlePostClose(ButtonInteractionEvent event, @NotNull ForumHelpManager manager) {
169+
if (manager.isForumEligibleToBeUnreserved(event)) {
170+
manager.close(event, event.getUser().getIdLong() == manager.postThread().getOwnerIdLong(), null);
171+
} else {
172+
Responses.warning(event, "Could not close this post", "You're not allowed to close this post.").queue();
173+
}
174+
}
111175
}

src/main/java/net/javadiscord/javabot/systems/help/forum/ForumHelpManager.java

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package net.javadiscord.javabot.systems.help.forum;
22

33
import com.dynxsty.dih4jda.interactions.ComponentIdBuilder;
4+
import net.dv8tion.jda.api.entities.Guild;
45
import net.dv8tion.jda.api.entities.Member;
56
import net.dv8tion.jda.api.entities.Message;
67
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
78
import net.dv8tion.jda.api.entities.emoji.Emoji;
89
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
10+
import net.dv8tion.jda.api.interactions.Interaction;
911
import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
1012
import net.dv8tion.jda.api.interactions.components.ActionRow;
1113
import net.dv8tion.jda.api.interactions.components.ItemComponent;
1214
import net.dv8tion.jda.api.interactions.components.buttons.Button;
1315
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
1416
import net.javadiscord.javabot.Bot;
1517
import net.javadiscord.javabot.data.config.guild.HelpConfig;
18+
import net.javadiscord.javabot.data.config.guild.HelpForumConfig;
1619
import net.javadiscord.javabot.data.h2db.DbActions;
1720
import net.javadiscord.javabot.systems.help.HelpExperienceService;
1821
import net.javadiscord.javabot.systems.help.model.HelpTransactionMessage;
@@ -33,14 +36,19 @@
3336
*/
3437
public record ForumHelpManager(ThreadChannel postThread) {
3538
/**
36-
* Static String that contains the Thank Message Text.
39+
* The identifier used for all help thanks-related buttons.
3740
*/
38-
public static final String THANK_MESSAGE_TEXT = "Before your post will be closed, would you like to express your gratitude to any of the people who helped you? When you're done, click **I'm done here. Close this post!**.";
41+
public static final String HELP_THANKS_IDENTIFIER = "forum-help-thank";
3942

4043
/**
41-
* The identifier used for all help thanks-related buttons.
44+
* The identifier used for all help close-related buttons.
4245
*/
43-
public static final String HELP_THANKS_IDENTIFIER = "forum-help-thank";
46+
public static final String HELP_CLOSE_IDENTIFIER = "forum-help-close";
47+
48+
/**
49+
* The identifier used for all help guidelines-related buttons.
50+
*/
51+
public static final String HELP_GUIDELINES_IDENTIFIER = "forum-help-guidelines";
4452

4553
/**
4654
* Builds and replies {@link ActionRow}s with all members which helped the
@@ -51,6 +59,7 @@ public record ForumHelpManager(ThreadChannel postThread) {
5159
* @return The {@link ReplyCallbackAction}.
5260
*/
5361
public ReplyCallbackAction replyHelpThanks(IReplyCallback callback, @NotNull List<Member> helpers) {
62+
HelpForumConfig config = Bot.getConfig().get(callback.getGuild()).getHelpForumConfig();
5463
List<ItemComponent> helperThanksButtons = new ArrayList<>(20);
5564
for (Member helper : helpers.subList(0, Math.min(helpers.size(), 20))) {
5665
helperThanksButtons.add(Button.success(ComponentIdBuilder.build(HELP_THANKS_IDENTIFIER, postThread.getId(), helper.getId()), helper.getEffectiveName())
@@ -64,7 +73,7 @@ public ReplyCallbackAction replyHelpThanks(IReplyCallback callback, @NotNull Lis
6473
List<ActionRow> rows = new ArrayList<>();
6574
rows.add(controlsRow);
6675
rows.addAll(MessageActionUtils.toActionRows(helperThanksButtons));
67-
return callback.reply(THANK_MESSAGE_TEXT)
76+
return callback.reply(config.getHelpThanksText())
6877
.setComponents(rows);
6978
}
7079

@@ -121,6 +130,25 @@ public void thankHelper(@NotNull ButtonInteractionEvent event, ThreadChannel pos
121130
});
122131
}
123132

133+
/**
134+
* Checks if the interactions' user is eligible to close a forum post.
135+
*
136+
* @param interaction The interaction itself.
137+
* @return Whether the user is eligible to close the post.
138+
*/
139+
public boolean isForumEligibleToBeUnreserved(@NotNull Interaction interaction) {
140+
if (interaction.getGuild() == null) return false;
141+
return interaction.getUser().getIdLong() == postThread.getOwnerIdLong() ||
142+
hasMemberHelperRole(interaction.getGuild(), interaction.getMember()) || hasMemberStaffRole(interaction.getGuild(), interaction.getMember());
143+
}
144+
145+
private boolean hasMemberStaffRole(@NotNull Guild guild, @Nullable Member member) {
146+
return member != null && member.getRoles().contains(Bot.getConfig().get(guild).getModerationConfig().getStaffRole());
147+
}
148+
149+
private boolean hasMemberHelperRole(@NotNull Guild guild, @Nullable Member member) {
150+
return member != null && member.getRoles().contains(Bot.getConfig().get(guild).getHelpConfig().getHelperRole());
151+
}
124152

125153
private @NotNull List<Member> getPostHelpers() {
126154
List<Message> messages = ForumHelpListener.HELP_POST_MESSAGES.get(postThread.getIdLong());
@@ -129,7 +157,6 @@ public void thankHelper(@NotNull ButtonInteractionEvent event, ThreadChannel pos
129157
.filter(m -> m.getMember() != null && m.getAuthor().getIdLong() != postThread.getOwnerIdLong())
130158
.map(Message::getMember)
131159
.distinct()
132-
.limit(20)
133160
.toList();
134161
}
135162
}

src/main/java/net/javadiscord/javabot/systems/user_preferences/model/Preference.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ public enum Preference {
77
/**
88
* Enables/Disables QOTW reminders.
99
*/
10-
QOTW_REMINDER("Question of the Week Reminder", "false", new BooleanPreference());
10+
QOTW_REMINDER("Question of the Week Reminder", "false", new BooleanPreference()),
11+
/**
12+
* A boolean preference which enables/disables the close reminder in forum help posts.
13+
*/
14+
FORUM_CLOSE_REMINDER("Help Forum Close Reminder", "true", new BooleanPreference());
1115

1216
private final String name;
1317
private final String defaultState;

0 commit comments

Comments
 (0)