Skip to content

Commit 5d5938e

Browse files
authored
Improved application handling (#5)
no application process handling for non-applicants, tail channel archival
1 parent 6b25fd2 commit 5d5938e

6 files changed

Lines changed: 168 additions & 119 deletions

File tree

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ WORKDIR /app
2121
LABEL internal-port="8080"
2222

2323
LABEL arachne.name="Ninetales Discord Bot"
24-
LABEL arachne.version="1.1.5"
24+
LABEL arachne.version="1.1.6"
2525

26-
LABEL ninetales.update-note="Fixed unknown roles (soggy)"
26+
LABEL ninetales.update-note="Improved Application Handling -:\n- no application process handling for non-applicants,\n- tail channel archival, \n- small formatting tweaks"
2727

2828
# Copy the built JAR from build stage
2929
COPY --from=build /app/target/*.jar ./app.jar

src/main/java/ws/mia/ninetales/discord/GuildRankService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,19 @@ public void syncRoles(boolean retrieve) {
129129
// check if they have open app channels (close them, it means they've joined the guild)
130130
if (ntUser.getGuildApplicationChannelId() != null) {
131131
TextChannel tc = guild.getTextChannelById(ntUser.getGuildApplicationChannelId());
132-
applicationArchiveService.archiveApplication(tc, () -> {
132+
TextChannel tailC = guild.getTextChannelById(ntUser.getTailDiscussionChannelId());
133+
applicationArchiveService.archiveApplication(tc, tailC, () -> {
133134
tc.delete().queue();
134135
mongoUserService.setGuildApplicationChannelId(ntUser.getDiscordId(), null);
135136

136137
if (ntUser.isAwaitingHypixelInvite()) {
137138
mongoUserService.setAwaitingHypixelInvite(ntUser.getDiscordId(), false);
138139
}
139-
});
140-
}
141140

142-
if (ntUser.getTailDiscussionChannelId() != null) {
143-
guild.getTextChannelById(ntUser.getTailDiscussionChannelId()).delete().queue();
144-
mongoUserService.setTailDiscussionChannelId(ntUser.getDiscordId(), null);
141+
guild.getTextChannelById(ntUser.getTailDiscussionChannelId()).delete().queue();
142+
mongoUserService.setTailDiscussionChannelId(ntUser.getDiscordId(), null);
143+
144+
});
145145
}
146146

147147
});

src/main/java/ws/mia/ninetales/discord/application/ApplicationArchiveService.java

Lines changed: 130 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -17,110 +17,139 @@
1717
import java.util.ArrayList;
1818
import java.util.Collections;
1919
import java.util.List;
20+
import java.util.function.Consumer;
21+
import java.util.function.Function;
2022

2123
@Service
2224
public class ApplicationArchiveService {
2325

24-
private final MongoUserService mongoUserService;
25-
private final EnvironmentService environmentService;
26-
private final DiscordLogService discordLogService;
27-
private final MojangAPI mojangAPI;
28-
29-
public ApplicationArchiveService(MongoUserService mongoUserService, EnvironmentService environmentService, DiscordLogService discordLogService, MojangAPI mojangAPI) {
30-
this.mongoUserService = mongoUserService;
31-
this.environmentService = environmentService;
32-
this.discordLogService = discordLogService;
33-
this.mojangAPI = mojangAPI;
34-
}
35-
36-
/**
37-
* @param callback guarantee running after archival
38-
*/
39-
public void archiveApplication(TextChannel applicationChannel, Runnable callback) {
40-
// Note: using complete()'s would make this way more pretty and eliminate the need for a callback. However, thank JDA for making that throw an error inside of
41-
// calling callbacks because of some edge-cases -.-
42-
if(applicationChannel == null) return;
43-
44-
NinetalesUser ntUser = mongoUserService.getUserByApplicationChannelId(applicationChannel.getIdLong());
45-
if (ntUser == null) {
46-
return;
47-
}
48-
ForumChannel forum = null;
49-
String archContent = null;
50-
String nPrefix = "";
51-
if (ntUser.getGuildApplicationChannelId() != null) {
52-
String arch = environmentService.getGuildApplicationsArchiveForum();
53-
if (arch == null) return;
54-
forum = applicationChannel.getGuild().getForumChannelById(arch);
55-
archContent = "Archive of <@" + ntUser.getDiscordId() + ">'s guild application";
56-
nPrefix = ntUser.isAwaitingHypixelInvite() ? "Accepted - " : "Denied - ";
57-
}
58-
if (ntUser.getDiscordApplicationChannelId() != null) {
59-
String arch = environmentService.getDiscordApplicationsArchiveForum();
60-
if (arch == null) return;
61-
forum = applicationChannel.getGuild().getForumChannelById(arch);
62-
archContent = "Archive of <@" + ntUser.getDiscordId() + ">'s discord application";
63-
nPrefix = ntUser.isDiscordMember() ? "Accepted - " : "Denied - ";
64-
}
65-
66-
final String finalArchContent = archContent;
67-
final ForumChannel finalForum = forum;
68-
final String finalNPrefix = nPrefix;
69-
applicationChannel.getGuild().retrieveMemberById(ntUser.getDiscordId()).queue(ntMember -> {
70-
if (finalForum == null) return;
71-
72-
String mcName = mojangAPI.getUsername(ntUser.getMinecraftUuid());
73-
if (mcName == null) mcName = applicationChannel.getName();
74-
75-
final String finalChName = finalNPrefix + mcName;
76-
applicationChannel.getHistory().retrievePast(100).queue(ml -> {
77-
List<Message> messages = new ArrayList<>(ml);
78-
Collections.reverse(messages);
79-
80-
finalForum.createForumPost(finalChName, MessageCreateData.fromContent(finalArchContent)).queue(archiveChannel -> {
81-
List<MessageEmbed> embeds = new ArrayList<>();
82-
messages.forEach(message -> {
83-
Color c = message.getMember() != null ? message.getMember().getColor() : null;
84-
if(message.getMember() != null) {
85-
if (ntMember != null && ntMember.getId().equals(message.getMember().getId())) c = ntMember.getColor(); // more up-to-date
86-
}
87-
EmbedBuilder eb = new EmbedBuilder()
88-
.setAuthor(message.getAuthor().getEffectiveName(), null, message.getAuthor().getAvatarUrl())
89-
.setTimestamp(message.getTimeCreated())
90-
.setDescription(message.getContentDisplay())
91-
.setColor(c);
92-
embeds.add(eb.build());
93-
94-
});
95-
96-
// we can send up to 10 embeds at a time, so group.
97-
List<List<MessageEmbed>> partitions = new ArrayList<>();
98-
for (int i = 0; i < embeds.size(); i += 10) {
99-
partitions.add(embeds.subList(i, Math.min(i + 10, embeds.size())));
100-
}
101-
if (ntMember != null) {
102-
ntMember.getUser().openPrivateChannel().queue(pc -> {
103-
String ap = ntUser.getDiscordApplicationChannelId() != null ? "discord" : "guild";
104-
pc.sendMessage("Below is a transcript of your recent application to join the Ninetales %s:".formatted(ap)).queue();
105-
partitions.forEach(m -> {
106-
pc.sendMessageEmbeds(m).queue();
107-
});
108-
});
109-
}
110-
111-
partitions.forEach(m -> {
112-
archiveChannel.getThreadChannel().sendMessageEmbeds(m).queue();
113-
});
114-
115-
discordLogService.debug("Application Archive", "Archived <@" + ntUser.getDiscordId() + ">'s application to " + archiveChannel.getThreadChannel().getJumpUrl());
116-
archiveChannel.getThreadChannel().getManager().setLocked(true).queue();
117-
118-
callback.run();
119-
});
120-
});
121-
});
122-
123-
}
124-
26+
private final MongoUserService mongoUserService;
27+
private final EnvironmentService environmentService;
28+
private final DiscordLogService discordLogService;
29+
private final MojangAPI mojangAPI;
30+
31+
public ApplicationArchiveService(MongoUserService mongoUserService, EnvironmentService environmentService, DiscordLogService discordLogService, MojangAPI mojangAPI) {
32+
this.mongoUserService = mongoUserService;
33+
this.environmentService = environmentService;
34+
this.discordLogService = discordLogService;
35+
this.mojangAPI = mojangAPI;
36+
}
37+
38+
/**
39+
* @param callback guarantee running after archival
40+
*/
41+
public void archiveApplication(TextChannel applicationChannel, TextChannel tailChannel, Runnable callback) {
42+
// Note: using complete()'s would make this way more pretty and eliminate the need for a callback. However, thank JDA for making that throw an error inside of
43+
// calling callbacks because of some edge-cases -.-
44+
if (applicationChannel == null || tailChannel == null) return;
45+
46+
NinetalesUser ntUser = mongoUserService.getUserByApplicationChannelId(applicationChannel.getIdLong());
47+
if (ntUser == null) {
48+
return;
49+
}
50+
ForumChannel forum = null;
51+
String archContent = null;
52+
String nPrefix = "";
53+
if (ntUser.getGuildApplicationChannelId() != null) {
54+
String arch = environmentService.getGuildApplicationsArchiveForum();
55+
if (arch == null) return;
56+
forum = applicationChannel.getGuild().getForumChannelById(arch);
57+
archContent = "Archive of <@" + ntUser.getDiscordId() + ">'s guild application";
58+
nPrefix = ntUser.isAwaitingHypixelInvite() ? "Accepted - " : "Denied - ";
59+
}
60+
if (ntUser.getDiscordApplicationChannelId() != null) {
61+
String arch = environmentService.getDiscordApplicationsArchiveForum();
62+
if (arch == null) return;
63+
forum = applicationChannel.getGuild().getForumChannelById(arch);
64+
archContent = "Archive of <@" + ntUser.getDiscordId() + ">'s discord application";
65+
nPrefix = ntUser.isDiscordMember() ? "Accepted - " : "Denied - ";
66+
}
67+
68+
final String finalArchContent = archContent;
69+
final ForumChannel finalForum = forum;
70+
final String finalNPrefix = nPrefix;
71+
applicationChannel.getGuild().retrieveMemberById(ntUser.getDiscordId()).queue(ntMember -> {
72+
if (finalForum == null) return;
73+
74+
String mcName = mojangAPI.getUsername(ntUser.getMinecraftUuid());
75+
if (mcName == null) mcName = applicationChannel.getName();
76+
77+
final String finalChName = finalNPrefix + mcName;
78+
79+
finalForum.createForumPost(finalChName, MessageCreateData.fromContent(finalArchContent)).queue(archiveChannel -> {
80+
applicationChannel.getHistory().retrievePast(100).queue(appChannelRetrievedMsgs -> {
81+
List<Message> appChannelMsgs = new ArrayList<>(appChannelRetrievedMsgs);
82+
Collections.reverse(appChannelMsgs);
83+
84+
// we can send up to 10 embeds at a time, so group.
85+
Function<List<MessageEmbed>, List<List<MessageEmbed>>> partitionEmbeds = (l) -> {
86+
List<List<MessageEmbed>> partitions = new ArrayList<>();
87+
for (int i = 0; i < l.size(); i += 10) {
88+
partitions.add(l.subList(i, Math.min(i + 10, l.size())));
89+
}
90+
return partitions;
91+
};
92+
93+
Function<List<Message>, List<MessageEmbed>> createMsgEmbeds = (msgs) -> {
94+
List<MessageEmbed> embeds = new ArrayList<>();
95+
msgs.forEach(message -> {
96+
Color c = message.getMember() != null ? message.getMember().getColor() : null;
97+
if (message.getMember() != null) {
98+
if (ntMember != null && ntMember.getId().equals(message.getMember().getId())) {
99+
c = ntMember.getColor() != null ? ntMember.getColor() : c; // more up-to-date
100+
}
101+
}
102+
103+
EmbedBuilder eb = new EmbedBuilder()
104+
.setAuthor(message.getAuthor().getEffectiveName(), null, message.getAuthor().getAvatarUrl())
105+
.setTimestamp(message.getTimeCreated())
106+
.setDescription(message.getContentDisplay())
107+
.setColor(c);
108+
109+
embeds.add(eb.build());
110+
});
111+
return embeds;
112+
};
113+
114+
List<List<MessageEmbed>> appChannelPartitions = partitionEmbeds.apply(createMsgEmbeds.apply(appChannelMsgs));
115+
116+
if (ntMember != null) {
117+
ntMember.getUser().openPrivateChannel().queue(pc -> {
118+
String ap = ntUser.getDiscordApplicationChannelId() != null ? "discord" : "guild";
119+
pc.sendMessage("Below is a transcript of your recent application to join the Ninetales %s:".formatted(ap)).queue();
120+
appChannelPartitions.forEach(m -> {
121+
pc.sendMessageEmbeds(m).queue();
122+
});
123+
});
124+
}
125+
126+
archiveChannel.getThreadChannel().sendMessage("## Application Channel").queue();
127+
appChannelPartitions.forEach(m -> {
128+
archiveChannel.getThreadChannel().sendMessageEmbeds(m).queue();
129+
});
130+
131+
132+
tailChannel.getHistory().retrievePast(100).queue(tailChannelRetrievedMsgs -> {
133+
List<Message> tailChannelMsgs = new ArrayList<>(tailChannelRetrievedMsgs);
134+
Collections.reverse(tailChannelMsgs);
135+
136+
archiveChannel.getThreadChannel().sendMessage("## Tail Channel").queue();
137+
List<List<MessageEmbed>> tailChannelPartitions = partitionEmbeds.apply(createMsgEmbeds.apply(tailChannelMsgs));
138+
tailChannelPartitions.forEach(m -> {
139+
archiveChannel.getThreadChannel().sendMessageEmbeds(m).queue();
140+
});
141+
142+
discordLogService.debug("Application Archive", "Archived <@" + ntUser.getDiscordId() + ">'s application to " + archiveChannel.getThreadChannel().getJumpUrl());
143+
archiveChannel.getThreadChannel().getManager().setLocked(true).queue();
144+
145+
callback.run();
146+
});
147+
148+
});
149+
});
150+
151+
});
152+
153+
}
125154

126155
}

src/main/java/ws/mia/ninetales/discord/application/ApplicationProcessListener.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,36 @@
55
import net.dv8tion.jda.api.hooks.ListenerAdapter;
66
import org.jetbrains.annotations.NotNull;
77
import org.springframework.stereotype.Component;
8+
import ws.mia.ninetales.mongo.MongoUserService;
9+
import ws.mia.ninetales.mongo.NinetalesUser;
10+
11+
import java.util.Objects;
812

913
@Component
1014
public class ApplicationProcessListener extends ListenerAdapter {
1115

1216
private final ApplicationService applicationService;
17+
private final MongoUserService mongoUserService;
1318

14-
public ApplicationProcessListener(ApplicationService applicationService) {
19+
public ApplicationProcessListener(ApplicationService applicationService, MongoUserService mongoUserService) {
1520
this.applicationService = applicationService;
21+
this.mongoUserService = mongoUserService;
1622
}
1723

1824
@Override
1925
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
2026
super.onMessageReceived(event);
2127
if(event.getChannelType() != ChannelType.TEXT) return;
2228
if(event.getAuthor().isBot()) return;
23-
applicationService.attemptSendNextApplicationProcessMessage(event.getChannel().asTextChannel());
29+
30+
NinetalesUser ntMsgAuthor = mongoUserService.getUser(event.getAuthor().getIdLong());
31+
if(ntMsgAuthor == null) return;
32+
33+
if(Objects.equals(event.getChannel().getIdLong(), ntMsgAuthor.getDiscordApplicationChannelId()) ||
34+
Objects.equals(event.getChannel().getIdLong(), ntMsgAuthor.getGuildApplicationChannelId())) {
35+
applicationService.attemptSendNextApplicationProcessMessage(event.getChannel().asTextChannel());
36+
}
37+
2438
}
2539

2640

src/main/java/ws/mia/ninetales/discord/application/ApplicationService.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ public void closeApplication(SlashCommandInteractionEvent event) {
232232

233233
event.deferReply(true).queue();
234234

235-
applicationArchiveService.archiveApplication(event.getChannel().asTextChannel(), () -> {
235+
TextChannel tailC = event.getGuild().getTextChannelById(ntUser.getTailDiscussionChannelId());
236+
applicationArchiveService.archiveApplication(event.getChannel().asTextChannel(), tailC, () -> {
236237
event.getChannel().asTextChannel().delete().queue();
237238

238239
if (ntUser.isAwaitingHypixelInvite()) {
@@ -259,13 +260,13 @@ public void closeApplication(SlashCommandInteractionEvent event) {
259260
}
260261

261262
mongoUserService.setAwaitingHypixelInvite(ntUser.getDiscordId(), false);
263+
264+
if (ntUser.getTailDiscussionChannelId() != null) {
265+
mongoUserService.setTailDiscussionChannelId(ntUser.getDiscordId(), null);
266+
event.getGuild().getTextChannelById(ntUser.getTailDiscussionChannelId()).delete().queue();
267+
}
262268
});
263269

264-
265-
if (ntUser.getTailDiscussionChannelId() != null) {
266-
mongoUserService.setTailDiscussionChannelId(ntUser.getDiscordId(), null);
267-
event.getGuild().getTextChannelById(ntUser.getTailDiscussionChannelId()).delete().queue();
268-
}
269270
}
270271

271272
private void acceptDiscordApplication(NinetalesUser ntApplicant, Guild guild, Optional<String> message) {
@@ -283,7 +284,8 @@ private void acceptDiscordApplication(NinetalesUser ntApplicant, Guild guild, Op
283284

284285
// archive channel
285286
mongoUserService.setDiscordMember(ntApplicant.getDiscordId(), true);
286-
applicationArchiveService.archiveApplication(guild.getTextChannelById(ntApplicant.getDiscordApplicationChannelId()), () -> {
287+
TextChannel tailC = guild.getTextChannelById(ntApplicant.getTailDiscussionChannelId());
288+
applicationArchiveService.archiveApplication(guild.getTextChannelById(ntApplicant.getDiscordApplicationChannelId()), tailC, () -> {
287289
// delete channels
288290
guild.getTextChannelById(ntApplicant.getDiscordApplicationChannelId()).delete().queue();
289291
if (ntApplicant.getTailDiscussionChannelId() != null) {
@@ -351,8 +353,9 @@ public void attemptSendNextApplicationProcessMessage(TextChannel channel) {
351353
botMessages -= (isGuildApp) ? GUILD_APPLICATION_PRE_PROCESS.size() : DISCORD_APPLICATION_PRE_PROCESS.size();
352354
List<String> process = isGuildApp ? GUILD_APPLICATION_PROCESS : DISCORD_APPLICATION_PROCESS;
353355

354-
if (botMessages < 0)
356+
if (botMessages < 0) {
355357
botMessages = 0; // fix async issues (sometimes trying to send this before the pre messages causing -1)
358+
}
356359

357360
if (botMessages < process.size()) {
358361
channel.sendMessage(process.get((int) botMessages)).queue();

src/main/java/ws/mia/ninetales/discord/command/db/StatusCommand.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ public void onCommand(SlashCommandInteractionEvent event) {
8585
.append(" (joined ").append(Math.round(Duration.ofMillis(Instant.now().toEpochMilli() - player.getJoinTimestamp()).toDays())).append(" days ago)");
8686
} else {
8787
response.append("\nThey are **not** in the Ninetales Hypixel guild.");
88+
89+
response.append("\nThey are %sa discord member (Visitor)".formatted(ntUser.isDiscordMember() ? "" : "**not** "));
90+
8891
}
8992

9093
boolean appChannel = false;

0 commit comments

Comments
 (0)