Skip to content

Commit 5e28950

Browse files
authored
Added /change-help-title command
1 parent 535777d commit 5e28950

File tree

4 files changed

+127
-22
lines changed

4 files changed

+127
-22
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public enum Features {
111111
features.add(new AskCommand(config, helpSystemHelper));
112112
features.add(new CloseCommand(helpSystemHelper));
113113
features.add(new ChangeHelpCategoryCommand(config, helpSystemHelper));
114+
features.add(new ChangeHelpTitleCommand(helpSystemHelper));
114115

115116
// Mixtures
116117
features.add(new HelpThreadOverviewUpdater(config, helpSystemHelper));

application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpCategoryCommand.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.time.Instant;
2020
import java.time.temporal.ChronoUnit;
21+
import java.util.Locale;
2122
import java.util.Optional;
2223
import java.util.concurrent.TimeUnit;
2324

@@ -34,8 +35,8 @@
3435
public final class ChangeHelpCategoryCommand extends SlashCommandAdapter {
3536
private static final String CATEGORY_OPTION = "category";
3637

37-
private static final int COOLDOWN_DURATION_VALUE = 1;
38-
private static final ChronoUnit COOLDOWN_DURATION_UNIT = ChronoUnit.HOURS;
38+
private static final int COOLDOWN_DURATION_VALUE = 30;
39+
private static final ChronoUnit COOLDOWN_DURATION_UNIT = ChronoUnit.MINUTES;
3940

4041
private final HelpSystemHelper helper;
4142
private final Cache<Long, Instant> helpThreadIdToLastCategoryChange;
@@ -82,8 +83,9 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
8283

8384
if (isHelpThreadOnCooldown(helpThread)) {
8485
event
85-
.reply("Please wait a bit, this command can only be used once per %d %s."
86-
.formatted(COOLDOWN_DURATION_VALUE, COOLDOWN_DURATION_UNIT))
86+
.reply("Please wait a bit, this command can only be used once per %d %s.".formatted(
87+
COOLDOWN_DURATION_VALUE,
88+
COOLDOWN_DURATION_UNIT.toString().toLowerCase(Locale.US)))
8789
.setEphemeral(true)
8890
.queue();
8991
return;
@@ -92,7 +94,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
9294

9395
event.deferReply().queue();
9496

95-
helper.renameChannelToCategoryTitle(helpThread, category)
97+
helper.renameChannelToCategory(helpThread, category)
9698
.flatMap(any -> sendCategoryChangedMessage(helpThread.getGuild(), event.getHook(),
9799
helpThread, category))
98100
.queue();
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package org.togetherjava.tjbot.commands.help;
2+
3+
import com.github.benmanes.caffeine.cache.Cache;
4+
import com.github.benmanes.caffeine.cache.Caffeine;
5+
import net.dv8tion.jda.api.entities.ThreadChannel;
6+
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
7+
import net.dv8tion.jda.api.interactions.commands.OptionType;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
10+
import org.togetherjava.tjbot.commands.SlashCommandVisibility;
11+
12+
import java.time.Instant;
13+
import java.time.temporal.ChronoUnit;
14+
import java.util.Locale;
15+
import java.util.Optional;
16+
import java.util.concurrent.TimeUnit;
17+
18+
/**
19+
* Implements the {@code /change-help-title} command, which is able to change the title of a help
20+
* thread.
21+
* <p>
22+
* This is to adjust a bad title in hindsight, for example if it was automatically created by
23+
* {@link ImplicitAskListener}.
24+
*/
25+
public final class ChangeHelpTitleCommand extends SlashCommandAdapter {
26+
private static final String TITLE_OPTION = "title";
27+
28+
private static final int COOLDOWN_DURATION_VALUE = 30;
29+
private static final ChronoUnit COOLDOWN_DURATION_UNIT = ChronoUnit.MINUTES;
30+
31+
private final HelpSystemHelper helper;
32+
private final Cache<Long, Instant> helpThreadIdToLastTitleChange;
33+
34+
/**
35+
* Creates a new instance.
36+
*
37+
* @param helper the helper to use
38+
*/
39+
public ChangeHelpTitleCommand(@NotNull HelpSystemHelper helper) {
40+
super("change-help-title", "changes the title of a help thread",
41+
SlashCommandVisibility.GUILD);
42+
43+
getData().addOption(OptionType.STRING, TITLE_OPTION, "short and to the point", true);
44+
45+
helpThreadIdToLastTitleChange = Caffeine.newBuilder()
46+
.maximumSize(1_000)
47+
.expireAfterAccess(COOLDOWN_DURATION_VALUE, TimeUnit.of(COOLDOWN_DURATION_UNIT))
48+
.build();
49+
50+
this.helper = helper;
51+
}
52+
53+
@Override
54+
public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
55+
String title = event.getOption(TITLE_OPTION).getAsString();
56+
57+
if (!helper.handleIsHelpThread(event)) {
58+
return;
59+
}
60+
61+
ThreadChannel helpThread = event.getThreadChannel();
62+
if (helpThread.isArchived()) {
63+
event.reply("This thread is already closed.").setEphemeral(true).queue();
64+
return;
65+
}
66+
67+
if (isHelpThreadOnCooldown(helpThread)) {
68+
event
69+
.reply("Please wait a bit, this command can only be used once per %d %s.".formatted(
70+
COOLDOWN_DURATION_VALUE,
71+
COOLDOWN_DURATION_UNIT.toString().toLowerCase(Locale.US)))
72+
.setEphemeral(true)
73+
.queue();
74+
return;
75+
}
76+
helpThreadIdToLastTitleChange.put(helpThread.getIdLong(), Instant.now());
77+
78+
helper.renameChannelToTitle(helpThread, title)
79+
.flatMap(any -> event.reply("Changed the title to **%s**.".formatted(title)))
80+
.queue();
81+
}
82+
83+
private boolean isHelpThreadOnCooldown(@NotNull ThreadChannel helpThread) {
84+
return Optional
85+
.ofNullable(helpThreadIdToLastTitleChange.getIfPresent(helpThread.getIdLong()))
86+
.map(lastCategoryChange -> lastCategoryChange.plus(COOLDOWN_DURATION_VALUE,
87+
COOLDOWN_DURATION_UNIT))
88+
.filter(Instant.now()::isBefore)
89+
.isPresent();
90+
}
91+
}

application/src/main/java/org/togetherjava/tjbot/commands/help/HelpSystemHelper.java

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -136,30 +136,24 @@ Optional<Role> handleFindRoleForCategory(@NotNull String category, @NotNull Guil
136136

137137
@NotNull
138138
Optional<String> getCategoryOfChannel(@NotNull Channel channel) {
139-
Matcher matcher = EXTRACT_CATEGORY_TITLE_PATTERN.matcher(channel.getName());
140-
if (!matcher.find()) {
141-
return Optional.empty();
142-
}
143-
144-
return Optional.ofNullable(matcher.group(CATEGORY_GROUP));
139+
return Optional.ofNullable(HelpThreadName.ofChannelName(channel.getName()).category);
145140
}
146141

147142
@NotNull
148-
RestAction<Void> renameChannelToCategoryTitle(@NotNull GuildChannel channel,
143+
RestAction<Void> renameChannelToCategory(@NotNull GuildChannel channel,
149144
@NotNull String category) {
150-
String currentTitle = channel.getName();
151-
Matcher matcher = EXTRACT_CATEGORY_TITLE_PATTERN.matcher(currentTitle);
145+
HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName());
146+
HelpThreadName changedName = new HelpThreadName(category, currentName.title);
152147

153-
if (!matcher.matches()) {
154-
throw new AssertionError("Pattern must match any thread name");
155-
}
156-
boolean hasCategoryInTitle = matcher.group(CATEGORY_GROUP) != null;
157-
String titleWithoutCategory =
158-
hasCategoryInTitle ? matcher.group(TITLE_GROUP) : currentTitle;
148+
return channel.getManager().setName(changedName.toChannelName());
149+
}
159150

160-
String titleWithCategory = "[%s] %s".formatted(category, titleWithoutCategory);
151+
@NotNull
152+
RestAction<Void> renameChannelToTitle(@NotNull GuildChannel channel, @NotNull String title) {
153+
HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName());
154+
HelpThreadName changedName = new HelpThreadName(currentName.category, title);
161155

162-
return channel.getManager().setName(titleWithCategory);
156+
return channel.getManager().setName(changedName.toChannelName());
163157
}
164158

165159
boolean isOverviewChannelName(@NotNull String channelName) {
@@ -186,4 +180,21 @@ static boolean isTitleValid(@NotNull CharSequence title) {
186180
return titleCompact.length() >= TITLE_COMPACT_LENGTH_MIN
187181
&& titleCompact.length() <= TITLE_COMPACT_LENGTH_MAX;
188182
}
183+
184+
private record HelpThreadName(@Nullable String category, @NotNull String title) {
185+
static @NotNull HelpThreadName ofChannelName(@NotNull CharSequence channelName) {
186+
Matcher matcher = EXTRACT_CATEGORY_TITLE_PATTERN.matcher(channelName);
187+
188+
if (!matcher.matches()) {
189+
throw new AssertionError("Pattern must match any thread name");
190+
}
191+
192+
return new HelpThreadName(matcher.group(CATEGORY_GROUP), matcher.group(TITLE_GROUP));
193+
}
194+
195+
@NotNull
196+
String toChannelName() {
197+
return category == null ? title : "[%s] %s".formatted(category, title);
198+
}
199+
}
189200
}

0 commit comments

Comments
 (0)