Skip to content

Commit 06dc663

Browse files
committed
resolved conflicts
2 parents 9bd78d5 + 3220fcb commit 06dc663

File tree

4 files changed

+91
-45
lines changed

4 files changed

+91
-45
lines changed

.github/workflows/stale.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

application/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ dependencies {
7474

7575
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.1'
7676

77-
implementation 'org.kohsuke:github-api:1.316'
77+
implementation 'org.kohsuke:github-api:1.317'
7878

7979
testImplementation 'org.mockito:mockito-core:5.3.1'
8080
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'

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

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
package org.togetherjava.tjbot.features.help;
22

33
import net.dv8tion.jda.api.EmbedBuilder;
4-
import net.dv8tion.jda.api.entities.Guild;
5-
import net.dv8tion.jda.api.entities.Message;
6-
import net.dv8tion.jda.api.entities.MessageEmbed;
7-
import net.dv8tion.jda.api.entities.Role;
4+
import net.dv8tion.jda.api.entities.*;
85
import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer;
96
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
107
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
118
import net.dv8tion.jda.api.entities.channel.forums.ForumTag;
129
import net.dv8tion.jda.api.entities.channel.forums.ForumTagSnowflake;
1310
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
1411
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
12+
import net.dv8tion.jda.api.interactions.components.buttons.Button;
1513
import net.dv8tion.jda.api.requests.RestAction;
1614
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
1715
import net.dv8tion.jda.api.utils.FileUpload;
@@ -26,6 +24,7 @@
2624
import org.togetherjava.tjbot.db.generated.tables.records.HelpThreadsRecord;
2725
import org.togetherjava.tjbot.features.chatgpt.ChatGptCommand;
2826
import org.togetherjava.tjbot.features.chatgpt.ChatGptService;
27+
import org.togetherjava.tjbot.features.componentids.ComponentIdInteractor;
2928

3029
import javax.annotation.Nullable;
3130

@@ -40,6 +39,7 @@
4039
import java.util.Map;
4140
import java.util.Optional;
4241
import java.util.Set;
42+
import java.util.concurrent.CopyOnWriteArrayList;
4343
import java.util.function.Consumer;
4444
import java.util.function.Function;
4545
import java.util.function.Predicate;
@@ -59,6 +59,7 @@ public final class HelpSystemHelper {
5959

6060
private static final String CODE_SYNTAX_EXAMPLE_PATH = "codeSyntaxExample.png";
6161

62+
private final Predicate<String> hasTagManageRole;
6263
private final Predicate<String> isHelpForumName;
6364
private final String helpForumPattern;
6465
/**
@@ -88,6 +89,7 @@ public HelpSystemHelper(Config config, Database database, ChatGptService chatGpt
8889
this.database = database;
8990
this.chatGptService = chatGptService;
9091

92+
hasTagManageRole = Pattern.compile(config.getTagManageRolePattern()).asMatchPredicate();
9193
helpForumPattern = helpConfig.getHelpForumPattern();
9294
isHelpForumName = Pattern.compile(helpForumPattern).asMatchPredicate();
9395

@@ -161,7 +163,7 @@ private RestAction<Message> sendExplanationMessage(GuildMessageChannel threadCha
161163
* why the message wasn't used.
162164
*/
163165
RestAction<Message> constructChatGptAttempt(ThreadChannel threadChannel,
164-
String originalQuestion) {
166+
String originalQuestion, ComponentIdInteractor componentIdInteractor) {
165167
Optional<String> questionOptional = prepareChatGptQuestion(threadChannel, originalQuestion);
166168
Optional<String[]> chatGPTAnswer;
167169

@@ -176,22 +178,39 @@ RestAction<Message> constructChatGptAttempt(ThreadChannel threadChannel,
176178
return useChatGptFallbackMessage(threadChannel);
177179
}
178180

181+
List<String> ids = new CopyOnWriteArrayList<>();
179182
RestAction<Message> message =
180183
mentionGuildSlashCommand(threadChannel.getGuild(), ChatGptCommand.COMMAND_NAME)
181184
.map("""
182185
Here is an AI assisted attempt to answer your question 🤖. Maybe it helps! \
183186
In any case, a human is on the way 👍. To continue talking to the AI, you can use \
184187
%s.
185188
"""::formatted)
186-
.flatMap(threadChannel::sendMessage);
189+
.flatMap(threadChannel::sendMessage)
190+
.onSuccess(m -> ids.add(m.getId()));
191+
String[] answers = chatGPTAnswer.orElseThrow();
192+
193+
for (int i = 0; i < answers.length; i++) {
194+
MessageCreateAction answer = threadChannel.sendMessage(answers[i]);
195+
196+
if (i == answers.length - 1) {
197+
message = message.flatMap(any -> answer
198+
.addActionRow(generateDismissButton(componentIdInteractor, ids)));
199+
continue;
200+
}
187201

188-
for (String aiResponse : chatGPTAnswer.get()) {
189-
message = message.map(aiResponse::formatted).flatMap(threadChannel::sendMessage);
202+
message = message.flatMap(ignored -> answer.onSuccess(m -> ids.add(m.getId())));
190203
}
191204

192205
return message;
193206
}
194207

208+
private Button generateDismissButton(ComponentIdInteractor componentIdInteractor,
209+
List<String> ids) {
210+
String buttonId = componentIdInteractor.generateComponentId(ids.toArray(String[]::new));
211+
return Button.danger(buttonId, "Dismiss");
212+
}
213+
195214
private Optional<String> prepareChatGptQuestion(ThreadChannel threadChannel,
196215
String originalQuestion) {
197216
String questionTitle = threadChannel.getName();
@@ -344,6 +363,10 @@ private static ForumTag requireTag(String tagName, ForumChannel forumChannel) {
344363
return matchingTags.get(0);
345364
}
346365

366+
boolean hasTagManageRole(Member member) {
367+
return member.getRoles().stream().map(Role::getName).anyMatch(hasTagManageRole);
368+
}
369+
347370
boolean isHelpForumName(String channelName) {
348371
return isHelpForumName.test(channelName);
349372
}

application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCreatedListener.java

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@
22

33
import com.github.benmanes.caffeine.cache.Cache;
44
import com.github.benmanes.caffeine.cache.Caffeine;
5+
import net.dv8tion.jda.api.entities.Member;
56
import net.dv8tion.jda.api.entities.Message;
67
import net.dv8tion.jda.api.entities.MessageEmbed;
78
import net.dv8tion.jda.api.entities.Role;
89
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
910
import net.dv8tion.jda.api.entities.channel.forums.ForumTag;
1011
import net.dv8tion.jda.api.events.channel.ChannelCreateEvent;
12+
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
13+
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
14+
import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent;
1115
import net.dv8tion.jda.api.hooks.ListenerAdapter;
1216
import net.dv8tion.jda.api.requests.RestAction;
1317

1418
import org.togetherjava.tjbot.features.EventReceiver;
19+
import org.togetherjava.tjbot.features.UserInteractionType;
20+
import org.togetherjava.tjbot.features.UserInteractor;
21+
import org.togetherjava.tjbot.features.componentids.ComponentIdGenerator;
22+
import org.togetherjava.tjbot.features.componentids.ComponentIdInteractor;
1523

1624
import java.time.Instant;
1725
import java.time.temporal.ChronoUnit;
26+
import java.util.List;
27+
import java.util.Objects;
1828
import java.util.concurrent.TimeUnit;
1929
import java.util.stream.Collectors;
2030

@@ -24,13 +34,16 @@
2434
* Will for example record thread metadata in the database and send an explanation message to the
2535
* user.
2636
*/
27-
public final class HelpThreadCreatedListener extends ListenerAdapter implements EventReceiver {
37+
public final class HelpThreadCreatedListener extends ListenerAdapter
38+
implements EventReceiver, UserInteractor {
2839

2940
private final HelpSystemHelper helper;
3041
private final Cache<Long, Instant> threadIdToCreatedAtCache = Caffeine.newBuilder()
3142
.maximumSize(1_000)
3243
.expireAfterAccess(2, TimeUnit.of(ChronoUnit.MINUTES))
3344
.build();
45+
private final ComponentIdInteractor componentIdInteractor =
46+
new ComponentIdInteractor(getInteractionType(), getName());
3447

3548
/**
3649
* Creates a new instance.
@@ -81,7 +94,7 @@ private RestAction<Message> createAIResponse(ThreadChannel threadChannel) {
8194
RestAction<Message> originalQuestion =
8295
threadChannel.retrieveMessageById(threadChannel.getIdLong());
8396
return originalQuestion.flatMap(message -> helper.constructChatGptAttempt(threadChannel,
84-
getMessageContent(message)));
97+
getMessageContent(message), componentIdInteractor));
8598
}
8699

87100
private RestAction<Void> pinOriginalQuestion(ThreadChannel threadChannel) {
@@ -125,4 +138,48 @@ private String getMessageContent(Message message) {
125138
.map(MessageEmbed::getDescription)
126139
.collect(Collectors.joining("\n"));
127140
}
141+
142+
@Override
143+
public String getName() {
144+
return "chatpgt-answer";
145+
}
146+
147+
@Override
148+
public UserInteractionType getInteractionType() {
149+
return UserInteractionType.OTHER;
150+
}
151+
152+
@Override
153+
public void acceptComponentIdGenerator(ComponentIdGenerator generator) {
154+
componentIdInteractor.acceptComponentIdGenerator(generator);
155+
}
156+
157+
@Override
158+
public void onButtonClick(ButtonInteractionEvent event, List<String> args) {
159+
// This method handles chatgpt's automatic response "dismiss" button
160+
ThreadChannel channel = event.getChannel().asThreadChannel();
161+
Member interactionUser = Objects.requireNonNull(event.getMember());
162+
if (channel.getOwnerIdLong() != interactionUser.getIdLong()
163+
&& !helper.hasTagManageRole(interactionUser)) {
164+
event.reply("You do not have permission for this action.").setEphemeral(true).queue();
165+
return;
166+
}
167+
168+
RestAction<Void> deleteMessages = event.getMessage().delete();
169+
for (String id : args) {
170+
deleteMessages = deleteMessages.and(channel.deleteMessageById(id));
171+
}
172+
deleteMessages.queue();
173+
}
174+
175+
@Override
176+
public void onSelectMenuSelection(SelectMenuInteractionEvent event, List<String> args) {
177+
throw new UnsupportedOperationException("Not used");
178+
}
179+
180+
@Override
181+
public void onModalSubmitted(ModalInteractionEvent event, List<String> args) {
182+
throw new UnsupportedOperationException("Not used");
183+
}
184+
128185
}

0 commit comments

Comments
 (0)