[AB-xxx] adding support for user installable apps to varying commands

This commit is contained in:
Sheldan
2024-04-02 23:48:27 +02:00
parent cd3378df32
commit 732535850b
98 changed files with 1184 additions and 773 deletions

View File

@@ -5,11 +5,13 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.UserCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.utils.ContextUtils;
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
@@ -44,8 +46,11 @@ public class CreateCustomCommand extends AbstractConditionableCommand {
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String name = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_NAME_PARAMETER, event, String.class);
String content = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_CONTENT_PARAMETER, event, String.class);
customCommandService.createCustomCommand(name, content, event.getMember());
if(ContextUtils.isUserCommand(event)) {
customCommandService.createUserCustomCommand(name, content, event.getUser());
} else {
customCommandService.createCustomCommand(name, content, event.getMember());
}
return interactionService.replyEmbed(CREATE_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@@ -80,6 +85,8 @@ public class CreateCustomCommand extends AbstractConditionableCommand {
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.userInstallable(true)
.userCommandConfig(UserCommandConfig.all())
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND)
.commandName("create")
.build();

View File

@@ -5,11 +5,13 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.UserCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.utils.ContextUtils;
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
@@ -42,8 +44,11 @@ public class DeleteCustomCommand extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String name = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_NAME_PARAMETER, event, String.class);
customCommandService.deleteCustomCommand(name, event.getGuild());
if(ContextUtils.isUserCommand(event)) {
customCommandService.deleteUserCustomCommand(name, event.getUser());
} else {
customCommandService.deleteCustomCommand(name, event.getGuild());
}
return interactionService.replyEmbed(DELETE_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@@ -66,6 +71,8 @@ public class DeleteCustomCommand extends AbstractConditionableCommand {
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.userInstallable(true)
.userCommandConfig(UserCommandConfig.all())
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND)
.commandName("delete")
.build();

View File

@@ -5,12 +5,14 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.UserCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandAutoCompleteService;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.utils.ContextUtils;
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.model.command.CustomCommandResponseModel;
@@ -48,7 +50,12 @@ public class GetCustomCommand extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String name = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_NAME_PARAMETER, event, String.class);
CustomCommand customCommand = customCommandService.getCustomCommand(name, event.getGuild());
CustomCommand customCommand;
if(ContextUtils.isUserCommand(event)) {
customCommand = customCommandService.getUserCustomCommand(name, event.getUser());
} else {
customCommand = customCommandService.getCustomCommand(name, event.getGuild());
}
CustomCommandResponseModel model = CustomCommandResponseModel
.builder()
.additionalText(customCommand.getAdditionalMessage())
@@ -61,11 +68,17 @@ public class GetCustomCommand extends AbstractConditionableCommand {
public List<String> performAutoComplete(CommandAutoCompleteInteractionEvent event) {
if(slashCommandAutoCompleteService.matchesParameter(event.getFocusedOption(), CUSTOM_COMMAND_NAME_PARAMETER)) {
String input = event.getFocusedOption().getValue();
return customCommandService.getCustomCommandsStartingWith(input, event.getGuild())
.stream()
.map(CustomCommand::getName)
.limit(25)
.toList();
if(ContextUtils.isNotUserCommand(event)) {
return customCommandService.getCustomCommandsStartingWith(input, event.getGuild())
.stream()
.map(CustomCommand::getName)
.toList();
} else {
return customCommandService.getUserCustomCommandsStartingWith(input, event.getUser())
.stream()
.map(CustomCommand::getName)
.toList();
}
} else {
return new ArrayList<>();
}
@@ -95,7 +108,10 @@ public class GetCustomCommand extends AbstractConditionableCommand {
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.userInstallable(true)
.userCommandConfig(UserCommandConfig.all())
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND_PUBLIC)
.userRootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND)
.commandName("get")
.build();

View File

@@ -4,11 +4,13 @@ import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.UserCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.service.PaginatorService;
import dev.sheldan.abstracto.core.utils.ContextUtils;
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.model.command.ListCustomCommandsResponseModel;
@@ -42,7 +44,12 @@ public class ListCustomCommands extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
List<CustomCommand> customCommands = customCommandService.getCustomCommands(event.getGuild());
List<CustomCommand> customCommands;
if(ContextUtils.isUserCommand(event)) {
customCommands = customCommandService.getUserCustomCommands(event.getUser());
} else {
customCommands = customCommandService.getCustomCommands(event.getGuild());
}
if(customCommands.isEmpty()) {
return interactionService.replyEmbed(NO_CUSTOM_COMMANDS_TEMPLATE_KEY, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
@@ -67,7 +74,10 @@ public class ListCustomCommands extends AbstractConditionableCommand {
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.userInstallable(true)
.userCommandConfig(UserCommandConfig.all())
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND_PUBLIC)
.userRootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND)
.commandName("list")
.build();

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.customcommand.repository;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@@ -11,7 +12,12 @@ import java.util.Optional;
@Repository
public interface CustomCommandRepository extends JpaRepository<CustomCommand, Long> {
Optional<CustomCommand> getByNameIgnoreCaseAndServer(String name, AServer server);
Optional<CustomCommand> getByNameIgnoreCaseAndCreatorUser(String name, AUser creator);
Optional<CustomCommand> getByNameIgnoreCaseAndCreatorUser_IdAndUserSpecific(String name, Long userId, Boolean userSpecific);
void deleteByNameAndServer(String name, AServer server);
void deleteByNameAndCreatorUserAndUserSpecific(String name, AUser aUser, Boolean userSpecific);
List<CustomCommand> findByServer(AServer server);
List<CustomCommand> findByCreatorUserAndUserSpecific(AUser user, Boolean userSpecific);
List<CustomCommand> findByNameStartsWithIgnoreCaseAndServer(String prefix, AServer server);
List<CustomCommand> findByNameStartsWithIgnoreCaseAndCreatorUserAndUserSpecific(String prefix, AUser aUser, Boolean userSpecific);
}

View File

@@ -1,9 +1,11 @@
package dev.sheldan.abstracto.customcommand.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
import dev.sheldan.abstracto.customcommand.exception.CustomCommandExistsException;
import dev.sheldan.abstracto.customcommand.exception.CustomCommandNotFoundException;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
@@ -11,6 +13,7 @@ import dev.sheldan.abstracto.customcommand.service.management.CustomCommandManag
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -28,6 +31,9 @@ public class CustomCommandServiceBean implements CustomCommandService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private UserManagementService userManagementService;
@Override
public CustomCommand createCustomCommand(String name, String content, Member creator) {
if(customCommandManagementService.getCustomCommandByName(name, creator.getGuild().getIdLong()).isPresent()) {
@@ -37,6 +43,15 @@ public class CustomCommandServiceBean implements CustomCommandService {
return customCommandManagementService.createCustomCommand(name, content, creatorUser);
}
@Override
public CustomCommand createUserCustomCommand(String name, String content, User user) {
AUser aUser = userManagementService.loadOrCreateUser(user.getIdLong());
if(customCommandManagementService.getUserCustomCommandByName(name, aUser).isPresent()) {
throw new CustomCommandExistsException();
}
return customCommandManagementService.createUserCustomCommand(name, content, aUser);
}
@Override
public void deleteCustomCommand(String name, Guild guild) {
if(customCommandManagementService.getCustomCommandByName(name, guild.getIdLong()).isEmpty()) {
@@ -46,21 +61,48 @@ public class CustomCommandServiceBean implements CustomCommandService {
customCommandManagementService.deleteCustomCommand(name, server);
}
@Override
public void deleteUserCustomCommand(String name, User user) {
if(customCommandManagementService.getUserCustomCommandByName(name, user.getIdLong()).isEmpty()) {
throw new CustomCommandNotFoundException();
}
AUser aUser = userManagementService.loadOrCreateUser(user.getIdLong());
customCommandManagementService.deleteCustomCommand(name, aUser);
}
@Override
public List<CustomCommand> getCustomCommands(Guild guild) {
AServer server = serverManagementService.loadServer(guild);
return customCommandManagementService.getCustomCommands(server);
}
@Override
public List<CustomCommand> getUserCustomCommands(User user) {
AUser aUser = userManagementService.loadOrCreateUser(user.getIdLong());
return customCommandManagementService.getUserCustomCommands(aUser);
}
@Override
public CustomCommand getCustomCommand(String name, Guild guild) {
return customCommandManagementService.getCustomCommandByName(name, guild.getIdLong())
.orElseThrow(CustomCommandNotFoundException::new);
}
@Override
public CustomCommand getUserCustomCommand(String name, User user) {
return customCommandManagementService.getUserCustomCommandByName(name, user.getIdLong())
.orElseThrow(CustomCommandNotFoundException::new);
}
@Override
public List<CustomCommand> getCustomCommandsStartingWith(String prefix, Guild guild) {
AServer server = serverManagementService.loadServer(guild);
return customCommandManagementService.getCustomCommandsStartingWith(prefix, server);
}
@Override
public List<CustomCommand> getUserCustomCommandsStartingWith(String prefix, User user) {
AUser aUser = userManagementService.loadOrCreateUser(user.getIdLong());
return customCommandManagementService.getUserCustomCommandsStartingWith(prefix, aUser);
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.customcommand.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
@@ -26,6 +27,16 @@ public class CustomCommandManagementServiceBean implements CustomCommandManageme
return repository.getByNameIgnoreCaseAndServer(name, server);
}
@Override
public Optional<CustomCommand> getUserCustomCommandByName(String name, AUser user) {
return repository.getByNameIgnoreCaseAndCreatorUser(name, user);
}
@Override
public Optional<CustomCommand> getUserCustomCommandByName(String name, Long userId) {
return repository.getByNameIgnoreCaseAndCreatorUser_IdAndUserSpecific(name, userId, true);
}
@Override
public CustomCommand createCustomCommand(String name, String content, AUserInAServer creator) {
CustomCommand customCommand = CustomCommand
@@ -34,6 +45,20 @@ public class CustomCommandManagementServiceBean implements CustomCommandManageme
.additionalMessage(content)
.server(creator.getServerReference())
.creator(creator)
.userSpecific(false)
.creatorUser(creator.getUserReference())
.build();
return repository.save(customCommand);
}
@Override
public CustomCommand createUserCustomCommand(String name, String content, AUser user) {
CustomCommand customCommand = CustomCommand
.builder()
.name(name)
.additionalMessage(content)
.creatorUser(user)
.userSpecific(true)
.build();
return repository.save(customCommand);
}
@@ -43,14 +68,29 @@ public class CustomCommandManagementServiceBean implements CustomCommandManageme
repository.deleteByNameAndServer(name, server);
}
@Override
public void deleteCustomCommand(String name, AUser user) {
repository.deleteByNameAndCreatorUserAndUserSpecific(name, user, true);
}
@Override
public List<CustomCommand> getCustomCommands(AServer server) {
return repository.findByServer(server);
}
@Override
public List<CustomCommand> getUserCustomCommands(AUser aUser) {
return repository.findByCreatorUserAndUserSpecific(aUser, true);
}
@Override
public List<CustomCommand> getCustomCommandsStartingWith(String prefix, AServer server) {
return repository.findByNameStartsWithIgnoreCaseAndServer(prefix, server);
}
@Override
public List<CustomCommand> getUserCustomCommandsStartingWith(String prefix, AUser aUser) {
return repository.findByNameStartsWithIgnoreCaseAndCreatorUserAndUserSpecific(prefix, aUser, true);
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,26 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<changeSet author="Sheldan" id="custom_command-add_user_installable_support">
<addColumn tableName="custom_command">
<column name="creator_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="user_specific" type="BOOLEAN" value="false">
<constraints nullable="false"/>
</column>
</addColumn>
<sql>
update custom_command set creator_id = (select ua.user_id from user_in_server ua where ua.user_in_server_id = creator_user_in_server_id order by ua.server_id limit 1)
</sql>
<addNotNullConstraint columnName="creator_id"
tableName="custom_command"
validate="true"/>
<sql>
ALTER TABLE custom_command ALTER COLUMN server_id DROP NOT NULL;
ALTER TABLE custom_command ALTER COLUMN creator_user_in_server_id DROP NOT NULL;
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="custom_command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -4,4 +4,5 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
<include file="1.4.0/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.8/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.37/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>