From 04f1db2408ca9c2d381f365b160d5009398f28c7 Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Wed, 11 Nov 2020 17:11:30 +0100 Subject: [PATCH] [AB-80] added tracking of emotes used by server members and configuration updated sonar scanner version changed some commands to be silent instead of adding a check reaction --- .github/workflows/build.yml | 2 +- .../ShowAssignableRolePlaceConfig.java | 2 +- .../command/ShowAssignableRolePlaces.java | 2 +- .../command/TestAssignableRolePlace.java | 2 +- .../assignable-roles/pom.xml | 3 +- .../commands/LeaderBoardCommand.java | 2 +- .../commands/ListDisabledExperienceRoles.java | 2 +- .../abstracto/experience/commands/Rank.java | 2 +- .../experience/commands/SyncRoles.java | 2 +- .../experience-tracking/pom.xml | 3 +- .../moderation/commands/MyWarnings.java | 2 +- .../moderation/commands/UserNotes.java | 2 +- .../moderation/commands/Warnings.java | 2 +- .../abstracto-modules/moderation/pom.xml | 3 +- .../abstracto/modmail/commands/Close.java | 2 +- .../modmail/commands/CloseNoLog.java | 2 +- .../modmail/commands/CloseSilently.java | 2 +- .../abstracto/modmail/commands/Contact.java | 2 +- .../abstracto-modules/modmail/pom.xml | 3 +- .../abstracto-modules/pom.xml | 2 + .../abstracto-modules/statistic/pom.xml | 30 + .../statistic/statistic-impl/pom.xml | 53 + .../src/main/assembly/liquibase.xml | 18 + .../statistic/config/StatisticModule.java | 21 + .../emotes/command/DeleteTrackedEmote.java | 60 + .../emotes/command/DeletedEmoteStats.java | 89 ++ .../emotes/command/DisableEmoteTracking.java | 64 + .../statistic/emotes/command/EmoteStats.java | 94 ++ .../emotes/command/ExportEmoteStats.java | 130 ++ .../emotes/command/ExternalEmoteStats.java | 102 ++ .../emotes/command/PurgeEmoteStats.java | 68 + .../emotes/command/ResetEmoteStats.java | 50 + .../command/ShowExternalTrackedEmote.java | 76 + .../emotes/command/ShowTrackedEmotes.java | 114 ++ .../emotes/command/SyncTrackedEmotes.java | 60 + .../statistic/emotes/command/TrackEmote.java | 87 ++ .../parameter/TrackEmoteParameter.java | 15 + .../handler/TrackedEmoteParameterHandler.java | 42 + ...TrackedEmoteParameterParameterHandler.java | 45 + .../emotes/converter/EmoteStatsConverter.java | 51 + .../emotes/job/EmotePersistingJob.java | 60 + .../listener/CreateTrackedEmoteListener.java | 36 + .../listener/DeleteTrackedEmoteListener.java | 35 + .../listener/EmoteTrackingListener.java | 43 + .../listener/UpdateTrackedEmoteListener.java | 34 + .../emotes/model/DownloadEmoteStatsModel.java | 22 + .../repository/TrackedEmoteRepository.java | 22 + .../repository/UsedEmoteRepository.java | 58 + .../service/TrackedEmoteRunTimeStorage.java | 29 + .../TrackedEmoteRuntimeServiceBean.java | 82 + .../service/TrackedEmoteServiceBean.java | 197 +++ .../emotes/service/UsedEmoteServiceBean.java | 61 + .../TrackedEmoteManagementServiceBean.java | 179 +++ .../UsedEmoteManagementServiceBean.java | 69 + .../migrations/1.0-statistic/collection.xml | 11 + .../statistic-seedData/command.xml | 88 ++ .../1.0-statistic/statistic-seedData/data.xml | 15 + .../default_feature_flag.xml | 18 + .../default_feature_mode.xml | 31 + .../emote_statistic_job.xml | 19 + .../statistic-seedData/feature.xml | 16 + .../statistic-seedData/module.xml | 16 + .../1.0-statistic/statistic-tables/tables.xml | 11 + .../statistic-tables/tracked_emote.xml | 30 + .../statistic-tables/used_emote.xml | 29 + .../resources/migrations/dbchangelog-3.8.xsd | 1377 +++++++++++++++++ .../migrations/statistic-changeLog.xml | 10 + .../command/DeleteTrackedEmoteTest.java | 72 + .../emotes/command/DeletedEmoteStatsTest.java | 97 ++ .../command/DisableEmoteTrackingTest.java | 63 + .../emotes/command/EmoteStatsTest.java | 96 ++ .../emotes/command/ExportEmoteStatsTest.java | 179 +++ .../command/ExternalEmoteStatsTest.java | 96 ++ .../emotes/command/PurgeEmoteStatsTest.java | 72 + .../emotes/command/ResetEmoteStatsTest.java | 39 + .../command/ShowExternalTrackedEmoteTest.java | 87 ++ .../emotes/command/ShowTrackedEmotesTest.java | 233 +++ .../emotes/command/SyncTrackedEmotesTest.java | 50 + .../emotes/command/TrackEmoteTest.java | 127 ++ .../TrackedEmoteParameterHandlerTest.java | 83 + ...kedEmoteParameterParameterHandlerTest.java | 89 ++ .../converter/EmoteStatsConverterTest.java | 138 ++ .../emotes/job/EmotePersistingJobTest.java | 72 + .../CreateTrackedEmoteListenerTest.java | 49 + .../DeleteTrackedEmoteListenerTest.java | 49 + .../listener/EmoteTrackingListenerTest.java | 96 ++ .../UpdateTrackedEmoteListenerTest.java | 46 + .../TrackedEmoteRuntimeServiceBeanTest.java | 181 +++ .../service/TrackedEmoteServiceBeanTest.java | 540 +++++++ .../service/UsedEmoteServiceBeanTest.java | 105 ++ ...TrackedEmoteManagementServiceBeanTest.java | 284 ++++ .../UsedEmoteManagementServiceBeanTest.java | 139 ++ .../statistic/statistic-int/pom.xml | 22 + .../statistic/config/StatisticFeatures.java | 18 + .../emotes/config/EmoteTrackingFeature.java | 23 + .../emotes/config/EmoteTrackingMode.java | 16 + ...DownloadEmoteStatsFileTooBigException.java | 24 + .../TrackedEmoteNotFoundException.java | 13 + .../emotes/model/AvailableTrackedEmote.java | 15 + .../emotes/model/EmoteStatsModel.java | 25 + .../emotes/model/EmoteStatsResult.java | 7 + .../emotes/model/EmoteStatsResultDisplay.java | 16 + .../emotes/model/PersistingEmote.java | 18 + .../emotes/model/TrackedEmoteOverview.java | 62 + .../TrackedEmoteSynchronizationResult.java | 13 + .../emotes/model/database/TrackedEmote.java | 69 + .../emotes/model/database/UsedEmote.java | 34 + .../database/embed/TrackedEmoteServer.java | 21 + .../model/database/embed/UsedEmoteDay.java | 25 + .../DownloadEmoteStatsFileTooBigModel.java | 15 + .../service/TrackedEmoteRuntimeService.java | 17 + .../emotes/service/TrackedEmoteService.java | 26 + .../emotes/service/UsedEmoteService.java | 16 + .../TrackedEmoteManagementService.java | 36 + .../UsedEmoteManagementService.java | 21 + .../abstracto-modules/utility/pom.xml | 3 +- .../utility/commands/ServerInfo.java | 2 +- .../utility/commands/ShowAvatar.java | 2 +- .../abstracto/utility/commands/ShowEmote.java | 2 +- .../abstracto/utility/commands/StarStats.java | 2 +- .../abstracto/utility/commands/UserInfo.java | 4 +- .../utility/commands/remind/Reminders.java | 2 +- abstracto-application/bundle/pom.xml | 6 + ...java => AChannelParameterHandlerImpl.java} | 4 +- ...r.java => AEmoteParameterHandlerImpl.java} | 4 +- ...er.java => ARoleParameterHandlerImpl.java} | 4 +- ....java => BooleanParameterHandlerImpl.java} | 3 +- ...va => CommandKeyParameterHandlerImpl.java} | 3 +- ...r.java => DoubleParameterHandlerImpl.java} | 3 +- ...java => DurationParameterHandlerImpl.java} | 3 +- ...er.java => EmoteParameterHandlerImpl.java} | 3 +- ...ava => FullEmoteParameterHandlerImpl.java} | 4 +- ...java => FullRoleParameterHandlerImpl.java} | 4 +- ....java => IntegerParameterHandlerImpl.java} | 3 +- ...ler.java => LongParameterHandlerImpl.java} | 3 +- ...r.java => MemberParameterHandlerImpl.java} | 3 +- ...ler.java => RoleParameterHandlerImpl.java} | 3 +- ...a => TextChannelParameterHandlerImpl.java} | 3 +- .../commands/channels/ListChannelGroups.java | 2 +- .../core/commands/config/SetupFeature.java | 2 +- .../config/features/FeatureModes.java | 2 +- .../commands/config/features/Features.java | 2 +- .../abstracto/core/commands/help/Help.java | 8 +- .../abstracto/core/commands/utility/Echo.java | 2 +- .../abstracto/core/commands/utility/Ping.java | 2 +- .../core/listener/EmoteListener.java | 80 + .../core/service/ChannelServiceBean.java | 44 +- .../core/service/EmoteServiceBean.java | 5 + .../core-tables/default_feature_flag.xml | 1 - ... => AChannelParameterHandlerImplTest.java} | 6 +- ...> AEmoteParameterHandlerImplImplTest.java} | 6 +- ...=> ARoleParameterHandlerImplImplTest.java} | 6 +- ...a => BooleanParameterHandlerImplTest.java} | 4 +- ...va => DoubleParameterHandlerImplTest.java} | 4 +- ... => DurationParameterHandlerImplTest.java} | 4 +- ...ava => EmoteParameterHandlerImplTest.java} | 4 +- ...ullEmoteParameterHandlerImplImplTest.java} | 6 +- ...FullRoleParameterHandlerImplImplTest.java} | 6 +- ...a => IntegerParameterHandlerImplTest.java} | 4 +- ...java => LongParameterHandlerImplTest.java} | 4 +- ...va => MemberParameterHandlerImplTest.java} | 4 +- ...java => RoleParameterHandlerImplTest.java} | 4 +- ... TextChannelParameterHandlerImplTest.java} | 4 +- .../condition/FeatureModeCondition.java | 2 +- .../core/command/execution/CommandResult.java | 4 + .../provided/AChanelParameterHandler.java | 6 + .../provided/AEmoteParameterHandler.java | 6 + .../provided/ARoleParameterHandler.java | 7 + .../provided/BooleanParameterHandler.java | 7 + .../provided/CommandKeyParameterHandler.java | 7 + .../provided/DoubleParameterHandler.java | 7 + .../provided/DurationParameterHandler.java | 7 + .../provided/EmoteParameterHandler.java | 7 + .../provided/FullEmoteParameterHandler.java | 7 + .../provided/FullRoleParameterHandler.java | 7 + .../provided/IntegerParameterHandler.java | 8 + .../provided/LongParameterHandler.java | 7 + .../provided/MemberParameterHandler.java | 7 + .../provided/RoleParameterHandler.java | 7 + .../provided/TextChannelParameterHandler.java | 7 + .../IncorrectFeatureModeException.java | 5 +- .../core/listener/EmoteCreatedListener.java | 7 + .../core/listener/EmoteDeletedListener.java | 7 + .../core/listener/EmoteUpdatedListener.java | 7 + .../abstracto/core/models/Fakeable.java | 5 + .../core/models/database/AEmote.java | 3 +- .../models/database/DefaultFeatureFlag.java | 4 - .../IncorrectFeatureModeExceptionModel.java | 2 - .../core/service/ChannelService.java | 2 + .../abstracto/core/service/EmoteService.java | 2 + .../abstracto/core/utils/FileUtils.java | 27 + .../test/command/CommandTestUtilities.java | 13 +- abstracto-application/coverage/pom.xml | 5 +- .../src/main/docs/asciidoc/main.adoc | 14 +- .../assignableRoles.adoc | 0 .../asciidoc/{features => modules}/core.adoc | 0 .../{features => modules}/experience.adoc | 0 .../{features => modules}/moderation.adoc | 0 .../{features => modules}/modmail.adoc | 4 +- .../main/docs/asciidoc/modules/statistic.adoc | 60 + .../{features => modules}/utility.adoc | 0 .../templating/model/MessageToSend.java | 9 + 202 files changed, 7989 insertions(+), 131 deletions(-) create mode 100644 abstracto-application/abstracto-modules/statistic/pom.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/assembly/liquibase.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticModule.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStats.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTracking.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStats.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStats.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStats.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStats.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStats.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotes.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotes.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/TrackEmoteParameter.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterHandler.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterParameterHandler.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverter.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJob.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListener.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListener.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListener.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListener.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/DownloadEmoteStatsModel.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/TrackedEmoteRepository.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/UsedEmoteRepository.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRunTimeStorage.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBean.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBean.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBean.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBean.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBean.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/collection.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/command.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/data.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_flag.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_mode.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/emote_statistic_job.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/feature.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/module.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tables.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tracked_emote.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/used_emote.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/dbchangelog-3.8.xsd create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/statistic-changeLog.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmoteTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStatsTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTrackingTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStatsTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStatsTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStatsTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStatsTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStatsTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmoteTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotesTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotesTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmoteTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterHandlerTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterParameterHandlerTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverterTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJobTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListenerTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListenerTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListenerTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListenerTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBeanTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBeanTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBeanTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBeanTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBeanTest.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticFeatures.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingFeature.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingMode.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/DownloadEmoteStatsFileTooBigException.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/TrackedEmoteNotFoundException.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/AvailableTrackedEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsModel.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResult.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResultDisplay.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/PersistingEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteOverview.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteSynchronizationResult.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/TrackedEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/UsedEmote.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/TrackedEmoteServer.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/UsedEmoteDay.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/exception/DownloadEmoteStatsFileTooBigModel.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeService.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteService.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteService.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementService.java create mode 100644 abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementService.java rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{AChannelParameterHandler.java => AChannelParameterHandlerImpl.java} (81%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{AEmoteParameterHandler.java => AEmoteParameterHandlerImpl.java} (83%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{ARoleParameterHandler.java => ARoleParameterHandlerImpl.java} (81%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{BooleanParameterHandler.java => BooleanParameterHandlerImpl.java} (78%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{CommandKeyParameterHandler.java => CommandKeyParameterHandlerImpl.java} (81%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{DoubleParameterHandler.java => DoubleParameterHandlerImpl.java} (79%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{DurationParameterHandler.java => DurationParameterHandlerImpl.java} (80%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{EmoteParameterHandler.java => EmoteParameterHandlerImpl.java} (87%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{FullEmoteParameterHandler.java => FullEmoteParameterHandlerImpl.java} (84%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{FullRoleParameterHandler.java => FullRoleParameterHandlerImpl.java} (82%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{IntegerParameterHandler.java => IntegerParameterHandlerImpl.java} (78%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{LongParameterHandler.java => LongParameterHandlerImpl.java} (79%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{MemberParameterHandler.java => MemberParameterHandlerImpl.java} (88%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{RoleParameterHandler.java => RoleParameterHandlerImpl.java} (86%) rename abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/{TextChannelParameterHandler.java => TextChannelParameterHandlerImpl.java} (84%) create mode 100644 abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/EmoteListener.java rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{AChannelParameterHandlerTest.java => AChannelParameterHandlerImplTest.java} (89%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{AEmoteParameterHandlerTest.java => AEmoteParameterHandlerImplImplTest.java} (91%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{ARoleParameterHandlerTest.java => ARoleParameterHandlerImplImplTest.java} (90%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{BooleanParameterHandlerTest.java => BooleanParameterHandlerImplTest.java} (91%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{DoubleParameterHandlerTest.java => DoubleParameterHandlerImplTest.java} (93%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{DurationParameterHandlerTest.java => DurationParameterHandlerImplTest.java} (93%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{EmoteParameterHandlerTest.java => EmoteParameterHandlerImplTest.java} (95%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{FullEmoteParameterHandlerTest.java => FullEmoteParameterHandlerImplImplTest.java} (92%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{FullRoleParameterHandlerTest.java => FullRoleParameterHandlerImplImplTest.java} (90%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{IntegerParameterHandlerTest.java => IntegerParameterHandlerImplTest.java} (93%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{LongParameterHandlerTest.java => LongParameterHandlerImplTest.java} (93%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{MemberParameterHandlerTest.java => MemberParameterHandlerImplTest.java} (96%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{RoleParameterHandlerTest.java => RoleParameterHandlerImplTest.java} (95%) rename abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/{TextChannelParameterHandlerTest.java => TextChannelParameterHandlerImplTest.java} (95%) create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AChanelParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AEmoteParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/ARoleParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/BooleanParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/CommandKeyParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DoubleParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DurationParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/EmoteParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullEmoteParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullRoleParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/IntegerParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/LongParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/MemberParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/RoleParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/TextChannelParameterHandler.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteCreatedListener.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteDeletedListener.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteUpdatedListener.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/Fakeable.java create mode 100644 abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/FileUtils.java rename abstracto-application/documentation/src/main/docs/asciidoc/{features => modules}/assignableRoles.adoc (100%) rename abstracto-application/documentation/src/main/docs/asciidoc/{features => modules}/core.adoc (100%) rename abstracto-application/documentation/src/main/docs/asciidoc/{features => modules}/experience.adoc (100%) rename abstracto-application/documentation/src/main/docs/asciidoc/{features => modules}/moderation.adoc (100%) rename abstracto-application/documentation/src/main/docs/asciidoc/{features => modules}/modmail.adoc (97%) create mode 100644 abstracto-application/documentation/src/main/docs/asciidoc/modules/statistic.adoc rename abstracto-application/documentation/src/main/docs/asciidoc/{features => modules}/utility.adoc (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 192d86fc5..1cbfd0fb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: - name: Build with Maven run: mvn -B install --file abstracto-application/pom.xml - name: Setup sonarqube - uses: warchant/setup-sonar-scanner@v1 + uses: warchant/setup-sonar-scanner@v3 - name: Run sonarqube env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 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 index 120468108..f23e91f43 100644 --- 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 @@ -29,7 +29,7 @@ public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand String name = (String) parameters.get(0); // TODO refactor to return something to be posted in this command here instead of relying it to be posted somewhere else service.showAssignablePlaceConfig(commandContext.getUserInitiatedContext().getServer(), name, commandContext.getChannel()); - return CommandResult.fromSuccess(); + return CommandResult.fromIgnored(); } @Override 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 index 3f9700457..7a628a119 100644 --- 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 @@ -23,7 +23,7 @@ public class ShowAssignableRolePlaces extends AbstractConditionableCommand { @Override public CompletableFuture executeAsync(CommandContext commandContext) { return service.showAllAssignableRolePlaces(commandContext.getUserInitiatedContext().getServer(), commandContext.getChannel()) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override 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 index e2c5e67ad..fd64cda53 100644 --- 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 @@ -28,7 +28,7 @@ public class TestAssignableRolePlace extends AbstractConditionableCommand { List parameters = commandContext.getParameters().getParameters(); String name = (String) parameters.get(0); return service.testAssignableRolePlace(commandContext.getUserInitiatedContext().getServer(), name, commandContext.getChannel()) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/assignable-roles/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/pom.xml index d12547d16..1a251dca3 100644 --- a/abstracto-application/abstracto-modules/assignable-roles/pom.xml +++ b/abstracto-application/abstracto-modules/assignable-roles/pom.xml @@ -3,13 +3,12 @@ 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"> - dev.sheldan.abstracto + dev.sheldan.abstracto.modules abstracto-modules 1.0-SNAPSHOT 4.0.0 - dev.sheldan.abstracto.modules assignable-roles pom diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/LeaderBoardCommand.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/LeaderBoardCommand.java index e59fc4b96..2805f8064 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/LeaderBoardCommand.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/LeaderBoardCommand.java @@ -74,7 +74,7 @@ public class LeaderBoardCommand extends AbstractConditionableCommand { leaderBoardModel.setUserExecuting(userRankFuture.join()); MessageToSend messageToSend = templateService.renderEmbedTemplate(LEADER_BOARD_POST_EMBED_TEMPLATE, leaderBoardModel); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())); - }).thenApply(aVoid -> CommandResult.fromSuccess()); + }).thenApply(aVoid -> CommandResult.fromIgnored()); } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ListDisabledExperienceRoles.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ListDisabledExperienceRoles.java index d254ea9eb..86a426439 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ListDisabledExperienceRoles.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ListDisabledExperienceRoles.java @@ -54,7 +54,7 @@ public class ListDisabledExperienceRoles extends AbstractConditionableCommand { disabledExperienceRolesModel.getRoles().add(role); }); List> futures = channelService.sendEmbedTemplateInChannel("list_disabled_experience_roles", disabledExperienceRolesModel, commandContext.getChannel()); - return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromSuccess()); + return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/Rank.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/Rank.java index 52955518a..563776ce5 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/Rank.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/Rank.java @@ -72,7 +72,7 @@ public class Rank extends AbstractConditionableCommand { CompletableFuture future = converter.fromLeaderBoardEntry(userRank); return future.thenCompose(leaderBoardEntryModel -> self.renderAndSendRank(commandContext, rankModel, leaderBoardEntryModel) - ).thenApply(result -> CommandResult.fromSuccess()); + ).thenApply(result -> CommandResult.fromIgnored()); } @Transactional diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SyncRoles.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SyncRoles.java index 525c72ece..9c273c1fd 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SyncRoles.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SyncRoles.java @@ -36,7 +36,7 @@ public class SyncRoles extends AbstractConditionableCommand { AServer server = commandContext.getUserInitiatedContext().getServer(); log.info("Synchronizing roles on server {}", server.getId()); return userExperienceService.syncUserRolesWithFeedback(server, commandContext.getUserInitiatedContext().getChannel()) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/experience-tracking/pom.xml b/abstracto-application/abstracto-modules/experience-tracking/pom.xml index e2f41285a..6939b6785 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/pom.xml +++ b/abstracto-application/abstracto-modules/experience-tracking/pom.xml @@ -3,13 +3,12 @@ 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"> - dev.sheldan.abstracto + dev.sheldan.abstracto.modules abstracto-modules 1.0-SNAPSHOT 4.0.0 - dev.sheldan.abstracto.modules experience-tracking pom diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/MyWarnings.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/MyWarnings.java index 0fb3fce6f..8327eee76 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/MyWarnings.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/MyWarnings.java @@ -38,7 +38,7 @@ public class MyWarnings extends AbstractConditionableCommand { Long totalWarnCount = warnManagementService.getTotalWarnsForUser(commandContext.getUserInitiatedContext().getAUserInAServer()); model.setTotalWarnCount(totalWarnCount); channelService.sendEmbedTemplateInChannel(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, commandContext.getChannel()); - return CommandResult.fromSuccess(); + return CommandResult.fromIgnored(); } @Override diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/UserNotes.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/UserNotes.java index 54b1be05a..2630be5cc 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/UserNotes.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/UserNotes.java @@ -71,7 +71,7 @@ public class UserNotes extends AbstractConditionableCommand { return listCompletableFuture.thenCompose(noteEntryModels -> { model.setUserNotes(noteEntryModels); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(USER_NOTES_RESPONSE_TEMPLATE, model, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); }); } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java index c11457776..2decc2bae 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/commands/Warnings.java @@ -62,7 +62,7 @@ public class Warnings extends AbstractConditionableCommand { } return warnEntryConverter.fromWarnings(warnsToDisplay).thenApply(warnEntries -> { self.renderWarnings(commandContext, warnEntries); - return CommandResult.fromSuccess(); + return CommandResult.fromIgnored(); }); diff --git a/abstracto-application/abstracto-modules/moderation/pom.xml b/abstracto-application/abstracto-modules/moderation/pom.xml index 14c07fe49..967e51a64 100644 --- a/abstracto-application/abstracto-modules/moderation/pom.xml +++ b/abstracto-application/abstracto-modules/moderation/pom.xml @@ -3,13 +3,12 @@ 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"> - dev.sheldan.abstracto + dev.sheldan.abstracto.modules abstracto-modules 1.0-SNAPSHOT 4.0.0 - dev.sheldan.abstracto.modules moderation pom diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java index b462a2d71..c9a431c38 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Close.java @@ -49,7 +49,7 @@ public class Close extends AbstractConditionableCommand { String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object()); ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); return modMailThreadService.closeModMailThread(thread, note, true, commandContext.getUndoActions(), true) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseNoLog.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseNoLog.java index bd9172fe4..c176f92cb 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseNoLog.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseNoLog.java @@ -47,7 +47,7 @@ public class CloseNoLog extends AbstractConditionableCommand { ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); // we don't have a note, therefore we cant pass any, the method handles this accordingly return modMailThreadService.closeModMailThread(thread, null, false, commandContext.getUndoActions(), false) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java index 8620ec384..cfcc72019 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/CloseSilently.java @@ -46,7 +46,7 @@ public class CloseSilently extends AbstractConditionableCommand { String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object()); ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); return modMailThreadService.closeModMailThread(thread, note, false, commandContext.getUndoActions(), true) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java index f35f109d8..97bb5099e 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Contact.java @@ -59,7 +59,7 @@ public class Contact extends AbstractConditionableCommand { ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user); model.setExistingModMailThread(existingThread); List> futures = channelService.sendEmbedTemplateInChannel("modmail_thread_already_exists", model, commandContext.getChannel()); - return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromSuccess()); + return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored()); } else { return modMailThreadService.createModMailThreadForUser(targetUser, null, commandContext.getChannel(), false, commandContext.getUndoActions()) .thenApply(aVoid -> CommandResult.fromSuccess()); diff --git a/abstracto-application/abstracto-modules/modmail/pom.xml b/abstracto-application/abstracto-modules/modmail/pom.xml index 4e26d118f..a1ef49133 100644 --- a/abstracto-application/abstracto-modules/modmail/pom.xml +++ b/abstracto-application/abstracto-modules/modmail/pom.xml @@ -3,13 +3,12 @@ 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"> - dev.sheldan.abstracto + dev.sheldan.abstracto.modules abstracto-modules 1.0-SNAPSHOT 4.0.0 - dev.sheldan.abstracto.modules modmail pom diff --git a/abstracto-application/abstracto-modules/pom.xml b/abstracto-application/abstracto-modules/pom.xml index 8248c8de7..a5100474d 100644 --- a/abstracto-application/abstracto-modules/pom.xml +++ b/abstracto-application/abstracto-modules/pom.xml @@ -10,6 +10,7 @@ 4.0.0 abstracto-modules + dev.sheldan.abstracto.modules pom moderation @@ -17,6 +18,7 @@ experience-tracking modmail assignable-roles + statistic diff --git a/abstracto-application/abstracto-modules/statistic/pom.xml b/abstracto-application/abstracto-modules/statistic/pom.xml new file mode 100644 index 000000000..1ded7aa10 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/pom.xml @@ -0,0 +1,30 @@ + + + + dev.sheldan.abstracto.modules + abstracto-modules + 1.0-SNAPSHOT + + 4.0.0 + + statistic + pom + + + statistic-int + statistic-impl + + + + + dev.sheldan.abstracto.core + core-interface + ${project.version} + compile + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml new file mode 100644 index 000000000..8a88e992e --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml @@ -0,0 +1,53 @@ + + + + dev.sheldan.abstracto.modules + statistic + 1.0-SNAPSHOT + + 4.0.0 + + statistic-impl + + + + + maven-assembly-plugin + + + src/main/assembly/liquibase.xml + + + + + make-assembly + package + + single + + + + + + + + + + dev.sheldan.abstracto.modules + statistic-int + ${project.version} + + + + dev.sheldan.abstracto.core + core-interface + ${project.version} + test + test-jar + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/assembly/liquibase.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/assembly/liquibase.xml new file mode 100644 index 000000000..8b4774fa0 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-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/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticModule.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticModule.java new file mode 100644 index 000000000..575d899f1 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticModule.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.statistic.config; + +import dev.sheldan.abstracto.core.command.config.ModuleInfo; +import dev.sheldan.abstracto.core.command.config.ModuleInterface; +import org.springframework.stereotype.Component; + +@Component +public class StatisticModule implements ModuleInterface { + + public static final String STATISTIC = "statistic"; + + @Override + public ModuleInfo getInfo() { + return ModuleInfo.builder().name(STATISTIC).description("Module containing commands related to statistic.").build(); + } + + @Override + public String getParentModule() { + return "default"; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmote.java new file mode 100644 index 000000000..114711aac --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmote.java @@ -0,0 +1,60 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class DeleteTrackedEmote extends AbstractConditionableCommand { + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0); + TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId()); + trackedEmoteService.deleteTrackedEmote(trackedEmote); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("trackedEmote").templated(true).type(TrackedEmote.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("deleteTrackedEmote") + .module(StatisticModule.STATISTIC) + .templated(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStats.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStats.java new file mode 100644 index 000000000..fbbae2e67 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStats.java @@ -0,0 +1,89 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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 dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class DeletedEmoteStats extends AbstractConditionableCommand { + + @Autowired + private UsedEmoteService usedEmoteService; + + @Autowired + private ChannelService channelService; + + public static final String EMOTE_STATS_STATIC_DELETED_RESPONSE = "deletedEmoteStats_static_response"; + public static final String EMOTE_STATS_ANIMATED_DELETED_RESPONSE = "deletedEmoteStats_animated_response"; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + Instant statsSince = Instant.EPOCH; + if(!parameters.isEmpty()) { + Duration duration = (Duration) parameters.get(0); + statsSince = Instant.now().minus(duration); + } + EmoteStatsModel emoteStatsModel = usedEmoteService.getDeletedEmoteStatsForServerSince(commandContext.getUserInitiatedContext().getServer(), statsSince); + List> messagePromises = new ArrayList<>(); + if(!emoteStatsModel.getStaticEmotes().isEmpty()) { + log.trace("Deleted emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, emoteStatsModel, commandContext.getChannel())); + } + if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) { + log.trace("Deleted emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, emoteStatsModel, commandContext.getChannel())); + } + if(!emoteStatsModel.areStatsAvailable()) { + log.info("No delete emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel())); + } + + return FutureUtils.toSingleFutureGeneric(messagePromises) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("deletedEmoteStats") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTracking.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTracking.java new file mode 100644 index 000000000..a6e6c1207 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTracking.java @@ -0,0 +1,64 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class DisableEmoteTracking extends AbstractConditionableCommand { + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + if(!parameters.isEmpty()) { + TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0); + TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId()); + trackedEmoteManagementService.disableTrackedEmote(trackedEmote); + } else { + trackedEmoteService.disableEmoteTracking(commandContext.getGuild()); + } + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("trackedEmote").templated(true).optional(true).type(TrackedEmote.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("disableEmoteTracking") + .module(StatisticModule.STATISTIC) + .templated(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStats.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStats.java new file mode 100644 index 000000000..31ef7cc74 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStats.java @@ -0,0 +1,94 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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 dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class EmoteStats extends AbstractConditionableCommand { + + @Autowired + private UsedEmoteService usedEmoteService; + + @Autowired + private ChannelService channelService; + + @Autowired + private FeatureModeService featureModeService; + + public static final String EMOTE_STATS_STATIC_RESPONSE = "emoteStats_static_response"; + public static final String EMOTE_STATS_ANIMATED_RESPONSE = "emoteStats_animated_response"; + public static final String EMOTE_STATS_NO_STATS_AVAILABLE = "emoteStats_no_stats_available"; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + Instant statsSince = Instant.EPOCH; + if(!parameters.isEmpty()) { + Duration duration = (Duration) parameters.get(0); + statsSince = Instant.now().minus(duration); + } + EmoteStatsModel emoteStatsModel = usedEmoteService.getActiveEmoteStatsForServerSince(commandContext.getUserInitiatedContext().getServer(), statsSince); + List> messagePromises = new ArrayList<>(); + if(!emoteStatsModel.getStaticEmotes().isEmpty()) { + log.trace("Emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, emoteStatsModel, commandContext.getChannel())); + } + if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) { + log.trace("Emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, emoteStatsModel, commandContext.getChannel())); + } + if(!emoteStatsModel.areStatsAvailable()) { + log.info("No emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel())); + } + + return FutureUtils.toSingleFutureGeneric(messagePromises) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("emoteStats") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStats.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStats.java new file mode 100644 index 000000000..f71e4ad77 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStats.java @@ -0,0 +1,130 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.management.ServerManagementService; +import dev.sheldan.abstracto.core.utils.FileUtils; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.exception.DownloadEmoteStatsFileTooBigException; +import dev.sheldan.abstracto.statistic.emotes.model.DownloadEmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService; +import dev.sheldan.abstracto.templating.model.MessageToSend; +import dev.sheldan.abstracto.templating.service.TemplateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class ExportEmoteStats extends AbstractConditionableCommand { + + public static final String DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_no_stats_available_response"; + public static final String DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY = "downloadEmoteStats_file_name"; + public static final String DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY = "downloadEmoteStats_file_content"; + public static final String DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY = "downloadEmoteStats_response"; + @Autowired + private ServerManagementService serverManagementService; + + @Autowired + private TemplateService templateService; + + @Autowired + private ChannelService channelService; + + @Autowired + private UsedEmoteManagementService usedEmoteManagementService; + + @Autowired + private FileUtils fileUtils; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + Instant statsSince = Instant.EPOCH; + if(!parameters.isEmpty()) { + Duration duration = (Duration) parameters.get(0); + statsSince = Instant.now().minus(duration); + } + AServer actualServer = serverManagementService.loadServer(commandContext.getGuild().getIdLong()); + List usedEmotes = usedEmoteManagementService.loadEmoteUsagesForServerSince(actualServer, statsSince); + if(usedEmotes.isEmpty()) { + return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY, new Object(), commandContext.getChannel())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + // info might not be nice to handle in the template, and 1970 would look weird to users + // effectively this means if its null its EPOCH, so it would be possible to render it still + Instant toUseForModel = statsSince != Instant.EPOCH ? statsSince : null; + DownloadEmoteStatsModel model = DownloadEmoteStatsModel + .builder() + .emotes(usedEmotes) + .guild(commandContext.getGuild()) + .downloadDate(Instant.now()) + .requester(commandContext.getAuthor()) + .statsSince(toUseForModel) + .build(); + String fileName = templateService.renderTemplate(DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY, model); + String fileContent = templateService.renderTemplate(DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY, model); + File tempFile = fileUtils.createTempFile(fileName); + try { + fileUtils.writeContentToFile(tempFile, fileContent); + long maxFileSize = commandContext.getGuild().getMaxFileSize(); + if(maxFileSize < tempFile.length()) { + throw new DownloadEmoteStatsFileTooBigException(tempFile.length(), maxFileSize); + } + MessageToSend messageToSend = templateService.renderEmbedTemplate(DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY, model); + messageToSend.setFileToSend(tempFile); + return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) + .thenApply(unused -> CommandResult.fromIgnored()); + } catch (IOException e) { + throw new AbstractoRunTimeException(e); + } finally { + try { + fileUtils.safeDelete(tempFile); + } catch (IOException e) { + log.error("Failed to delete temporary export emote statistics file {}.", tempFile.getAbsoluteFile(), e); + } + } + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("exportEmoteStats") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStats.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStats.java new file mode 100644 index 000000000..36eddd5af --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStats.java @@ -0,0 +1,102 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.config.FeatureMode; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class ExternalEmoteStats extends AbstractConditionableCommand { + + @Autowired + private UsedEmoteService usedEmoteService; + + @Autowired + private ChannelService channelService; + + @Autowired + private FeatureModeService featureModeService; + + public static final String EMOTE_STATS_STATIC_EXTERNAL_RESPONSE = "externalEmoteStats_static_response"; + public static final String EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE = "externalEmoteStats_animated_response"; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + Instant statsSince = Instant.EPOCH; + if(!parameters.isEmpty()) { + Duration duration = (Duration) parameters.get(0); + statsSince = Instant.now().minus(duration); + } + EmoteStatsModel emoteStatsModel = usedEmoteService.getExternalEmoteStatsForServerSince(commandContext.getUserInitiatedContext().getServer(), statsSince); + List> messagePromises = new ArrayList<>(); + + if(!emoteStatsModel.getStaticEmotes().isEmpty()) { + log.trace("External emote stats has {} static emotes since {}.", emoteStatsModel.getStaticEmotes().size(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, emoteStatsModel, commandContext.getChannel())); + } + if(!emoteStatsModel.getAnimatedEmotes().isEmpty()) { + log.trace("External emote stats has {} animated emotes since {}.", emoteStatsModel.getAnimatedEmotes(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, emoteStatsModel, commandContext.getChannel())); + } + if(!emoteStatsModel.areStatsAvailable()) { + log.info("No external emote stats available for guild {} since {}.", commandContext.getGuild().getIdLong(), statsSince); + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel())); + } + + return FutureUtils.toSingleFutureGeneric(messagePromises) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("externalEmoteStats") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public List getFeatureModeLimitations() { + return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStats.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStats.java new file mode 100644 index 000000000..f7974de32 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStats.java @@ -0,0 +1,68 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Component +public class PurgeEmoteStats extends AbstractConditionableCommand { + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Autowired + private UsedEmoteService usedEmoteService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0); + TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId()); + Instant since = Instant.EPOCH; + if(parameters.size() > 1) { + Duration parameter = (Duration) parameters.get(1); + since = Instant.now().minus(parameter); + } + usedEmoteService.purgeEmoteUsagesSince(trackedEmote, since); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("trackedEmote").templated(true).type(TrackedEmote.class).build()); + parameters.add(Parameter.builder().name("period").templated(true).optional(true).type(Duration.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("purgeEmoteStats") + .module(StatisticModule.STATISTIC) + .templated(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStats.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStats.java new file mode 100644 index 000000000..7021112f5 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStats.java @@ -0,0 +1,50 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class ResetEmoteStats extends AbstractConditionableCommand { + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Override + public CommandResult execute(CommandContext commandContext) { + trackedEmoteService.resetEmoteStats(commandContext.getGuild()); + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("resetEmoteStats") + .module(StatisticModule.STATISTIC) + .templated(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmote.java new file mode 100644 index 000000000..dbc2d6956 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmote.java @@ -0,0 +1,76 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.exception.AbstractoTemplatedException; +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.config.FeatureMode; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class ShowExternalTrackedEmote extends AbstractConditionableCommand { + + public static final String SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY = "showExternalTrackedEmote_response"; + @Autowired + private ChannelService channelService; + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + List parameters = commandContext.getParameters().getParameters(); + TrackedEmote fakeTrackedEmote = (TrackedEmote) parameters.get(0); + TrackedEmote trackedEmote = trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId()); + if(!trackedEmote.getExternal()) { + throw new AbstractoTemplatedException("Emote is not external", "showExternalTrackedEmote_emote_is_not_external"); + } + return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, trackedEmote, commandContext.getChannel())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("trackedEmote").templated(true).type(TrackedEmote.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("showExternalTrackedEmote") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public List getFeatureModeLimitations() { + return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotes.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotes.java new file mode 100644 index 000000000..a11c5fda9 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotes.java @@ -0,0 +1,114 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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 dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class ShowTrackedEmotes extends AbstractConditionableCommand { + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Autowired + private ChannelService channelService; + + @Autowired + private FeatureModeService featureModeService; + + public static final String EMOTE_STATS_STATIC_RESPONSE = "showTrackedEmotes_static_response"; + public static final String EMOTE_STATS_ANIMATED_RESPONSE = "showTrackedEmotes_animated_response"; + public static final String EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE = "showTrackedEmotes_external_animated_response"; + public static final String EMOTE_STATS_EXTERNAL_STATIC_RESPONSE = "showTrackedEmotes_external_static_response"; + public static final String EMOTE_STATS_DELETED_STATIC_RESPONSE = "showTrackedEmotes_deleted_static_response"; + public static final String EMOTE_STATS_DELETED_ANIMATED_RESPONSE = "showTrackedEmotes_deleted_animated_response"; + public static final String EMOTE_STATS_NO_STATS_AVAILABLE = "showTrackedEmotes_no_emotes_available"; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + checkParameters(commandContext); + + Boolean showTrackingDisabled = false; + if(!commandContext.getParameters().getParameters().isEmpty()) { + showTrackingDisabled = (Boolean) commandContext.getParameters().getParameters().get(0); + } + + boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, commandContext.getGuild().getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES); + + TrackedEmoteOverview trackedEmoteOverview = trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), showTrackingDisabled); + boolean noStatsAvailable = true; + List> messagePromises = new ArrayList<>(); + if(!trackedEmoteOverview.getStaticEmotes().isEmpty()) { + noStatsAvailable = false; + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel())); + } + if(!trackedEmoteOverview.getAnimatedEmotes().isEmpty()) { + noStatsAvailable = false; + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel())); + } + if(!trackedEmoteOverview.getDeletedStaticEmotes().isEmpty()) { + noStatsAvailable = false; + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel())); + } + if(!trackedEmoteOverview.getDeletedAnimatedEmotes().isEmpty()) { + noStatsAvailable = false; + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel())); + } + if(externalTrackingEnabled) { + if(!trackedEmoteOverview.getExternalStaticEmotes().isEmpty()) { + noStatsAvailable = false; + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, trackedEmoteOverview, commandContext.getChannel())); + } + if(!trackedEmoteOverview.getExternalAnimatedEmotes().isEmpty()) { + noStatsAvailable = false; + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, trackedEmoteOverview, commandContext.getChannel())); + } + } + if(noStatsAvailable) { + messagePromises.addAll(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_NO_STATS_AVAILABLE, new Object(), commandContext.getChannel())); + } + return FutureUtils.toSingleFutureGeneric(messagePromises) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + parameters.add(Parameter.builder().name("showAll").templated(true).optional(true).type(Boolean.class).build()); + return CommandConfiguration.builder() + .name("showTrackedEmotes") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotes.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotes.java new file mode 100644 index 000000000..9d5ce825e --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotes.java @@ -0,0 +1,60 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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 dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class SyncTrackedEmotes extends AbstractConditionableCommand { + + public static final String SYNC_TRACKED_EMOTES_RESULT_RESPONSE = "syncTrackedEmotes_result_response"; + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Autowired + private ChannelService channelService; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + TrackedEmoteSynchronizationResult syncResult = trackedEmoteService.synchronizeTrackedEmotes(commandContext.getGuild()); + return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, syncResult, commandContext.getChannel())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("syncTrackedEmotes") + .module(StatisticModule.STATISTIC) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmote.java new file mode 100644 index 000000000..09896f6e1 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmote.java @@ -0,0 +1,87 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +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.exception.IncorrectParameterException; +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.exception.IncorrectFeatureModeException; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.config.StatisticModule; +import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Component +public class TrackEmote extends AbstractConditionableCommand { + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Autowired + private EmoteService emoteService; + + @Autowired + private FeatureModeService featureModeService; + + @Override + public CommandResult execute(CommandContext commandContext) { + checkParameters(commandContext); + TrackEmoteParameter emoteToTrack = (TrackEmoteParameter) commandContext.getParameters().getParameters().get(0); + Long emoteId = emoteToTrack.getTrackedEmote().getTrackedEmoteId().getEmoteId(); + long serverId = commandContext.getGuild().getIdLong(); + if(trackedEmoteManagementService.trackedEmoteExists(emoteId, serverId)) { + TrackedEmote trackedemote = trackedEmoteManagementService.loadByEmoteId(emoteId, serverId); + trackedEmoteManagementService.enableTrackedEmote(trackedemote); + } else if(emoteToTrack.getEmote() != null) { + boolean external = !emoteService.emoteIsFromGuild(emoteToTrack.getEmote(), commandContext.getGuild()); + if(external) { + boolean trackExternalEmotes = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId, EmoteTrackingMode.EXTERNAL_EMOTES); + if(!trackExternalEmotes) { + throw new IncorrectFeatureModeException(StatisticFeatures.EMOTE_TRACKING, Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES)); + } + } + trackedEmoteService.createFakeTrackedEmote(emoteToTrack.getEmote(), commandContext.getGuild()); + } else { + throw new IncorrectParameterException(this, getConfiguration().getParameters().get(0).getName()); + } + return CommandResult.fromSuccess(); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + parameters.add(Parameter.builder().name("emote").templated(true).type(TrackEmoteParameter.class).build()); + HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); + return CommandConfiguration.builder() + .name("trackEmote") + .module(StatisticModule.STATISTIC) + .templated(true) + .supportsEmbedException(true) + .causesReaction(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/TrackEmoteParameter.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/TrackEmoteParameter.java new file mode 100644 index 000000000..1ca15807b --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/TrackEmoteParameter.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.statistic.emotes.command.parameter; + +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Emote; + +@Getter +@Setter +@Builder +public class TrackEmoteParameter { + private Emote emote; + private TrackedEmote trackedEmote; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterHandler.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterHandler.java new file mode 100644 index 000000000..3d3352f24 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterHandler.java @@ -0,0 +1,42 @@ +package dev.sheldan.abstracto.statistic.emotes.command.parameter.handler; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; +import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class TrackedEmoteParameterHandler implements CommandParameterHandler { + + @Autowired + private EmoteParameterHandler emoteParameterHandler; + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Override + public boolean handles(Class clazz) { + return clazz.equals(TrackedEmote.class); + } + + @Override + public Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) { + Emote emote = (Emote) emoteParameterHandler.handle(input, iterators, Emote.class, context); + if(emote != null) { + return trackedEmoteService.getFakeTrackedEmote(emote, context.getGuild()); + } else { + long trackedEmoteId = Long.parseLong(input); + return trackedEmoteService.getFakeTrackedEmote(trackedEmoteId, context.getGuild()); + } + } + + @Override + public Integer getPriority() { + return 51; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterParameterHandler.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterParameterHandler.java new file mode 100644 index 000000000..62ac2e809 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/command/parameter/handler/TrackedEmoteParameterParameterHandler.java @@ -0,0 +1,45 @@ +package dev.sheldan.abstracto.statistic.emotes.command.parameter.handler; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; +import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; +import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class TrackedEmoteParameterParameterHandler implements CommandParameterHandler { + + @Autowired + private EmoteParameterHandler emoteParameterHandler; + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Override + public boolean handles(Class clazz) { + return clazz.equals(TrackEmoteParameter.class); + } + + @Override + public Object handle(String input, CommandParameterIterators iterators, Class clazz, Message context) { + TrackEmoteParameter parameter = TrackEmoteParameter.builder().build(); + Emote emote = (Emote) emoteParameterHandler.handle(input, iterators, Emote.class, context); + if(emote != null) { + parameter.setEmote(emote); + parameter.setTrackedEmote(trackedEmoteService.getFakeTrackedEmote(emote, context.getGuild())); + } else { + long trackedEmoteId = Long.parseLong(input); + parameter.setTrackedEmote(trackedEmoteService.getFakeTrackedEmote(trackedEmoteId, context.getGuild())); + } + return parameter; + } + + @Override + public Integer getPriority() { + return 51; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverter.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverter.java new file mode 100644 index 000000000..911378ada --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverter.java @@ -0,0 +1,51 @@ +package dev.sheldan.abstracto.statistic.emotes.converter; + +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class EmoteStatsConverter { + + @Autowired + private BotService botService; + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + public EmoteStatsModel fromEmoteStatsResults(List resultList) { + if(resultList.isEmpty()) { + return EmoteStatsModel.builder().build(); + } + Guild relevantGuild = botService.getGuildById(resultList.get(0).getServerId()); + EmoteStatsModel resultingModel = EmoteStatsModel.builder().build(); + resultList.forEach(emoteStatsResult -> { + TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmoteId(emoteStatsResult.getEmoteId(), emoteStatsResult.getServerId()); + Emote loadedEmote = null; + if(!trackedEmote.getExternal() && !trackedEmote.getDeleted()) { + loadedEmote = relevantGuild.getEmoteById(trackedEmote.getTrackedEmoteId().getEmoteId()); + } + EmoteStatsResultDisplay display = EmoteStatsResultDisplay + .builder() + .emote(loadedEmote) + .result(emoteStatsResult) + .trackedEmote(trackedEmote) + .build(); + if(display.getTrackedEmote().getAnimated()) { + resultingModel.getAnimatedEmotes().add(display); + } else { + resultingModel.getStaticEmotes().add(display); + } + }); + return resultingModel; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJob.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJob.java new file mode 100644 index 000000000..0234d2a2c --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJob.java @@ -0,0 +1,60 @@ +package dev.sheldan.abstracto.statistic.emotes.job; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteRuntimeService; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import lombok.extern.slf4j.Slf4j; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.PersistJobDataAfterExecution; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@DisallowConcurrentExecution +@Component +@PersistJobDataAfterExecution +public class EmotePersistingJob extends QuartzJobBean { + + @Autowired + private TrackedEmoteRuntimeService trackedEmoteRuntimeService; + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Override + @Transactional + protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { + Map>> runtimeConfig = trackedEmoteRuntimeService.getRuntimeConfig(); + log.info("Running statistic persisting job."); + Long pastMinute = getPastMinute(); + if(runtimeConfig.containsKey(pastMinute)) { + Map> foundStatistics = runtimeConfig.get(pastMinute); + log.info("Found emote statistics from {} servers to persist.", foundStatistics.size()); + trackedEmoteService.storeEmoteStatistics(foundStatistics); + runtimeConfig.remove(pastMinute); + checkForPastEmoteStats(pastMinute, runtimeConfig); + } + } + + private void checkForPastEmoteStats(Long minuteToCheck, Map>> runtimeConfig) { + List missedMinutes = runtimeConfig.keySet().stream().filter(aLong -> aLong < minuteToCheck).collect(Collectors.toList()); + missedMinutes.forEach(pastMinute -> { + log.info("Persisting emotes for a minute in the past, it should have been previously, but was not. Minute {}.", pastMinute); + trackedEmoteService.storeEmoteStatistics(runtimeConfig.get(pastMinute)); + runtimeConfig.remove(pastMinute); + }); + } + + public long getPastMinute() { + return (Instant.now().getEpochSecond() / 60) - 1; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListener.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListener.java new file mode 100644 index 000000000..cd578984d --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListener.java @@ -0,0 +1,36 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.listener.EmoteCreatedListener; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class CreateTrackedEmoteListener implements EmoteCreatedListener { + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Override + public void emoteCreated(Emote createdEmote) { + // guild should be available, because we are in the emote created event, and the emote object should come from there + log.info("Creating tracked emote {} in server {}.", createdEmote.getGuild().getIdLong(), createdEmote.getIdLong()); + trackedEmoteManagementService.createTrackedEmote(createdEmote, createdEmote.getGuild()); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public Integer getPriority() { + return ListenerPriority.MEDIUM; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListener.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListener.java new file mode 100644 index 000000000..fccbce01c --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListener.java @@ -0,0 +1,35 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.listener.EmoteDeletedListener; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class DeleteTrackedEmoteListener implements EmoteDeletedListener { + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Override + public void emoteDeleted(Emote deletedEmote) { + log.info("Marking tracked emote {} in gild {} as deleted.", deletedEmote.getId(), deletedEmote.getGuild().getIdLong()); + trackedEmoteManagementService.markAsDeleted(deletedEmote.getGuild().getIdLong(), deletedEmote.getIdLong()); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public Integer getPriority() { + return ListenerPriority.MEDIUM; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListener.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListener.java new file mode 100644 index 000000000..6d11be2b8 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListener.java @@ -0,0 +1,43 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.listener.MessageReceivedListener; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.ISnowflake; +import net.dv8tion.jda.api.entities.Message; +import org.apache.commons.collections4.Bag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +public class EmoteTrackingListener implements MessageReceivedListener { + + @Autowired + private TrackedEmoteService trackedEmoteService; + + @Override + public void execute(Message message) { + Bag emotesBag = message.getEmotesBag(); + Map> collect = emotesBag.stream().collect(Collectors.groupingBy(ISnowflake::getIdLong)); + collect.values().forEach(groupedEmotes -> + trackedEmoteService.addEmoteToRuntimeStorage(groupedEmotes.get(0), message.getGuild(), (long) groupedEmotes.size()) + ); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public Integer getPriority() { + return ListenerPriority.LOW; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListener.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListener.java new file mode 100644 index 000000000..4a69ff1be --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListener.java @@ -0,0 +1,34 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.listener.EmoteUpdatedListener; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class UpdateTrackedEmoteListener implements EmoteUpdatedListener { + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Override + public void emoteUpdated(Emote updatedEmote, String oldValue, String newValue) { + TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmote(updatedEmote); + trackedEmoteManagementService.changeName(trackedEmote, newValue); + } + + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public Integer getPriority() { + return ListenerPriority.MEDIUM; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/DownloadEmoteStatsModel.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/DownloadEmoteStatsModel.java new file mode 100644 index 000000000..c9a3547f6 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/DownloadEmoteStatsModel.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; + +import java.time.Instant; +import java.util.List; + +@Getter +@Setter +@Builder +public class DownloadEmoteStatsModel { + private Guild guild; + private Instant downloadDate; + private Instant statsSince; + private Member requester; + private List emotes; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/TrackedEmoteRepository.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/TrackedEmoteRepository.java new file mode 100644 index 000000000..06f94cc05 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/TrackedEmoteRepository.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.statistic.emotes.repository; + +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.QueryHints; +import org.springframework.stereotype.Repository; + +import javax.persistence.QueryHint; +import java.util.List; + +@Repository +public interface TrackedEmoteRepository extends JpaRepository { + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + List findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(Long serverId); + + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + List findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(Long serverId); + + @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) + List findByTrackedEmoteId_ServerId(Long serverId); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/UsedEmoteRepository.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/UsedEmoteRepository.java new file mode 100644 index 000000000..46d0f05ed --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/repository/UsedEmoteRepository.java @@ -0,0 +1,58 @@ +package dev.sheldan.abstracto.statistic.emotes.repository; + +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.UsedEmoteDay; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +@Repository +public interface UsedEmoteRepository extends JpaRepository { + + @Query(value="select * from used_emote " + + "where emote_id = :emote_id and server_id = :server_id " + + "and use_date = date_trunc('day', now())", nativeQuery = true) + Optional findEmoteFromServerToday(@Param("emote_id") Long emoteId, @Param("server_id") Long server_id); + + @Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " + + "inner join tracked_emote te " + + "on us.emote_id = te.id and us.server_id = te.server_id " + + "where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id " + + "group by us.emote_id, us.server_id " + + "order by amount desc", nativeQuery = true) + List getEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since); + + @Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " + + "inner join tracked_emote te " + + "on us.emote_id = te.id and us.server_id = te.server_id " + + "where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.external = true " + + "group by us.emote_id, us.server_id " + + "order by amount desc", nativeQuery = true) + List getExternalEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since); + + @Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " + + "inner join tracked_emote te " + + "on us.emote_id = te.id and us.server_id = te.server_id " + + "where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.deleted = true " + + "group by us.emote_id, us.server_id " + + "order by amount desc", nativeQuery = true) + List getDeletedEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since); + + @Query(value = "select us.emote_id as emoteId, us.server_id as serverId, sum(us.amount) as amount from used_emote us " + + "inner join tracked_emote te " + + "on us.emote_id = te.id and us.server_id = te.server_id " + + "where us.use_date >= date_trunc('day', cast(:start_date AS timestamp)) and us.server_id = :server_id and te.external = false and te.deleted = false " + + "group by us.emote_id, us.server_id " + + "order by amount desc", nativeQuery = true) + List getCurrentlyExistingEmoteStatsForServerSince(@Param("server_id") Long serverId, @Param("start_date") Instant since); + + void deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(Long emoteId, Long serverId, Instant timestamp); + + List getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(Long emoteId, Instant timestamp); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRunTimeStorage.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRunTimeStorage.java new file mode 100644 index 000000000..c9b1a16c5 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRunTimeStorage.java @@ -0,0 +1,29 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class TrackedEmoteRunTimeStorage { + private HashMap>> trackedEmotes = new HashMap<>(); + + public Map>> getRuntimeConfig() { + return trackedEmotes; + } + + public boolean contains(Long key) { + return trackedEmotes.containsKey(key); + } + + public void put(Long key, Map> objectToPut) { + trackedEmotes.put(key, objectToPut); + } + + public Map> get(Long key) { + return trackedEmotes.get(key); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBean.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBean.java new file mode 100644 index 000000000..490b7ac3c --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBean.java @@ -0,0 +1,82 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.*; + +@Component +@Slf4j +public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeService { + + @Autowired + private TrackedEmoteRunTimeStorage trackedEmoteRunTimeStorage; + + @Override + public Map>> getRuntimeConfig() { + return trackedEmoteRunTimeStorage.getRuntimeConfig(); + } + + @Override + public void addEmoteForServer(Emote emote, Guild guild, boolean external) { + addEmoteForServer(emote, guild, 1L, external); + } + + @Override + public void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external) { + Long key = getKey(); + PersistingEmote newPersistentEmote = createFromEmote(guild, emote, count, external); + if(trackedEmoteRunTimeStorage.contains(key)) { + Map> elementsForKey = trackedEmoteRunTimeStorage.get(key); + if(elementsForKey.containsKey(guild.getIdLong())) { + List persistingEmotes = elementsForKey.get(guild.getIdLong()); + Optional existingEmote = persistingEmotes + .stream() + .filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getIdLong())) + .findFirst(); + existingEmote.ifPresent(persistingEmote -> persistingEmote.setCount(persistingEmote.getCount() + count)); + if(!existingEmote.isPresent()) { + persistingEmotes.add(newPersistentEmote); + } + } else { + log.trace("Adding emote {} to list of server {}.", newPersistentEmote.getEmoteId(), guild.getIdLong()); + elementsForKey.put(guild.getIdLong(), new ArrayList<>(Arrays.asList(newPersistentEmote))); + } + } else { + HashMap> serverEmotes = new HashMap<>(); + serverEmotes.put(guild.getIdLong(), new ArrayList<>(Arrays.asList(newPersistentEmote))); + log.trace("Adding emote map entry for server {}.", guild.getIdLong()); + trackedEmoteRunTimeStorage.put(key, serverEmotes); + } + } + + @Override + public Long getKey() { + return Instant.now().getEpochSecond() / 60; + } + + @Override + public PersistingEmote createFromEmote(Guild guild, Emote emote, boolean external) { + return createFromEmote(guild, emote, 1L, external); + } + + @Override + public PersistingEmote createFromEmote(Guild guild, Emote emote, Long count, boolean external) { + String url = external ? emote.getImageUrl() : null; + return PersistingEmote + .builder() + .animated(emote.isAnimated()) + .emoteId(emote.getIdLong()) + .external(external) + .externalUrl(url) + .emoteName(emote.getName()) + .count(count) + .serverId(guild.getIdLong()) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBean.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBean.java new file mode 100644 index 000000000..8e09c5567 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBean.java @@ -0,0 +1,197 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.Map; +import java.util.List; +import java.util.Optional; + +@Component +@Slf4j +public class TrackedEmoteServiceBean implements TrackedEmoteService { + + @Autowired + private TrackedEmoteRuntimeService trackedEmoteRuntimeService; + + @Autowired + private FeatureModeService featureModeService; + + @Autowired + private EmoteService emoteService; + + @Autowired + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Autowired + private UsedEmoteManagementService usedEmoteManagementService; + + @Autowired + private BotService botService; + + @Override + public void addEmoteToRuntimeStorage(List emotes, Guild guild) { + boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES); + emotes.forEach(emote -> { + boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild); + if(externalTrackingEnabled || emoteIsFromGuild) { + trackedEmoteRuntimeService.addEmoteForServer(emote, guild, !emoteIsFromGuild); + } + }); + } + + @Override + public void addEmoteToRuntimeStorage(Emote emote, Guild guild, Long count) { + boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES); + boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild); + if(externalTrackingEnabled || emoteIsFromGuild) { + trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, !emoteIsFromGuild); + } + } + + @Override + @Transactional + public void storeEmoteStatistics(Map> usagesToStore) { + usagesToStore.forEach((serverId, persistingEmotes) -> { + log.info("Storing {} emotes for server {}.", persistingEmotes.size(), serverId); + boolean autoTrackExternalEmotes = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId, EmoteTrackingMode.AUTO_TRACK_EXTERNAL); + boolean trackExternalEmotes = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId, EmoteTrackingMode.EXTERNAL_EMOTES); + persistingEmotes.forEach(persistingEmote -> { + Optional emoteOptional = trackedEmoteManagementService.loadByEmoteIdOptional(persistingEmote.getEmoteId(), serverId); + emoteOptional.ifPresent(trackedEmote -> { + if(trackedEmote.getTrackingEnabled()) { + Optional existingUsedEmote = usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote); + existingUsedEmote.ifPresent(usedEmote -> + usedEmote.setAmount(usedEmote.getAmount() + persistingEmote.getCount()) + ); + if(!existingUsedEmote.isPresent()) { + usedEmoteManagementService.createEmoteUsageForToday(trackedEmote, persistingEmote.getCount()); + } + } else { + log.trace("Tracking disabled for emote {} in server {}.", trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId()); + } + }); + if(!emoteOptional.isPresent()) { + createNewTrackedEmote(serverId, autoTrackExternalEmotes, trackExternalEmotes, persistingEmote); + } + }); + }); + } + + private void createNewTrackedEmote(Long serverId, boolean autoTrackExternalEmotes, boolean trackExternalEmotes, PersistingEmote persistingEmote) { + Optional guildOptional = botService.getGuildByIdOptional(serverId); + guildOptional.ifPresent(guild -> { + Emote emoteFromGuild = guild.getEmoteById(persistingEmote.getEmoteId()); + if(emoteFromGuild != null) { + TrackedEmote newCreatedTrackedEmote = trackedEmoteManagementService.createTrackedEmote(emoteFromGuild, guild); + usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount()); + } else if(autoTrackExternalEmotes && trackExternalEmotes){ + TrackedEmote newCreatedTrackedEmote = trackedEmoteManagementService.createExternalEmote(persistingEmote); + usedEmoteManagementService.createEmoteUsageForToday(newCreatedTrackedEmote, persistingEmote.getCount()); + } + }); + } + + @Override + public TrackedEmote getFakeTrackedEmote(Emote emote, Guild guild) { + return getFakeTrackedEmote(emote.getIdLong(), guild); + } + + @Override + public TrackedEmote getFakeTrackedEmote(Long id, Guild guild) { + return TrackedEmote + .builder() + .trackedEmoteId(new TrackedEmoteServer(id, guild.getIdLong())) + .fake(true) + .build(); + } + + @Override + public TrackedEmoteSynchronizationResult synchronizeTrackedEmotes(Guild guild) { + List activeTrackedEmotes = trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(guild.getIdLong()); + Long addedEmotes = 0L; + List allExistingEmotes = guild.getEmotes(); + log.info("Synchronizing emotes for server {}, currently tracked emotes {}, available emotes for server {}.", guild.getIdLong(), activeTrackedEmotes.size(), allExistingEmotes.size()); + for (Emote emote : allExistingEmotes) { + Optional trackedEmoteOptional = activeTrackedEmotes + .stream() + .filter(trackedEmote -> + trackedEmote.getTrackedEmoteId().getEmoteId().equals(emote.getIdLong()) + && trackedEmote.getTrackedEmoteId().getServerId().equals(guild.getIdLong())) + .findFirst(); + if (!trackedEmoteOptional.isPresent()) { + trackedEmoteManagementService.createTrackedEmote(emote, guild); + addedEmotes++; + } else { + activeTrackedEmotes.remove(trackedEmoteOptional.get()); + } + } + + activeTrackedEmotes.forEach(trackedEmote -> + trackedEmoteManagementService.markAsDeleted(trackedEmote) + ); + return TrackedEmoteSynchronizationResult + .builder() + .emotesAdded(addedEmotes) + .emotesMarkedDeleted((long) activeTrackedEmotes.size()) + .build(); + } + + @Override + public TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild) { + return loadTrackedEmoteOverview(guild, false); + } + + @Override + public TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild, Boolean showTrackingDisabled) { + List trackedEmotes = trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), showTrackingDisabled); + TrackedEmoteOverview emoteOverView = TrackedEmoteOverview.builder().build(); + trackedEmotes.forEach(trackedEmote -> + emoteOverView.addTrackedEmote(trackedEmote, guild) + ); + return emoteOverView; + } + + @Override + public TrackedEmote createFakeTrackedEmote(Emote emote, Guild guild) { + boolean external = !emoteService.emoteIsFromGuild(emote, guild); + return trackedEmoteManagementService.createTrackedEmote(emote, guild, external); + } + + @Override + public void deleteTrackedEmote(TrackedEmote trackedEmote) { + usedEmoteManagementService.purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH); + trackedEmoteManagementService.deleteTrackedEmote(trackedEmote); + } + + @Override + public void resetEmoteStats(Guild guild) { + List trackedEmotes = trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true); + trackedEmotes.forEach(this::deleteTrackedEmote); + } + + @Override + public void disableEmoteTracking(Guild guild) { + List trackedEmotes = trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true); + trackedEmotes.forEach(trackedEmote -> trackedEmote.setTrackingEnabled(false)); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBean.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBean.java new file mode 100644 index 000000000..b3502e199 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBean.java @@ -0,0 +1,61 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.converter.EmoteStatsConverter; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.List; + +@Component +@Slf4j +public class UsedEmoteServiceBean implements UsedEmoteService { + + @Autowired + private EmoteStatsConverter converter; + + @Autowired + private UsedEmoteManagementService usedEmoteManagementService; + + @Override + public EmoteStatsModel getEmoteStatsForServerSince(AServer server, Instant since) { + List emoteStatsResults = usedEmoteManagementService.loadAllEmoteStatsForServerSince(server, since); + return converter.fromEmoteStatsResults(emoteStatsResults); + } + + @Override + public EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since) { + List emoteStatsResults = usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(server, since); + return converter.fromEmoteStatsResults(emoteStatsResults); + } + + @Override + public EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since) { + List emoteStatsResults = usedEmoteManagementService.loadExternalEmoteStatsForServerSince(server, since); + return converter.fromEmoteStatsResults(emoteStatsResults); + } + + @Override + public EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since) { + List emoteStatsResults = usedEmoteManagementService.loadActiveEmoteStatsForServerSince(server, since); + return converter.fromEmoteStatsResults(emoteStatsResults); + } + + @Override + public void purgeEmoteUsagesSince(TrackedEmote emote, Instant since) { + log.info("Purging emote {} in server {} since {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId(), since); + usedEmoteManagementService.purgeEmoteUsagesSince(emote, since.truncatedTo(ChronoUnit.DAYS)); + } + + @Override + public void purgeEmoteUsages(TrackedEmote emote) { + purgeEmoteUsagesSince(emote, Instant.EPOCH); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBean.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBean.java new file mode 100644 index 000000000..001474f97 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBean.java @@ -0,0 +1,179 @@ +package dev.sheldan.abstracto.statistic.emotes.service.management; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.service.management.ServerManagementService; +import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException; +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.repository.TrackedEmoteRepository; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +@Component +@Slf4j +public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagementService { + + @Autowired + private TrackedEmoteRepository repository; + + @Autowired + private ServerManagementService serverManagementService; + + @Override + public TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server) { + return createTrackedEmote(emoteId, emoteName, animated, true, server); + } + + @Override + public TrackedEmote createTrackedEmote(Emote emote, Guild guild) { + AServer server = serverManagementService.loadServer(guild.getIdLong()); + return createTrackedEmote(emote.getIdLong(), emote.getName(), emote.isAnimated(), true, server); + } + + @Override + public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) { + if(external) { + return createExternalEmote(emote, guild); + } else { + return createTrackedEmote(emote, guild); + } + } + + @Override + public TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, Boolean tracked, AServer server) { + TrackedEmote emote = TrackedEmote + .builder() + .animated(animated) + .trackedEmoteId(new TrackedEmoteServer(emoteId, server.getId())) + .trackingEnabled(tracked) + .emoteName(emoteName) + .server(server) + .external(false) + .deleted(false) + .build(); + log.info("Creating tracking emote with id {} and server {}.", emoteId, server.getId()); + return repository.save(emote); + } + + @Override + public TrackedEmote createExternalEmote(Long emoteId, String emoteName, String externalUrl, Boolean animated, AServer server) { + TrackedEmote emote = TrackedEmote + .builder() + .animated(animated) + .trackedEmoteId(new TrackedEmoteServer(emoteId, server.getId())) + .trackingEnabled(true) + .deleted(false) + .emoteName(emoteName) + .server(server) + .external(true) + .externalUrl(externalUrl) + .build(); + log.info("Creating external emote with id {} for server {}.", emoteId, server.getId()); + return repository.save(emote); + } + + @Override + public TrackedEmote createNotTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server) { + return createTrackedEmote(emoteId, emoteName, animated, false, server); + } + + @Override + public TrackedEmote createExternalEmote(PersistingEmote persistingEmote) { + AServer server = serverManagementService.loadServer(persistingEmote.getServerId()); + return createExternalEmote(persistingEmote.getEmoteId(), persistingEmote.getEmoteName(), persistingEmote.getExternalUrl(), persistingEmote.getAnimated(), server); + } + + @Override + public TrackedEmote createExternalEmote(Emote emote, Guild guild) { + AServer server = serverManagementService.loadServer(guild.getIdLong()); + return createExternalEmote(emote.getIdLong(), emote.getName(), emote.getImageUrl(), emote.isAnimated(), server); + } + + @Override + public void markAsDeleted(Long serverId, Long emoteId) { + TrackedEmote emote = loadByEmoteId(emoteId, serverId); + markAsDeleted(emote); + } + + @Override + public void markAsDeleted(TrackedEmote trackedemote) { + log.info("Marking tracked emote {} in server {} as deleted.", trackedemote.getTrackedEmoteId().getEmoteId(), trackedemote.getTrackedEmoteId().getServerId()); + trackedemote.setDeleted(true); + } + + @Override + public TrackedEmote loadByEmoteId(Long emoteId, Long serverId) { + return loadByEmoteIdOptional(emoteId, serverId).orElseThrow(() -> new TrackedEmoteNotFoundException(String.format("Tracked emote %s in server %s not found.", emoteId, serverId))); + } + + @Override + public TrackedEmote loadByEmote(Emote emote) { + return loadByEmoteId(emote.getIdLong(), emote.getGuild().getIdLong()); + } + + @Override + public boolean trackedEmoteExists(Long emoteId, Long serverId) { + return loadByEmoteIdOptional(emoteId, serverId).isPresent(); + } + + @Override + public TrackedEmote loadByTrackedEmoteServer(TrackedEmoteServer trackedEmoteServer) { + return loadByEmoteId(trackedEmoteServer.getEmoteId(), trackedEmoteServer.getServerId()); + } + + @Override + public Optional loadByEmoteIdOptional(Long emoteId, Long serverId) { + return repository.findById(new TrackedEmoteServer(emoteId, serverId)); + } + + @Override + public List getAllActiveTrackedEmoteForServer(AServer server) { + return getAllActiveTrackedEmoteForServer(server.getId()); + } + + @Override + public List getAllActiveTrackedEmoteForServer(Long serverId) { + return repository.findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(serverId); + } + + @Override + public List getTrackedEmoteForServer(Long serverId, Boolean showTrackingDisabledEmotes) { + if(showTrackingDisabledEmotes) { + return repository.findByTrackedEmoteId_ServerId(serverId); + } else { + return repository.findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(serverId); + } + } + + @Override + public void changeName(TrackedEmote emote, String newName) { + log.info("Changing name of emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId()); + emote.setEmoteName(newName); + } + + @Override + public void disableTrackedEmote(TrackedEmote emote) { + log.info("Disabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId()); + emote.setTrackingEnabled(false); + } + + @Override + public void enableTrackedEmote(TrackedEmote emote) { + log.info("Enabling tracking for tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId()); + emote.setTrackingEnabled(true); + } + + @Override + public void deleteTrackedEmote(TrackedEmote emote) { + log.info("Deleting tracked emote {} in server {}.", emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId()); + repository.delete(emote); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBean.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBean.java new file mode 100644 index 000000000..ddec056ef --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBean.java @@ -0,0 +1,69 @@ +package dev.sheldan.abstracto.statistic.emotes.service.management; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.UsedEmoteDay; +import dev.sheldan.abstracto.statistic.emotes.repository.UsedEmoteRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +@Component +@Slf4j +public class UsedEmoteManagementServiceBean implements UsedEmoteManagementService { + + @Autowired + private UsedEmoteRepository usedEmoteRepository; + + @Override + public Optional loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote) { + return usedEmoteRepository.findEmoteFromServerToday(trackedEmote.getTrackedEmoteId().getEmoteId() , trackedEmote.getTrackedEmoteId().getServerId()); + } + + @Override + public UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count) { + UsedEmote usedEmote = UsedEmote + .builder() + .emoteId(new UsedEmoteDay(trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId(), Instant.now())) + .amount(count) + .build(); + log.trace("Creating emote usage for emote {} in server {} with count {}.", trackedEmote.getTrackedEmoteId().getEmoteId(), trackedEmote.getTrackedEmoteId().getServerId(), count); + return usedEmoteRepository.save(usedEmote); + } + + @Override + public List loadEmoteUsagesForServerSince(AServer server, Instant since) { + return usedEmoteRepository.getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(server.getId(), since); + } + + @Override + public List loadAllEmoteStatsForServerSince(AServer server, Instant since) { + return usedEmoteRepository.getEmoteStatsForServerSince(server.getId(), since); + } + + @Override + public List loadDeletedEmoteStatsForServerSince(AServer server, Instant since) { + return usedEmoteRepository.getDeletedEmoteStatsForServerSince(server.getId(), since); + } + + @Override + public List loadExternalEmoteStatsForServerSince(AServer server, Instant since) { + return usedEmoteRepository.getExternalEmoteStatsForServerSince(server.getId(), since); + } + + @Override + public List loadActiveEmoteStatsForServerSince(AServer server, Instant since) { + return usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(server.getId(), since); + } + + @Override + public void purgeEmoteUsagesSince(TrackedEmote emote, Instant since) { + usedEmoteRepository.deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(emote.getTrackedEmoteId().getEmoteId(), emote.getTrackedEmoteId().getServerId(), since); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/collection.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/collection.xml new file mode 100644 index 000000000..6bf80b4c3 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/collection.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/command.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/command.xml new file mode 100644 index 000000000..d2a849b71 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/command.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/data.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/data.xml new file mode 100644 index 000000000..20cd8dab8 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/data.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_flag.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_flag.xml new file mode 100644 index 000000000..8875c2191 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_flag.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_mode.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_mode.xml new file mode 100644 index 000000000..1b811cceb --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/default_feature_mode.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/emote_statistic_job.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/emote_statistic_job.xml new file mode 100644 index 000000000..906b8d2a7 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/emote_statistic_job.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/feature.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/feature.xml new file mode 100644 index 000000000..0c8c75272 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/feature.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/module.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/module.xml new file mode 100644 index 000000000..028f9db8f --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-seedData/module.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tables.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tables.xml new file mode 100644 index 000000000..fe4b396ea --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tables.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tracked_emote.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tracked_emote.xml new file mode 100644 index 000000000..741a3d3c3 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/tracked_emote.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/used_emote.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/used_emote.xml new file mode 100644 index 000000000..1d574d2bf --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/1.0-statistic/statistic-tables/used_emote.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/dbchangelog-3.8.xsd b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/dbchangelog-3.8.xsd new file mode 100644 index 000000000..ebfe6d612 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-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/statistic/statistic-impl/src/main/resources/migrations/statistic-changeLog.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/statistic-changeLog.xml new file mode 100644 index 000000000..59ca6fbd4 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/main/resources/migrations/statistic-changeLog.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmoteTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmoteTest.java new file mode 100644 index 000000000..fa4f9de69 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeleteTrackedEmoteTest.java @@ -0,0 +1,72 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class DeleteTrackedEmoteTest { + + @InjectMocks + private DeleteTrackedEmote testUnit; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Test(expected = InsufficientParametersException.class) + public void testTooLittleParameters() { + CommandTestUtilities.executeNoParametersTest(testUnit); + } + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTest(testUnit); + } + + @Test + public void testExecuteWithExistingTrackedEmote() { + TrackedEmote fakedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(1L, 1L); + when(fakedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote); + CommandResult result = testUnit.execute(CommandTestUtilities.getWithParameters(Arrays.asList(fakedEmote))); + CommandTestUtilities.checkSuccessfulCompletion(result); + verify(trackedEmoteService, times(1)).deleteTrackedEmote(actualTrackedEmote); + } + + @Test(expected = TrackedEmoteNotFoundException.class) + public void testExecuteNonExistingTrackedEmote() { + TrackedEmote fakedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(1L, 1L); + when(fakedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenThrow(new TrackedEmoteNotFoundException()); + testUnit.execute(CommandTestUtilities.getWithParameters(Arrays.asList(fakedEmote))); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStatsTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStatsTest.java new file mode 100644 index 000000000..0df4c9799 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DeletedEmoteStatsTest.java @@ -0,0 +1,97 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; + +import static dev.sheldan.abstracto.statistic.emotes.command.DeletedEmoteStats.EMOTE_STATS_ANIMATED_DELETED_RESPONSE; +import static dev.sheldan.abstracto.statistic.emotes.command.DeletedEmoteStats.EMOTE_STATS_STATIC_DELETED_RESPONSE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class DeletedEmoteStatsTest { + + @InjectMocks + private DeletedEmoteStats testUnit; + + @Mock + private UsedEmoteService usedEmoteService; + + @Mock + private ChannelService channelService; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTestAsync(testUnit); + } + + @Test + public void testWithoutParameterStaticEmotes() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getStaticEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getDeletedEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithoutParameterAnimatedEmotesEmotes() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getDeletedEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithoutParametersNoResult() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + when(model.areStatsAvailable()).thenReturn(false); + when(usedEmoteService.getDeletedEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithParameterStaticEmotes() { + CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(4))); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getStaticEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getDeletedEmoteStatsForServerSince(eq(noParameters.getUserInitiatedContext().getServer()), any(Instant.class))).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_DELETED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTrackingTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTrackingTest.java new file mode 100644 index 000000000..3b1032296 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/DisableEmoteTrackingTest.java @@ -0,0 +1,63 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class DisableEmoteTrackingTest { + + @InjectMocks + private DisableEmoteTracking testUnit; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTest(testUnit); + } + + @Test + public void testDisableAllTracking() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + testUnit.execute(commandContext); + verify(trackedEmoteService, times(1)).disableEmoteTracking(commandContext.getGuild()); + } + + @Test + public void testDisableTrackingForOneTrackedEmote() { + TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class); + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote)); + TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class); + when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote); + testUnit.execute(commandContext); + verify(trackedEmoteManagementService, times(1)).disableTrackedEmote(actualTrackedEmote); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStatsTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStatsTest.java new file mode 100644 index 000000000..3f8af6e53 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/EmoteStatsTest.java @@ -0,0 +1,96 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; + +import static dev.sheldan.abstracto.statistic.emotes.command.EmoteStats.EMOTE_STATS_ANIMATED_RESPONSE; +import static dev.sheldan.abstracto.statistic.emotes.command.EmoteStats.EMOTE_STATS_STATIC_RESPONSE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class EmoteStatsTest { + + @InjectMocks + private EmoteStats testUnit; + + @Mock + private UsedEmoteService usedEmoteService; + + @Mock + private ChannelService channelService; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTestAsync(testUnit); + } + + @Test + public void testWithoutParameterStaticEmotes() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getStaticEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getActiveEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithoutParameterAnimatedEmotesEmotes() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getActiveEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithoutParametersNoResult() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + when(model.areStatsAvailable()).thenReturn(false); + when(usedEmoteService.getActiveEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithParameterStaticEmotes() { + CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(4))); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getStaticEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getActiveEmoteStatsForServerSince(eq(noParameters.getUserInitiatedContext().getServer()), any(Instant.class))).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStatsTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStatsTest.java new file mode 100644 index 000000000..3e88e518f --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExportEmoteStatsTest.java @@ -0,0 +1,179 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.management.ServerManagementService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.core.utils.FileUtils; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.exception.DownloadEmoteStatsFileTooBigException; +import dev.sheldan.abstracto.statistic.emotes.model.DownloadEmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService; +import dev.sheldan.abstracto.templating.model.MessageToSend; +import dev.sheldan.abstracto.templating.service.TemplateService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import static dev.sheldan.abstracto.statistic.emotes.command.ExportEmoteStats.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class ExportEmoteStatsTest { + + @InjectMocks + private ExportEmoteStats testUnit; + + @Mock + private ServerManagementService serverManagementService; + + @Mock + private TemplateService templateService; + + @Mock + private ChannelService channelService; + + @Mock + private UsedEmoteManagementService usedEmoteManagementService; + + @Mock + private FileUtils fileUtils; + + @Captor + private ArgumentCaptor modelArgumentCaptor; + + @Mock + private UsedEmote usedEmote; + + private static final Long SERVER_ID = 4L; + private static final String FILE_NAME = "name"; + private static final String FILE_CONTENT = "content"; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTestAsync(testUnit); + } + + @Test + public void testExportAllEmoteStats() throws IOException { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getMaxFileSize()).thenReturn(4L); + mockServerAndFileRendering(commandContext); + File file = Mockito.mock(File.class); + when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file); + when(file.length()).thenReturn(3L); + MessageToSend messageToSend = Mockito.mock(MessageToSend.class); + when(templateService.renderEmbedTemplate(eq(DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY), any())).thenReturn(messageToSend); + when(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + verify(fileUtils, times(1)).writeContentToFile(file, FILE_CONTENT); + verify(messageToSend, times(1)).setFileToSend(file); + verify(fileUtils, times(1)).safeDelete(file); + verifyModel(); + } + + @Test + public void testExportAllEmoteStatsSince() throws IOException { + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(3))); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + AServer server = Mockito.mock(AServer.class); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + when(commandContext.getGuild().getMaxFileSize()).thenReturn(4L); + List usedEmotes = Arrays.asList(usedEmote); + when(usedEmoteManagementService.loadEmoteUsagesForServerSince(eq(server), any(Instant.class))).thenReturn(usedEmotes); + when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY), modelArgumentCaptor.capture())).thenReturn(FILE_NAME); + when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY), any())).thenReturn(FILE_CONTENT); + File file = Mockito.mock(File.class); + when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file); + when(file.length()).thenReturn(3L); + MessageToSend messageToSend = Mockito.mock(MessageToSend.class); + when(templateService.renderEmbedTemplate(eq(DOWNLOAD_EMOTE_STATS_RESPONSE_TEMPLATE_KEY), any())).thenReturn(messageToSend); + when(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + verify(fileUtils, times(1)).writeContentToFile(file, FILE_CONTENT); + verify(messageToSend, times(1)).setFileToSend(file); + verify(fileUtils, times(1)).safeDelete(file); + verifyModel(); + } + + @Test + public void testExportNoStatsAvailable() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + AServer server = Mockito.mock(AServer.class); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + List usedEmotes = new ArrayList<>(); + when(usedEmoteManagementService.loadEmoteUsagesForServerSince(server, Instant.EPOCH)).thenReturn(usedEmotes); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + verify(channelService, times(1)).sendEmbedTemplateInChannel(eq(DOWNLOAD_EMOTE_STATS_NO_STATS_AVAILABLE_RESPONSE_TEMPLATE_KEY), any(), eq(commandContext.getChannel())); + } + + @Test(expected = AbstractoRunTimeException.class) + public void testFileIOException() throws IOException { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + mockServerAndFileRendering(commandContext); + File file = Mockito.mock(File.class); + when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file); + doThrow(new IOException()).when(fileUtils).writeContentToFile(file, FILE_CONTENT); + testUnit.executeAsync(commandContext); + } + + @Test(expected = DownloadEmoteStatsFileTooBigException.class) + public void testExportAllEmoteStatsTooBig() throws IOException { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getMaxFileSize()).thenReturn(2L); + mockServerAndFileRendering(commandContext); + File file = Mockito.mock(File.class); + when(fileUtils.createTempFile(FILE_NAME)).thenReturn(file); + when(file.length()).thenReturn(3L); + MessageToSend messageToSend = Mockito.mock(MessageToSend.class); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + verify(fileUtils, times(1)).writeContentToFile(file, FILE_CONTENT); + verify(messageToSend, times(1)).setFileToSend(file); + verify(fileUtils, times(1)).safeDelete(file); + verifyModel(); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + + private void verifyModel() { + DownloadEmoteStatsModel model = modelArgumentCaptor.getValue(); + Assert.assertEquals(1, model.getEmotes().size()); + Assert.assertEquals(usedEmote, model.getEmotes().get(0)); + } + + private void mockServerAndFileRendering(CommandContext commandContext) { + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + AServer server = Mockito.mock(AServer.class); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + List usedEmotes = Arrays.asList(usedEmote); + when(usedEmoteManagementService.loadEmoteUsagesForServerSince(server, Instant.EPOCH)).thenReturn(usedEmotes); + when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_NAME_TEMPLATE_KEY), modelArgumentCaptor.capture())).thenReturn(FILE_NAME); + when(templateService.renderTemplate(eq(DOWNLOAD_EMOTE_STATS_FILE_CONTENT_TEMPLATE_KEY), any())).thenReturn(FILE_CONTENT); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStatsTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStatsTest.java new file mode 100644 index 000000000..92a54ef5c --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ExternalEmoteStatsTest.java @@ -0,0 +1,96 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResultDisplay; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; + +import static dev.sheldan.abstracto.statistic.emotes.command.ExternalEmoteStats.EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE; +import static dev.sheldan.abstracto.statistic.emotes.command.ExternalEmoteStats.EMOTE_STATS_STATIC_EXTERNAL_RESPONSE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ExternalEmoteStatsTest { + + @InjectMocks + private ExternalEmoteStats testUnit; + + @Mock + private UsedEmoteService usedEmoteService; + + @Mock + private ChannelService channelService; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTestAsync(testUnit); + } + + @Test + public void testWithoutParameterStaticEmotes() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getStaticEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getExternalEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithoutParameterAnimatedEmotesEmotes() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getAnimatedEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getExternalEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithoutParametersNoResult() { + CommandContext noParameters = CommandTestUtilities.getNoParameters(); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + when(model.areStatsAvailable()).thenReturn(false); + when(usedEmoteService.getExternalEmoteStatsForServerSince(noParameters.getUserInitiatedContext().getServer(), Instant.EPOCH)).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(eq(EmoteStats.EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testWithParameterStaticEmotes() { + CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(Duration.ofHours(4))); + EmoteStatsModel model = Mockito.mock(EmoteStatsModel.class); + EmoteStatsResultDisplay display = Mockito.mock(EmoteStatsResultDisplay.class); + when(model.getStaticEmotes()).thenReturn(Arrays.asList(display)); + when(model.areStatsAvailable()).thenReturn(true); + when(usedEmoteService.getExternalEmoteStatsForServerSince(eq(noParameters.getUserInitiatedContext().getServer()), any(Instant.class))).thenReturn(model); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_EXTERNAL_RESPONSE, model, noParameters.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CommandTestUtilities.checkSuccessfulCompletionAsync(testUnit.executeAsync(noParameters)); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStatsTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStatsTest.java new file mode 100644 index 000000000..36ae37c1e --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/PurgeEmoteStatsTest.java @@ -0,0 +1,72 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.UsedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class PurgeEmoteStatsTest { + + @InjectMocks + private PurgeEmoteStats testUnit; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Mock + private UsedEmoteService usedEmoteService; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTest(testUnit); + } + + @Test + public void testPurgeEntireTimeLineOfEmote() { + TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class); + when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote); + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote)); + testUnit.execute(commandContext); + verify(usedEmoteService, times(1)).purgeEmoteUsagesSince(actualTrackedEmote, Instant.EPOCH); + } + + @Test + public void testPurgeEmoteWithPeriod() { + TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class); + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote, Duration.ofHours(4))); + TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class); + when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(trackedEmoteServer)).thenReturn(actualTrackedEmote); + testUnit.execute(commandContext); + verify(usedEmoteService, times(1)).purgeEmoteUsagesSince(eq(actualTrackedEmote), any(Instant.class)); + } + + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStatsTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStatsTest.java new file mode 100644 index 000000000..f3bceb8fe --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ResetEmoteStatsTest.java @@ -0,0 +1,39 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ResetEmoteStatsTest { + + @InjectMocks + private ResetEmoteStats testUnit; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Test + public void testExecute() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + CommandResult result = testUnit.execute(commandContext); + CommandTestUtilities.checkSuccessfulCompletion(result); + verify(trackedEmoteService, times(1)).resetEmoteStats(commandContext.getGuild()); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmoteTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmoteTest.java new file mode 100644 index 000000000..c806628d4 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowExternalTrackedEmoteTest.java @@ -0,0 +1,87 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; + +import static dev.sheldan.abstracto.statistic.emotes.command.ShowExternalTrackedEmote.SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ShowExternalTrackedEmoteTest { + + @InjectMocks + private ShowExternalTrackedEmote testUnit; + + @Mock + private ChannelService channelService; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Test(expected = InsufficientParametersException.class) + public void testTooLittleParameters() { + CommandTestUtilities.executeNoParametersTestAsync(testUnit); + } + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTestAsync(testUnit); + } + + @Test + public void testShowExternalEmote() { + TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class); + when(actualTrackedEmote.getExternal()).thenReturn(true); + TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class); + when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId())).thenReturn(actualTrackedEmote); + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote)); + when(channelService.sendEmbedTemplateInChannel(SHOW_EXTERNAL_TRACKED_EMOTE_RESPONSE_TEMPLATE_KEY, actualTrackedEmote, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CompletableFuture resultFuture = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(resultFuture); + } + + @Test(expected = AbstractoTemplatedException.class) + public void testShowNotExternalEmote() { + TrackedEmote fakeTrackedEmote = Mockito.mock(TrackedEmote.class); + TrackedEmote actualTrackedEmote = Mockito.mock(TrackedEmote.class); + when(actualTrackedEmote.getExternal()).thenReturn(false); + TrackedEmoteServer trackedEmoteServer = Mockito.mock(TrackedEmoteServer.class); + when(fakeTrackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteManagementService.loadByTrackedEmoteServer(fakeTrackedEmote.getTrackedEmoteId())).thenReturn(actualTrackedEmote); + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(fakeTrackedEmote)); + CompletableFuture resultFuture = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(resultFuture); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + + @Test + public void testFeatureModeLimitations() { + Assert.assertTrue(testUnit.getFeatureModeLimitations().contains(EmoteTrackingMode.EXTERNAL_EMOTES)); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotesTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotesTest.java new file mode 100644 index 000000000..3c8924b27 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/ShowTrackedEmotesTest.java @@ -0,0 +1,233 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.AvailableTrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; + +import static dev.sheldan.abstracto.statistic.emotes.command.ShowTrackedEmotes.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class ShowTrackedEmotesTest { + + @InjectMocks + private ShowTrackedEmotes testUnit; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private ChannelService channelService; + + @Mock + private FeatureModeService featureModeService; + + private static final Long SERVER_ID = 4L; + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTestAsync(testUnit); + } + + @Test + public void testShowTrackedEmotesNoStats() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + when(channelService.sendEmbedTemplateInChannel(eq(EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(commandContext.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList()); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + verifyNoMessage(commandContext, false, true, true, true, true, true, true); + } + + @Test + public void testShowTrackedEmotesNoStatsWithShowAll() { + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(Boolean.TRUE)); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + when(channelService.sendEmbedTemplateInChannel(eq(EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(commandContext.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList()); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), true)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + verifyNoMessage(commandContext, false, true, true, true, true, true, true); + } + + @Test + public void testShowStaticEmotes() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + AvailableTrackedEmote staticEmote = Mockito.mock(AvailableTrackedEmote.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getStaticEmotes()).thenReturn(Arrays.asList(staticEmote)); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, false, true, true, true, true, true); + } + + @Test + public void testShowAnimatedEmotes() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + AvailableTrackedEmote animatedEmote = Mockito.mock(AvailableTrackedEmote.class); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, true, false, true, true, true, true); + } + + @Test + public void testShowDeletedStaticEmote() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getDeletedStaticEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, true, true, false, true, true, true); + } + + @Test + public void testShowDeletedAnimatedEmote() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getDeletedAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, true, true, true, false, true, true); + } + + + @Test + public void testShowExternalStatic() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getExternalStaticEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, true, true, true, true, false, true); + } + + @Test + public void testShowExternalAnimated() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getExternalAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, true, true, true, true, true, false); + } + + @Test + public void testShowAll() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteOverview overview = Mockito.mock(TrackedEmoteOverview.class); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + TrackedEmote animatedEmote = Mockito.mock(TrackedEmote.class); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_DELETED_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(channelService.sendEmbedTemplateInChannel(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE, overview, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + when(overview.getExternalAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(overview.getExternalStaticEmotes()).thenReturn(Arrays.asList(animatedEmote)); + AvailableTrackedEmote trackedEmote = Mockito.mock(AvailableTrackedEmote.class); + when(overview.getStaticEmotes()).thenReturn(Arrays.asList(trackedEmote)); + when(overview.getAnimatedEmotes()).thenReturn(Arrays.asList(trackedEmote)); + when(overview.getDeletedStaticEmotes()).thenReturn(Arrays.asList(animatedEmote)); + when(overview.getDeletedAnimatedEmotes()).thenReturn(Arrays.asList(animatedEmote)); + + when(trackedEmoteService.loadTrackedEmoteOverview(commandContext.getGuild(), false)).thenReturn(overview); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + + verifyNoMessage(commandContext, true, false, false, false, false, false, false); + } + + private void verifyNoMessage(CommandContext commandContext, boolean noStats, boolean staticEmote, boolean animatedEmote, boolean deletedStatic, boolean deletedAnimated, boolean externalStatic, boolean externalAnimated) { + if(noStats) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_NO_STATS_AVAILABLE), any(), eq(commandContext.getChannel())); + } + if(staticEmote) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_STATIC_RESPONSE), any(), eq(commandContext.getChannel())); + } + if(animatedEmote) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_ANIMATED_RESPONSE), any(), eq(commandContext.getChannel())); + } + if(deletedStatic) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_DELETED_STATIC_RESPONSE), any(), eq(commandContext.getChannel())); + } + if(deletedAnimated) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_DELETED_ANIMATED_RESPONSE), any(), eq(commandContext.getChannel())); + } + if(externalStatic) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_EXTERNAL_STATIC_RESPONSE), any(), eq(commandContext.getChannel())); + } + if(externalAnimated) { + verify(channelService, times(0)).sendEmbedTemplateInChannel(eq(EMOTE_STATS_EXTERNAL_ANIMATED_RESPONSE), any(), eq(commandContext.getChannel())); + } + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotesTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotesTest.java new file mode 100644 index 000000000..3ab12519f --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/SyncTrackedEmotesTest.java @@ -0,0 +1,50 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.concurrent.CompletableFuture; + +import static dev.sheldan.abstracto.statistic.emotes.command.SyncTrackedEmotes.SYNC_TRACKED_EMOTES_RESULT_RESPONSE; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class SyncTrackedEmotesTest { + + @InjectMocks + private SyncTrackedEmotes testUnit; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private ChannelService channelService; + + @Test + public void testExecuteSync() { + CommandContext commandContext = CommandTestUtilities.getNoParameters(); + TrackedEmoteSynchronizationResult result = Mockito.mock(TrackedEmoteSynchronizationResult.class); + when(trackedEmoteService.synchronizeTrackedEmotes(commandContext.getGuild())).thenReturn(result); + when(channelService.sendEmbedTemplateInChannel(SYNC_TRACKED_EMOTES_RESULT_RESPONSE, result, commandContext.getChannel())).thenReturn(CommandTestUtilities.messageFutureList()); + CompletableFuture asyncResult = testUnit.executeAsync(commandContext); + CommandTestUtilities.checkSuccessfulCompletionAsync(asyncResult); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmoteTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmoteTest.java new file mode 100644 index 000000000..9b6d14d96 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/TrackEmoteTest.java @@ -0,0 +1,127 @@ +package dev.sheldan.abstracto.statistic.emotes.command; + +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException; +import dev.sheldan.abstracto.core.command.exception.IncorrectParameterTypeException; +import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.exception.IncorrectFeatureModeException; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.test.command.CommandTestUtilities; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class TrackEmoteTest { + + @InjectMocks + private TrackEmote testUnit; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Mock + private EmoteService emoteService; + + @Mock + private FeatureModeService featureModeService; + + @Mock + private TrackEmoteParameter trackEmoteParameter; + + private static final Long EMOTE_ID = 4L; + private static final Long SERVER_ID = 5L; + + @Test(expected = InsufficientParametersException.class) + public void testTooLittleParameters() { + CommandTestUtilities.executeNoParametersTest(testUnit); + } + + @Test(expected = IncorrectParameterTypeException.class) + public void testIncorrectParameterType() { + CommandTestUtilities.executeWrongParametersTest(testUnit); + } + + @Test + public void testReTrackTrackedEmote(){ + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter)); + when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(true); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + when(trackedEmoteManagementService.loadByEmoteId(EMOTE_ID, SERVER_ID)).thenReturn(trackedEmote); + when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote); + CommandResult result = testUnit.execute(commandContext); + CommandTestUtilities.checkSuccessfulCompletion(result); + verify(trackedEmoteManagementService, times(1)).enableTrackedEmote(trackedEmote); + } + + @Test(expected = IncorrectFeatureModeException.class) + public void testTrackExternalWithExternalDisabled(){ + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter)); + when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(false); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + Emote emoteToTrack = Mockito.mock(Emote.class); + when(trackEmoteParameter.getEmote()).thenReturn(emoteToTrack); + when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote); + when(emoteService.emoteIsFromGuild(emoteToTrack, commandContext.getGuild())).thenReturn(false); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(false); + testUnit.execute(commandContext); + } + + @Test + public void testTrackExternalWithExternalEnabled(){ + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter)); + when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(false); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + Emote emoteToTrack = Mockito.mock(Emote.class); + when(trackEmoteParameter.getEmote()).thenReturn(emoteToTrack); + when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote); + when(emoteService.emoteIsFromGuild(emoteToTrack, commandContext.getGuild())).thenReturn(false); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + CommandResult result = testUnit.execute(commandContext); + CommandTestUtilities.checkSuccessfulCompletion(result); + verify(trackedEmoteService, times(1)).createFakeTrackedEmote(emoteToTrack, commandContext.getGuild()); + } + + @Test(expected = IncorrectParameterException.class) + public void testTrackExternalIncorrectParameter(){ + CommandContext commandContext = CommandTestUtilities.getWithParameters(Arrays.asList(trackEmoteParameter)); + when(trackedEmoteManagementService.trackedEmoteExists(EMOTE_ID, SERVER_ID)).thenReturn(false); + when(commandContext.getGuild().getIdLong()).thenReturn(SERVER_ID); + TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + when(trackEmoteParameter.getTrackedEmote()).thenReturn(trackedEmote); + testUnit.execute(commandContext); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterHandlerTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterHandlerTest.java new file mode 100644 index 000000000..e84545977 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterHandlerTest.java @@ -0,0 +1,83 @@ +package dev.sheldan.abstracto.statistic.emotes.command.handler; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; +import dev.sheldan.abstracto.statistic.emotes.command.parameter.handler.TrackedEmoteParameterHandler; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class TrackedEmoteParameterHandlerTest { + + @InjectMocks + private TrackedEmoteParameterHandler testUnit; + + @Mock + private EmoteParameterHandler emoteParameterHandler; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private Message contextMessage; + + @Mock + private CommandParameterIterators iterators; + + @Mock + private Guild guild; + + @Mock + private TrackedEmote trackedEmote; + + private static final String WRONG_FORMATTED_INPUT = "input"; + + @Test + public void testHandleIncorrect() { + Assert.assertFalse(testUnit.handles(String.class)); + } + + @Test + public void testHandleCorrect() { + Assert.assertTrue(testUnit.handles(TrackedEmote.class)); + } + + @Test + public void testHandleWithEmote() { + when(contextMessage.getGuild()).thenReturn(guild); + Emote emote = Mockito.mock(Emote.class); + when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(emote); + when(trackedEmoteService.getFakeTrackedEmote(emote, guild)).thenReturn(trackedEmote); + TrackedEmote parsedEmote = (TrackedEmote) testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage); + Assert.assertEquals(trackedEmote, parsedEmote); + } + + @Test + public void testHandleWithId() { + Long emoteId = 5L; + when(contextMessage.getGuild()).thenReturn(guild); + when(trackedEmoteService.getFakeTrackedEmote(emoteId, guild)).thenReturn(trackedEmote); + when(emoteParameterHandler.handle(emoteId.toString(), iterators, Emote.class, contextMessage)).thenReturn(null); + TrackedEmote parsedEmote = (TrackedEmote) testUnit.handle(emoteId.toString(), iterators, TrackedEmote.class, contextMessage); + verify(trackedEmoteService, times(0)).getFakeTrackedEmote(any(Emote.class), eq(guild)); + Assert.assertEquals(trackedEmote, parsedEmote); + } + + @Test(expected = NumberFormatException.class) + public void testWithIllegalInput() { + when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(null); + testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterParameterHandlerTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterParameterHandlerTest.java new file mode 100644 index 000000000..a33884049 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/command/handler/TrackedEmoteParameterParameterHandlerTest.java @@ -0,0 +1,89 @@ +package dev.sheldan.abstracto.statistic.emotes.command.handler; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; +import dev.sheldan.abstracto.statistic.emotes.command.parameter.TrackEmoteParameter; +import dev.sheldan.abstracto.statistic.emotes.command.parameter.handler.TrackedEmoteParameterParameterHandler; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class TrackedEmoteParameterParameterHandlerTest { + + @InjectMocks + private TrackedEmoteParameterParameterHandler testUnit; + + @Mock + private EmoteParameterHandler emoteParameterHandler; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private Message contextMessage; + + @Mock + private CommandParameterIterators iterators; + + @Mock + private Guild guild; + + @Mock + private TrackedEmote trackedEmote; + + private static final String WRONG_FORMATTED_INPUT = "input"; + + @Test + public void testHandleIncorrect() { + Assert.assertFalse(testUnit.handles(String.class)); + } + + @Test + public void testHandleCorrect() { + Assert.assertTrue(testUnit.handles(TrackEmoteParameter.class)); + } + + @Test + public void testHandleWithEmote() { + when(contextMessage.getGuild()).thenReturn(guild); + Emote emote = Mockito.mock(Emote.class); + when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(emote); + when(trackedEmoteService.getFakeTrackedEmote(emote, guild)).thenReturn(trackedEmote); + TrackEmoteParameter parsedEmote = (TrackEmoteParameter) testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage); + Assert.assertEquals(trackedEmote, parsedEmote.getTrackedEmote()); + Assert.assertEquals(emote, parsedEmote.getEmote()); + } + + @Test + public void testHandleWithId() { + Long emoteId = 5L; + when(contextMessage.getGuild()).thenReturn(guild); + when(trackedEmoteService.getFakeTrackedEmote(emoteId, guild)).thenReturn(trackedEmote); + when(emoteParameterHandler.handle(emoteId.toString(), iterators, Emote.class, contextMessage)).thenReturn(null); + TrackEmoteParameter parsedEmote = (TrackEmoteParameter) testUnit.handle(emoteId.toString(), iterators, TrackedEmote.class, contextMessage); + verify(trackedEmoteService, times(0)).getFakeTrackedEmote(any(Emote.class), eq(guild)); + Assert.assertEquals(trackedEmote, parsedEmote.getTrackedEmote()); + } + + @Test(expected = NumberFormatException.class) + public void testWithIllegalInput() { + when(emoteParameterHandler.handle(WRONG_FORMATTED_INPUT, iterators, Emote.class, contextMessage)).thenReturn(null); + testUnit.handle(WRONG_FORMATTED_INPUT, iterators, TrackedEmote.class, contextMessage); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverterTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverterTest.java new file mode 100644 index 000000000..ef7c394b7 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/converter/EmoteStatsConverterTest.java @@ -0,0 +1,138 @@ +package dev.sheldan.abstracto.statistic.emotes.converter; + +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class EmoteStatsConverterTest { + @InjectMocks + private EmoteStatsConverter testUnit; + + @Mock + private BotService botService; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Mock + private EmoteStatsResult emoteStatsResult; + + @Mock + private EmoteStatsResult emoteStatsResult2; + + @Mock + private TrackedEmote trackedEmote; + + @Mock + private TrackedEmote trackedEmote2; + + @Mock + private Guild guild; + + private static final Long EMOTE_ID = 4L; + private static final Long EMOTE_ID_2 = 5L; + private static final Long SERVER_ID = 6L; + + @Test + public void testFromEmoteStatsResultsEmpty() { + EmoteStatsModel result = testUnit.fromEmoteStatsResults(new ArrayList<>()); + Assert.assertEquals(0, result.getStaticEmotes().size()); + Assert.assertEquals(0, result.getAnimatedEmotes().size()); + Assert.assertFalse(result.areStatsAvailable()); + } + + @Test + public void testFromEmoteStatsExternal() { + setupResults(); + when(trackedEmote.getExternal()).thenReturn(true); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote2.getExternal()).thenReturn(true); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(botService.getGuildById(SERVER_ID)).thenReturn(guild); + EmoteStatsModel result = testUnit.fromEmoteStatsResults(Arrays.asList(emoteStatsResult, emoteStatsResult2)); + + Assert.assertEquals(1, result.getStaticEmotes().size()); + Assert.assertEquals(trackedEmote, result.getStaticEmotes().get(0).getTrackedEmote()); + Assert.assertNull(result.getStaticEmotes().get(0).getEmote()); + Assert.assertEquals(1, result.getAnimatedEmotes().size()); + Assert.assertNull(result.getAnimatedEmotes().get(0).getEmote()); + Assert.assertEquals(trackedEmote2, result.getAnimatedEmotes().get(0).getTrackedEmote()); + Assert.assertTrue(result.areStatsAvailable()); + } + + @Test + public void testFromEmoteStatsInternal() { + setupResults(); + when(trackedEmote.getExternal()).thenReturn(false); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote.getDeleted()).thenReturn(false); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + when(trackedEmote2.getExternal()).thenReturn(false); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(trackedEmote2.getDeleted()).thenReturn(false); + when(trackedEmote2.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID_2, SERVER_ID)); + when(botService.getGuildById(SERVER_ID)).thenReturn(guild); + Emote emote1 = Mockito.mock(Emote.class); + when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote1); + Emote emote2 = Mockito.mock(Emote.class); + when(guild.getEmoteById(EMOTE_ID_2)).thenReturn(emote2); + EmoteStatsModel result = testUnit.fromEmoteStatsResults(Arrays.asList(emoteStatsResult, emoteStatsResult2)); + + Assert.assertEquals(1, result.getStaticEmotes().size()); + Assert.assertEquals(trackedEmote, result.getStaticEmotes().get(0).getTrackedEmote()); + Assert.assertEquals(emote1, result.getStaticEmotes().get(0).getEmote()); + Assert.assertEquals(1, result.getAnimatedEmotes().size()); + Assert.assertEquals(emote2, result.getAnimatedEmotes().get(0).getEmote()); + Assert.assertEquals(trackedEmote2, result.getAnimatedEmotes().get(0).getTrackedEmote()); + Assert.assertTrue(result.areStatsAvailable()); + } + + @Test + public void testFromEmoteStatsInternalDeleted() { + setupResults(); + when(trackedEmote.getExternal()).thenReturn(false); + when(trackedEmote.getDeleted()).thenReturn(true); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote2.getExternal()).thenReturn(false); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(trackedEmote2.getDeleted()).thenReturn(true); + when(botService.getGuildById(SERVER_ID)).thenReturn(guild); + EmoteStatsModel result = testUnit.fromEmoteStatsResults(Arrays.asList(emoteStatsResult, emoteStatsResult2)); + + Assert.assertEquals(1, result.getStaticEmotes().size()); + Assert.assertEquals(trackedEmote, result.getStaticEmotes().get(0).getTrackedEmote()); + Assert.assertNull(result.getStaticEmotes().get(0).getEmote()); + Assert.assertEquals(1, result.getAnimatedEmotes().size()); + Assert.assertNull(result.getAnimatedEmotes().get(0).getEmote()); + Assert.assertEquals(trackedEmote2, result.getAnimatedEmotes().get(0).getTrackedEmote()); + Assert.assertTrue(result.areStatsAvailable()); + } + + + private void setupResults() { + when(emoteStatsResult.getEmoteId()).thenReturn(EMOTE_ID); + when(emoteStatsResult.getServerId()).thenReturn(SERVER_ID); + when(trackedEmoteManagementService.loadByEmoteId(EMOTE_ID, SERVER_ID)).thenReturn(trackedEmote); + when(emoteStatsResult2.getEmoteId()).thenReturn(EMOTE_ID_2); + when(emoteStatsResult2.getServerId()).thenReturn(SERVER_ID); + when(trackedEmoteManagementService.loadByEmoteId(EMOTE_ID_2, SERVER_ID)).thenReturn(trackedEmote2); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJobTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJobTest.java new file mode 100644 index 000000000..952467d02 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/job/EmotePersistingJobTest.java @@ -0,0 +1,72 @@ +package dev.sheldan.abstracto.statistic.emotes.job; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteRuntimeService; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class EmotePersistingJobTest { + + @InjectMocks + @Spy + private EmotePersistingJob testUnit; + + @Mock + private TrackedEmoteRuntimeService trackedEmoteRuntimeService; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private JobExecutionContext executionContext; + + @Test + public void testExecuteNoEmoteStats() throws JobExecutionException { + when(trackedEmoteRuntimeService.getRuntimeConfig()).thenReturn(new HashMap<>()); + testUnit.executeInternal(executionContext); + verify(trackedEmoteService, times(0)).storeEmoteStatistics(any()); + } + + @Test + public void testExecuteWithStats() throws JobExecutionException { + Map>> emoteStats = new HashMap<>(); + long minuteToPersist = 4L; + Map> statsForMinute = new HashMap<>(); + statsForMinute.put(8L, new ArrayList<>()); + emoteStats.put(minuteToPersist, statsForMinute); + when(trackedEmoteRuntimeService.getRuntimeConfig()).thenReturn(emoteStats); + when(testUnit.getPastMinute()).thenReturn(minuteToPersist); + testUnit.executeInternal(executionContext); + verify(trackedEmoteService, times(1)).storeEmoteStatistics(any()); + } + + @Test + public void testExecuteWithPastStats() throws JobExecutionException { + Map>> emoteStats = new HashMap<>(); + long minuteToPersist = 4L; + Map> statsForMinute = new HashMap<>(); + statsForMinute.put(8L, new ArrayList<>()); + emoteStats.put(minuteToPersist, statsForMinute); + emoteStats.put(minuteToPersist - 2, statsForMinute); + when(trackedEmoteRuntimeService.getRuntimeConfig()).thenReturn(emoteStats); + when(testUnit.getPastMinute()).thenReturn(minuteToPersist); + testUnit.executeInternal(executionContext); + verify(trackedEmoteService, times(2)).storeEmoteStatistics(any()); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListenerTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListenerTest.java new file mode 100644 index 000000000..7f74ba019 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/CreateTrackedEmoteListenerTest.java @@ -0,0 +1,49 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class CreateTrackedEmoteListenerTest { + + @InjectMocks + private CreateTrackedEmoteListener testUnit; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Test + public void testEmoteCreated() { + Long serverId = 4L; + Long emoteId = 5L; + Emote emote = Mockito.mock(Emote.class); + Guild guild = Mockito.mock(Guild.class); + when(guild.getIdLong()).thenReturn(serverId); + when(emote.getIdLong()).thenReturn(emoteId); + when(emote.getGuild()).thenReturn(guild); + testUnit.emoteCreated(emote); + verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + + @Test + public void testPriority() { + Assert.assertEquals(ListenerPriority.MEDIUM, testUnit.getPriority()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListenerTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListenerTest.java new file mode 100644 index 000000000..26721e229 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/DeleteTrackedEmoteListenerTest.java @@ -0,0 +1,49 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class DeleteTrackedEmoteListenerTest { + + @InjectMocks + private DeleteTrackedEmoteListener testUnit; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Test + public void testEmoteDeleted() { + Long serverId = 4L; + Long emoteId = 5L; + Emote emote = Mockito.mock(Emote.class); + Guild guild = Mockito.mock(Guild.class); + when(guild.getIdLong()).thenReturn(serverId); + when(emote.getIdLong()).thenReturn(emoteId); + when(emote.getGuild()).thenReturn(guild); + testUnit.emoteDeleted(emote); + verify(trackedEmoteManagementService, times(1)).markAsDeleted(serverId, emoteId); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + + @Test + public void testPriority() { + Assert.assertEquals(ListenerPriority.MEDIUM, testUnit.getPriority()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListenerTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListenerTest.java new file mode 100644 index 000000000..84a2ddc63 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/EmoteTrackingListenerTest.java @@ -0,0 +1,96 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import org.apache.commons.collections4.bag.HashBag; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class EmoteTrackingListenerTest { + + @InjectMocks + private EmoteTrackingListener testUnit; + + @Mock + private TrackedEmoteService trackedEmoteService; + + @Mock + private Message message; + + @Mock + private Emote emote1; + + @Mock + private Emote emote2; + + @Mock + private Guild guild; + + private static final Long EMOTE_ID = 4L; + + @Test + public void testExecuteOneEmote() { + HashBag emotesBag = new HashBag<>(); + emotesBag.add(emote1); + when(message.getGuild()).thenReturn(guild); + when(message.getEmotesBag()).thenReturn(emotesBag); + testUnit.execute(message); + verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L); + } + + @Test + public void testExecuteOneEmoteMultipleTimes() { + HashBag emotesBag = new HashBag<>(); + when(emote1.getIdLong()).thenReturn(EMOTE_ID); + when(emote2.getIdLong()).thenReturn(EMOTE_ID); + emotesBag.add(emote1); + emotesBag.add(emote2); + when(message.getGuild()).thenReturn(guild); + when(message.getEmotesBag()).thenReturn(emotesBag); + testUnit.execute(message); + verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(any(Emote.class), eq(guild), eq(2L)); + } + + @Test + public void testExecuteMultipleEmotes() { + HashBag emotesBag = new HashBag<>(); + when(emote1.getIdLong()).thenReturn(EMOTE_ID); + when(emote2.getIdLong()).thenReturn(EMOTE_ID + 1); + emotesBag.add(emote1); + emotesBag.add(emote2); + when(message.getGuild()).thenReturn(guild); + when(message.getEmotesBag()).thenReturn(emotesBag); + testUnit.execute(message); + verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L); + verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote2, guild, 1L); + } + + @Test + public void testExecuteNoEmote() { + when(message.getEmotesBag()).thenReturn(new HashBag<>()); + testUnit.execute(message); + verify(trackedEmoteService, times(0)).addEmoteToRuntimeStorage(any(), any(), anyLong()); + } + + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + + @Test + public void testPriority() { + Assert.assertEquals(ListenerPriority.LOW, testUnit.getPriority()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListenerTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListenerTest.java new file mode 100644 index 000000000..6af60121e --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/listener/UpdateTrackedEmoteListenerTest.java @@ -0,0 +1,46 @@ +package dev.sheldan.abstracto.statistic.emotes.listener; + +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class UpdateTrackedEmoteListenerTest { + + @InjectMocks + private UpdateTrackedEmoteListener testUnit; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Test + public void testEmoteUpdated() { + Emote changedEmote = Mockito.mock(Emote.class); + TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class); + when(trackedEmoteManagementService.loadByEmote(changedEmote)).thenReturn(trackedEmote); + String newValue = "AFTER"; + testUnit.emoteUpdated(changedEmote, "BEFORE", newValue); + verify(trackedEmoteManagementService, times(1)).changeName(trackedEmote, newValue); + } + + @Test + public void testFeature() { + Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); + } + + @Test + public void testPriority() { + Assert.assertEquals(ListenerPriority.MEDIUM, testUnit.getPriority()); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBeanTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBeanTest.java new file mode 100644 index 000000000..f84c0f865 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeServiceBeanTest.java @@ -0,0 +1,181 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class TrackedEmoteRuntimeServiceBeanTest { + + @InjectMocks + @Spy + private TrackedEmoteRuntimeServiceBean testUnit; + + @Mock + private TrackedEmoteRunTimeStorage trackedEmoteRunTimeStorage; + + @Mock + private Guild guild; + + @Mock + private Emote emote; + + @Mock + private PersistingEmote persistingEmote; + + @Captor + private ArgumentCaptor>> putCaptor; + + private static final Long COUNT = 4L; + private static final String URL = "url"; + private static final Long EMOTE_ID = 8L; + private static final Long SECOND = 9L; + private static final Long SERVER_ID = 45L; + + @Test + public void testCreateFromEmoteFromGuild() { + when(emote.getIdLong()).thenReturn(EMOTE_ID); + PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, false); + Assert.assertFalse(createdEmote.getExternal()); + Assert.assertNull(createdEmote.getExternalUrl()); + Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId()); + Assert.assertEquals(COUNT, createdEmote.getCount()); + } + + @Test + public void testCreateFromEmoteExternal() { + when(emote.getImageUrl()).thenReturn(URL); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, true); + Assert.assertTrue(createdEmote.getExternal()); + Assert.assertEquals(URL, createdEmote.getExternalUrl()); + Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId()); + Assert.assertEquals(COUNT, createdEmote.getCount()); + } + + @Test + public void testCreateFromEmoteOneCountFromGuild() { + when(emote.getIdLong()).thenReturn(EMOTE_ID); + PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, false); + Assert.assertFalse(createdEmote.getExternal()); + Assert.assertNull(createdEmote.getExternalUrl()); + Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId()); + Assert.assertEquals(1, createdEmote.getCount().longValue()); + } + + @Test + public void testCreateFromEmoteOneCountExternal() { + when(emote.getImageUrl()).thenReturn(URL); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, true); + Assert.assertTrue(createdEmote.getExternal()); + Assert.assertEquals(URL, createdEmote.getExternalUrl()); + Assert.assertEquals(EMOTE_ID, createdEmote.getEmoteId()); + Assert.assertEquals(1, createdEmote.getCount().longValue()); + } + + @Test + public void testEmoteForServerWithoutExistingSecond() { + doReturn(SECOND).when(testUnit).getKey(); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(false); + testUnit.addEmoteForServer(emote, guild, false); + verify(trackedEmoteRunTimeStorage, times(1)).put(eq(SECOND), putCaptor.capture()); + HashMap> value = putCaptor.getValue(); + Assert.assertEquals(1, value.keySet().size()); + Assert.assertEquals(SERVER_ID, value.keySet().iterator().next()); + List createdEmotes = value.values().iterator().next(); + Assert.assertEquals(1, createdEmotes.size()); + Assert.assertEquals(EMOTE_ID, createdEmotes.get(0).getEmoteId()); + } + + @Test + public void testEmoteForServerWithExistingSecondButNotServer() { + doReturn(SECOND).when(testUnit).getKey(); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); + HashMap> serverMap = new HashMap<>(); + when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap); + testUnit.addEmoteForServer(emote, guild, false); + Assert.assertEquals(1, serverMap.keySet().size()); + Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next()); + List createdEmotes = serverMap.values().iterator().next(); + Assert.assertEquals(1, createdEmotes.size()); + Assert.assertEquals(EMOTE_ID, createdEmotes.get(0).getEmoteId()); + } + + @Test + public void testEmoteForServerWithExistingSecondAndServerButNotEmote() { + doReturn(SECOND).when(testUnit).getKey(); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); + HashMap> serverMap = new HashMap<>(); + serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote))); + when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap); + testUnit.addEmoteForServer(emote, guild, false); + Assert.assertEquals(1, serverMap.keySet().size()); + Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next()); + List persistingEmotes = serverMap.values().iterator().next(); + Assert.assertEquals(2, persistingEmotes.size()); + Assert.assertEquals(persistingEmote, persistingEmotes.get(0)); + Assert.assertEquals(EMOTE_ID, persistingEmotes.get(1).getEmoteId()); + } + + @Test + public void testEmoteForServerWithExistingSecondAndServerAndEmote() { + doReturn(SECOND).when(testUnit).getKey(); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); + HashMap> serverMap = new HashMap<>(); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(persistingEmote.getCount()).thenReturn(COUNT); + serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote))); + when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap); + testUnit.addEmoteForServer(emote, guild, false); + Assert.assertEquals(1, serverMap.keySet().size()); + Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next()); + List persistingEmotes = serverMap.values().iterator().next(); + Assert.assertEquals(1, persistingEmotes.size()); + PersistingEmote persistedEmote = persistingEmotes.get(0); + Assert.assertEquals(EMOTE_ID, persistedEmote.getEmoteId()); + verify(persistedEmote, times(1)).setCount(COUNT + 1); + } + + @Test + public void testEmoteForServerWithExistingSecondAndServerAndEmoteCustomCount() { + doReturn(SECOND).when(testUnit).getKey(); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); + HashMap> serverMap = new HashMap<>(); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(persistingEmote.getCount()).thenReturn(COUNT); + serverMap.put(SERVER_ID, new ArrayList<>(Arrays.asList(persistingEmote))); + when(trackedEmoteRunTimeStorage.get(SECOND)).thenReturn(serverMap); + testUnit.addEmoteForServer(emote, guild, COUNT, false); + Assert.assertEquals(1, serverMap.keySet().size()); + Assert.assertEquals(SERVER_ID, serverMap.keySet().iterator().next()); + List persistingEmotes = serverMap.values().iterator().next(); + Assert.assertEquals(1, persistingEmotes.size()); + PersistingEmote persistedEmote = persistingEmotes.get(0); + Assert.assertEquals(EMOTE_ID, persistedEmote.getEmoteId()); + verify(persistedEmote, times(1)).setCount(COUNT + COUNT); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBeanTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBeanTest.java new file mode 100644 index 000000000..49e7c2d4b --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteServiceBeanTest.java @@ -0,0 +1,540 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.core.service.BotService; +import dev.sheldan.abstracto.core.service.EmoteService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; +import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Instant; +import java.util.*; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class TrackedEmoteServiceBeanTest { + + private static final Long COUNT = 2L; + private static final Long SERVER_ID = 3L; + private static final Long EMOTE_ID = 5L; + private static final Long EMOTE_ID_2 = 6L; + @InjectMocks + private TrackedEmoteServiceBean testUnit; + + @Mock + private TrackedEmoteRuntimeService trackedEmoteRuntimeService; + + @Mock + private FeatureModeService featureModeService; + + @Mock + private EmoteService emoteService; + + @Mock + private TrackedEmoteManagementService trackedEmoteManagementService; + + @Mock + private UsedEmoteManagementService usedEmoteManagementService; + + @Mock + private BotService botService; + + @Mock + private Emote emote; + + @Mock + private Emote secondEmote; + + @Mock + private Guild guild; + + @Mock + private TrackedEmote trackedEmote; + + @Mock + private TrackedEmote trackedEmote2; + + @Mock + private TrackedEmoteServer trackedEmoteServer; + + @Mock + private TrackedEmote secondTrackedEmote; + + @Mock + private PersistingEmote persistingEmote; + + @Mock + private PersistingEmote persistingEmote2; + + @Mock + private UsedEmote usedEmote; + + @Mock + private TrackedEmoteServer secondTrackedEmoteServer; + + @Captor + private ArgumentCaptor emoteArgumentCaptor; + + @Captor + private ArgumentCaptor booleanArgumentCaptor; + + @Test + public void addSingleServerEmote() { + externalEmotesEnabled(true); + isEmoteExternal(false); + testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT); + verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT,false); + } + + @Test + public void addSingleExternalEmote() { + externalEmotesEnabled(true); + isEmoteExternal(true); + testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT); + verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT,true); + } + + @Test + public void addSingleExternalWhenExternalDisabled() { + externalEmotesEnabled(false); + isEmoteExternal(true); + testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT); + verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(eq(emote), eq(guild), anyBoolean()); + } + + @Test + public void addSingleServerEmoteExternalDisabled() { + externalEmotesEnabled(false); + isEmoteExternal(false); + testUnit.addEmoteToRuntimeStorage(emote, guild, COUNT); + verify(trackedEmoteRuntimeService, times(1)).addEmoteForServer(emote, guild, COUNT, false); + } + + @Test + public void addTwoExternalEmotes() { + externalEmotesEnabled(true); + bothEmotesExternal(true, true); + testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); + verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(true)); + List usedEmotes = emoteArgumentCaptor.getAllValues(); + Assert.assertEquals(2, usedEmotes.size()); + Assert.assertEquals(emote, usedEmotes.get(0)); + Assert.assertEquals(secondEmote, usedEmotes.get(1)); + } + + @Test + public void addOneExternalAndOneLocalEmote() { + externalEmotesEnabled(true); + bothEmotesExternal(true, false); + testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); + verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture()); + List usedEmotes = emoteArgumentCaptor.getAllValues(); + Assert.assertEquals(2, usedEmotes.size()); + Assert.assertEquals(emote, usedEmotes.get(0)); + Assert.assertEquals(secondEmote, usedEmotes.get(1)); + List externalValues = booleanArgumentCaptor.getAllValues(); + Assert.assertEquals(2, externalValues.size()); + Assert.assertTrue(externalValues.get(0)); + Assert.assertFalse(externalValues.get(1)); + } + + @Test + public void addTwoExternalEmotesWhenExternalDisabled() { + externalEmotesEnabled(false); + bothEmotesExternal(true, true); + testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); + verify(trackedEmoteRuntimeService, times(0)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture()); + } + + @Test + public void addTwoLocalEmotes() { + externalEmotesEnabled(false); + bothEmotesExternal(false, false); + testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); + verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture()); + List usedEmotes = emoteArgumentCaptor.getAllValues(); + Assert.assertEquals(2, usedEmotes.size()); + Assert.assertEquals(emote, usedEmotes.get(0)); + Assert.assertEquals(secondEmote, usedEmotes.get(1)); + List externalValues = booleanArgumentCaptor.getAllValues(); + Assert.assertEquals(2, externalValues.size()); + Assert.assertFalse(externalValues.get(0)); + Assert.assertFalse(externalValues.get(1)); + } + + public void bothEmotesExternal(boolean external, boolean external2) { + when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external); + when(emoteService.emoteIsFromGuild(secondEmote, guild)).thenReturn(!external2); + } + + public void isEmoteExternal(boolean external) { + when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external); + } + + public void externalEmotesEnabled(boolean external) { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(external); + } + + @Test + public void testCrateFakeEmote() { + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + TrackedEmote fakeTrackedEmote = testUnit.getFakeTrackedEmote(emote, guild); + Assert.assertTrue(fakeTrackedEmote.isFake()); + Assert.assertEquals(EMOTE_ID, fakeTrackedEmote.getTrackedEmoteId().getEmoteId()); + Assert.assertEquals(SERVER_ID, fakeTrackedEmote.getTrackedEmoteId().getServerId()); + } + + @Test + public void testCrateFakeEmoteViaId() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + TrackedEmote fakedTrackedEmote = testUnit.getFakeTrackedEmote(EMOTE_ID, guild); + Assert.assertTrue(fakedTrackedEmote.isFake()); + Assert.assertEquals(EMOTE_ID, fakedTrackedEmote.getTrackedEmoteId().getEmoteId()); + Assert.assertEquals(SERVER_ID, fakedTrackedEmote.getTrackedEmoteId().getServerId()); + } + + @Test + public void testSynchronizeTrackedEmotesNoNewEmotes() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID); + when(trackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID); + when(secondTrackedEmote.getTrackedEmoteId()).thenReturn(secondTrackedEmoteServer); + when(secondTrackedEmoteServer.getServerId()).thenReturn(SERVER_ID); + when(secondTrackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID_2); + when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote)); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(secondEmote.getIdLong()).thenReturn(EMOTE_ID_2); + when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote))); + TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); + Assert.assertEquals(0L, result.getEmotesAdded().longValue()); + Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue()); + verify(trackedEmoteManagementService, times(0)).createTrackedEmote(any(Emote.class), any(Guild.class)); + verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class)); + } + + @Test + public void testSynchronizeTrackedEmotesOneNewEmote() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID); + when(trackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID); + when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote)); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote))); + TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); + Assert.assertEquals(1L, result.getEmotesAdded().longValue()); + Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue()); + verify(trackedEmoteManagementService, times(1)).createTrackedEmote(secondEmote, guild); + verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class)); + } + + @Test + public void testSynchronizeTrackedEmotesWithEmotesDeleted() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID); + when(trackedEmoteServer.getEmoteId()).thenReturn(EMOTE_ID); + when(guild.getEmotes()).thenReturn(Arrays.asList(emote)); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote))); + TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); + Assert.assertEquals(0L, result.getEmotesAdded().longValue()); + Assert.assertEquals(1L, result.getEmotesMarkedDeleted().longValue()); + verify(trackedEmoteManagementService, times(0)).createTrackedEmote(any(Emote.class), any(Guild.class)); + verify(trackedEmoteManagementService, times(1)).markAsDeleted(secondTrackedEmote); + } + + @Test + public void testSynchronizeTrackedEmotesNoEmotesLeft() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(guild.getEmotes()).thenReturn(new ArrayList<>()); + when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote))); + TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); + Assert.assertEquals(0L, result.getEmotesAdded().longValue()); + Assert.assertEquals(2L, result.getEmotesMarkedDeleted().longValue()); + verify(trackedEmoteManagementService, times(0)).createTrackedEmote(any(Emote.class), any(Guild.class)); + verify(trackedEmoteManagementService, times(2)).markAsDeleted(any(TrackedEmote.class)); + } + + @Test + public void testSynchronizeTrackedEmotesAllEmotesAreNew() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote)); + when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>()); + TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); + Assert.assertEquals(2L, result.getEmotesAdded().longValue()); + Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue()); + verify(trackedEmoteManagementService, times(2)).createTrackedEmote(any(Emote.class), any(Guild.class)); + verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class)); + } + + @Test + public void testStoreEmptyEmoteStatistics() { + HashMap> usagesToStore = new HashMap<>(); + testUnit.storeEmoteStatistics(usagesToStore); + verify(featureModeService, times(0)).featureModeActive(eq(StatisticFeatures.EMOTE_TRACKING), anyLong(), eq(EmoteTrackingMode.AUTO_TRACK)); + } + + @Test + public void testStoreStatisticOneServerExistingInternalEmoteUsageExistsYetTrackingEnabled() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(persistingEmote.getCount()).thenReturn(COUNT); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote)); + when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.of(usedEmote)); + when(trackedEmote.getTrackingEnabled()).thenReturn(true); + when(usedEmote.getAmount()).thenReturn(COUNT); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmote, times(1)).setAmount(2 * COUNT); + } + + @Test + public void testStoreStatisticOneServerExistingInternalEmoteUsageExistsTrackingDisabled() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote)); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + when(trackedEmote.getTrackingEnabled()).thenReturn(false); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmote, times(0)).setAmount(anyLong()); + } + + @Test + public void testStoreStatisticOneServerExistingInternalEmoteNoUsageYetTrackingEnabled() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(persistingEmote.getCount()).thenReturn(COUNT); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(trackedEmote)); + when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.empty()); + when(trackedEmote.getTrackingEnabled()).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT); + } + + @Test + public void testStoreStatisticOneServerNotInternalEmoteTrackingDisabledAutoTracking() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty()); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong()); + } + + @Test + public void testStoreStatisticOneServerInternalEmoteTrackingEnabledAutoTracking() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild)); + when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote); + when(persistingEmote.getCount()).thenReturn(COUNT); + when(trackedEmoteManagementService.createTrackedEmote(emote, guild)).thenReturn(trackedEmote); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty()); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT); + } + + @Test + public void testStoreStatisticOneServerExternalEmoteTrackingEnabledAutoTrackingDisabledExternal() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild)); + when(guild.getEmoteById(EMOTE_ID)).thenReturn(null); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty()); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(false); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmoteManagementService, times(0)).createEmoteUsageForToday(any(TrackedEmote.class), anyLong()); + } + + @Test + public void testStoreStatisticOneServerExternalEmoteTrackingEnabledAutoTrackingEnabledExternal() { + HashMap> usagesToStore = new HashMap<>(); + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild)); + when(guild.getEmoteById(EMOTE_ID)).thenReturn(null); + when(persistingEmote.getCount()).thenReturn(COUNT); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty()); + when(trackedEmoteManagementService.createExternalEmote(persistingEmote)).thenReturn(trackedEmote); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + testUnit.storeEmoteStatistics(usagesToStore); + verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(trackedEmote, COUNT); + } + + @Test + public void testStoreStatisticTwoServerInternalEmoteCreateNewTrackedEmote() { + HashMap> usagesToStore = new HashMap<>(); + + usagesToStore.put(SERVER_ID, Arrays.asList(persistingEmote)); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID, SERVER_ID)).thenReturn(Optional.empty()); + when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild)); + when(guild.getEmoteById(EMOTE_ID)).thenReturn(null); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(persistingEmote.getCount()).thenReturn(COUNT); + when(trackedEmoteManagementService.createExternalEmote(persistingEmote)).thenReturn(trackedEmote); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, SERVER_ID, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + + Long serverId2 = SERVER_ID + 1; + usagesToStore.put(serverId2, Arrays.asList(persistingEmote2)); + when(trackedEmoteManagementService.loadByEmoteIdOptional(EMOTE_ID_2, serverId2)).thenReturn(Optional.of(trackedEmote)); + when(trackedEmote.getTrackingEnabled()).thenReturn(true); + when(persistingEmote2.getEmoteId()).thenReturn(EMOTE_ID_2); + when(persistingEmote2.getCount()).thenReturn(COUNT); + when(usedEmote.getAmount()).thenReturn(COUNT); + when(usedEmoteManagementService.loadUsedEmoteForTrackedEmoteToday(trackedEmote)).thenReturn(Optional.of(usedEmote)); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId2, EmoteTrackingMode.AUTO_TRACK_EXTERNAL)).thenReturn(true); + when(featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, serverId2, EmoteTrackingMode.EXTERNAL_EMOTES)).thenReturn(true); + + testUnit.storeEmoteStatistics(usagesToStore); + + verify(usedEmoteManagementService, times(1)).createEmoteUsageForToday(eq(trackedEmote), anyLong()); + verify(usedEmote, times(1)).setAmount(2 * COUNT); + } + + @Test + public void testCreateFakeTrackedEmoteExternal() { + executeCreateFakeTrackedEmoteTest(true); + } + + @Test + public void testCreateFakeTrackedEmoteInternal() { + executeCreateFakeTrackedEmoteTest(false); + } + + private void executeCreateFakeTrackedEmoteTest(boolean external) { + when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external); + testUnit.createFakeTrackedEmote(emote, guild); + verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild, external); + } + + @Test + public void testDeleteTrackedEmote() { + testUnit.deleteTrackedEmote(trackedEmote); + verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH); + verify(trackedEmoteManagementService, times(1)).deleteTrackedEmote(trackedEmote); + } + + @Test + public void testResetEmoteStats() { + when(trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true)).thenReturn(Arrays.asList(trackedEmote)); + testUnit.resetEmoteStats(guild); + verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH); + verify(trackedEmoteManagementService, times(1)).deleteTrackedEmote(trackedEmote); + } + + @Test + public void testResetEmoteStatsNoEmotes() { + when(trackedEmoteManagementService.getTrackedEmoteForServer(guild.getIdLong(), true)).thenReturn(new ArrayList<>()); + testUnit.resetEmoteStats(guild); + verify(usedEmoteManagementService, times(0)).purgeEmoteUsagesSince(any(TrackedEmote.class), eq(Instant.EPOCH)); + verify(trackedEmoteManagementService, times(0)).deleteTrackedEmote(any(TrackedEmote.class)); + } + + @Test + public void testDisableEmoteTracking() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote)); + testUnit.disableEmoteTracking(guild); + verify(trackedEmote, times(1)).setTrackingEnabled(false); + } + + @Test + public void testLoadTrackedEmoteOverviewInternal() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getDeleted()).thenReturn(false); + when(trackedEmote.getExternal()).thenReturn(false); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote2.getDeleted()).thenReturn(false); + when(trackedEmote2.getExternal()).thenReturn(false); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + when(trackedEmote2.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID_2, SERVER_ID)); + when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote); + Emote emote2 = Mockito.mock(Emote.class); + when(guild.getEmoteById(EMOTE_ID_2)).thenReturn(emote2); + when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2)); + TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true); + Assert.assertEquals(emote, trackedEmoteOverview.getStaticEmotes().get(0).getEmote()); + Assert.assertEquals(trackedEmote, trackedEmoteOverview.getStaticEmotes().get(0).getTrackedEmote()); + Assert.assertEquals(emote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getEmote()); + Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getTrackedEmote()); + } + + @Test + public void testLoadTrackedEmoteOverviewExternal() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getDeleted()).thenReturn(false); + when(trackedEmote.getExternal()).thenReturn(true); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote2.getDeleted()).thenReturn(false); + when(trackedEmote2.getExternal()).thenReturn(true); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2)); + TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true); + Assert.assertEquals(trackedEmote, trackedEmoteOverview.getExternalStaticEmotes().get(0)); + Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getExternalAnimatedEmotes().get(0)); + } + + @Test + public void testLoadTrackedEmoteOverviewDeleted() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getDeleted()).thenReturn(true); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote2.getDeleted()).thenReturn(true); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2)); + TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true); + Assert.assertEquals(trackedEmote, trackedEmoteOverview.getDeletedStaticEmotes().get(0)); + Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getDeletedAnimatedEmotes().get(0)); + } + + @Test + public void testLoadTrackedEmoteOverviewDeletedShowTrackedFalse() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(trackedEmote.getDeleted()).thenReturn(true); + when(trackedEmote.getAnimated()).thenReturn(false); + when(trackedEmote2.getDeleted()).thenReturn(true); + when(trackedEmote2.getAnimated()).thenReturn(true); + when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, false)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2)); + TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, false); + Assert.assertEquals(trackedEmote, trackedEmoteOverview.getDeletedStaticEmotes().get(0)); + Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getDeletedAnimatedEmotes().get(0)); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBeanTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBeanTest.java new file mode 100644 index 000000000..d2c21a32d --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteServiceBeanTest.java @@ -0,0 +1,105 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.converter.EmoteStatsConverter; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.service.management.UsedEmoteManagementService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class UsedEmoteServiceBeanTest { + + @InjectMocks + private UsedEmoteServiceBean testUnit; + + @Mock + private EmoteStatsConverter converter; + + @Mock + private UsedEmoteManagementService usedEmoteManagementService; + + @Mock + private AServer server; + + @Mock + private EmoteStatsModel emoteStatsModel; + + @Mock + private TrackedEmote trackedEmote; + + private static final Instant pointInTime = Instant.parse("2020-12-12T00:00:00.00Z"); + private static final Long SERVER_ID = 4L; + private static final Long EMOTE_ID = 7L; + + @Test + public void testGetEmoteStatsForServerSince() { + List mockedEmoteStatsResult = getMockedStatsResult(); + when(usedEmoteManagementService.loadAllEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult); + when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel); + EmoteStatsModel result = testUnit.getEmoteStatsForServerSince(server, pointInTime); + Assert.assertEquals(emoteStatsModel, result); + } + + @Test + public void testGetDeletedEmoteStatsForServerSince() { + List mockedEmoteStatsResult = getMockedStatsResult(); + when(usedEmoteManagementService.loadDeletedEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult); + when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel); + EmoteStatsModel result = testUnit.getDeletedEmoteStatsForServerSince(server, pointInTime); + Assert.assertEquals(emoteStatsModel, result); + } + + @Test + public void testGetExternalEmoteStatsForServerSince() { + List mockedEmoteStatsResult = getMockedStatsResult(); + when(usedEmoteManagementService.loadExternalEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult); + when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel); + EmoteStatsModel result = testUnit.getExternalEmoteStatsForServerSince(server, pointInTime); + Assert.assertEquals(emoteStatsModel, result); + } + + @Test + public void testGetActiveEmoteStatsForServerSince() { + List mockedEmoteStatsResult = getMockedStatsResult(); + when(usedEmoteManagementService.loadActiveEmoteStatsForServerSince(eq(server), any(Instant.class))).thenReturn(mockedEmoteStatsResult); + when(converter.fromEmoteStatsResults(mockedEmoteStatsResult)).thenReturn(emoteStatsModel); + EmoteStatsModel result = testUnit.getActiveEmoteStatsForServerSince(server, pointInTime); + Assert.assertEquals(emoteStatsModel, result); + } + + @Test + public void testPurgeEmoteUsagesSince() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + testUnit.purgeEmoteUsagesSince(trackedEmote, pointInTime); + verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, pointInTime); + } + + @Test + public void testPurgeEmoteUsages() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + testUnit.purgeEmoteUsages(trackedEmote); + verify(usedEmoteManagementService, times(1)).purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH); + } + + private List getMockedStatsResult() { + return Arrays.asList(Mockito.mock(EmoteStatsResult.class), Mockito.mock(EmoteStatsResult.class)); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBeanTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBeanTest.java new file mode 100644 index 000000000..153070bff --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementServiceBeanTest.java @@ -0,0 +1,284 @@ +package dev.sheldan.abstracto.statistic.emotes.service.management; + +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.service.management.ServerManagementService; +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.repository.TrackedEmoteRepository; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class TrackedEmoteManagementServiceBeanTest { + + private static final Long SERVER_ID = 3L; + private static final Long EMOTE_ID = 4L; + private static final String EMOTE_NAME = "name"; + private static final Boolean ANIMATED = true; + private static final String EXTERNAL_URL = "url"; + + @InjectMocks + private TrackedEmoteManagementServiceBean testUnit; + + @Mock + private TrackedEmoteRepository repository; + + @Mock + private ServerManagementService serverManagementService; + + @Mock + private Emote emote; + + @Mock + private Guild guild; + + @Mock + private AServer server; + + @Mock + private TrackedEmote trackedEmote; + + @Captor + private ArgumentCaptor trackedEmoteArgumentCaptor; + + @Test + public void testCreateTrackedEmote() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(emote.getName()).thenReturn(EMOTE_NAME); + when(emote.isAnimated()).thenReturn(ANIMATED); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + when(server.getId()).thenReturn(SERVER_ID); + testUnit.createTrackedEmote(emote, guild); + verifyEmoteCreation(true, false, null); + } + + @Test + public void testCreateTrackedEmoteAllParams() { + when(server.getId()).thenReturn(SERVER_ID); + testUnit.createTrackedEmote(EMOTE_ID, EMOTE_NAME, ANIMATED, server); + verifyEmoteCreation(true, false, null); + } + + @Test + public void testCreateExternalEmote() { + when(server.getId()).thenReturn(SERVER_ID); + testUnit.createExternalEmote(EMOTE_ID, EMOTE_NAME, EXTERNAL_URL, ANIMATED, server); + verifyEmoteCreation(true, true, EXTERNAL_URL); + } + + @Test + public void testCreateTrackedEmoteExternal() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(emote.getName()).thenReturn(EMOTE_NAME); + when(emote.getImageUrl()).thenReturn(EXTERNAL_URL); + when(emote.isAnimated()).thenReturn(ANIMATED); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + when(server.getId()).thenReturn(SERVER_ID); + testUnit.createTrackedEmote(emote, guild, true); + verifyEmoteCreation(true, true, EXTERNAL_URL); + } + + @Test + public void testCreateTrackedEmoteInternal() { + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(emote.getName()).thenReturn(EMOTE_NAME); + when(emote.isAnimated()).thenReturn(ANIMATED); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + when(server.getId()).thenReturn(SERVER_ID); + testUnit.createTrackedEmote(emote, guild, false); + verifyEmoteCreation(true, false, null); + } + + @Test + public void testCreateNotTrackedEmote() { + when(server.getId()).thenReturn(SERVER_ID); + testUnit.createNotTrackedEmote(EMOTE_ID, EMOTE_NAME, ANIMATED, server); + verifyEmoteCreation(false, false, null); + } + + @Test + public void testCreateExternalEmotePersistingEmote() { + when(server.getId()).thenReturn(SERVER_ID); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + PersistingEmote persistingEmote = Mockito.mock(PersistingEmote.class); + when(persistingEmote.getServerId()).thenReturn(SERVER_ID); + when(persistingEmote.getEmoteId()).thenReturn(EMOTE_ID); + when(persistingEmote.getEmoteName()).thenReturn(EMOTE_NAME); + when(persistingEmote.getAnimated()).thenReturn(ANIMATED); + when(persistingEmote.getExternalUrl()).thenReturn(EXTERNAL_URL); + testUnit.createExternalEmote(persistingEmote); + verifyEmoteCreation(true, true, EXTERNAL_URL); + } + + @Test + public void testCreateExternalEmoteDirect() { + when(emote.getImageUrl()).thenReturn(EXTERNAL_URL); + when(emote.isAnimated()).thenReturn(ANIMATED); + when(emote.getName()).thenReturn(EMOTE_NAME); + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(guild.getIdLong()).thenReturn(SERVER_ID); + when(server.getId()).thenReturn(SERVER_ID); + when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); + testUnit.createExternalEmote(emote, guild); + verifyEmoteCreation(true, true, EXTERNAL_URL); + } + + public void verifyEmoteCreation(boolean tracked, boolean external, String externalUrl) { + verify(repository, times(1)).save(trackedEmoteArgumentCaptor.capture()); + TrackedEmote createdTrackedEmote = trackedEmoteArgumentCaptor.getValue(); + Assert.assertEquals(EMOTE_ID, createdTrackedEmote.getTrackedEmoteId().getEmoteId()); + Assert.assertEquals(SERVER_ID, createdTrackedEmote.getTrackedEmoteId().getServerId()); + Assert.assertEquals(EMOTE_NAME, createdTrackedEmote.getEmoteName()); + Assert.assertEquals(ANIMATED, createdTrackedEmote.getAnimated()); + Assert.assertEquals(tracked, createdTrackedEmote.getTrackingEnabled()); + Assert.assertEquals(server, createdTrackedEmote.getServer()); + Assert.assertFalse(createdTrackedEmote.getDeleted()); + Assert.assertEquals(external, createdTrackedEmote.getExternal()); + Assert.assertEquals(externalUrl, createdTrackedEmote.getExternalUrl()); + } + + @Test + public void testMarkAsDeleted() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + testUnit.markAsDeleted(trackedEmote); + verify(trackedEmote, times(1)).setDeleted(true); + } + + @Test + public void testMarkAsDeletedId() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote)); + when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); + testUnit.markAsDeleted(SERVER_ID, EMOTE_ID); + verify(trackedEmote, times(1)).setDeleted(true); + } + + @Test + public void testLoadByEmoteEmote() { + when(emote.getIdLong()).thenReturn(EMOTE_ID); + when(emote.getGuild()).thenReturn(guild); + when(guild.getIdLong()).thenReturn(SERVER_ID); + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote)); + TrackedEmote retrievedTrackedEmote = testUnit.loadByEmote(emote); + Assert.assertEquals(trackedEmote, retrievedTrackedEmote); + } + + @Test + public void testLoadByEmoteId() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote)); + TrackedEmote retrievedEmote = testUnit.loadByEmoteId(EMOTE_ID, SERVER_ID); + Assert.assertEquals(trackedEmote, retrievedEmote); + } + + @Test(expected = AbstractoRunTimeException.class) + public void testLoadByEmoteIdNotFound() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.empty()); + testUnit.loadByEmoteId(EMOTE_ID, SERVER_ID); + } + + @Test + public void testTrackedEmoteExists() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote)); + boolean exists = testUnit.trackedEmoteExists(EMOTE_ID, SERVER_ID); + Assert.assertTrue(exists); + } + + @Test + public void testTrackedEmoteExistsNot() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.empty()); + boolean exists = testUnit.trackedEmoteExists(EMOTE_ID, SERVER_ID); + Assert.assertFalse(exists); + } + + @Test + public void testLoadByTrackedEmoteServer() { + TrackedEmoteServer trackedEmoteServer = new TrackedEmoteServer(EMOTE_ID, SERVER_ID); + when(repository.findById(trackedEmoteServer)).thenReturn(Optional.of(trackedEmote)); + TrackedEmote retrievedTrackedEmote = testUnit.loadByTrackedEmoteServer(trackedEmoteServer); + Assert.assertEquals(trackedEmote, retrievedTrackedEmote); + } + + @Test + public void testGetAllActiveTrackedEmoteForServer() { + List controlTrackedEmotes = Arrays.asList(trackedEmote); + when(repository.findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(SERVER_ID)).thenReturn(controlTrackedEmotes); + List retrievedTrackedEmotes = testUnit.getAllActiveTrackedEmoteForServer(SERVER_ID); + Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes); + } + + @Test + public void testGetAllActiveTrackedEmoteForServerId() { + when(server.getId()).thenReturn(SERVER_ID); + List controlTrackedEmotes = Arrays.asList(trackedEmote); + when(repository.findByTrackedEmoteId_ServerIdAndDeletedFalseAndExternalFalse(SERVER_ID)).thenReturn(controlTrackedEmotes); + List retrievedTrackedEmotes = testUnit.getAllActiveTrackedEmoteForServer(server); + Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes); + } + + @Test + public void testGetTrackedEmoteForServerGetAll() { + List controlTrackedEmotes = Arrays.asList(trackedEmote); + when(repository.findByTrackedEmoteId_ServerId(SERVER_ID)).thenReturn(controlTrackedEmotes); + List retrievedTrackedEmotes = testUnit.getTrackedEmoteForServer(SERVER_ID, true); + Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes); + } + + @Test + public void testGetTrackedEmoteForServerGet() { + List controlTrackedEmotes = Arrays.asList(trackedEmote); + when(repository.findByTrackedEmoteId_ServerIdAndTrackingEnabledTrue(SERVER_ID)).thenReturn(controlTrackedEmotes); + List retrievedTrackedEmotes = testUnit.getTrackedEmoteForServer(SERVER_ID, false); + Assert.assertEquals(controlTrackedEmotes, retrievedTrackedEmotes); + } + + @Test + public void testSetName() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + testUnit.changeName(trackedEmote, EMOTE_NAME); + verify(trackedEmote, times(1)).setEmoteName(EMOTE_NAME); + } + + @Test + public void testDisableTrackedEmote() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + testUnit.disableTrackedEmote(trackedEmote); + verify(trackedEmote, times(1)).setTrackingEnabled(false); + } + + @Test + public void testEnableTrackedEmote() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + testUnit.enableTrackedEmote(trackedEmote); + verify(trackedEmote, times(1)).setTrackingEnabled(true); + } + + @Test + public void testDeleteTrackedEmote() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + testUnit.deleteTrackedEmote(trackedEmote); + verify(repository, times(1)).delete(trackedEmote); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBeanTest.java b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBeanTest.java new file mode 100644 index 000000000..5ece06e2f --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/src/test/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementServiceBeanTest.java @@ -0,0 +1,139 @@ +package dev.sheldan.abstracto.statistic.emotes.service.management; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import dev.sheldan.abstracto.statistic.emotes.repository.UsedEmoteRepository; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class UsedEmoteManagementServiceBeanTest { + + private static final Long EMOTE_ID = 4L; + private static final Long SERVER_ID = 3L; + private static final Long COUNT = 5L; + + @InjectMocks + private UsedEmoteManagementServiceBean testUnit; + + @Mock + private UsedEmoteRepository usedEmoteRepository; + + @Mock + private TrackedEmote trackedEmote; + + @Mock + private UsedEmote usedEmote; + + @Mock + private AServer server; + + @Captor + private ArgumentCaptor usedEmoteArgumentCaptor; + + @Test + public void testLoadUsedEmoteForTrackedEmoteToday() { + setupTrackedEmote(); + when(usedEmoteRepository.findEmoteFromServerToday(EMOTE_ID, SERVER_ID)).thenReturn(Optional.of(usedEmote)); + Optional usedEmoteOptional = testUnit.loadUsedEmoteForTrackedEmoteToday(trackedEmote); + Assert.assertTrue(usedEmoteOptional.isPresent()); + usedEmoteOptional.ifPresent(usedEmote1 -> + Assert.assertEquals(usedEmote, usedEmote1) + ); + } + + @Test + public void testCreateEmoteUsageForToday() { + setupTrackedEmote(); + testUnit.createEmoteUsageForToday(trackedEmote, COUNT); + verify(usedEmoteRepository, times(1)).save(usedEmoteArgumentCaptor.capture()); + UsedEmote createdUsedEmote = usedEmoteArgumentCaptor.getValue(); + Assert.assertEquals(COUNT, createdUsedEmote.getAmount()); + Assert.assertEquals(EMOTE_ID, createdUsedEmote.getEmoteId().getEmoteId()); + Assert.assertEquals(SERVER_ID, createdUsedEmote.getEmoteId().getServerId()); + } + + @Test + public void testPurgeEmoteUsagesSince() { + setupTrackedEmote(); + testUnit.purgeEmoteUsagesSince(trackedEmote, Instant.EPOCH); + verify(usedEmoteRepository, times(1)).deleteByEmoteId_EmoteIdAndEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(EMOTE_ID, SERVER_ID, Instant.EPOCH); + } + + @Test + public void testLoadEmoteUsagesForServerSince() { + setupServer(); + when(usedEmoteRepository.getByEmoteId_ServerIdAndEmoteId_UseDateGreaterThan(SERVER_ID, Instant.EPOCH)).thenReturn(Arrays.asList(usedEmote)); + List returnedUsedEmotes = testUnit.loadEmoteUsagesForServerSince(server, Instant.EPOCH); + Assert.assertEquals(1, returnedUsedEmotes.size()); + Assert.assertEquals(usedEmote, returnedUsedEmotes.get(0)); + } + + @Test + public void testLoadAllEmoteStatsForServerSince() { + setupServer(); + List results = getEmoteStatsResults(); + when(usedEmoteRepository.getEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results); + List returnedResult = testUnit.loadAllEmoteStatsForServerSince(server, Instant.EPOCH); + Assert.assertEquals(results.size(), returnedResult.size()); + Assert.assertEquals(results, returnedResult); + } + + @Test + public void testLoadDeletedEmoteStatsForServerSince() { + setupServer(); + List results = getEmoteStatsResults(); + when(usedEmoteRepository.getDeletedEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results); + List returnedResult = testUnit.loadDeletedEmoteStatsForServerSince(server, Instant.EPOCH); + Assert.assertEquals(results.size(), returnedResult.size()); + Assert.assertEquals(results, returnedResult); + } + + @Test + public void testLoadExternalEmoteStatsForServerSince() { + setupServer(); + List results = getEmoteStatsResults(); + when(usedEmoteRepository.getExternalEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results); + List returnedResult = testUnit.loadExternalEmoteStatsForServerSince(server, Instant.EPOCH); + Assert.assertEquals(results.size(), returnedResult.size()); + Assert.assertEquals(results, returnedResult); + } + + @Test + public void testLoadActiveEmoteStatsForServerSince() { + setupServer(); + List results = getEmoteStatsResults(); + when(usedEmoteRepository.getCurrentlyExistingEmoteStatsForServerSince(SERVER_ID, Instant.EPOCH)).thenReturn(results); + List returnedResult = testUnit.loadActiveEmoteStatsForServerSince(server, Instant.EPOCH); + Assert.assertEquals(results.size(), returnedResult.size()); + Assert.assertEquals(results, returnedResult); + } + + public List getEmoteStatsResults() { + EmoteStatsResult emoteStatsResult = Mockito.mock(EmoteStatsResult.class); + EmoteStatsResult emoteStatsResult2 = Mockito.mock(EmoteStatsResult.class); + return Arrays.asList(emoteStatsResult, emoteStatsResult2); + } + + private void setupTrackedEmote() { + when(trackedEmote.getTrackedEmoteId()).thenReturn(new TrackedEmoteServer(EMOTE_ID, SERVER_ID)); + } + + private void setupServer() { + when(server.getId()).thenReturn(SERVER_ID); + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml b/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml new file mode 100644 index 000000000..c32347582 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml @@ -0,0 +1,22 @@ + + + + dev.sheldan.abstracto.modules + statistic + 1.0-SNAPSHOT + + 4.0.0 + + statistic-int + + + + dev.sheldan.abstracto.scheduling + scheduling-int + ${project.version} + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticFeatures.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticFeatures.java new file mode 100644 index 000000000..2fe6870c7 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/config/StatisticFeatures.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.statistic.config; + +import dev.sheldan.abstracto.core.config.FeatureEnum; + +public enum StatisticFeatures implements FeatureEnum { + EMOTE_TRACKING("emote_tracking"); + + private String key; + + StatisticFeatures(String key) { + this.key = key; + } + + @Override + public String getKey() { + return this.key; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingFeature.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingFeature.java new file mode 100644 index 000000000..f172750f7 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingFeature.java @@ -0,0 +1,23 @@ +package dev.sheldan.abstracto.statistic.emotes.config; + +import dev.sheldan.abstracto.core.config.FeatureConfig; +import dev.sheldan.abstracto.core.config.FeatureEnum; +import dev.sheldan.abstracto.core.config.FeatureMode; +import dev.sheldan.abstracto.statistic.config.StatisticFeatures; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@Component +public class EmoteTrackingFeature implements FeatureConfig { + @Override + public FeatureEnum getFeature() { + return StatisticFeatures.EMOTE_TRACKING; + } + + @Override + public List getAvailableModes() { + return Arrays.asList(EmoteTrackingMode.EXTERNAL_EMOTES, EmoteTrackingMode.AUTO_TRACK, EmoteTrackingMode.AUTO_TRACK_EXTERNAL); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingMode.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingMode.java new file mode 100644 index 000000000..3b0256134 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/config/EmoteTrackingMode.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.statistic.emotes.config; + +import dev.sheldan.abstracto.core.config.FeatureMode; +import lombok.Getter; + +@Getter +public enum EmoteTrackingMode implements FeatureMode { + AUTO_TRACK("emoteAutoTrack"), EXTERNAL_EMOTES("externalEmotes"), AUTO_TRACK_EXTERNAL("autoTrackExternal"); + + private final String key; + + EmoteTrackingMode(String key) { + this.key = key; + } + +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/DownloadEmoteStatsFileTooBigException.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/DownloadEmoteStatsFileTooBigException.java new file mode 100644 index 000000000..05a1355ea --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/DownloadEmoteStatsFileTooBigException.java @@ -0,0 +1,24 @@ +package dev.sheldan.abstracto.statistic.emotes.exception; + +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.statistic.emotes.model.exception.DownloadEmoteStatsFileTooBigModel; +import dev.sheldan.abstracto.templating.Templatable; + +public class DownloadEmoteStatsFileTooBigException extends AbstractoRunTimeException implements Templatable { + + private final DownloadEmoteStatsFileTooBigModel model; + + public DownloadEmoteStatsFileTooBigException(Long fileSize, Long maxFileSize) { + this.model = DownloadEmoteStatsFileTooBigModel.builder().fileSize(fileSize).fileSizeLimit(maxFileSize).build(); + } + + @Override + public String getTemplateName() { + return "emote_stats_download_file_size_too_big"; + } + + @Override + public Object getTemplateModel() { + return model; + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/TrackedEmoteNotFoundException.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/TrackedEmoteNotFoundException.java new file mode 100644 index 000000000..dacffbe58 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/exception/TrackedEmoteNotFoundException.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.statistic.emotes.exception; + +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; + +public class TrackedEmoteNotFoundException extends AbstractoRunTimeException { + + public TrackedEmoteNotFoundException(String message) { + super(message); + } + + public TrackedEmoteNotFoundException() { + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/AvailableTrackedEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/AvailableTrackedEmote.java new file mode 100644 index 000000000..4f9f4feb7 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/AvailableTrackedEmote.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Emote; + +@Getter +@Setter +@Builder +public class AvailableTrackedEmote { + private Emote emote; + private TrackedEmote trackedEmote; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsModel.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsModel.java new file mode 100644 index 000000000..7fb8582aa --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsModel.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Guild; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@Builder +public class EmoteStatsModel { + @Builder.Default + private List animatedEmotes = new ArrayList<>(); + @Builder.Default + private List staticEmotes = new ArrayList<>(); + private Guild guild; + + public boolean areStatsAvailable() { + return !animatedEmotes.isEmpty() || !staticEmotes.isEmpty(); + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResult.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResult.java new file mode 100644 index 000000000..8a699f6e8 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResult.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +public interface EmoteStatsResult { + Long getEmoteId(); + Long getServerId(); + Long getAmount(); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResultDisplay.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResultDisplay.java new file mode 100644 index 000000000..7c6f42823 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/EmoteStatsResultDisplay.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Emote; + +@Getter +@Setter +@Builder +public class EmoteStatsResultDisplay { + private Emote emote; + private EmoteStatsResult result; + private TrackedEmote trackedEmote; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/PersistingEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/PersistingEmote.java new file mode 100644 index 000000000..8f5454edb --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/PersistingEmote.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class PersistingEmote { + private Long emoteId; + private String emoteName; + private Boolean animated; + private Boolean external; + private String externalUrl; + private Long count; + private Long serverId; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteOverview.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteOverview.java new file mode 100644 index 000000000..5b1711305 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteOverview.java @@ -0,0 +1,62 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Guild; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@Builder +public class TrackedEmoteOverview { + @Builder.Default + private List animatedEmotes = new ArrayList<>(); + + @Builder.Default + private List staticEmotes = new ArrayList<>(); + + @Builder.Default + private List deletedStaticEmotes = new ArrayList<>(); + + @Builder.Default + private List deletedAnimatedEmotes = new ArrayList<>(); + + @Builder.Default + private List externalStaticEmotes = new ArrayList<>(); + + @Builder.Default + private List externalAnimatedEmotes = new ArrayList<>(); + + private Guild guild; + + public void addTrackedEmote(TrackedEmote trackedEmote, Guild guild) { + if(trackedEmote.getDeleted()) { + if(trackedEmote.getAnimated()) { + deletedAnimatedEmotes.add(trackedEmote); + } else { + deletedStaticEmotes.add(trackedEmote); + } + } else if(trackedEmote.getExternal()){ + if(trackedEmote.getAnimated()) { + externalAnimatedEmotes.add(trackedEmote); + } else { + externalStaticEmotes.add(trackedEmote); + } + } else { + AvailableTrackedEmote availableEmote = AvailableTrackedEmote + .builder() + .emote(guild.getEmoteById(trackedEmote.getTrackedEmoteId().getEmoteId())) + .trackedEmote(trackedEmote) + .build(); + if(trackedEmote.getAnimated()) { + animatedEmotes.add(availableEmote); + } else { + staticEmotes.add(availableEmote); + } + } + } +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteSynchronizationResult.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteSynchronizationResult.java new file mode 100644 index 000000000..eadcdccd4 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/TrackedEmoteSynchronizationResult.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.statistic.emotes.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class TrackedEmoteSynchronizationResult { + private Long emotesAdded; + private Long emotesMarkedDeleted; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/TrackedEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/TrackedEmote.java new file mode 100644 index 000000000..1d26df0c2 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/TrackedEmote.java @@ -0,0 +1,69 @@ +package dev.sheldan.abstracto.statistic.emotes.model.database; + +import dev.sheldan.abstracto.core.models.Fakeable; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import java.io.Serializable; +import java.time.Instant; + +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tracked_emote") +@Getter +@Setter +@EqualsAndHashCode +@Cacheable +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class TrackedEmote implements Serializable, Fakeable { + + @EmbeddedId + private TrackedEmoteServer trackedEmoteId; + + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @MapsId("serverId") + @JoinColumn(name = "server_id", referencedColumnName = "id", nullable = false) + private AServer server; + + @Column(name = "name", length = 32) + private String emoteName; + + @Column(name = "animated") + private Boolean animated; + + @Column(name = "tracking_enabled") + private Boolean trackingEnabled; + + @Column(name = "deleted") + private Boolean deleted; + + @Column(name = "external") + private Boolean external; + + @Column(name = "external_url") + private String externalUrl; + + @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(); + } + + @Transient + private boolean fake; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/UsedEmote.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/UsedEmote.java new file mode 100644 index 000000000..67a4b6e36 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/UsedEmote.java @@ -0,0 +1,34 @@ +package dev.sheldan.abstracto.statistic.emotes.model.database; + +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.UsedEmoteDay; +import lombok.*; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; + +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "used_emote") +@Getter +@Setter +@EqualsAndHashCode +@Cacheable +@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) +public class UsedEmote { + + @EmbeddedId + private UsedEmoteDay emoteId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumns( + { + @JoinColumn(updatable = false, insertable = false, name = "emote_id", referencedColumnName = "id"), + @JoinColumn(updatable = false, insertable = false, name = "server_id", referencedColumnName = "server_id") + }) + private TrackedEmote trackedEmote; + + @Column(name = "amount") + private Long amount; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/TrackedEmoteServer.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/TrackedEmoteServer.java new file mode 100644 index 000000000..d8f4bbbbf --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/TrackedEmoteServer.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.statistic.emotes.model.database.embed; + +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +@Getter +@Setter +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class TrackedEmoteServer implements Serializable { + + @Column(name = "id") + private Long emoteId; + @Column(name = "server_id") + private Long serverId; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/UsedEmoteDay.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/UsedEmoteDay.java new file mode 100644 index 000000000..042ca71d5 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/database/embed/UsedEmoteDay.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.statistic.emotes.model.database.embed; + +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import java.io.Serializable; +import java.time.Instant; + +@Embeddable +@Getter +@Setter +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class UsedEmoteDay implements Serializable { + + @Column(name = "emote_id") + private Long emoteId; + @Column(name = "server_id") + private Long serverId; + + @Column(name = "use_date") + private Instant useDate; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/exception/DownloadEmoteStatsFileTooBigModel.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/exception/DownloadEmoteStatsFileTooBigModel.java new file mode 100644 index 000000000..2c7b596d7 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/model/exception/DownloadEmoteStatsFileTooBigModel.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.statistic.emotes.model.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +@Builder +public class DownloadEmoteStatsFileTooBigModel implements Serializable { + private Long fileSize; + private Long fileSizeLimit; +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeService.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeService.java new file mode 100644 index 000000000..8ca85ab91 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteRuntimeService.java @@ -0,0 +1,17 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; + +import java.util.List; +import java.util.Map; + +public interface TrackedEmoteRuntimeService { + Map>> getRuntimeConfig(); + void addEmoteForServer(Emote emote, Guild guild, boolean external); + void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external); + Long getKey(); + PersistingEmote createFromEmote(Guild guild, Emote emote, boolean external); + PersistingEmote createFromEmote(Guild guild, Emote emote, Long count, boolean external); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteService.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteService.java new file mode 100644 index 000000000..230b22055 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/TrackedEmoteService.java @@ -0,0 +1,26 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview; +import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; + +import java.util.Map; +import java.util.List; + +public interface TrackedEmoteService { + void addEmoteToRuntimeStorage(List emotes, Guild guild); + void addEmoteToRuntimeStorage(Emote emote, Guild guild, Long count); + void storeEmoteStatistics(Map> usagesToStore); + TrackedEmote getFakeTrackedEmote(Emote emote, Guild guild); + TrackedEmote getFakeTrackedEmote(Long id, Guild guild); + TrackedEmoteSynchronizationResult synchronizeTrackedEmotes(Guild guild); + TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild); + TrackedEmoteOverview loadTrackedEmoteOverview(Guild guild, Boolean showTrackingDisabled); + TrackedEmote createFakeTrackedEmote(Emote emote, Guild guild); + void deleteTrackedEmote(TrackedEmote trackedEmote); + void resetEmoteStats(Guild guild); + void disableEmoteTracking(Guild guild); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteService.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteService.java new file mode 100644 index 000000000..8536ac074 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/UsedEmoteService.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.statistic.emotes.service; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsModel; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; + +import java.time.Instant; + +public interface UsedEmoteService { + EmoteStatsModel getEmoteStatsForServerSince(AServer server, Instant since); + EmoteStatsModel getDeletedEmoteStatsForServerSince(AServer server, Instant since); + EmoteStatsModel getExternalEmoteStatsForServerSince(AServer server, Instant since); + EmoteStatsModel getActiveEmoteStatsForServerSince(AServer server, Instant since); + void purgeEmoteUsagesSince(TrackedEmote emote, Instant since); + void purgeEmoteUsages(TrackedEmote emote); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementService.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementService.java new file mode 100644 index 000000000..f3f06570c --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/TrackedEmoteManagementService.java @@ -0,0 +1,36 @@ +package dev.sheldan.abstracto.statistic.emotes.service.management; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.embed.TrackedEmoteServer; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; + +import java.util.List; +import java.util.Optional; + +public interface TrackedEmoteManagementService { + TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server); + TrackedEmote createTrackedEmote(Emote emote, Guild guild); + TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external); + TrackedEmote createTrackedEmote(Long emoteId, String emoteName, Boolean animated, Boolean tracked, AServer server); + TrackedEmote createExternalEmote(Long emoteId, String emoteName, String externalUrl, Boolean animated, AServer server); + TrackedEmote createNotTrackedEmote(Long emoteId, String emoteName, Boolean animated, AServer server); + TrackedEmote createExternalEmote(PersistingEmote persistingEmote); + TrackedEmote createExternalEmote(Emote emote, Guild guild); + void markAsDeleted(Long serverId, Long emoteId); + void markAsDeleted(TrackedEmote trackedemote); + TrackedEmote loadByEmoteId(Long emoteId, Long serverId); + TrackedEmote loadByEmote(Emote emote); + boolean trackedEmoteExists(Long emoteId, Long serverId); + TrackedEmote loadByTrackedEmoteServer(TrackedEmoteServer trackedEmoteServer); + Optional loadByEmoteIdOptional(Long emoteId, Long serverId); + List getAllActiveTrackedEmoteForServer(AServer server); + List getAllActiveTrackedEmoteForServer(Long serverId); + List getTrackedEmoteForServer(Long serverId, Boolean showTrackingDisabledEmotes); + void changeName(TrackedEmote emote, String name); + void disableTrackedEmote(TrackedEmote emote); + void enableTrackedEmote(TrackedEmote emote); + void deleteTrackedEmote(TrackedEmote emote); +} diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementService.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementService.java new file mode 100644 index 000000000..45a4b6d28 --- /dev/null +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emotes/service/management/UsedEmoteManagementService.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.statistic.emotes.service.management; + +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.statistic.emotes.model.EmoteStatsResult; +import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; +import dev.sheldan.abstracto.statistic.emotes.model.database.UsedEmote; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +public interface UsedEmoteManagementService { + Optional loadUsedEmoteForTrackedEmoteToday(TrackedEmote trackedEmote); + UsedEmote createEmoteUsageForToday(TrackedEmote trackedEmote, Long count); + List loadEmoteUsagesForServerSince(AServer server, Instant since); + List loadAllEmoteStatsForServerSince(AServer server, Instant since); + List loadDeletedEmoteStatsForServerSince(AServer server, Instant since); + List loadExternalEmoteStatsForServerSince(AServer server, Instant since); + List loadActiveEmoteStatsForServerSince(AServer server, Instant since); + void purgeEmoteUsagesSince(TrackedEmote emote, Instant since); +} diff --git a/abstracto-application/abstracto-modules/utility/pom.xml b/abstracto-application/abstracto-modules/utility/pom.xml index fee26b6a5..b237601de 100644 --- a/abstracto-application/abstracto-modules/utility/pom.xml +++ b/abstracto-application/abstracto-modules/utility/pom.xml @@ -3,13 +3,12 @@ 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"> - dev.sheldan.abstracto + dev.sheldan.abstracto.modules abstracto-modules 1.0-SNAPSHOT 4.0.0 - dev.sheldan.abstracto.modules utility pom diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ServerInfo.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ServerInfo.java index 81b51f494..2c4cdc022 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ServerInfo.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ServerInfo.java @@ -34,7 +34,7 @@ public class ServerInfo extends AbstractConditionableCommand { model.setGuild(commandContext.getGuild()); log.info("Displaying serverinfo for server {}", commandContext.getGuild().getId()); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel("serverinfo_response", model, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowAvatar.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowAvatar.java index ed96ea943..91d8c30d4 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowAvatar.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowAvatar.java @@ -40,7 +40,7 @@ public class ShowAvatar extends AbstractConditionableCommand { memberToShow.getId(), commandContext.getAuthor().getId(), commandContext.getChannel().getId(), commandContext.getGuild().getId()); model.setMemberInfo(memberToShow); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_AVATAR_RESPONSE_TEMPLATE, model, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowEmote.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowEmote.java index 646a39567..b5e26bf49 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowEmote.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/ShowEmote.java @@ -35,7 +35,7 @@ public class ShowEmote extends AbstractConditionableCommand { ShowEmoteLog emoteLog = (ShowEmoteLog) ContextConverter.fromCommandContext(commandContext, ShowEmoteLog.class); emoteLog.setEmote(emoteParameter); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_EMOTE_RESPONSE_TEMPLATE, emoteLog, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/StarStats.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/StarStats.java index 0bd9af54d..c74bb3e5f 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/StarStats.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/StarStats.java @@ -35,7 +35,7 @@ public class StarStats extends AbstractConditionableCommand { return starboardService.retrieveStarStats(commandContext.getGuild().getIdLong()) .thenCompose(starStatsModel -> FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(STARSTATS_RESPONSE_TEMPLATE, starStatsModel, commandContext.getChannel())) - ).thenApply(o -> CommandResult.fromSuccess()); + ).thenApply(o -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/UserInfo.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/UserInfo.java index d276258d7..f5b533847 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/UserInfo.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/UserInfo.java @@ -48,12 +48,12 @@ public class UserInfo extends AbstractConditionableCommand { return botService.forceReloadMember(memberToShow).thenCompose(member -> { model.setMemberInfo(member); return self.sendResponse(commandContext, model) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); }); } else { model.setMemberInfo(memberToShow); return self.sendResponse(commandContext, model) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } } diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/remind/Reminders.java b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/remind/Reminders.java index 2a7fb0aab..29b8502e2 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/remind/Reminders.java +++ b/abstracto-application/abstracto-modules/utility/utility-impl/src/main/java/dev/sheldan/abstracto/utility/commands/remind/Reminders.java @@ -42,7 +42,7 @@ public class Reminders extends AbstractConditionableCommand { model.setReminders(activeReminders); log.info("Showing {} reminders for user {} in server {}.", activeReminders.size(), commandContext.getAuthor().getId(), commandContext.getGuild().getId()); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(REMINDERS_RESPONSE_TEMPLATE, model, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/bundle/pom.xml b/abstracto-application/bundle/pom.xml index 7d4d5f278..cebc8628b 100644 --- a/abstracto-application/bundle/pom.xml +++ b/abstracto-application/bundle/pom.xml @@ -61,6 +61,12 @@ ${project.version} + + dev.sheldan.abstracto.modules + statistic-impl + ${project.version} + + diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerImpl.java similarity index 81% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerImpl.java index fed4ede80..3548ca1e0 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerImpl.java @@ -1,6 +1,8 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.AChanelParameterHandler; +import dev.sheldan.abstracto.core.command.handler.provided.TextChannelParameterHandler; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.service.ChannelService; import net.dv8tion.jda.api.entities.Message; @@ -9,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class AChannelParameterHandler implements CommandParameterHandler { +public class AChannelParameterHandlerImpl implements AChanelParameterHandler { @Autowired private TextChannelParameterHandler textChannelParameterHandler; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerImpl.java similarity index 83% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerImpl.java index e7f51165e..be4cb4147 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerImpl.java @@ -1,6 +1,8 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.AEmoteParameterHandler; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.service.EmoteService; import net.dv8tion.jda.api.entities.Emote; @@ -9,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class AEmoteParameterHandler implements CommandParameterHandler { +public class AEmoteParameterHandlerImpl implements AEmoteParameterHandler { @Autowired private EmoteParameterHandler emoteParameterHandler; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerImpl.java similarity index 81% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerImpl.java index d27127fec..6359c03c4 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerImpl.java @@ -1,6 +1,8 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.ARoleParameterHandler; +import dev.sheldan.abstracto.core.command.handler.provided.RoleParameterHandler; import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.service.RoleService; import net.dv8tion.jda.api.entities.Message; @@ -9,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class ARoleParameterHandler implements CommandParameterHandler { +public class ARoleParameterHandlerImpl implements ARoleParameterHandler { @Autowired private RoleParameterHandler roleParameterHandler; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerImpl.java similarity index 78% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerImpl.java index c9ca2a1b7..29b1c54ee 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerImpl.java @@ -1,11 +1,12 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.BooleanParameterHandler; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @Component -public class BooleanParameterHandler implements CommandParameterHandler { +public class BooleanParameterHandlerImpl implements BooleanParameterHandler { @Override public boolean handles(Class clazz) { return clazz.equals(Boolean.class); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/CommandKeyParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/CommandKeyParameterHandlerImpl.java similarity index 81% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/CommandKeyParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/CommandKeyParameterHandlerImpl.java index 92d103a6b..61d751766 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/CommandKeyParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/CommandKeyParameterHandlerImpl.java @@ -2,11 +2,12 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; import dev.sheldan.abstracto.core.command.execution.CommandParameterKey; +import dev.sheldan.abstracto.core.command.handler.provided.CommandKeyParameterHandler; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @Component -public class CommandKeyParameterHandler implements CommandParameterHandler { +public class CommandKeyParameterHandlerImpl implements CommandKeyParameterHandler { @Override public boolean handles(Class clazz) { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerImpl.java similarity index 79% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerImpl.java index f1d297538..a221b6066 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerImpl.java @@ -1,11 +1,12 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.DoubleParameterHandler; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @Component -public class DoubleParameterHandler implements CommandParameterHandler { +public class DoubleParameterHandlerImpl implements DoubleParameterHandler { @Override public boolean handles(Class clazz) { return clazz.equals(Double.class); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerImpl.java similarity index 80% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerImpl.java index 6d98875f0..e7f9ae654 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerImpl.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.DurationParameterHandler; import dev.sheldan.abstracto.core.utils.ParseUtils; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @@ -8,7 +9,7 @@ import org.springframework.stereotype.Component; import java.time.Duration; @Component -public class DurationParameterHandler implements CommandParameterHandler { +public class DurationParameterHandlerImpl implements DurationParameterHandler { @Override public boolean handles(Class clazz) { return clazz.equals(Duration.class); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerImpl.java similarity index 87% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerImpl.java index f795f5b5f..b0a8641cf 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerImpl.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; import net.dv8tion.jda.api.entities.Emote; import net.dv8tion.jda.api.entities.Message; import org.apache.commons.lang3.StringUtils; @@ -9,7 +10,7 @@ import org.springframework.stereotype.Component; import java.util.regex.Matcher; @Component -public class EmoteParameterHandler implements CommandParameterHandler { +public class EmoteParameterHandlerImpl implements EmoteParameterHandler { @Override public boolean handles(Class clazz) { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerImpl.java similarity index 84% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerImpl.java index aee662d7f..4f74e61ff 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerImpl.java @@ -1,6 +1,8 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.EmoteParameterHandler; +import dev.sheldan.abstracto.core.command.handler.provided.FullEmoteParameterHandler; import dev.sheldan.abstracto.core.models.FullEmote; import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.service.EmoteService; @@ -10,7 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class FullEmoteParameterHandler implements CommandParameterHandler { +public class FullEmoteParameterHandlerImpl implements FullEmoteParameterHandler { @Autowired private EmoteParameterHandler emoteParameterHandler; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerImpl.java similarity index 82% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerImpl.java index 94f51e444..ac056ed57 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerImpl.java @@ -1,6 +1,8 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.FullRoleParameterHandler; +import dev.sheldan.abstracto.core.command.handler.provided.RoleParameterHandler; import dev.sheldan.abstracto.core.models.FullRole; import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.service.RoleService; @@ -10,7 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class FullRoleParameterHandler implements CommandParameterHandler { +public class FullRoleParameterHandlerImpl implements FullRoleParameterHandler { @Autowired private RoleParameterHandler roleParameterHandler; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerImpl.java similarity index 78% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerImpl.java index 622b52fc3..2c185f08a 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerImpl.java @@ -1,11 +1,12 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.IntegerParameterHandler; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @Component -public class IntegerParameterHandler implements CommandParameterHandler { +public class IntegerParameterHandlerImpl implements IntegerParameterHandler { @Override public boolean handles(Class clazz) { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerImpl.java similarity index 79% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerImpl.java index 80a47b59a..30772d9bc 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerImpl.java @@ -1,11 +1,12 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.LongParameterHandler; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @Component -public class LongParameterHandler implements CommandParameterHandler { +public class LongParameterHandlerImpl implements LongParameterHandler { @Override public boolean handles(Class clazz) { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java similarity index 88% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java index b2c3bbfc8..71387cb17 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.MemberParameterHandler; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import org.springframework.stereotype.Component; @@ -9,7 +10,7 @@ import java.util.concurrent.CompletableFuture; import java.util.regex.Matcher; @Component -public class MemberParameterHandler implements CommandParameterHandler { +public class MemberParameterHandlerImpl implements MemberParameterHandler { @Override public boolean handles(Class clazz) { return clazz.equals(Member.class); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java similarity index 86% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java index 6dac69366..d93627656 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImpl.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.RoleParameterHandler; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Role; import org.springframework.stereotype.Component; @@ -8,7 +9,7 @@ import org.springframework.stereotype.Component; import java.util.regex.Matcher; @Component -public class RoleParameterHandler implements CommandParameterHandler { +public class RoleParameterHandlerImpl implements RoleParameterHandler { @Override public boolean handles(Class clazz) { return clazz.equals(Role.class); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java similarity index 84% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandler.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java index 7ead9d136..8cdece1bc 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImpl.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.command.handler; import dev.sheldan.abstracto.core.command.CommandConstants; +import dev.sheldan.abstracto.core.command.handler.provided.TextChannelParameterHandler; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.stereotype.Component; @@ -8,7 +9,7 @@ import org.springframework.stereotype.Component; import java.util.regex.Matcher; @Component -public class TextChannelParameterHandler implements CommandParameterHandler { +public class TextChannelParameterHandlerImpl implements TextChannelParameterHandler { @Override public boolean handles(Class clazz) { return clazz.equals(TextChannel.class); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java index bef571812..f3360d4f7 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java @@ -44,7 +44,7 @@ public class ListChannelGroups extends AbstractConditionableCommand { template.setGroups(convertAChannelGroupToChannelGroupChannel(channelGroups)); MessageToSend response = templateService.renderEmbedTemplate("listChannelGroups_response", template); channelService.sendMessageToSendToChannel(response, commandContext.getChannel()); - return CommandResult.fromSuccess(); + return CommandResult.fromIgnored(); } private List convertAChannelGroupToChannelGroupChannel(List channelGroups) { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetupFeature.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetupFeature.java index 15cc9de64..fa4b01073 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetupFeature.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/SetupFeature.java @@ -49,7 +49,7 @@ public class SetupFeature extends AbstractConditionableCommand { .userId(commandContext.getAuthor().getIdLong()) .build(); return setupService.performFeatureSetup(feature, initiatingUser, commandContext.getMessage().getIdLong()) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } throw new FeatureNotFoundException(name, featureConfigService.getFeaturesAsList()); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/FeatureModes.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/FeatureModes.java index e03d7e1ab..de11df062 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/FeatureModes.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/FeatureModes.java @@ -54,7 +54,7 @@ public class FeatureModes extends AbstractConditionableCommand { } FeatureModesModel model = FeatureModesModel.builder().featureModes(featureModes).build(); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(FEATURE_MODES_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/Features.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/Features.java index fd88b2236..c4b5f7fe2 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/Features.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/features/Features.java @@ -45,7 +45,7 @@ public class Features extends AbstractConditionableCommand { featuresModel.setFeatures(featureFlagConverter.fromFeatureFlags(features)); MessageToSend messageToSend = templateService.renderEmbedTemplate("features_response", featuresModel); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java index 7031f8f1b..ea37888f5 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java @@ -84,7 +84,7 @@ public class Help implements Command { model.setSubModules(subModules); MessageToSend messageToSend = templateService.renderEmbedTemplate("help_module_details_response", model); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } else if(commandRegistry.commandExists(parameter)) { Command command = commandRegistry.getCommandByName(parameter); log.trace("Displaying help for command {}.", command.getConfiguration().getName()); @@ -100,7 +100,7 @@ public class Help implements Command { model.setCommand(command.getConfiguration()); MessageToSend messageToSend = templateService.renderEmbedTemplate("help_command_details_response", model); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } else { return displayHelpOverview(commandContext); } @@ -115,7 +115,7 @@ public class Help implements Command { model.setModules(subModules); MessageToSend messageToSend = templateService.renderEmbedTemplate("help_module_overview_response", model); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) - .thenApply(aVoid -> CommandResult.fromSuccess()); + .thenApply(aVoid -> CommandResult.fromIgnored()); } @Override @@ -134,7 +134,7 @@ public class Help implements Command { .parameters(Collections.singletonList(moduleOrCommandName)) .help(helpInfo) .templated(true) - .causesReaction(false) + .causesReaction(true) .build(); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Echo.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Echo.java index 2dce83478..d39b90a63 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Echo.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Echo.java @@ -33,7 +33,7 @@ public class Echo extends AbstractConditionableCommand { ); EchoModel model = EchoModel.builder().text(sb.toString()).build(); commandContext.getChannel().sendMessage(templateService.renderTemplate(TEMPLATE_NAME, model)).queue(); - return CommandResult.fromSuccess(); + return CommandResult.fromIgnored(); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Ping.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Ping.java index ff9a796bd..727c3a205 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Ping.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/utility/Ping.java @@ -36,7 +36,7 @@ public class Ping implements Command { long ping = commandContext.getJda().getGatewayPing(); PingModel model = PingModel.builder().latency(ping).build(); return channelService.sendTextTemplateInChannel(PING_TEMPLATE, model, commandContext.getChannel()) - .thenApply(message -> CommandResult.fromSuccess()); + .thenApply(message -> CommandResult.fromIgnored()); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/EmoteListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/EmoteListener.java new file mode 100644 index 000000000..2c385c221 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/EmoteListener.java @@ -0,0 +1,80 @@ +package dev.sheldan.abstracto.core.listener; + +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.events.emote.EmoteAddedEvent; +import net.dv8tion.jda.api.events.emote.EmoteRemovedEvent; +import net.dv8tion.jda.api.events.emote.update.EmoteUpdateNameEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; +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.PostConstruct; +import java.util.Comparator; +import java.util.List; + +@Service +@Slf4j +public class EmoteListener extends ListenerAdapter { + + @Autowired + private List createdListeners; + + @Autowired + private List deletedListeners; + + @Autowired + private List updatedListeners; + + @Autowired + @Lazy + private EmoteListener self; + + @Override + @Transactional + public void onEmoteAdded(@NotNull EmoteAddedEvent event) { + createdListeners.forEach(listener -> + self.executeCreatedListener(listener, event.getEmote()) + ); + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void executeCreatedListener(EmoteCreatedListener listener, Emote createDdEmote) { + listener.emoteCreated(createDdEmote); + } + + @Override + public void onEmoteRemoved(@NotNull EmoteRemovedEvent event) { + deletedListeners.forEach(listener -> + self.executeDeletedListener(listener, event.getEmote()) + ); + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void executeDeletedListener(EmoteDeletedListener listener, Emote createDdEmote) { + listener.emoteDeleted(createDdEmote); + } + + @Override + public void onEmoteUpdateName(@NotNull EmoteUpdateNameEvent event) { + updatedListeners.forEach(emoteUpdatedListener -> + self.executeUpdatedListener(emoteUpdatedListener, event.getEmote(), event.getOldName(), event.getNewName()) + ); + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void executeUpdatedListener(EmoteUpdatedListener listener, Emote updatedEmote, String oldName, String newName) { + listener.emoteUpdated(updatedEmote, oldName, newName); + } + + @PostConstruct + public void postConstruct() { + createdListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed()); + deletedListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed()); + updatedListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed()); + } +} 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 e6d9cf044..fdfffef70 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 @@ -101,7 +101,12 @@ public class ChannelServiceBean implements ChannelService { @Override public CompletableFuture sendEmbedToChannel(MessageEmbed embed, MessageChannel channel) { log.trace("Sending embed to channel {}.", channel.getId()); - return channel.sendMessage(embed).submit(); + return sendEmbedToChannelInComplete(embed, channel).submit(); + } + + @Override + public MessageAction sendEmbedToChannelInComplete(MessageEmbed embed, MessageChannel channel) { + return channel.sendMessage(embed); } @Override @@ -122,25 +127,30 @@ public class ChannelServiceBean implements ChannelService { public List> sendMessageToSendToChannel(MessageToSend messageToSend, MessageChannel textChannel) { String messageText = messageToSend.getMessage(); List> futures = new ArrayList<>(); - if(StringUtils.isBlank(messageText)) { - log.trace("Only sending {} embeds to channel {}.", messageToSend.getEmbeds().size(), textChannel.getId()); - messageToSend.getEmbeds().forEach(embed -> - futures.add(sendEmbedToChannel(embed, textChannel)) - ); - } else { - log.trace("Sending mesagte text to channel {}.", textChannel.getId()); - MessageAction messageAction = textChannel.sendMessage(messageText); - if(messageToSend.getEmbeds() != null && !messageToSend.getEmbeds().isEmpty()) { - log.trace("Also sending {} embeds to channel {}.", messageToSend.getEmbeds().size(), textChannel.getId()); - CompletableFuture firstMessageFuture = messageAction.embed(messageToSend.getEmbeds().get(0)).submit(); - futures.add(firstMessageFuture); - messageToSend.getEmbeds().stream().skip(1).forEach(embed -> - futures.add(sendEmbedToChannel(embed, textChannel)) - ); + MessageAction firstMessageAction = null; + List allMessageActions = new ArrayList<>(); + if(!StringUtils.isBlank(messageText)) { + firstMessageAction = textChannel.sendMessage(messageText); + } + if(!messageToSend.getEmbeds().isEmpty()) { + if(firstMessageAction != null) { + firstMessageAction.embed(messageToSend.getEmbeds().get(0)); } else { - futures.add(messageAction.submit()); + firstMessageAction = textChannel.sendMessage(messageToSend.getEmbeds().get(0)); + } + messageToSend.getEmbeds().stream().skip(1).forEach(embed -> allMessageActions.add(sendEmbedToChannelInComplete(embed, textChannel))); + } + if(messageToSend.hasFileToSend()) { + if(firstMessageAction != null) { + firstMessageAction.addFile(messageToSend.getFileToSend()); + } else { + firstMessageAction = textChannel.sendFile(messageToSend.getFileToSend()); } } + allMessageActions.add(0, firstMessageAction); + allMessageActions.forEach(messageAction -> + futures.add(messageAction.submit()) + ); return futures; } 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 cd00413ee..c9c0bf227 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 @@ -158,4 +158,9 @@ public class EmoteServiceBean implements EmoteService { .build(); } + @Override + public boolean emoteIsFromGuild(Emote emote, Guild guild) { + return guild.getEmoteById(emote.getId()) != null; + } + } diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/default_feature_flag.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/default_feature_flag.xml index f28630082..3f9243c46 100644 --- a/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/default_feature_flag.xml +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.0-core/core-tables/default_feature_flag.xml @@ -15,7 +15,6 @@ - diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerImplTest.java similarity index 89% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerImplTest.java index f44f161ce..4540b3932 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AChannelParameterHandlerImplTest.java @@ -14,13 +14,13 @@ import org.mockito.junit.MockitoJUnitRunner; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class AChannelParameterHandlerTest { +public class AChannelParameterHandlerImplTest { @InjectMocks - private AChannelParameterHandler testUnit; + private AChannelParameterHandlerImpl testUnit; @Mock - private TextChannelParameterHandler textChannelParameterHandler; + private TextChannelParameterHandlerImpl textChannelParameterHandler; @Mock private ChannelService channelService; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerImplImplTest.java similarity index 91% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerImplImplTest.java index bd9a3739a..46e1329ce 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/AEmoteParameterHandlerImplImplTest.java @@ -14,13 +14,13 @@ import org.mockito.junit.MockitoJUnitRunner; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class AEmoteParameterHandlerTest { +public class AEmoteParameterHandlerImplImplTest { @InjectMocks - private AEmoteParameterHandler testUnit; + private AEmoteParameterHandlerImpl testUnit; @Mock - private EmoteParameterHandler emoteParameterHandler; + private EmoteParameterHandlerImpl emoteParameterHandler; @Mock private EmoteService emoteService; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerImplImplTest.java similarity index 90% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerImplImplTest.java index c83cb2fce..5cfe5f82e 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/ARoleParameterHandlerImplImplTest.java @@ -15,13 +15,13 @@ import org.mockito.junit.MockitoJUnitRunner; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class ARoleParameterHandlerTest { +public class ARoleParameterHandlerImplImplTest { @InjectMocks - private ARoleParameterHandler testUnit; + private ARoleParameterHandlerImpl testUnit; @Mock - private RoleParameterHandler roleParameterHandler; + private RoleParameterHandlerImpl roleParameterHandler; @Mock private RoleService roleService; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerImplTest.java similarity index 91% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerImplTest.java index 585a4a1b6..4a028b000 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/BooleanParameterHandlerImplTest.java @@ -7,10 +7,10 @@ import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class BooleanParameterHandlerTest { +public class BooleanParameterHandlerImplTest { @InjectMocks - private BooleanParameterHandler testUnit; + private BooleanParameterHandlerImpl testUnit; @Test public void testSuccessfulCondition() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerImplTest.java similarity index 93% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerImplTest.java index 44073ccd2..df8b1534c 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DoubleParameterHandlerImplTest.java @@ -7,10 +7,10 @@ import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class DoubleParameterHandlerTest { +public class DoubleParameterHandlerImplTest { @InjectMocks - private DoubleParameterHandler testUnit; + private DoubleParameterHandlerImpl testUnit; @Test public void testSuccessfulCondition() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerImplTest.java similarity index 93% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerImplTest.java index 0be225bbd..bb1b3ba20 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/DurationParameterHandlerImplTest.java @@ -11,10 +11,10 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; @RunWith(MockitoJUnitRunner.class) -public class DurationParameterHandlerTest { +public class DurationParameterHandlerImplTest { @InjectMocks - private DurationParameterHandler testUnit; + private DurationParameterHandlerImpl testUnit; @Test public void testSuccessfulCondition() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerImplTest.java similarity index 95% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerImplTest.java index 008b1dfe9..ffd0aebae 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/EmoteParameterHandlerImplTest.java @@ -16,10 +16,10 @@ import java.util.List; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class EmoteParameterHandlerTest { +public class EmoteParameterHandlerImplTest { @InjectMocks - private EmoteParameterHandler testUnit; + private EmoteParameterHandlerImpl testUnit; @Mock private CommandParameterIterators iterators; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerImplImplTest.java similarity index 92% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerImplImplTest.java index e917e4ac3..cec8d7524 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullEmoteParameterHandlerImplImplTest.java @@ -15,13 +15,13 @@ import org.mockito.junit.MockitoJUnitRunner; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class FullEmoteParameterHandlerTest { +public class FullEmoteParameterHandlerImplImplTest { @InjectMocks - private FullEmoteParameterHandler testUnit; + private FullEmoteParameterHandlerImpl testUnit; @Mock - private EmoteParameterHandler emoteParameterHandler; + private EmoteParameterHandlerImpl emoteParameterHandler; @Mock private EmoteService emoteService; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerImplImplTest.java similarity index 90% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerImplImplTest.java index 1bdf5ca3e..7084a600a 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/FullRoleParameterHandlerImplImplTest.java @@ -15,13 +15,13 @@ import org.mockito.junit.MockitoJUnitRunner; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class FullRoleParameterHandlerTest { +public class FullRoleParameterHandlerImplImplTest { @InjectMocks - private FullRoleParameterHandler testUnit; + private FullRoleParameterHandlerImpl testUnit; @Mock - private RoleParameterHandler roleParameterHandler; + private RoleParameterHandlerImpl roleParameterHandler; @Mock private RoleService roleService; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerImplTest.java similarity index 93% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerImplTest.java index e909ffa8b..b0388ef5b 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/IntegerParameterHandlerImplTest.java @@ -7,10 +7,10 @@ import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class IntegerParameterHandlerTest { +public class IntegerParameterHandlerImplTest { @InjectMocks - private IntegerParameterHandler testUnit; + private IntegerParameterHandlerImpl testUnit; @Test public void testSuccessfulCondition() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerImplTest.java similarity index 93% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerImplTest.java index 6acd0701f..b8145fd0b 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/LongParameterHandlerImplTest.java @@ -7,10 +7,10 @@ import org.mockito.InjectMocks; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class LongParameterHandlerTest { +public class LongParameterHandlerImplTest { @InjectMocks - private LongParameterHandler testUnit; + private LongParameterHandlerImpl testUnit; @Test public void testSuccessfulCondition() { diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java similarity index 96% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java index e3012ad07..60b155853 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java @@ -17,10 +17,10 @@ import java.util.concurrent.CompletableFuture; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class MemberParameterHandlerTest { +public class MemberParameterHandlerImplTest { @InjectMocks - private MemberParameterHandler testUnit; + private MemberParameterHandlerImpl testUnit; @Mock private CommandParameterIterators iterators; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java similarity index 95% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java index 475734937..31858c0e3 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/RoleParameterHandlerImplTest.java @@ -16,10 +16,10 @@ import java.util.List; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class RoleParameterHandlerTest { +public class RoleParameterHandlerImplTest { @InjectMocks - private RoleParameterHandler testUnit; + private RoleParameterHandlerImpl testUnit; @Mock private CommandParameterIterators iterators; diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java similarity index 95% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java index 862651a65..337a88295 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/TextChannelParameterHandlerImplTest.java @@ -16,10 +16,10 @@ import java.util.List; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class TextChannelParameterHandlerTest { +public class TextChannelParameterHandlerImplTest { @InjectMocks - private TextChannelParameterHandler testUnit; + private TextChannelParameterHandlerImpl testUnit; @Mock private CommandParameterIterators iterators; 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 153417572..be52e7fc1 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 @@ -25,7 +25,7 @@ public class FeatureModeCondition implements CommandCondition { return ConditionResult.builder().result(true).build(); } } - throw new IncorrectFeatureModeException(command, feature, command.getFeatureModeLimitations()); + throw new IncorrectFeatureModeException(feature, command.getFeatureModeLimitations()); } } 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 3d922511d..d84a8e7a2 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 @@ -35,6 +35,10 @@ public class CommandResult { return CommandResult.builder().result(ResultState.ERROR).message(message).throwable(throwable).build(); } + public static CommandResult fromIgnored() { + return CommandResult.builder().result(ResultState.IGNORED).build(); + } + public static CommandResult fromCondition(ConditionResult result) { return CommandResult.builder().conditionResult(result).result(ResultState.CONDITION).build(); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AChanelParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AChanelParameterHandler.java new file mode 100644 index 000000000..91656058e --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AChanelParameterHandler.java @@ -0,0 +1,6 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface AChanelParameterHandler extends CommandParameterHandler { +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AEmoteParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AEmoteParameterHandler.java new file mode 100644 index 000000000..d7cc5546e --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/AEmoteParameterHandler.java @@ -0,0 +1,6 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface AEmoteParameterHandler extends CommandParameterHandler { +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/ARoleParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/ARoleParameterHandler.java new file mode 100644 index 000000000..f2efe2be0 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/ARoleParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface ARoleParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/BooleanParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/BooleanParameterHandler.java new file mode 100644 index 000000000..37c2a5665 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/BooleanParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface BooleanParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/CommandKeyParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/CommandKeyParameterHandler.java new file mode 100644 index 000000000..5301b75b9 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/CommandKeyParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface CommandKeyParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DoubleParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DoubleParameterHandler.java new file mode 100644 index 000000000..3fa4a3898 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DoubleParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface DoubleParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DurationParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DurationParameterHandler.java new file mode 100644 index 000000000..3d9b17e51 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/DurationParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface DurationParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/EmoteParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/EmoteParameterHandler.java new file mode 100644 index 000000000..2b5b8a2f1 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/EmoteParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface EmoteParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullEmoteParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullEmoteParameterHandler.java new file mode 100644 index 000000000..917ea94b5 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullEmoteParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface FullEmoteParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullRoleParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullRoleParameterHandler.java new file mode 100644 index 000000000..a3bafa9da --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/FullRoleParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface FullRoleParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/IntegerParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/IntegerParameterHandler.java new file mode 100644 index 000000000..00e917481 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/IntegerParameterHandler.java @@ -0,0 +1,8 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface IntegerParameterHandler extends CommandParameterHandler { + + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/LongParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/LongParameterHandler.java new file mode 100644 index 000000000..9f7769194 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/LongParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface LongParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/MemberParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/MemberParameterHandler.java new file mode 100644 index 000000000..ae7a70e53 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/MemberParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface MemberParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/RoleParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/RoleParameterHandler.java new file mode 100644 index 000000000..e68c313d9 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/RoleParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface RoleParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/TextChannelParameterHandler.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/TextChannelParameterHandler.java new file mode 100644 index 000000000..6dceb9ac5 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/command/handler/provided/TextChannelParameterHandler.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.command.handler.provided; + +import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler; + +public interface TextChannelParameterHandler extends CommandParameterHandler { + +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/IncorrectFeatureModeException.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/IncorrectFeatureModeException.java index b3c8738b0..121ea0fa0 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/IncorrectFeatureModeException.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/exception/IncorrectFeatureModeException.java @@ -1,7 +1,6 @@ package dev.sheldan.abstracto.core.exception; -import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureMode; import dev.sheldan.abstracto.core.models.exception.IncorrectFeatureModeExceptionModel; @@ -13,9 +12,9 @@ public class IncorrectFeatureModeException extends AbstractoRunTimeException imp private final IncorrectFeatureModeExceptionModel model; - public IncorrectFeatureModeException(Command command, FeatureEnum featureEnum, List requiredModes) { + public IncorrectFeatureModeException(FeatureEnum featureEnum, List requiredModes) { super("Incorrect feature mode for the command."); - this.model = IncorrectFeatureModeExceptionModel.builder().command(command).featureEnum(featureEnum).requiredModes(requiredModes).build(); + this.model = IncorrectFeatureModeExceptionModel.builder().featureEnum(featureEnum).requiredModes(requiredModes).build(); } @Override diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteCreatedListener.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteCreatedListener.java new file mode 100644 index 000000000..9468bff9b --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteCreatedListener.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.listener; + +import net.dv8tion.jda.api.entities.Emote; + +public interface EmoteCreatedListener extends FeatureAware, Prioritized { + void emoteCreated(Emote createdEmote); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteDeletedListener.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteDeletedListener.java new file mode 100644 index 000000000..05e456501 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteDeletedListener.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.listener; + +import net.dv8tion.jda.api.entities.Emote; + +public interface EmoteDeletedListener extends FeatureAware, Prioritized { + void emoteDeleted(Emote deletedEmote); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteUpdatedListener.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteUpdatedListener.java new file mode 100644 index 000000000..0cd314fe6 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/listener/EmoteUpdatedListener.java @@ -0,0 +1,7 @@ +package dev.sheldan.abstracto.core.listener; + +import net.dv8tion.jda.api.entities.Emote; + +public interface EmoteUpdatedListener extends FeatureAware, Prioritized { + void emoteUpdated(Emote updatedEmote, String oldValue, String newValue); +} diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/Fakeable.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/Fakeable.java new file mode 100644 index 000000000..77fe21e32 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/Fakeable.java @@ -0,0 +1,5 @@ +package dev.sheldan.abstracto.core.models; + +public interface Fakeable { + boolean isFake(); +} 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 b197fb77e..03dd70956 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 @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.models.database; +import dev.sheldan.abstracto.core.models.Fakeable; import lombok.*; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -16,7 +17,7 @@ import java.time.Instant; @EqualsAndHashCode @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) -public class AEmote implements Serializable { +public class AEmote implements Serializable, Fakeable { @javax.persistence.Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/DefaultFeatureFlag.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/DefaultFeatureFlag.java index d2156ba9f..96bc41c51 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/DefaultFeatureFlag.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/database/DefaultFeatureFlag.java @@ -33,10 +33,6 @@ public class DefaultFeatureFlag implements Serializable { @Setter private boolean enabled; - @Getter - @Setter - private String mode; - @Column(name = "created") private Instant created; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/IncorrectFeatureModeExceptionModel.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/IncorrectFeatureModeExceptionModel.java index 73878dcd3..1dd302b14 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/IncorrectFeatureModeExceptionModel.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/exception/IncorrectFeatureModeExceptionModel.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.models.exception; -import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureMode; import lombok.Builder; @@ -15,6 +14,5 @@ import java.util.List; @Builder public class IncorrectFeatureModeExceptionModel implements Serializable { private List requiredModes; - private Command command; private FeatureEnum featureEnum; } 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 091a50ee3..3101541a1 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 @@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.core.models.database.AChannel; import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.requests.restaction.MessageAction; import java.util.List; import java.util.Optional; @@ -18,6 +19,7 @@ public interface ChannelService { CompletableFuture sendTextToChannel(String text, MessageChannel channel); CompletableFuture sendEmbedToAChannel(MessageEmbed embed, AChannel channel); CompletableFuture sendEmbedToChannel(MessageEmbed embed, MessageChannel channel); + MessageAction sendEmbedToChannelInComplete(MessageEmbed embed, MessageChannel channel); List> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel); CompletableFuture sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex); List> sendMessageToSendToChannel(MessageToSend messageToSend, MessageChannel textChannel); 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 3ec70ecec..d37f577e3 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 @@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedReaction; import dev.sheldan.abstracto.core.models.database.AEmote; import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.MessageReaction; import java.util.Optional; @@ -22,4 +23,5 @@ public interface EmoteService { boolean compareAEmote(AEmote a, AEmote b); AEmote getFakeEmote(Object object); AEmote getFakeEmoteFromEmote(Emote emote); + boolean emoteIsFromGuild(Emote emote, Guild guild); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/FileUtils.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/FileUtils.java new file mode 100644 index 000000000..41bbdb288 --- /dev/null +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/utils/FileUtils.java @@ -0,0 +1,27 @@ +package dev.sheldan.abstracto.core.utils; + +import com.google.common.io.Files; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +@Component +public class FileUtils { + public void writeContentToFile(File file, String content) throws IOException { + try(FileWriter fw = new FileWriter(file)) { + fw.write(content); + fw.flush(); + } + + } + + public File createTempFile(String fileName) { + return new File(Files.createTempDir(), fileName); + } + + public void safeDelete(File file) throws IOException { + java.nio.file.Files.delete(file.toPath()); + } +} diff --git a/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/test/command/CommandTestUtilities.java b/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/test/command/CommandTestUtilities.java index b4811d968..dd9b4bc74 100644 --- a/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/test/command/CommandTestUtilities.java +++ b/abstracto-application/core/core-interface/src/test/java/dev/sheldan/abstracto/core/test/command/CommandTestUtilities.java @@ -101,11 +101,20 @@ public class CommandTestUtilities { } public static void checkSuccessfulCompletion(CommandResult result){ - Assert.assertEquals(ResultState.SUCCESSFUL, result.getResult()); + ResultState resultState = result.getResult(); + checkForSuccessResultState(resultState); + } + + private static void checkForSuccessResultState(ResultState resultState) { + boolean canBeConsideredSuccessful = ResultState.SUCCESSFUL.equals(resultState) + || ResultState.IGNORED.equals(resultState) + || ResultState.SELF_DESTRUCT.equals(resultState); + Assert.assertTrue(canBeConsideredSuccessful); } public static void checkSuccessfulCompletionAsync(CompletableFuture result){ - Assert.assertEquals(ResultState.SUCCESSFUL, result.join().getResult()); + ResultState resultState = result.join().getResult(); + checkForSuccessResultState(resultState); } public static List> messageFutureList() { diff --git a/abstracto-application/coverage/pom.xml b/abstracto-application/coverage/pom.xml index 7b62a1eea..258d1adc5 100644 --- a/abstracto-application/coverage/pom.xml +++ b/abstracto-application/coverage/pom.xml @@ -67,9 +67,10 @@ scheduling-impl + - dev.sheldan.abstracto.core - core-impl + dev.sheldan.abstracto.modules + statistic-impl diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc index ef8e567c7..19a8e62fa 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/main.adoc @@ -35,14 +35,16 @@ In the mode `log` mod mail threads will be logged into the post target `modmailL == Features -include::features/core.adoc[] +include::modules/core.adoc[] -include::features/moderation.adoc[] +include::modules/moderation.adoc[] -include::features/modmail.adoc[] +include::modules/modmail.adoc[] -include::features/experience.adoc[] +include::modules/experience.adoc[] -include::features/assignableRoles.adoc[] +include::modules/assignableRoles.adoc[] -include::features/utility.adoc[] +include::modules/statistic.adoc[] + +include::modules/utility.adoc[] diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/assignableRoles.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/assignableRoles.adoc similarity index 100% rename from abstracto-application/documentation/src/main/docs/asciidoc/features/assignableRoles.adoc rename to abstracto-application/documentation/src/main/docs/asciidoc/modules/assignableRoles.adoc diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/core.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/core.adoc similarity index 100% rename from abstracto-application/documentation/src/main/docs/asciidoc/features/core.adoc rename to abstracto-application/documentation/src/main/docs/asciidoc/modules/core.adoc diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/experience.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/experience.adoc similarity index 100% rename from abstracto-application/documentation/src/main/docs/asciidoc/features/experience.adoc rename to abstracto-application/documentation/src/main/docs/asciidoc/modules/experience.adoc diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/moderation.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/moderation.adoc similarity index 100% rename from abstracto-application/documentation/src/main/docs/asciidoc/features/moderation.adoc rename to abstracto-application/documentation/src/main/docs/asciidoc/modules/moderation.adoc diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/modmail.adoc similarity index 97% rename from abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc rename to abstracto-application/documentation/src/main/docs/asciidoc/modules/modmail.adoc index 92e784797..c845184ef 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/modules/modmail.adoc @@ -30,7 +30,7 @@ Feature key: `modmail` ==== Feature modes `log`:: If this is enabled, the messages should be logged into the `modmailLog` post target when the thread is closed (by the respective commands). This is required for the command `closeNoLog` to be available. Enabled by default. -`threadMessage`:: if this is enabled, every message which is send via the commands `reply` and `anonReply` will also be sent to the thread in order to have a visualizer how the message looks +`threadMessage`:: If this is enabled, every message which is send via the commands `reply` and `anonReply` will also be sent to the thread in order to have a visualizer how the message looks and to have a clear indication which messages were sent. Enabled by default. @@ -77,5 +77,5 @@ When closing a thread, a closing header with general information will be send an Close a thread without logging:: * Usage: `closeNoLog` * Description: Closes the thread without notifying the user and without logging the messages. -* Mode Restriction: This command is only available when mod mail is in the mode `log`. +* Mode Restriction: This command is only available when the feature mode `log` is enabled. diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/modules/statistic.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/statistic.adoc new file mode 100644 index 000000000..9c231bb44 --- /dev/null +++ b/abstracto-application/documentation/src/main/docs/asciidoc/modules/statistic.adoc @@ -0,0 +1,60 @@ +=== Statistic + +This component will contain multiple features, currently only emote tracking is available. + +=== Emote tracking +This feature is about tracking the usage of emotes from the server and external servers. +The intention of this feature is to see what emotes are doing better than others and which emotes might be interesting to add to the server. + +Feature key: `emote_tracking` + +==== Feature modes +`emoteAutoTrack`:: If this is enabled, emotes which are created within the server, are automatically stored and tracked. If they are renamed/deleted this will also be reflected automatically. Enabled by default. +`externalEmotes`:: If this is enabled, every external tracked emote will be counted. It is also possible to track additional external emotes via the `trackEmote` command. Disabled by default. +`autoTrackExternal`:: If this is enabled, every external emote which is used in a message by a server member will be automatically stored and tracked. `externalEmotes` needs to be enabled in order for this to function properly. Disabled by default. + +==== Commands +Creating a newly tracked emote:: +* Usage: `trackEmote ` +* Description: The `enoteName` needs to be a valid usage of an emote. If this emote is part of the server, it will now be automatically tracked. +If the emote was tracked previously, it will be enabled again. For external emotes to be tracked this way, the feature mode `externalEmotes` needs to be enabled. The `emote` can either be a valid usage or the ID of an emote (it can only be an ID if it was previously tracked). +Disable tracking for an emote:: +* Usage: `disableEmoteTracking [emote]` +* Description: This command will cause the usages of `emote` to not be counted anymore. The `emote` can either be a valid usage or the ID of an emote. If `emote` is not given, the tracking for all tracked emotes is disabled. +Show currently tracked emotes:: +* Usage: `showTrackedEmotes [showTrackingDisabled]` +* Description: This commands shows the currently tracked emotes of this server. If ´showTrackingDisabled´ is `true` this command will also show the emotes for which the tracking is currently disabled. +The shown tracked emotes are split into six groups: static/animated emotes from the server, static/animated emotes which previously existed on the server and static/animated external emotes. The categories for external emotes will not be shown if `externalEmotes` is disabled. +If there are no emotes of a group, there will be no message. +Show emote statistics of emotes in the server:: +* Usage: `emoteStats [period]` +* Description: This command shows the amount each tracked emote from the server has been used overall. If a `period` is supplied, it will only show the amount of usages in that time period. If it is not provided, it will show the whole timeline. +Beware that the amount of emotes is only tracked per day. For example, if it is 3PM UTC and you use `18h` as a timeperiod, it will also show the emote statistics for the day before. +Show emote statistics of emotes previously in the server:: +* Usage: `deletedEmoteStats [period]` +* Description: This command behaves the same way as `emoteStats` with the difference that it shows the emotes which were previously in the server. This means that the output will only show the name and the ID of the emote. +Show emote statistics of external emotes:: +* Usage: `externalEmoteStats [period]` +* Description: This command behaves the same way as `emoteStats` with the difference that it shows emotes which are not from this server. This means that the output will only show the name and the ID of the emote. +* Mode Restriction: This command is only available when the feature mode `externalEmotes` is enabled. +Synchronize the server emotes with the database:: +* Usage: `syncTrackedEmotes` +* Description: This command cross checks the emotes in the database with the ones currently available in the server. If an emote was deleted in the server, but is still marked as available in the database, it will be marked as deleted. If an emote from the server is not available in the database, it will be created and tracked automatically. +A message containing the amount of emotes deleted and created is shown. If the feature mode `emoteAutoTrack` is enabled, this should only be necessary in case the bot had an outage. +Delete emote usages:: +* Usage: `purgeEmoteStats [period]` +* Description: This command removes any stored usages of `emote`. The `emote` can either be a valid usage or the ID of an emote. If `period` is given, only usages within this time period will be deleted, if it is not provided, the complete timeline will be deleted. +Deleting an individual tracked emote:: +* Usage: `deleteTrackedEmote ` +* Description: Deletes the tracked emote from the database including the usages. The `emote` can either be a valid usage or the ID of an emote. +Reset emote statistics:: +* Usage: `resetEmoteStats` +* Description: This will delete all emote usages and tracked emotes in the database. +Show the image of external tracked emotes:: +* Usage: `showExternalTrackedEmote ` +* Description: Shows the ID, name, link to the image and the image directly for `emote` in an embed. +* Mode Restriction: This command is only available when the feature mode `externalEmotes` is enabled. +Export the stored emote usages:: +* Usage: `exportEmoteStats [period]` +* Description: Creates a CSV file containing the emote usages and attaches it to a message. Each line in the file is the amount of usages of an emote per day. When an emote has not been used in a day, no line is present. If `period` is given, only usages from this time period will be exported, if it is not provided, the complete timeline will be exported. +If the resulting file size is over the upload limit of the server, this command will not provide the file. \ No newline at end of file diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/utility.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/utility.adoc similarity index 100% rename from abstracto-application/documentation/src/main/docs/asciidoc/features/utility.adoc rename to abstracto-application/documentation/src/main/docs/asciidoc/modules/utility.adoc diff --git a/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/model/MessageToSend.java b/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/model/MessageToSend.java index 088b6195e..8ef4cb755 100644 --- a/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/model/MessageToSend.java +++ b/abstracto-application/templating/templating-interface/src/main/java/dev/sheldan/abstracto/templating/model/MessageToSend.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.api.entities.MessageEmbed; +import java.io.File; import java.util.List; /** @@ -22,4 +23,12 @@ public class MessageToSend { * The string content to be used in the first message. */ private String message; + /** + * The file handle to send attached to the message. + */ + private File fileToSend; + + public boolean hasFileToSend() { + return fileToSend != null; + } }