functional editing notes

This commit is contained in:
2024-08-08 18:58:45 +02:00
parent a8a38b2c04
commit 71588a1bb7
4 changed files with 449 additions and 38 deletions
@@ -59,14 +59,14 @@ public class Main {
jda.upsertCommand(Commands.slash("note", "Get a note") jda.upsertCommand(Commands.slash("note", "Get a note")
.setIntegrationTypes(IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL) .setIntegrationTypes(IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL)
.addOptions( .addOptions(
new OptionData(OptionType.STRING, "note-id", "The ID of the note", true, true), new OptionData(OptionType.STRING, "alias", "The ID of the note", true, true),
new OptionData(OptionType.BOOLEAN, "ephermeal", "Whether the note should be ephermal", true) new OptionData(OptionType.BOOLEAN, "ephermeal", "Whether the note should be ephermal", false)
) )
.setContexts(InteractionContextType.BOT_DM, InteractionContextType.GUILD, InteractionContextType.PRIVATE_CHANNEL) .setContexts(InteractionContextType.BOT_DM, InteractionContextType.GUILD, InteractionContextType.PRIVATE_CHANNEL)
).queue(); ).queue();
jda.upsertCommand(Commands.slash("add-note", "Add a note") jda.upsertCommand(Commands.slash("add-note", "Add a note")
.setIntegrationTypes(IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL) .setIntegrationTypes(IntegrationType.USER_INSTALL)
.addOptions( .addOptions(
new OptionData(OptionType.STRING, "alias", "An alias for the note") new OptionData(OptionType.STRING, "alias", "An alias for the note")
.setMinLength(1) .setMinLength(1)
@@ -80,6 +80,10 @@ public class Main {
.setMinLength(1) .setMinLength(1)
.setMaxLength(4096) .setMaxLength(4096)
.setRequired(true), .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") new OptionData(OptionType.STRING, "image-url", "The image URL of the note")
.setMinLength(1) .setMinLength(1)
.setMaxLength(2000) .setMaxLength(2000)
@@ -89,7 +93,7 @@ public class Main {
.setMaxLength(2000) .setMaxLength(2000)
.setRequired(false), .setRequired(false),
new OptionData(OptionType.STRING, "color", "The color of the note") new OptionData(OptionType.STRING, "color", "The color of the note")
.setMinLength(1) .setMinLength(7)
.setMaxLength(7) .setMaxLength(7)
.setRequired(false), .setRequired(false),
new OptionData(OptionType.STRING, "author", "The author of the note") new OptionData(OptionType.STRING, "author", "The author of the note")
@@ -112,6 +116,56 @@ public class Main {
.setContexts(InteractionContextType.BOT_DM) .setContexts(InteractionContextType.BOT_DM)
).queue(); ).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();
} }
private static void loadProperties() { private static void loadProperties() {
@@ -18,8 +18,6 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Logger; import java.util.logging.Logger;
public class Storage { public class Storage {
public final List<String> aliases = new ArrayList<>(); public final List<String> aliases = new ArrayList<>();
@@ -110,8 +108,7 @@ public class Storage {
statement.executeUpdate(); statement.executeUpdate();
statement = connection.prepareStatement(""" statement = connection.prepareStatement("""
INSERT INTO aliases (alias, note_id) INSERT INTO aliases (alias, note_id) VALUES (?, ?)
VALUES (?, ?)
"""); """);
statement.setString(1, alias); statement.setString(1, alias);
statement.setString(2, note.id.toString()); statement.setString(2, note.id.toString());
@@ -128,6 +125,31 @@ public class Storage {
} }
} }
public Status editNote(UUID noteId, Note note) {
try (Connection connection = dataSource.getConnection()) {
PreparedStatement statement = connection.prepareStatement("""
UPDATE notes
SET title = ?, title_url = ?, description = ?, image_url = ?, thumbnail_url = ?, color = ?, author = ?, author_url = ?, footer = ?, footer_url = ?
WHERE id = ?
""");
statement.setString(1, note.title);
statement.setString(2, note.titleUrl);
statement.setString(3, note.content);
statement.setString(4, note.imageUrl);
statement.setString(5, note.thumbnailUrl);
statement.setInt(6, note.color != null ? note.color.getRGB() : 0);
statement.setString(7, note.author);
statement.setString(8, note.authorUrl);
statement.setString(9, note.footer);
statement.setString(10, note.footerUrl);
statement.setString(11, noteId.toString());
statement.executeUpdate();
return Status.SUCCESS;
} catch (SQLException e) {
return Status.ERROR;
}
}
public Status addAlias(@NotNull String alias, @NotNull UUID noteId) throws RuntimeException { public Status addAlias(@NotNull String alias, @NotNull UUID noteId) throws RuntimeException {
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
PreparedStatement statement = connection.prepareStatement(""" PreparedStatement statement = connection.prepareStatement("""
@@ -6,39 +6,55 @@ import me.youhavetrouble.noted.note.Note;
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.InteractionType;
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 net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
import java.awt.*;
import java.util.List; import java.util.List;
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"
);
@Override @Override
public void onCommandAutoCompleteInteraction(CommandAutoCompleteInteractionEvent event) { public void onCommandAutoCompleteInteraction(CommandAutoCompleteInteractionEvent event) {
if (event.getName().equals("note") && event.getFocusedOption().getName().equals("note-id")) { if (!event.getName().equals("note") || event.getName().equals("edit-note")) return;
List<Command.Choice> options = Main.getStorage().aliases.stream() if (!event.getFocusedOption().getName().equals("alias")) return;
.filter(word -> word.startsWith(event.getFocusedOption().getValue())) List<Command.Choice> options = Main.getStorage().aliases.stream()
.map(word -> new Command.Choice(word, word)) .filter(word -> word.startsWith(event.getFocusedOption().getValue()))
.limit(25) .map(word -> new Command.Choice(word, word))
.collect(Collectors.toList()); .limit(25)
event.replyChoices(options).queue(); .collect(Collectors.toList());
} event.replyChoices(options).queue();
} }
@Override @Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
switch (event.getName()) { switch (event.getName()) {
case "note" -> { case "note" -> {
OptionMapping noteIdOption = event.getOption("note-id"); OptionMapping noteIdOption = event.getOption("alias");
OptionMapping ephemeralOption = event.getOption("ephemeral"); OptionMapping ephemeralOption = event.getOption("ephemeral");
if (noteIdOption == null) { if (noteIdOption == null) {
event.reply("Please provide a note ID.") event.reply("Please provide a note alias.")
.setEphemeral(true) .setEphemeral(true)
.queue(); .queue();
return; return;
} }
boolean ephemeral; boolean ephemeral = false;
try { try {
ephemeral = ephemeralOption != null && ephemeralOption.getAsBoolean(); ephemeral = ephemeralOption != null && ephemeralOption.getAsBoolean();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@@ -58,20 +74,17 @@ public class SlashCommandListener extends ListenerAdapter {
.queue(); .queue();
return; return;
} }
addNote(event);
OptionMapping aliasOption = event.getOption("alias"); }
OptionMapping titleOption = event.getOption("title"); case "edit-note" -> {
OptionMapping contentOption = event.getOption("content"); Long adminId = Main.getAdminId();
if (titleOption == null || contentOption == null || aliasOption == null) { if (adminId == null || !adminId.equals(event.getUser().getIdLong())) {
event.reply("Please provide a alias, title and content.") event.reply("You do not have permission to use this command.")
.setEphemeral(true) .setEphemeral(true)
.queue(); .queue();
return; return;
} }
String alias = aliasOption.getAsString(); editNote(event);
String title = titleOption.getAsString();
String content = contentOption.getAsString();
addNote(event, alias, title, content);
} }
default -> event.reply("Unknown command.") default -> event.reply("Unknown command.")
@@ -94,26 +107,189 @@ public class SlashCommandListener extends ListenerAdapter {
.queue(); .queue();
} }
private void addNote(SlashCommandInteractionEvent event, String noteAlias, String title, String description) { private void addNote(SlashCommandInteractionEvent event) {
Note note = Note.createNew(title, description); OptionMapping aliasOption = event.getOption("alias");
Storage.Status status = Main.getStorage().addNote(note, noteAlias); OptionMapping titleOption = event.getOption("title");
OptionMapping contentOption = event.getOption("content");
if (status == Storage.Status.ALIAS_EXISTS) { 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());
}
Storage.Status status = Main.getStorage().addNote(note, aliasOption.getAsString());
if (status == Storage.Status.SUCCESS) {
event.reply("Note added.")
.setEphemeral(true)
.queue();
} else if (status == Storage.Status.ALIAS_EXISTS) {
event.reply("Alias already exists.") event.reply("Alias already exists.")
.setEphemeral(true) .setEphemeral(true)
.queue(); .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; return;
} }
if (status == Storage.Status.ERROR) { String noteAlias = noteAliasMapping.getAsString();
event.reply("An error occurred.")
Note note = Main.getStorage().getNote(noteAlias);
if (note == null) {
event.reply("Note with alias %s not found.".formatted(noteAlias))
.setEphemeral(true) .setEphemeral(true)
.queue(); .queue();
return; return;
} }
event.reply("Note added.") boolean shouldOpenModal = true;
.setEphemeral(true)
.queue(); for (String optionMappingId : optionMappingIds) {
if (event.getOption(optionMappingId) != null) {
shouldOpenModal = false;
break;
}
}
if (shouldOpenModal) {
// TODO open modal with few basic fields
event.reply("Here a modal should open. After I make it.")
.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();
}
} }
} }
@@ -48,6 +48,165 @@ public class Note {
this.footerUrl = footerUrl; this.footerUrl = footerUrl;
} }
public Note withTitle(@NotNull String title) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withTitleUrl(@Nullable String titleUrl) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withContent(@NotNull String content) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withImageUrl(@Nullable String imageUrl) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withThumbnailUrl(@Nullable String thumbnailUrl) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withColor(@Nullable Color color) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withAuthor(@Nullable String author) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withAuthorUrl(@Nullable String authorUrl) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withFooter(@Nullable String footer) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public Note withFooterUrl(@Nullable String footerUrl) {
return new Note(
id,
title,
titleUrl,
content,
imageUrl,
thumbnailUrl,
color,
author,
authorUrl,
footer,
footerUrl
);
}
public MessageEmbed toEmbed() { public MessageEmbed toEmbed() {
return new EmbedBuilder() return new EmbedBuilder()
.setTitle(title, titleUrl) .setTitle(title, titleUrl)