refactor command management

This commit is contained in:
2024-08-11 22:27:33 +02:00
parent fd97f86116
commit e1e41b4136
10 changed files with 734 additions and 548 deletions
+8 -137
View File
@@ -1,5 +1,6 @@
package me.youhavetrouble.noted; package me.youhavetrouble.noted;
import me.youhavetrouble.noted.command.*;
import me.youhavetrouble.noted.listener.SlashCommandListener; import me.youhavetrouble.noted.listener.SlashCommandListener;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.JDABuilder;
@@ -21,7 +22,7 @@ import java.util.logging.Logger;
public class Main { public class Main {
private static final Logger logger = Logger.getLogger("Main"); public static final Logger logger = Logger.getLogger("Main");
private static final Properties properties = new Properties(); private static final Properties properties = new Properties();
private static String version = "Unknown version"; private static String version = "Unknown version";
private static Storage storage; private static Storage storage;
@@ -66,142 +67,12 @@ public class Main {
command = "note"; command = "note";
} }
jda.upsertCommand(Commands.slash(command, "Get a note") Command.registerCommand(new NoteCommand(command));
.setIntegrationTypes(IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL) Command.registerCommand(new AddNoteCommand());
.addOptions( Command.registerCommand(new EditNoteCommand());
new OptionData(OptionType.STRING, "alias", "The ID of the note", true, true), Command.registerCommand(new DeleteNoteCommand());
new OptionData(OptionType.BOOLEAN, "ephermeal", "Whether the note should be ephermal", false) Command.registerCommand(new AddAliasCommand());
) Command.registerCommand(new DeleteAliasCommand());
.setContexts(InteractionContextType.BOT_DM, InteractionContextType.GUILD, InteractionContextType.PRIVATE_CHANNEL)
).queue();
jda.upsertCommand(Commands.slash("add-note", "Add a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "An alias for the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(true),
new OptionData(OptionType.STRING, "title", "The title of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(true),
new OptionData(OptionType.STRING, "content", "The content of the note")
.setMinLength(1)
.setMaxLength(4096)
.setRequired(true),
new OptionData(OptionType.STRING, "title-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "image-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "thumbnail-url", "The thumbnail URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "color", "The color of the note")
.setMinLength(7)
.setMaxLength(7)
.setRequired(false),
new OptionData(OptionType.STRING, "author", "The author of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "author-url", "The author URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "footer", "The footer of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "footer-url", "The footer URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
jda.upsertCommand(Commands.slash("edit-note", "Edit a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "An alias for the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(true),
new OptionData(OptionType.STRING, "title", "The title of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "content", "The content of the note")
.setMinLength(1)
.setMaxLength(4096)
.setRequired(false),
new OptionData(OptionType.STRING, "title-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "image-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "thumbnail-url", "The thumbnail URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "color", "The color of the note")
.setMinLength(7)
.setMaxLength(7)
.setRequired(false),
new OptionData(OptionType.STRING, "author", "The author of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "author-url", "The author URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "footer", "The footer of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "footer-url", "The footer URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
jda.upsertCommand(Commands.slash("delete-note", "Delete a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "The ID of the note", true, true)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
jda.upsertCommand(Commands.slash("add-alias", "Add alias to a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "Existing alias of a note", true, true),
new OptionData(OptionType.STRING, "new-alias", "New alias for the note", true)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
jda.upsertCommand(Commands.slash("delete-alias", "Remove alias to a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "Existing alias of a note", true, true)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
} }
private static void loadProperties() { private static void loadProperties() {
@@ -0,0 +1,78 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.Storage;
import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.IntegrationType;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
public class AddAliasCommand extends Command {
@Override
public void register(JDA jda, String name) {
jda.upsertCommand(Commands.slash("add-alias", "Add alias to a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "Existing alias of a note", true, true),
new OptionData(OptionType.STRING, "new-alias", "New alias for the note", true)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
}
@Override
public void execute(SlashCommandInteractionEvent event) {
OptionMapping noteAliasMapping = event.getOption("alias");
if (noteAliasMapping == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
OptionMapping newAliasMapping = event.getOption("new-alias");
if (newAliasMapping == null) {
event.reply("Please provide a new alias.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteAliasMapping.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
Storage.Status status = Main.getStorage().addAlias(newAliasMapping.getAsString(), note.id);
if (status == Storage.Status.SUCCESS) {
Note.ALIASES.add(newAliasMapping.getAsString());
event.reply("Alias added.")
.setEphemeral(true)
.queue();
} else if (status == Storage.Status.ALIAS_EXISTS) {
event.reply("Alias already exists.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to add alias.")
.setEphemeral(true)
.queue();
}
}
@Override
public String getName() {
return "add-alias";
}
}
@@ -0,0 +1,159 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.Storage;
import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.IntegrationType;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import java.awt.*;
public class AddNoteCommand extends Command {
@Override
public void register(JDA jda, String name) {
jda.upsertCommand(Commands.slash(getName(), "Add a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "An alias for the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(true),
new OptionData(OptionType.STRING, "title", "The title of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(true),
new OptionData(OptionType.STRING, "content", "The content of the note")
.setMinLength(1)
.setMaxLength(4096)
.setRequired(true),
new OptionData(OptionType.STRING, "title-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "image-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "thumbnail-url", "The thumbnail URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "color", "The color of the note")
.setMinLength(7)
.setMaxLength(7)
.setRequired(false),
new OptionData(OptionType.STRING, "author", "The author of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "author-url", "The author URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "footer", "The footer of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "footer-url", "The footer URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
}
@Override
public void execute(SlashCommandInteractionEvent event) {
OptionMapping aliasOption = event.getOption("alias");
OptionMapping titleOption = event.getOption("title");
OptionMapping contentOption = event.getOption("content");
if (titleOption == null || contentOption == null || aliasOption == null) {
event.reply("Please provide a alias, title and content.")
.setEphemeral(true)
.queue();
return;
}
Note note = Note.createNew(titleOption.getAsString(), contentOption.getAsString());
OptionMapping titleUrlOption = event.getOption("title-url");
if (titleUrlOption != null) {
note = note.withTitleUrl(titleUrlOption.getAsString());
}
OptionMapping imageUrlOption = event.getOption("image-url");
if (imageUrlOption != null) {
note = note.withImageUrl(imageUrlOption.getAsString());
}
OptionMapping thumbnailUrlOption = event.getOption("thumbnail-url");
if (thumbnailUrlOption != null) {
note = note.withThumbnailUrl(thumbnailUrlOption.getAsString());
}
OptionMapping colorOption = event.getOption("color");
if (colorOption != null) {
try {
note = note.withColor(Color.decode(colorOption.getAsString()));
} catch (NumberFormatException e) {
event.reply("Invalid color.")
.setEphemeral(true)
.queue();
return;
}
}
OptionMapping authorOption = event.getOption("author");
if (authorOption != null) {
note = note.withAuthor(authorOption.getAsString());
}
OptionMapping authorUrlOption = event.getOption("author-url");
if (authorUrlOption != null) {
note = note.withAuthorUrl(authorUrlOption.getAsString());
}
OptionMapping footerOption = event.getOption("footer");
if (footerOption != null) {
note = note.withFooter(footerOption.getAsString());
}
OptionMapping footerUrlOption = event.getOption("footer-url");
if (footerUrlOption != null) {
note = note.withFooterUrl(footerUrlOption.getAsString());
}
String alias = aliasOption.getAsString();
Storage.Status status = Main.getStorage().addNote(note, alias);
if (status == Storage.Status.SUCCESS) {
Note.ALIASES.add(alias);
event.reply("Note added.")
.setEphemeral(true)
.queue();
} else if (status == Storage.Status.ALIAS_EXISTS) {
event.reply("Alias already exists.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to add note.")
.setEphemeral(true)
.queue();
}
}
@Override
public String getName() {
return "add-note";
}
}
@@ -0,0 +1,65 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public abstract class Command extends ListenerAdapter {
private static final Map<String, Command> commands = new HashMap<>();
public void register(JDA jda, String name) {
}
public void execute(SlashCommandInteractionEvent event) {
}
@Nullable
public String getName() {
return null;
}
boolean canUse(User user) {
Long adminId = Main.getAdminId();
return adminId != null && adminId.equals(user.getIdLong());
}
public static void registerCommand(Command command) {
String name = command.getName();
if (commands.containsKey(name)) {
Main.logger.warning("Command " + name + " is already registered.");
return;
}
command.register(Main.jda, name);
commands.put(name, command);
}
public static void executeCommand(SlashCommandInteractionEvent event, String name) {
Command command = commands.get(name.toLowerCase(Locale.ENGLISH));
if (command == null) {
event.reply("Unknown command.")
.setEphemeral(true)
.queue();
return;
}
if (!command.canUse(event.getUser())) {
event.reply("You do not have permission to use this command.")
.setEphemeral(true)
.queue();
return;
}
command.execute(event);
}
}
@@ -0,0 +1,65 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.Storage;
import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.IntegrationType;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
public class DeleteAliasCommand extends Command {
@Override
public void register(JDA jda, String name) {
jda.upsertCommand(Commands.slash("delete-alias", "Remove alias to a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "Existing alias of a note", true, true)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
}
@Override
public void execute(SlashCommandInteractionEvent event) {
OptionMapping aliasMapping = event.getOption("alias");
if (aliasMapping == null) {
event.reply("Please provide a alias.")
.setEphemeral(true)
.queue();
return;
}
String alias = aliasMapping.getAsString();
Storage.Status status = Main.getStorage().deleteAlias(alias);
switch (status) {
case SUCCESS -> {
Note.ALIASES.remove(alias);
event.reply("Alias deleted.")
.setEphemeral(true)
.queue();
}
case ALIAS_NOT_FOUND -> event.reply("Provided alias does not exist.")
.setEphemeral(true)
.queue();
case ALIAS_IS_REQUIRED -> event.reply("At least one alias per note is required.")
.setEphemeral(true)
.queue();
case null, default -> event.reply("Failed to delete alias.")
.setEphemeral(true)
.queue();
}
}
@Override
public String getName() {
return "delete-alias";
}
}
@@ -0,0 +1,68 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.Storage;
import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.IntegrationType;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import java.util.Set;
public class DeleteNoteCommand extends Command {
@Override
public void register(JDA jda, String name) {
jda.upsertCommand(Commands.slash("delete-note", "Delete a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "The ID of the note", true, true)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
}
@Override
public void execute(SlashCommandInteractionEvent event) {
OptionMapping noteAliasMapping = event.getOption("alias");
if (noteAliasMapping == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteAliasMapping.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
Set<String> noteAliases = Main.getStorage().getAliases(note.id);
Storage.Status status = Main.getStorage().deleteNote(note.id);
if (status == Storage.Status.SUCCESS) {
noteAliases.forEach(Note.ALIASES::remove);
event.reply("Note deleted.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to delete note.")
.setEphemeral(true)
.queue();
}
}
@Override
public String getName() {
return "delete-note";
}
}
@@ -0,0 +1,198 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.Storage;
import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.IntegrationType;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import java.awt.*;
import java.util.List;
public class EditNoteCommand extends Command {
private final java.util.List<String> optionMappingIds = List.of(
"title",
"content",
"title-url",
"image-url",
"thumbnail-url",
"color",
"author",
"author-url",
"footer",
"footer-url"
);
@Override
public void register(JDA jda, String name) {
jda.upsertCommand(Commands.slash("edit-note", "Edit a note")
.setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "An alias for the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(true),
new OptionData(OptionType.STRING, "title", "The title of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "content", "The content of the note")
.setMinLength(1)
.setMaxLength(4096)
.setRequired(false),
new OptionData(OptionType.STRING, "title-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "image-url", "The image URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "thumbnail-url", "The thumbnail URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "color", "The color of the note")
.setMinLength(7)
.setMaxLength(7)
.setRequired(false),
new OptionData(OptionType.STRING, "author", "The author of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "author-url", "The author URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false),
new OptionData(OptionType.STRING, "footer", "The footer of the note")
.setMinLength(1)
.setMaxLength(256)
.setRequired(false),
new OptionData(OptionType.STRING, "footer-url", "The footer URL of the note")
.setMinLength(1)
.setMaxLength(2000)
.setRequired(false)
)
.setContexts(InteractionContextType.BOT_DM)
).queue();
}
@Override
public void execute(SlashCommandInteractionEvent event) {
OptionMapping noteAliasMapping = event.getOption("alias");
if (noteAliasMapping == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteAliasMapping.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
boolean shouldOpenModal = true;
for (String optionMappingId : optionMappingIds) {
if (event.getOption(optionMappingId) != null) {
shouldOpenModal = false;
break;
}
}
if (shouldOpenModal) {
// TODO open modal with few basic fields
event.reply("You need to provide arguments what parts of the note to edit.")
.setEphemeral(true)
.queue();
return;
}
OptionMapping titleOption = event.getOption("title");
if (titleOption != null) {
note = note.withTitle(titleOption.getAsString());
}
OptionMapping titleUrlOption = event.getOption("title-url");
if (titleUrlOption != null) {
note = note.withTitleUrl(titleUrlOption.getAsString());
}
OptionMapping contentOption = event.getOption("content");
if (contentOption != null) {
note = note.withContent(contentOption.getAsString());
}
OptionMapping imageUrlOption = event.getOption("image-url");
if (imageUrlOption != null) {
note = note.withImageUrl(imageUrlOption.getAsString());
}
OptionMapping thumbnailUrlOption = event.getOption("thumbnail-url");
if (thumbnailUrlOption != null) {
note = note.withThumbnailUrl(thumbnailUrlOption.getAsString());
}
OptionMapping colorOption = event.getOption("color");
if (colorOption != null) {
try {
note = note.withColor(Color.decode(colorOption.getAsString()));
} catch (NumberFormatException e) {
event.reply("Invalid color.")
.setEphemeral(true)
.queue();
return;
}
}
OptionMapping authorOption = event.getOption("author");
if (authorOption != null) {
note = note.withAuthor(authorOption.getAsString());
}
OptionMapping authorUrlOption = event.getOption("author-url");
if (authorUrlOption != null) {
note = note.withAuthorUrl(authorUrlOption.getAsString());
}
OptionMapping footerOption = event.getOption("footer");
if (footerOption != null) {
note = note.withFooter(footerOption.getAsString());
}
OptionMapping footerUrlOption = event.getOption("footer-url");
if (footerUrlOption != null) {
note = note.withFooterUrl(footerUrlOption.getAsString());
}
Storage.Status status = Main.getStorage().editNote(note.id, note);
if (status == Storage.Status.SUCCESS) {
event.reply("Note edited.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to edit note.")
.setEphemeral(true)
.queue();
}
}
@Override
public String getName() {
return "edit-note";
}
}
@@ -0,0 +1,85 @@
package me.youhavetrouble.noted.command;
import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.IntegrationType;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import java.util.Locale;
public class NoteCommand extends Command {
private final String commandName;
public NoteCommand(String commandName) {
if (commandName.equals("add-note") || commandName.equals("edit-note")) {
Main.logger.warning("The command name " + commandName + " is reserved. Please change the command name in noted.properties.");
Main.logger.warning("The command name has been changed to 'note'.");
this.commandName = "note";
return;
}
this.commandName = commandName.toLowerCase(Locale.ENGLISH);
}
@Override
public void register(JDA jda, String name) {
jda.upsertCommand(Commands.slash(commandName, "Get a note")
.setIntegrationTypes(IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL)
.addOptions(
new OptionData(OptionType.STRING, "alias", "The ID of the note", true, true),
new OptionData(OptionType.BOOLEAN, "ephermeal", "Whether the note should be ephermal", false)
)
.setContexts(InteractionContextType.BOT_DM, InteractionContextType.GUILD, InteractionContextType.PRIVATE_CHANNEL)
).queue();
}
@Override
public void execute(SlashCommandInteractionEvent event) {
OptionMapping noteIdOption = event.getOption("alias");
OptionMapping ephemeralOption = event.getOption("ephemeral");
if (noteIdOption == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
boolean ephemeral;
try {
ephemeral = ephemeralOption != null && ephemeralOption.getAsBoolean();
} catch (IllegalArgumentException e) {
event.reply("Invalid value for ephemeral.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteIdOption.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
event.replyEmbeds(note.toEmbed())
.setEphemeral(ephemeral)
.queue();
}
@Override
public boolean canUse(User user) {
return true;
}
@Override
public String getName() {
return commandName;
}
}
@@ -1,45 +1,24 @@
package me.youhavetrouble.noted.listener; package me.youhavetrouble.noted.listener;
import me.youhavetrouble.noted.Main; import me.youhavetrouble.noted.Main;
import me.youhavetrouble.noted.Storage;
import me.youhavetrouble.noted.note.Note; import me.youhavetrouble.noted.note.Note;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.Command;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import java.awt.Color;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SlashCommandListener extends ListenerAdapter { public class SlashCommandListener extends ListenerAdapter {
private final List<String> optionMappingIds = List.of(
"title",
"content",
"title-url",
"image-url",
"thumbnail-url",
"color",
"author",
"author-url",
"footer",
"footer-url"
);
private final Set<String> aliases;
public SlashCommandListener() { public SlashCommandListener() {
aliases = Main.getStorage().getAliases(); Note.ALIASES.addAll(Main.getStorage().getAliases());
} }
@Override @Override
public void onCommandAutoCompleteInteraction(CommandAutoCompleteInteractionEvent event) { public void onCommandAutoCompleteInteraction(CommandAutoCompleteInteractionEvent event) {
if (!event.getFocusedOption().getName().equals("alias")) return; if (!event.getFocusedOption().getName().equals("alias")) return;
List<Command.Choice> options = aliases.stream() List<Command.Choice> options = Note.ALIASES.stream()
.filter(word -> word.startsWith(event.getFocusedOption().getValue())) .filter(word -> word.startsWith(event.getFocusedOption().getValue()))
.map(word -> new Command.Choice(word, word)) .map(word -> new Command.Choice(word, word))
.limit(25) .limit(25)
@@ -49,394 +28,8 @@ public class SlashCommandListener extends ListenerAdapter {
@Override @Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
if (Main.command.equals(event.getName())) { String command = event.getName();
OptionMapping noteIdOption = event.getOption("alias"); me.youhavetrouble.noted.command.Command.executeCommand(event, command);
OptionMapping ephemeralOption = event.getOption("ephemeral");
if (noteIdOption == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
boolean ephemeral = false;
try {
ephemeral = ephemeralOption != null && ephemeralOption.getAsBoolean();
} catch (IllegalArgumentException e) {
event.reply("Invalid value for ephemeral.")
.setEphemeral(true)
.queue();
return;
}
String noteId = noteIdOption.getAsString();
getNote(event, noteId, ephemeral);
return;
}
switch (event.getName()) {
case "add-note" -> {
if (!isAdmin(event.getUser())) {
event.reply("You do not have permission to use this command.")
.setEphemeral(true)
.queue();
return;
}
addNote(event);
}
case "edit-note" -> {
if (!isAdmin(event.getUser())) {
event.reply("You do not have permission to use this command.")
.setEphemeral(true)
.queue();
return;
}
editNote(event);
}
case "delete-note" -> {
if (!isAdmin(event.getUser())) {
event.reply("You do not have permission to use this command.")
.setEphemeral(true)
.queue();
return;
}
deleteNote(event);
}
case "add-alias" -> {
if (!isAdmin(event.getUser())) {
event.reply("You do not have permission to use this command.")
.setEphemeral(true)
.queue();
return;
}
addAlias(event);
}
case "delete-alias" -> {
if (!isAdmin(event.getUser())) {
event.reply("You do not have permission to use this command.")
.setEphemeral(true)
.queue();
return;
}
deleteAlias(event);
}
default -> event.reply("Unknown command.")
.setEphemeral(true)
.queue();
}
}
private boolean isAdmin(User user) {
Long adminId = Main.getAdminId();
return adminId != null && adminId.equals(user.getIdLong());
}
private void getNote(SlashCommandInteractionEvent event, String noteAlias, boolean ephemeral) {
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
event.replyEmbeds(note.toEmbed())
.setEphemeral(ephemeral)
.queue();
}
private void addNote(SlashCommandInteractionEvent event) {
OptionMapping aliasOption = event.getOption("alias");
OptionMapping titleOption = event.getOption("title");
OptionMapping contentOption = event.getOption("content");
if (titleOption == null || contentOption == null || aliasOption == null) {
event.reply("Please provide a alias, title and content.")
.setEphemeral(true)
.queue();
return;
}
Note note = Note.createNew(titleOption.getAsString(), contentOption.getAsString());
OptionMapping titleUrlOption = event.getOption("title-url");
if (titleUrlOption != null) {
note = note.withTitleUrl(titleUrlOption.getAsString());
}
OptionMapping imageUrlOption = event.getOption("image-url");
if (imageUrlOption != null) {
note = note.withImageUrl(imageUrlOption.getAsString());
}
OptionMapping thumbnailUrlOption = event.getOption("thumbnail-url");
if (thumbnailUrlOption != null) {
note = note.withThumbnailUrl(thumbnailUrlOption.getAsString());
}
OptionMapping colorOption = event.getOption("color");
if (colorOption != null) {
try {
note = note.withColor(Color.decode(colorOption.getAsString()));
} catch (NumberFormatException e) {
event.reply("Invalid color.")
.setEphemeral(true)
.queue();
return;
}
}
OptionMapping authorOption = event.getOption("author");
if (authorOption != null) {
note = note.withAuthor(authorOption.getAsString());
}
OptionMapping authorUrlOption = event.getOption("author-url");
if (authorUrlOption != null) {
note = note.withAuthorUrl(authorUrlOption.getAsString());
}
OptionMapping footerOption = event.getOption("footer");
if (footerOption != null) {
note = note.withFooter(footerOption.getAsString());
}
OptionMapping footerUrlOption = event.getOption("footer-url");
if (footerUrlOption != null) {
note = note.withFooterUrl(footerUrlOption.getAsString());
}
String alias = aliasOption.getAsString();
Storage.Status status = Main.getStorage().addNote(note, alias);
if (status == Storage.Status.SUCCESS) {
aliases.add(alias);
event.reply("Note added.")
.setEphemeral(true)
.queue();
} else if (status == Storage.Status.ALIAS_EXISTS) {
event.reply("Alias already exists.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to add note.")
.setEphemeral(true)
.queue();
}
}
private void editNote(SlashCommandInteractionEvent event) {
OptionMapping noteAliasMapping = event.getOption("alias");
if (noteAliasMapping == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteAliasMapping.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
boolean shouldOpenModal = true;
for (String optionMappingId : optionMappingIds) {
if (event.getOption(optionMappingId) != null) {
shouldOpenModal = false;
break;
}
}
if (shouldOpenModal) {
// TODO open modal with few basic fields
event.reply("You need to provide arguments what parts of the note to edit.")
.setEphemeral(true)
.queue();
return;
}
OptionMapping titleOption = event.getOption("title");
if (titleOption != null) {
note = note.withTitle(titleOption.getAsString());
}
OptionMapping titleUrlOption = event.getOption("title-url");
if (titleUrlOption != null) {
note = note.withTitleUrl(titleUrlOption.getAsString());
}
OptionMapping contentOption = event.getOption("content");
if (contentOption != null) {
note = note.withContent(contentOption.getAsString());
}
OptionMapping imageUrlOption = event.getOption("image-url");
if (imageUrlOption != null) {
note = note.withImageUrl(imageUrlOption.getAsString());
}
OptionMapping thumbnailUrlOption = event.getOption("thumbnail-url");
if (thumbnailUrlOption != null) {
note = note.withThumbnailUrl(thumbnailUrlOption.getAsString());
}
OptionMapping colorOption = event.getOption("color");
if (colorOption != null) {
try {
note = note.withColor(Color.decode(colorOption.getAsString()));
} catch (NumberFormatException e) {
event.reply("Invalid color.")
.setEphemeral(true)
.queue();
return;
}
}
OptionMapping authorOption = event.getOption("author");
if (authorOption != null) {
note = note.withAuthor(authorOption.getAsString());
}
OptionMapping authorUrlOption = event.getOption("author-url");
if (authorUrlOption != null) {
note = note.withAuthorUrl(authorUrlOption.getAsString());
}
OptionMapping footerOption = event.getOption("footer");
if (footerOption != null) {
note = note.withFooter(footerOption.getAsString());
}
OptionMapping footerUrlOption = event.getOption("footer-url");
if (footerUrlOption != null) {
note = note.withFooterUrl(footerUrlOption.getAsString());
}
Storage.Status status = Main.getStorage().editNote(note.id, note);
if (status == Storage.Status.SUCCESS) {
event.reply("Note edited.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to edit note.")
.setEphemeral(true)
.queue();
}
}
private void deleteNote(SlashCommandInteractionEvent event) {
OptionMapping noteAliasMapping = event.getOption("alias");
if (noteAliasMapping == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteAliasMapping.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
Set<String> noteAliases = Main.getStorage().getAliases(note.id);
Storage.Status status = Main.getStorage().deleteNote(note.id);
if (status == Storage.Status.SUCCESS) {
noteAliases.forEach(aliases::remove);
event.reply("Note deleted.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to delete note.")
.setEphemeral(true)
.queue();
}
}
private void addAlias(SlashCommandInteractionEvent event) {
OptionMapping noteAliasMapping = event.getOption("alias");
if (noteAliasMapping == null) {
event.reply("Please provide a note alias.")
.setEphemeral(true)
.queue();
return;
}
OptionMapping newAliasMapping = event.getOption("new-alias");
if (newAliasMapping == null) {
event.reply("Please provide a new alias.")
.setEphemeral(true)
.queue();
return;
}
String noteAlias = noteAliasMapping.getAsString();
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true)
.queue();
return;
}
Storage.Status status = Main.getStorage().addAlias(newAliasMapping.getAsString(), note.id);
if (status == Storage.Status.SUCCESS) {
aliases.add(newAliasMapping.getAsString());
event.reply("Alias added.")
.setEphemeral(true)
.queue();
} else if (status == Storage.Status.ALIAS_EXISTS) {
event.reply("Alias already exists.")
.setEphemeral(true)
.queue();
} else {
event.reply("Failed to add alias.")
.setEphemeral(true)
.queue();
}
}
private void deleteAlias(SlashCommandInteractionEvent event) {
OptionMapping aliasMapping = event.getOption("alias");
if (aliasMapping == null) {
event.reply("Please provide a alias.")
.setEphemeral(true)
.queue();
return;
}
String alias = aliasMapping.getAsString();
Storage.Status status = Main.getStorage().deleteAlias(alias);
switch (status) {
case SUCCESS -> {
aliases.remove(alias);
event.reply("Alias deleted.")
.setEphemeral(true)
.queue();
}
case ALIAS_NOT_FOUND -> event.reply("Provided alias does not exist.")
.setEphemeral(true)
.queue();
case ALIAS_IS_REQUIRED -> event.reply("At least one alias per note is required.")
.setEphemeral(true)
.queue();
case null, default -> event.reply("Failed to delete alias.")
.setEphemeral(true)
.queue();
}
} }
} }
@@ -6,10 +6,14 @@ import net.dv8tion.jda.api.entities.MessageEmbed;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.awt.Color; import java.awt.Color;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
public class Note { public class Note {
public static final Set<String> ALIASES = new HashSet<>();
public final UUID id; public final UUID id;
public final String title; public final String title;
public final String titleUrl; public final String titleUrl;