From fd4d7840817be23ceea09f0031be1fb8c8630306 Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Thu, 23 Jul 2020 02:22:58 +0200 Subject: [PATCH] added assignable role place module including: setting up, configuring, deleting commands and documentation upgraded JDA version to 4.2.0 refactored multiple interfaces to be more convenient/contain more information (reaction added/removed now gets the actual event) added generic way to check for conditions. these conditions are provided by modules and are loosely connected via condition context and a condition name added changeable flag to emotes to indicate that they can be updated via setEmote refactored emote parsing in command parameters, the command parameters will now contain a fake emote added feature to embed templates for fields to force a new message regardless of the discord limit added some more functionality to message and channel service regarding field edit/embed sending introduced the full emote parameter, to have both the emote (if custom) and a fake aemote at hand refactored some methods to already throw exceptions within the retrieval methods, instead of optionals which need to be dealt outside changed getEmotes to getEmotesBag to have duplicates of emotes fixed setEmote to behave correctly with new parameter types fixed creation of emotes, which previously created additional instances fixed templating multiple fields handling refactored command handling to allow async commands, they are the same interface, but configuration dicates whether or not it is async added generic exception reporting for async commands refactored a bunch of service methods to be named optional, and the non optional methods throw exceptions in case nothing is found added a few more customized exceptions added clearing freemarker internal template cache to clear cache added feature to skip, not use, embeds if they look to be empty (no fields, no description, no attachment) added virtual env to gitignore fixed initial sync of roles un-marking roles as deleted added some convenience methods to remove reactions from users directly fixed post command handling in case it is not a templatable instance fixed exceptions without cause in generic exception model --- .gitignore | 3 + .../assignable-roles-impl/pom.xml | 45 + .../src/main/assembly/liquibase.xml | 18 + .../command/ActivateAssignableRolePlace.java | 52 + .../command/AddRoleToAssignableRolePost.java | 75 + .../command/AssignableRoleModule.java | 18 + .../ChangeAssignablePlaceDescription.java | 54 + .../ChangeAssignableRolePlaceConfig.java | 62 + .../command/CreateAssignableRolePost.java | 67 + .../DeactivateAssignableRolePlace.java | 52 + .../command/DeleteAssignableRolePlace.java | 52 + .../command/EditAssignableRolePlaceText.java | 58 + .../command/MoveAssignableRolePlace.java | 55 + .../RemoveRoleFromAssignableRolePlace.java | 55 + .../command/SetAssignableRolePosition.java | 63 + .../command/SetupAssignableRolePlace.java | 61 + .../ShowAssignableRolePlaceConfig.java | 53 + .../command/ShowAssignableRolePlaces.java | 47 + .../command/SwapAssignableRolePosition.java | 73 + .../command/TestAssignableRolePlace.java | 52 + .../AssignablePostDeletedListener.java | 40 + .../listener/AssignablePostReactionAdded.java | 106 ++ .../AssignablePostReactionRemoved.java | 63 + .../AssignableRolePlacePostRepository.java | 10 + .../AssignableRolePlaceRepository.java | 16 + .../repository/AssignableRoleRepository.java | 9 + .../AssignedRoleUserRepository.java | 9 + .../AssignableRolePlaceServiceBean.java | 751 +++++++++ .../service/AssignableRoleServiceBean.java | 69 + .../AssignableRoleManagementServiceBean.java | 77 + ...ignableRolePlaceManagementServiceBean.java | 72 + ...bleRolePlacePostManagementServiceBean.java | 28 + ...AssignedRoleUserManagementServiceBean.java | 54 + .../assignableRoles-seedData/command.xml | 111 ++ .../assignableRoles-seedData/data.xml | 13 + .../default_feature_flag.xml | 18 + .../assignableRoles-seedData/feature.xml | 16 + .../assignableRoles-seedData/module.xml | 16 + .../assignable_role.xml | 50 + .../assignable_role_place.xml | 39 + .../assignable_role_place_post.xml | 33 + .../assigned_role_user.xml | 38 + .../assignableRoles-tables/tables.xml | 13 + .../1.0-assignableRoles/collection.xml | 11 + .../migrations/assignableRoles-changeLog.xml | 10 + .../resources/migrations/dbchangelog-3.8.xsd | 1377 +++++++++++++++++ .../assignable-roles-int/pom.xml | 21 + .../AssignableRolePlaceParameterKey.java | 10 + .../features/AssignableFeatureConfig.java | 13 + .../features/AssignableRoleFeature.java | 15 + .../AssignablePlacePostNotFoundException.java | 25 + ...AssignableRoleAlreadyDefinedException.java | 25 + .../AssignableRoleNotUsableException.java | 26 + ...gnableRolePlaceAlreadyExistsException.java | 25 + ...ssignableRolePlaceChannelDoesNotExist.java | 25 + .../AssignableRolePlaceNotFoundException.java | 25 + .../AssignedUserNotFoundException.java | 26 + ...moteNotInAssignableRolePlaceException.java | 26 + .../models/database/AssignableRole.java | 73 + .../models/database/AssignableRolePlace.java | 88 ++ .../database/AssignableRolePlacePost.java | 51 + .../models/database/AssignedRoleUser.java | 46 + .../AssignableRoleAlreadyDefinedModel.java | 16 + .../AssignableRoleNotUsableModel.java | 17 + ...AssignableRolePlaceAlreadyExistsModel.java | 12 + ...ableRolePlaceChannelDoesNotExistModel.java | 15 + .../AssignableRolePlaceExceptionModel.java | 28 + .../AssignableRolePlaceNotFoundModel.java | 12 + .../AssignableRolePlacePostNotFoundModel.java | 14 + .../exception/AssignedUserNotFoundModel.java | 13 + .../EmoteNotInAssignableRolePlaceModel.java | 16 + .../templates/AssignablePlaceOverview.java | 17 + .../templates/AssignablePostConfigRole.java | 21 + .../templates/AssignablePostMessage.java | 17 + .../models/templates/AssignablePostRole.java | 19 + .../templates/AssignableRolePlaceConfig.java | 16 + .../service/AssignableRolePlaceService.java | 66 + .../service/AssignableRoleService.java | 11 + .../AssignableRoleManagementService.java | 14 + .../AssignableRolePlaceManagementService.java | 20 + ...ignableRolePlacePostManagementService.java | 10 + .../AssignedRoleUserManagementService.java | 16 + .../assignable-roles/pom.xml | 29 + .../service/condition/HasLevelCondition.java | 56 + .../moderation/service/BanServiceBean.java | 4 +- .../moderation/service/MuteServiceBean.java | 4 +- .../service/SlowModeServiceBean.java | 4 +- .../service/BanServiceBeanTest.java | 4 +- .../service/MuteServiceBeanTest.java | 2 +- .../service/SlowModeServiceBeanTest.java | 4 +- .../service/ModMailMessageServiceBean.java | 2 +- .../service/ModMailThreadServiceBean.java | 2 +- .../ModMailThreadManagementServiceBean.java | 4 +- .../setup/ModMailCategorySetupBean.java | 87 +- .../abstracto-modules/pom.xml | 1 + .../MessageEmbedRemovalReactionListener.java | 9 +- .../listener/starboard/StarboardListener.java | 17 +- .../service/MessageEmbedServiceBean.java | 6 +- .../utility/service/RemindServiceBean.java | 5 +- .../utility/service/StarboardServiceBean.java | 5 +- ...MessageEmbedPostManagementServiceBean.java | 5 +- .../StarboardPostManagementServiceBean.java | 3 +- .../SuggestionManagementServiceBean.java | 9 +- ...ssageEmbedRemovalReactionListenerTest.java | 11 +- .../starboard/StarboardListenerTest.java | 52 +- .../service/MessageEmbedServiceBeanTest.java | 4 +- .../service/RemindServiceBeanTest.java | 8 +- .../service/StarboardServiceBeanTest.java | 16 +- ...ageEmbedPostManagementServiceBeanTest.java | 2 +- ...tarboardPostManagementServiceBeanTest.java | 27 +- .../SuggestionManagementServiceBeanTest.java | 16 +- abstracto-application/bundle/pom.xml | 6 + .../core/command/CommandReceivedHandler.java | 170 +- .../command/post/ExceptionPostExecution.java | 23 +- .../command/post/ReactionPostExecution.java | 2 +- .../command/service/ExceptionServiceBean.java | 52 + .../core/commands/utility/SetEmote.java | 22 +- .../interactive/InteractiveServiceBean.java | 5 +- .../core/interactive/PostTargetSetupStep.java | 74 +- .../core/interactive/SetupSummaryStep.java | 44 +- .../interactive/SystemConfigSetupStep.java | 70 +- .../listener/MessageDeletedListenerBean.java | 4 +- .../listener/ReactionUpdatedListener.java | 6 +- .../core/repository/EmoteRepository.java | 12 +- .../core/service/BotServiceBean.java | 45 +- .../core/service/CacheServiceBean.java | 5 + .../core/service/ChannelGroupServiceBean.java | 9 +- .../core/service/ChannelServiceBean.java | 78 +- .../core/service/ConditionServiceBean.java | 45 + .../core/service/EmoteServiceBean.java | 22 +- .../core/service/MessageCacheBean.java | 8 +- .../core/service/MessageServiceBean.java | 126 +- .../core/service/PostTargetServiceBean.java | 6 +- .../core/service/RoleServiceBean.java | 121 +- .../core/service/SetupServiceBean.java | 2 +- .../core/service/StartupServiceBean.java | 3 +- .../ChannelManagementServiceBean.java | 12 +- .../EmoteManagementServiceBean.java | 87 +- .../management/PostTargetManagementBean.java | 8 +- .../management/RoleManagementServiceBean.java | 8 +- .../ServerManagementServiceBean.java | 15 +- .../resources/config/application.properties | 5 - .../migrations/1.0-core/core-tables/emote.xml | 1 + .../abstracto/core/command/Command.java | 5 +- .../condition/CommandDisallowedCondition.java | 2 +- .../condition/FeatureEnabledCondition.java | 2 +- .../condition/FeatureModeCondition.java | 2 +- .../condition/ImmuneUserCondition.java | 2 +- .../command/config/CommandConfiguration.java | 6 + ...ndParameterKeyValueWrongTypeException.java | 27 + .../execution/CommandParameterKey.java | 22 + .../core/command/execution/CommandResult.java | 4 + .../core/command/execution/ResultState.java | 2 +- ...ommandParameterKeyValueWrongTypeModel.java | 14 + .../FeatureDisabledMessage.java | 2 +- .../exception/GenericExceptionModel.java | 26 + .../IncorrectFeatureModeMessage.java | 2 +- .../InsufficientPermissionMessage.java | 2 +- .../{ => exception}/UserImmuneMessage.java | 2 +- .../command/service/ExceptionService.java | 9 + .../exception/AbstractoRunTimeException.java | 6 + .../exception/ChannelNotFoundException.java | 7 +- .../exception/EmoteNotFoundInDbException.java | 28 + .../exception/EmoteNotUsableException.java | 25 + .../ExceptionNotInServerException.java | 24 + ...ption.java => GuildNotFoundException.java} | 6 +- .../InvalidConditionParametersException.java | 7 + .../core/exception/RoleDeletedException.java | 25 + .../exception/RoleNotFoundInDBException.java | 5 +- .../core/listener/ReactedAddedListener.java | 4 +- .../core/listener/ReactedRemovedListener.java | 4 +- .../core/models/ConditionContext.java | 14 + .../core/models/ConditionContextInstance.java | 15 + .../core/models/ConditionContextVariable.java | 13 + .../abstracto/core/models/FullEmote.java | 27 + .../abstracto/core/models/FullRole.java | 8 + .../core/models/database/AEmote.java | 10 + .../exception/EmoteNotInServerModel.java | 12 + .../core/models/exception/EmoteNotUsable.java | 13 + .../models/exception/RoleDeletedModel.java | 13 + .../abstracto/core/service/BotService.java | 7 +- .../core/service/ChannelService.java | 7 + .../core/service/ConditionService.java | 7 + .../abstracto/core/service/EmoteService.java | 5 +- .../core/service/MessageService.java | 16 + .../abstracto/core/service/RoleService.java | 8 + .../core/service/SystemCondition.java | 10 + .../management/ChannelManagementService.java | 3 +- .../management/EmoteManagementService.java | 23 +- .../management/RoleManagementService.java | 3 +- .../management/ServerManagementService.java | 3 + .../abstracto/core/utils/ContextUtils.java | 5 +- .../core/utils/ContextUtilsTest.java | 3 +- abstracto-application/coverage/pom.xml | 5 + .../asciidoc/features/assignableRoles.adoc | 77 + .../src/main/docs/asciidoc/main.adoc | 2 + abstracto-application/pom.xml | 4 +- .../templating/model/EmbedConfiguration.java | 2 + .../templating/model/EmbedField.java | 1 + .../service/TemplateServiceBean.java | 36 +- .../templating/service/TemplateService.java | 2 + 201 files changed, 6547 insertions(+), 527 deletions(-) create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/assembly/liquibase.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ActivateAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AddRoleToAssignableRolePost.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AssignableRoleModule.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignablePlaceDescription.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignableRolePlaceConfig.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/CreateAssignableRolePost.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeactivateAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeleteAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/EditAssignableRolePlaceText.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/MoveAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/RemoveRoleFromAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetAssignableRolePosition.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetupAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaceConfig.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaces.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SwapAssignableRolePosition.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/TestAssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostDeletedListener.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionAdded.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionRemoved.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlacePostRepository.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlaceRepository.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRoleRepository.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignedRoleUserRepository.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleServiceBean.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementServiceBean.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementServiceBean.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementServiceBean.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementServiceBean.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/command.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/data.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/default_feature_flag.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/feature.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/module.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place_post.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assigned_role_user.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/tables.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/collection.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/assignableRoles-changeLog.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/dbchangelog-3.8.xsd create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/AssignableRolePlaceParameterKey.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableFeatureConfig.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableRoleFeature.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignablePlacePostNotFoundException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleAlreadyDefinedException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleNotUsableException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceAlreadyExistsException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceChannelDoesNotExist.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceNotFoundException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignedUserNotFoundException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/EmoteNotInAssignableRolePlaceException.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRole.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlace.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlacePost.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignedRoleUser.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleAlreadyDefinedModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleNotUsableModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceAlreadyExistsModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceChannelDoesNotExistModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceExceptionModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceNotFoundModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlacePostNotFoundModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignedUserNotFoundModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/EmoteNotInAssignableRolePlaceModel.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePlaceOverview.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostConfigRole.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostMessage.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostRole.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignableRolePlaceConfig.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceService.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleService.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementService.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementService.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementService.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementService.java create mode 100644 abstracto-application/abstracto-modules/assignable-roles/pom.xml create mode 100644 abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/condition/HasLevelCondition.java create mode 100644 abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java create mode 100644 abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConditionServiceBean.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterKeyValueWrongTypeException.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandParameterKey.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/CommandParameterKeyValueWrongTypeModel.java rename abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/{ => exception}/FeatureDisabledMessage.java (79%) create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/GenericExceptionModel.java rename abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/{ => exception}/IncorrectFeatureModeMessage.java (83%) rename abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/{ => exception}/InsufficientPermissionMessage.java (80%) rename abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/{ => exception}/UserImmuneMessage.java (76%) create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ExceptionNotInServerException.java rename abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/{GuildException.java => GuildNotFoundException.java} (72%) create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/InvalidConditionParametersException.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleDeletedException.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContext.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextInstance.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextVariable.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullEmote.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotInServerModel.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotUsable.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/RoleDeletedModel.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConditionService.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/SystemCondition.java create mode 100644 abstracto-application/documentation/src/main/docs/asciidoc/features/assignableRoles.adoc diff --git a/.gitignore b/.gitignore index af7e11dba..e2932c6f1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + + +venv/ \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml new file mode 100644 index 000000000..04419f7a4 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml @@ -0,0 +1,45 @@ + + + + dev.sheldan.abstracto.modules + assignable-roles + 1.0-SNAPSHOT + + 4.0.0 + + assignable-roles-impl + + + + + maven-assembly-plugin + + + src/main/assembly/liquibase.xml + + + + + make-assembly + package + + single + + + + + + + + + + dev.sheldan.abstracto.modules + assignable-roles-int + ${project.version} + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/assembly/liquibase.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/assembly/liquibase.xml new file mode 100644 index 000000000..8b4774fa0 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/assembly/liquibase.xml @@ -0,0 +1,18 @@ + + liquibase + + zip + + false + + + . + ${project.basedir}/src/main/resources/migrations + + **/* + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ActivateAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ActivateAssignableRolePlace.java new file mode 100644 index 000000000..5dd6e9cf9 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ActivateAssignableRolePlace.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class ActivateAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + service.activateAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("activateAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AddRoleToAssignableRolePost.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AddRoleToAssignableRolePost.java new file mode 100644 index 000000000..1024e7533 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AddRoleToAssignableRolePost.java @@ -0,0 +1,75 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.exceptions.AssignableRoleAlreadyDefinedException; +import dev.sheldan.abstracto.assignableroles.exceptions.AssignableRoleNotUsableException; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.core.models.FullRole; +import dev.sheldan.abstracto.core.service.RoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class AddRoleToAssignableRolePost extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Autowired + private RoleService roleService; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + FullEmote emote = (FullEmote) parameters.get(1); + String description = (String) parameters.get(2); + FullRole role = (FullRole) parameters.get(3); + if(service.hasAssignableRolePlaceEmote(commandContext.getUserInitiatedContext().getServer(), name, emote.getFakeEmote())) { + throw new AssignableRoleAlreadyDefinedException(emote, name); + } + if(!roleService.canBotInteractWithRole(role.getRole())) { + throw new AssignableRoleNotUsableException(role, commandContext.getGuild()); + } + return service.addRoleToAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, role.getRole(), emote, description) + .thenApply(aVoid -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).templated(true).build(); + Parameter description = Parameter.builder().name("description").type(String.class).templated(true).build(); + Parameter role = Parameter.builder().name("role").type(FullRole.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, emote, description, role); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("addRoleToAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .async(true) + .reportsException(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AssignableRoleModule.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AssignableRoleModule.java new file mode 100644 index 000000000..11b4d72b5 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/AssignableRoleModule.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.core.command.config.ModuleInfo; +import dev.sheldan.abstracto.core.command.config.ModuleInterface; + +public class AssignableRoleModule implements ModuleInterface { + public static final String ASSIGNABLE_ROLES = "assignableRoles"; + + @Override + public ModuleInfo getInfo() { + return ModuleInfo.builder().name(ASSIGNABLE_ROLES).description("Module containing commands for creating and maintaining assignable role posts.").build(); + } + + @Override + public String getParentModule() { + return "default"; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignablePlaceDescription.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignablePlaceDescription.java new file mode 100644 index 000000000..027bf9f73 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignablePlaceDescription.java @@ -0,0 +1,54 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class ChangeAssignablePlaceDescription extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + String newDescription = (String) parameters.get(1); + service.changeAssignablePlaceDescription(commandContext.getUserInitiatedContext().getServer(), name, newDescription); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter newDescription = Parameter.builder().name("newDescription").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, newDescription); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("changeAssignablePlaceDescription") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignableRolePlaceConfig.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignableRolePlaceConfig.java new file mode 100644 index 000000000..760aaa2f8 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ChangeAssignableRolePlaceConfig.java @@ -0,0 +1,62 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.AssignableRolePlaceParameterKey; +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class ChangeAssignableRolePlaceConfig extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + AssignableRolePlaceParameterKey configKey = (AssignableRolePlaceParameterKey) parameters.get(1); + Object parameterValue = parameters.get(2); + return service.changeConfiguration(commandContext.getUserInitiatedContext().getServer(), name, configKey, parameterValue) + .thenApply(aVoid -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter assignableRolePlaceName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter parameterKey = Parameter.builder().name("key").type(AssignableRolePlaceParameterKey.class).templated(true).build(); + Parameter parameterValue = Parameter.builder().name("value").type(Object.class).templated(true).build(); + + List parameters = Arrays.asList(assignableRolePlaceName, parameterKey, parameterValue); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("changeAssignableRolePlaceConfig") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .async(true) + .reportsException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/CreateAssignableRolePost.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/CreateAssignableRolePost.java new file mode 100644 index 000000000..53724d93f --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/CreateAssignableRolePost.java @@ -0,0 +1,67 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.service.management.ChannelManagementService; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.TextChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class CreateAssignableRolePost extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Autowired + private ChannelManagementService channelManagementService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + MessageChannel channel = (TextChannel) parameters.get(1); + String text = (String) parameters.get(2); + AChannel chosenChannel = channelManagementService.loadChannel(channel.getIdLong()); + service.createAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, chosenChannel, text); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter channel = Parameter.builder().name("channel").type(TextChannel.class).templated(true).build(); + Parameter text = Parameter.builder().name("text").type(String.class).remainder(true).optional(true).templated(true).build(); + List aliases = Arrays.asList("crRPl", "crAssRoPl"); + List parameters = Arrays.asList(rolePostName, channel, text); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("createAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .reportsException(true) + .causesReaction(true) + .parameters(parameters) + .aliases(aliases) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeactivateAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeactivateAssignableRolePlace.java new file mode 100644 index 000000000..3f05d3f82 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeactivateAssignableRolePlace.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class DeactivateAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + service.deactivateAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("deactivateAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeleteAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeleteAssignableRolePlace.java new file mode 100644 index 000000000..b1eaa4f1b --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/DeleteAssignableRolePlace.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class DeleteAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + service.deleteAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("deleteAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/EditAssignableRolePlaceText.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/EditAssignableRolePlaceText.java new file mode 100644 index 000000000..4b9f45899 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/EditAssignableRolePlaceText.java @@ -0,0 +1,58 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + + +@Component +public class EditAssignableRolePlaceText extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + String newText = (String) parameters.get(1); + + return service.changeText(commandContext.getUserInitiatedContext().getServer(), name, newText).thenApply(aVoid -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter newText = Parameter.builder().name("newText").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, newText); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("editAssignableRolePlaceText") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .async(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/MoveAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/MoveAssignableRolePlace.java new file mode 100644 index 000000000..420292543 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/MoveAssignableRolePlace.java @@ -0,0 +1,55 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import net.dv8tion.jda.api.entities.TextChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class MoveAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService placeManagementService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + TextChannel newChannel = (TextChannel) parameters.get(1); + placeManagementService.moveAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, newChannel); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter channel = Parameter.builder().name("channel").type(TextChannel.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, channel); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("moveAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/RemoveRoleFromAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/RemoveRoleFromAssignableRolePlace.java new file mode 100644 index 000000000..3495cff98 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/RemoveRoleFromAssignableRolePlace.java @@ -0,0 +1,55 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.models.FullEmote; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class RemoveRoleFromAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + FullEmote emote = (FullEmote) parameters.get(1); + service.removeRoleFromAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, emote); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, emote); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("removeRoleFromAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetAssignableRolePosition.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetAssignableRolePosition.java new file mode 100644 index 000000000..21d55d525 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetAssignableRolePosition.java @@ -0,0 +1,63 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.models.FullEmote; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class SetAssignableRolePosition extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + FullEmote emote = (FullEmote) parameters.get(1); + Integer newPosition = (Integer) parameters.get(2); + if(!service.hasAssignableRolePlaceEmote(commandContext.getUserInitiatedContext().getServer(), name, emote.getFakeEmote())) { + return CommandResult.fromError("Place does not have emote assigned."); + } + if(service.isPositionUsed(commandContext.getUserInitiatedContext().getServer(), name, newPosition)) { + return CommandResult.fromError("Position is already used"); + } + service.setEmoteToPosition(commandContext.getUserInitiatedContext().getServer(), name, emote, newPosition); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).templated(true).build(); + Parameter newPosition = Parameter.builder().name("newPosition").type(Integer.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, emote, newPosition); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("setAssignableRolePosition") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetupAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetupAssignableRolePlace.java new file mode 100644 index 000000000..e04504571 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SetupAssignableRolePlace.java @@ -0,0 +1,61 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.service.ChannelService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class SetupAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Autowired + private ChannelService channelService; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + return service.setupAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name) + .thenApply(aVoid -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("setupAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .async(true) + .reportsException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaceConfig.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaceConfig.java new file mode 100644 index 000000000..749314cf4 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaceConfig.java @@ -0,0 +1,53 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand { + + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + service.showAssignablePlaceConfig(commandContext.getUserInitiatedContext().getServer(), name, commandContext.getChannel()); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("showAssignableRolePlaceConfig") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaces.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaces.java new file mode 100644 index 000000000..b12723e84 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/ShowAssignableRolePlaces.java @@ -0,0 +1,47 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CompletableFuture; + + +@Component +public class ShowAssignableRolePlaces extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + return service.showAllAssignableRolePlaces(commandContext.getUserInitiatedContext().getServer(), commandContext.getChannel()) + .thenApply(aVoid -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("showAssignableRolePlaces") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .async(true) + .reportsException(true) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SwapAssignableRolePosition.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SwapAssignableRolePosition.java new file mode 100644 index 000000000..276825733 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/SwapAssignableRolePosition.java @@ -0,0 +1,73 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.exceptions.EmoteNotInAssignableRolePlaceException; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.service.EmoteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class SwapAssignableRolePosition extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Autowired + private EmoteService emoteService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + FullEmote firstEmote = (FullEmote) parameters.get(1); + FullEmote secondEmote = (FullEmote) parameters.get(2); + AServer server = commandContext.getUserInitiatedContext().getServer(); + if(emoteService.compareAEmote(firstEmote.getFakeEmote(), secondEmote.getFakeEmote())) { + return CommandResult.fromError("You cannot swap the same emote"); + } + if(!service.hasAssignableRolePlaceEmote(server, name, firstEmote.getFakeEmote())) { + throw new EmoteNotInAssignableRolePlaceException(firstEmote, name); + } + if(!service.hasAssignableRolePlaceEmote(server, name, firstEmote.getFakeEmote())) { + throw new EmoteNotInAssignableRolePlaceException(secondEmote, name); + } + service.swapPositions(server, name, firstEmote, secondEmote); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + Parameter firstEmote = Parameter.builder().name("firstEmote").type(FullEmote.class).templated(true).build(); + Parameter secondEmote = Parameter.builder().name("secondEmote").type(FullEmote.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName, firstEmote, secondEmote); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("swapAssignableRolePosition") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/TestAssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/TestAssignableRolePlace.java new file mode 100644 index 000000000..3571b5dcf --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/command/TestAssignableRolePlace.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.assignableroles.command; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class TestAssignableRolePlace extends AbstractConditionableCommand { + + @Autowired + private AssignableRolePlaceService service; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + String name = (String) parameters.get(0); + service.testAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, commandContext.getChannel()); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build(); + List parameters = Arrays.asList(rolePostName); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("testAssignableRolePlace") + .module(AssignableRoleModule.ASSIGNABLE_ROLES) + .templated(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostDeletedListener.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostDeletedListener.java new file mode 100644 index 000000000..438368495 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostDeletedListener.java @@ -0,0 +1,40 @@ +package dev.sheldan.abstracto.assignableroles.listener; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.listener.MessageDeletedListener; +import dev.sheldan.abstracto.core.models.AServerAChannelAUser; +import dev.sheldan.abstracto.core.models.GuildChannelMember; +import dev.sheldan.abstracto.core.models.cache.CachedMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +@Slf4j +public class AssignablePostDeletedListener implements MessageDeletedListener { + + @Autowired + private AssignableRolePlacePostManagementService service; + + @Override + public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) { + Optional messageOptional = service.findByMessageIdOptional(messageBefore.getMessageId()); + messageOptional.ifPresent(post -> { + AssignableRolePlace assignablePlace = post.getAssignablePlace(); + log.info("Post {} has been deleted in server {} in channel {}, we are removing a post from place {}.", post.getId(), messageBefore.getServerId(), messageBefore.getChannelId(), assignablePlace.getKey()); + post.getAssignableRoles().forEach(assignableRole -> assignableRole.setAssignableRolePlacePost(null)); + assignablePlace.getMessagePosts().remove(post); + }); + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionAdded.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionAdded.java new file mode 100644 index 000000000..7eab887a7 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionAdded.java @@ -0,0 +1,106 @@ +package dev.sheldan.abstracto.assignableroles.listener; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; +import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService; +import dev.sheldan.abstracto.assignableroles.service.AssignableRoleServiceBean; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; +import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.listener.ReactedAddedListener; +import dev.sheldan.abstracto.core.models.cache.CachedMessage; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.EmoteService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class AssignablePostReactionAdded implements ReactedAddedListener { + + @Autowired + private AssignableRolePlacePostManagementService service; + + @Autowired + private AssignableRoleServiceBean assignableRoleServiceBean; + + @Autowired + private EmoteService emoteService; + + @Autowired + private AssignableRolePlaceService assignableRolePlaceService; + + @Autowired + private AssignedRoleUserManagementService assignedRoleUserManagementService; + + @Override + public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent event, AUserInAServer userAdding) { + Optional messageOptional = service.findByMessageIdOptional(message.getMessageId()); + if(messageOptional.isPresent()) { + MessageReaction reaction = event.getReaction(); + AssignableRolePlacePost assignablePlacePost = messageOptional.get(); + if(reaction.isSelf()) { + log.info("Ignoring self reaction on assignable role post in server {}.", message.getServerId()); + return; + } + MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); + if(assignablePlacePost.getAssignablePlace().getActive()) { + addAppropriateRoles(event, reaction, assignablePlacePost, reactionEmote, userAdding); + } else { + reaction.removeReaction(event.getUser()).submit(); + log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), userAdding.getServerReference().getId()); + } + } + } + + private void addAppropriateRoles(GuildMessageReactionAddEvent event, MessageReaction reaction, AssignableRolePlacePost assignablePlacePost, MessageReaction.ReactionEmote reactionEmote, AUserInAServer userAdding) { + boolean validReaction = false; + AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace(); + for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) { + if (emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) { + CompletableFuture future; + if(assignableRolePlace.getUniqueRoles()) { + Optional byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(userAdding); + if(byUserInServer.isPresent()){ + future = assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, byUserInServer.get()); + } else { + future = CompletableFuture.completedFuture(null); + } + } else { + future = CompletableFuture.completedFuture(null); + } + + Long assignableRoleId = assignableRole.getId(); + future.whenComplete((aVoid, throwable) -> { + if(throwable != null) { + log.warn("Failed to remove previous role assignments for {} in server {} at place {}.", + userAdding.getUserReference().getId(), userAdding.getServerReference().getId(), assignablePlacePost.getAssignablePlace().getKey()); + } + assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, event.getMember()).exceptionally(innerThrowable -> { + log.error("Failed to add new role assignment.", innerThrowable); + return null; + }); + }); + validReaction = true; + break; + } + } + if(!validReaction || assignableRolePlace.getAutoRemove()) { + reaction.removeReaction(event.getUser()).submit(); + } + } + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionRemoved.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionRemoved.java new file mode 100644 index 000000000..91e13b416 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignablePostReactionRemoved.java @@ -0,0 +1,63 @@ +package dev.sheldan.abstracto.assignableroles.listener; + +import dev.sheldan.abstracto.assignableroles.config.features.AssignableRoleFeature; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.assignableroles.service.AssignableRoleService; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.listener.ReactedRemovedListener; +import dev.sheldan.abstracto.core.models.cache.CachedMessage; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.RoleService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +@Slf4j +public class AssignablePostReactionRemoved implements ReactedRemovedListener { + + @Autowired + private AssignableRolePlacePostManagementService service; + + @Autowired + private EmoteService emoteService; + + @Autowired + private RoleService roleService; + + @Autowired + private AssignableRoleService assignableRoleService; + + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } + + @Override + public void executeReactionRemoved(CachedMessage message, GuildMessageReactionRemoveEvent event, AUserInAServer userRemoving) { + Optional messageOptional = service.findByMessageIdOptional(message.getMessageId()); + if(messageOptional.isPresent()) { + MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); + AssignableRolePlacePost assignablePlacePost = messageOptional.get(); + if(assignablePlacePost.getAssignablePlace().getActive()) { + assignablePlacePost.getAssignableRoles().forEach(assignableRole -> { + if(emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) { + Long assignableRoleId = assignableRole.getId(); + assignableRoleService.removeAssignableRoleFromUser(assignableRole, event.getMember()).exceptionally(throwable -> { + log.error("Failed to remove assignable role {} from user {}.", assignableRoleId, event.getMember(), throwable); + return null; + }); + } + }); + } else { + log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), userRemoving.getServerReference().getId()); + } + } + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlacePostRepository.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlacePostRepository.java new file mode 100644 index 000000000..1384dfaaf --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlacePostRepository.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.assignableroles.repository; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AssignableRolePlacePostRepository extends JpaRepository { + +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlaceRepository.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlaceRepository.java new file mode 100644 index 000000000..28309e326 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRolePlaceRepository.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.assignableroles.repository; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.core.models.database.AServer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface AssignableRolePlaceRepository extends JpaRepository { + boolean existsByServerAndKey(AServer server, String key); + Optional findByServerAndKey(AServer server, String key); + List findByServer(AServer server); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRoleRepository.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRoleRepository.java new file mode 100644 index 000000000..3236b704a --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignableRoleRepository.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.assignableroles.repository; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AssignableRoleRepository extends JpaRepository { +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignedRoleUserRepository.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignedRoleUserRepository.java new file mode 100644 index 000000000..1ab367bf5 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/repository/AssignedRoleUserRepository.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.assignableroles.repository; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AssignedRoleUserRepository extends JpaRepository { +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java new file mode 100644 index 000000000..b75c73906 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java @@ -0,0 +1,751 @@ +package dev.sheldan.abstracto.assignableroles.service; + +import dev.sheldan.abstracto.assignableroles.config.AssignableRolePlaceParameterKey; +import dev.sheldan.abstracto.assignableroles.exceptions.AssignableRolePlaceAlreadyExistsException; +import dev.sheldan.abstracto.assignableroles.exceptions.AssignableRolePlaceChannelDoesNotExist; +import dev.sheldan.abstracto.assignableroles.exceptions.EmoteNotInAssignableRolePlaceException; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; +import dev.sheldan.abstracto.assignableroles.models.templates.*; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleManagementService; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlaceManagementService; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; +import dev.sheldan.abstracto.core.command.exception.CommandParameterKeyValueWrongTypeException; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; +import dev.sheldan.abstracto.core.exception.EmoteNotUsableException; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.core.models.database.*; +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.MessageService; +import dev.sheldan.abstracto.core.service.management.*; +import dev.sheldan.abstracto.templating.model.MessageToSend; +import dev.sheldan.abstracto.templating.service.TemplateService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.*; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class AssignableRolePlaceServiceBean implements AssignableRolePlaceService { + + public static final String ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY = "assignable_roles_config_post"; + public static final String ASSIGNABLE_ROLES_POST_TEMPLATE_KEY = "assignable_roles_post"; + public static final String ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY = "assignable_role_places_overview"; + @Autowired + private AssignableRolePlaceManagementService rolePlaceManagementService; + + @Autowired + private AssignableRoleManagementService assignableRoleManagementServiceBean; + + @Autowired + private MessageService messageService; + + @Autowired + private ChannelService channelService; + + @Autowired + private ServerManagementService serverManagementService; + + @Autowired + private BotService botService; + + @Autowired + private EmoteService emoteService; + + @Autowired + private AssignableRolePlaceServiceBean self; + + @Autowired + private TemplateService templateService; + + @Autowired + private EmoteManagementService emoteManagementService; + + @Autowired + private AssignableRolePlacePostManagementService postManagementService; + + @Autowired + private ChannelManagementService channelManagementService; + + @Autowired + private RoleManagementService roleManagementService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private AssignableRoleService roleService; + + @Override + public void createAssignableRolePlace(AServer server, String name, AChannel channel, String text) { + if(rolePlaceManagementService.doesPlaceExist(server, name)) { + throw new AssignableRolePlaceAlreadyExistsException(name); + } + rolePlaceManagementService.createPlace(server, name, channel, text); + } + + @Override + public boolean hasAssignableRolePlaceEmote(AServer server, String placeName, AEmote emote) { + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); + return hasAssignableRolePlaceEmote(assignableRolePlace, emote); + } + + @Override + public boolean isPositionUsed(AServer server, String placeName, Integer position) { + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); + return assignableRolePlace.getAssignableRoles().stream().anyMatch(role -> role.getPosition().equals(position)); + } + + @Override + public CompletableFuture setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position) { + Integer emoteId = emote.getFakeEmote().getId(); + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); + Optional emoteOptional = assignableRolePlace.getAssignableRoles().stream().filter(role -> role.getEmote().getId().equals(emoteId)).findFirst(); + if(emoteOptional.isPresent()) { + AssignableRole toChange = emoteOptional.get(); + toChange.setPosition(position); + } + throw new EmoteNotInAssignableRolePlaceException(emote, placeName); + } + + @Override + public boolean hasAssignableRolePlaceEmote(AssignableRolePlace place, AEmote emote) { + for (AssignableRole assignableRole : place.getAssignableRoles()) { + if(emoteService.compareAEmote(assignableRole.getEmote(), emote)) { + return true; + } + } + return false; + } + + @Override + public CompletableFuture addRoleToAssignableRolePlace(AServer server, String placeName, ARole role, FullEmote fakeEmote, String description) { + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); + Long placeId = assignableRolePlace.getId(); + Long roleId = role.getId(); + Long serverId = server.getId(); + boolean emoteUsable = true; + if(fakeEmote.getEmote() != null) { + // it only may be unusable if its a custom emote + emoteUsable = emoteService.isEmoteUsableByBot(fakeEmote.getEmote()) && fakeEmote.getEmote().isAvailable(); + } + if(emoteUsable) { + AEmote createdEmote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), server.getId(), false); + Integer emoteId = createdEmote.getId(); + + List existingMessagePosts = assignableRolePlace.getMessagePosts(); + existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId)); + createdEmote.setChangeable(false); + + if(!assignableRolePlace.getMessagePosts().isEmpty()){ + AssignableRolePlacePost latestPost = existingMessagePosts.get(assignableRolePlace.getMessagePosts().size() - 1); + AssignablePostMessage model = prepareAssignablePostMessageModel(assignableRolePlace); + AssignablePostRole newAssignableRole = AssignablePostRole + .builder() + .description(description) + .emote(fakeEmote) + .forceNewMessage(latestPost.getAssignableRoles().size() >= 20) + .build(); + model.getRoles().add(newAssignableRole); + MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model); + // add it to the last currently existing post + Optional channelOptional = channelService.getTextChannelInGuild(server.getId(), latestPost.getUsedChannel().getId()); + if(channelOptional.isPresent()) { + TextChannel textChannel = channelOptional.get(); + if(latestPost.getAssignableRoles().size() < 20) { + return addReactionToExistingAssignableRolePlacePost(fakeEmote, description, assignableRolePlace, placeId, roleId, serverId, emoteId, latestPost, messageToSend, textChannel); + } else { + return addNewMessageToAssignableRolePlace(placeName, fakeEmote, description, roleId, serverId, emoteId, messageToSend, textChannel); + } + } else { + throw new ChannelNotFoundException(latestPost.getUsedChannel().getId()); + } + } else { + log.info("Added emote to assignable place {} in server {}, but no message post yet.", placeName, serverId); + self.addAssignableRoleInstanceWithoutPost(placeId, roleId, emoteId, description); + } + } else { + throw new EmoteNotUsableException(fakeEmote.getEmote()); + } + return CompletableFuture.completedFuture(null); + } + + private CompletableFuture addReactionToExistingAssignableRolePlacePost(FullEmote fakeEmote, String description, AssignableRolePlace assignableRolePlace, Long placeId, Long roleId, Long serverId, Integer emoteId, AssignableRolePlacePost latestPost, MessageToSend messageToSend, TextChannel textChannel) { + return textChannel.retrieveMessageById(latestPost.getId()).submit() + .thenCompose(message -> messageService.addReactionToMessageWithFuture(fakeEmote.getFakeEmote(), serverId, message)) + .thenCompose(aVoid -> { + MessageEmbed embedToUse = messageToSend.getEmbeds().get(assignableRolePlace.getMessagePosts().size() - 1); + return channelService.editEmbedMessageInAChannel(embedToUse, textChannel, latestPost.getId()); + }) + .thenCompose(message -> { + self.addAssignableRoleInstanceWithPost(message.getIdLong(), placeId, roleId, emoteId, description); + return CompletableFuture.completedFuture(null); + }); + } + + private CompletableFuture addNewMessageToAssignableRolePlace(String placeName, FullEmote fakeEmote, String description, Long roleId, Long serverId, Integer emoteId, MessageToSend messageToSend, TextChannel textChannel) { + MessageEmbed embedToUse = messageToSend.getEmbeds().get(messageToSend.getEmbeds().size() - 1); + return channelService.sendEmbedToChannel(embedToUse, textChannel) + .thenCompose(message -> messageService.addReactionToMessageWithFuture(fakeEmote.getFakeEmote(), serverId, message).thenAccept(aVoid -> + self.addNewlyCreatedAssignablePlacePost(placeName, description, roleId, serverId, emoteId, textChannel, message) + )); + } + + @Transactional + public void addNewlyCreatedAssignablePlacePost(String placeName, String description,Long roleId, Long serverId, Integer emoteId, TextChannel textChannel, Message message) { + AChannel loadedChannel = channelManagementService.loadChannel(textChannel.getIdLong()); + AServer loadedServer = serverManagementService.loadOrCreate(serverId); + ARole role = roleManagementService.findRole(roleId); + AEmote emote = emoteManagementService.loadEmote(emoteId); + AssignableRolePlace loadedPlace = rolePlaceManagementService.findByServerAndKey(loadedServer, placeName); + + AssignableRolePlacePost newPost = AssignableRolePlacePost + .builder() + .id(message.getIdLong()) + .usedChannel(loadedChannel) + .assignablePlace(loadedPlace) + .build(); + + loadedPlace.getMessagePosts().add(newPost); + assignableRoleManagementServiceBean.addRoleToPlace(loadedPlace, emote, role, description, newPost); + } + + @Transactional + public void addAssignableRoleInstanceWithPost(Long messageId, Long placeId, Long roleId, Integer emoteId, String description) { + assignableRoleManagementServiceBean.addRoleToPlace(placeId, emoteId, roleId, description, messageId); + } + + @Transactional + public void addAssignableRoleInstanceWithoutPost(Long placeId, Long roleId, Integer emoteId, String description) { + assignableRoleManagementServiceBean.addRoleToPlace(placeId, emoteId, roleId, description); + } + + @Override + public CompletableFuture removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote) { + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); + for (AssignableRole assignableRole : assignableRolePlace.getAssignableRoles()) { + if(emoteService.compareAEmote(assignableRole.getEmote(), emote.getFakeEmote())) { + return removeRoleFromAssignablePlace(assignableRole, assignableRolePlace).thenAccept(aVoid -> + self.deleteAssignableRoleFromPlace(server.getId(), placeName, assignableRole.getId()) + ); + } + } + return CompletableFuture.completedFuture(null); + } + + @Transactional + public void deleteAssignableRoleFromPlace(Long serverId, String placeName, Long assignableRoleId) { + AServer server = serverManagementService.loadOrCreate(serverId); + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); + Optional roleToRemoveOptional = assignableRolePlace.getAssignableRoles().stream().filter(role -> role.getId().equals(assignableRoleId)).findAny(); + roleToRemoveOptional.ifPresent(assignableRole -> { + assignableRolePlace.getAssignableRoles().remove(assignableRole); + assignableRole.setAssignablePlace(null); + }); + } + + private CompletableFuture removeRoleFromAssignablePlace(AssignableRole role, AssignableRolePlace assignableRolePlace) { + AssignableRolePlacePost post = role.getAssignableRolePlacePost(); + if(post != null) { + AServer server = assignableRolePlace.getServer(); + TextChannel textChannel = botService.getTextChannelFromServer(server.getId(), post.getUsedChannel().getId()); + List assignableRoles = assignableRolePlace.getAssignableRoles(); + assignableRoles.sort(Comparator.comparing(AssignableRole::getPosition)); + Long messageId = post.getId(); + CompletableFuture fieldEditing = channelService.removeFieldFromMessage(textChannel, messageId, assignableRoles.indexOf(role)); + CompletableFuture reactionRemoval = messageService.clearReactionFromMessageWithFuture(role.getEmote(), assignableRolePlace.getServer().getId(), role.getAssignableRolePlacePost().getUsedChannel().getId(), role.getAssignableRolePlacePost().getId()); + return CompletableFuture.allOf(fieldEditing, reactionRemoval); + } else { + // this case comes from the situation in which, the emote was deleted ant he initial post setup failed + log.warn("Reaction {} to remove does not have a post attached. The post needs to be setup again, it is most likely not functioning currently anyway.", role.getEmote().getEmoteId()); + return CompletableFuture.completedFuture(null); + } + } + + @Override + public CompletableFuture setupAssignableRolePlace(AServer server, String name) { + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name); + List> oldPostDeletionFutures = deleteExistingMessagePostsForPlace(assignableRolePlace); + assignableRolePlace.getMessagePosts().clear(); + assignableRolePlace.getAssignableRoles().forEach(assignableRole -> + assignableRole.setAssignableRolePlacePost(null) + ); + Long serverId = server.getId(); + return CompletableFuture.allOf(oldPostDeletionFutures.toArray(new CompletableFuture[0])) + .thenCompose(aVoid -> self.createAssignableRolePlacePosts(serverId, name)); + } + + @Override + public CompletableFuture refreshAssignablePlacePosts(AServer server, String name) { + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name); + return refreshAssignablePlacePosts(assignableRolePlace); + } + + @Override + public CompletableFuture refreshAssignablePlacePosts(AssignableRolePlace place) { + MessageToSend messageToSend = renderAssignablePlacePosts(place); + List existingMessagePosts = place.getMessagePosts(); + existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId)); + AssignableRolePlacePost latestPost = existingMessagePosts.get(place.getMessagePosts().size() - 1); + List> futures = new ArrayList<>(); + Optional channelOptional = channelService.getTextChannelInGuild(place.getServer().getId(), latestPost.getUsedChannel().getId()); + if(channelOptional.isPresent()) { + TextChannel textChannel = channelOptional.get(); + Iterator iterator = messageToSend.getEmbeds().iterator(); + place.getMessagePosts().forEach(post -> { + CompletableFuture messageCompletableFuture = channelService.editEmbedMessageInAChannel(iterator.next(), textChannel, post.getId()); + futures.add(messageCompletableFuture); + }); + + } + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + } + + @Override + public CompletableFuture refreshTextFromPlace(AssignableRolePlace place) { + List existingMessagePosts = place.getMessagePosts(); + if(!existingMessagePosts.isEmpty()) { + MessageToSend renderedMessage = renderAssignablePlacePosts(place); + existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId)); + AssignableRolePlacePost latestPost = existingMessagePosts.get(0); + Long channelId = latestPost.getUsedChannel().getId(); + Optional channelOptional = channelService.getTextChannelInGuild(place.getServer().getId(), channelId); + if(channelOptional.isPresent()) { + return channelService.editEmbedMessageInAChannel(renderedMessage.getEmbeds().get(0), channelOptional.get(), latestPost.getId()).thenCompose(message -> CompletableFuture.completedFuture(null)); + } + throw new ChannelNotFoundException(channelId); + } + return CompletableFuture.completedFuture(null); + } + + @Override + public void setAssignablePlaceActiveTo(AServer server, String name, Boolean newValue) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + if(newValue) { + this.activateAssignableRolePlace(place); + } else { + this.deactivateAssignableRolePlace(place); + } + } + + private List> deleteExistingMessagePostsForPlace(AssignableRolePlace assignableRolePlace) { + List> oldPostDeletionFutures = new ArrayList<>(); + assignableRolePlace.getMessagePosts().forEach(assignableRolePlacePost -> + oldPostDeletionFutures.add(messageService.deleteMessageInChannelInServer(assignableRolePlace.getServer().getId(), assignableRolePlacePost.getUsedChannel().getId(), assignableRolePlacePost.getId())) + ); + return oldPostDeletionFutures; + } + + @Override + public void deactivateAssignableRolePlace(AServer server, String name) { + setAssignablePlaceActiveTo(server, name, false); + } + + @Override + public void deactivateAssignableRolePlace(AssignableRolePlace place) { + place.setActive(false); + log.info("Deactivating assignable role place {} in server {}", place.getId(), place.getServer().getId()); + } + + @Override + public void activateAssignableRolePlace(AServer server, String name) { + setAssignablePlaceActiveTo(server, name, true); + } + + @Override + public void activateAssignableRolePlace(AssignableRolePlace place) { + place.setActive(true); + log.info("Activating assignable role place {} in server {}", place.getId(), place.getServer().getId()); + } + + @Override + public CompletableFuture setAssignablePlaceInlineTo(AServer server, String name, Boolean newValue) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + if(newValue) { + return this.inlineAssignableRolePlace(place); + } else { + return this.spreadAssignableRolePlace(place); + } + } + + @Override + public CompletableFuture inlineAssignableRolePlace(AServer server, String name) { + return setAssignablePlaceInlineTo(server, name, true); + } + + @Override + public CompletableFuture inlineAssignableRolePlace(AssignableRolePlace place) { + log.info("Setting assignable role place inline {} in server {} to {}", place.getId(), place.getServer().getId(), true); + place.setInline(true); + return refreshAssignablePlacePosts(place); + } + + @Override + public CompletableFuture spreadAssignableRolePlace(AServer server, String name) { + return setAssignablePlaceInlineTo(server, name, false); + } + + @Override + public CompletableFuture spreadAssignableRolePlace(AssignableRolePlace place) { + log.info("Setting assignable role place inline {} in server {} to {}", place.getId(), place.getServer().getId(), false); + place.setInline(false); + return refreshAssignablePlacePosts(place); + } + + @Override + public void setAssignablePlaceUniqueTo(AServer server, String name, Boolean newValue) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + if(newValue) { + this.uniqueAssignableRolePlace(place); + } else { + this.multipleAssignableRolePlace(place); + } + } + + @Override + public void uniqueAssignableRolePlace(AServer server, String name) { + setAssignablePlaceInlineTo(server, name, true); + } + + @Override + public void uniqueAssignableRolePlace(AssignableRolePlace place) { + log.info("Setting assignable role place uniqueness {} in server {} to {}", place.getId(), place.getServer().getId(), true); + place.setUniqueRoles(true); + } + + @Override + public void multipleAssignableRolePlace(AServer server, String name) { + setAssignablePlaceInlineTo(server, name, false); + } + + @Override + public void multipleAssignableRolePlace(AssignableRolePlace place) { + log.info("Setting assignable role place uniqueness {} in server {} to {}", place.getId(), place.getServer().getId(), false); + place.setUniqueRoles(false); + } + + @Override + public void setAssignablePlaceAutoRemoveTo(AServer server, String name, Boolean newValue) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + if(newValue) { + this.autoRemoveAssignableRolePlace(place); + } else { + this.keepReactionsAssignableRolePlace(place); + } + } + + @Override + public void autoRemoveAssignableRolePlace(AServer server, String name) { + setAssignablePlaceAutoRemoveTo(server, name, true); + } + + @Override + public void autoRemoveAssignableRolePlace(AssignableRolePlace place) { + log.info("Setting assignable role place auto remove {} in server {} to {}", place.getId(), place.getServer().getId(), true); + place.setAutoRemove(true); + } + + @Override + public void keepReactionsAssignableRolePlace(AServer server, String name) { + setAssignablePlaceAutoRemoveTo(server, name, false); + } + + @Override + public void keepReactionsAssignableRolePlace(AssignableRolePlace place) { + log.info("Setting assignable role place auto remove {} in server {} to {}", place.getId(), place.getServer().getId(), false); + place.setAutoRemove(false); + } + + @Override + public void swapPositions(AServer server, String name, FullEmote firstEmote, FullEmote secondEmote) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + Optional firstEmoteOptional = place.getAssignableRoles().stream().filter(role -> emoteService.compareAEmote(role.getEmote(), firstEmote.getFakeEmote())).findFirst(); + Optional secondEmoteOptional = place.getAssignableRoles().stream().filter(role -> emoteService.compareAEmote(role.getEmote(), secondEmote.getFakeEmote())).findFirst(); + if(firstEmoteOptional.isPresent() && secondEmoteOptional.isPresent()) { + AssignableRole firstRole = firstEmoteOptional.get(); + AssignableRole secondRole = secondEmoteOptional.get(); + int firstPosition = firstRole.getPosition(); + firstRole.setPosition(secondRole.getPosition()); + secondRole.setPosition(firstPosition); + } else { + if(!firstEmoteOptional.isPresent()) { + throw new EmoteNotInAssignableRolePlaceException(firstEmote, name); + } else { + throw new EmoteNotInAssignableRolePlaceException(secondEmote, name); + } + } + } + + @Override + public CompletableFuture testAssignableRolePlace(AServer server, String name, MessageChannel channel) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + MessageToSend messageToSend = renderAssignablePlacePosts(place); + List> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, channel); + return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])); + } + + @Override + public void showAssignablePlaceConfig(AServer server, String name, MessageChannel channel) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + List roles = new ArrayList<>(); + Guild guild = botService.getGuildByIdNullable(server.getId()); + List assignableRoles = place.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); + for (AssignableRole role : assignableRoles) { + AEmote emoteForRole = role.getEmote(); + Emote jdaEmoteForRole = botService.getEmote(emoteForRole).orElse(null); + Role jdaRole = guild.getRoleById(role.getRole().getId()); + AssignablePostConfigRole postRole = AssignablePostConfigRole + .builder() + .description(role.getDescription()) + .emote(jdaEmoteForRole) + .position(role.getPosition()) + .awardedRole(jdaRole) + .build(); + roles.add(postRole); + } + AssignableRolePlaceConfig configModel = AssignableRolePlaceConfig + .builder() + .roles(roles) + .place(place) + .build(); + channelService.sendEmbedTemplateInChannel(ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY, configModel, channel); + } + + @Override + public void moveAssignableRolePlace(AServer server, String name, TextChannel newChannel) { + AChannel channel = channelManagementService.loadChannel(newChannel.getIdLong()); + rolePlaceManagementService.moveAssignableRolePlace(server, name, channel); + } + + @Override + public void changeAssignablePlaceDescription(AServer server, String name, String newDescription) { + rolePlaceManagementService.changeAssignableRolePlaceDescription(server, name, newDescription); + } + + @Override + public CompletableFuture deleteAssignableRolePlace(AServer server, String name) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + rolePlaceManagementService.deleteAssignablePlace(place); + deleteEmotesFromAssignableRolePlace(place); + List> deleteFutures = deleteExistingMessagePostsForPlace(place); + return CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])); + } + + @Override + public CompletableFuture changeText(AServer server, String name, String newText) { + AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); + place.setText(newText); + return refreshTextFromPlace(place); + } + + @Override + public CompletableFuture removeExistingReactionsAndRoles(AssignableRolePlace place, AssignedRoleUser user) { + Member memberInServer = botService.getMemberInServer(user.getUser()); + List> futures = new ArrayList<>(); + user.getRoles().forEach(assignableRole -> { + futures.add(roleService.removeAssignableRoleFromUser(assignableRole, memberInServer)); + AEmote emoteToUseObject = emoteManagementService.loadEmote(assignableRole.getEmote().getId()); + AssignableRolePlacePost assignablePlacePost = assignableRole.getAssignableRolePlacePost(); + futures.add(messageService.removeReactionOfUserFromMessageWithFuture(emoteToUseObject, place.getServer().getId(), + assignablePlacePost.getUsedChannel().getId(), assignablePlacePost.getId(), memberInServer)); + }); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + } + + @Override + public CompletableFuture changeConfiguration(AServer server, String name, AssignableRolePlaceParameterKey keyToChange, Object newValue) { + Boolean booleanValue = BooleanUtils.toBooleanObject(newValue.toString()); + if(booleanValue == null) { + throwBooleanParameterKeyException(); + } + switch (keyToChange) { + case INLINE: + return setAssignablePlaceInlineTo(server, name, booleanValue); + case AUTOREMOVE: + setAssignablePlaceAutoRemoveTo(server, name, booleanValue); + return CompletableFuture.completedFuture(null); + case UNIQUE: + setAssignablePlaceUniqueTo(server, name, booleanValue); + return CompletableFuture.completedFuture(null); + case ACTIVE: + setAssignablePlaceActiveTo(server, name, booleanValue); + return CompletableFuture.completedFuture(null); + default: + throw new IllegalArgumentException("Illegal assignable role place parameter key was passed."); + } + } + + @Override + public CompletableFuture showAllAssignableRolePlaces(AServer server, MessageChannel channel) { + List assignableRolePlaces = rolePlaceManagementService.findAllByServer(server); + AssignablePlaceOverview overViewModel = AssignablePlaceOverview.builder().places(assignableRolePlaces).build(); + List> promises = channelService.sendEmbedTemplateInChannel(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, overViewModel, channel); + return CompletableFuture.allOf(promises.toArray(new CompletableFuture[0])); + } + + private void throwBooleanParameterKeyException() { + throw new CommandParameterKeyValueWrongTypeException(Arrays.asList("yes", "no", "true", "false", "on", "off")); + } + + private void deleteEmotesFromAssignableRolePlace(AssignableRolePlace place) { + place.getAssignableRoles().forEach(role -> + emoteManagementService.deleteEmote(role.getEmote()) + ); + } + + private List> sendAssignablePostMessages(AssignableRolePlace place, MessageChannel channel) { + MessageToSend messageToSend = renderAssignablePlacePosts(place); + return channelService.sendMessageToSendToChannel(messageToSend, channel); + } + + private MessageToSend renderAssignablePlacePosts(AssignableRolePlace place) { + AssignablePostMessage model = prepareAssignablePostMessageModel(place); + return templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model); + } + + private AssignablePostMessage prepareAssignablePostMessageModel(AssignableRolePlace place) { + List roles = new ArrayList<>(); + List rolesToAdd = place.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); + int maxPosition = 0; + if(!rolesToAdd.isEmpty()) { + maxPosition = rolesToAdd.get(rolesToAdd.size() - 1).getPosition(); + Iterator rolesToAddIterator = rolesToAdd.iterator(); + AssignableRole current = rolesToAddIterator.next(); + AssignablePostRole lastAddedRole = null; + for (int position = 0; position < maxPosition + 1; position++) { + boolean legitEntry = current.getPosition().equals(position); + boolean startOfNewMessage = position > 0 && (position % 21) == 0; + if(legitEntry) { + AEmote emoteForRole = current.getEmote(); + Emote jdaEmoteForRole = botService.getEmote(emoteForRole).orElse(null); + FullEmote fullEmote = FullEmote.builder().emote(jdaEmoteForRole).fakeEmote(emoteForRole).build(); + AssignablePostRole postRole = AssignablePostRole + .builder() + .description(current.getDescription()) + .emote(fullEmote) + .position(position) + .forceNewMessage(startOfNewMessage) + .build(); + roles.add(postRole); + lastAddedRole = postRole; + if(rolesToAddIterator.hasNext()) { + current = rolesToAddIterator.next(); + } + } else if(startOfNewMessage && lastAddedRole != null) { + lastAddedRole.setForceNewMessage(true); + } + } + } + return AssignablePostMessage + .builder() + .roles(roles) + .place(place) + .maxPosition(maxPosition) + .build(); + } + + @Transactional + public CompletableFuture createAssignableRolePlacePosts(Long serverId, String name) { + AServer server = serverManagementService.loadOrCreate(serverId); + AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name); + Optional channelOptional = botService.getTextChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId()); + if(channelOptional.isPresent()) { + MessageChannel channel = channelOptional.get(); + List> messageFutures = sendAssignablePostMessages(assignableRolePlace, channel); + return CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0])) + .thenCompose(aVoid -> self.addEmotes(messageFutures, name)); + } else { + log.warn("Channel to create assignable role post in does not exist."); + throw new AssignableRolePlaceChannelDoesNotExist(assignableRolePlace.getChannel().getId(), name); + } + } + + + @Transactional + public CompletableFuture addEmotes(List> assignablePlacePostsMessageFutures, String placeKey) { + try { + Message firstMessage = assignablePlacePostsMessageFutures.get(0).get(); + Long serverId = firstMessage.getGuild().getIdLong(); + + AServer innerServer = serverManagementService.loadOrCreate(serverId); + AssignableRolePlace innerRolePlace = rolePlaceManagementService.findByServerAndKey(innerServer, placeKey); + + List roleStream = innerRolePlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); + List> reactionFutures = new ArrayList<>(); + int usedEmotes = 0; + for (CompletableFuture messageCompletableFuture : assignablePlacePostsMessageFutures) { + Message sentMessage = messageCompletableFuture.get(); + // this uses the actual embed count as a limit, so this relies on fields to be used for description, if this changes, this needs to be changed + MessageEmbed embed = sentMessage.getEmbeds().get(0); + List firstRoles = roleStream.subList(usedEmotes, usedEmotes + embed.getFields().size()); + usedEmotes += embed.getFields().size(); + List usedEmoteIds = firstRoles.stream().map(assignableRole -> assignableRole.getEmote().getId()).collect(Collectors.toList()); + CompletableFuture firstMessageFuture = createAssignableRolePlacePost(sentMessage, serverId, usedEmoteIds); + reactionFutures.add(firstMessageFuture); + } + return CompletableFuture.allOf(reactionFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> { + self.storeCreatedAssignableRolePlacePosts(placeKey, serverId, assignablePlacePostsMessageFutures); + return CompletableFuture.completedFuture(null); + }); + } catch (InterruptedException | ExecutionException e) { + log.error("Failed to process future from sending assignable place posts messages.", e); + throw new AbstractoRunTimeException(e); + } + + } + + @Transactional + public void storeCreatedAssignableRolePlacePosts(String name, Long serverId, List> futures) { + AServer server = serverManagementService.loadOrCreate(serverId); + AssignableRolePlace updatedPlace = rolePlaceManagementService.findByServerAndKey(server, name); + List rolesToAdd = updatedPlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); + int usedEmotes = 0; + for (int i = 0; i < futures.size(); i++) { + CompletableFuture messageCompletableFuture = futures.get(i); + try { + Message message = messageCompletableFuture.get(); + Message sentMessage = messageCompletableFuture.get(); + // this uses the actual embed count as a limit, so this relies on fields to be used for description, if this changes, this needs to be changed + MessageEmbed embed = sentMessage.getEmbeds().get(0); + List firstRoles = rolesToAdd.subList(usedEmotes, usedEmotes + embed.getFields().size()); + usedEmotes += embed.getFields().size(); + AssignableRolePlacePost post = AssignableRolePlacePost + .builder() + .id(message.getIdLong()) + .usedChannel(updatedPlace.getChannel()) + .assignablePlace(updatedPlace) + .build(); + firstRoles.forEach(assignableRole -> + assignableRole.setAssignableRolePlacePost(post) + ); + updatedPlace.getMessagePosts().add(post); + } catch (Exception e) { + log.error("Failed to get future.", e); + } + } + } + + @Transactional + public CompletableFuture createAssignableRolePlacePost(Message message, Long server, List emotesToAdd) { + // TODO might need to guarantee the order + List> futures = new ArrayList<>(); + emotesToAdd.forEach(emotesToUse -> { + AEmote emoteToUseObject = emoteManagementService.loadEmote(emotesToUse); + futures.add(messageService.addReactionToMessageWithFuture(emoteToUseObject, server, message)); + }); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleServiceBean.java new file mode 100644 index 000000000..364d43a74 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleServiceBean.java @@ -0,0 +1,69 @@ +package dev.sheldan.abstracto.assignableroles.service; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleManagementServiceBean; +import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService; +import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementServiceBean; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.RoleService; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import net.dv8tion.jda.api.entities.Member; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.concurrent.CompletableFuture; + +@Component +public class AssignableRoleServiceBean implements AssignableRoleService { + + @Autowired + private RoleService roleService; + + @Autowired + private AssignedRoleUserManagementService assignedRoleUserManagementService; + + @Autowired + private AssignableRoleManagementServiceBean assignableRoleManagementServiceBean; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private AssignedRoleUserManagementServiceBean assignedRoleUserManagementServiceBean; + + @Autowired + private AssignableRoleServiceBean self; + + @Override + public CompletableFuture assignAssignableRoleToUser(Long assignableRoleId, Member toAdd) { + AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId); + return roleService.addRoleToMemberFuture(toAdd, role.getRole()).thenApply(aVoid -> { + self.persistRoleAssignment(assignableRoleId, toAdd); + return null; + }); + } + + @Override + public CompletableFuture removeAssignableRoleFromUser(AssignableRole assignableRole, Member member) { + Long assignableRoleId = assignableRole.getId(); + return roleService.removeRoleFromMemberFuture(member, assignableRole.getRole()).thenApply(aVoid -> { + self.persistRoleRemoval(assignableRoleId, member); + return null; + }); + } + + @Transactional + public void persistRoleAssignment(Long assignableRoleId, Member member) { + AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId); + AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member); + assignedRoleUserManagementServiceBean.addAssignedRoleToUser(role, aUserInAServer); + } + + @Transactional + public void persistRoleRemoval(Long assignableRoleId, Member member) { + AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId); + AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member); + assignedRoleUserManagementServiceBean.removeAssignedRoleFromUser(role, aUserInAServer); + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementServiceBean.java new file mode 100644 index 000000000..bdcc04999 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementServiceBean.java @@ -0,0 +1,77 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.exceptions.AssignableRolePlaceNotFoundException; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleRepository; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.models.database.ARole; +import dev.sheldan.abstracto.core.service.management.EmoteManagementService; +import dev.sheldan.abstracto.core.service.management.RoleManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class AssignableRoleManagementServiceBean implements AssignableRoleManagementService { + + @Autowired + private AssignableRolePlaceManagementService rolePlaceManagementService; + + @Autowired + private EmoteManagementService emoteManagementService; + + @Autowired + private RoleManagementService roleManagementService; + + @Autowired + private AssignableRolePlacePostManagementService postManagementService; + + @Autowired + private AssignableRoleRepository repository; + + @Override + public AssignableRole addRoleToPlace(AssignableRolePlace place, AEmote emote, ARole role, String description, AssignableRolePlacePost post) { + Integer maxPosition = place.getAssignableRoles().stream().map(AssignableRole::getPosition).max(Integer::compareTo).orElse(0); + if(!place.getAssignableRoles().isEmpty()) { + maxPosition += 1; + } + AssignableRole roleToAdd = AssignableRole + .builder() + .assignablePlace(place) + .emote(emote) + .role(role) + .requiredLevel(0) + .position(maxPosition) + .description(description) + .assignableRolePlacePost(post) + .build(); + place.getAssignableRoles().add(roleToAdd); + return roleToAdd; + } + + @Override + public AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description, Long messageId) { + AssignableRolePlace place = rolePlaceManagementService.findByPlaceId(placeId).orElseThrow(() -> new AssignableRolePlaceNotFoundException(placeId)); + AEmote emote = emoteManagementService.loadEmote(emoteId); + ARole role = roleManagementService.findRole(roleId); + AssignableRolePlacePost post = postManagementService.findByMessageId(messageId); + AssignableRole assignableRole = addRoleToPlace(place, emote, role, description, post); + post.getAssignableRoles().add(assignableRole); + return assignableRole; + } + + @Override + public AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description) { + AssignableRolePlace place = rolePlaceManagementService.findByPlaceId(placeId).orElseThrow(() -> new AssignableRolePlaceNotFoundException(placeId)); + AEmote emote = emoteManagementService.loadEmote(emoteId); + ARole role = roleManagementService.findRole(roleId); + return addRoleToPlace(place, emote, role, description, null); + } + + @Override + public AssignableRole getByAssignableRoleId(Long assignableRoleId) { + return repository.findById(assignableRoleId).orElseThrow(() -> new AbstractoRunTimeException("Assignable role not found")); + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementServiceBean.java new file mode 100644 index 000000000..9811bf41c --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementServiceBean.java @@ -0,0 +1,72 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.exceptions.AssignableRolePlaceNotFoundException; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.repository.AssignableRolePlaceRepository; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +@Component +public class AssignableRolePlaceManagementServiceBean implements AssignableRolePlaceManagementService { + + @Autowired + private AssignableRolePlaceRepository repository; + + @Override + public AssignableRolePlace createPlace(AServer server, String name, AChannel channel, String text) { + AssignableRolePlace place = AssignableRolePlace + .builder() + .channel(channel) + .server(server) + .text(text) + .key(name) + .build(); + repository.save(place); + return place; + } + + @Override + public boolean doesPlaceExist(AServer server, String name) { + return repository.existsByServerAndKey(server, name); + } + + @Override + public AssignableRolePlace findByServerAndKey(AServer server, String name) { + // todo use other exception or adapt exception + return repository.findByServerAndKey(server, name).orElseThrow(() -> new AssignableRolePlaceNotFoundException(0L)); + } + + @Override + public Optional findByPlaceId(Long id) { + return repository.findById(id); + } + + @Override + public void moveAssignableRolePlace(AServer server, String name, AChannel newChannel) { + AssignableRolePlace assignablePlaceToChange = findByServerAndKey(server, name); + assignablePlaceToChange.setChannel(newChannel); + } + + @Override + public void changeAssignableRolePlaceDescription(AServer server, String name, String newDescription) { + AssignableRolePlace assignablePlaceToChange = findByServerAndKey(server, name); + assignablePlaceToChange.setText(newDescription); + } + + @Override + public void deleteAssignablePlace(AssignableRolePlace toDelete) { + repository.delete(toDelete); + } + + @Override + public List findAllByServer(AServer server) { + return repository.findByServer(server); + } + + +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementServiceBean.java new file mode 100644 index 000000000..067a56a8e --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementServiceBean.java @@ -0,0 +1,28 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.assignableroles.exceptions.AssignablePlacePostNotFoundException; +import dev.sheldan.abstracto.assignableroles.repository.AssignableRolePlacePostRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class AssignableRolePlacePostManagementServiceBean implements AssignableRolePlacePostManagementService { + + @Autowired + private AssignableRolePlacePostRepository repository; + + + @Override + public Optional findByMessageIdOptional(Long messageId) { + return repository.findById(messageId); + } + + @Override + public AssignableRolePlacePost findByMessageId(Long messageId) { + return findByMessageIdOptional(messageId).orElseThrow(() -> new AssignablePlacePostNotFoundException(messageId)); + } + +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementServiceBean.java new file mode 100644 index 000000000..07a05de61 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementServiceBean.java @@ -0,0 +1,54 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.exceptions.AssignedUserNotFoundException; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; +import dev.sheldan.abstracto.assignableroles.repository.AssignedRoleUserRepository; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserManagementService { + + @Autowired + private AssignedRoleUserRepository repository; + + @Override + public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { + Optional optional = findByUserInServerOptional(aUserInAServer); + AssignedRoleUser user = optional.orElseGet(() -> createAssignedRoleUser(aUserInAServer)); + assignableRole.getAssignedUsers().add(user); + user.getRoles().add(assignableRole); + } + + @Override + public void removeAssignedRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { + AssignedRoleUser user = findByUserInServer(aUserInAServer); + assignableRole.getAssignedUsers().remove(user); + user.getRoles().remove(assignableRole); + } + + @Override + public AssignedRoleUser createAssignedRoleUser(AUserInAServer aUserInAServer) { + AssignedRoleUser newUser = AssignedRoleUser.builder().user(aUserInAServer).id(aUserInAServer.getUserInServerId()).build(); + return repository.save(newUser); + } + + @Override + public boolean doesAssignedRoleUserExist(AUserInAServer aUserInAServer) { + return repository.existsById(aUserInAServer.getUserInServerId()); + } + + @Override + public Optional findByUserInServerOptional(AUserInAServer aUserInAServer) { + return repository.findById(aUserInAServer.getUserInServerId()); + } + + @Override + public AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer) { + return findByUserInServerOptional(aUserInAServer).orElseThrow(() -> new AssignedUserNotFoundException(aUserInAServer)); + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/command.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/command.xml new file mode 100644 index 000000000..1e3b22286 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/command.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/data.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/data.xml new file mode 100644 index 000000000..4c4182ad7 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/data.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/default_feature_flag.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/default_feature_flag.xml new file mode 100644 index 000000000..b653dbe97 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/default_feature_flag.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/feature.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/feature.xml new file mode 100644 index 000000000..c1cc36ec7 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/feature.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/module.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/module.xml new file mode 100644 index 000000000..1711e732b --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-seedData/module.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role.xml new file mode 100644 index 000000000..628120b36 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place.xml new file mode 100644 index 000000000..0a59dd547 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place_post.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place_post.xml new file mode 100644 index 000000000..1d299e93d --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assignable_role_place_post.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assigned_role_user.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assigned_role_user.xml new file mode 100644 index 000000000..97046f9be --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/assigned_role_user.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/tables.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/tables.xml new file mode 100644 index 000000000..af238938a --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/assignableRoles-tables/tables.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/collection.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/collection.xml new file mode 100644 index 000000000..9c0a0bf9d --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/1.0-assignableRoles/collection.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/assignableRoles-changeLog.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/assignableRoles-changeLog.xml new file mode 100644 index 000000000..697c1e25b --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/assignableRoles-changeLog.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/dbchangelog-3.8.xsd b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/dbchangelog-3.8.xsd new file mode 100644 index 000000000..ebfe6d612 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/resources/migrations/dbchangelog-3.8.xsd @@ -0,0 +1,1377 @@ + + + + + + + + + + + + + + Extension to standard XSD boolean type to allow ${} parameters + + + + + + + + + + + + + + + + Extension to standard XSD integer type to allow ${} parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + onChangeLogPreconditionOnSqlOutput determines what should + happen when evaluating this precondition in updateSQL mode. TEST: Run + precondition, FAIL: Fail precondition, IGNORE: Skip precondition check + [DEFAULT] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with valueClobFile to specify file encoding explicitly. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true for a cycling sequence, false for a non-cycling sequence. + Default is false. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml new file mode 100644 index 000000000..c65ca4883 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml @@ -0,0 +1,21 @@ + + + + dev.sheldan.abstracto.modules + assignable-roles + 1.0-SNAPSHOT + + 4.0.0 + assignable-roles-int + + + + dev.sheldan.abstracto.templating + templating-interface + ${project.version} + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/AssignableRolePlaceParameterKey.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/AssignableRolePlaceParameterKey.java new file mode 100644 index 000000000..5981e53fa --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/AssignableRolePlaceParameterKey.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.assignableroles.config; + +import dev.sheldan.abstracto.core.command.execution.CommandParameterKey; +import lombok.Getter; + + +@Getter +public enum AssignableRolePlaceParameterKey implements CommandParameterKey { + INLINE, UNIQUE, AUTOREMOVE, ACTIVE +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableFeatureConfig.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableFeatureConfig.java new file mode 100644 index 000000000..4d849202e --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableFeatureConfig.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.assignableroles.config.features; + +import dev.sheldan.abstracto.core.config.FeatureConfig; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import org.springframework.stereotype.Component; + +@Component +public class AssignableFeatureConfig implements FeatureConfig { + @Override + public FeatureEnum getFeature() { + return AssignableRoleFeature.ASSIGNABLE_ROLES; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableRoleFeature.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableRoleFeature.java new file mode 100644 index 000000000..8dee3d39d --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/config/features/AssignableRoleFeature.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.assignableroles.config.features; + +import dev.sheldan.abstracto.core.config.FeatureEnum; +import lombok.Getter; + +@Getter +public enum AssignableRoleFeature implements FeatureEnum { + ASSIGNABLE_ROLES("assignableRole"); + + private String key; + + AssignableRoleFeature(String key) { + this.key = key; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignablePlacePostNotFoundException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignablePlacePostNotFoundException.java new file mode 100644 index 000000000..8469a58a7 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignablePlacePostNotFoundException.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignableRolePlacePostNotFoundModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; + +public class AssignablePlacePostNotFoundException extends AbstractoRunTimeException implements Templatable { + + private final AssignableRolePlacePostNotFoundModel model; + + public AssignablePlacePostNotFoundException(Long messageId) { + super("Assignable place post not found."); + this.model = AssignableRolePlacePostNotFoundModel.builder().messageId(messageId).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_post_not_found_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleAlreadyDefinedException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleAlreadyDefinedException.java new file mode 100644 index 000000000..331da1cd4 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleAlreadyDefinedException.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignableRoleAlreadyDefinedModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.templating.Templatable; + +public class AssignableRoleAlreadyDefinedException extends AbstractoRunTimeException implements Templatable { + private final AssignableRoleAlreadyDefinedModel model; + + public AssignableRoleAlreadyDefinedException(FullEmote emote, String placeName) { + super("Assignable role already assigned"); + this.model = AssignableRoleAlreadyDefinedModel.builder().emote(emote).placeName(placeName).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_emote_already_defined_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleNotUsableException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleNotUsableException.java new file mode 100644 index 000000000..67d83086f --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRoleNotUsableException.java @@ -0,0 +1,26 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignableRoleNotUsableModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.FullRole; +import dev.sheldan.abstracto.templating.Templatable; +import net.dv8tion.jda.api.entities.Guild; + +public class AssignableRoleNotUsableException extends AbstractoRunTimeException implements Templatable { + private final AssignableRoleNotUsableModel model; + + public AssignableRoleNotUsableException(FullRole role, Guild guild) { + super("Role is not usable as assignable role"); + this.model = AssignableRoleNotUsableModel.builder().role(role).guild(guild).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_role_not_usable_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceAlreadyExistsException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceAlreadyExistsException.java new file mode 100644 index 000000000..3393cb2d3 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceAlreadyExistsException.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignableRolePlaceAlreadyExistsModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; + +public class AssignableRolePlaceAlreadyExistsException extends AbstractoRunTimeException implements Templatable { + + private final AssignableRolePlaceAlreadyExistsModel model; + + public AssignableRolePlaceAlreadyExistsException(String name) { + super("Assignable role place already exists"); + this.model = AssignableRolePlaceAlreadyExistsModel.builder().name(name).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_exists_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceChannelDoesNotExist.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceChannelDoesNotExist.java new file mode 100644 index 000000000..8caba4c25 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceChannelDoesNotExist.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignableRolePlaceChannelDoesNotExistModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; + +public class AssignableRolePlaceChannelDoesNotExist extends AbstractoRunTimeException implements Templatable { + + private final AssignableRolePlaceChannelDoesNotExistModel model; + + public AssignableRolePlaceChannelDoesNotExist(Long channelId, String placeName) { + super("Assignable role place channel does not exist"); + this.model = AssignableRolePlaceChannelDoesNotExistModel.builder().channelId(channelId).placeName(placeName).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_channel_does_not_exist_exception"; + } + + @Override + public Object getTemplateModel() { + return this.model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceNotFoundException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceNotFoundException.java new file mode 100644 index 000000000..052e36e2b --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignableRolePlaceNotFoundException.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignableRolePlaceNotFoundModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; + +public class AssignableRolePlaceNotFoundException extends AbstractoRunTimeException implements Templatable { + + private final AssignableRolePlaceNotFoundModel model; + + public AssignableRolePlaceNotFoundException(Long placeId) { + super("Assignable role place not found"); + this.model = AssignableRolePlaceNotFoundModel.builder().placeId(placeId).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_not_found_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignedUserNotFoundException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignedUserNotFoundException.java new file mode 100644 index 000000000..587142051 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/AssignedUserNotFoundException.java @@ -0,0 +1,26 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.AssignedUserNotFoundModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.templating.Templatable; + +public class AssignedUserNotFoundException extends AbstractoRunTimeException implements Templatable { + + private final AssignedUserNotFoundModel model; + + public AssignedUserNotFoundException(AUserInAServer userInAServer) { + super("Assigned user was not found"); + this.model = AssignedUserNotFoundModel.builder().aUserInAServer(userInAServer).build(); + } + + @Override + public String getTemplateName() { + return "assignable_role_place_assigned_user_not_found_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/EmoteNotInAssignableRolePlaceException.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/EmoteNotInAssignableRolePlaceException.java new file mode 100644 index 000000000..f0a1cb338 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/exceptions/EmoteNotInAssignableRolePlaceException.java @@ -0,0 +1,26 @@ +package dev.sheldan.abstracto.assignableroles.exceptions; + +import dev.sheldan.abstracto.assignableroles.models.exception.EmoteNotInAssignableRolePlaceModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.templating.Templatable; + +public class EmoteNotInAssignableRolePlaceException extends AbstractoRunTimeException implements Templatable { + + private final EmoteNotInAssignableRolePlaceModel model; + + public EmoteNotInAssignableRolePlaceException(FullEmote emote, String placeName) { + super("Emote not found in assignable role place"); + this.model = EmoteNotInAssignableRolePlaceModel.builder().emote(emote).placeName(placeName).build(); + } + + @Override + public String getTemplateName() { + return "emote_not_in_assignable_role_place_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRole.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRole.java new file mode 100644 index 000000000..c926a6c37 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRole.java @@ -0,0 +1,73 @@ +package dev.sheldan.abstracto.assignableroles.models.database; + +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.models.database.ARole; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name="assignable_role") +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class AssignableRole { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true) + @JoinColumn(name = "emote_id") + private AEmote emote; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "role_id", nullable = false) + private ARole role; + + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @Getter + @Setter + @JoinColumn(name = "assignable_place_id", nullable = false) + private AssignableRolePlace assignablePlace; + + @Getter + @Setter + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @JoinColumn(name = "assignable_role_place_post_id") + private AssignableRolePlacePost assignableRolePlacePost; + + @Getter + @Setter + @ManyToMany(mappedBy = "roles") + @Builder.Default + private List assignedUsers = new ArrayList<>(); + + private String description; + + private Integer requiredLevel; + private Integer position; + + @Column(name = "created") + private Instant created; + + @PrePersist + private void onInsert() { + this.created = Instant.now(); + } + + @Column(name = "updated") + private Instant updated; + + @PreUpdate + private void onUpdate() { + this.updated = Instant.now(); + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlace.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlace.java new file mode 100644 index 000000000..86328d78e --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlace.java @@ -0,0 +1,88 @@ +package dev.sheldan.abstracto.assignableroles.models.database; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name="assignable_role_place") +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class AssignableRolePlace { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + @JoinColumn(name="channel_id") + private AChannel channel; + + @OneToOne + @JoinColumn(name="server_id") + private AServer server; + + private String key; + + + @OneToMany( + fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + orphanRemoval = true, + mappedBy = "assignablePlace" + ) + @Builder.Default + @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private List messagePosts = new ArrayList<>(); + + @OneToMany( + fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + orphanRemoval = true, + mappedBy = "assignablePlace" + ) + @Builder.Default + @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private List assignableRoles = new ArrayList<>(); + + private String text; + + @Builder.Default + private Boolean active = true; + + @Builder.Default + private Boolean inline = false; + + @Builder.Default + private Boolean uniqueRoles = false; + + @Builder.Default + private Boolean autoRemove = false; + + @Column(name = "created") + private Instant created; + + @PrePersist + private void onInsert() { + this.created = Instant.now(); + } + + @Column(name = "updated") + private Instant updated; + + @PreUpdate + private void onUpdate() { + this.updated = Instant.now(); + } + +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlacePost.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlacePost.java new file mode 100644 index 000000000..f3a7a8d72 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignableRolePlacePost.java @@ -0,0 +1,51 @@ +package dev.sheldan.abstracto.assignableroles.models.database; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name="assignable_role_place_post") +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class AssignableRolePlacePost { + + @Id + private Long id; + + @ManyToOne + @JoinColumn(name = "channel_id") + private AChannel usedChannel; + + @Column(name = "created") + private Instant created; + + @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @Getter + @Setter + @JoinColumn(name = "assignable_place_id", nullable = false) + private AssignableRolePlace assignablePlace; + + @OneToMany( + fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + mappedBy = "assignableRolePlacePost") + @Builder.Default + @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + private List assignableRoles = new ArrayList<>(); + + @PrePersist + private void onInsert() { + this.created = Instant.now(); + } + +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignedRoleUser.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignedRoleUser.java new file mode 100644 index 000000000..e2c5dbfdf --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/database/AssignedRoleUser.java @@ -0,0 +1,46 @@ +package dev.sheldan.abstracto.assignableroles.models.database; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name="assigned_role_user") +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class AssignedRoleUser { + + @Id + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @PrimaryKeyJoinColumn + private AUserInAServer user; + + @ManyToMany + @JoinTable( + name = "assigned_role_in_user", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "assigned_role_id")) + @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) + @Builder.Default + private List roles = new ArrayList<>(); + + + @Column(name = "created") + private Instant created; + + @PrePersist + private void onInsert() { + this.created = Instant.now(); + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleAlreadyDefinedModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleAlreadyDefinedModel.java new file mode 100644 index 000000000..50916fdd9 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleAlreadyDefinedModel.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import dev.sheldan.abstracto.core.models.FullEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class AssignableRoleAlreadyDefinedModel implements Serializable { + private FullEmote emote; + private String placeName; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleNotUsableModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleNotUsableModel.java new file mode 100644 index 000000000..91781fd1c --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRoleNotUsableModel.java @@ -0,0 +1,17 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import dev.sheldan.abstracto.core.models.FullRole; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Guild; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class AssignableRoleNotUsableModel implements Serializable { + private FullRole role; + private Guild guild; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceAlreadyExistsModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceAlreadyExistsModel.java new file mode 100644 index 000000000..386d30be4 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceAlreadyExistsModel.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class AssignableRolePlaceAlreadyExistsModel { + private String name; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceChannelDoesNotExistModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceChannelDoesNotExistModel.java new file mode 100644 index 000000000..f969d7903 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceChannelDoesNotExistModel.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class AssignableRolePlaceChannelDoesNotExistModel implements Serializable { + private Long channelId; + private String placeName; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceExceptionModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceExceptionModel.java new file mode 100644 index 000000000..7bc69cc4b --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceExceptionModel.java @@ -0,0 +1,28 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.templating.Templatable; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class AssignableRolePlaceExceptionModel { + private AssignableRolePlace rolePlace; + private FullUser user; + private Throwable throwable; + + public Templatable getTemplate() { + Throwable current = throwable; + while(!(current instanceof Templatable) && !current.getCause().equals(current)) { + current = current.getCause(); + } + if(current instanceof Templatable) { + return (Templatable) current; + } + return null; + } +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceNotFoundModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceNotFoundModel.java new file mode 100644 index 000000000..5208e7d86 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlaceNotFoundModel.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class AssignableRolePlaceNotFoundModel { + private Long placeId; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlacePostNotFoundModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlacePostNotFoundModel.java new file mode 100644 index 000000000..882cee542 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignableRolePlacePostNotFoundModel.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class AssignableRolePlacePostNotFoundModel implements Serializable { + private Long messageId; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignedUserNotFoundModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignedUserNotFoundModel.java new file mode 100644 index 000000000..1328c5501 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/AssignedUserNotFoundModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class AssignedUserNotFoundModel { + private AUserInAServer aUserInAServer; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/EmoteNotInAssignableRolePlaceModel.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/EmoteNotInAssignableRolePlaceModel.java new file mode 100644 index 000000000..3e6eee50e --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/exception/EmoteNotInAssignableRolePlaceModel.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.assignableroles.models.exception; + +import dev.sheldan.abstracto.core.models.FullEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class EmoteNotInAssignableRolePlaceModel implements Serializable { + private FullEmote emote; + private String placeName; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePlaceOverview.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePlaceOverview.java new file mode 100644 index 000000000..07014c859 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePlaceOverview.java @@ -0,0 +1,17 @@ +package dev.sheldan.abstracto.assignableroles.models.templates; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@Builder +public class AssignablePlaceOverview { + @Builder.Default + private List places = new ArrayList<>(); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostConfigRole.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostConfigRole.java new file mode 100644 index 000000000..4b90c7e8b --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostConfigRole.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.assignableroles.models.templates; + + +import dev.sheldan.abstracto.core.models.database.ARole; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Role; + +@Getter +@Setter +@Builder +public class AssignablePostConfigRole { + private Emote emote; + private String description; + private Integer position; + private Boolean inline; + private ARole role; + private Role awardedRole; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostMessage.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostMessage.java new file mode 100644 index 000000000..2b4d6ed76 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostMessage.java @@ -0,0 +1,17 @@ +package dev.sheldan.abstracto.assignableroles.models.templates; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class AssignablePostMessage { + private AssignableRolePlace place; + private List roles; + private Integer maxPosition; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostRole.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostRole.java new file mode 100644 index 000000000..19623e9e9 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignablePostRole.java @@ -0,0 +1,19 @@ +package dev.sheldan.abstracto.assignableroles.models.templates; + + +import dev.sheldan.abstracto.core.models.FullEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class AssignablePostRole { + private FullEmote emote; + private String description; + private Integer position; + @Builder.Default + private Boolean forceNewMessage = false; + private Boolean inline; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignableRolePlaceConfig.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignableRolePlaceConfig.java new file mode 100644 index 000000000..6da25d256 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/models/templates/AssignableRolePlaceConfig.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.assignableroles.models.templates; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class AssignableRolePlaceConfig { + private AssignableRolePlace place; + private List roles; +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceService.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceService.java new file mode 100644 index 000000000..dcedcfbf3 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceService.java @@ -0,0 +1,66 @@ +package dev.sheldan.abstracto.assignableroles.service; + +import dev.sheldan.abstracto.assignableroles.config.AssignableRolePlaceParameterKey; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.models.database.ARole; +import dev.sheldan.abstracto.core.models.database.AServer; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.TextChannel; + +import java.util.concurrent.CompletableFuture; + +public interface AssignableRolePlaceService { + void createAssignableRolePlace(AServer server, String name, AChannel channel, String text); + boolean hasAssignableRolePlaceEmote(AServer server, String placeName, AEmote emote); + boolean hasAssignableRolePlaceEmote(AssignableRolePlace place, AEmote emote); + boolean isPositionUsed(AServer server, String placeName, Integer position); + CompletableFuture setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position); + CompletableFuture addRoleToAssignableRolePlace(AServer server, String placeName, ARole role, FullEmote emote, String description); + CompletableFuture removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote); + CompletableFuture setupAssignableRolePlace(AServer server, String name); + CompletableFuture refreshAssignablePlacePosts(AServer server, String name); + CompletableFuture refreshAssignablePlacePosts(AssignableRolePlace place); + CompletableFuture refreshTextFromPlace(AssignableRolePlace place); + void setAssignablePlaceActiveTo(AServer server, String name, Boolean newValue); + void activateAssignableRolePlace(AServer server, String name); + void activateAssignableRolePlace(AssignableRolePlace place); + void deactivateAssignableRolePlace(AServer server, String name); + void deactivateAssignableRolePlace(AssignableRolePlace place); + + // inline attribute + CompletableFuture setAssignablePlaceInlineTo(AServer server, String name, Boolean newValue); + CompletableFuture inlineAssignableRolePlace(AServer server, String name); + CompletableFuture inlineAssignableRolePlace(AssignableRolePlace place); + CompletableFuture spreadAssignableRolePlace(AServer server, String name); + CompletableFuture spreadAssignableRolePlace(AssignableRolePlace place); + + // unique attribute + void setAssignablePlaceUniqueTo(AServer server, String name, Boolean newValue); + void uniqueAssignableRolePlace(AServer server, String name); + void uniqueAssignableRolePlace(AssignableRolePlace place); + void multipleAssignableRolePlace(AServer server, String name); + void multipleAssignableRolePlace(AssignableRolePlace place); + + // auto remove attribute + void setAssignablePlaceAutoRemoveTo(AServer server, String name, Boolean newValue); + void autoRemoveAssignableRolePlace(AServer server, String name); + void autoRemoveAssignableRolePlace(AssignableRolePlace place); + void keepReactionsAssignableRolePlace(AServer server, String name); + void keepReactionsAssignableRolePlace(AssignableRolePlace place); + + void swapPositions(AServer server, String name, FullEmote firstEmote, FullEmote secondEmote); + CompletableFuture testAssignableRolePlace(AServer server, String name, MessageChannel channel); + void showAssignablePlaceConfig(AServer server, String name, MessageChannel channel); + void moveAssignableRolePlace(AServer server, String name, TextChannel newChannel); + void changeAssignablePlaceDescription(AServer server, String name, String newDescription); + CompletableFuture deleteAssignableRolePlace(AServer server, String name); + CompletableFuture changeText(AServer server, String name, String newText); + CompletableFuture removeExistingReactionsAndRoles(AssignableRolePlace place, AssignedRoleUser user); + CompletableFuture changeConfiguration(AServer server, String name, AssignableRolePlaceParameterKey keyToChange, Object newValue); + + CompletableFuture showAllAssignableRolePlaces(AServer server, MessageChannel channel); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleService.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleService.java new file mode 100644 index 000000000..f3998961e --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRoleService.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.assignableroles.service; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import net.dv8tion.jda.api.entities.Member; + +import java.util.concurrent.CompletableFuture; + +public interface AssignableRoleService { + CompletableFuture assignAssignableRoleToUser(Long assignableRoleId, Member toAdd); + CompletableFuture removeAssignableRoleFromUser(AssignableRole assignableRole, Member member); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementService.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementService.java new file mode 100644 index 000000000..93c11cef0 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRoleManagementService.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.models.database.ARole; + +public interface AssignableRoleManagementService { + AssignableRole addRoleToPlace(AssignableRolePlace place, AEmote emote, ARole role, String description, AssignableRolePlacePost post); + AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description, Long messageId); + AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description); + AssignableRole getByAssignableRoleId(Long assignableRoleId); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementService.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementService.java new file mode 100644 index 000000000..46571487e --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlaceManagementService.java @@ -0,0 +1,20 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; + +import java.util.List; +import java.util.Optional; + +public interface AssignableRolePlaceManagementService { + AssignableRolePlace createPlace(AServer server, String name, AChannel channel, String text); + boolean doesPlaceExist(AServer server, String name); + AssignableRolePlace findByServerAndKey(AServer server, String name); + Optional findByPlaceId(Long id); + void moveAssignableRolePlace(AServer server, String name, AChannel newChannel); + void changeAssignableRolePlaceDescription(AServer server, String name, String newDescription); + void deleteAssignablePlace(AssignableRolePlace place); + List findAllByServer(AServer server); + +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementService.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementService.java new file mode 100644 index 000000000..713bea70c --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignableRolePlacePostManagementService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; + +import java.util.Optional; + +public interface AssignableRolePlacePostManagementService { + Optional findByMessageIdOptional(Long messageId); + AssignableRolePlacePost findByMessageId(Long messageId); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementService.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementService.java new file mode 100644 index 000000000..1711cb881 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/src/main/java/dev/sheldan/abstracto/assignableroles/service/management/AssignedRoleUserManagementService.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.assignableroles.service.management; + +import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; +import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; + +import java.util.Optional; + +public interface AssignedRoleUserManagementService { + void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer); + void removeAssignedRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer); + AssignedRoleUser createAssignedRoleUser(AUserInAServer aUserInAServer); + boolean doesAssignedRoleUserExist(AUserInAServer aUserInAServer); + Optional findByUserInServerOptional(AUserInAServer aUserInAServer); + AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer); +} diff --git a/abstracto-application/abstracto-modules/assignable-roles/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/pom.xml new file mode 100644 index 000000000..d12547d16 --- /dev/null +++ b/abstracto-application/abstracto-modules/assignable-roles/pom.xml @@ -0,0 +1,29 @@ + + + + dev.sheldan.abstracto + abstracto-modules + 1.0-SNAPSHOT + + 4.0.0 + + dev.sheldan.abstracto.modules + assignable-roles + pom + + + assignable-roles-int + assignable-roles-impl + + + + + dev.sheldan.abstracto.core + core-interface + ${project.version} + compile + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/condition/HasLevelCondition.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/condition/HasLevelCondition.java new file mode 100644 index 000000000..b0991733b --- /dev/null +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/condition/HasLevelCondition.java @@ -0,0 +1,56 @@ +package dev.sheldan.abstracto.experience.service.condition; + +import dev.sheldan.abstracto.core.models.ConditionContext; +import dev.sheldan.abstracto.core.models.ConditionContextInstance; +import dev.sheldan.abstracto.core.models.ConditionContextVariable; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.SystemCondition; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.experience.models.database.AUserExperience; +import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Optional; + +@Component +public class HasLevelCondition implements SystemCondition { + + public static final String USER_ID_VARIABLE = "userId"; + public static final String LEVEL_VARIABLE = "level"; + @Autowired + private UserExperienceManagementService userExperienceManagementService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Override + public boolean checkCondition(ConditionContextInstance conditionContext) { + HashMap parameters = conditionContext.getParameters(); + + Long userId = (Long) parameters.get(USER_ID_VARIABLE); + Integer level = (Integer) parameters.get(LEVEL_VARIABLE); + Optional userInServerOptional = userInServerManagementService.loadUser(userId); + if(userInServerOptional.isPresent()) { + AUserInAServer userInServer = userInServerOptional.get(); + AUserExperience user = userExperienceManagementService.findUserInServer(userInServer); + return user.getCurrentLevel() != null && user.getCurrentLevel().getLevel() >= level; + } + + return false; + } + + @Override + public String getConditionName() { + return "HAS_LEVEL"; + } + + @Override + public ConditionContext getExpectedContext() { + ConditionContextVariable userIdVariable = ConditionContextVariable.builder().name(USER_ID_VARIABLE).type(Long.class).build(); + ConditionContextVariable levelVariable = ConditionContextVariable.builder().name(LEVEL_VARIABLE).type(Integer.class).build(); + return ConditionContext.builder().expectedVariables(Arrays.asList(userIdVariable, levelVariable)).build(); + } +} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/BanServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/BanServiceBean.java index 4b41b8cfd..618c7afec 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/BanServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/BanServiceBean.java @@ -1,6 +1,6 @@ package dev.sheldan.abstracto.moderation.service; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.context.ServerContext; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.PostTargetService; @@ -52,7 +52,7 @@ public class BanServiceBean implements BanService { banUser(guildByIdOptional.get(), userId, reason); } else { log.warn("Guild {} not found. Not able to ban user {}", guildId, userId); - throw new GuildException(guildId); + throw new GuildNotFoundException(guildId); } } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java index 7d31085ad..66057f045 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.moderation.service; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.AServerAChannelMessage; import dev.sheldan.abstracto.core.models.FullUser; import dev.sheldan.abstracto.core.models.database.AChannel; @@ -157,8 +156,7 @@ public class MuteServiceBean implements MuteService { AServerAChannelMessage origin = null; if(message != null) { long channelId = message.getChannel().getIdLong(); - Optional channelOpt = channelManagementService.loadChannel(channelId); - AChannel channel = channelOpt.orElseThrow(() -> new ChannelNotFoundException(channelId, userInServerBeingMuted.getServerReference().getId())); + AChannel channel = channelManagementService.loadChannel(channelId); origin = AServerAChannelMessage .builder() .channel(channel) diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java index 279ff948d..7ddfdba0b 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java @@ -35,12 +35,12 @@ public class SlowModeServiceBean implements SlowModeService { @Override public void setSlowMode(AChannel channel, Duration duration) { - Optional textChannelOptional = botService.getTextChannelFromServer(channel.getServer().getId(), channel.getId()); + Optional textChannelOptional = botService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); if(textChannelOptional.isPresent()) { TextChannel textChannel = textChannelOptional.get(); this.setSlowMode(textChannel, duration); } else { - throw new ChannelNotFoundException(channel.getId(), channel.getServer().getId()); + throw new ChannelNotFoundException(channel.getId()); } } } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/BanServiceBeanTest.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/BanServiceBeanTest.java index b4966afe3..3da0139dc 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/BanServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/BanServiceBeanTest.java @@ -1,6 +1,6 @@ package dev.sheldan.abstracto.moderation.service; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.context.ServerContext; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.PostTargetService; @@ -73,7 +73,7 @@ public class BanServiceBeanTest { verify(postTargetService, times(1)).sendEmbedInPostTarget(mockedMessage, ModerationPostTarget.BAN_LOG, serverId); } - @Test(expected = GuildException.class) + @Test(expected = GuildNotFoundException.class) public void tryToBanInNonExistentGuild() { Long userId = 8L; Long serverId = 5L; diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/MuteServiceBeanTest.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/MuteServiceBeanTest.java index f8a1380a9..229c3e6e8 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/MuteServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/MuteServiceBeanTest.java @@ -347,7 +347,7 @@ public class MuteServiceBeanTest { when(cause.getChannel()).thenReturn(channel); when(muteRoleManagementService.muteRoleForServerExists(server)).thenReturn(true); when(muteRoleManagementService.retrieveMuteRoleForServer(server)).thenReturn(muteRole); - when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(Optional.of(aChannel)); + when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(aChannel); Mute createdMute = Mute.builder().id(muteId).build(); when(muteManagementService.createMute(eq(userBeingMuted), eq(userMuting), eq(REASON), eq(unMuteDate), any(AServerAChannelMessage.class))).thenReturn(createdMute); when(templateService.renderTemplate(eq(MuteServiceBean.MUTE_NOTIFICATION_TEMPLATE), any(MuteNotification.class))).thenReturn(NOTIFICATION_TEXT); diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java index 829b9eaf0..af667e2e2 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java @@ -58,7 +58,7 @@ public class SlowModeServiceBeanTest { when(channelManager.setSlowmode(anyInt())).thenReturn(returnedManager); when(channel.getGuild()).thenReturn(guild); when(channel.getManager()).thenReturn(channelManager); - when(botService.getTextChannelFromServer(server.getId(), aChannel.getId())).thenReturn(Optional.of(channel)); + when(botService.getTextChannelFromServerOptional(server.getId(), aChannel.getId())).thenReturn(Optional.of(channel)); testUnit.setSlowMode(aChannel, duration); verify(channelManager, times(1)).setSlowmode((int)duration.getSeconds()); } @@ -84,7 +84,7 @@ public class SlowModeServiceBeanTest { AServer server = MockUtils.getServer(); AChannel aChannel = MockUtils.getTextChannel(server, 5L); Duration duration = Duration.ofMinutes(5); - when(botService.getTextChannelFromServer(server.getId(), aChannel.getId())).thenReturn(Optional.empty()); + when(botService.getTextChannelFromServerOptional(server.getId(), aChannel.getId())).thenReturn(Optional.empty()); testUnit.setSlowMode(aChannel, duration); } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java index 2e54795ad..8cd5f3859 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java @@ -49,7 +49,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService { // the opening of a private channel is a rest operation it itself, so we need // to create the promises here already, else the list is empty for example modMailMessages.forEach(modMailMessage -> messageFutures.add(new CompletableFuture<>())); - Optional textChannelFromServer = botService.getTextChannelFromServer(thread.getServer().getId(), thread.getChannel().getId()); + Optional textChannelFromServer = botService.getTextChannelFromServerOptional(thread.getServer().getId(), thread.getChannel().getId()); if(textChannelFromServer.isPresent()) { TextChannel modMailThread = textChannelFromServer.get(); botService.getInstance().openPrivateChannelById(thread.getUser().getUserReference().getId()).queue(privateChannel -> { diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java index 4ab9a9182..78f6d331d 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java @@ -313,7 +313,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Override public void relayMessageToModMailThread(ModMailThread modMailThread, Message message) { - Optional textChannelFromServer = botService.getTextChannelFromServer(modMailThread.getServer().getId(), modMailThread.getChannel().getId()); + Optional textChannelFromServer = botService.getTextChannelFromServerOptional(modMailThread.getServer().getId(), modMailThread.getChannel().getId()); if(textChannelFromServer.isPresent()) { TextChannel textChannel = textChannelFromServer.get(); self.sendUserReply(textChannel, modMailThread, message); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java index 22ac5856e..4e437040c 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.modmail.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; @@ -26,8 +25,7 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme @Override public ModMailThread getByChannelId(Long channelId) { - Optional channelOpt = channelManagementService.loadChannel(channelId); - AChannel channel = channelOpt.orElseThrow(() -> new ChannelNotFoundException(channelId, 0L)); + AChannel channel = channelManagementService.loadChannel(channelId); return getByChannel(channel); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java index 9114ef39a..a96ba8f5a 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.modmail.setup; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.interactive.*; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.FeatureValidationResult; @@ -25,7 +24,6 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -86,59 +84,54 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { model.setCategory(category); } String messageText = templateService.renderTemplate(messageTemplateKey, model); - Optional channel = channelManagementService.loadChannel(user.getChannelId()); + AChannel channel = channelManagementService.loadChannel(user.getChannelId()); CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId()); - // very odd case, if the channel the command was executed in, was not found in the database. - if(channel.isPresent()) { - Runnable finalAction = getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - Consumer configAction = (MessageReceivedEvent event) -> { - try { + Runnable finalAction = getTimeoutRunnable(user.getGuildId(), user.getChannelId()); + Consumer configAction = (MessageReceivedEvent event) -> { + try { - SetupStepResult result; - Message message = event.getMessage(); - // this checks whether or not the user wanted to cancel the setup - if(checkForExit(message)) { - result = SetupStepResult.fromCancelled(); + SetupStepResult result; + Message message = event.getMessage(); + // this checks whether or not the user wanted to cancel the setup + if(checkForExit(message)) { + result = SetupStepResult.fromCancelled(); + } else { + String messageContent = event.getMessage().getContentRaw(); + // directly parse the long from the message, for *now*, only the category ID is supported + Long categoryId = Long.parseLong(messageContent); + Guild guild = botService.getGuildByIdNullable(user.getGuildId()); + FeatureValidationResult featureValidationResult = FeatureValidationResult.builder().validationResult(true).build(); + // directly validate whether or not the given category ID is a valid value + modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId); + if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) { + ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig + .builder() + .serverId(user.getGuildId()) + .category(guild.getCategoryById(categoryId)) + .categoryId(categoryId) + .build(); + List delayedSteps = Arrays.asList(build); + result = SetupStepResult + .builder() + .result(SetupStepResultType.SUCCESS) + .delayedActionConfigList(delayedSteps) + .build(); } else { - String messageContent = event.getMessage().getContentRaw(); - // directly parse the long from the message, for *now*, only the category ID is supported - Long categoryId = Long.parseLong(messageContent); - Guild guild = botService.getGuildByIdNullable(user.getGuildId()); - FeatureValidationResult featureValidationResult = FeatureValidationResult.builder().validationResult(true).build(); - // directly validate whether or not the given category ID is a valid value - modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId); - if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) { - ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig - .builder() - .serverId(user.getGuildId()) - .category(guild.getCategoryById(categoryId)) - .categoryId(categoryId) - .build(); - List delayedSteps = Arrays.asList(build); - result = SetupStepResult - .builder() - .result(SetupStepResultType.SUCCESS) - .delayedActionConfigList(delayedSteps) - .build(); - } else { - // exceptions this exception is used to effectively fail the setup step - throw new InvalidCategoryException(); - } - + // exceptions this exception is used to effectively fail the setup step + throw new InvalidCategoryException(); } - future.complete(result); - } catch (Exception e) { - log.error("Failed to handle mod mail category step.", e); - future.completeExceptionally(new SetupStepException(e)); } - }; - interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel.get(), parameter.getPreviousMessageId(), configAction, finalAction); - } else { - future.completeExceptionally(new ChannelNotFoundException(user.getGuildId(), user.getChannelId())); - } + + future.complete(result); + } catch (Exception e) { + log.error("Failed to handle mod mail category step.", e); + future.completeExceptionally(new SetupStepException(e)); + } + }; + interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, parameter.getPreviousMessageId(), configAction, finalAction); return future; } diff --git a/abstracto-application/abstracto-modules/pom.xml b/abstracto-application/abstracto-modules/pom.xml index 94bb2bd2f..8248c8de7 100644 --- a/abstracto-application/abstracto-modules/pom.xml +++ b/abstracto-application/abstracto-modules/pom.xml @@ -16,6 +16,7 @@ utility experience-tracking modmail + assignable-roles diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListener.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListener.java index 7f2a753f0..8e6fc935b 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListener.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListener.java @@ -15,6 +15,7 @@ import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManageme import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Emote; import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -40,13 +41,13 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener @Override - public void executeReactionAdded(CachedMessage message, MessageReaction reaction, AUserInAServer userAdding) { + public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent event, AUserInAServer userAdding) { Long guildId = message.getServerId(); - AEmote aEmote = emoteService.getEmoteOrFakeEmote(REMOVAL_EMOTE, guildId); - MessageReaction.ReactionEmote reactionEmote = reaction.getReactionEmote(); + AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId); + MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); Optional emoteInGuild = botService.getEmote(guildId, aEmote); log.trace("Removing embed in message {} in channel {} in server {} because of a user reaction.", message.getMessageId(), message.getChannelId(), message.getServerId()); - if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote, emoteInGuild.orElse(null))) { + if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { Optional embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId()); if(embeddedMessageOptional.isPresent()) { EmbeddedMessage embeddedMessage = embeddedMessageOptional.get(); diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListener.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListener.java index afe21d3c4..91832e459 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListener.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListener.java @@ -18,8 +18,9 @@ import dev.sheldan.abstracto.utility.service.StarboardService; import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Emote; import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -59,15 +60,14 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi @Override @Transactional - public void executeReactionAdded(CachedMessage message, MessageReaction addedReaction, AUserInAServer userAdding) { + public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent addedReaction, AUserInAServer userAdding) { if(userAdding.getUserReference().getId().equals(message.getAuthorId())) { return; } Long guildId = message.getServerId(); - AEmote aEmote = emoteService.getEmoteOrFakeEmote(STAR_EMOTE, guildId); + AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId); MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote(); - Optional emoteInGuild = botService.getEmote(guildId, aEmote); - if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote, emoteInGuild.orElse(null))) { + if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { log.trace("User {} in server {} reacted with star to put a message {} on starboard.", userAdding.getUserReference().getId(), userAdding.getServerReference().getId(), message.getMessageId()); Optional reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote); handleStarboardPostChange(message, reactionOptional.orElse(null), userAdding, true); @@ -122,15 +122,14 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi @Override @Transactional - public void executeReactionRemoved(CachedMessage message, MessageReaction removedReaction, AUserInAServer userRemoving) { + public void executeReactionRemoved(CachedMessage message, GuildMessageReactionRemoveEvent removedReaction, AUserInAServer userRemoving) { if(message.getAuthorId().equals(userRemoving.getUserReference().getId())) { return; } Long guildId = message.getServerId(); - AEmote aEmote = emoteService.getEmoteOrFakeEmote(STAR_EMOTE, guildId); + AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId); MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote(); - Optional emoteInGuild = botService.getEmote(guildId, aEmote); - if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote, emoteInGuild.orElse(null))) { + if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { log.trace("User {} in server {} removed star reaction from message {} on starboard.", userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), message.getMessageId()); Optional reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote); diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBean.java index 5fc1e920c..59520c982 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.template.listener.MessageEmbeddedModel; import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.core.models.cache.CachedMessage; @@ -144,13 +143,12 @@ public class MessageEmbedServiceBean implements MessageEmbedService { } private MessageEmbeddedModel buildTemplateParameter(Message message, CachedMessage embeddedMessage) { - Optional channelOpt = channelManagementService.loadChannel(message.getChannel().getIdLong()); AServer server = serverManagementService.loadOrCreate(message.getGuild().getIdLong()); AUserInAServer user = userInServerManagementService.loadUser(message.getMember()); Member author = botService.getMemberInServer(embeddedMessage.getServerId(), embeddedMessage.getAuthorId()); - Optional textChannelFromServer = botService.getTextChannelFromServer(embeddedMessage.getServerId(), embeddedMessage.getChannelId()); + Optional textChannelFromServer = botService.getTextChannelFromServerOptional(embeddedMessage.getServerId(), embeddedMessage.getChannelId()); TextChannel sourceChannel = textChannelFromServer.orElse(null); - AChannel channel = channelOpt.orElseThrow(() -> new ChannelNotFoundException(message.getChannel().getIdLong(), server.getId())); + AChannel channel = channelManagementService.loadChannel(message.getChannel().getIdLong()); return MessageEmbeddedModel .builder() .channel(channel) diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/RemindServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/RemindServiceBean.java index ce957d4ac..3f49cab69 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/RemindServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/RemindServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.models.AServerAChannelAUser; @@ -64,7 +63,7 @@ public class RemindServiceBean implements ReminderService { @Override public Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Message message) { - AChannel channel = channelManagementService.loadChannel(message.getChannel().getIdLong()).orElseThrow(() -> new ChannelNotFoundException(message.getChannel().getIdLong(), message.getGuild().getIdLong())); + AChannel channel = channelManagementService.loadChannel(message.getChannel().getIdLong()); AServerAChannelAUser aServerAChannelAUser = AServerAChannelAUser .builder() .user(user.getUserReference()) @@ -109,7 +108,7 @@ public class RemindServiceBean implements ReminderService { log.info("Executing reminder {}.", reminderId); Optional guildToAnswerIn = botService.getGuildById(server.getId()); if(guildToAnswerIn.isPresent()) { - Optional channelToAnswerIn = botService.getTextChannelFromServer(server.getId(), channel.getId()); + Optional channelToAnswerIn = botService.getTextChannelFromServerOptional(server.getId(), channel.getId()); // only send the message if the channel still exists, if not, only set the reminder to reminded. if(channelToAnswerIn.isPresent()) { AUser userReference = reminderToRemindFor.getRemindedUser().getUserReference(); diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/StarboardServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/StarboardServiceBean.java index 2fafb8945..a9005acb4 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/StarboardServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/StarboardServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService; @@ -105,7 +104,7 @@ public class StarboardServiceBean implements StarboardService { public void persistPost(CachedMessage message, List userExceptAuthorIds, List> completableFutures, Long starboardChannelId, Long starredUserId, Long userReactingId) { AUserInAServer innerStarredUser = userInServerManagementService.loadUser(starredUserId).orElseThrow(() -> new UserInServerNotFoundException(starredUserId)); try { - AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId).orElseThrow(() -> new ChannelNotFoundException(starboardChannelId, message.getServerId())); + AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId); Message message1 = completableFutures.get(0).get(); AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage .builder() @@ -129,7 +128,7 @@ public class StarboardServiceBean implements StarboardService { private StarboardPostModel buildStarboardPostModel(CachedMessage message, Integer starCount) { Member member = botService.getMemberInServer(message.getServerId(), message.getAuthorId()); - Optional channel = botService.getTextChannelFromServer(message.getServerId(), message.getChannelId()); + Optional channel = botService.getTextChannelFromServerOptional(message.getServerId(), message.getChannelId()); Optional guild = botService.getGuildById(message.getServerId()); AChannel aChannel = AChannel.builder().id(message.getChannelId()).build(); AUser user = AUser.builder().id(message.getAuthorId()).build(); diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBean.java index 5602978eb..a43ced42a 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AServer; @@ -43,8 +42,8 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa if(!embeddedServer.getId().equals(embeddingServer.getId())) { throw new CrossServerEmbedException(String.format("Message %s is not from server %s", embeddedMessage.getMessageUrl(), embeddingServer.getId())); } - AChannel embeddingChannel = channelManagementService.loadChannel(messageContainingEmbed.getChannel().getIdLong()).orElseThrow(() -> new ChannelNotFoundException(messageContainingEmbed.getChannel().getIdLong(), messageContainingEmbed.getGuild().getIdLong())); - AChannel embeddedChannel = channelManagementService.loadChannel(embeddedMessage.getChannelId()).orElseThrow(() -> new ChannelNotFoundException(embeddedMessage.getChannelId(), embeddedMessage.getServerId())); + AChannel embeddingChannel = channelManagementService.loadChannel(messageContainingEmbed.getChannel().getIdLong()); + AChannel embeddedChannel = channelManagementService.loadChannel(embeddedMessage.getChannelId()); AUserInAServer embeddedAuthor = userInServerManagementService.loadUser(embeddedMessage.getServerId(), embeddedMessage.getAuthorId()); EmbeddedMessage messageEmbedPost = EmbeddedMessage .builder() diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java index 9109353b2..2e4857d43 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.AServerAChannelMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AChannel; @@ -28,7 +27,7 @@ public class StarboardPostManagementServiceBean implements StarboardPostManageme @Override public StarboardPost createStarboardPost(CachedMessage starredMessage, AUserInAServer starredUser, AServerAChannelMessage starboardPost) { - AChannel build = channelManagementService.loadChannel(starredMessage.getChannelId()).orElseThrow(() -> new ChannelNotFoundException(starredMessage.getChannelId(), starredMessage.getServerId())); + AChannel build = channelManagementService.loadChannel(starredMessage.getChannelId()); StarboardPost post = StarboardPost .builder() .author(starredUser) diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java index bec4992f4..e144728e5 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; @@ -60,12 +59,8 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ @Override public void setPostedMessage(Suggestion suggestion, Message message) { long channelId = message.getChannel().getIdLong(); - Optional channelOptional = channelManagementService.loadChannel(channelId); - if(channelOptional.isPresent()) { - suggestion.setChannel(channelOptional.get()); - } else { - throw new ChannelNotFoundException(channelId, suggestion.getServer().getId()); - } + AChannel channel = channelManagementService.loadChannel(channelId); + suggestion.setChannel(channel); suggestion.setMessageId(message.getIdLong()); suggestionRepository.save(suggestion); } diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListenerTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListenerTest.java index ecc6ef12e..793ff0589 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListenerTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/embed/MessageEmbedRemovalReactionListenerTest.java @@ -12,6 +12,7 @@ import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage; import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService; import net.dv8tion.jda.api.entities.Emote; import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -42,7 +43,7 @@ public class MessageEmbedRemovalReactionListenerTest { private EmoteService emoteService; @Mock - private MessageReaction messageReaction; + private GuildMessageReactionAddEvent messageReaction; @Mock private MessageReaction.ReactionEmote reactionEmote; @@ -100,10 +101,10 @@ public class MessageEmbedRemovalReactionListenerTest { .channelId(channelId) .build(); AEmote reactedEmote = AEmote.builder().build(); - when(emoteService.getEmoteOrFakeEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); + when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); when(botService.getEmote(serverId, reactedEmote)).thenReturn(Optional.of(emote)); - when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote, emote)).thenReturn(true); + when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(true); EmbeddedMessage message = EmbeddedMessage .builder() .embeddingUser(embeddingUser) @@ -131,10 +132,10 @@ public class MessageEmbedRemovalReactionListenerTest { .build(); AUserInAServer userInAServer = MockUtils.getUserObject(5L, server); AEmote reactedEmote = AEmote.builder().build(); - when(emoteService.getEmoteOrFakeEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); + when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); when(botService.getEmote(serverId, reactedEmote)).thenReturn(Optional.of(emote)); - when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote, emote)).thenReturn(wasCorrectEmote); + when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(wasCorrectEmote); testUnit.executeReactionAdded(cachedMessage, messageReaction, userInAServer); verify(messageService, times(0)).deleteMessageInChannelInServer(serverId, channelId, messageId); } diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListenerTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListenerTest.java index 102e02102..470394f80 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListenerTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/listener/starboard/StarboardListenerTest.java @@ -16,6 +16,8 @@ import dev.sheldan.abstracto.utility.service.StarboardService; import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService; import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -57,7 +59,10 @@ public class StarboardListenerTest { private EmoteService emoteService; @Mock - private MessageReaction messageReaction; + private GuildMessageReactionAddEvent addEvent; + + @Mock + private GuildMessageReactionRemoveEvent removeEvent; @Mock private MessageReaction.ReactionEmote reactionEmote; @@ -72,8 +77,8 @@ public class StarboardListenerTest { .serverId(serverId) .build(); AUserInAServer userAdding = MockUtils.getUserObject(authorId, MockUtils.getServer(serverId)); - testUnit.executeReactionAdded(cachedMessage, messageReaction, userAdding); - verify(emoteService, times(0)).getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId); + testUnit.executeReactionAdded(cachedMessage, addEvent, userAdding); + verify(emoteService, times(0)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); } @Test @@ -84,8 +89,8 @@ public class StarboardListenerTest { AEmote starEmote = AEmote.builder().build(); AUserInAServer userAdding = MockUtils.getUserObject(reactionUserId, MockUtils.getServer(serverId)); CachedMessage cachedMessage = setupWrongEmote(serverId, authorId, starEmote); - testUnit.executeReactionAdded(cachedMessage, messageReaction, userAdding); - verify(emoteService, times(1)).getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId); + testUnit.executeReactionAdded(cachedMessage, addEvent, userAdding); + verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); verify(emoteService, times(0)).getReactionFromMessageByEmote(any(CachedMessage.class), eq(starEmote)); } @@ -144,8 +149,8 @@ public class StarboardListenerTest { .serverId(serverId) .build(); AUserInAServer userAdding = MockUtils.getUserObject(authorId, MockUtils.getServer(serverId)); - testUnit.executeReactionRemoved(cachedMessage, messageReaction, userAdding); - verify(emoteService, times(0)).getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId); + testUnit.executeReactionRemoved(cachedMessage, removeEvent, userAdding); + verify(emoteService, times(0)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); } @Test @@ -156,8 +161,8 @@ public class StarboardListenerTest { AEmote starEmote = AEmote.builder().build(); AUserInAServer userAdding = MockUtils.getUserObject(reactionUserId, MockUtils.getServer(serverId)); CachedMessage cachedMessage = setupWrongEmote(serverId, authorId, starEmote); - testUnit.executeReactionRemoved(cachedMessage, messageReaction, userAdding); - verify(emoteService, times(1)).getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId); + testUnit.executeReactionRemoved(cachedMessage, removeEvent, userAdding); + verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); verify(emoteService, times(0)).getReactionFromMessageByEmote(any(CachedMessage.class), eq(starEmote)); } @@ -235,19 +240,18 @@ public class StarboardListenerTest { .serverId(serverId) .messageId(messageId) .build(); - when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); + when(removeEvent.getReactionEmote()).thenReturn(reactionEmote); AEmote starEmote = AEmote.builder().build(); - when(emoteService.getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); - when(botService.getEmote(serverId, starEmote)).thenReturn(Optional.empty()); - when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote, null)).thenReturn(true); + when(emoteService.getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); + when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote)).thenReturn(true); CachedReaction reaction = CachedReaction.builder().userInServersIds(remainingUsers).build(); when(emoteService.getReactionFromMessageByEmote(cachedMessage, starEmote)).thenReturn(Optional.of(reaction)); when(starboardPostManagementService.findByMessageId(messageId)).thenReturn(Optional.ofNullable(post)); when(userInServerManagementService.loadUser(serverId, author.getUserReference().getId())).thenReturn(author); when(userInServerManagementService.loadUser(remainingUser.getUserReference().getId())).thenReturn(Optional.of(remainingUser)); when(configManagementService.loadConfig(serverId, StarboardListener.FIRST_LEVEL_THRESHOLD_KEY)).thenReturn(AConfig.builder().longValue(requiredStars).build()); - testUnit.executeReactionRemoved(cachedMessage, messageReaction, userRemoving); - verify(emoteService, times(1)).getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId); + testUnit.executeReactionRemoved(cachedMessage, removeEvent, userRemoving); + verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); verify(emoteService, times(1)).getReactionFromMessageByEmote(cachedMessage, starEmote); } @@ -260,19 +264,18 @@ public class StarboardListenerTest { .serverId(serverId) .messageId(messageId) .build(); - when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); + when(addEvent.getReactionEmote()).thenReturn(reactionEmote); AEmote starEmote = AEmote.builder().build(); - when(emoteService.getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); - when(botService.getEmote(serverId, starEmote)).thenReturn(Optional.empty()); - when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote, null)).thenReturn(true); + when(emoteService.getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); + when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote)).thenReturn(true); CachedReaction reaction = CachedReaction.builder().userInServersIds(Arrays.asList(userAdding.getUserReference().getId())).build(); when(emoteService.getReactionFromMessageByEmote(cachedMessage, starEmote)).thenReturn(Optional.of(reaction)); when(starboardPostManagementService.findByMessageId(messageId)).thenReturn(Optional.ofNullable(existingPost)); when(userInServerManagementService.loadUser(serverId, author.getUserReference().getId())).thenReturn(author); when(userInServerManagementService.loadUser(userAdding.getUserReference().getId())).thenReturn(Optional.of(userAdding)); when(configManagementService.loadConfig(serverId, StarboardListener.FIRST_LEVEL_THRESHOLD_KEY)).thenReturn(AConfig.builder().longValue(requiredStars).build()); - testUnit.executeReactionAdded(cachedMessage, messageReaction, userAdding); - verify(emoteService, times(1)).getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId); + testUnit.executeReactionAdded(cachedMessage, addEvent, userAdding); + verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); verify(emoteService, times(1)).getReactionFromMessageByEmote(cachedMessage, starEmote); } @@ -282,10 +285,9 @@ public class StarboardListenerTest { .authorId(authorId) .serverId(serverId) .build(); - when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); - when(emoteService.getEmoteOrFakeEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); - when(botService.getEmote(serverId, starEmote)).thenReturn(Optional.empty()); - when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote, null)).thenReturn(false); + when(addEvent.getReactionEmote()).thenReturn(reactionEmote); + when(emoteService.getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); + when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote)).thenReturn(false); return cachedMessage; } } diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBeanTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBeanTest.java index 6fde7f018..9016a684c 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/MessageEmbedServiceBeanTest.java @@ -203,10 +203,10 @@ public class MessageEmbedServiceBeanTest { when(embeddingMessage.getChannel()).thenReturn(textChannel); when(userInServerManagementService.loadUser(embeddingMember)).thenReturn(embeddingUser); when(userInServerManagementService.loadUser(userEmbeddingUserInServerId)).thenReturn(Optional.of(embeddingUser)); - when(channelManagementService.loadChannel(channelId)).thenReturn(Optional.of(aChannel)); + when(channelManagementService.loadChannel(channelId)).thenReturn(aChannel); when(serverManagementService.loadOrCreate(serverId)).thenReturn(server); when(botService.getMemberInServer(cachedMessage.getServerId(), cachedMessage.getAuthorId())).thenReturn(author); - when(botService.getTextChannelFromServer(cachedMessage.getServerId(), cachedMessage.getChannelId())).thenReturn(Optional.of(textChannel)); + when(botService.getTextChannelFromServerOptional(cachedMessage.getServerId(), cachedMessage.getChannelId())).thenReturn(Optional.of(textChannel)); MessageToSend messageToSend = MessageToSend.builder().build(); when(templateService.renderEmbedTemplate(eq(MessageEmbedServiceBean.MESSAGE_EMBED_TEMPLATE), any(MessageEmbeddedModel.class))).thenReturn(messageToSend); Message messageContainingEmbed = Mockito.mock(Message.class); diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/RemindServiceBeanTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/RemindServiceBeanTest.java index 404a48a1b..4d87b9344 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/RemindServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/RemindServiceBeanTest.java @@ -87,7 +87,7 @@ public class RemindServiceBeanTest { AChannel aChannel = MockUtils.getTextChannel(server, 5L); String remindText = "text"; Duration duration = Duration.ofSeconds(62); - when(channelManagementService.loadChannel(channel.getIdLong())).thenReturn(Optional.of(aChannel)); + when(channelManagementService.loadChannel(channel.getIdLong())).thenReturn(aChannel); Long reminderId = 5L; Reminder createdReminder = Reminder.builder().targetDate(Instant.now().plus(duration)).text(remindText).id(reminderId).build(); Long messageId = 5L; @@ -109,7 +109,7 @@ public class RemindServiceBeanTest { AChannel aChannel = MockUtils.getTextChannel(server, 5L); String remindText = "text"; Duration duration = Duration.ofSeconds(50); - when(channelManagementService.loadChannel(channel.getIdLong())).thenReturn(Optional.of(aChannel)); + when(channelManagementService.loadChannel(channel.getIdLong())).thenReturn(aChannel); Long reminderId = 5L; Reminder createdReminder = Reminder.builder().targetDate(Instant.now().plus(duration)).text(remindText).id(reminderId).build(); Long messageId = 5L; @@ -130,7 +130,7 @@ public class RemindServiceBeanTest { when(reminderManagementService.loadReminder(reminderId)).thenReturn(Optional.of(remindedReminder)); Guild guildMock = Mockito.mock(Guild.class); when(botService.getGuildById(server.getId())).thenReturn(Optional.of(guildMock)); - when(botService.getTextChannelFromServer(server.getId(), aChannel.getId())).thenReturn(Optional.of(channel)); + when(botService.getTextChannelFromServerOptional(server.getId(), aChannel.getId())).thenReturn(Optional.of(channel)); Member mockedMember = Mockito.mock(Member.class); when(botService.getMemberInServer(server.getId(), remindedUser.getUserReference().getId())).thenReturn(mockedMember); MessageToSend messageToSend = MessageToSend.builder().build(); @@ -149,7 +149,7 @@ public class RemindServiceBeanTest { when(reminderManagementService.loadReminder(reminderId)).thenReturn(Optional.of(remindedReminder)); Guild guildMock = Mockito.mock(Guild.class); when(botService.getGuildById(server.getId())).thenReturn(Optional.of(guildMock)); - when(botService.getTextChannelFromServer(server.getId(), aChannel.getId())).thenReturn(Optional.empty()); + when(botService.getTextChannelFromServerOptional(server.getId(), aChannel.getId())).thenReturn(Optional.empty()); testUnit.executeReminder(reminderId); verify(reminderManagementService, times(1)).setReminded(remindedReminder); } diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/StarboardServiceBeanTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/StarboardServiceBeanTest.java index 60c7b6449..47ccadaae 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/StarboardServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/StarboardServiceBeanTest.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException; import dev.sheldan.abstracto.core.models.AServerAChannelMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage; @@ -117,7 +116,7 @@ public class StarboardServiceBeanTest { .build(); Member authorMember = Mockito.mock(Member.class); when(botService.getMemberInServer(message.getServerId(), message.getAuthorId())).thenReturn(authorMember); - when(botService.getTextChannelFromServer(server.getId(), channelId)).thenReturn(Optional.of(mockedTextChannel)); + when(botService.getTextChannelFromServerOptional(server.getId(), channelId)).thenReturn(Optional.of(mockedTextChannel)); when(botService.getGuildById(server.getId())).thenReturn(Optional.of(guild)); MessageToSend postMessage = MessageToSend.builder().build(); when(templateService.renderEmbedTemplate(eq(StarboardServiceBean.STARBOARD_POST_TEMPLATE), starboardPostModelArgumentCaptor.capture())).thenReturn(postMessage); @@ -157,7 +156,7 @@ public class StarboardServiceBeanTest { when(userInServerManagementService.loadUser(starredUser.getUserInServerId())).thenReturn(Optional.of(starredUser)); when(userInServerManagementService.loadUser(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting)); AChannel channel = MockUtils.getTextChannel(server, channelId); - when(channelManagementService.loadChannel(channelId)).thenReturn(Optional.of(channel)); + when(channelManagementService.loadChannel(channelId)).thenReturn(channel); StarboardPost post = StarboardPost.builder().build(); when(starboardPostManagementService.createStarboardPost(eq(message), eq(starredUser), any(AServerAChannelMessage.class))).thenReturn(post); AUserInAServer secondStarrerUserObj = MockUtils.getUserObject(secondStarrerUserId, server); @@ -223,17 +222,6 @@ public class StarboardServiceBeanTest { executeLoadErrorTest(server, userReacting, starredUser, 10L); } - @Test(expected = ChannelNotFoundException.class) - public void testPersistingOfNotFoundChannel() { - AServer server = MockUtils.getServer(); - AUserInAServer userReacting = MockUtils.getUserObject(4L, server); - AUserInAServer starredUser = MockUtils.getUserObject(5L, server); - when(userInServerManagementService.loadUser(starredUser.getUserInServerId())).thenReturn(Optional.of(starredUser)); - Long channelId = 10L; - when(channelManagementService.loadChannel(channelId)).thenReturn(Optional.empty()); - executeLoadErrorTest(server, userReacting, starredUser, channelId); - } - @Test public void testRetrieveStarStats() { AServer server = MockUtils.getServer(); diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBeanTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBeanTest.java index 04b12ea03..f07982476 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/MessageEmbedPostManagementServiceBeanTest.java @@ -52,7 +52,7 @@ public class MessageEmbedPostManagementServiceBeanTest { AUserInAServer embeddedUser = MockUtils.getUserObject(7L, server); AChannel channel = MockUtils.getTextChannel(server, 8L); when(serverManagementService.loadOrCreate(server.getId())).thenReturn(server); - when(channelManagementService.loadChannel(channel.getId())).thenReturn(Optional.of(channel)); + when(channelManagementService.loadChannel(channel.getId())).thenReturn(channel); Long embeddedMessageId = 5L; Long embeddingMessageId = 7L; CachedMessage cachedMessage = CachedMessage diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBeanTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBeanTest.java index 1160219ef..062a8d85a 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/StarboardPostManagementServiceBeanTest.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.AServerAChannelMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AChannel; @@ -57,7 +56,7 @@ public class StarboardPostManagementServiceBeanTest { .channel(starboardChannel) .messageId(starboardPostId) .build(); - when(channelManagementService.loadChannel(starredMessage.getChannelId())).thenReturn(Optional.ofNullable(sourceChannel)); + when(channelManagementService.loadChannel(starredMessage.getChannelId())).thenReturn(sourceChannel); StarboardPost createdStarboardPost = testUnit.createStarboardPost(starredMessage, userInAServer, postInStarboard); verify(repository, times(1)).save(createdStarboardPost); Assert.assertEquals(postInStarboard.getChannel().getId(), createdStarboardPost.getStarboardChannel().getId()); @@ -69,30 +68,6 @@ public class StarboardPostManagementServiceBeanTest { Assert.assertFalse(createdStarboardPost.isIgnored()); } - @Test(expected = ChannelNotFoundException.class) - public void testCreateStarboardPostForNonExistingChannel() { - AServer server = MockUtils.getServer(); - AUserInAServer userInAServer = MockUtils.getUserObject(7L, server); - AChannel sourceChannel = MockUtils.getTextChannel(server, 9L); - AChannel starboardChannel = MockUtils.getTextChannel(server, 10L); - Long starboardPostId = 5L; - Long starredMessageId = 8L; - CachedMessage starredMessage = CachedMessage - .builder() - .channelId(sourceChannel.getId()) - .messageId(starredMessageId) - .serverId(server.getId()) - .build(); - AServerAChannelMessage postInStarboard = AServerAChannelMessage - .builder() - .server(server) - .channel(starboardChannel) - .messageId(starboardPostId) - .build(); - when(channelManagementService.loadChannel(starredMessage.getChannelId())).thenReturn(Optional.empty()); - testUnit.createStarboardPost(starredMessage, userInAServer, postInStarboard); - } - @Test public void setStarboardMessageId(){ StarboardPost post = StarboardPost diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBeanTest.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBeanTest.java index 4bfa53f3c..bee52094b 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/test/java/dev/sheldan/abstracto/utility/service/management/SuggestionManagementServiceBeanTest.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.utility.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer; @@ -99,26 +98,13 @@ public class SuggestionManagementServiceBeanTest { when(channel.getIdLong()).thenReturn(channelId); when(message.getIdLong()).thenReturn(messageId); AChannel aChannel = AChannel.builder().id(channelId).build(); - when(channelManagementService.loadChannel(channelId)).thenReturn(Optional.of(aChannel)); + when(channelManagementService.loadChannel(channelId)).thenReturn(aChannel); testUnit.setPostedMessage(suggestion, message); Assert.assertEquals(messageId, suggestion.getMessageId()); Assert.assertEquals(channelId, suggestion.getChannel().getId()); verify(suggestionRepository, times(1)).save(suggestion); } - @Test(expected = ChannelNotFoundException.class) - public void testSetPostedMessageChannelNotFound() { - Long channelId = 6L; - AServer server = MockUtils.getServer(); - Suggestion suggestion = Suggestion.builder().server(server).build(); - Message message = Mockito.mock(Message.class); - MessageChannel channel = Mockito.mock(MessageChannel.class); - when(message.getChannel()).thenReturn(channel); - when(channel.getIdLong()).thenReturn(channelId); - when(channelManagementService.loadChannel(channelId)).thenReturn(Optional.empty()); - testUnit.setPostedMessage(suggestion, message); - } - @Test public void setSuggestionState() { Suggestion suggestion = Suggestion.builder().build(); diff --git a/abstracto-application/bundle/pom.xml b/abstracto-application/bundle/pom.xml index 8ae754da3..7d4d5f278 100644 --- a/abstracto-application/bundle/pom.xml +++ b/abstracto-application/bundle/pom.xml @@ -55,6 +55,12 @@ ${project.version} + + dev.sheldan.abstracto.modules + assignable-roles-impl + ${project.version} + + diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java index b6b209da1..b441a09c1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java @@ -7,22 +7,20 @@ import dev.sheldan.abstracto.core.command.exception.IncorrectParameter; import dev.sheldan.abstracto.core.command.exception.ParameterTooLong; import dev.sheldan.abstracto.core.command.service.CommandManager; import dev.sheldan.abstracto.core.command.service.CommandService; +import dev.sheldan.abstracto.core.command.service.ExceptionService; import dev.sheldan.abstracto.core.command.service.PostCommandExecution; import dev.sheldan.abstracto.core.command.execution.*; import dev.sheldan.abstracto.core.command.execution.UnParsedCommandParameter; import dev.sheldan.abstracto.core.Constants; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.exception.MemberNotFoundException; import dev.sheldan.abstracto.core.exception.RoleNotFoundInDBException; -import dev.sheldan.abstracto.core.models.database.ARole; -import dev.sheldan.abstracto.core.service.management.ChannelManagementService; -import dev.sheldan.abstracto.core.service.management.RoleManagementService; -import dev.sheldan.abstracto.core.service.management.ServerManagementService; -import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; -import dev.sheldan.abstracto.core.models.database.AChannel; -import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.FullEmote; +import dev.sheldan.abstracto.core.models.FullRole; +import dev.sheldan.abstracto.core.models.database.*; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.RoleService; +import dev.sheldan.abstracto.core.service.management.*; import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; -import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.utils.ParseUtils; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.*; @@ -32,7 +30,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Nonnull; @@ -68,6 +65,18 @@ public class CommandReceivedHandler extends ListenerAdapter { @Autowired private CommandService commandService; + @Autowired + private EmoteService emoteService; + + @Autowired + private ExceptionService exceptionService; + + @Autowired + private EmoteManagementService emoteManagementService; + + @Autowired + private RoleService roleService; + @Override @Transactional public void onMessageReceived(@Nonnull MessageReceivedEvent event) { @@ -85,47 +94,84 @@ public class CommandReceivedHandler extends ListenerAdapter { .message(event.getMessage()) .jda(event.getJDA()) .userInitiatedContext(userInitiatedContext); - Command foundCommand = null; + final Command foundCommand; try { String contentStripped = event.getMessage().getContentStripped(); List parameters = Arrays.asList(contentStripped.split(" ")); UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped); String commandName = commandManager.getCommandName(parameters.get(0), event.getGuild().getIdLong()); foundCommand = commandManager.findCommandByParameters(commandName, unParsedParameter); - Parameters parsedParameters = getParsedParameters(unParsedParameter, foundCommand, event.getMessage(), userInitiatedContext); - CommandContext commandContext = commandContextBuilder.parameters(parsedParameters).build(); - ConditionResult conditionResult = commandService.isCommandExecutable(foundCommand, commandContext); - CommandResult commandResult; - if(conditionResult.isResult()) { - commandResult = self.executeCommand(foundCommand, commandContext); - } else { - commandResult = CommandResult.fromCondition(conditionResult); - } - for (PostCommandExecution postCommandExecution : executions) { - postCommandExecution.execute(commandContext, commandResult, foundCommand); - } + tryToExecuteFoundCommand(event, userInitiatedContext, commandContextBuilder, foundCommand, unParsedParameter); + } catch (Exception e) { + log.error("Exception when preparing command.", e); CommandResult commandResult = CommandResult.fromError(e.getMessage(), e); CommandContext commandContext = commandContextBuilder.build(); - for (PostCommandExecution postCommandExecution : executions) { - postCommandExecution.execute(commandContext, commandResult, foundCommand); - } + self.executePostCommandListener(null, commandContext, commandResult); } } - @Transactional(propagation = Propagation.REQUIRES_NEW) + private void tryToExecuteFoundCommand(@Nonnull MessageReceivedEvent event, UserInitiatedServerContext userInitiatedContext, CommandContext.CommandContextBuilder commandContextBuilder, Command foundCommand, UnParsedCommandParameter unParsedParameter) { + try { + Parameters parsedParameters = getParsedParameters(unParsedParameter, foundCommand, event.getMessage(), userInitiatedContext); + CommandContext commandContext = commandContextBuilder.parameters(parsedParameters).build(); + ConditionResult conditionResult = commandService.isCommandExecutable(foundCommand, commandContext); + CommandResult commandResult = null; + if(conditionResult.isResult()) { + if(foundCommand.getConfiguration().isAsync()) { + foundCommand.executeAsync(commandContext).thenAccept(result -> + executePostCommandListener(foundCommand, commandContext, result) + ).exceptionally(throwable -> { + log.error("Asynchronous command {} failed.", foundCommand.getConfiguration().getName(), throwable); + UserInitiatedServerContext rebuildUserContext = buildTemplateParameter(event); + CommandContext rebuildContext = CommandContext.builder() + .author(event.getMember()) + .guild(event.getGuild()) + .channel(event.getTextChannel()) + .message(event.getMessage()) + .jda(event.getJDA()) + .userInitiatedContext(rebuildUserContext) + .parameters(parsedParameters).build(); + CommandResult failedResult = CommandResult.fromError(throwable.getMessage(), throwable); + self.executePostCommandListener(foundCommand, rebuildContext, failedResult); + return null; + }); + } else { + commandResult = self.executeCommand(foundCommand, commandContext); + } + } else { + commandResult = CommandResult.fromCondition(conditionResult); + } + if(commandResult != null) { + self.executePostCommandListener(foundCommand, commandContext, commandResult); + } + } catch (Exception e) { + log.error("Exception when executing command.", e); + CommandResult commandResult = CommandResult.fromError(e.getMessage(), e); + CommandContext commandContext = commandContextBuilder.build(); + self.executePostCommandListener(foundCommand, commandContext, commandResult); + } + } + + @Transactional + public void executePostCommandListener(Command foundCommand, CommandContext commandContext, CommandResult result) { + for (PostCommandExecution postCommandExecution : executions) { + postCommandExecution.execute(commandContext, result, foundCommand); + } + } + + @Transactional public CommandResult executeCommand(Command foundCommand, CommandContext commandContext) { return foundCommand.execute(commandContext); } private UserInitiatedServerContext buildTemplateParameter(MessageReceivedEvent event) { - Optional channel = channelManagementService.loadChannel(event.getChannel().getIdLong()); + AChannel channel = channelManagementService.loadChannel(event.getChannel().getIdLong()); AServer server = serverManagementService.loadOrCreate(event.getGuild().getIdLong()); AUserInAServer user = userInServerManagementService.loadUser(event.getMember()); - AChannel channel1 = channel.orElseThrow(() -> new ChannelNotFoundException(event.getChannel().getIdLong(), event.getGuild().getIdLong())); return UserInitiatedServerContext .builder() - .channel(channel1) + .channel(channel) .server(server) .member(event.getMember()) .aUserInAServer(user) @@ -141,9 +187,9 @@ public class CommandReceivedHandler extends ListenerAdapter { return Parameters.builder().parameters(parsedParameters).build(); } Iterator channelIterator = message.getMentionedChannels().iterator(); - Iterator emoteIterator = message.getEmotes().iterator(); + Iterator emoteIterator = message.getEmotesBag().iterator(); Iterator memberIterator = message.getMentionedMembers().iterator(); - Iterator roleIterator = message.getMentionedRoles().iterator(); + Iterator roleIterator = message.getMentionedRolesBag().iterator(); Parameter param = command.getConfiguration().getParameters().get(0); boolean reminderActive = false; for (int i = 0; i < unParsedCommandParameter.getParameters().size(); i++) { @@ -175,21 +221,69 @@ public class CommandReceivedHandler extends ListenerAdapter { } else { parsedParameters.add(memberIterator.next()); } - } else if(param.getType().equals(Emote.class)) { + } else if(param.getType().equals(FullEmote.class)) { // TODO maybe rework, this fails if two emotes are needed, and the second one is an emote, the first one a default one // the second one shadows the first one, and there are too little parameters to go of if (emoteIterator.hasNext()) { - parsedParameters.add(emoteIterator.next()); + try { + Long emoteId = Long.parseLong(value); + if(emoteManagementService.emoteExists(emoteId)) { + AEmote aEmote = AEmote.builder().emoteId(emoteId).custom(true).build(); + FullEmote emote = FullEmote.builder().fakeEmote(aEmote).build(); + parsedParameters.add(emote); + } + } catch (Exception ex) { + Emote actualEmote = emoteIterator.next(); + AEmote fakeEmote = emoteService.getFakeEmote(actualEmote); + FullEmote emote = FullEmote.builder().fakeEmote(fakeEmote).emote(actualEmote).build(); + parsedParameters.add(emote); + } } else { - parsedParameters.add(value); + try { + Long emoteId = Long.parseLong(value); + if(emoteManagementService.emoteExists(emoteId)) { + // we do not need to load the actual emote, as there is no guarantee that it exists anyway + // there might be multiple emotes with the same emoteId, so we dont have any gain to fetch any of them + AEmote aEmote = AEmote.builder().emoteId(emoteId).custom(true).build(); + FullEmote emote = FullEmote.builder().fakeEmote(aEmote).build(); + parsedParameters.add(emote); + } + } catch (Exception ex) { + AEmote fakeEmote = emoteService.getFakeEmote(value); + FullEmote emote = FullEmote.builder().fakeEmote(fakeEmote).build(); + parsedParameters.add(emote); + } } + } else if(param.getType().equals(AEmote.class)) { + // TODO maybe rework, this fails if two emotes are needed, and the second one is an emote, the first one a default one + // the second one shadows the first one, and there are too little parameters to go of + if (emoteIterator.hasNext()) { + parsedParameters.add(emoteService.getFakeEmote(emoteIterator.next())); + } else { + parsedParameters.add(emoteService.getFakeEmote(value)); + } + } else if(CommandParameterKey.class.isAssignableFrom(param.getType())) { + CommandParameterKey cast = (CommandParameterKey) CommandParameterKey.getEnumFromKey(param.getType(), value); + parsedParameters.add(cast); + } else if(param.getType().equals(FullRole.class)) { + ARole aRole; + if(StringUtils.isNumeric(value)) { + long roleId = Long.parseLong(value); + aRole = roleManagementService.findRoleOptional(roleId).orElseThrow(() -> new RoleNotFoundInDBException(roleId)); + } else { + long roleId = roleIterator.next().getIdLong(); + aRole = roleManagementService.findRoleOptional(roleId).orElseThrow(() -> new RoleNotFoundInDBException(roleId)); + } + Role role = roleService.getRoleFromGuild(aRole); + FullRole fullRole = FullRole.builder().role(aRole).serverRole(role).build(); + parsedParameters.add(fullRole); } else if(param.getType().equals(ARole.class)) { if(StringUtils.isNumeric(value)) { long roleId = Long.parseLong(value); - parsedParameters.add(roleManagementService.findRole(roleId, userInitiatedServerContext.getServer()).orElseThrow(() -> new RoleNotFoundInDBException(roleId, message.getGuild().getIdLong()))); + parsedParameters.add(roleManagementService.findRoleOptional(roleId).orElseThrow(() -> new RoleNotFoundInDBException(roleId))); } else { long roleId = roleIterator.next().getIdLong(); - parsedParameters.add(roleManagementService.findRole(roleId, userInitiatedServerContext.getServer()).orElseThrow(() -> new RoleNotFoundInDBException(roleId, message.getGuild().getIdLong()))); + parsedParameters.add(roleManagementService.findRoleOptional(roleId).orElseThrow(() -> new RoleNotFoundInDBException(roleId))); } } else if(param.getType().equals(Boolean.class)) { parsedParameters.add(Boolean.valueOf(value)); @@ -209,6 +303,8 @@ public class CommandReceivedHandler extends ListenerAdapter { } } catch (NoSuchElementException e) { throw new IncorrectParameter(command, param.getType(), param.getName()); + } catch (IllegalArgumentException e) { + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ExceptionPostExecution.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ExceptionPostExecution.java index eeb177a16..126018a5c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ExceptionPostExecution.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ExceptionPostExecution.java @@ -1,8 +1,8 @@ package dev.sheldan.abstracto.core.command.post; import dev.sheldan.abstracto.core.command.Command; +import dev.sheldan.abstracto.core.command.service.ExceptionService; import dev.sheldan.abstracto.core.command.service.PostCommandExecution; -import dev.sheldan.abstracto.templating.Templatable; import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.ResultState; @@ -18,24 +18,17 @@ public class ExceptionPostExecution implements PostCommandExecution { @Autowired private TemplateService templateService; + @Autowired + private ExceptionService exceptionService; + @Override public void execute(CommandContext commandContext, CommandResult commandResult, Command command) { - if(commandResult.getResult().equals(ResultState.ERROR)) { + ResultState result = commandResult.getResult(); + if(result.equals(ResultState.ERROR)) { Throwable throwable = commandResult.getThrowable(); if(throwable != null) { - log.error("Exception: ", throwable); - if(throwable instanceof Templatable) { - Templatable exception = (Templatable) throwable; - String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel()); - commandContext.getChannel().sendMessage(text).queue(); - } else { - if(throwable.getCause() == null) { - commandContext.getChannel().sendMessage(throwable.getClass().getSimpleName() + ": " + commandResult.getMessage()).queue(); - } else { - Throwable cause = throwable.getCause(); - commandContext.getChannel().sendMessage(throwable.getClass().getSimpleName() + ": " + commandResult.getMessage() + ": " + cause.getClass().getSimpleName() + ":" + cause.getMessage()).queue(); - } - } + log.info("Exception handling for exception {}.", throwable.getClass().getSimpleName()); + exceptionService.reportExceptionToContext(throwable, commandContext, command); } } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ReactionPostExecution.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ReactionPostExecution.java index 76a056ff4..6881d9a49 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ReactionPostExecution.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/ReactionPostExecution.java @@ -20,7 +20,7 @@ public class ReactionPostExecution implements PostCommandExecution { @Override public void execute(CommandContext commandContext, CommandResult commandResult, Command command) { ResultState result = commandResult.getResult(); - if(result.equals(ResultState.ERROR)) { + if(result.equals(ResultState.ERROR) || result.equals(ResultState.REPORTED_ERROR)) { messageService.addReactionToMessage(WARN_REACTION_EMOTE, commandContext.getGuild().getIdLong(), commandContext.getMessage()); if(commandResult.getMessage() != null && commandResult.getThrowable() == null){ commandContext.getChannel().sendMessage(commandResult.getMessage()).queue(); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java new file mode 100644 index 000000000..c136a40aa --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.core.command.service; + +import dev.sheldan.abstracto.core.command.Command; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.command.models.exception.GenericExceptionModel; +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.templating.Templatable; +import dev.sheldan.abstracto.templating.service.TemplateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ExceptionServiceBean implements ExceptionService { + + @Autowired + private ChannelService channelService; + + @Autowired + private TemplateService templateService; + + @Override + public CommandResult reportExceptionToContext(Throwable throwable, CommandContext context, Command command) { + if(command != null && command.getConfiguration().isReportsException()) { + try { + FullUser fullUser = FullUser + .builder() + .aUserInAServer(context.getUserInitiatedContext().getAUserInAServer()) + .member(context.getAuthor()) + .build(); + GenericExceptionModel modMailExceptionModel = GenericExceptionModel + .builder() + .user(fullUser) + .throwable(throwable) + .build(); + channelService.sendEmbedTemplateInChannel("generic_command_exception", modMailExceptionModel, context.getChannel()); + } catch (Exception e) { + log.error("Failed to notify about assignable role exception.", e); + } + } else if(throwable instanceof Templatable){ + Templatable exception = (Templatable) throwable; + String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel()); + channelService.sendTextToChannel(text, context.getChannel()); + } else { + channelService.sendTextToChannel(throwable.getLocalizedMessage(), context.getChannel()); + } + return CommandResult.fromReportedError(); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/SetEmote.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/SetEmote.java index 8274dac12..0d8fa1ac0 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/SetEmote.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/SetEmote.java @@ -9,8 +9,9 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.config.Parameter; import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.command.config.features.CoreFeatures; +import dev.sheldan.abstracto.core.models.database.AEmote; +import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.management.EmoteManagementService; -import net.dv8tion.jda.api.entities.Emote; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -23,25 +24,22 @@ public class SetEmote extends AbstractConditionableCommand { @Autowired private EmoteManagementService emoteManagementService; + @Autowired + private EmoteService emoteService; + @Override public CommandResult execute(CommandContext commandContext) { - String emoteKey = (String) commandContext.getParameters().getParameters().get(0); - Object o = commandContext.getParameters().getParameters().get(1); - if(o instanceof String) { - String emote = (String) o; - emoteManagementService.setEmoteToDefaultEmote(emoteKey, emote, commandContext.getGuild().getIdLong()); - } else { - Emote emote = (Emote) o; - // todo check if usable - emoteManagementService.setEmoteToCustomEmote(emoteKey, emote, commandContext.getGuild().getIdLong()); - } + List parameters = commandContext.getParameters().getParameters(); + String emoteKey = (String) parameters.get(0); + AEmote emote = (AEmote) parameters.get(1); + emoteManagementService.setEmoteToAEmote(emoteKey, emote, commandContext.getGuild().getIdLong()); return CommandResult.fromSuccess(); } @Override public CommandConfiguration getConfiguration() { Parameter emoteKey = Parameter.builder().name("emoteKey").type(String.class).templated(true).build(); - Parameter emote = Parameter.builder().name("emote").type(net.dv8tion.jda.api.entities.Emote.class).templated(true).build(); + Parameter emote = Parameter.builder().name("emote").type(AEmote.class).templated(true).build(); List parameters = Arrays.asList(emoteKey, emote); HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); return CommandConfiguration.builder() diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java index b1f815699..d28d5c5ba 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java @@ -48,9 +48,10 @@ public class InteractiveServiceBean implements InteractiveService { @Override public void createMessageWithResponse(String messageText, AUserInAServer responder, AChannel channel, Long messageId, Consumer action, Runnable finalAction) { channelService.sendTextToAChannel(messageText, channel); + Long channelId = channel.getId(); eventWaiter.waitForEvent(MessageReceivedEvent.class, event -> { if(event != null) { - return event.getAuthor().getIdLong() == responder.getUserReference().getId() && event.getMessage().getIdLong() != messageId; + return event.getAuthor().getIdLong() == responder.getUserReference().getId() && event.getMessage().getIdLong() != messageId && event.getMessage().getChannel().getIdLong() == channelId; } return false; }, action, 1, TimeUnit.MINUTES, finalAction); @@ -94,7 +95,7 @@ public class InteractiveServiceBean implements InteractiveService { } private void addEmoteToBuilder(String key, Consumer consumer, Long serverId, ButtonMenu.Builder builder, HashMap> actions) { - AEmote emoteOrFakeEmote = emoteService.getEmoteOrFakeEmote(key, serverId); + AEmote emoteOrFakeEmote = emoteService.getEmoteOrDefaultEmote(key, serverId); if(Boolean.TRUE.equals(emoteOrFakeEmote.getCustom())){ Optional emote = botService.getEmote(serverId, emoteOrFakeEmote); emote.ifPresent(emote1 -> { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java index 347fd9e40..6ccdc9633 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.interactive; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; @@ -21,7 +20,6 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -59,7 +57,7 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { TextChannel currentTextChannel; if(postTargetManagement.postTargetExists(postTargetStepParameter.getPostTargetKey(), user.getGuildId())) { PostTarget postTarget = postTargetManagement.getPostTarget(postTargetStepParameter.getPostTargetKey(), user.getGuildId()); - currentTextChannel = botService.getTextChannelFromServer(user.getGuildId(), postTarget.getChannelReference().getId()).orElse(null); + currentTextChannel = botService.getTextChannelFromServerOptional(user.getGuildId(), postTarget.getChannelReference().getId()).orElse(null); } else { currentTextChannel = null; } @@ -70,48 +68,44 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { .build(); String messageTemplateKey = "setup_post_target_message"; String messageText = templateService.renderTemplate(messageTemplateKey, model); - Optional channel = channelManagementService.loadChannel(user.getChannelId()); + AChannel channel = channelManagementService.loadChannel(user.getChannelId()); CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId()); - if(channel.isPresent()) { - Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - Consumer configAction = (MessageReceivedEvent event) -> { - try { + Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); + Consumer configAction = (MessageReceivedEvent event) -> { + try { - SetupStepResult result; - Message message = event.getMessage(); - if(checkForExit(message)) { - result = SetupStepResult.fromCancelled(); - } else { - if(message.getMentionedChannels().size() == 0) { - throw new NoChannelProvidedException("No channel was provided."); - } - TextChannel textChannel = message.getMentionedChannels().get(0); - PostTargetDelayedActionConfig build = PostTargetDelayedActionConfig - .builder() - .postTargetKey(postTargetStepParameter.getPostTargetKey()) - .serverId(user.getGuildId()) - .textChannel(textChannel) - .channelId(textChannel.getIdLong()) - .build(); - List delayedSteps = Arrays.asList(build); - result = SetupStepResult - .builder() - .result(SetupStepResultType.SUCCESS) - .delayedActionConfigList(delayedSteps) - .build(); + SetupStepResult result; + Message message = event.getMessage(); + if(checkForExit(message)) { + result = SetupStepResult.fromCancelled(); + } else { + if(message.getMentionedChannels().size() == 0) { + throw new NoChannelProvidedException("No channel was provided."); } - - future.complete(result); - } catch (Exception e) { - log.error("Failed to handle post target step.", e); - future.completeExceptionally(new SetupStepException(e)); + TextChannel textChannel = message.getMentionedChannels().get(0); + PostTargetDelayedActionConfig build = PostTargetDelayedActionConfig + .builder() + .postTargetKey(postTargetStepParameter.getPostTargetKey()) + .serverId(user.getGuildId()) + .textChannel(textChannel) + .channelId(textChannel.getIdLong()) + .build(); + List delayedSteps = Arrays.asList(build); + result = SetupStepResult + .builder() + .result(SetupStepResultType.SUCCESS) + .delayedActionConfigList(delayedSteps) + .build(); } - }; - interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel.get(), parameter.getPreviousMessageId(), configAction, finalAction); - } else { - future.completeExceptionally(new ChannelNotFoundException(user.getGuildId(), user.getChannelId())); - } + + future.complete(result); + } catch (Exception e) { + log.error("Failed to handle post target step.", e); + future.completeExceptionally(new SetupStepException(e)); + } + }; + interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, parameter.getPreviousMessageId(), configAction, finalAction); return future; } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java index 5add94252..96dbf9de4 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.interactive; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -48,35 +46,31 @@ public class SetupSummaryStep extends AbstractConfigSetupStep { .actionConfigs(parameter.getDelayedActionList()) .build(); String messageToSend = templateService.renderTemplate("setup_confirmation", model); - Optional channel = channelManagementService.loadChannel(user.getChannelId()); + AChannel channel = channelManagementService.loadChannel(user.getChannelId()); CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId()); - if(channel.isPresent()) { - Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - Consumer confirmation = (Void none) -> { - try { - self.executeDelayedSteps(parameter); - SetupStepResult result = SetupStepResult - .builder() - .result(SetupStepResultType.SUCCESS) - .build(); - future.complete(result); - } catch (Exception e) { - future.completeExceptionally(e); - } - }; - - Consumer denial = (Void none) -> { + Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); + Consumer confirmation = (Void none) -> { + try { + self.executeDelayedSteps(parameter); SetupStepResult result = SetupStepResult .builder() - .result(SetupStepResultType.CANCELLED) + .result(SetupStepResultType.SUCCESS) .build(); future.complete(result); - }; - interactiveService.createMessageWithConfirmation(messageToSend, aUserInAServer, channel.get(), parameter.getPreviousMessageId(), confirmation, denial, finalAction); - } else { - future.completeExceptionally(new ChannelNotFoundException(user.getGuildId(), user.getChannelId())); - } + } catch (Exception e) { + future.completeExceptionally(e); + } + }; + + Consumer denial = (Void none) -> { + SetupStepResult result = SetupStepResult + .builder() + .result(SetupStepResultType.CANCELLED) + .build(); + future.complete(result); + }; + interactiveService.createMessageWithConfirmation(messageToSend, aUserInAServer, channel, parameter.getPreviousMessageId(), confirmation, denial, finalAction); return future; } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java index 8dbd0477a..6c40c2a1f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.interactive; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AConfig; @@ -21,7 +20,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -61,47 +59,43 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep { .build(); String messageTemplateKey = "setup_system_config_message"; String messageText = templateService.renderTemplate(messageTemplateKey, model); - Optional channel = channelManagementService.loadChannel(user.getChannelId()); + AChannel channel = channelManagementService.loadChannel(user.getChannelId()); CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId()); - if(channel.isPresent()) { - Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - Consumer configAction = (MessageReceivedEvent event) -> { - try { - SetupStepResult result; - Message message = event.getMessage(); - if(checkForExit(message)) { - result = SetupStepResult.fromCancelled(); + Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); + Consumer configAction = (MessageReceivedEvent event) -> { + try { + SetupStepResult result; + Message message = event.getMessage(); + if(checkForExit(message)) { + result = SetupStepResult.fromCancelled(); + } else { + AConfig config; + if(checkForKeep(message)) { + config = self.loadDefaultConfig(systemConfigStepParameter); } else { - AConfig config; - if(checkForKeep(message)) { - config = self.loadDefaultConfig(systemConfigStepParameter); - } else { - config = self.checkValidity(user, systemConfigStepParameter, event); - } - SystemConfigDelayedActionConfig build = SystemConfigDelayedActionConfig - .builder() - .configKey(systemConfigStepParameter.getConfigKey()) - .serverId(user.getGuildId()) - .value(config) - .build(); - List delayedSteps = Arrays.asList(build); - result = SetupStepResult - .builder() - .result(SetupStepResultType.SUCCESS) - .delayedActionConfigList(delayedSteps) - .build(); + config = self.checkValidity(user, systemConfigStepParameter, event); } - future.complete(result); - } catch (Exception e) { - log.warn("Failed to handle system config. Retrying..", e); - future.completeExceptionally(new SetupStepException(e)); + SystemConfigDelayedActionConfig build = SystemConfigDelayedActionConfig + .builder() + .configKey(systemConfigStepParameter.getConfigKey()) + .serverId(user.getGuildId()) + .value(config) + .build(); + List delayedSteps = Arrays.asList(build); + result = SetupStepResult + .builder() + .result(SetupStepResultType.SUCCESS) + .delayedActionConfigList(delayedSteps) + .build(); } - }; - interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel.get(), parameter.getPreviousMessageId(), configAction, finalAction); - } else { - future.completeExceptionally(new ChannelNotFoundException(user.getGuildId(), user.getChannelId())); - } + future.complete(result); + } catch (Exception e) { + log.warn("Failed to handle system config. Retrying..", e); + future.completeExceptionally(new SetupStepException(e)); + } + }; + interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, parameter.getPreviousMessageId(), configAction, finalAction); return future; } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageDeletedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageDeletedListenerBean.java index 2af1995b4..6710620c5 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageDeletedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageDeletedListenerBean.java @@ -72,14 +72,14 @@ public class MessageDeletedListenerBean extends ListenerAdapter { AServerAChannelAUser authorUser = AServerAChannelAUser .builder() .guild(serverManagementService.loadOrCreate(cachedMessage.getServerId())) - .channel(channelManagementService.loadChannel(cachedMessage.getChannelId()).orElseThrow(() -> new ChannelNotFoundException(cachedMessage.getServerId(), cachedMessage.getChannelId()))) + .channel(channelManagementService.loadChannel(cachedMessage.getChannelId())) .aUserInAServer(userInServerManagementService.loadUser(cachedMessage.getServerId(), cachedMessage.getAuthorId())) .build(); GuildChannelMember authorMember = GuildChannelMember .builder() .guild(botService.getGuildByIdNullable(cachedMessage.getServerId())) - .textChannel(botService.getTextChannelFromServer(cachedMessage.getServerId(), cachedMessage.getChannelId()).orElseThrow(() -> new ChannelNotFoundException(cachedMessage.getServerId(), cachedMessage.getChannelId()))) + .textChannel(botService.getTextChannelFromServerOptional(cachedMessage.getServerId(), cachedMessage.getChannelId()).orElseThrow(() -> new ChannelNotFoundException(cachedMessage.getChannelId()))) .member(botService.getMemberInServer(cachedMessage.getServerId(), cachedMessage.getAuthorId())) .build(); listener.forEach(messageDeletedListener -> { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ReactionUpdatedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ReactionUpdatedListener.java index f71aa6a32..76599e053 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ReactionUpdatedListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/ReactionUpdatedListener.java @@ -67,7 +67,7 @@ public class ReactionUpdatedListener extends ListenerAdapter { self.callAddedListeners(event, cachedMessage, reaction); messageCache.putMessageInCache(cachedMessage); }).exceptionally(throwable -> { - log.error("Failed to add reaction to message {} ", event.getMessageIdLong(), throwable); + log.error("Failed to handle add reaction to message {} ", event.getMessageIdLong(), throwable); return null; }) ).exceptionally(throwable -> { @@ -112,7 +112,7 @@ public class ReactionUpdatedListener extends ListenerAdapter { return; } try { - reactedAddedListener.executeReactionAdded(cachedMessage, event.getReaction(), userInAServer); + reactedAddedListener.executeReactionAdded(cachedMessage, event, userInAServer); } catch (Exception e) { log.warn(String.format("Failed to execute reaction added listener %s.", reactedAddedListener.getClass().getName()), e); } @@ -151,7 +151,7 @@ public class ReactionUpdatedListener extends ListenerAdapter { return; } try { - reactionRemovedListener.executeReactionRemoved(cachedMessage, event.getReaction(), userInAServer); + reactionRemovedListener.executeReactionRemoved(cachedMessage, event, userInAServer); } catch (AbstractoRunTimeException e) { log.warn(String.format("Failed to execute reaction removed listener %s.", reactionRemovedListener.getClass().getName()), e); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/EmoteRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/EmoteRepository.java index 97490b7c9..341f0898f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/EmoteRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/EmoteRepository.java @@ -7,13 +7,23 @@ import org.springframework.data.jpa.repository.QueryHints; import org.springframework.stereotype.Repository; import javax.persistence.QueryHint; +import java.util.Optional; @Repository -public interface EmoteRepository extends JpaRepository { +public interface EmoteRepository extends JpaRepository { @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) AEmote findAEmoteByNameAndServerRef(String name, AServer server); @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) boolean existsByNameAndServerRef(String name, AServer server); + + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + Optional findByEmoteId(Long emoteId); + + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + boolean existsByEmoteId(Long emoteId); + + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + boolean existsByEmoteIdAndServerRef(String emoteId, AServer server); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/BotServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/BotServiceBean.java index 89bca40f7..2b81caac1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/BotServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/BotServiceBean.java @@ -1,7 +1,7 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.GuildChannelMember; import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AServer; @@ -52,17 +52,17 @@ public class BotServiceBean implements BotService { Optional guildOptional = getGuildById(serverId); if(guildOptional.isPresent()) { Guild guild = guildOptional.get(); - Optional textChannelOptional = this.getTextChannelFromServer(guild, channelId); + Optional textChannelOptional = this.getTextChannelFromServerOptional(guild, channelId); if(textChannelOptional.isPresent()) { TextChannel textChannel = textChannelOptional.get(); Member member = guild.getMemberById(userId); return GuildChannelMember.builder().guild(guild).textChannel(textChannel).member(member).build(); } else { - throw new ChannelNotFoundException(channelId, serverId); + throw new ChannelNotFoundException(channelId); } } else { - throw new GuildException(serverId); + throw new GuildNotFoundException(serverId); } } @@ -72,7 +72,7 @@ public class BotServiceBean implements BotService { if(guildById != null) { return guildById.getMemberById(memberId); } else { - throw new GuildException(serverId); + throw new GuildNotFoundException(serverId); } } @@ -82,7 +82,7 @@ public class BotServiceBean implements BotService { if(guildById != null) { return isUserInGuild(guildById, aUserInAServer); } else { - throw new GuildException(aUserInAServer.getServerReference().getId()); + throw new GuildNotFoundException(aUserInAServer.getServerReference().getId()); } } @@ -103,10 +103,13 @@ public class BotServiceBean implements BotService { @Override public CompletableFuture deleteMessage(Long serverId, Long channelId, Long messageId) { - Optional textChannelOptional = getTextChannelFromServer(serverId, channelId); + Optional textChannelOptional = getTextChannelFromServerOptional(serverId, channelId); if(textChannelOptional.isPresent()) { TextChannel textChannel = textChannelOptional.get(); - return textChannel.deleteMessageById(messageId).submit(); + return textChannel.deleteMessageById(messageId).submit().exceptionally(throwable -> { + log.warn("Deleting the message {} in channel {} in guild {} failed.", messageId, channelId, serverId, throwable); + return null; + }); } else { log.warn("Could not find channel {} in guild {} to delete message {} in.", channelId, serverId, messageId); } @@ -140,22 +143,40 @@ public class BotServiceBean implements BotService { Emote emoteById = guild.getEmoteById(emote.getEmoteId()); return Optional.ofNullable(emoteById); } - throw new GuildException(serverId); + throw new GuildNotFoundException(serverId); } @Override - public Optional getTextChannelFromServer(Guild guild, Long textChannelId) { + public Optional getEmote(AEmote emote) { + if(Boolean.FALSE.equals(emote.getCustom())) { + return Optional.empty(); + } + return Optional.ofNullable(instance.getEmoteById(emote.getEmoteId())); + } + + @Override + public Optional getTextChannelFromServerOptional(Guild guild, Long textChannelId) { return Optional.ofNullable(guild.getTextChannelById(textChannelId)); } @Override - public Optional getTextChannelFromServer(Long serverId, Long textChannelId) { + public TextChannel getTextChannelFromServer(Guild guild, Long textChannelId) { + return getTextChannelFromServerOptional(guild, textChannelId).orElseThrow(() -> new ChannelNotFoundException(textChannelId)); + } + + @Override + public Optional getTextChannelFromServerOptional(Long serverId, Long textChannelId) { Optional guildOptional = getGuildById(serverId); if(guildOptional.isPresent()) { Guild guild = guildOptional.get(); return Optional.ofNullable(guild.getTextChannelById(textChannelId)); } - throw new GuildException(serverId); + throw new GuildNotFoundException(serverId); + } + + @Override + public TextChannel getTextChannelFromServer(Long serverId, Long textChannelId) { + return getTextChannelFromServerOptional(serverId, textChannelId).orElseThrow(() -> new ChannelNotFoundException(textChannelId)); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/CacheServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/CacheServiceBean.java index ba2c368e1..4f57dc918 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/CacheServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/CacheServiceBean.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +16,9 @@ public class CacheServiceBean { private SessionFactory sessionFactory; + @Autowired + private TemplateService templateService; + @Autowired public CacheServiceBean(EntityManagerFactory factory) { SessionFactory unWrapped = factory.unwrap(SessionFactory.class); @@ -26,5 +30,6 @@ public class CacheServiceBean { public void clearCaches() { sessionFactory.getCache().evictAllRegions(); + templateService.clearCache(); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java index daf1f7372..3068a265f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java @@ -5,7 +5,6 @@ import dev.sheldan.abstracto.core.command.exception.CommandNotFoundException; import dev.sheldan.abstracto.core.command.models.database.ACommand; import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService; import dev.sheldan.abstracto.core.command.service.management.CommandManagementService; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannelGroup; import dev.sheldan.abstracto.core.models.database.AServer; @@ -16,8 +15,6 @@ import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.Optional; - @Component public class ChannelGroupServiceBean implements ChannelGroupService { @@ -55,8 +52,7 @@ public class ChannelGroupServiceBean implements ChannelGroupService { @Override public void addChannelToChannelGroup(String channelGroupName, Long channelId, Long serverId) { - Optional aChannel = channelManagementService.loadChannel(channelId); - AChannel channel = aChannel.orElseThrow(() -> new ChannelNotFoundException(channelId, serverId)); + AChannel channel = channelManagementService.loadChannel(channelId); addChannelToChannelGroup(channelGroupName, channel); } @@ -77,8 +73,7 @@ public class ChannelGroupServiceBean implements ChannelGroupService { @Override public void removeChannelFromChannelGroup(String channelGroupName, Long channelId, Long serverId) { - Optional aChannel = channelManagementService.loadChannel(channelId); - AChannel channel = aChannel.orElseThrow(() -> new ChannelNotFoundException(channelId, serverId)); + AChannel channel = channelManagementService.loadChannel(channelId); removeChannelFromChannelGroup(channelGroupName, channel); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java index 02391f536..ae82e49da 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java @@ -3,12 +3,13 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.CategoryNotFoundException; import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.requests.restaction.MessageAction; import org.apache.commons.lang3.StringUtils; @@ -50,22 +51,22 @@ public class ChannelServiceBean implements ChannelService { return sendTextToChannel(text, textChannel); } else { log.error("Channel {} to post towards was not found in server {}", channel.getId(), channel.getServer().getId()); - throw new ChannelNotFoundException(channel.getId(), channel.getServer().getId()); + throw new ChannelNotFoundException(channel.getId()); } } else { log.error("Guild {} was not found when trying to post a message", channel.getServer().getId()); - throw new GuildException(channel.getServer().getId()); + throw new GuildNotFoundException(channel.getServer().getId()); } } @Override public CompletableFuture sendMessageToAChannel(Message message, AChannel channel) { - Optional textChannelOpt = botService.getTextChannelFromServer(channel.getServer().getId(), channel.getId()); + Optional textChannelOpt = botService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); if(textChannelOpt.isPresent()) { TextChannel textChannel = textChannelOpt.get(); return sendMessageToChannel(message, textChannel); } - throw new ChannelNotFoundException(channel.getId(), channel.getServer().getId()); + throw new ChannelNotFoundException(channel.getId()); } @Override @@ -87,11 +88,11 @@ public class ChannelServiceBean implements ChannelService { return sendEmbedToChannel(embed, textChannel); } else { log.error("Channel {} to post towards was not found in server {}", channel.getId(), channel.getServer().getId()); - throw new ChannelNotFoundException(channel.getId(), guild.getIdLong()); + throw new ChannelNotFoundException(channel.getId()); } } else { log.error("Guild {} was not found when trying to post a message", channel.getServer().getId()); - throw new GuildException(channel.getServer().getId()); + throw new GuildNotFoundException(channel.getServer().getId()); } } @@ -102,11 +103,16 @@ public class ChannelServiceBean implements ChannelService { @Override public List> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel) { - Optional textChannelFromServer = botService.getTextChannelFromServer(channel.getServer().getId(), channel.getId()); + Optional textChannelFromServer = botService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); if(textChannelFromServer.isPresent()) { return sendMessageToSendToChannel(messageToSend, textChannelFromServer.get()); } - throw new ChannelNotFoundException(channel.getId(), channel.getServer().getId()); + throw new ChannelNotFoundException(channel.getId()); + } + + @Override + public CompletableFuture sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex) { + return sendEmbedToAChannel(messageToSend.getEmbeds().get(embedIndex), channel); } @Override @@ -134,22 +140,27 @@ public class ChannelServiceBean implements ChannelService { @Override public Optional getTextChannelInGuild(Long serverId, Long channelId) { - return botService.getTextChannelFromServer(serverId, channelId); + return botService.getTextChannelFromServerOptional(serverId, channelId); } @Override public void editMessageInAChannel(MessageToSend messageToSend, AChannel channel, Long messageId) { - Optional textChannelFromServer = botService.getTextChannelFromServer(channel.getServer().getId(), channel.getId()); + Optional textChannelFromServer = botService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); if(textChannelFromServer.isPresent()) { TextChannel textChannel = textChannelFromServer.get(); editMessageInAChannel(messageToSend, textChannel, messageId); } else { - throw new ChannelNotFoundException(channel.getId(), channel.getServer().getId()); + throw new ChannelNotFoundException(channel.getId()); } } @Override public void editMessageInAChannel(MessageToSend messageToSend, MessageChannel channel, Long messageId) { + editMessageInAChannelFuture(messageToSend, channel, messageId); + } + + @Override + public CompletableFuture editMessageInAChannelFuture(MessageToSend messageToSend, MessageChannel channel, Long messageId) { MessageAction messageAction; if(!StringUtils.isBlank(messageToSend.getMessage())) { messageAction = channel.editMessageById(messageId, messageToSend.getMessage()); @@ -163,7 +174,42 @@ public class ChannelServiceBean implements ChannelService { throw new AbstractoRunTimeException("Message to send did not contain anything to send."); } } - messageAction.queue(); + return messageAction.submit(); + } + + @Override + public CompletableFuture editEmbedMessageInAChannel(MessageEmbed embedToSend, MessageChannel channel, Long messageId) { + return channel.editMessageById(messageId, embedToSend).submit(); + } + + @Override + public CompletableFuture editTextMessageInAChannel(String text, MessageChannel channel, Long messageId) { + return channel.editMessageById(messageId, text).submit(); + } + + @Override + public List> editMessagesInAChannelFuture(MessageToSend messageToSend, MessageChannel channel, List messageIds) { + List> futures = new ArrayList<>(); + futures.add(editMessageInAChannelFuture(messageToSend, channel ,messageIds.get(0))); + for (int i = 1; i < messageIds.size(); i++) { + Long messageIdToUpdate = messageIds.get(i); + futures.add(channel.editMessageById(messageIdToUpdate, messageToSend.getEmbeds().get(i)).submit()); + } + return futures; + } + + @Override + public CompletableFuture removeFieldFromMessage(MessageChannel channel, Long messageId, Integer index) { + return removeFieldFromMessage(channel, messageId, index, 0); + } + + @Override + public CompletableFuture removeFieldFromMessage(MessageChannel channel, Long messageId, Integer index, Integer embedIndex) { + return channel.retrieveMessageById(messageId).submit().thenCompose(message -> { + EmbedBuilder embedBuilder = new EmbedBuilder(message.getEmbeds().get(embedIndex)); + embedBuilder.getFields().remove(index.intValue()); + return channel.editMessageById(messageId, embedBuilder.build()).submit(); + }); } @Override @@ -177,7 +223,7 @@ public class ChannelServiceBean implements ChannelService { if(textChannelById != null) { return textChannelById.delete().submit(); } - throw new ChannelNotFoundException(channelId, serverId); + throw new ChannelNotFoundException(channelId); } @Override @@ -198,11 +244,11 @@ public class ChannelServiceBean implements ChannelService { } throw new CategoryNotFoundException(categoryId, server.getId()); } - throw new GuildException(server.getId()); + throw new GuildNotFoundException(server.getId()); } @Override public Optional getChannelFromAChannel(AChannel channel) { - return botService.getTextChannelFromServer(channel.getServer().getId(), channel.getId()); + return botService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConditionServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConditionServiceBean.java new file mode 100644 index 000000000..a3b1fcab1 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ConditionServiceBean.java @@ -0,0 +1,45 @@ +package dev.sheldan.abstracto.core.service; + +import dev.sheldan.abstracto.core.exception.InvalidConditionParametersException; +import dev.sheldan.abstracto.core.models.ConditionContextInstance; +import dev.sheldan.abstracto.core.models.ConditionContextVariable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +@Component +public class ConditionServiceBean implements ConditionService { + + @Autowired + private List conditionList; + + @Override + public boolean checkConditions(ConditionContextInstance context) { + Optional matchingCondition = conditionList + .stream() + .filter(systemCondition -> systemCondition.getConditionName().equalsIgnoreCase(context.getConditionName())) + .findAny(); + return matchingCondition.map(systemCondition -> { + verifyConditionContext(context, systemCondition); + return systemCondition.checkCondition(context); + }).orElse(true); + } + + private void verifyConditionContext(ConditionContextInstance contextInstance, SystemCondition condition) { + for (ConditionContextVariable conditionContextVariable : condition.getExpectedContext().getExpectedVariables()) { + HashMap providedParameters = contextInstance.getParameters(); + if(!providedParameters.containsKey(conditionContextVariable.getName())) { + throw new InvalidConditionParametersException(String.format("Variable %s was not present", conditionContextVariable.getName())); + } + Class expectedType = conditionContextVariable.getType(); + Object providedParameter = providedParameters.get(conditionContextVariable.getName()); + if(!expectedType.isInstance(providedParameter)) { + throw new InvalidConditionParametersException(String.format("Variable %s was of type %s instead of %s.", + conditionContextVariable.getName(), providedParameter.getClass(), expectedType)); + } + } + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/EmoteServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/EmoteServiceBean.java index 1e544b51a..2eef7e377 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/EmoteServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/EmoteServiceBean.java @@ -86,7 +86,7 @@ public class EmoteServiceBean implements EmoteService { } @Override - public AEmote getEmoteOrFakeEmote(String emoteKey, Long serverId) { + public AEmote getEmoteOrDefaultEmote(String emoteKey, Long serverId) { Optional emoteOptional = emoteManagementService.loadEmoteByName(emoteKey, serverId); return emoteOptional.orElseGet(() -> AEmote.builder().emoteKey(getDefaultEmote(emoteKey)).custom(false).name(emoteKey).build()); } @@ -97,13 +97,9 @@ public class EmoteServiceBean implements EmoteService { } @Override - public boolean isReactionEmoteAEmote(MessageReaction.ReactionEmote reaction, AEmote storedEmote, Emote actualEmoteInGuild) { + public boolean isReactionEmoteAEmote(MessageReaction.ReactionEmote reaction, AEmote storedEmote) { if(reaction.isEmote() && storedEmote.getCustom()) { - if(actualEmoteInGuild != null) { - return actualEmoteInGuild.equals(reaction.getEmote()); - } else { - return false; - } + return reaction.getEmote().getIdLong() == storedEmote.getEmoteId(); } else if(reaction.isEmoji()){ return reaction.getEmoji().equals(storedEmote.getEmoteKey()); } @@ -128,4 +124,16 @@ public class EmoteServiceBean implements EmoteService { } } + @Override + public AEmote getFakeEmote(Object object) { + if(object instanceof Emote) { + Emote emote = (Emote) object; + return AEmote.builder().fake(true).emoteKey(emote.getName()).custom(true).animated(emote.isAnimated()).emoteId(emote.getIdLong()).build(); + } else if(object instanceof String) { + String emoteText = (String) object; + return AEmote.builder().fake(true).custom(false).emoteKey(emoteText).build(); + } + throw new IllegalArgumentException("Not possible to convert given object to AEmote."); + } + } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java index 8120575e9..a1418eece 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java @@ -1,7 +1,7 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedReaction; import dev.sheldan.abstracto.core.models.cache.*; @@ -84,7 +84,7 @@ public class MessageCacheBean implements MessageCache { CompletableFuture future = new CompletableFuture<>(); Optional guildOptional = botService.getGuildById(guildId); if(guildOptional.isPresent()) { - Optional textChannelByIdOptional = botService.getTextChannelFromServer(guildOptional.get(), textChannelId); + Optional textChannelByIdOptional = botService.getTextChannelFromServerOptional(guildOptional.get(), textChannelId); if(textChannelByIdOptional.isPresent()) { TextChannel textChannel = textChannelByIdOptional.get(); textChannel.retrieveMessageById(messageId).queue(message -> @@ -100,11 +100,11 @@ public class MessageCacheBean implements MessageCache { ); } else { log.error("Not able to load message {} in channel {} in guild {}. Text channel not found.", messageId, textChannelId, guildId); - future.completeExceptionally(new ChannelNotFoundException(textChannelId, guildId)); + future.completeExceptionally(new ChannelNotFoundException(textChannelId)); } } else { log.error("Not able to load message {} in channel {} in guild {}. Guild not found.", messageId, textChannelId, guildId); - future.completeExceptionally(new GuildException(guildId)); + future.completeExceptionally(new GuildNotFoundException(guildId)); } return future; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java index 9f48e2c74..8f4d7b9c1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java @@ -1,7 +1,8 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.exception.EmoteNotDefinedException; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.ExceptionNotInServerException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.service.management.EmoteManagementService; @@ -44,8 +45,8 @@ public class MessageServiceBean implements MessageService { @Override public CompletableFuture addReactionToMessageWithFuture(String emoteKey, Long serverId, Message message) { + AEmote emote = emoteService.getEmoteOrDefaultEmote(emoteKey, serverId); Optional guildByIdOptional = botService.getGuildById(serverId); - AEmote emote = emoteService.getEmoteOrFakeEmote(emoteKey, serverId); if(guildByIdOptional.isPresent()) { Guild guild = guildByIdOptional.get(); if(Boolean.TRUE.equals(emote.getCustom())) { @@ -61,10 +62,129 @@ public class MessageServiceBean implements MessageService { } } else { log.error("Cannot add reaction, guild not found {}", serverId); - throw new GuildException(serverId); + throw new GuildNotFoundException(serverId); } } + @Override + public CompletableFuture addReactionToMessageWithFuture(AEmote emote, Long serverId, Message message) { + if(Boolean.TRUE.equals(emote.getCustom())) { + return addReactionToMessageWithFuture(emote.getEmoteId(), serverId, message); + } else { + return message.addReaction(emote.getEmoteKey()).submit(); + } + } + + @Override + public CompletableFuture addReactionToMessageWithFuture(Long emoteId, Long serverId, Message message) { + Emote emoteById = botService.getInstance().getEmoteById(emoteId); + if(emoteById == null) { + throw new ExceptionNotInServerException(emoteId); + } + return message.addReaction(emoteById).submit(); + } + + @Override + public CompletableFuture removeReactionFromMessageWithFuture(AEmote emote, Long serverId, Message message) { + if(Boolean.TRUE.equals(emote.getCustom())) { + Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId()); + if(emoteById == null) { + throw new ExceptionNotInServerException(emote.getEmoteId()); + } + return message.removeReaction(emoteById).submit(); + } else { + return message.removeReaction(emote.getEmoteKey()).submit(); + } + } + + @Override + public CompletableFuture clearReactionFromMessageWithFuture(AEmote emote, Message message) { + if(Boolean.TRUE.equals(emote.getCustom())) { + Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId()); + if(emoteById == null) { + throw new ExceptionNotInServerException(emote.getEmoteId()); + } + return message.clearReactions(emoteById).submit(); + } else { + return message.clearReactions(emote.getEmoteKey()).submit(); + } + } + + @Override + public CompletableFuture removeReactionFromMessageWithFuture(Integer emoteId, Long serverId, Message message) { + AEmote emote = emoteManagementService.loadEmote(emoteId); + return removeReactionFromMessageWithFuture(emote, serverId, message); + } + + @Override + public CompletableFuture clearReactionFromMessageWithFuture(Integer emoteId, Long serverId, Message message) { + AEmote emote = emoteManagementService.loadEmote(emoteId); + return clearReactionFromMessageWithFuture(emote, message); + } + + @Override + public CompletableFuture removeReactionFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId) { + TextChannel channel = botService.getTextChannelFromServer(serverId, channelId); + Integer emoteId = emote.getId(); + return channel.retrieveMessageById(messageId).submit() + .thenCompose(message1 -> removeReactionFromMessageWithFuture(emoteId, serverId, message1)); + } + + @Override + public CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId, Long userId) { + Guild guild = botService.getGuildByIdNullable(serverId); + Member memberById = guild.getMemberById(userId); + return removeReactionOfUserFromMessageWithFuture(emote, serverId, channelId, messageId, memberById); + } + + @Override + public CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId, Member member) { + TextChannel channel = botService.getTextChannelFromServer(serverId, channelId); + Integer emoteId = emote.getId(); + return channel.retrieveMessageById(messageId).submit() + .thenCompose(message1 -> removeReactionOfUserFromMessageWithFuture(emoteId, message1, member)); + } + + @Override + public CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Message message, Member member) { + if(Boolean.TRUE.equals(emote.getCustom())) { + Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId()); + if(emoteById == null) { + throw new ExceptionNotInServerException(emote.getEmoteId()); + } + return message.removeReaction(emoteById, member.getUser()).submit(); + } else { + return message.removeReaction(emote.getEmoteKey(), member.getUser()).submit(); + } + } + + @Override + public CompletableFuture removeReactionOfUserFromMessageWithFuture(Integer emoteId, Message message, Member member) { + AEmote emote = emoteManagementService.loadEmote(emoteId); + return removeReactionOfUserFromMessageWithFuture(emote, message, member); + } + + @Override + public CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Message message, Long userId) { + Member memberById = message.getGuild().getMemberById(userId); + return removeReactionOfUserFromMessageWithFuture(emote, message, memberById); + } + + @Override + public CompletableFuture removeReactionOfUserFromMessageWithFuture(Integer emoteId, Message message, Long userId) { + Member memberById = message.getGuild().getMemberById(userId); + AEmote emote = emoteManagementService.loadEmote(emoteId); + return removeReactionOfUserFromMessageWithFuture(emote, message, memberById); + } + + @Override + public CompletableFuture clearReactionFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId) { + TextChannel channel = botService.getTextChannelFromServer(serverId, channelId); + Integer emoteId = emote.getId(); + return channel.retrieveMessageById(messageId).submit() + .thenCompose(message1 -> clearReactionFromMessageWithFuture(emoteId, serverId, message1)); + } + @Override public List> addReactionsToMessageWithFuture(List emoteKeys, Long serverId, Message message) { List> futures = new ArrayList<>(); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java index 438cbc76e..944fc3ac4 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PostTargetServiceBean.java @@ -3,7 +3,7 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.config.FeatureConfig; import dev.sheldan.abstracto.core.config.PostTargetEnum; import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.exception.PostTargetNotFoundException; import dev.sheldan.abstracto.core.exception.PostTargetNotValidException; import dev.sheldan.abstracto.core.models.database.AServer; @@ -68,10 +68,10 @@ public class PostTargetServiceBean implements PostTargetService { } else { log.error("Incorrect post target configuration: {} points to {} on server {}", target.getName(), target.getChannelReference().getId(), target.getServerReference().getId()); - throw new ChannelNotFoundException(target.getChannelReference().getId(), target.getServerReference().getId()); + throw new ChannelNotFoundException(target.getChannelReference().getId()); } } else { - throw new GuildException(target.getServerReference().getId()); + throw new GuildNotFoundException(target.getServerReference().getId()); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/RoleServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/RoleServiceBean.java index dc96eed4c..cd21c03ab 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/RoleServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/RoleServiceBean.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.service; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; +import dev.sheldan.abstracto.core.exception.RoleDeletedException; import dev.sheldan.abstracto.core.exception.RoleNotFoundInDBException; import dev.sheldan.abstracto.core.exception.RoleNotFoundInGuildException; import dev.sheldan.abstracto.core.models.database.ARole; @@ -16,6 +17,7 @@ import org.springframework.stereotype.Component; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @Component @@ -32,31 +34,99 @@ public class RoleServiceBean implements RoleService { public void addRoleToUser(AUserInAServer aUserInAServer, ARole role) { Optional guildById = botService.getGuildById(aUserInAServer.getServerReference().getId()); if(guildById.isPresent()) { - Guild guild = guildById.get(); - Role roleById = guild.getRoleById(role.getId()); - if(roleById != null) { - guild.addRoleToMember(aUserInAServer.getUserReference().getId(), roleById).queue(); - } else { - throw new RoleNotFoundInGuildException(role.getId(), aUserInAServer.getServerReference().getId()); - } + addRoleToUser(guildById.get(), role, aUserInAServer.getUserReference().getId()); } else { - throw new GuildException(aUserInAServer.getServerReference().getId()); + throw new GuildNotFoundException(aUserInAServer.getServerReference().getId()); } } + @Override + public CompletableFuture addRoleToUserFuture(AUserInAServer aUserInAServer, ARole role) { + Optional guildById = botService.getGuildById(aUserInAServer.getServerReference().getId()); + if(guildById.isPresent()) { + return addRoleToUserFuture(guildById.get(), role, aUserInAServer.getUserReference().getId()); + } else { + throw new GuildNotFoundException(aUserInAServer.getServerReference().getId()); + } + } + + @Override + public void addRoleToMember(Member member, ARole role) { + Guild guild = member.getGuild(); + addRoleToUser(guild, role, member.getIdLong()); + } + + @Override + public CompletableFuture addRoleToMemberFuture(Member member, ARole role) { + Guild guild = member.getGuild(); + return addRoleToUserFuture(guild, role, member.getIdLong()); + } + + @Override + public void removeRoleFromMember(Member member, ARole role) { + Guild guild = member.getGuild(); + removeRoleFromUser(guild, role, member.getIdLong()); + } + + @Override + public CompletableFuture removeRoleFromMemberFuture(Member member, ARole role) { + Guild guild = member.getGuild(); + return removeRoleFromUserFuture(guild, role, member.getIdLong()); + } + + private CompletableFuture addRoleToUserFuture(Guild guild, ARole role, Long userId) { + if(role.getDeleted()) { + log.warn("Not possible to add role to user. Role {} was marked as deleted.", role.getId()); + throw new RoleDeletedException(role); + } + Role roleById = guild.getRoleById(role.getId()); + if(roleById != null) { + return guild.addRoleToMember(userId, roleById).submit(); + } else { + throw new RoleNotFoundInGuildException(role.getId(), guild.getIdLong()); + } + } + + + private void addRoleToUser(Guild guild, ARole role, Long userId) { + addRoleToUserFuture(guild, role, userId); + } + + private CompletableFuture removeRoleFromUserFuture(Guild guild, ARole role, Long userId) { + if(role.getDeleted()) { + log.warn("Not possible to remove role from user. Role {} was marked as deleted.", role.getId()); + throw new RoleDeletedException(role); + } + Role roleById = guild.getRoleById(role.getId()); + if(roleById != null) { + return guild.removeRoleFromMember(userId, roleById).submit(); + } else { + throw new RoleNotFoundInGuildException(role.getId(), guild.getIdLong()); + } + } + + + private void removeRoleFromUser(Guild guild, ARole role, Long userId) { + removeRoleFromUserFuture(guild, role, userId); + } + @Override public void removeRoleFromUser(AUserInAServer aUserInAServer, ARole role) { Optional guildById = botService.getGuildById(aUserInAServer.getServerReference().getId()); if(guildById.isPresent()) { - Guild guild = guildById.get(); - Role roleById = guild.getRoleById(role.getId()); - if(roleById != null) { - guild.removeRoleFromMember(aUserInAServer.getUserReference().getId(), roleById).queue(); - } else { - throw new RoleNotFoundInGuildException(role.getId(), aUserInAServer.getServerReference().getId()); - } + removeRoleFromUser(guildById.get(), role, aUserInAServer.getUserReference().getId()); } else { - throw new GuildException(aUserInAServer.getServerReference().getId()); + throw new GuildNotFoundException(aUserInAServer.getServerReference().getId()); + } + } + + @Override + public CompletableFuture removeRoleFromUserFuture(AUserInAServer aUserInAServer, ARole role) { + Optional guildById = botService.getGuildById(aUserInAServer.getServerReference().getId()); + if(guildById.isPresent()) { + return removeRoleFromUserFuture(guildById.get(), role, aUserInAServer.getUserReference().getId()); + } else { + throw new GuildNotFoundException(aUserInAServer.getServerReference().getId()); } } @@ -67,18 +137,22 @@ public class RoleServiceBean implements RoleService { @Override public void markDeleted(Long id, AServer server) { - Optional role = roleManagementService.findRole(id, server); - ARole role1 = role.orElseThrow(() -> new RoleNotFoundInDBException(id, server.getId())); + Optional role = roleManagementService.findRoleOptional(id); + ARole role1 = role.orElseThrow(() -> new RoleNotFoundInDBException(id)); roleManagementService.markDeleted(role1); } @Override public Role getRoleFromGuild(ARole role) { + if(role.getDeleted()) { + log.warn("Trying to load role {} which is marked as deleted.", role.getId()); + throw new RoleDeletedException(role); + } Optional guildById = botService.getGuildById(role.getServer().getId()); if(guildById.isPresent()) { return guildById.get().getRoleById(role.getId()); } else { - throw new GuildException(role.getServer().getId()); + throw new GuildNotFoundException(role.getServer().getId()); } } @@ -106,4 +180,11 @@ public class RoleServiceBean implements RoleService { public boolean isRoleInServer(ARole role) { return getRoleFromGuild(role) != null; } + + @Override + public boolean canBotInteractWithRole(ARole role) { + Role jdaRole = getRoleFromGuild(role); + Member selfMember = jdaRole.getGuild().getSelfMember(); + return selfMember.canInteract(jdaRole); + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/SetupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/SetupServiceBean.java index 9914ee3db..6b3ec170d 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/SetupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/SetupServiceBean.java @@ -125,7 +125,7 @@ public class SetupServiceBean implements SetupService { if(throwable instanceof Templatable) { Templatable exception = (Templatable) throwable; String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel()); - Optional channelOptional = botService.getTextChannelFromServer(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId()); + Optional channelOptional = botService.getTextChannelFromServerOptional(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId()); channelOptional.ifPresent(channel -> channelService.sendTextToChannel(text, channel)); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java index b1b7bb855..041bc4200 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java @@ -81,12 +81,13 @@ public class StartupServiceBean implements Startup { } + // TODO mark deleted roles ad deleted, use intersect for that private void synchronizeRolesOf(Guild guild, AServer existingAServer){ List existingRoles = guild.getRoles(); List knownARoles = existingAServer.getRoles(); Set knownRolesId = SnowflakeUtils.getOwnItemsIds(knownARoles); Set availableRoles = SnowflakeUtils.getSnowflakeIds(existingRoles); - Set newRoles = SetUtils.disjunction(availableRoles, knownRolesId); + Set newRoles = SetUtils.difference(availableRoles, knownRolesId); newRoles.forEach(aLong -> { ARole newRole = roleManagementService.createRole(aLong, existingAServer); log.trace("Adding new role: {}", aLong); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java index a6d056694..4fd4b33f1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java @@ -24,10 +24,15 @@ public class ChannelManagementServiceBean implements ChannelManagementService { private LockService lockService; @Override - public Optional loadChannel(Long id) { + public Optional loadChannelOptional(Long id) { return repository.findById(id); } + @Override + public AChannel loadChannel(Long id) { + return loadChannelOptional(id).orElseThrow(() -> new ChannelNotFoundException(id)); + } + @Override public AChannel createChannel(Long id, AChannelType type, AServer server) { lockService.lockTable(TableLocks.CHANNELS); @@ -42,15 +47,14 @@ public class ChannelManagementServiceBean implements ChannelManagementService { .build(); return repository.save(build); } else { - Optional channelOptional = loadChannel(id); + Optional channelOptional = loadChannelOptional(id); return channelOptional.orElse(null); } } @Override public AChannel markAsDeleted(Long id) { - Optional channelOptional = loadChannel(id); - AChannel channel = channelOptional.orElseThrow(() -> new ChannelNotFoundException(id, 0L)); + AChannel channel = loadChannel(id); channel.setDeleted(true); return channel; } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java index bd6080aa8..2848fbec3 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementServiceBean.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.service.management; import dev.sheldan.abstracto.core.exception.EmoteNotFoundException; +import dev.sheldan.abstracto.core.exception.EmoteNotFoundInDbException; import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.repository.EmoteRepository; @@ -24,22 +25,41 @@ public class EmoteManagementServiceBean implements EmoteManagementService { private DefaultEmoteManagementService defaultEmoteManagementService; @Override - public Optional loadEmote(Long id) { + public Optional loadEmoteOptional(Integer id) { return repository.findById(id); } @Override - public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId) { - AServer server = serverManagementService.loadOrCreate(serverId); - return this.createCustomEmote(name, emoteKey, emoteId, animated, server); + public AEmote loadEmote(Integer id) { + return loadEmoteOptional(id).orElseThrow(() -> new EmoteNotFoundInDbException(id)); } @Override - public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, AServer server) { - validateEmoteName(name); + public Optional loadEmote(Long id) { + return repository.findByEmoteId(id); + } + + @Override + public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId, boolean validateName) { + AServer server = serverManagementService.loadOrCreate(serverId); + return this.createCustomEmote(name, emoteKey, emoteId, animated, server, validateName); + } + + @Override + public AEmote createCustomEmote(String name, AEmote fakeEmote, Long serverId, boolean validateName) { + AServer server = serverManagementService.loadOrCreate(serverId); + return this.createCustomEmote(name, fakeEmote.getEmoteKey(), fakeEmote.getEmoteId(), fakeEmote.getAnimated(), server, validateName); + } + + @Override + public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, AServer server, boolean validateName) { + if(validateName) { + validateEmoteName(name); + } AEmote emoteToCreate = AEmote .builder() .custom(true) + .changeable(true) .name(name) .animated(animated) .emoteId(emoteId) @@ -51,17 +71,20 @@ public class EmoteManagementServiceBean implements EmoteManagementService { } @Override - public AEmote createDefaultEmote(String name, String emoteKey, Long serverId) { + public AEmote createDefaultEmote(String name, String emoteKey, Long serverId, boolean validateName) { AServer server = serverManagementService.loadOrCreate(serverId); - return createDefaultEmote(name, emoteKey, server); + return createDefaultEmote(name, emoteKey, server, validateName); } @Override - public AEmote createDefaultEmote(String name, String emoteKey, AServer server) { - validateEmoteName(name); + public AEmote createDefaultEmote(String name, String emoteKey, AServer server, boolean validateName) { + if(validateName) { + validateEmoteName(name); + } AEmote emoteToCreate = AEmote .builder() .custom(false) + .changeable(true) .name(name) .emoteKey(emoteKey) .serverRef(server) @@ -87,7 +110,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService { AEmote emote; Optional emoteOptional = loadEmoteByName(name, server); if(!emoteOptional.isPresent()) { - emote = this.createCustomEmote(name, emoteKey, emoteId, animated, server); + emote = this.createCustomEmote(name, emoteKey, emoteId, animated, server, true); } else { emote = emoteOptional.get(); emote.setEmoteKey(emoteKey); @@ -105,7 +128,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService { AEmote emoteBeingSet; Optional emoteOptional = loadEmoteByName(name, serverId); if(!emoteOptional.isPresent()) { - emoteBeingSet = this.createCustomEmote(name, emote.getName(), emote.getIdLong(), emote.isAnimated(), server); + emoteBeingSet = this.createCustomEmote(name, emote.getName(), emote.getIdLong(), emote.isAnimated(), server, true); } else { emoteBeingSet = emoteOptional.get(); emoteBeingSet.setCustom(true); @@ -123,7 +146,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService { AEmote emoteBeingSet; Optional emoteOptional = loadEmoteByName(name, serverId); if(!emoteOptional.isPresent()) { - emoteBeingSet = this.createDefaultEmote(name, emoteKey, server); + emoteBeingSet = this.createDefaultEmote(name, emoteKey, server, true); } else { emoteBeingSet = emoteOptional.get(); emoteBeingSet.setEmoteKey(emoteKey); @@ -133,12 +156,50 @@ public class EmoteManagementServiceBean implements EmoteManagementService { return emoteBeingSet; } + @Override + public AEmote setEmoteToAEmote(String name, AEmote emote, Long serverId) { + Optional emoteOptional = loadEmoteByName(name, serverId); + if(!emoteOptional.isPresent()) { + return createEmote(name, emote, serverId, true); + } else { + AEmote emoteBeingSet = emoteOptional.get(); + if(emote.getCustom()) { + emoteBeingSet.setCustom(emote.getCustom()); + emoteBeingSet.setEmoteId(emote.getEmoteId()); + emoteBeingSet.setEmoteKey(emote.getEmoteKey()); + } else { + emoteBeingSet.setCustom(false); + emoteBeingSet.setEmoteKey(emote.getEmoteKey()); + } + return emoteBeingSet; + } + } + + @Override + public AEmote createEmote(String name, AEmote emote, Long serverId, boolean validateName) { + if(emote.getCustom()) { + return this.createCustomEmote(name, emote, serverId, validateName); + } else { + return this.createDefaultEmote(name, emote.getEmoteKey(), serverId, validateName); + } + } + @Override public boolean emoteExists(String name, Long serverId) { AServer server = serverManagementService.loadOrCreate(serverId); return emoteExists(name, server); } + @Override + public boolean emoteExists(Long emoteId) { + return repository.existsByEmoteId(emoteId); + } + + @Override + public void deleteEmote(AEmote aEmote) { + repository.delete(aEmote); + } + @Override public boolean emoteExists(String name, AServer server) { return repository.existsByNameAndServerRef(name, server); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java index cb260b359..b83218c1c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/PostTargetManagementBean.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.service.management; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.exception.PostTargetNotValidException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AServer; @@ -12,7 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; -import java.util.Optional; @Service @Slf4j @@ -56,15 +54,13 @@ public class PostTargetManagementBean implements PostTargetManagement { @Override public PostTarget createOrUpdate(String name, AServer server, Long channelId) { - Optional dbChannelOpt = channelManagementService.loadChannel(channelId); - AChannel dbChannel = dbChannelOpt.orElseThrow(() -> new ChannelNotFoundException(channelId, server.getId())); + AChannel dbChannel = channelManagementService.loadChannel(channelId); return createOrUpdate(name, server, dbChannel); } @Override public PostTarget createOrUpdate(String name, Long serverId, Long channelId) { - Optional dbChannelOpt = channelManagementService.loadChannel(channelId); - AChannel dbChannel = dbChannelOpt.orElseThrow(() -> new ChannelNotFoundException(channelId, serverId)); + AChannel dbChannel = channelManagementService.loadChannel(channelId); AServer dbServer = serverManagementService.loadOrCreate(serverId); return createOrUpdate(name, dbServer, dbChannel); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementServiceBean.java index 0b7404072..c781685f7 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementServiceBean.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.service.management; +import dev.sheldan.abstracto.core.exception.RoleNotFoundInDBException; import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.repository.RoleRepository; @@ -26,10 +27,15 @@ public class RoleManagementServiceBean implements RoleManagementService { } @Override - public Optional findRole(Long id, AServer server) { + public Optional findRoleOptional(Long id) { return repository.findById(id); } + @Override + public ARole findRole(Long id) { + return findRoleOptional(id).orElseThrow(() -> new RoleNotFoundInDBException(id)); + } + @Override public void markDeleted(ARole role) { role.setDeleted(true); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java index c3c9d34b5..da03795ee 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementServiceBean.java @@ -1,6 +1,6 @@ package dev.sheldan.abstracto.core.service.management; -import dev.sheldan.abstracto.core.exception.GuildException; +import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.database.*; import dev.sheldan.abstracto.core.repository.ServerRepository; import lombok.extern.slf4j.Slf4j; @@ -37,6 +37,16 @@ public class ServerManagementServiceBean implements ServerManagementService { } } + @Override + public AServer loadServer(Long id) { + return loadServerOptional(id).orElseThrow(() -> new GuildNotFoundException(id)); + } + + @Override + public Optional loadServerOptional(Long id) { + return repository.findById(id); + } + @Override public void addChannelToServer(AServer server, AChannel channel) { server.getChannels().add(channel); @@ -51,9 +61,8 @@ public class ServerManagementServiceBean implements ServerManagementService { @Override public AUserInAServer addUserToServer(Long serverId, Long userId) { log.info("Adding user {} to server {}", userId, serverId); - Optional server = repository.findById(serverId); AUser user = userManagementService.loadUser(userId); - AServer serverReference = server.orElseThrow(() -> new GuildException(serverId)); + AServer serverReference = loadServer(serverId); AUserInAServer aUserInAServer = AUserInAServer.builder().serverReference(serverReference).userReference(user).build(); serverReference.getUsers().add(aUserInAServer); return aUserInAServer; diff --git a/abstracto-application/core/core-impl/src/main/resources/config/application.properties b/abstracto-application/core/core-impl/src/main/resources/config/application.properties index 26e9a98a8..67ae68e26 100644 --- a/abstracto-application/core/core-impl/src/main/resources/config/application.properties +++ b/abstracto-application/core/core-impl/src/main/resources/config/application.properties @@ -1,12 +1,7 @@ -spring.jpa.show-sql = false -spring.jpa.hibernate.ddl-auto = none spring.jpa.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy spring.jpa.properties.hibernate.format_sql = false -log4j.logger.org.hibernate.SQL=info -log4j.logger.org.hibernate.type.descriptor.sql=trace -log4j.logger.org.hibernate.type=trace spring.jpa.properties.hibernate.generate_statistics = false spring.jpa.properties.hibernate.cache.use_second_level_cache=true diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/emote.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/emote.xml index c275eb76f..0412b8ecd 100644 --- a/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/emote.xml +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/emote.xml @@ -14,6 +14,7 @@ + diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/Command.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/Command.java index 34de556f7..2cf49bb51 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/Command.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/Command.java @@ -5,8 +5,11 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.listener.FeatureAware; +import java.util.concurrent.CompletableFuture; + public interface Command extends FeatureAware { - CommandResult execute(CommandContext commandContext); + default CommandResult execute(CommandContext commandContext) {return CommandResult.fromSuccess();}; + default CompletableFuture executeAsync(CommandContext commandContext) {return CompletableFuture.completedFuture(CommandResult.fromSuccess());}; CommandConfiguration getConfiguration(); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandDisallowedCondition.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandDisallowedCondition.java index 315ced477..9b70b96af 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandDisallowedCondition.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandDisallowedCondition.java @@ -2,7 +2,7 @@ package dev.sheldan.abstracto.core.command.condition; import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.command.execution.CommandContext; -import dev.sheldan.abstracto.core.command.models.InsufficientPermissionMessage; +import dev.sheldan.abstracto.core.command.models.exception.InsufficientPermissionMessage; import dev.sheldan.abstracto.core.command.models.database.ACommand; import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer; import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureEnabledCondition.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureEnabledCondition.java index 891eb2d0d..0121f76e2 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureEnabledCondition.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureEnabledCondition.java @@ -2,7 +2,7 @@ package dev.sheldan.abstracto.core.command.condition; import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.command.execution.CommandContext; -import dev.sheldan.abstracto.core.command.models.FeatureDisabledMessage; +import dev.sheldan.abstracto.core.command.models.exception.FeatureDisabledMessage; import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.service.FeatureConfigService; import dev.sheldan.abstracto.core.service.FeatureFlagService; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureModeCondition.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureModeCondition.java index 5fe8746c4..ea5521f28 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureModeCondition.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/FeatureModeCondition.java @@ -2,7 +2,7 @@ package dev.sheldan.abstracto.core.command.condition; import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.command.execution.CommandContext; -import dev.sheldan.abstracto.core.command.models.IncorrectFeatureModeMessage; +import dev.sheldan.abstracto.core.command.models.exception.IncorrectFeatureModeMessage; import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.models.database.AFeatureMode; import dev.sheldan.abstracto.core.service.FeatureConfigService; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/ImmuneUserCondition.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/ImmuneUserCondition.java index bc500d47d..714b31680 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/ImmuneUserCondition.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/condition/ImmuneUserCondition.java @@ -2,7 +2,7 @@ package dev.sheldan.abstracto.core.command.condition; import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.command.execution.CommandContext; -import dev.sheldan.abstracto.core.command.models.UserImmuneMessage; +import dev.sheldan.abstracto.core.command.models.exception.UserImmuneMessage; import dev.sheldan.abstracto.core.command.models.database.ACommand; import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer; import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java index 19bf702ce..75d16b2b8 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java @@ -13,6 +13,12 @@ public class CommandConfiguration { private String module; private String description; + @Builder.Default + private boolean async = false; + + @Builder.Default + private boolean reportsException = false; + @Builder.Default private List parameters = new ArrayList<>(); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterKeyValueWrongTypeException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterKeyValueWrongTypeException.java new file mode 100644 index 000000000..da4fc11f1 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterKeyValueWrongTypeException.java @@ -0,0 +1,27 @@ +package dev.sheldan.abstracto.core.command.exception; + +import dev.sheldan.abstracto.core.command.models.exception.CommandParameterKeyValueWrongTypeModel; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; + +import java.util.List; + +public class CommandParameterKeyValueWrongTypeException extends AbstractoRunTimeException implements Templatable { + + private CommandParameterKeyValueWrongTypeModel model; + + public CommandParameterKeyValueWrongTypeException(List expectedValues) { + super("Command parameter value did not have expected values present"); + this.model = CommandParameterKeyValueWrongTypeModel.builder().expectedValues(expectedValues).build(); + } + + @Override + public String getTemplateName() { + return "command_parameter_value_wrong_type_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandParameterKey.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandParameterKey.java new file mode 100644 index 000000000..e6ed1caeb --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandParameterKey.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.core.command.execution; + +import dev.sheldan.abstracto.core.command.exception.CommandParameterKeyValueWrongTypeException; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public interface CommandParameterKey { + static > T getEnumFromKey(Class clazz, String key) { + try { + if(clazz != null && key != null ) { + return Enum.valueOf(clazz, key.trim().toUpperCase()); + } + } catch (IllegalArgumentException e) { + List ts = Arrays.asList(clazz.getEnumConstants()); + List keys = ts.stream().map(Enum::toString).map(String::toLowerCase).collect(Collectors.toList()); + throw new CommandParameterKeyValueWrongTypeException(keys); + } + throw new IllegalArgumentException("Clazz and key must not be null"); + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java index df4b82595..3d922511d 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandResult.java @@ -23,6 +23,10 @@ public class CommandResult { return CommandResult.builder().result(ResultState.SELF_DESTRUCT).build(); } + public static CommandResult fromReportedError() { + return CommandResult.builder().result(ResultState.REPORTED_ERROR).build(); + } + public static CommandResult fromError(String message){ return CommandResult.builder().result(ResultState.ERROR).message(message).build(); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java index 6089fa8bc..830604ac6 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/execution/ResultState.java @@ -1,5 +1,5 @@ package dev.sheldan.abstracto.core.command.execution; public enum ResultState { - ERROR, SUCCESSFUL, IGNORED, CONDITION, SELF_DESTRUCT + ERROR, SUCCESSFUL, IGNORED, CONDITION, SELF_DESTRUCT, REPORTED_ERROR } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/CommandParameterKeyValueWrongTypeModel.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/CommandParameterKeyValueWrongTypeModel.java new file mode 100644 index 000000000..e3e71b54a --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/CommandParameterKeyValueWrongTypeModel.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.core.command.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class CommandParameterKeyValueWrongTypeModel { + private List expectedValues; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/FeatureDisabledMessage.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/FeatureDisabledMessage.java similarity index 79% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/FeatureDisabledMessage.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/FeatureDisabledMessage.java index 906fb5430..80994da4f 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/FeatureDisabledMessage.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/FeatureDisabledMessage.java @@ -1,4 +1,4 @@ -package dev.sheldan.abstracto.core.command.models; +package dev.sheldan.abstracto.core.command.models.exception; import dev.sheldan.abstracto.core.config.FeatureConfig; import lombok.Builder; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/GenericExceptionModel.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/GenericExceptionModel.java new file mode 100644 index 000000000..f4dca37c9 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/GenericExceptionModel.java @@ -0,0 +1,26 @@ +package dev.sheldan.abstracto.core.command.models.exception; + +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.templating.Templatable; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class GenericExceptionModel { + private FullUser user; + private Throwable throwable; + + public Templatable getTemplate() { + Throwable current = throwable; + while(!(current instanceof Templatable) && (current.getCause() != null && !current.getCause().equals(current))) { + current = current.getCause(); + } + if(current instanceof Templatable) { + return (Templatable) current; + } + return null; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/IncorrectFeatureModeMessage.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/IncorrectFeatureModeMessage.java similarity index 83% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/IncorrectFeatureModeMessage.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/IncorrectFeatureModeMessage.java index 06a280540..f5914f898 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/IncorrectFeatureModeMessage.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/IncorrectFeatureModeMessage.java @@ -1,4 +1,4 @@ -package dev.sheldan.abstracto.core.command.models; +package dev.sheldan.abstracto.core.command.models.exception; import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.config.FeatureConfig; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/InsufficientPermissionMessage.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/InsufficientPermissionMessage.java similarity index 80% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/InsufficientPermissionMessage.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/InsufficientPermissionMessage.java index 7c1d4d8a5..725fa21ad 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/InsufficientPermissionMessage.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/InsufficientPermissionMessage.java @@ -1,4 +1,4 @@ -package dev.sheldan.abstracto.core.command.models; +package dev.sheldan.abstracto.core.command.models.exception; import lombok.Builder; import lombok.Getter; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/UserImmuneMessage.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/UserImmuneMessage.java similarity index 76% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/UserImmuneMessage.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/UserImmuneMessage.java index c66a6fb0c..209c28fe2 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/UserImmuneMessage.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/models/exception/UserImmuneMessage.java @@ -1,4 +1,4 @@ -package dev.sheldan.abstracto.core.command.models; +package dev.sheldan.abstracto.core.command.models.exception; import lombok.Builder; import lombok.Getter; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java new file mode 100644 index 000000000..a13cfa1ef --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.core.command.service; + +import dev.sheldan.abstracto.core.command.Command; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; + +public interface ExceptionService { + CommandResult reportExceptionToContext(Throwable exception, CommandContext context, Command command); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/AbstractoRunTimeException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/AbstractoRunTimeException.java index adb8399eb..8310ebfe8 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/AbstractoRunTimeException.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/AbstractoRunTimeException.java @@ -4,6 +4,12 @@ public class AbstractoRunTimeException extends RuntimeException { public AbstractoRunTimeException(String message) { super(message); } + public AbstractoRunTimeException() { + super(); + } + public AbstractoRunTimeException(Throwable throwable) { + super(throwable); + } public AbstractoRunTimeException(String message, Throwable cause) { super(message, cause); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java index e2beb1bbc..6aaa667b0 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java @@ -7,12 +7,10 @@ import java.util.HashMap; public class ChannelNotFoundException extends AbstractoRunTimeException implements Templatable { private final Long channelId; - private final Long guildId; - public ChannelNotFoundException(Long channelId, Long guildId) { - super(""); + public ChannelNotFoundException(Long channelId) { + super("Channel not found in database"); this.channelId = channelId; - this.guildId = guildId; } @Override @@ -24,7 +22,6 @@ public class ChannelNotFoundException extends AbstractoRunTimeException implemen public Object getTemplateModel() { HashMap param = new HashMap<>(); param.put("channelId", this.channelId); - param.put("guildID", this.guildId); return param; } } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java new file mode 100644 index 000000000..ce08d2217 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java @@ -0,0 +1,28 @@ +package dev.sheldan.abstracto.core.exception; + +import dev.sheldan.abstracto.templating.Templatable; + +import java.util.HashMap; +import java.util.List; + +public class EmoteNotFoundInDbException extends AbstractoRunTimeException implements Templatable { + + private final Integer emoteId; + + public EmoteNotFoundInDbException(Integer emoteId) { + super(""); + this.emoteId = emoteId; + } + + @Override + public String getTemplateName() { + return "emote_not_found_in_db_exception"; + } + + @Override + public Object getTemplateModel() { + HashMap param = new HashMap<>(); + param.put("emoteId", this.emoteId); + return param; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java new file mode 100644 index 000000000..168ca8fab --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.core.exception; + +import dev.sheldan.abstracto.core.models.exception.EmoteNotUsable; +import dev.sheldan.abstracto.templating.Templatable; +import net.dv8tion.jda.api.entities.Emote; + +public class EmoteNotUsableException extends AbstractoRunTimeException implements Templatable { + + private EmoteNotUsable model; + + public EmoteNotUsableException(Emote emote) { + super(""); + this.model = EmoteNotUsable.builder().emote(emote).build(); + } + + @Override + public String getTemplateName() { + return "emote_not_usable"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ExceptionNotInServerException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ExceptionNotInServerException.java new file mode 100644 index 000000000..e6fb118d8 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/ExceptionNotInServerException.java @@ -0,0 +1,24 @@ +package dev.sheldan.abstracto.core.exception; + +import dev.sheldan.abstracto.core.models.exception.EmoteNotInServerModel; +import dev.sheldan.abstracto.templating.Templatable; + +public class ExceptionNotInServerException extends AbstractoRunTimeException implements Templatable { + + private EmoteNotInServerModel model; + + public ExceptionNotInServerException(Long emoteId) { + super("Emote not available in server"); + this.model = EmoteNotInServerModel.builder().emoteId(emoteId).build(); + } + + @Override + public String getTemplateName() { + return "emote_not_available_in_server_exception"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/GuildException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java similarity index 72% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/GuildException.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java index d7fe62e2c..a36b05610 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/GuildException.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java @@ -4,15 +4,15 @@ import dev.sheldan.abstracto.templating.Templatable; import java.util.HashMap; -public class GuildException extends AbstractoRunTimeException implements Templatable { +public class GuildNotFoundException extends AbstractoRunTimeException implements Templatable { private final Long guildId; - public GuildException(String message, Long guildId) { + public GuildNotFoundException(String message, Long guildId) { super(message); this.guildId = guildId; } - public GuildException(Long guildId) { + public GuildNotFoundException(Long guildId) { super(""); this.guildId = guildId; } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/InvalidConditionParametersException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/InvalidConditionParametersException.java new file mode 100644 index 000000000..252410990 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/InvalidConditionParametersException.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.exception; + +public class InvalidConditionParametersException extends AbstractoRunTimeException { + public InvalidConditionParametersException(String message) { + super(message); + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleDeletedException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleDeletedException.java new file mode 100644 index 000000000..0072b5f72 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleDeletedException.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.core.exception; + +import dev.sheldan.abstracto.core.models.database.ARole; +import dev.sheldan.abstracto.core.models.exception.RoleDeletedModel; +import dev.sheldan.abstracto.templating.Templatable; + +public class RoleDeletedException extends AbstractoRunTimeException implements Templatable { + + private RoleDeletedModel model; + + public RoleDeletedException(ARole role) { + super("Role has been marked as deleted and cannot be used."); + this.model = RoleDeletedModel.builder().role(role).build(); + } + + @Override + public String getTemplateName() { + return ""; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleNotFoundInDBException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleNotFoundInDBException.java index c9840484e..972f55c31 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleNotFoundInDBException.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/RoleNotFoundInDBException.java @@ -7,12 +7,10 @@ import java.util.HashMap; public class RoleNotFoundInDBException extends AbstractoRunTimeException implements Templatable { private final Long roleId; - private final Long serverId; - public RoleNotFoundInDBException(Long roleId, Long serverId) { + public RoleNotFoundInDBException(Long roleId) { super(""); this.roleId = roleId; - this.serverId = serverId; } @Override @@ -24,7 +22,6 @@ public class RoleNotFoundInDBException extends AbstractoRunTimeException impleme public Object getTemplateModel() { HashMap param = new HashMap<>(); param.put("roleId", this.roleId); - param.put("serverId", this.serverId); return param; } } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedAddedListener.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedAddedListener.java index 763e3f8f2..e43a959f4 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedAddedListener.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedAddedListener.java @@ -2,8 +2,8 @@ package dev.sheldan.abstracto.core.listener; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AUserInAServer; -import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; public interface ReactedAddedListener extends FeatureAware { - void executeReactionAdded(CachedMessage message, MessageReaction reaction, AUserInAServer userAdding); + void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent event, AUserInAServer userAdding); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedRemovedListener.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedRemovedListener.java index 73c13d0b3..669a88280 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedRemovedListener.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/ReactedRemovedListener.java @@ -2,8 +2,8 @@ package dev.sheldan.abstracto.core.listener; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AUserInAServer; -import net.dv8tion.jda.api.entities.MessageReaction; +import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; public interface ReactedRemovedListener extends FeatureAware { - void executeReactionRemoved(CachedMessage message, MessageReaction reaction, AUserInAServer userRemoving); + void executeReactionRemoved(CachedMessage message, GuildMessageReactionRemoveEvent reaction, AUserInAServer userRemoving); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContext.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContext.java new file mode 100644 index 000000000..4deae8436 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContext.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.core.models; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class ConditionContext { + private List expectedVariables; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextInstance.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextInstance.java new file mode 100644 index 000000000..7b828523a --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextInstance.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.core.models; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.HashMap; + +@Getter +@Setter +@Builder +public class ConditionContextInstance { + private HashMap parameters; + private String conditionName; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextVariable.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextVariable.java new file mode 100644 index 000000000..efc2fda1f --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ConditionContextVariable.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class ConditionContextVariable { + private String name; + private Class type; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullEmote.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullEmote.java new file mode 100644 index 000000000..95e3c2bbc --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullEmote.java @@ -0,0 +1,27 @@ +package dev.sheldan.abstracto.core.models; + +import dev.sheldan.abstracto.core.models.database.AEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Emote; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class FullEmote implements Serializable { + private AEmote fakeEmote; + private Emote emote; + + public String getEmoteRepr() { + if(!fakeEmote.getCustom()) { + return fakeEmote.getEmoteKey(); + } else if(emote != null) { + return emote.getAsMention(); + } else { + return fakeEmote.getEmoteId().toString(); + } + } +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullRole.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullRole.java index d0b680f61..9273a66c5 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullRole.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FullRole.java @@ -12,4 +12,12 @@ import net.dv8tion.jda.api.entities.Role; public class FullRole { private ARole role; private Role serverRole; + + public String getRoleRepr() { + if(serverRole != null) { + return serverRole.getAsMention(); + } else { + return role.getId().toString(); + } + } } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java index 50494ab0e..e54c045cf 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/AEmote.java @@ -25,6 +25,7 @@ public class AEmote implements Serializable { @Column private String name; + // the way discord calls them and the unicode char for default Tweemoji emotes @Column @Setter private String emoteKey; @@ -61,6 +62,15 @@ public class AEmote implements Serializable { this.updated = Instant.now(); } + @Column(name = "changeable") + @Getter + @Setter + @Builder.Default + private boolean changeable = true; + + @Transient + private boolean fake; + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotInServerModel.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotInServerModel.java new file mode 100644 index 000000000..f390c5c8a --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotInServerModel.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.core.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class EmoteNotInServerModel { + private Long emoteId; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotUsable.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotUsable.java new file mode 100644 index 000000000..a0c6fe57a --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/EmoteNotUsable.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Emote; + +@Getter +@Setter +@Builder +public class EmoteNotUsable { + private Emote emote; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/RoleDeletedModel.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/RoleDeletedModel.java new file mode 100644 index 000000000..64962339a --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/RoleDeletedModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models.exception; + +import dev.sheldan.abstracto.core.models.database.ARole; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class RoleDeletedModel { + private ARole role; +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/BotService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/BotService.java index 8459623d8..eb7c3d80b 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/BotService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/BotService.java @@ -27,8 +27,11 @@ public interface BotService { CompletableFuture deleteMessage(Long channelId, Long messageId); CompletableFuture forceReloadMember(Member member); Optional getEmote(Long serverId, AEmote emote); - Optional getTextChannelFromServer(Guild serverId, Long textChannelId); - Optional getTextChannelFromServer(Long serverId, Long textChannelId); + Optional getEmote(AEmote emote); + Optional getTextChannelFromServerOptional(Guild serverId, Long textChannelId); + TextChannel getTextChannelFromServer(Guild serverId, Long textChannelId); + Optional getTextChannelFromServerOptional(Long serverId, Long textChannelId); + TextChannel getTextChannelFromServer(Long serverId, Long textChannelId); Optional getGuildById(Long serverId); Guild getGuildByIdNullable(Long serverId); Member getBotInGuild(AServer server); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java index fe021b349..57bd3966e 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java @@ -22,10 +22,17 @@ public interface ChannelService { CompletableFuture sendEmbedToAChannel(MessageEmbed embed, AChannel channel); CompletableFuture sendEmbedToChannel(MessageEmbed embed, MessageChannel channel); List> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel); + CompletableFuture sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex); List> sendMessageToSendToChannel(MessageToSend messageToSend, MessageChannel textChannel); Optional getTextChannelInGuild(Long serverId, Long channelId); void editMessageInAChannel(MessageToSend messageToSend, AChannel channel, Long messageId); void editMessageInAChannel(MessageToSend messageToSend, MessageChannel channel, Long messageId); + CompletableFuture editMessageInAChannelFuture(MessageToSend messageToSend, MessageChannel channel, Long messageId); + CompletableFuture editEmbedMessageInAChannel(MessageEmbed embedToSend, MessageChannel channel, Long messageId); + CompletableFuture editTextMessageInAChannel(String text, MessageChannel channel, Long messageId); + List> editMessagesInAChannelFuture(MessageToSend messageToSend, MessageChannel channel, List messageIds); + CompletableFuture removeFieldFromMessage(MessageChannel channel, Long messageId, Integer index); + CompletableFuture removeFieldFromMessage(MessageChannel channel, Long messageId, Integer index, Integer embedIndex); CompletableFuture deleteTextChannel(AChannel channel); CompletableFuture deleteTextChannel(Long serverId, Long channelId); List> sendEmbedTemplateInChannel(String templateKey, Object model, MessageChannel channel); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConditionService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConditionService.java new file mode 100644 index 000000000..5b21862d3 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/ConditionService.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.service; + +import dev.sheldan.abstracto.core.models.ConditionContextInstance; + +public interface ConditionService { + boolean checkConditions(ConditionContextInstance context); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/EmoteService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/EmoteService.java index 127308822..fbc36eb17 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/EmoteService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/EmoteService.java @@ -15,9 +15,10 @@ public interface EmoteService { String getEmoteAsMention(AEmote emote, Long serverId); String getUsableEmoteOrDefault(Long serverId, String name); void throwIfEmoteDoesNotExist(String emoteKey, Long serverId); - AEmote getEmoteOrFakeEmote(String emoteKey, Long serverId); + AEmote getEmoteOrDefaultEmote(String emoteKey, Long serverId); String getDefaultEmote(String emoteKey); - boolean isReactionEmoteAEmote(MessageReaction.ReactionEmote reaction, AEmote storedEmote, Emote actualEmoteInGuild); + boolean isReactionEmoteAEmote(MessageReaction.ReactionEmote reaction, AEmote storedEmote); Optional getReactionFromMessageByEmote(CachedMessage message, AEmote emote); boolean compareAEmote(AEmote a, AEmote b); + AEmote getFakeEmote(Object object); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java index e7bce80fa..440c83d5c 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/MessageService.java @@ -1,8 +1,10 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.templating.model.MessageToSend; +import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.User; @@ -13,6 +15,20 @@ import java.util.concurrent.CompletableFuture; public interface MessageService { void addReactionToMessage(String emoteKey, Long serverId, Message message); CompletableFuture addReactionToMessageWithFuture(String emoteKey, Long serverId, Message message); + CompletableFuture addReactionToMessageWithFuture(AEmote emote, Long serverId, Message message); + CompletableFuture addReactionToMessageWithFuture(Long emoteId, Long serverId, Message message); + CompletableFuture removeReactionFromMessageWithFuture(AEmote emote, Long serverId, Message message); + CompletableFuture clearReactionFromMessageWithFuture(AEmote emote, Message message); + CompletableFuture removeReactionFromMessageWithFuture(Integer emoteId, Long serverId, Message message); + CompletableFuture clearReactionFromMessageWithFuture(Integer emoteId, Long serverId, Message message); + CompletableFuture removeReactionFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId); + CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId, Long userId); + CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId, Member member); + CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Message message, Member member); + CompletableFuture removeReactionOfUserFromMessageWithFuture(Integer emoteId, Message message, Member member); + CompletableFuture removeReactionOfUserFromMessageWithFuture(AEmote emote, Message message, Long userId); + CompletableFuture removeReactionOfUserFromMessageWithFuture(Integer emoteId, Message message, Long userId); + CompletableFuture clearReactionFromMessageWithFuture(AEmote emote, Long serverId, Long channelId, Long messageId); List> addReactionsToMessageWithFuture(List emoteKeys, Long serverId, Message message); CompletableFuture deleteMessageInChannelInServer(Long serverId, Long channelId, Long messageId); CompletableFuture createStatusMessage(MessageToSend messageToSend, AChannel channel); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/RoleService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/RoleService.java index d0576d75a..3dd4b9617 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/RoleService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/RoleService.java @@ -7,10 +7,17 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import java.util.List; +import java.util.concurrent.CompletableFuture; public interface RoleService { void addRoleToUser(AUserInAServer aUserInAServer, ARole role); + CompletableFuture addRoleToUserFuture(AUserInAServer aUserInAServer, ARole role); + void addRoleToMember(Member member, ARole role); + CompletableFuture addRoleToMemberFuture(Member member, ARole role); + void removeRoleFromMember(Member member, ARole role); + CompletableFuture removeRoleFromMemberFuture(Member member, ARole role); void removeRoleFromUser(AUserInAServer aUserInAServer, ARole role); + CompletableFuture removeRoleFromUserFuture(AUserInAServer aUserInAServer, ARole role); void markDeleted(Role role, AServer server); void markDeleted(Long id, AServer server); Role getRoleFromGuild(ARole role); @@ -19,4 +26,5 @@ public interface RoleService { boolean memberHasRole(Member member, Role role); boolean memberHasRole(Member member, ARole role); boolean isRoleInServer(ARole role); + boolean canBotInteractWithRole(ARole role); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/SystemCondition.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/SystemCondition.java new file mode 100644 index 000000000..41d340638 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/SystemCondition.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.core.service; + +import dev.sheldan.abstracto.core.models.ConditionContext; +import dev.sheldan.abstracto.core.models.ConditionContextInstance; + +public interface SystemCondition { + boolean checkCondition(ConditionContextInstance conditionContext); + String getConditionName(); + ConditionContext getExpectedContext(); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java index 5b79dbe2e..fc033e6b5 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java @@ -7,7 +7,8 @@ import dev.sheldan.abstracto.core.models.database.AServer; import java.util.Optional; public interface ChannelManagementService { - Optional loadChannel(Long id); + Optional loadChannelOptional(Long id); + AChannel loadChannel(Long id); AChannel createChannel(Long id, AChannelType type, AServer server); AChannel markAsDeleted(Long id); boolean channelExists(Long id); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementService.java index 3b50540ef..d8ddf95f6 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/EmoteManagementService.java @@ -7,16 +7,23 @@ import net.dv8tion.jda.api.entities.Emote; import java.util.Optional; public interface EmoteManagementService { - Optional loadEmote(Long id); - AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId) ; - AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, AServer server) ; - AEmote createDefaultEmote(String name, String emoteKey, Long serverId) ; - AEmote createDefaultEmote(String name, String emoteKey, AServer server) ; + Optional loadEmoteOptional(Integer id); + AEmote loadEmote(Integer id); + AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId, boolean validateName); + AEmote createCustomEmote(String name, AEmote fakeEmote, Long serverId, boolean validateName); + AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, AServer server, boolean validateName); + AEmote createDefaultEmote(String name, String emoteKey, Long serverId, boolean validateName); + AEmote createDefaultEmote(String name, String emoteKey, AServer server, boolean validateName); Optional loadEmoteByName(String name, Long serverId); Optional loadEmoteByName(String name, AServer server); - AEmote setEmoteToCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId) ; - AEmote setEmoteToCustomEmote(String name, Emote emote, Long serverId) ; - AEmote setEmoteToDefaultEmote(String name, String emoteKey, Long serverId) ; + AEmote setEmoteToCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId); + AEmote setEmoteToCustomEmote(String name, Emote emote, Long serverId); + AEmote setEmoteToDefaultEmote(String name, String emoteKey, Long serverId); + AEmote setEmoteToAEmote(String name, AEmote emote, Long serverId); + AEmote createEmote(String name, AEmote emote, Long serverId, boolean validateName); boolean emoteExists(String name, Long serverId); + boolean emoteExists(Long emoteId); + void deleteEmote(AEmote aEmote); + Optional loadEmote(Long id); boolean emoteExists(String name, AServer server); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementService.java index d83c37bf7..513ff776f 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/RoleManagementService.java @@ -7,6 +7,7 @@ import java.util.Optional; public interface RoleManagementService { ARole createRole(Long id, AServer server); - Optional findRole(Long id, AServer server); + Optional findRoleOptional(Long id); + ARole findRole(Long id); void markDeleted(ARole role); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementService.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementService.java index 8166e9b41..ff4987353 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementService.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/service/management/ServerManagementService.java @@ -3,10 +3,13 @@ package dev.sheldan.abstracto.core.service.management; import dev.sheldan.abstracto.core.models.database.*; import java.util.List; +import java.util.Optional; public interface ServerManagementService { AServer createServer(Long id); AServer loadOrCreate(Long id); + AServer loadServer(Long id); + Optional loadServerOptional(Long id); void addChannelToServer(AServer server, AChannel channel); AUserInAServer addUserToServer(AServer server, AUser user); AUserInAServer addUserToServer(Long serverId, Long userId); diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java index ae94834eb..0611a4373 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java @@ -1,7 +1,6 @@ package dev.sheldan.abstracto.core.utils; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; -import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; @@ -16,7 +15,6 @@ import org.springframework.stereotype.Component; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Optional; @Component @Slf4j @@ -38,8 +36,7 @@ public class ContextUtils { m = clazz.getMethod("builder"); UserInitiatedServerContext.UserInitiatedServerContextBuilder builder = (UserInitiatedServerContext.UserInitiatedServerContextBuilder) m.invoke(null, null); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(message.getServerId(), message.getAuthorId()); - Optional channelOptional = channelManagementService.loadChannel(message.getChannelId()); - AChannel channel = channelOptional.orElseThrow(() -> new ChannelNotFoundException(message.getChannelId(), message.getServerId())); + AChannel channel = channelManagementService.loadChannel(message.getChannelId()); return builder .member(guildChannelMember.getMember()) .guild(guildChannelMember.getGuild()) diff --git a/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/utils/ContextUtilsTest.java b/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/utils/ContextUtilsTest.java index 4565d7381..1487fe4c3 100644 --- a/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/utils/ContextUtilsTest.java +++ b/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/utils/ContextUtilsTest.java @@ -49,8 +49,7 @@ public class ContextUtilsTest { AUserInAServer aUserInAServer = AUserInAServer.builder().userReference(AUser.builder().id(AUTHOR_ID).build()).serverReference(server).build(); when(userInServerManagementService.loadUser(eq(SERVER_ID), eq(AUTHOR_ID))).thenReturn(aUserInAServer); AChannel channel = AChannel.builder().id(CHANNEL_ID).build(); - Optional op = Optional.of(channel); - when(channelManagementService.loadChannel(eq(CHANNEL_ID))).thenReturn(op); + when(channelManagementService.loadChannel(eq(CHANNEL_ID))).thenReturn(channel); } @Test diff --git a/abstracto-application/coverage/pom.xml b/abstracto-application/coverage/pom.xml index 7a6189997..9e8338e31 100644 --- a/abstracto-application/coverage/pom.xml +++ b/abstracto-application/coverage/pom.xml @@ -57,6 +57,11 @@ experience-tracking-impl + + dev.sheldan.abstracto.modules + assignable-roles-impl + + dev.sheldan.abstracto.scheduling scheduling-impl diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/assignableRoles.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/features/assignableRoles.adoc new file mode 100644 index 000000000..cc1f1fd56 --- /dev/null +++ b/abstracto-application/documentation/src/main/docs/asciidoc/features/assignableRoles.adoc @@ -0,0 +1,77 @@ +=== Assignable roles + +This feature enables creating and maintaining so-called 'assignable role places'. These places are messages at which reactions are added, and when a member reacts a configured role is assigned to the user. +These places can consist of multiple messages (reactions are limited to 20 per message) and assignable roles can be added/removed. A place can be disabled, which causes any reaction to be removed and no role to be assigned. +There are several configurations possible for each individual assignable role place. +* `inline`: tries to display the embed as compact as possible and when this is disabled, every assignable role is displayed in a separate line. Default: `false` +* `autoRemove`: if a member adds a reaction to the assignable role place, they are removed immediately afterwards. Default: `false` +* `unique`: if a member adds a reaction and has previously selected other roles, these previous roles are removed before the new ones are assigned. Default: `false` +* `active`: an inactive assignable role place does not assign any roles and immediately removes any reactions added. Default: `true` + +If there are reactions added by members, which are not used within an assignable role place, the reaction gets removed automatically. + +If the emote is deleted, the assignable role place is still functional, but if you set it up again, it fail to do so. You need to remove the emote from the assignable role place via its ID. The ID will be displayed for the emotes which were removed. +Deleting the actual role behind an assignable role causes the assignable role place to become non-functional: the added reaction will remain and reactions can still be added, but nothing will happen. + +Feature key: `assignableRole` + + +==== Commands +Create a new assignable role place:: +* Usage: `createAssignableRolePlace ` +* Description: Creates a new assignable role place with the key `name`. The `text` will be shown in the description of the first message. +When the place is setup, it will be posted in the `channel`. The created place is active and inline by default. + +Add a role to an assignable role place:: +* Usage: `addRoleToAssignableRolePlace ` +* Description: Adds to the assignable role place identified by `name` an additional assignable role. The reaction to be used will be `emote` and `role` will be assigned when a member adds the reaction. +It is required that `emote` is usable by Abstracto and not yet used in the assignable role place. If the assignable role place is currently setup, the assignable role will be directly appended to the assignable role place and is +immediately available to be used. If this requires a new post, because the last message already has the maximum amount of reactions, it is required to setup the assignable role place again. + +Create the assignable role place in discord:: +* Usage: `setupAssignableRolePlace ` +* Description: Posts the messages of the assignable role place identified by `name` to the configured channel in discord and adds the reactions. This will delete the old messages connected to this assignable role place, if there are any. + +Remove a role from an assignable role place:: +* Usage: `removeRoleFromAssignableRolePlace ` +* Description: Removes from the assignable role place identified by `name`, the emote identified by `emote`. If the assignable role place is currently in use, this will update the message and remove all reactions using `emote`. + +Show the current configuration for an assignable role place:: +* Usage: `showAssignableRolePlaceConfig ` +* Description: This command displays the current configuration of assignable role place identified by `name`. This information includes the available emotes, which roles they represent and what position they have. + +Test how the assignable role place would look like:: +* Usage: `testAssignableRolePlace ` +* Description: Posts the assignable role place identified by `name` in the current channel. This command does not add the reactions, and is purely to check how the messages look. + +Move an assignable role place to another channel:: +* Usage: `moveAssignableRolePlace ` +* Description: Moves the assignable role place identified by `name` to be in `newChannel`. This change takes effect the next time the assignable role place is setup via `setupAssignableRolePlace`. + +Deactivate the assignable role place:: +* Usage: `deactivateAssignableRolePlace ` +* Description: Deactivates the assignable role place identified by `name`. Any further reactions placed by members will be removed immediately and not assign any roles. + +Activate the assignable role place:: +* Usage: `activateAssignableRolePlace ` +* Description: Activates the assignable role place identified by `name` and enables the assignment of roles. + +Change configuration of assignable role place:: +* Usage: `changeAssignableRolePlaceConfig ` +* Description: Changes the config attribute indicated by `key` of the place identified by `name` to `newValue`. The possible keys are: `inline`, `unique`, `autoRemove` and `active` respectively and all of these can take `true`/`false` as `newValue`. + +Swap two emotes in an assignable role place:: +* Usage: `swapAssignableRolePosition ` +* Description: Swaps the position of the assignable role places `firstEmote` and `secondEmote` in the assignable role place identified by `name`. This change takes effect the next time the assignable role place is setup via `setupAssignableRolePlace`. + +Set the position of an assignable role within an assignable role place:: +* Usage: `setAssignableRolePosition ` +* Description: Sets the position of the `emote` within the assignable role place identified by `name` to `position`. This change takes effect the next time the assignable role place is setup via `setupAssignableRolePlace`. + +Delete an assignable role place:: +* Usage: `deleteAssignableRolePlace ` +* Description: Completely deletes the assignable role place identified by `name`. This includes any trace in the database and the current messages, if any. + +Change description text of assignable role place:: +* Usage `editAssignableRolePlaceText ` +* Description: Changes the text which is shown in the first message of the assignable role place identified by `name` to `newText`. This changes the message immediately. \ No newline at end of file diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc index 8370549d9..1b618864d 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc @@ -43,4 +43,6 @@ include::features/modmail.adoc[] include::features/experience.adoc[] +include::features/assignableRoles.adoc[] + include::features/utility.adoc[] diff --git a/abstracto-application/pom.xml b/abstracto-application/pom.xml index c26077a54..06e9b97b2 100644 --- a/abstracto-application/pom.xml +++ b/abstracto-application/pom.xml @@ -3,7 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - pom org.springframework.boot @@ -15,6 +14,7 @@ dev.sheldan.abstracto abstracto-application 1.0-SNAPSHOT + pom test-commons @@ -50,7 +50,7 @@ yyyy/MM/dd HH:mm - 4.1.1_167 + 4.2.0_180 3.0.4 2.0.0-RC.1 1.5.3 diff --git a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedConfiguration.java b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedConfiguration.java index 0be0c450f..8fe32c6c0 100644 --- a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedConfiguration.java +++ b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedConfiguration.java @@ -55,4 +55,6 @@ public class EmbedConfiguration { * The message which is posted along the {@link net.dv8tion.jda.api.entities.MessageEmbed} as a normal message. */ private String additionalMessage; + + private boolean preventEmptyEmbed = false; } diff --git a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedField.java b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedField.java index 840924d7e..6322de196 100644 --- a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedField.java +++ b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/model/EmbedField.java @@ -24,4 +24,5 @@ public class EmbedField { * This means, if multiple fields can be put on the same height in the {@link net.dv8tion.jda.api.entities.MessageEmbed} this will be done by discord. */ private Boolean inline; + private Boolean forceNewMessage; } diff --git a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java index 5588b59ce..d9f797b62 100644 --- a/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java +++ b/abstracto-application/templating/templating-impl/src/main/java/dev/sheldan/abstracto/templating/service/TemplateServiceBean.java @@ -28,6 +28,7 @@ import java.util.stream.Collectors; @Component public class TemplateServiceBean implements TemplateService { + public static final double MAX_FIELD_COUNT = 25D; @Autowired private Configuration configuration; @@ -60,9 +61,9 @@ public class TemplateServiceBean implements TemplateService { @Override public MessageToSend renderEmbedTemplate(String key, Object model) { String embedConfig = this.renderTemplate(key + "_embed", model); + EmbedConfiguration embedConfiguration = gson.fromJson(embedConfig, EmbedConfiguration.class); List embedBuilders = new ArrayList<>(); embedBuilders.add(new EmbedBuilder()); - EmbedConfiguration embedConfiguration = gson.fromJson(embedConfig, EmbedConfiguration.class); String description = embedConfiguration.getDescription(); if(description != null) { double neededIndices = Math.ceil(description.length() / (double) MessageEmbed.TEXT_MAX_LENGTH) - 1; @@ -104,7 +105,7 @@ public class TemplateServiceBean implements TemplateService { } List embeds = new ArrayList<>(); - if(embedBuilders.size() > 1 || !embedBuilders.get(0).isEmpty()) { + if((embedBuilders.size() > 1 || !embedBuilders.get(0).isEmpty()) && !isEmptyEmbed(embedConfiguration)) { embeds = embedBuilders.stream().map(EmbedBuilder::build).collect(Collectors.toList()); } @@ -114,6 +115,13 @@ public class TemplateServiceBean implements TemplateService { .build(); } + private boolean isEmptyEmbed(EmbedConfiguration configuration) { + if(configuration.isPreventEmptyEmbed()) { + return configuration.getFields() == null && configuration.getDescription() == null && configuration.getImageUrl() == null; + } + return false; + } + @Override public MessageToSend renderTemplateToMessageToSend(String key, Object model) { return MessageToSend.builder().message(renderTemplate(key, model)).build(); @@ -129,13 +137,24 @@ public class TemplateServiceBean implements TemplateService { configuration.getFields().add(i + 1, secondPart); } } - double neededIndex = Math.ceil(configuration.getFields().size() / 25D) - 1; - extendIfNecessary(embedBuilders, neededIndex); + int actualCurrentIndex = 0; + int neededMessages = 0; for (int i = 0; i < configuration.getFields().size(); i++) { - double currentPart = Math.floor(i / 25D); + EmbedField field = configuration.getFields().get(i); + boolean lastMessageInEmbed = ((actualCurrentIndex + 1) % MAX_FIELD_COUNT) == 0; + boolean isStartOfNewMessage = (actualCurrentIndex % MAX_FIELD_COUNT) == 0; + boolean newMessageForcedWithinEmbeds = Boolean.TRUE.equals(field.getForceNewMessage()) && !lastMessageInEmbed; + boolean startOfNewMessage = actualCurrentIndex != 0 && isStartOfNewMessage; + if(newMessageForcedWithinEmbeds || startOfNewMessage) { + actualCurrentIndex = 0; + neededMessages++; + } else { + actualCurrentIndex++; + } + extendIfNecessary(embedBuilders, neededMessages); EmbedField embedField = configuration.getFields().get(i); boolean inline = embedField.getInline() != null ? embedField.getInline() : Boolean.FALSE; - embedBuilders.get((int) currentPart).addField(embedField.getName(), embedField.getValue(), inline); + embedBuilders.get(neededMessages).addField(embedField.getName(), embedField.getValue(), inline); } } @@ -221,4 +240,9 @@ public class TemplateServiceBean implements TemplateService { public String renderTemplatable(Templatable templatable) { return renderTemplate(templatable.getTemplateName(), templatable.getTemplateModel()); } + + @Override + public void clearCache() { + configuration.getCacheStorage().clear(); + } } diff --git a/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java b/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java index f5c6aa695..88c1db18a 100644 --- a/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java +++ b/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/service/TemplateService.java @@ -56,4 +56,6 @@ public interface TemplateService { * @return The template rendered as string */ String renderTemplatable(Templatable templatable); + + void clearCache(); }