Conversation
A command to attach form buttons to bot's messages Form data deserialization Store forms in database Use an array of form fields instead of a form data object Move `FormsRepository` and `FormField` to different packages Reading forms from database Open modals on form button interaction Log submissions in a configured channel Allow setting a custom submission message Use an *Empty* value if user ommits a field Ignore case when parsing form field text input styles Store forms' origin messages, their channels, and expiration date Form delete command autocompletion Form delete command Forms closing and reopening commands Form details command Form modification command Check if the form is not closed or expired on submission Reword expiration command parameter description Additional checks in all form commands Don't accept raw JSON data and don't immediately attach forms Added `add-field` form command Form field remove command Form show command Put a limit of 5 components for forms Allow field inserting Forms attach and detach commands Prevent removing the last field from an attached form Javadocs Remove redundant checks from form commands Move some common methods to the form interaction manager Added `hasExpired` method to `FormData` Add `onetime` form parameter Logging form submissions to the database Add a repository method to query forms for a specific `closed` state Include total submissions count in the form details message Additional null checks in the forms repository Prevent further submissions to one-time forms A command to export all form submissions Delete form submissions on form deletion Command to delete user's submissions Fix checkstyle violations
danthe1st
left a comment
There was a problem hiding this comment.
This is my initial review which is about the model and database.
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormData.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormField.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormField.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormField.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormUser.java
Outdated
Show resolved
Hide resolved
danthe1st
left a comment
There was a problem hiding this comment.
Round 2 of reviewing, FormInteractionManager, /form add-field, /form attach
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/commands/FormCommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/FormInteractionManager.java
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/FormInteractionManager.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/FormInteractionManager.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/FormInteractionManager.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/FormInteractionManager.java
Show resolved
Hide resolved
danthe1st
left a comment
There was a problem hiding this comment.
With this, most of the changed files should be reviewed.
TODO for myself: check with spotbugs
...n/java/net/discordjug/javabot/systems/staff_commands/forms/commands/CloseFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
...ava/net/discordjug/javabot/systems/staff_commands/forms/commands/AddFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
.../net/discordjug/javabot/systems/staff_commands/forms/commands/RemoveFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
.../net/discordjug/javabot/systems/staff_commands/forms/commands/RemoveFieldFormSubcommand.java
Outdated
Show resolved
Hide resolved
.../java/net/discordjug/javabot/systems/staff_commands/forms/commands/ReopenFormSubcommand.java
Show resolved
Hide resolved
.../java/net/discordjug/javabot/systems/staff_commands/forms/commands/ReopenFormSubcommand.java
Outdated
Show resolved
Hide resolved
| if (!form.isClosed()) { | ||
| event.reply("This form is already opened").setEphemeral(true).queue(); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Maybe also add an error if the form is expired? After all, there isn't much of a point in reopening an expired form...
danthe1st
left a comment
There was a problem hiding this comment.
This should be the last review of your initial version.
Overall, the structure is mostly good but there are quite a few things I found.
I think you could use JDA's capabilities more in some places and you are repeating yourself quite a bit between all of the subcommands. This can be refactored using a superclass for form subcommands that operate on a form. This would allow you using common handling for autocomplete, addition (the constructor in the superclass can accept FormRepository (if necessary), the description and the OptionDatas (or similar) of the subcommand) and extraction of the form-id (or form) argument and the loading of the FormData. If the FormData is present, you could call an abstract method, e.g. protected abstract execute(SlashCommandInteractionEvent event, FormData form)
This would also allow you using Optional#ifPresentOrElse for the FormData instead of Optional#get.
...in/java/net/discordjug/javabot/systems/staff_commands/forms/commands/ShowFormSubcommand.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsDeleteFormSubcommand.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsDeleteFormSubcommand.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsDeleteFormSubcommand.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsExportFormSubcommand.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsExportFormSubcommand.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsExportFormSubcommand.java
Outdated
Show resolved
Hide resolved
danthe1st
left a comment
There was a problem hiding this comment.
TODO for myself: test with native-image - there shouldn't be any issues but just in case...
danthe1st
left a comment
There was a problem hiding this comment.
Please still act on the other requested changes like unifying autocomplete.
|
|
||
| CREATE TABLE FORM_SUBMISSIONS ( | ||
| ID BIGINT NOT NULL AUTO_INCREMENT, | ||
| MESSAGE_ID BIGINT NOT NULL, |
There was a problem hiding this comment.
If you are storing a message ID, is there a need to add a distinct ID for the primary key?
.../java/net/discordjug/javabot/systems/staff_commands/forms/commands/DeleteFormSubcommand.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/dao/FormsRepository.java
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/dao/FormsRepository.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormData.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormField.java
Outdated
Show resolved
Hide resolved
src/main/java/net/discordjug/javabot/systems/staff_commands/forms/model/FormData.java
Outdated
Show resolved
Hide resolved
...iscordjug/javabot/systems/staff_commands/forms/commands/SubmissionsDeleteFormSubcommand.java
Outdated
Show resolved
Hide resolved
|
By the way, the last build failed because of checkstyle. |
I know. I will take care of checkstyle once I'm done writing the actual code. |
Signed-off-by: Defective <def3ctive4@gmail.com>
b1b596f to
3425fa0
Compare
|
Also, please keep in mind that even though I'm pushing new commits, I'm still not done addressing most of the issues. I have a habit of pushing immediately after committing new changes to the code. |
Just comment when you think I should re-review it. |
|
Okay, the PR should be ready to re-review. |
992be05 to
06d724b
Compare
06d724b to
f43f7df
Compare
danthe1st
left a comment
There was a problem hiding this comment.
Most of these comments are fairly minor details.
Overall, it looks pretty good.
| FormData form = formOpt.get(); | ||
|
|
||
| if (form.getFields().size() >= 5) { | ||
| if (form.fields().size() >= 5) { |
There was a problem hiding this comment.
I think you could use Message.MAX_COMPONENT_COUNT for this.
| "Whether or not the user has to input data in this field. Default: false") | ||
| .addOption(OptionType.STRING, "style", "Input style. Default: SHORT", false, true) | ||
| .addOption(OptionType.STRING, "value", "Initial field value")); | ||
| .addOption(OptionType.STRING, FORM_STYLE_FIELD, "Input style. Default: SHORT", false, true) |
There was a problem hiding this comment.
I think there are only two possible styles. Hence, you could use OptionData#addOption to specify a predefined amount of options and Discord should ensure that only these options can be used.
| /** | ||
| * The `/form attach` command. | ||
| * The `/form attach` command. This command can be used to attach a form to an | ||
| * existing message. "Attaching" a form to message in this case mean that the |
There was a problem hiding this comment.
Grammar: "Attaching" a form to a message means
| } | ||
| }); | ||
| String buttonLabel = event.getOption(FORM_BUTTON_LABEL_FIELD, "Submit", OptionMapping::getAsString); | ||
| net.dv8tion.jda.api.components.buttons.ButtonStyle style = event.getOption(FORM_BUTTON_STYLE_FIELD, |
There was a problem hiding this comment.
I think the fully qualified name is not necessary here.
| true))); | ||
| new OptionData(OptionType.STRING, FORM_BUTTON_LABEL_FIELD, | ||
| "Label of the submit button. Default is \"Submit\""), | ||
| new OptionData(OptionType.STRING, FORM_BUTTON_STYLE_FIELD, "Submit button style. Defaults to primary", |
There was a problem hiding this comment.
Given there is a limited amount of possibilities for this option, I think using OptionData#addChoice is better than autocomplete.
| public boolean removeField(FormData form, int index) { | ||
| List<FormField> fields = form.fields(); | ||
| if (index < 0 || index >= fields.size()) return false; | ||
| return jdbcTemplate.update("delete from `form_fields` where `id` = ?", fields.get(index).id()) > 0; |
There was a problem hiding this comment.
This needs to check the form ID as well, not just the field index.
| @@ -237,11 +244,12 @@ public void addSubmission(User user, FormData form, Message message) { | |||
There was a problem hiding this comment.
The part about failing silently isn't really true any more with it returning a boolean.
By the way, you can use @CheckReturnValue if you want to make sure the return value is used.
| return messageChannel != null && messageId != null; | ||
| /** | ||
| * Get information about the form's attachment state. If the form is attached to | ||
| * a message, this method will return a non-empty optional containin information |
| } | ||
| public record FormUser(long id, String username) { | ||
|
|
||
| // @Override |
There was a problem hiding this comment.
I think this commented out code should be removed.
| form.getAttachmentInfo().ifPresent(info -> { | ||
| long messageChannelId = info.messageChannelId(); | ||
| long messageId = info.messageId(); | ||
| TextChannel formChannel = guild.getTextChannelById(messageChannelId); |
There was a problem hiding this comment.
As mentioned before, this may not be a text channel.
|
Okay, I've committed changes addressing all of the new review comments, except for this one |
c080ab8 to
00102a1
Compare
|
If I didn't omit anything, I've addressed all of the old issues. I reacted with 👍 to every comment I've seen. The PR should be ready for review. |
This pull request adds the forms system to the bot.
The forms can be attached to any of the bot's messages. Users can fill in a form by clicking on the button added to the message the form is attached. After doing so, the user is presented with a modal dialog containing up to 5 fields defined in the form.
Upon submission, the contents of the fields are sent to a dedicated channel (configurable per form).
Included in this PR are commands to create, manage, and customize forms.
Forms can also be configured to accept only one submission per user. This was achieved by keeping track of who had submitted the form before in the dedicated forms repository.
Below is a video showcasing how the system works, along with most of the commands:
link(the link is broken by now)I'm aware this can be improved in some areas. I'm looking forward to your reviews!