Add embed message support to Discord bot and update appeal flow to use embeds for Discord notifications

This commit is contained in:
2025-08-24 00:43:58 +02:00
parent ffddffa8dc
commit eab1c9322b
6 changed files with 187 additions and 95 deletions
@@ -1,64 +0,0 @@
package com.alttd.webinterface.bot;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@Slf4j
public class DiscordSender {
private static final DiscordSender INSTANCE = new DiscordSender();
private final DiscordBotInstance botInstance = new DiscordBotInstance();
private DiscordSender() {}
public static DiscordSender getInstance() {
return INSTANCE;
}
private void ensureStarted() {
if (botInstance.getJda() != null) return;
String token = Optional.ofNullable(System.getenv("DISCORD_TOKEN"))
.orElse(System.getProperty("DISCORD_TOKEN"));
if (token == null || token.isBlank()) {
log.error("Discord token not found. Set DISCORD_TOKEN as an environment variable or system property.");
return;
}
botInstance.start(token);
}
public void sendMessageToChannels(List<Long> channelIds, String message) {
ensureStarted();
if (botInstance.getJda() == null) {
log.error("JDA not initialized; cannot send Discord message.");
return;
}
try {
if (!botInstance.isReady()) {
botInstance.getJda().awaitReady();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.warn("Error while waiting for JDA ready state", e);
}
channelIds.stream()
.filter(Objects::nonNull)
.forEach(id -> {
TextChannel channel = botInstance.getJda().getChannelById(TextChannel.class, id);
if (channel == null) {
log.warn("TextChannel with id {} not found", id);
return;
}
channel.sendMessage(message).queue(
success -> log.debug("Sent message to channel {}", id),
error -> log.error("Failed sending message to channel {}", id, error)
);
});
}
}
@@ -0,0 +1,133 @@
package com.alttd.webinterface.send_message;
import com.alttd.webinterface.bot.DiscordBotInstance;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import java.awt.*;
import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@Slf4j
public class DiscordSender {
private static final DiscordSender INSTANCE = new DiscordSender();
private final DiscordBotInstance botInstance = new DiscordBotInstance();
private DiscordSender() {}
public static DiscordSender getInstance() {
return INSTANCE;
}
private void ensureStarted() {
if (botInstance.getJda() != null) return;
String token = Optional.ofNullable(System.getenv("DISCORD_TOKEN"))
.orElse(System.getProperty("DISCORD_TOKEN"));
if (token == null || token.isBlank()) {
log.error("Discord token not found. Set DISCORD_TOKEN as an environment variable or system property.");
return;
}
botInstance.start(token);
}
public void sendMessageToChannels(List<Long> channelIds, String message) {
ensureStarted();
if (botInstance.getJda() == null) {
log.error("JDA not initialized; cannot send Discord message.");
return;
}
try {
if (!botInstance.isReady()) {
botInstance.getJda().awaitReady();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.warn("Error while waiting for JDA ready state", e);
}
channelIds.stream()
.filter(Objects::nonNull)
.forEach(id -> {
TextChannel channel = botInstance.getJda().getChannelById(TextChannel.class, id);
if (channel == null) {
log.warn("TextChannel with id {} not found", id);
return;
}
channel.sendMessage(message).queue(
success -> log.debug("Sent message to channel {}", id),
error -> log.error("Failed sending message to channel {}", id, error)
);
});
}
public void sendEmbedToChannels(List<Long> channelIds, String title, String description, List<EmbedField> fields,
Integer colorRgb, Instant timestamp, String footer) {
ensureStarted();
if (botInstance.getJda() == null) {
log.error("JDA not initialized; cannot send Discord embed.");
return;
}
try {
if (!botInstance.isReady()) {
botInstance.getJda().awaitReady();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.warn("Error while waiting for JDA ready state", e);
}
EmbedBuilder eb = new EmbedBuilder();
if (title != null && !title.isBlank()) eb.setTitle(title);
if (description != null && !description.isBlank()) eb.setDescription(description);
if (colorRgb != null) eb.setColor(new Color(colorRgb)); else eb.setColor(new Color(0xFF8C00)); // default orange
eb.setTimestamp(timestamp != null ? timestamp : Instant.now());
if (footer != null && !footer.isBlank()) eb.setFooter(footer);
if (fields != null) {
for (EmbedField f : fields) {
if (f == null) continue;
String name = f.getName() == null ? "" : f.getName();
String value = f.getValue() == null ? "" : f.getValue();
// JDA field value max is 1024; truncate to be safe
if (value.length() > 1024) value = value.substring(0, 1021) + "...";
eb.addField(new MessageEmbed.Field(name, value, f.isInline()));
}
}
MessageEmbed embed = eb.build();
channelIds.stream()
.filter(Objects::nonNull)
.forEach(id -> {
TextChannel channel = botInstance.getJda().getChannelById(TextChannel.class, id);
if (channel == null) {
log.warn("TextChannel with id {} not found", id);
return;
}
channel.sendMessageEmbeds(embed).queue(
success -> log.debug("Sent embed to channel {}", id),
error -> log.error("Failed sending embed to channel {}", id, error)
);
});
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class EmbedField {
private String name;
private String value;
private boolean inline;
}
}