diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpForRole.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpForRole.java index 18025c394..cda5097d6 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpForRole.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpForRole.java @@ -16,6 +16,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to add a role to the roles for which experience has been disabled. + */ @Component public class DisableExpForRole extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpGain.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpGain.java index 2d23c1ee0..1b44364d4 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpGain.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/DisableExpGain.java @@ -18,6 +18,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to disable the experience gain for a specific member + */ @Component public class DisableExpGain extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpForRole.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpForRole.java index 705bf40ef..9c2a09f03 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpForRole.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpForRole.java @@ -16,6 +16,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to remove a role from the list of roles for which experience is disabled + */ @Component public class EnableExpForRole extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpGain.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpGain.java index e9874a5d3..21884483f 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpGain.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/EnableExpGain.java @@ -18,6 +18,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command to enable experience again for a member + */ @Component public class EnableExpGain extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ExpScale.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ExpScale.java index 9e7b7877d..7a61c5769 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ExpScale.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/ExpScale.java @@ -16,6 +16,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to change the experience multiplier on the server. + */ @Component @Slf4j public class ExpScale extends AbstractConditionableCommand { 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 804f37204..03a44f832 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 @@ -24,6 +24,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Shows the experience gain information of the top 10 users in the server, or if a page number is provided as a parameter, only the members which are on this page. + */ @Component @Slf4j public class LeaderBoardCommand extends AbstractConditionableCommand { 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 eadec1aec..8859eb476 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 @@ -22,6 +22,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +/** + * Creates an embed containing the roles for which the experience gain has been disabled. + */ @Component public class ListDisabledExperienceRoles extends AbstractConditionableCommand { 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 abdc75d9b..179f801e8 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 @@ -24,6 +24,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to show an embed containing information about the experience amount, level and message count of a ember on a server + */ @Component public class Rank extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SetExpRole.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SetExpRole.java index d6325055e..d4e1ee23e 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SetExpRole.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/SetExpRole.java @@ -20,6 +20,9 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to define which commands are to be awarded at which level + */ @Component @Slf4j public class SetExpRole extends AbstractConditionableCommand { 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 98b88b5af..066757522 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 @@ -17,6 +17,12 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to synchronize the actual awarded roles which what is defined to be awarded in the database. + * This also calculates the appropriate role for each user and then awards the role, while removing the previously awarded role. + * The synchronization is usually a longer process, and there is a status message to see how far this progress is. + * + */ @Component @Slf4j public class SyncRoles extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/UnSetExpRole.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/UnSetExpRole.java index e040a6856..033e80325 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/UnSetExpRole.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/commands/UnSetExpRole.java @@ -16,6 +16,10 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +/** + * Command used to remove a role from the roles to be awarded at certain levels. If there are users with this role currently, their role + * will be recalculated, and this will be shown with an status update message. + */ @Component public class UnSetExpRole extends AbstractConditionableCommand { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceConfig.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceConfig.java index 50eafcc97..1d94e1947 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceConfig.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceConfig.java @@ -26,7 +26,8 @@ public class ExperienceConfig { private Double expMultiplier; /** - * The defaul maxLevel from the properties file. This configuration applies globally, as the amount of levels does not depend on the server. + * The default maxLevel from the properties file. This configuration applies globally, as the amount of levels does not depend on the server. + * This is only used once, when creating the {@link dev.sheldan.abstracto.experience.models.database.AExperienceLevel} once */ private Integer maxLvl; } \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceDefaultConfigListener.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceDefaultConfigListener.java index f2be6ae21..28b0f5c85 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceDefaultConfigListener.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceDefaultConfigListener.java @@ -8,7 +8,11 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; - +/** + * Bean used to define the default values for the required configuration in the experience module. + * This {@link dev.sheldan.abstracto.core.models.database.ADefaultConfig} is used, when a config key in a module is set to the default value + * This service only creates a value if no one is previously there. + */ @Component public class ExperienceDefaultConfigListener { diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceLevelLoader.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceLevelLoader.java index 8dd2fdea9..0fe17d9e6 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceLevelLoader.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/config/ExperienceLevelLoader.java @@ -24,7 +24,7 @@ public class ExperienceLevelLoader { @EventListener public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) { Integer maxLevel = experienceConfig.getMaxLvl(); - log.info("Setting up experience level configuration."); + log.info("Creating experience levels up to level {}", maxLevel); experienceLevelService.createLevelsUntil(maxLevel); } } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/converter/LeaderBoardModelConverter.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/converter/LeaderBoardModelConverter.java index 345e9970e..96992c672 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/converter/LeaderBoardModelConverter.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/converter/LeaderBoardModelConverter.java @@ -13,7 +13,7 @@ import java.util.ArrayList; import java.util.List; /** - * Converter used to conver from {@link LeaderBoard} to a list of {@link LeaderBoardEntryModel} + * Converter used to convert from {@link LeaderBoard} to a list of {@link LeaderBoardEntryModel} */ @Component public class LeaderBoardModelConverter { @@ -23,10 +23,10 @@ public class LeaderBoardModelConverter { /** * Converts the complete {@link LeaderBoard} into a list of {@link LeaderBoardEntryModel} which contain additional - * information available for rendering the leaderboard ({@link Member} reference) + * information available for rendering the leader board ({@link Member} reference and more) * @param leaderBoard The {@link LeaderBoard} object to be converted * @return The list of {@link LeaderBoardEntryModel} which contain the fully fledged information provided to the - * leaderboard template + * leader board template */ public List fromLeaderBoard(LeaderBoard leaderBoard) { List models = new ArrayList<>(); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/DisabledExpRoleRepository.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/DisabledExpRoleRepository.java index 14104b14c..282ddf6ef 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/DisabledExpRoleRepository.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/DisabledExpRoleRepository.java @@ -8,6 +8,9 @@ import org.springframework.stereotype.Repository; import java.util.List; +/** + * Repository to manage the access to the table managed by {@link ADisabledExpRole} + */ @Repository public interface DisabledExpRoleRepository extends JpaRepository { boolean existsByRole(ARole role); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/UserExperienceRepository.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/UserExperienceRepository.java index d3477618d..ef48578c2 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/UserExperienceRepository.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/repository/UserExperienceRepository.java @@ -39,6 +39,8 @@ public interface UserExperienceRepository extends JpaRepository updateUserRole(experience, roles)); } + /** + * Executes the given {@link Consumer} on each of the experiences and provides feedback in the given AChannel in the form of a status message + * @param experiences The list of {@link AUserExperience} to be working on + * @param channel The {@link AChannel} used to provide feedback to the user + * @param toExecute The {@link Consumer} which should be executed on each element of the passed list + */ @Override public void executeActionOnUserExperiencesWithFeedBack(List experiences, AChannel channel, Consumer toExecute) { MessageToSend status = getUserSyncStatusUpdateModel(0, experiences.size()); @@ -308,7 +314,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService { } page--; int pageSize = 10; - List experiences = userExperienceManagementService.findLeaderboardUsersPaginated(server, page * pageSize, (page + 1) * pageSize); + List experiences = userExperienceManagementService.findLeaderBoardUsersPaginated(server, page * pageSize, (page + 1) * pageSize); List entries = new ArrayList<>(); for (int i = 0; i < experiences.size(); i++) { AUserExperience userExperience = experiences.get(i); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceLevelServiceBean.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceLevelServiceBean.java index 55b1d0df6..e5bdb3394 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceLevelServiceBean.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceLevelServiceBean.java @@ -14,6 +14,11 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService { @Autowired private ExperienceLevelManagementService experienceLevelManagementService; + /** + * Creates experience level if it does not yet exist. + * @param level The level to create + * @param experienceNeeded The total amount of experience needed to reach the given level + */ private void createExperienceLevel(Integer level, Long experienceNeeded) { if(!experienceLevelManagementService.levelExists(level)) { log.trace("Creating new experience level {} with experience needed {}.", level, experienceNeeded); @@ -41,6 +46,7 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService { * @param level The level to calculate the experience amount for * @return The needed experience to reach this level, if the user already has the level below the passed one */ + @Override public Long calculateExperienceForLevel(Integer level) { if(level < 0) { throw new IllegalArgumentException("Level should not be less to 0."); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/ExperienceRoleManagementServiceBean.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/ExperienceRoleManagementServiceBean.java index f3ac21d73..ad0cbd912 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/ExperienceRoleManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/ExperienceRoleManagementServiceBean.java @@ -19,7 +19,7 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage private ExperienceRoleRepository experienceRoleRepository; /** - * Removes all assignments of roles for the given level + * Removes *all* assignments of roles for the given level * @param level The level to remove the roles for * @param server The server in which this should happen */ @@ -45,6 +45,12 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage return experienceRoleRepository.findByRoleServer(server); } + /** + * Creates a new role if nothing is found, and if its found the experience role will be set to the given level. + * @param level The {@link AExperienceLevel} to set the role for + * @param role The {@link ARole} to set to + * @return The created/updated {@link AExperienceRole} + */ @Override public AExperienceRole setLevelToRole(AExperienceLevel level, ARole role) { AExperienceRole byRoleServerAndRole = experienceRoleRepository.findByRole(role); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBean.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBean.java index 3c64ebe6f..0967da016 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBean.java @@ -30,6 +30,11 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage return byId.orElseGet(() -> createUserInServer(aUserInAServer)); } + /** + * Initializes the {@link AUserExperience} with default values the following: 0 experience, 0 messages and experience gain enabled + * @param aUserInAServer The {@link AUserInAServer} to create the {@link AUserExperience} object for. + * @return The created/changed {@link AUserExperience} object + */ @Override public AUserExperience createUserInServer(AUserInAServer aUserInAServer) { AExperienceLevel startingLevel = experienceLevelManagementService.getLevel(0).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", 0))); @@ -81,7 +86,7 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage } @Override - public List findLeaderboardUsersPaginated(AServer aServer, Integer start, Integer end) { + public List findLeaderBoardUsersPaginated(AServer aServer, Integer start, Integer end) { return repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(aServer, PageRequest.of(start, end)); } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/AUserExperienceServiceBeanTest.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/AUserExperienceServiceBeanTest.java index f84635e46..5b7ffb636 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/AUserExperienceServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/AUserExperienceServiceBeanTest.java @@ -583,7 +583,7 @@ public class AUserExperienceServiceBeanTest extends ExperienceRelatedTest { private void executeLeaderBoardTest(AServer server, Integer page) { int pageSize = 10; List experiences = getUserExperiences(pageSize, server); - when(userExperienceManagementService.findLeaderboardUsersPaginated(server, (page - 1) * pageSize, page * pageSize)).thenReturn(experiences); + when(userExperienceManagementService.findLeaderBoardUsersPaginated(server, (page - 1) * pageSize, page * pageSize)).thenReturn(experiences); LeaderBoard leaderBoardData = testUnit.findLeaderBoardData(server, page); page--; List entries = leaderBoardData.getEntries(); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBeanTest.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBeanTest.java index 31a1f3675..dc088a95e 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/src/test/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementServiceBeanTest.java @@ -87,10 +87,10 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe int startIndex = 11; List userExperiences = getUserExperiences(); when(repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(server, PageRequest.of(startIndex, endIndex))).thenReturn(userExperiences); - List leaderboardUsersPaginated = testUnit.findLeaderboardUsersPaginated(server, startIndex, endIndex); - Assert.assertEquals(userExperiences.size(), leaderboardUsersPaginated.size()); + List leaderBoardUsersPaginated = testUnit.findLeaderBoardUsersPaginated(server, startIndex, endIndex); + Assert.assertEquals(userExperiences.size(), leaderBoardUsersPaginated.size()); for (int i = 0; i < userExperiences.size(); i++) { - Assert.assertEquals(userExperiences.get(i).getExperience(), leaderboardUsersPaginated.get(i).getExperience()); + Assert.assertEquals(userExperiences.get(i).getExperience(), leaderBoardUsersPaginated.get(i).getExperience()); } } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeature.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeature.java index 9c46292f4..9a03cfb27 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeature.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeature.java @@ -3,6 +3,9 @@ package dev.sheldan.abstracto.experience.config.features; import dev.sheldan.abstracto.core.config.FeatureEnum; import lombok.Getter; +/** + * The experience tracking feature enum, this is used to switch off/on experience tracking. + */ @Getter public enum ExperienceFeature implements FeatureEnum { EXPERIENCE("experience"); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeatureConfig.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeatureConfig.java index c31c85903..9af361922 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeatureConfig.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/config/features/ExperienceFeatureConfig.java @@ -7,11 +7,24 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * {@link FeatureConfig} instance containing the required configuration concerning system config and post targets for + * the {@link ExperienceFeature} feature. + */ @Component public class ExperienceFeatureConfig implements FeatureConfig { + /** + * Minimum experience a user can earn per tracked message + */ public static final String MIN_EXP_KEY = "minExp"; + /** + * Maximum experience a user can earn per tracked message + */ public static final String MAX_EXP_KEY = "maxExp"; + /** + * The multiplier which is applied to each calculated gained experience + */ public static final String EXP_MULTIPLIER_KEY = "expMultiplier"; @Override @@ -19,6 +32,9 @@ public class ExperienceFeatureConfig implements FeatureConfig { return ExperienceFeature.EXPERIENCE; } + /** + * All of the configuration keys are required in order for this feature to function + */ @Override public List getRequiredSystemConfigKeys() { return Arrays.asList(EXP_MULTIPLIER_KEY, MIN_EXP_KEY, MAX_EXP_KEY); diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/database/ADisabledExpRole.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/database/ADisabledExpRole.java index 25ceafa4a..3ed884861 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/database/ADisabledExpRole.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/database/ADisabledExpRole.java @@ -6,6 +6,9 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; +/** + * A role for which the experience gain in a particular server has been disabled. + */ @Builder @Entity @NoArgsConstructor diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/DisabledExperienceRolesModel.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/DisabledExperienceRolesModel.java index b2e3d3418..fd2e8902f 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/DisabledExperienceRolesModel.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/DisabledExperienceRolesModel.java @@ -10,6 +10,9 @@ import lombok.experimental.SuperBuilder; import java.util.ArrayList; import java.util.List; +/** + * Model used to render an overview of the roles for which experience gain has been disabled on the current server. + */ @Getter @Setter @SuperBuilder diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/LeaderBoardEntryModel.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/LeaderBoardEntryModel.java index e264b9b5f..ebdbc02b7 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/LeaderBoardEntryModel.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/LeaderBoardEntryModel.java @@ -7,7 +7,7 @@ import lombok.Setter; import net.dv8tion.jda.api.entities.Member; /** - * Model used in the list of members when rendering the leaderboard command. The reason this is necessary, + * Model used in the list of members when rendering the leaderboard template. The reason this is necessary, * is because we need more than just the {@link AUserExperience} object, we also need the position of the user in this * guild and the {@link Member} for convenience in the templates. */ diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/UserSyncStatusModel.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/UserSyncStatusModel.java index db77dde2e..c4a34efa0 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/UserSyncStatusModel.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/models/templates/UserSyncStatusModel.java @@ -6,7 +6,7 @@ import lombok.Setter; /** * Object containing the status update information when the user executes the - * command responsible for synchronizing the users with their experience roles. This is a very barebones + * command responsible for synchronizing the users with their experience roles. This is a very small * object as it only contains the current count and the total amount. */ @Getter diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/AUserExperienceService.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/AUserExperienceService.java index 3dae58fe8..90e7e204d 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/AUserExperienceService.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/AUserExperienceService.java @@ -44,7 +44,7 @@ public interface AUserExperienceService { AExperienceLevel calculateLevel(AUserExperience experience, List levels); /** - * Increases the experience of the provided {@link AUserExperience} object and and calculates the new level according + * Calculates the new level of the provided {@link AUserExperience} according * to the provided list of {@link AExperienceLevel} used as level configuration * @param userExperience The {@link AUserExperience} to increase the experience for * @param levels The list of {@link AExperienceLevel} to be used as level configuration @@ -127,6 +127,15 @@ public interface AUserExperienceService { */ void executeActionOnUserExperiencesWithFeedBack(List experiences, AChannel channel, Consumer toExecute); + /** + * Disables the experience gain for a user directly. This sets the `experienceGainDisabled` on the respective {@link AUserExperience} object to true + * @param userInAServer The {@link AUserInAServer} to disable experience gain for + */ void disableExperienceForUser(AUserInAServer userInAServer); + + /** + * Enables the experience gain for a user directly. This sets the `experienceGainDisabled` on the respective {@link AUserExperience} object to false + * @param userInAServer The {@link AUserInAServer} to enable experience for + */ void enableExperienceForUser(AUserInAServer userInAServer); } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceRoleService.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceRoleService.java index 44f47850c..8de299905 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceRoleService.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/ExperienceRoleService.java @@ -36,5 +36,13 @@ public interface ExperienceRoleService { */ AExperienceRole calculateRole(AUserExperience userExperience, List roles); + /** + * Calculates the level at which the next role for a given level is available. + * For example, if the given {@link AExperienceLevel} is 5, and a a {@link AExperienceRole} is awarded at 8, but none in between, this method will return + * the {@link AExperienceLevel} 8. + * @param startLevel The {@link AExperienceLevel} to start off at + * @param server The {@link AServer} to use for the {@link AExperienceRole} configuration + * @return The next {@link AExperienceLevel} a {@link AExperienceRole} is awarded at, this will be null if there are no roles or there is no further role to reach + */ AExperienceLevel getLevelOfNextRole(AExperienceLevel startLevel, AServer server); } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/DisabledExpRoleManagementService.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/DisabledExpRoleManagementService.java index 063014ae4..6cd630083 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/DisabledExpRoleManagementService.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/DisabledExpRoleManagementService.java @@ -6,9 +6,37 @@ import dev.sheldan.abstracto.experience.models.database.ADisabledExpRole; import java.util.List; +/** + * Service used to manage the instances of {@link ADisabledExpRole} in the database, which includes creating, removing and retrieving them + */ public interface DisabledExpRoleManagementService { + + /** + * Creates an instance of {@link ADisabledExpRole} which marks the {@link ARole} as disabled. This effectively means, that the experience is disabled for members + * which have the {@link ARole} + * @param role The {@link ARole} which should be used as a role to disable experience + * @return The create instance of {@link ADisabledExpRole} + */ ADisabledExpRole setRoleToBeDisabledForExp(ARole role); + + /** + * Removes the given {@link ARole} from the list of roles which had their experience gain disabled. This method removes the instance from the list of + * {@link ADisabledExpRole} and enables experience for the given {@link ARole} + * @param role The {@link ARole} to enable experience for + */ void removeRoleToBeDisabledForExp(ARole role); + + /** + * Retrieves all the {@link ADisabledExpRole} roles for a given {@link AServer}, which means, it returns all roles for which there is + * @param server The {@link AServer} to retrieve all {@link ADisabledExpRole} for + * @return A List of {@link ADisabledExpRole} which are currently on the {@link AServer} + */ List getDisabledRolesForServer(AServer server); + + /** + * Checks if the given {@link ARole} has its experience disabled and returns true if so + * @param role The {@link ARole} to check for + * @return Whether or not the given {@link ARole} has the experience disabled. + */ boolean isExperienceDisabledForRole(ARole role); } diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementService.java b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementService.java index d8323a47a..901aa6042 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementService.java +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/src/main/java/dev/sheldan/abstracto/experience/service/management/UserExperienceManagementService.java @@ -51,7 +51,7 @@ public interface UserExperienceManagementService { * @param end The end index for which to return a sublist of {@link AUserExperience} elements for * @return A list desc ordered by {@link AUserExperience.experience} only containing the elements between {@code start} and @{code end} */ - List findLeaderboardUsersPaginated(AServer server, Integer start, Integer end); + List findLeaderBoardUsersPaginated(AServer server, Integer start, Integer end); /** * Returns the {@link LeaderBoardEntryResult} of the given {@link AUserExperience}. diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java index e663abfd7..21f2c817e 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/AnonReply.java @@ -8,7 +8,7 @@ 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.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.ModMailThreadService; @@ -19,11 +19,15 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * Sends the reply from the staff member to the user, but marks the reply as anonymous. The original author is still + * tracked internally. + */ @Component public class AnonReply extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadService modMailThreadService; @@ -34,6 +38,7 @@ public class AnonReply extends AbstractConditionableCommand { @Override public CommandResult execute(CommandContext commandContext) { List parameters = commandContext.getParameters().getParameters(); + // text is optional, for example if only an attachment is sent String text = parameters.size() == 1 ? (String) parameters.get(0) : ""; ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); modMailThreadService.relayMessageToDm(thread, text, commandContext.getMessage(), true, commandContext.getChannel()); 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 13cf0693c..012d5dee2 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 @@ -8,7 +8,7 @@ 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.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.ModMailThreadService; @@ -21,11 +21,16 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.List; +/** + * Closes the mod mail thread: logs the messages to the log post target, if the feature has the appropriate + * {@link dev.sheldan.abstracto.core.config.FeatureMode}, deletes the {@link net.dv8tion.jda.api.entities.MessageChannel}. + * This command takes an optional parameter, the note, which will be replaced with a default value, if not present + */ @Component public class Close extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadManagementService modMailThreadManagementService; @@ -41,6 +46,7 @@ public class Close extends AbstractConditionableCommand { @Transactional public CommandResult execute(CommandContext commandContext) { List parameters = commandContext.getParameters().getParameters(); + // the default value of the note is configurable via template String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object()); ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), note, true); 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 78eff3190..0672e40c2 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 @@ -8,7 +8,7 @@ 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.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.config.ModMailMode; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; @@ -21,11 +21,16 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * This command closes a mod mail thread without logging the closing and the contents of the {@link ModMailThread}. + * This command is only available if the server has the {@link dev.sheldan.abstracto.modmail.config.ModMailFeature} + * in the 'LOGGING' mode, because else the normal close command behaves the same way. + */ @Component public class CloseNoLog extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadManagementService modMailThreadManagementService; @@ -39,6 +44,7 @@ public class CloseNoLog extends AbstractConditionableCommand { @Override public CommandResult execute(CommandContext commandContext) { ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); + // we dont have a note, therefore we cant pass any, the method handles this accordingly modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), null, false, false); return CommandResult.fromSuccess(); } @@ -67,6 +73,9 @@ public class CloseNoLog extends AbstractConditionableCommand { return conditions; } + /** + * This command is only available in the LOGGING mod mail feature mode + */ @Override public List getFeatureModeLimitations() { return Arrays.asList(ModMailMode.LOGGING); 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 a023b1a1f..dda1e7dc2 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 @@ -8,7 +8,7 @@ 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.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.ModMailThreadService; @@ -20,11 +20,15 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * This command can be used to close the mod mail thread without sending a 'closing' message to the user. + * This behaves the same way as the default close commmand otherwise + */ @Component public class CloseSilently extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadManagementService modMailThreadManagementService; @@ -37,6 +41,7 @@ public class CloseSilently extends AbstractConditionableCommand { @Override public CommandResult execute(CommandContext commandContext) { List parameters = commandContext.getParameters().getParameters(); + // default note text is configurable via template, because the note is optional String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object()); ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); modMailThreadService.closeModMailThread(thread, commandContext.getChannel(), note, false); 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 592fcd702..7e6ddfd45 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 @@ -26,6 +26,10 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * This command is used to create a thread with a member directly. If a thread already exists, this will post a link to + * the {@link net.dv8tion.jda.api.entities.MessageChannel} + */ @Component public class Contact extends AbstractConditionableCommand { @@ -38,9 +42,6 @@ public class Contact extends AbstractConditionableCommand { @Autowired private UserInServerManagementService userManagementService; - @Autowired - private TemplateService templateService; - @Autowired private ChannelService channelService; @@ -48,12 +49,13 @@ public class Contact extends AbstractConditionableCommand { public CommandResult execute(CommandContext commandContext) { Member targetUser = (Member) commandContext.getParameters().getParameters().get(0); AUserInAServer user = userManagementService.loadUser(targetUser); - ModMailThread existingThread = modMailThreadManagementService.getOpenModmailThreadForUser(user); - if(existingThread != null) { + // if this AUserInAServer already has an open thread, we should instead post a message + // containing a link to the channel, instead of opening a new one + if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) { ModMailThreadExistsModel model = (ModMailThreadExistsModel) ContextConverter.fromCommandContext(commandContext, ModMailThreadExistsModel.class); + ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user); model.setExistingModMailThread(existingThread); - MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_thread_already_exists", model); - channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()); + channelService.sendEmbedTemplateInChannel("modmail_thread_already_exists", model, commandContext.getChannel()); } else { FullUser fullUser = FullUser .builder() diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java index 915fe0e18..7b657ca77 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/ModMailModuleInterface.java @@ -2,6 +2,8 @@ package dev.sheldan.abstracto.modmail.commands; import dev.sheldan.abstracto.core.command.config.ModuleInfo; import dev.sheldan.abstracto.core.command.config.ModuleInterface; +import dev.sheldan.abstracto.templating.service.TemplateService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component @@ -9,9 +11,13 @@ public class ModMailModuleInterface implements ModuleInterface { public static final String MODMAIL = "modMail"; + @Autowired + private TemplateService templateService; + @Override public ModuleInfo getInfo() { - return ModuleInfo.builder().name(MODMAIL).description("Commands to be used for modmail.").build(); + String description = templateService.renderSimpleTemplate("modmail_help_module_info"); + return ModuleInfo.builder().name(MODMAIL).description(description).build(); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/RemoveModMailRole.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/RemoveModMailRole.java index f38e8e2d2..446e900ae 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/RemoveModMailRole.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/RemoveModMailRole.java @@ -16,6 +16,11 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * This command is used to remove a role from the roles to be notified when a new {@link dev.sheldan.abstracto.modmail.models.database.ModMailThread} + * is opened. The method this command executes also automatically dis-allows all mod mail related {@link dev.sheldan.abstracto.core.command.Command} + * for this role. + */ @Component public class RemoveModMailRole extends AbstractConditionableCommand { @@ -25,7 +30,7 @@ public class RemoveModMailRole extends AbstractConditionableCommand { @Override public CommandResult execute(CommandContext commandContext) { ARole role = (ARole) commandContext.getParameters().getParameters().get(0); - modMailRoleService.removeRoleFromModMailRoles(role, commandContext.getUserInitiatedContext().getServer()); + modMailRoleService.removeRoleFromModMailRoles(role); return CommandResult.fromSuccess(); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java index da9a18a68..22e9ddf4a 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Reply.java @@ -8,7 +8,7 @@ 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.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.ModMailThreadService; @@ -19,11 +19,14 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * Sends the reply from the staff member to the user, and shows the actual author in the created embed. + */ @Component public class Reply extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadService modMailThreadService; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java index d68c73d8d..cfb481228 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailCategory.java @@ -15,6 +15,10 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * This command is used to change the category used to create new mod mail threads. This does not migrate the + * existing mod mail threads. + */ @Component public class SetModMailCategory extends AbstractConditionableCommand { @@ -24,7 +28,7 @@ public class SetModMailCategory extends AbstractConditionableCommand { @Override public CommandResult execute(CommandContext commandContext) { Long categoryId = (Long) commandContext.getParameters().getParameters().get(0); - modMailThreadService.setModMailCategoryTo(commandContext.getUserInitiatedContext().getServer(), categoryId); + modMailThreadService.setModMailCategoryTo(commandContext.getGuild(), categoryId); return CommandResult.fromSuccess(); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailRole.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailRole.java index a66878e45..142183be1 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailRole.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/SetModMailRole.java @@ -16,6 +16,11 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * This command is used to add roles to the roles being pinged when a new mod mail thread is opened. + * The method this command uses automatically adds the mentioned roles to the roles which are allowed to execute + * the mod mail related commands. + */ @Component public class SetModMailRole extends AbstractConditionableCommand { @@ -25,7 +30,7 @@ public class SetModMailRole extends AbstractConditionableCommand { @Override public CommandResult execute(CommandContext commandContext) { ARole role = (ARole) commandContext.getParameters().getParameters().get(0); - modMailRoleService.addRoleToModMailRoles(role, commandContext.getUserInitiatedContext().getServer()); + modMailRoleService.addRoleToModMailRoles(role); return CommandResult.fromSuccess(); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Subscribe.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Subscribe.java index ef27f4d5f..db542816f 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Subscribe.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/Subscribe.java @@ -7,7 +7,7 @@ import dev.sheldan.abstracto.core.command.config.HelpInfo; import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.config.FeatureEnum; -import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService; @@ -18,11 +18,16 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; + +/** + * This command subscribes the member executing this command to the {@link ModMailThread} in which the command was executed in. + * In case the member is already subscribed an error message is displayed. + */ @Component public class Subscribe extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadManagementService modMailThreadManagementService; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/UnSubscribe.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/UnSubscribe.java index becdf75ba..223ed8c56 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/UnSubscribe.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/UnSubscribe.java @@ -7,7 +7,7 @@ import dev.sheldan.abstracto.core.command.config.HelpInfo; import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.config.FeatureEnum; -import dev.sheldan.abstracto.modmail.commands.condition.RequiresModMailCondition; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService; @@ -18,11 +18,16 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; + +/** + * This command un-subscribes the member executing this command from the {@link ModMailThread} in which the command was executed in. + * In case the member is not subscribed an error message is displayed. + */ @Component public class UnSubscribe extends AbstractConditionableCommand { @Autowired - private RequiresModMailCondition requiresModMailCondition; + private ModMailContextCondition requiresModMailCondition; @Autowired private ModMailThreadManagementService modMailThreadManagementService; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java index e69fd2a31..c3a1bf7fa 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/commands/condition/RequiresModMailCondition.java @@ -1,26 +1,35 @@ package dev.sheldan.abstracto.modmail.commands.condition; import dev.sheldan.abstracto.core.command.Command; -import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.ConditionResult; import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; +import dev.sheldan.abstracto.templating.service.TemplateService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +/** + * This {@link dev.sheldan.abstracto.core.command.condition.CommandCondition} checks the channel it is executed in + * and checks if the channel is a valid and open mod mail thread. + */ @Component -public class RequiresModMailCondition implements CommandCondition { +public class RequiresModMailCondition implements ModMailContextCondition { @Autowired private ModMailThreadManagementService modMailThreadManagementService; + @Autowired + private TemplateService templateService; + @Override public ConditionResult shouldExecute(CommandContext commandContext, Command command) { ModMailThread thread = modMailThreadManagementService.getByChannel(commandContext.getUserInitiatedContext().getChannel()); if(thread != null) { return ConditionResult.builder().result(true).build(); } - return ConditionResult.builder().result(false).reason("Not in a mod mail thread.").build(); + String text = templateService.renderSimpleTemplate("modmail_not_in_modmail_thread"); + return ConditionResult.builder().result(false).reason(text).build(); } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailConfigListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailConfigListener.java index 4e5c4502e..c31ac5ce1 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailConfigListener.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailConfigListener.java @@ -10,6 +10,11 @@ import org.springframework.stereotype.Component; import static dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean.MODMAIL_CLOSING_MESSAGE_TEXT; +/** + * This listener is used to used to set the initial values of some server specific values, so we dont need to fall + * back to the default values. The values might not be functional, for example mod mail category id, but their existence + * makes things easier + */ @Component public class ModMailConfigListener implements ServerConfigListener { diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailDefaultConfigListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailDefaultConfigListener.java index 5e5846bb4..7392441b7 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailDefaultConfigListener.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailDefaultConfigListener.java @@ -10,6 +10,10 @@ import org.springframework.transaction.annotation.Transactional; import static dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean.MODMAIL_CLOSING_MESSAGE_TEXT; +/** + * This listener is executed when the Spring context starts up and is used to set some default values related + * to mod mail. + */ @Component public class ModMailDefaultConfigListener { diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java index 3526737e1..8aafa88a3 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailMessageListener.java @@ -3,6 +3,8 @@ package dev.sheldan.abstracto.modmail.listener; import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.listener.PrivateMessageReceivedListener; import dev.sheldan.abstracto.core.models.database.AUser; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserManagementService; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; @@ -14,6 +16,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + +/** + * This listener is the core mechanic behind mod mail, if the bot receives a message via DM, this listener is executed + * and checks if the message should be forwarded to an existing mod mail thread, or if a new thread should be created/the + * user should be prompted for a new mod mail thread. + */ @Component @Slf4j public class ModMailMessageListener implements PrivateMessageReceivedListener { @@ -27,12 +36,17 @@ public class ModMailMessageListener implements PrivateMessageReceivedListener { @Autowired private UserManagementService userManagementService; + @Autowired + private UserInServerManagementService userInServerManagementService; + @Override @Transactional public void execute(Message message) { AUser user = userManagementService.loadUser(message.getAuthor().getIdLong()); - ModMailThread existingThread = modMailThreadManagementService.getOpenModmailThreadForUser(user); - if(existingThread != null) { + if(modMailThreadManagementService.hasOpenModMailThread(user)) { + // there is only one open mod mail thread for a user at a time, so we can select the first one + // we cannot use the AUserInAServer directly, because a message in a private channel does not have a Member + ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadsForUser(user).get(0); modMailThreadService.relayMessageToModMailThread(existingThread, message); } else { modMailThreadService.createModMailPrompt(user, message); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java index 654edebe3..4d0ea93b7 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailMessageRepository.java @@ -7,6 +7,9 @@ import org.springframework.stereotype.Repository; import java.util.List; +/** + * Repository to manage the stored {@link ModMailMessage} instances + */ @Repository public interface ModMailMessageRepository extends JpaRepository { List findByThreadReference(ModMailThread modMailThread); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailRoleRepository.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailRoleRepository.java index 7a3349cda..ee6b41e58 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailRoleRepository.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailRoleRepository.java @@ -8,6 +8,9 @@ import org.springframework.stereotype.Repository; import java.util.List; +/** + * Repository to manage the stored {@link ModMailRole} instances + */ @Repository public interface ModMailRoleRepository extends JpaRepository { boolean existsByServerAndRole(AServer server, ARole role); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailSubscriberRepository.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailSubscriberRepository.java index ea7caa480..3311b9b03 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailSubscriberRepository.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailSubscriberRepository.java @@ -8,6 +8,9 @@ import org.springframework.stereotype.Repository; import java.util.List; +/** + * Repository to manage the stored {@link ModMailThreadSubscriber} instances + */ @Repository public interface ModMailSubscriberRepository extends JpaRepository { List findByThreadReference(ModMailThread thread); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java index 938d5fde9..a4b43204c 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/repository/ModMailThreadRepository.java @@ -11,13 +11,18 @@ import org.springframework.stereotype.Repository; import java.util.List; +/** + * Repository to manage the stored {@link ModMailThread} instances + */ @Repository public interface ModMailThreadRepository extends JpaRepository { ModMailThread findByChannel(AChannel channel); List findByUser(AUserInAServer aUserInAServer); ModMailThread findTopByUserOrderByClosedDesc(AUserInAServer aUserInAServer); - ModMailThread findByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state); + List findByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state); + boolean existsByUser_UserReferenceAndStateNot(AUser user, ModMailThreadState state); List findByServerAndState(AServer server, ModMailThreadState state); ModMailThread findByUserAndStateNot(AUserInAServer userInAServer, ModMailThreadState state); + boolean existsByUserAndStateNot(AUserInAServer userInAServer, ModMailThreadState state); List findByUserAndState(AUserInAServer userInAServer, ModMailThreadState state); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java index 4b7f51bd1..2e54795ad 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java @@ -28,12 +28,14 @@ public class ModMailMessageServiceBean implements ModMailMessageService { if(modMailMessages.isEmpty()) { return new ArrayList<>(); } + // all message must be from the same thread ModMailThread thread = modMailMessages.get(0).getThreadReference(); List messageIds = new ArrayList<>(); modMailMessages.forEach(modMailMessage -> { ServerChannelMessage.ServerChannelMessageBuilder serverChannelMessageBuilder = ServerChannelMessage .builder() .messageId(modMailMessage.getMessageId()); + // if its not from a private chat, we need to set the server and channel ID in order to fetch the data if(Boolean.FALSE.equals(modMailMessage.getDmChannel())) { serverChannelMessageBuilder .channelId(modMailMessage.getThreadReference().getChannel().getId()) @@ -42,6 +44,10 @@ public class ModMailMessageServiceBean implements ModMailMessageService { messageIds.add(serverChannelMessageBuilder.build()); }); List> messageFutures = new ArrayList<>(); + // add the place holder futures, which are then resolved one by one + // because we cannot directly fetch the messages, in case they are in a private channel + // the opening of a private channel is a rest operation it itself, so we need + // to create the promises here already, else the list is empty for example modMailMessages.forEach(modMailMessage -> messageFutures.add(new CompletableFuture<>())); Optional textChannelFromServer = botService.getTextChannelFromServer(thread.getServer().getId(), thread.getChannel().getId()); if(textChannelFromServer.isPresent()) { @@ -49,6 +55,8 @@ public class ModMailMessageServiceBean implements ModMailMessageService { botService.getInstance().openPrivateChannelById(thread.getUser().getUserReference().getId()).queue(privateChannel -> { Iterator> iterator = messageFutures.iterator(); messageIds.forEach(serverChannelMessage -> { + // TODO fix out of order promises + // depending what the source of the message is, we need to fetch the message from the correct channel if(serverChannelMessage.getChannelId() == null){ privateChannel.retrieveMessageById(serverChannelMessage.getMessageId()).queue(message -> iterator.next().complete(message), throwable -> { log.info("Failed to load message in private channel with user {}", thread.getUser().getUserReference().getId()); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java index 2bd3468d2..88118dfc1 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleServiceBean.java @@ -3,7 +3,6 @@ package dev.sheldan.abstracto.modmail.service; import dev.sheldan.abstracto.core.command.service.CommandService; import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService; import dev.sheldan.abstracto.core.models.database.ARole; -import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService; import org.springframework.beans.factory.annotation.Autowired; @@ -22,16 +21,16 @@ public class ModMailRoleServiceBean implements ModMailRoleService { private FeatureManagementService featureManagementService; @Override - public void addRoleToModMailRoles(ARole role, AServer server) { - if(!modMailRoleManagementService.isRoleAlreadyAssigned(role, server)) { - modMailRoleManagementService.addRoleToModMailRoles(role, server); + public void addRoleToModMailRoles(ARole role) { + if(!modMailRoleManagementService.isRoleAlreadyAssigned(role, role.getServer())) { + modMailRoleManagementService.addRoleToModMailRoles(role, role.getServer()); } commandService.allowFeatureForRole(ModMailFeatures.MOD_MAIL, role); } @Override - public void removeRoleFromModMailRoles(ARole role, AServer server) { - modMailRoleManagementService.removeRoleFromModMailRoles(role, server); + public void removeRoleFromModMailRoles(ARole role) { + modMailRoleManagementService.removeRoleFromModMailRoles(role, role.getServer()); commandService.disAllowFeatureForRole(ModMailFeatures.MOD_MAIL, role); } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionServiceBean.java index 1123d77e7..61a6ac268 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionServiceBean.java @@ -19,7 +19,7 @@ public class ModMailSubscriptionServiceBean implements ModMailSubscriptionServic if(!modMailSubscriberManagementService.isSubscribedToThread(aUserInAServer, modMailThread)){ modMailSubscriberManagementService.createSubscriber(aUserInAServer, modMailThread); } else { - throw new AlreadySubscribedException("The user is already subscribed to the thread."); + throw new AlreadySubscribedException(); } } @@ -28,7 +28,7 @@ public class ModMailSubscriptionServiceBean implements ModMailSubscriptionServic if(modMailSubscriberManagementService.isSubscribedToThread(aUserInAServer, modMailThread)){ modMailSubscriberManagementService.removeSubscriber(aUserInAServer, modMailThread); } else { - throw new NotSubscribedException("The user is not subscribed to the thread."); + throw new NotSubscribedException(); } } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java index 60bf08cfa..9a04bfb02 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java @@ -2,7 +2,10 @@ package dev.sheldan.abstracto.modmail.service; import com.jagrosh.jdautilities.commons.waiter.EventWaiter; import com.jagrosh.jdautilities.menu.ButtonMenu; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.PostTargetNotFoundException; +import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException; +import dev.sheldan.abstracto.core.models.FeatureValidationResult; import dev.sheldan.abstracto.core.models.FullGuild; import dev.sheldan.abstracto.core.models.FullUser; import dev.sheldan.abstracto.core.models.UndoActionInstance; @@ -13,6 +16,7 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi import dev.sheldan.abstracto.core.service.management.UserInServerService; import dev.sheldan.abstracto.core.utils.CompletableFutureList; import dev.sheldan.abstracto.modmail.config.*; +import dev.sheldan.abstracto.modmail.exception.ModMailCategoryIdException; import dev.sheldan.abstracto.modmail.exception.ModMailThreadNotFoundException; import dev.sheldan.abstracto.modmail.models.database.*; import dev.sheldan.abstracto.modmail.models.dto.ServerChoice; @@ -21,6 +25,7 @@ import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagement import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailSubscriberManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; +import dev.sheldan.abstracto.modmail.validator.ModMailFeatureValidator; import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; @@ -39,9 +44,19 @@ import java.util.concurrent.ExecutionException; @Slf4j public class ModMailThreadServiceBean implements ModMailThreadService { + /** + * The config key to use for the closing text + */ public static final String MODMAIL_CLOSING_MESSAGE_TEXT = "modMailClosingText"; + /** + * The config key to use for the ID of the category to create {@link MessageChannel} in + */ public static final String MODMAIL_CATEGORY = "modmailCategory"; + /** + * The template key used for default mod mail exceptions + */ public static final String MODMAIL_EXCEPTION_GENERIC_TEMPLATE = "modmail_exception_generic"; + @Autowired private ModMailThreadManagementService modMailThreadManagementService; @@ -99,10 +114,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Autowired private FeatureModeService featureModeService; + @Autowired + private ModMailFeatureValidator modMailFeatureValidator; @Autowired private ModMailThreadServiceBean self; + /** + * The emoji used when the user can decide for a server to open a mod mail thread in. + */ private List NUMBER_EMOJI = Arrays.asList("\u0031\u20e3", "\u0032\u20e3", "\u0033\u20e3", "\u0034\u20e3", "\u0035\u20e3", "\u0036\u20e3", "\u0037\u20e3", "\u0038\u20e3", "\u0039\u20e3", @@ -111,21 +131,32 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Override public void createModMailThreadForUser(FullUser aUserInAServer, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated) { - Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, aUserInAServer.getAUserInAServer().getServerReference().getId()); + Long serverId = aUserInAServer.getAUserInAServer().getServerReference().getId(); + Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId); User user = aUserInAServer.getMember().getUser(); - CompletableFuture textChannel = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId); + CompletableFuture textChannelFuture = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId); - textChannel.thenAccept(channel -> { + Long userInServerId = aUserInAServer.getAUserInAServer().getUserInServerId(); + textChannelFuture.thenAccept(channel -> { List undoActions = new ArrayList<>(); - undoActions.add(UndoActionInstance.getChannelDeleteAction(aUserInAServer.getAUserInAServer().getServerReference().getId(), channel.getIdLong())); + undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong())); self.performModMailThreadSetup(aUserInAServer, initialMessage, channel, userInitiated, undoActions); }).exceptionally(throwable -> { log.error("Failed to create mod mail thread", throwable); - sendModMailFailure("modmail_exception_failed_to_create_mod_mail_thread", aUserInAServer.getAUserInAServer(), null, feedBackChannel, throwable); + sendModMailFailure("modmail_exception_failed_to_create_mod_mail_thread", userInServerId, null, feedBackChannel, throwable); return null; }); } + /** + * this method is responsible for creating the instance in the database, sending the header in the newly created text channel and forwarding the initial message + * by the user (if any), after this is complete, this method executes the method to perform the mod mail notification. + * @param aUserInAServer The {@link FullUser} for which a {@link ModMailThread} is being created + * @param initialMessage The {@link Message} which was sent by the user to open a thread, this is null, if the thread was oepend via a command + * @param channel The created {@link TextChannel} in which the mod mail thread is dealth with + * @param userInitiated Whether or not the thread was initiated by a member + * @param undoActions The list of actions to undo, in case an exception occurs + */ @Transactional public void performModMailThreadSetup(FullUser aUserInAServer, Message initialMessage, TextChannel channel, boolean userInitiated, List undoActions) { try { @@ -148,6 +179,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * Sends the message containing the pings to notify the staff members to handle the opened {@link ModMailThread} + * @param aUserInAServer The {@link FullUser} which opened the thread + * @param thread The {@link ModMailThread} instance which was created + * @param undoActions The list of {@link UndoActionInstance} to perform, in case an exception occurs + */ @Transactional public void sendModMailNotification(FullUser aUserInAServer, ModMailThread thread, List undoActions) { List rolesToPing = modMailRoleManagementService.getRolesForServer(thread.getServer()); @@ -167,6 +204,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService { }); } + /** + * Creates the instance of the {@link ModMailThread} in the database. + * @param channel The {@link TextChannel} in which the {@link ModMailThread} is being done + * @param user The {@link FullUser} which the thread is about + * @return The created instance of {@link ModMailThread} + */ public ModMailThread createThreadObject(TextChannel channel, FullUser user) { AChannel channel2 = channelManagementService.createChannel(channel.getIdLong(), AChannelType.TEXT, user.getAUserInAServer().getServerReference()); log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), channel2.getId()); @@ -174,28 +217,26 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } @Override - public boolean hasOpenThread(AUserInAServer aUserInAServer) { - return modMailThreadManagementService.getOpenModmailThreadForUser(aUserInAServer) != null; - } - - @Override - public boolean hasOpenThread(AUser user) { - return modMailThreadManagementService.getOpenModmailThreadForUser(user) != null; - } - - @Override - public void setModMailCategoryTo(AServer server, Long categoryId) { - configService.setLongValue(MODMAIL_CATEGORY, server.getId(), categoryId); + public void setModMailCategoryTo(Guild guild, Long categoryId) { + FeatureValidationResult result = FeatureValidationResult.builder().build(); + modMailFeatureValidator.validateModMailCategory(result, guild, categoryId); + if(result.getValidationResult()) { + throw new ModMailCategoryIdException(categoryId); + } + configService.setLongValue(MODMAIL_CATEGORY, guild.getIdLong(), categoryId); } @Override public void createModMailPrompt(AUser user, Message initialMessage) { List knownServers = userInServerManagementService.getUserInAllServers(user.getId()); + // do nothing if we dont know the user if(!knownServers.isEmpty()) { List availableGuilds = new ArrayList<>(); HashMap choices = new HashMap<>(); for (int i = 0; i < knownServers.size(); i++) { AUserInAServer aUserInAServer = knownServers.get(i); + // only take the servers in which mod mail is actually enabled, would not make much sense to make the + // other servers available if(featureFlagService.isFeatureEnabled(modMailFeature, aUserInAServer.getServerReference())) { AServer serverReference = aUserInAServer.getServerReference(); FullGuild guild = FullGuild @@ -203,12 +244,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService { .guild(botService.getGuildByIdNullable(serverReference.getId())) .server(serverReference) .build(); + // TODO support more than this limited amount of servers String reactionEmote = NUMBER_EMOJI.get(i); ServerChoice serverChoice = ServerChoice.builder().guild(guild).reactionEmote(reactionEmote).build(); choices.put(reactionEmote, aUserInAServer); availableGuilds.add(serverChoice); } } + // if more than 1 server is available, show a choice dialog if(availableGuilds.size() > 1) { ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel .builder() @@ -227,14 +270,29 @@ public class ModMailThreadServiceBean implements ModMailThreadService { }) .build(); menu.display(initialMessage.getChannel()); + } else if(availableGuilds.size() == 1) { + // if exactly one server is available, open the thread directly + AUserInAServer chosenServer = choices.get(availableGuilds.get(0).getReactionEmote()); + Member memberInServer = botService.getMemberInServer(chosenServer); + FullUser fullUser = FullUser.builder().member(memberInServer).aUserInAServer(chosenServer).build(); + self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true); } else { + // in case there is no server available, send an error message channelService.sendEmbedTemplateInChannel("modmail_no_server_available", new Object(), initialMessage.getChannel()); } - + } else { + log.warn("User which was not known in any of the servers tried to contact the bot. {}", user.getId()); } } + /** + * Method used to send the header of a newly created mod mail thread. This message contains information about + * the user which the thread is about + * @param channel The {@link TextChannel} in which the mod mail thread is present in + * @param aUserInAServer The {@link AUserInAServer} which the {@link ModMailThread} is about + * @param undoActions The list of {@link UndoActionInstance} to execute in case an exception occurs + */ private void sendModMailHeader(TextChannel channel, FullUser aUserInAServer, List undoActions) { ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer.getAUserInAServer()); List oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer.getAUserInAServer()); @@ -267,6 +325,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * This message takes a received {@link Message} from a user, renders it to a new message to send and sends it to + * the appropriate {@link ModMailThread} channel, the returned promise only returns if the message was dealt with on the user + * side. + * @param textChannel The {@link TextChannel} in which the {@link ModMailThread} is being handled + * @param modMailThread The {@link ModMailThread} to which the received {@link Message} is a reply to + * @param message The received message from the user + * @return A {@link CompletableFuture} which resolves when the post processing of the message is completed (adding read notification, and storing messageIDs) + */ public CompletableFuture sendUserReply(TextChannel textChannel, ModMailThread modMailThread, Message message) { Long modMailThreadId = modMailThread.getId(); FullUser fullUser = FullUser @@ -300,6 +367,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } + /** + * This message handles the post processing of the messages received by the user. This includes: saving the messageIDs + * in the database, updating the state of the {@link ModMailThread} and adding the read reaction to the user message + * @param modMailThreadId The ID of the {@link ModMailThread} for which the message was directed to + * @param message The actual {@link Message} instance received from the user. + * @param completableFutures The list of {@link CompletableFuture} which were rendered from the sent message + * and posted in the {@link ModMailThread} by Abstracto + */ @Transactional public void postProcessSendMessages(Long modMailThreadId, Message message, List> completableFutures) { Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); @@ -315,7 +390,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService { Thread.currentThread().interrupt(); } self.saveMessageIds(messages, modMailThread, modMailThread.getUser(), false, false); + // update the state of the thread modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED); + // add the reaction to show that the message has been processed messageService.addReactionToMessage("readReaction", modMailThread.getServer().getId(), message); }); } else { @@ -336,9 +413,21 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * Notifies the staff members in the thread about any exception occurring when executing a command in a {@link ModMailThread}. + * This takes a custom template which is rendered and a generic model is provided. + * @param template The key of the {@link dev.sheldan.abstracto.templating.model.database.Template} to use + * @param userInServerId The ID of the user in the server which the {@link ModMailThread} is about + * @param modMailTreadId The ID of the {@link ModMailThread} in which an exception occurred + * @param channel The {@link MessageChannel} in to which the exception message should be sent to + * @param throwable The instance of the {@link Throwable} which happened. + * @throws UserInServerNotFoundException in case the {@link AUserInAServer} was not found by the ID + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} was not found by the ID + */ @Transactional - public void sendModMailFailure(String template, AUserInAServer aUserInAServer, Long modMailTreadId, MessageChannel channel, Throwable throwable) { + public void sendModMailFailure(String template, Long userInServerId, Long modMailTreadId, MessageChannel channel, Throwable throwable) { Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailTreadId); + AUserInAServer aUserInAServer = userInServerManagementService.loadUser(userInServerId).orElseThrow(() -> new UserInServerNotFoundException(userInServerId)); if(modMailThreadOpt.isPresent()) { ModMailThread modMailThread = modMailThreadOpt.get(); try { @@ -363,10 +452,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } @Override - public synchronized void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser) { + public void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser) { AFeatureMode aFeatureMode = featureModeService.getFeatureMode(ModMailFeatures.MOD_MAIL, modMailThread.getServer()); boolean loggingMode = aFeatureMode.getMode().equalsIgnoreCase(ModMailMode.LOGGING.getKey()); - closeModMailThread(modMailThread, feedBack, note, notifyUser, loggingMode); + closeModMailThread(modMailThread, feedBack, note, notifyUser, loggingMode); } @Override @@ -404,7 +493,19 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * This method takes the actively loaded futures, calls the method responsible for logging the messages, and calls the method + * after the logging has been done. + * @param feedBack The {@link MessageChannel} in which possible feedback about exceptions is sent to + * @param note The note which was provided when closing the {@link ModMailThread} + * @param notifyUser Whether or not to notify the user + * @param modMailThreadId The ID of the {@link ModMailThread} which is being closed + * @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions + * @param messages The list of loaded {@link Message} to log + * @param innerModMailThread An instance of {@link ModMailThread} which is getting closed + */ private void logMessagesToModMailLog(MessageChannel feedBack, String note, Boolean notifyUser, Long modMailThreadId, List undoActions, List> messages, ModMailThread innerModMailThread) { + Long userInServerId = innerModMailThread.getUser().getUserInServerId(); try { CompletableFutureList list = self.logModMailThread(modMailThreadId, messages, note); list.getMainFuture().thenRun(() -> { @@ -422,19 +523,28 @@ public class ModMailThreadServiceBean implements ModMailThreadService { self.afterSuccessfulLog(modMailThreadId, feedBack, notifyUser, undoActions); }); list.getMainFuture().exceptionally(innerThrowable -> { - sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, innerModMailThread.getUser(), modMailThreadId, feedBack, innerThrowable); + sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, userInServerId, modMailThreadId, feedBack, innerThrowable); log.error("Failed to log messages for mod mail thread {}.", modMailThreadId, innerThrowable); return null; }); } catch (PostTargetNotFoundException po) { log.error("Failed to log mod mail messages", po); - sendModMailFailure("modmail_exception_post_target_not_defined", innerModMailThread.getUser(), modMailThreadId, feedBack, po); + sendModMailFailure("modmail_exception_post_target_not_defined", userInServerId, modMailThreadId, feedBack, po); } catch (Exception e) { log.error("Failed to log mod mail messages", e); - sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, innerModMailThread.getUser(), modMailThreadId, feedBack, e); + sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, userInServerId, modMailThreadId, feedBack, e); } } + /** + * This message is executed after the thread has been logged and notifies the user about the closed {@link ModMailThread} + * which a configurable closing text. This method then calls the method to delete the channel. + * @param modMailThreadId The ID of the {@link ModMailThread} which is being closed. + * @param feedBack The {@link MessageChannel} in which exceptions should be sent to + * @param notifyUser Whether or not the user should be notified + * @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID + */ @Transactional public void afterSuccessfulLog(Long modMailThreadId, MessageChannel feedBack, Boolean notifyUser, List undoActions) { log.trace("Mod mail logging for thread {} has completed. Starting post logging activities.", modMailThreadId); @@ -463,7 +573,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService { }); } catch (Exception e) { log.error("Failed to render closing user message", e); - sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, modMailThread.getUser(), modMailThreadId, feedBack, e); + Long userInServerId = modMailThread.getUser().getUserInServerId(); + sendModMailFailure(MODMAIL_EXCEPTION_GENERIC_TEMPLATE, userInServerId, modMailThreadId, feedBack, e); } }, throwable -> { log.error("Failed to load private channel with user {}", user.getIdLong(), throwable); @@ -474,6 +585,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * Deletes the actual {@link MessageChannel} in which the {@link ModMailThread} happened. This method then calls the + * method to update the stats in the database + * @param modMailThreadId The ID of the {@link ModMailThread} to delete the {@link MessageChannel} from + * @param feedBack The {@link MessageChannel} in which exceptions should be sent to + * @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID + */ @Transactional public void deleteChannelAndClose(Long modMailThreadId, MessageChannel feedBack, List undoActions) { Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); @@ -495,7 +614,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } catch (InsufficientPermissionException ex) { log.error(failureMessage, modMailThreadId, ex); undoActionService.performActions(undoActions); - sendModMailFailure("modmail_exception_cannot_delete_channel", modMailThread.getUser(), modMailThreadId, feedBack, ex); + sendModMailFailure("modmail_exception_cannot_delete_channel", modMailThread.getUser().getUserInServerId(), modMailThreadId, feedBack, ex); } catch (Exception ex) { log.error(failureMessage, modMailThreadId, ex); undoActionService.performActions(undoActions); @@ -506,13 +625,25 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } + /** + * Takes the list of {@link CompletableFuture} which are returned from retrieving the {@link Message} to log, + * and creates the models necessary to render the log entries. This message also sends the closing header in the + * log concerning general information about the closed {@link ModMailThread} + * @param modMailThreadId The ID of the {@link ModMailThread} to log the messages of + * @param messages The list of {@link CompletableFuture} which contain the {@link Message} which could be loaded + * @param note The note which was entered when closing the {@link ModMailThread} + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID + * @return An instance of {@link CompletableFutureList}, which contains a main {@link CompletableFuture} which is resolved, + * when all of the smaller {@link CompletableFuture} in it are resolved. We need this construct, because we need to access + * the result values of the individual futures after they are done. + */ @Transactional public CompletableFutureList logModMailThread(Long modMailThreadId, List> messages, String note) { log.info("Logging mod mail thread {}.", modMailThreadId); Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); if(modMailThreadOpt.isPresent()) { ModMailThread modMailThread = modMailThreadOpt.get(); - List loggedMessages = new ArrayList<>(); + List loggedMessages = new ArrayList<>(); messages.forEach(future -> { try { if(!future.isCompletedExceptionally()) { @@ -521,15 +652,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService { ModMailMessage modmailMessage = modMailThread.getMessages() .stream() .filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong())) - .findFirst().get(); - ModMailLoggedMessage modMailLoggedMessage = - ModMailLoggedMessage + .findFirst().orElseThrow(() -> new AbstractoRunTimeException("Could not find desired message in list of messages in thread. This should not happen, as we just retrieved them from the same place.")); + ModMailLoggedMessageModel modMailLoggedMessageModel = + ModMailLoggedMessageModel .builder() .message(loadedMessage) .modMailMessage(modmailMessage) .author(userInServerService.getFullUser(modmailMessage.getAuthor())) .build(); - loggedMessages.add(modMailLoggedMessage); + loggedMessages.add(modMailLoggedMessageModel); } } } catch (InterruptedException | ExecutionException e) { @@ -562,6 +693,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * Sets the {@link ModMailThread} in the database to CLOSED. + * @param modMailThreadId The ID of the {@link ModMailThread} to update the state of + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID + */ @Transactional public void closeModMailThreadInDb(Long modMailThreadId) { Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); @@ -574,7 +710,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } - public List> sendMessagesToPostTarget(ModMailThread modMailThread, List loadedMessages) { + /** + * Renders the retrieved {@link Message} which are in {@link ModMailLoggedMessageModel} into {@link MessageToSend} and + * sends this to the appropriate logging {@link PostTarget} + * @param modMailThread The {@link ModMailThread} to which the loaded messages belong to + * @param loadedMessages The list of {@link ModMailLoggedMessageModel} which can be rendered + * @return A list of {@link CompletableFuture} which represent each of the messages being send to the {@link PostTarget} + */ + public List> sendMessagesToPostTarget(ModMailThread modMailThread, List loadedMessages) { List> messageFutures = new ArrayList<>(); loadedMessages.forEach(message -> { MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_logged_message", message); @@ -584,6 +727,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService { return messageFutures; } + /** + * Sends the reply which was done by a staff member to the private channel with the {@link Member} and calls the + * method for saving the messages and updating the status + * @param modMailThreadId The ID of the {@link ModMailThread} for which the reply was created for + * @param text The text the reply should contain + * @param message The original message which triggered the command to create the reply. This is necessary for attachments + * @param privateChannel The instance of a {@link PrivateChannel} which was opened with the user and is used to send messages + * @param anonymous Whether or not the reply should be anonymous + * @param feedBack The {@link MessageChannel} in which exceptions should be sent to + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID + */ @Transactional public void sendReply(Long modMailThreadId, String text, Message message, PrivateChannel privateChannel, Boolean anonymous, MessageChannel feedBack) { Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); @@ -591,7 +745,6 @@ public class ModMailThreadServiceBean implements ModMailThreadService { ModMailThread modMailThread = modMailThreadOpt.get(); AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember()); Member userInGuild = botService.getMemberInServer(modMailThread.getUser()); - Member moderatorMember = botService.getMemberInServer(moderator); FullUser fullThreadUser = FullUser .builder() .aUserInAServer(modMailThread.getUser()) @@ -607,16 +760,18 @@ public class ModMailThreadServiceBean implements ModMailThreadService { if(anonymous) { modMailModeratorReplyModelBuilder.moderator(botService.getBotInGuild(modMailThread.getServer())); } else { + Member moderatorMember = botService.getMemberInServer(moderator); modMailModeratorReplyModelBuilder.moderator(moderatorMember); } ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build(); MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_staff_message", modMailUserReplyModel); + Long userInServerId = modMailThread.getUser().getUserInServerId(); List> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, privateChannel); CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> self.saveSendMessagesAndUpdateState(modMailThreadId, anonymous, moderator, completableFutures) ).exceptionally(throwable -> { - log.error("Failed to send message to user {}", modMailThread.getUser().getUserReference().getId()); - sendModMailFailure("modmail_exception_cannot_message_user", modMailThread.getUser(), modMailThread.getId(), feedBack, throwable); + log.error("Failed to send message to user in server {}", userInServerId); + sendModMailFailure("modmail_exception_cannot_message_user", userInServerId, modMailThread.getId(), feedBack, throwable); return null; }); } else { @@ -625,6 +780,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } + /** + * Evaluates the promises which were created when sending the messages to the private channel and stores the message IDs + * and updates the state of the {@link ModMailThread}. + * @param modMailThreadId The ID of the {@link ModMailThread} for which the messages were sent for + * @param anonymous Whether or not the messages were send anonymous + * @param moderator The original {@link AUserInAServer} which authored the messages + * @param completableFutures The list of {@link CompletableFuture} which contain the {@link Message} which were sent to the member + * @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID + */ @Transactional public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, AUserInAServer moderator, List> completableFutures) { Optional modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); @@ -649,6 +813,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + /** + * Takes the list of {@link Message} and attaches them to the given {@link ModMailThread} as {@link ModMailMessage} which should possibly + * be logged at a later time + * @param messages The list of {@link Message} to store the IDs of + * @param modMailThread The {@link ModMailThread} which should have the messages attached + * @param author The {@link AUserInAServer} who authored the {@link Message} + * @param anonymous Whether or not the {@link Message} was anonymous + * @param inDmChannel Whether or not the {@link Message} was sent in a private channel + */ public void saveMessageIds(List messages, ModMailThread modMailThread, AUserInAServer author, Boolean anonymous, Boolean inDmChannel) { messages.forEach(message -> modMailMessageManagementService.addMessageToThread(modMailThread, message, author, anonymous, inDmChannel) diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java index 9c3cfab3f..22ac5856e 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementServiceBean.java @@ -47,15 +47,25 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme } @Override - public ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer) { + public ModMailThread getOpenModMailThreadForUser(AUserInAServer userInAServer) { return modMailThreadRepository.findByUserAndStateNot(userInAServer, ModMailThreadState.CLOSED); } @Override - public ModMailThread getOpenModmailThreadForUser(AUser user) { + public boolean hasOpenModMailThreadForUser(AUserInAServer userInAServer) { + return modMailThreadRepository.existsByUserAndStateNot(userInAServer, ModMailThreadState.CLOSED); + } + + @Override + public List getOpenModMailThreadsForUser(AUser user) { return modMailThreadRepository.findByUser_UserReferenceAndStateNot(user, ModMailThreadState.CLOSED); } + @Override + public boolean hasOpenModMailThread(AUser user) { + return modMailThreadRepository.existsByUser_UserReferenceAndStateNot(user, ModMailThreadState.CLOSED); + } + @Override public List getModMailThreadForUser(AUserInAServer aUserInAServer) { return modMailThreadRepository.findByUser(aUserInAServer); @@ -66,6 +76,12 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme return modMailThreadRepository.findTopByUserOrderByClosedDesc(aUserInAServer); } + /** + * The status of the created instance is INITIAL. + * @param userInAServer The {@link AUserInAServer} for which the thread was created for + * @param channel An instance of {@link AChannel} in which the conversation with the member is handled + * @return the created {@link ModMailThread} instance + */ @Override public ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel) { ModMailThread thread = ModMailThread diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/InvalidCategoryException.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/InvalidCategoryException.java index 1f20d7a4a..d33eeea15 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/InvalidCategoryException.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/InvalidCategoryException.java @@ -3,6 +3,10 @@ package dev.sheldan.abstracto.modmail.setup; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.templating.Templatable; +/** + * This exception is thrown when the provided category used for creating mod mail thread is not valid. + * (If it does not exist in the guild) + */ public class InvalidCategoryException extends AbstractoRunTimeException implements Templatable { public InvalidCategoryException() { super(""); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedAction.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedAction.java index 2df5f2ae2..4e9b4d604 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedAction.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedAction.java @@ -7,19 +7,34 @@ import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +/** + * This delayed action is responsible for setting the system configuration of the mod mail category for a given server + */ @Component public class ModMailCategoryDelayedAction implements DelayedAction { - @Autowired private ConfigService configService; + /** + * Sets the config key of MODMAIL_CATEGORY to the given category ID contained in the {@link DelayedActionConfig} + * @param delayedActionConfig An instance of {@link ModMailCategoryDelayedActionConfig} containing the ID + * of the {@link net.dv8tion.jda.api.entities.Category} and the ID of the + * {@link net.dv8tion.jda.api.entities.Guild} to change + */ @Override public void execute(DelayedActionConfig delayedActionConfig) { ModMailCategoryDelayedActionConfig concrete = (ModMailCategoryDelayedActionConfig) delayedActionConfig; - configService.setConfigValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, concrete.getServerId(), concrete.getValue()); + configService.setLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, concrete.getServerId(), concrete.getCategoryId()); } + /** + * This delayed action only reacts to delayed action configurations of typ {@link ModMailCategoryDelayedActionConfig}. + * As this the instance bound to this {@link DelayedAction} + * @param delayedActionConfig An instance of check whether or not this {@link DelayedAction} should be executed for this + * {@link DelayedActionConfig} + * @return Whether or not the passed {@link DelayedActionConfig} is going to be handled by this class. + */ @Override public boolean handles(DelayedActionConfig delayedActionConfig) { return delayedActionConfig instanceof ModMailCategoryDelayedActionConfig; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java index 8a8303849..0557360e3 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java @@ -1,19 +1,24 @@ package dev.sheldan.abstracto.modmail.setup; import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; -import dev.sheldan.abstracto.core.models.database.AConfig; import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryActionModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.api.entities.Category; +/** + * This represents both an instance of a {@link DelayedActionConfig} used to be executed in the + * {@link dev.sheldan.abstracto.core.service.DelayedActionService} and, as all {@link DelayedActionConfig}, as a + * model when all setup steps are presented, and the member executing the setup command needs to confirm the changes. + * This model is responsible to contain the values needed to displayed the mod mail category changes. + */ @Getter @Setter @Builder public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig { private Long serverId; - private AConfig value; + private Long categoryId; private Category category; @Override @@ -26,7 +31,7 @@ public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig { return ModMailCategoryActionModel .builder() .category(this.category) - .categoryId(value.getLongValue()) + .categoryId(categoryId) .build(); } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java index b3810901f..9114ef39a 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java @@ -5,7 +5,6 @@ import dev.sheldan.abstracto.core.interactive.*; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.FeatureValidationResult; import dev.sheldan.abstracto.core.models.database.AChannel; -import dev.sheldan.abstracto.core.models.database.AConfig; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.ConfigService; @@ -61,6 +60,19 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { @Autowired private BotService botService; + /** + * This setup method loads the existing mod mail category (if anything) and populates the model used to render the prompt. + * This method will then render the prompt and wait for the users input, if the provided input was a valid + * category ID in the current server, this method returns the proper result. If anything else is put in (except the input + * triggering a cancellation) this this method will jump back to this step and prompt the user again. + * @param user The {@link AServerChannelUserId} context required in order to execute the step. This is needed + * to check if the returned message is from the same user and to see for which server + * we need to change the mod mail category for + * @param parameter This is a parameter which contains the previous message triggering the setup step. + * This is necessary, because sometimes the {@link Message} executing the setup was also triggering + * the first {@link SetupStep}, so, if we are aware of it, we can ignore it + * @return A {@link CompletableFuture} containing the {@link SetupStepResult}. This might be cancelled or successful. + */ @Override public CompletableFuture execute(AServerChannelUserId user, SetupStepParameter parameter) { String messageTemplateKey = "setup_modmail_category_message"; @@ -78,6 +90,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId()); + // very odd case, if the channel the command was executed in, was not found in the database. if(channel.isPresent()) { Runnable finalAction = getTimeoutRunnable(user.getGuildId(), user.getChannelId()); Consumer configAction = (MessageReceivedEvent event) -> { @@ -85,21 +98,23 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { SetupStepResult result; Message message = event.getMessage(); + // this checks whether or not the user wanted to cancel the setup if(checkForExit(message)) { result = SetupStepResult.fromCancelled(); } else { String messageContent = event.getMessage().getContentRaw(); + // directly parse the long from the message, for *now*, only the category ID is supported Long categoryId = Long.parseLong(messageContent); Guild guild = botService.getGuildByIdNullable(user.getGuildId()); FeatureValidationResult featureValidationResult = FeatureValidationResult.builder().validationResult(true).build(); + // directly validate whether or not the given category ID is a valid value modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId); - if(Boolean.FALSE.equals(featureValidationResult.getValidationResult())) { - AConfig fakeValue = configService.getFakeConfigForValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, user.getGuildId(), messageContent); + if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) { ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig .builder() .serverId(user.getGuildId()) .category(guild.getCategoryById(categoryId)) - .value(fakeValue) + .categoryId(categoryId) .build(); List delayedSteps = Arrays.asList(build); result = SetupStepResult @@ -108,6 +123,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { .delayedActionConfigList(delayedSteps) .build(); } else { + // exceptions this exception is used to effectively fail the setup step throw new InvalidCategoryException(); } @@ -115,7 +131,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { future.complete(result); } catch (Exception e) { - log.error("Failed to handle post target step.", e); + log.error("Failed to handle mod mail category step.", e); future.completeExceptionally(new SetupStepException(e)); } }; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidatorBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidatorBean.java index 5bad7ae9f..a44037dce 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidatorBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidatorBean.java @@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.ConfigService; import dev.sheldan.abstracto.core.service.FeatureValidatorService; -import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryValidationError; +import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryValidationErrorModel; import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; import net.dv8tion.jda.api.entities.Category; import net.dv8tion.jda.api.entities.Guild; @@ -15,6 +15,11 @@ import org.springframework.stereotype.Component; import java.util.Optional; +/** + * This component is used to validate whether or not the mod mail feature has a mod mail category configured, which points to + * a category on the server it is configured for. This and other {@link dev.sheldan.abstracto.core.service.FeatureValidator} + * are used to fully validate the mod mail feature. + */ @Component public class ModMailFeatureValidatorBean implements ModMailFeatureValidator { @@ -27,6 +32,12 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator { @Autowired private FeatureValidatorService featureValidatorService; + /** + * Checks if the mod mail category contains a value and whether or not this valid also points to a {@link Category} + * @param featureConfig The instance of {@link FeatureConfig} of mod mail + * @param server The {@link AServer} to check the config for + * @param validationResult The current {@link FeatureValidationResult} used to accumulate the wrong values + */ @Override public void featureIsSetup(FeatureConfig featureConfig, AServer server, FeatureValidationResult validationResult) { Optional guildById = botService.getGuildById(server.getId()); @@ -40,15 +51,21 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator { } } + /** + * Validates the category and checks if the given ID is a valid category in the given {@link Guild} + * @param validationResult The object in which the result of the validation will be stored + * @param guild The {@link Guild} to check for the category + * @param modMailCategory The configured ID of the category + */ public void validateModMailCategory(FeatureValidationResult validationResult, Guild guild, Long modMailCategory) { Category categoryById = guild.getCategoryById(modMailCategory); if(categoryById == null) { validationResult.setValidationResult(false); - ModMailCategoryValidationError newError = ModMailCategoryValidationError + ModMailCategoryValidationErrorModel newError = ModMailCategoryValidationErrorModel .builder() .currentCategoryId(modMailCategory) .build(); - validationResult.getValidationErrors().add(newError); + validationResult.getValidationErrorModels().add(newError); } } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/modmail/setup/setup_modmail_category_message_en_US.ftl b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/modmail/setup/setup_modmail_category_message_en_US.ftl index 15907ad72..7947f143c 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/modmail/setup/setup_modmail_category_message_en_US.ftl +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/resources/templates/modmail/setup/setup_modmail_category_message_en_US.ftl @@ -1 +1 @@ -<#assign categoryName><#if category?has_content>${category.name}<#else><#include "setup_modmail_category_message_no_category">><#include "setup_modmail_category_message_display"> \ No newline at end of file +<#assign categoryName><#if category?has_content>${category.name}<#else><#include "setup_modmail_category_message_no_category"><#include "setup_modmail_category_message_display"> \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/condition/ModMailContextCondition.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/condition/ModMailContextCondition.java new file mode 100644 index 000000000..737c47546 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/condition/ModMailContextCondition.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.modmail.condition; + +import dev.sheldan.abstracto.core.command.condition.CommandCondition; + +/** + * This condition represents the condition that the command can only be executed while the member + * is within a mod mail channel. + */ +public interface ModMailContextCondition extends CommandCondition { +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java index 98b959b5f..bf5cc69ff 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailFeature.java @@ -14,6 +14,9 @@ import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; +/** + * General instance of {@link FeatureConfig} to establish the mod mail feature + */ @Component public class ModMailFeature implements FeatureConfig { diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java index 16edb8b3d..5c41d7cad 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailMode.java @@ -3,6 +3,10 @@ package dev.sheldan.abstracto.modmail.config; import dev.sheldan.abstracto.core.config.FeatureMode; import lombok.Getter; +/** + * This enum defines the to {@link FeatureMode} mod mail has. + * Either closed mod mail threads are logged, or they are not logged to the respective post target. + */ @Getter public enum ModMailMode implements FeatureMode { LOGGING("log"), NO_LOG("nolog"); diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailPostTargets.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailPostTargets.java index 57fd4d705..76ea31b21 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailPostTargets.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/config/ModMailPostTargets.java @@ -5,7 +5,14 @@ import lombok.Getter; @Getter public enum ModMailPostTargets implements PostTargetEnum { - MOD_MAIL_PING("modmailPing"), MOD_MAIL_LOG("modmailLog"); + /** + * The channel to be used for notifying the users about new mod mail threads + */ + MOD_MAIL_PING("modmailPing"), + /** + * The channel to be used to log the contents of closed mod mail threads + */ + MOD_MAIL_LOG("modmailLog"); private String key; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/AlreadySubscribedException.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/AlreadySubscribedException.java index 6512770bb..e9f609d36 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/AlreadySubscribedException.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/AlreadySubscribedException.java @@ -3,9 +3,12 @@ package dev.sheldan.abstracto.modmail.exception; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.templating.Templatable; +/** + * This exception is thrown then you try to subscribe to a mod mail thread, to which you are already subscribed to + */ public class AlreadySubscribedException extends AbstractoRunTimeException implements Templatable { - public AlreadySubscribedException(String message) { - super(message); + public AlreadySubscribedException() { + super(""); } @Override diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailCategoryIdException.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailCategoryIdException.java new file mode 100644 index 000000000..717a2f499 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailCategoryIdException.java @@ -0,0 +1,36 @@ +package dev.sheldan.abstracto.modmail.exception; + +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.templating.Templatable; +import lombok.Getter; +import lombok.Setter; + +import java.util.HashMap; + +/** + * This exception is thrown when a {@link net.dv8tion.jda.api.entities.Member} tries to set the mod mail category + * via a command, and the new value does not qualify as a valid {@link net.dv8tion.jda.api.entities.Category} + * in the member executes the command in + */ +@Getter +@Setter +public class ModMailCategoryIdException extends AbstractoRunTimeException implements Templatable { + private Long categoryId; + + public ModMailCategoryIdException(Long categoryId) { + super(""); + this.categoryId = categoryId; + } + + @Override + public String getTemplateName() { + return "modmail_category_not_setup"; + } + + @Override + public Object getTemplateModel() { + HashMap params = new HashMap<>(); + params.put("categoryId", this.categoryId); + return params; + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadNotFoundException.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadNotFoundException.java index ad301da18..5ff6fcfa1 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadNotFoundException.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadNotFoundException.java @@ -5,6 +5,10 @@ import dev.sheldan.abstracto.templating.Templatable; import java.util.HashMap; +/** + * This exception is raised, when for some reason the mod mail thread is not found in the database anymore, but the context which is executed stems from a mod mail thread. + * For example if it is attempted to log a thread, without the thread existing in the database. + */ public class ModMailThreadNotFoundException extends AbstractoRunTimeException implements Templatable { private final Long modMailThreadId; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/NotSubscribedException.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/NotSubscribedException.java index 51891bab5..3ab472a25 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/NotSubscribedException.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/NotSubscribedException.java @@ -3,9 +3,12 @@ package dev.sheldan.abstracto.modmail.exception; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.templating.Templatable; +/** + * This exception is thrown when you try to unsubscribe from a mod mail thread, to which you are not subscribed to + */ public class NotSubscribedException extends AbstractoRunTimeException implements Templatable { - public NotSubscribedException(String message) { - super(message); + public NotSubscribedException() { + super(""); } @Override diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java index ad2b031f8..61a9f2924 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailMessage.java @@ -7,6 +7,11 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; import java.time.Instant; +/** + * A table used to store which messages need to be retrieved when logging a mod mail thread. + * These messages are only the messages passed between the member and the staff handling the thread and include all messages by the user + * and only the messages send via command (reply/anonreply) + */ @Builder @Entity @NoArgsConstructor @@ -18,19 +23,34 @@ import java.time.Instant; @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class ModMailMessage { + /** + * The globally unique message ID which was send in the mod mail thread, either by a user of by the staff handling the thread + */ @Id private Long messageId; + /** + * The {@link AUserInAServer} which authored this message + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_message_author", nullable = false) private AUserInAServer author; + /** + * The {@link ModMailThread} in whose context this message was sent and this message is related to + */ @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "threadReference", nullable = false) private ModMailThread threadReference; + /** + * Whether or not this message was from the user or a staff member, for convenience + */ private Boolean dmChannel; + /** + * Staff only: Whether or not this message meant to be sent anonymous + */ private Boolean anonymous; @Column(name = "created") diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailRole.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailRole.java index 1d957c939..576e8bb9d 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailRole.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailRole.java @@ -8,6 +8,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; import java.time.Instant; +/** + * The table responsible to define which roles are the roles responsible for handling the mod mail threads. + * These will get notified via a ping, when a new mod mail thread is created. + */ @Builder @Entity @NoArgsConstructor @@ -19,14 +23,23 @@ import java.time.Instant; @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class ModMailRole { + /** + * Unique ID of the mod mail role + */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long modMailRoleId; + /** + * Which {@link AServer} this role is associated with, for convenience + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_role_server", nullable = false) private AServer server; + /** + * The actual {@link ARole} which this mod mail role references + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_role", nullable = false) private ARole role; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java index 4d39b2c7b..51670a15b 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThread.java @@ -9,6 +9,10 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; +/** + * The table responsible to associate certain channels to be mod mail thread channels. It also stores the current state of the thread (answered, initial) + * ,who the associated user is, who has subscribed to the thread and the messages posted in the thread. + */ @Builder @Entity @NoArgsConstructor @@ -24,14 +28,23 @@ public class ModMailThread { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + /** + * The member who opened the thread or who got contacted + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_user", nullable = false) private AUserInAServer user; + /** + * The text channel in which this thread is dealt with + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_thread_channel", nullable = false) private AChannel channel; + /** + * The server on which this mod mail thread is, for convenience + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_thread_server", nullable = false) private AServer server; @@ -55,6 +68,10 @@ public class ModMailThread { @Column private Instant closed; + /** + * The messages which were officially posted in the context of the mod mail thread. Either via command (from the + * staff side of view) or by messaging the bot (from the member view) + */ @OneToMany( fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, @@ -64,6 +81,9 @@ public class ModMailThread { @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) private List messages = new ArrayList<>(); + /** + * The staff members who subscribed to be notified in case there is a new message in a mod mail thread. + */ @OneToMany( fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, @@ -73,6 +93,9 @@ public class ModMailThread { @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) private List subscribers = new ArrayList<>(); + /** + * The current state of the mod mail thread. Whether or not the last post was by staff or user. + */ @Enumerated(EnumType.STRING) @Column private ModMailThreadState state; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java index 84ed63a7a..d871c03ee 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadState.java @@ -1,5 +1,20 @@ package dev.sheldan.abstracto.modmail.models.database; public enum ModMailThreadState { - INITIAL, USER_REPLIED, MOD_REPLIED, CLOSED, CLOSING; + /** + * User opened the mod mail thread or staff contacted member, but did not post a message yet + */ + INITIAL, + /** + * User replied to mod mail thread + */ + USER_REPLIED, + /** + * Staff member responded to the mod mail thread + */ + MOD_REPLIED, + /** + * The thread was closed by a staff member and the channel was removed + */ + CLOSED, CLOSING; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadSubscriber.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadSubscriber.java index 4002d7f34..e280c3916 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadSubscriber.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/database/ModMailThreadSubscriber.java @@ -7,6 +7,10 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; import java.time.Instant; +/** + * This able contains the staff users which subscribed to a certain mod mail thread and will get notified of new messages + * in a mod mail thread + */ @Builder @Entity @NoArgsConstructor @@ -22,10 +26,16 @@ public class ModMailThreadSubscriber { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long subscriberId; + /** + * The staff member which is subscribed + */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "modmail_message_subscriber", nullable = false) private AUserInAServer subscriber; + /** + * The thread for which the member is subscribed to + */ @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "modMailThread", nullable = false) private ModMailThread threadReference; diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java index 278f68791..fed76de7a 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/dto/ServerChoice.java @@ -5,10 +5,20 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; +/** + * Used when the user shares multiple servers with the bot and needs to determine for which server the user + * wants to open a mod mail thread, this is done by reacting to the prompt with the proper emote. + */ @Getter @Setter @Builder public class ServerChoice { + /** + * The possible guild to open a mod mail thread for + */ private FullGuild guild; + /** + * The unicode emote used in the prompt to identify this choice + */ private String reactionEmote; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryActionModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryActionModel.java index bdba6b9a9..4b6eb8099 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryActionModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryActionModel.java @@ -5,6 +5,11 @@ import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.api.entities.Category; +/** + * This model is used when confirming the setup up the mod mail configuration for the category in which the channels should be created + * This model contains the actual JDA category object where the channels will be created in, and the id of said + * category + */ @Getter @Setter @Builder diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryValidationError.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryValidationErrorModel.java similarity index 56% rename from abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryValidationError.java rename to abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryValidationErrorModel.java index 6bb6f3687..a8b3e6a4f 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryValidationError.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailCategoryValidationErrorModel.java @@ -1,16 +1,21 @@ package dev.sheldan.abstracto.modmail.models.template; -import dev.sheldan.abstracto.core.models.ValidationError; +import dev.sheldan.abstracto.core.models.ValidationErrorModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; import java.util.HashMap; +/** + * This model is used when the category for creating mod mail threads is not properly setup + * and when the feature is enabled via command. This will be rendered as a simple additional line of validation errors + * after the command finished + */ @Getter @Setter @Builder -public class ModMailCategoryValidationError implements ValidationError { +public class ModMailCategoryValidationErrorModel implements ValidationErrorModel { private Long currentCategoryId; @Override diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailClosingHeaderModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailClosingHeaderModel.java index f6a21bd2e..cdafc1a73 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailClosingHeaderModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailClosingHeaderModel.java @@ -7,13 +7,27 @@ import lombok.Setter; import java.time.Duration; +/** + * This model is used when rendering the message before logging the messages in a closed {@link ModMailThread} and contains + * general information about why the thread was closed and the thread itself. + */ @Getter @Setter @Builder public class ModMailClosingHeaderModel { + /** + * The note used to close the thread, might be the default value + */ private String note; + /** + * The {@link ModMailThread} which was closed + */ private ModMailThread closedThread; + /** + * The duration between the creation and closed date of a {@link ModMailThread} + * @return + */ public Duration getDuration() { return Duration.between(closedThread.getCreated(), closedThread.getClosed()); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailExceptionModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailExceptionModel.java index f6c47c799..585a49efb 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailExceptionModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailExceptionModel.java @@ -6,11 +6,25 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; +/** + * This model is used to render any exception happening when executing a command within a {@link ModMailThread} + * and this command failing in any capacity. This model is used to render multiple templates (for differnet kinds of + * exceptions), all of which might use the information or not. + */ @Getter @Setter @Builder public class ModMailExceptionModel { + /** + * The {@link ModMailThread} in which the exception occurred + */ private ModMailThread modMailThread; + /** + * A user associated with this exception, depends on the exact behaviour of the exception. + */ private FullUser user; + /** + * The exception which was thrown + */ private Throwable throwable; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailLoggedMessage.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailLoggedMessage.java deleted file mode 100644 index ba11f736e..000000000 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailLoggedMessage.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.sheldan.abstracto.modmail.models.template; - -import dev.sheldan.abstracto.core.models.FullUser; -import dev.sheldan.abstracto.modmail.models.database.ModMailMessage; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import net.dv8tion.jda.api.entities.Message; - -@Getter -@Setter -@Builder -public class ModMailLoggedMessage { - private Message message; - private ModMailMessage modMailMessage; - private FullUser author; - - -} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailLoggedMessageModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailLoggedMessageModel.java new file mode 100644 index 000000000..b893d4b90 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailLoggedMessageModel.java @@ -0,0 +1,32 @@ +package dev.sheldan.abstracto.modmail.models.template; + +import dev.sheldan.abstracto.core.models.FullUser; +import dev.sheldan.abstracto.modmail.models.database.ModMailMessage; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.Message; + +/** + * This model is used to render a message from a mod mail thread when closing the thread and logging the thread to the logging post target + */ +@Getter +@Setter +@Builder +public class ModMailLoggedMessageModel { + /** + * The {@link Message} instance which was posted + */ + private Message message; + /** + * The reference to the {@link ModMailMessage} stored in the database + */ + private ModMailMessage modMailMessage; + + /** + * A reference to the {@link FullUser} which is the author. The member part is null, if the member left the guild. + */ + private FullUser author; + + +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java index 6e67445b0..eabe050d3 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailModeratorReplyModel.java @@ -8,14 +8,36 @@ import lombok.Setter; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; +/** + * Model used to render the response by staff members to the DM channel with the user + */ @Getter @Setter @Builder public class ModMailModeratorReplyModel { + /** + * A {@link FullUser} reference representing the user the thread is about. The member attribute is null, if the user left the guild + */ private FullUser threadUser; + /** + * The staff {@link Member} which replied to the thread, be it anonymously or normal. + */ private Member moderator; + /** + * The text which was used to reply. This is necessary, because the reply is triggered via a command, so + * we would need re-parse the {@link Message} in order to find the value to display + */ private String text; + /** + * The {@link Message} which contained the command to reply to the user. This is needed for attachments. + */ private Message postedMessage; + /** + * Whether or not the reply should be shown anonymous + */ private Boolean anonymous; + /** + * The {@link ModMailThread} to reply to + */ private ModMailThread modMailThread; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailNotificationModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailNotificationModel.java index dbd18da78..73cbdd6dc 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailNotificationModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailNotificationModel.java @@ -10,11 +10,24 @@ import lombok.experimental.SuperBuilder; import java.util.List; +/** + * The model used to notify staff members about a newly created mod mail thread. This model contains a dynamic amount of roles which are pinged + * upon creation of a mod mail thread + */ @Getter @Setter @SuperBuilder public class ModMailNotificationModel extends ServerContext { + /** + * The created {@link ModMailThread} which was just created + */ private ModMailThread modMailThread; + /** + * The {@link FullUser} for which this thread is about + */ private FullUser threadUser; + /** + * A list of roles which will be notified upon creation of the mod mail thread. + */ private List roles; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java index 9147b790b..88ff17ed1 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailServerChooserModel.java @@ -7,9 +7,17 @@ import lombok.Setter; import java.util.List; +/** + * Container model used to define all the possible {@link ServerChoice} which are presented when the initial message is + * sent to the bot + */ @Getter @Setter @Builder public class ModMailServerChooserModel { + /** + * A list of {@link ServerChoice} which contains the common servers of the user and the bot, but only those + * in which the mod mail feature is currently enabled + */ private List commonGuilds; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreadExistsModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreadExistsModel.java index 1fe2230c2..f621a5353 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreadExistsModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreadExistsModel.java @@ -7,6 +7,10 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.SuperBuilder; +/** + * This model is used to notify a staff member that there is already a mod mail thread open for the user + * and provide a link to the channel associated with the user. + */ @Getter @Setter @SuperBuilder diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreaderHeader.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreaderHeader.java index 7c686028c..57e986c8a 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreaderHeader.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailThreaderHeader.java @@ -6,11 +6,25 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; +/** + * This is the model used when a new mod mail thread is opened and a message containing some information about the user + * is displayed for the user handling the mod mail thread. + */ @Getter @Setter @Builder public class ModMailThreaderHeader { + /** + * A {@link FullUser} instance to retrieve information from + */ private FullUser threadUser; + /** + * The latest {@link ModMailThread}, before the current opened one. This is null if there is no closed mod mail thread + * for the user + */ private ModMailThread latestModMailThread; + /** + * The amount of previous mod mail thread the user has. + */ private Long pastModMailThreadCount; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java index 2a25c54a9..673eb247d 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/ModMailUserReplyModel.java @@ -9,12 +9,28 @@ import net.dv8tion.jda.api.entities.Message; import java.util.List; +/** + * Model used to render the response by the user to the mod mail thread channel. + */ @Getter @Setter @Builder public class ModMailUserReplyModel { + /** + * The {@link FullUser} from which the message is and whose mod mail thread it is + */ private FullUser threadUser; + /** + * The {@link Message} which was posted, which contains all the possible information + */ private Message postedMessage; + /** + * The {@link ModMailThread} for which the {@link Message} was a reply for + */ private ModMailThread modMailThread; + /** + * List of {@link FullUser} which are registered as subscribers for a particular mod mail thread and will be pinged + * when the user sends a new message + */ private List subscribers; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/SetupModMailCategoryMessageModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/SetupModMailCategoryMessageModel.java index e5d02f326..6d6f2d9b9 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/SetupModMailCategoryMessageModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/models/template/SetupModMailCategoryMessageModel.java @@ -5,6 +5,10 @@ import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.api.entities.Category; +/** + * Model which is used when setting up the mod mail feature. The category property will be used when there is already a category + * defined to be used for mod mail threads and it is still a valid category. + */ @Getter @Setter @Builder diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageService.java index 532b77278..b43426a23 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageService.java @@ -6,6 +6,14 @@ import net.dv8tion.jda.api.entities.Message; import java.util.List; import java.util.concurrent.CompletableFuture; +/** + * Service to handle the messages of a {@link dev.sheldan.abstracto.modmail.models.database.ModMailThread} + */ public interface ModMailMessageService { + /** + * Loads the given mod mail messages in the form of {@link Message} from Discord and returns the created promises, some of which might fail, if the message was already deleted + * @param modMailMessages The list of {@link ModMailMessage} to load + * @return A list of futures which contain the individual results of actively loading the {@link Message} + */ List> loadModMailMessages(List modMailMessages); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleService.java index dc613b3a1..f9fe6f7d5 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailRoleService.java @@ -1,9 +1,24 @@ package dev.sheldan.abstracto.modmail.service; import dev.sheldan.abstracto.core.models.database.ARole; -import dev.sheldan.abstracto.core.models.database.AServer; +/** + * Service for managing {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole}, this includes crating and removing them + */ public interface ModMailRoleService { - void addRoleToModMailRoles(ARole role, AServer server); - void removeRoleFromModMailRoles(ARole role, AServer server); + /** + * Adds a given {@link ARole} to the list of {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} of the given server. + * This method also allows the given role to execute the mod mail related commands. (Which causes the commands to automatically be restricted) + * @param role The {@link ARole} to change to a {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} + * + */ + void addRoleToModMailRoles(ARole role); + + /** + * Removes the given {@link ARole} from the list of {@link dev.sheldan.abstracto.modmail.models.database.ModMailRole} of the server. + * This automatically dis-allows the mod mail related commands for the given role. + * @param role The {@link ARole} to remove from the list of mod mail roles + * + */ + void removeRoleFromModMailRoles(ARole role); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionService.java index ab0845fab..15593dcef 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailSubscriptionService.java @@ -3,7 +3,23 @@ package dev.sheldan.abstracto.modmail.service; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +/** + * Service used to add subscriptions to threads and remove them as well. + */ public interface ModMailSubscriptionService { + /** + * Subscribes the {@link AUserInAServer} to the given {@link ModMailThread}. + * @param aUserInAServer The {@link AUserInAServer} to subscribe + * @param modMailThread The {@link ModMailThread} to subscribe the user to + * @throws dev.sheldan.abstracto.modmail.exception.AlreadySubscribedException in case the user is already subscribed + */ void subscribeToThread(AUserInAServer aUserInAServer, ModMailThread modMailThread); + + /** + * Un-subscribes the {@link AUserInAServer} from the given {@link ModMailThread} + * @param aUserInAServer The {@link AUserInAServer} to un-subscribe + * @param modMailThread The {@link ModMailThread} to un-subscribe the user from + * @throws dev.sheldan.abstracto.modmail.exception.NotSubscribedException in case the user is not subscribed to the thread + */ void unsubscribeFromThread(AUserInAServer aUserInAServer, ModMailThread modMailThread); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java index 925d5baf0..a23ac2911 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadService.java @@ -6,17 +6,85 @@ import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.modmail.models.database.ModMailThread; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageChannel; +/** + * Service used to handle the mod mail life cycle, including creation, updating, sending/receiving messages and logging the mod mail thread + */ public interface ModMailThreadService { + /** + * Creates a new mod mail thread for the given user. including: the {@link net.dv8tion.jda.api.entities.TextChannel} + * in the appropriate {@link net.dv8tion.jda.api.entities.Category} and calls the methods responsible for storing + * the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread} + * @param userInAServer The {@link AUserInAServer} to create the mod mail thread for + * @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command + * @param feedBackChannel The {@link MessageChannel} in which feedback about exceptions should be posted to + * @param userInitiated Whether or not the mod mail thread was initiated by a user + */ void createModMailThreadForUser(FullUser userInAServer, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated); - boolean hasOpenThread(AUserInAServer aUserInAServer); - boolean hasOpenThread(AUser user); - void setModMailCategoryTo(AServer server, Long categoryId); + + /** + * Changes the configuration value of the category used to create mod mail threads to the given ID. + * @param guild The {@link Guild} to change the category value for + * @param categoryId The ID of the category to use + */ + void setModMailCategoryTo(Guild guild, Long categoryId); + + /** + * Creates a prompt message, where the user initiating the mod mail thread has to chose for which server + * the user wants to create a mod mail thread for. The message will be displayed in the same channel + * as the original message was displayed in. Only servers in which the mod mail feature is enabled, will be counted + * and if there are no servers available an error message will be displayed. + * @param user The {@link AUser} who wants to open a mod mail thread + * @param initialMessage The {@link Message} which was send by the user to open a mod mail thread with. + */ void createModMailPrompt(AUser user, Message initialMessage); + + /** + * Forwards the given {@link Message} send by the user to the appropriate text channel of the given {@link ModMailThread}. + * In case there was no channel found, this will cause a message to be shown to the user and the existing mod mail thread will be closed. + * This is the case, if the mod mail thread was still open in the database, but no text channel was found anymore. + * @param modMailThread The {@link ModMailThread} on which the user answered + * @param message The {@link Message} object which was sent by the user to answer with + */ void relayMessageToModMailThread(ModMailThread modMailThread, Message message); + + /** + * Forwards a message send by a moderator to the direct message channel opened with the user. If the message is + * marked as anonymous, the bot will take the place of the author, in other case the author is shown in the embed. + * @param modMailThread The {@link ModMailThread} to which the reply was sent to + * @param text The parsed text of the reply + * @param message The pure {@link Message} containing the command which caused the reply + * @param anonymous Whether or nor the message should be send anonymous + * @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to + */ void relayMessageToDm(ModMailThread modMailThread, String text, Message message, boolean anonymous, MessageChannel feedBack); + + /** + * Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread, + * and depending on the {@link dev.sheldan.abstracto.core.config.FeatureMode} of mod mail logs the content of the thread into the appropriate + * post target. This also takes an optional note, which will be displayed in the first message of the logging. This method changes the state of the + * {@link ModMailThread} to CLOSED and notifies the user about closing. + * @param modMailThread The {@link ModMailThread} which is being closed. + * @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to + * @param note The text of the note used for the header message of the logged mod mail thread. + * @param notifyUser Whether or not the user should be notified + */ void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser); + + /** + * Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread, + * and logs the content of the thread into the appropriate post target. This also takes an optional note, which will + * be displayed in the first message of the logging. This method changes the state of the {@link ModMailThread} to + * CLOSED and notifies the user about closing. + * @param modMailThread The {@link ModMailThread} which is being closed. + * @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to + * @param note The text of the note used for the header message of the logged mod mail thread, this is only required when actually + * logging the mod mail thread + * @param notifyUser Whether or not the user should be notified + * @param logThread Whether or not the thread should be logged to the appropriate post target + */ void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, boolean notifyUser, boolean logThread); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java index 6bf1a3724..c2c6bc9bb 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailMessageManagementService.java @@ -7,7 +7,25 @@ import net.dv8tion.jda.api.entities.Message; import java.util.List; +/** + * Management service to handle the creation and retrieval of {@link ModMailMessage} instances from the database + */ public interface ModMailMessageManagementService { + /** + * Creates an instance of {@link ModMailMessage}, attaches it to the given {@link ModMailThread} and returns the created instance + * @param modMailThread The {@link ModMailThread} the message should be attached to + * @param message The {@link Message} which should be attached to the {@link ModMailThread} + * @param author The {@link AUserInAServer} who authored the {@link Message} originally + * @param anonymous Whether or not the message was sent anonymous (only possible by staff members) + * @param dmChannel Whether or not the message originated from the user, and therefore in an direct message channel + * @return + */ ModMailMessage addMessageToThread(ModMailThread modMailThread, Message message, AUserInAServer author, Boolean anonymous, Boolean dmChannel); + + /** + * Retrieves all messages which were sent in a {@link ModMailThread} + * @param modMailThread The {@link ModMailThread} to retrieve the messages for + * @return A list of {@link ModMailMessage} which were sent in the given thread + */ List getMessagesOfThread(ModMailThread modMailThread); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailRoleManagementService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailRoleManagementService.java index f1ace3033..df9334162 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailRoleManagementService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailRoleManagementService.java @@ -6,9 +6,40 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailRole; import java.util.List; +/** + * Management service bean responsible to create, remove, retrieve and check mod mail roles which are used to determine + * which roles are getting pinged when a new mod mail thread is created. + */ public interface ModMailRoleManagementService { + /** + * Adds the given {@link ARole} to the mod mail roles of the {@link AServer}. This method does not check if the role + * is already present. + * @param role The {@link ARole} to add to the mod mail roles + * @param server The {@link AServer} to which the given {@link ARole} should be added to the mod mail roles + */ void addRoleToModMailRoles(ARole role, AServer server); + + /** + * Removes the given {@link ARole} from the mod mail roles of the given {@link AServer}. Does nothing if the + * role is not used as a mod mail role on the server + * @param role The {@link ARole} to remove from the mod mail roles + * @param server The {@link AServer} from which the role should be removed from the mod mail roles + */ void removeRoleFromModMailRoles(ARole role, AServer server); + + /** + * Retrieves all roles which should be pinged when a new mod mail thread is created by a user and returns the list + * of {@link ModMailRole} for the given {@link AServer}. + * @param server The {@link AServer} for which to retrieve the mod mail roles for + * @return The list of found {@link ModMailRole} for the given {@link AServer} + */ List getRolesForServer(AServer server); + + /** + * Checks whether or not the given {@link ARole} has already been assigned as a {@link ModMailRole} in the given {@link AServer} + * @param role The {@link ARole} to check for + * @param server The {@link AServer} to check in + * @return Whether or not the given {@link ARole} is used as a {@link ModMailRole} in the given {@link AServer} + */ boolean isRoleAlreadyAssigned(ARole role, AServer server); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailSubscriberManagementService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailSubscriberManagementService.java index c4e970809..09f35c6aa 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailSubscriberManagementService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailSubscriberManagementService.java @@ -6,9 +6,38 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThreadSubscriber; import java.util.List; +/** + * Management service used to retrieve/create/remove instances of {@link ModMailThreadSubscriber} + */ public interface ModMailSubscriberManagementService { + /** + * Retrieves all the {@link ModMailThreadSubscriber} of the given {@link ModMailThread} + * @param modMailThread The {@link ModMailThread} to retrieve the subscribers of + * @return The list of {@link ModMailThreadSubscriber} which are currently configured for the given {@link ModMailThread} + */ List getSubscribersForThread(ModMailThread modMailThread); + + /** + * This method checks if a {@link AUserInAServer} is stored as a {@link ModMailThreadSubscriber} for the given + * {@link ModMailThread} + * @param aUserInAServer The {@link AUserInAServer} to check for + * @param modMailThread The {@link ModMailThread} to check in + * @return Whether or not the given {@link AUserInAServer} is a subscriber of the mod mail thread + */ boolean isSubscribedToThread(AUserInAServer aUserInAServer, ModMailThread modMailThread); + + /** + * Creates a {@link ModMailThreadSubscriber} with the given parameters and returns the created instance + * @param aUserInAServer The {@link AUserInAServer} to subscribe to a thread + * @param modMailThread The {@link ModMailThread} to which the user should be subscribed to + * @return The created instance of {@link ModMailThreadSubscriber} + */ ModMailThreadSubscriber createSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread); + + /** + * Removes the instance of the {@link ModMailThreadSubscriber}, effectively un-subscribing the user from the thread + * @param aUserInAServer The {@link AUserInAServer} to un-subscribe + * @param modMailThread The {@link ModMailThread} to unsubscribe from + */ void removeSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java index f0572a854..777d1cf1d 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/service/management/ModMailThreadManagementService.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.modmail.service.management; +import dev.sheldan.abstracto.core.exception.ChannelNotFoundException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; @@ -9,16 +10,100 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState; import java.util.List; import java.util.Optional; +/** + * Management service to create/retrieve/modify instances of {@link ModMailThread} + */ + public interface ModMailThreadManagementService { + + /** + * Retrieves a {@link ModMailThread} found in the {@link net.dv8tion.jda.api.entities.MessageChannel} given by the ID of the channel + * @param channelId The id of the channel to retrieve the {@link ModMailThread} for + * @throws ChannelNotFoundException if an appropriate {@link AChannel} was not found + * @return The instance of {@link ModMailThread} if it exists, null if none was found + */ ModMailThread getByChannelId(Long channelId); + + /** + * Retrieves the {@link ModMailThread} by the given ID in an optional, if it exists, and an {@literal Optional#empty()} otherwise + * @param modMailThreadId The ID of the mod mail to search for + * @return An {@link Optional} containing the mod mail thread or empty + */ Optional getById(Long modMailThreadId); + + /** + * Retrieves a {@link ModMailThread} found in the {@link net.dv8tion.jda.api.entities.MessageChannel} given by the + * {@link AChannel} object + * @param channel The {@link AChannel} object to search a mod mail thread for + * @return The found mod mail thread, or null if none was found + */ ModMailThread getByChannel(AChannel channel); + + /** + * Searches for mod mail threads with the appropriate staten which concern the given {@link AUserInAServer} + * @param userInAServer The {@link AUserInAServer} to search mod mail threads for + * @param state The {@link ModMailThreadState} to be used as a criteria + * @return A list of {@link ModMailThread} which were found by the given criteria + */ List getThreadByUserAndState(AUserInAServer userInAServer, ModMailThreadState state); - ModMailThread getOpenModmailThreadForUser(AUserInAServer userInAServer); - ModMailThread getOpenModmailThreadForUser(AUser user); + + /** + * Retrieves the *only* open mod mail thread for the given {@link AUserInAServer}, and null if none is in the state open + * @param userInAServer The {@link AUserInAServer} to search an open {@link ModMailThread} for + * @return The found open {@link ModMailThread}, or null if none is found + */ + ModMailThread getOpenModMailThreadForUser(AUserInAServer userInAServer); + + /** + * Returns whether or not the {@link AUserInAServer} has a {@link ModMailThread} in a state which is not CLOSED + * @param userInAServer The {@link AUserInAServer} to check for + * @return Boolean whether or not the {@link AUserInAServer} has an open thread + */ + boolean hasOpenModMailThreadForUser(AUserInAServer userInAServer); + + /** + * Retrieves all the open {@link ModMailThread} for the {@link AUser}, which means over all the known guilds + * @param user The {@link AUser} for which the open mod mail threads should be retrieved + * @return A list of {@link ModMailThread} which contains all the current threads which are not CLOSED + */ + List getOpenModMailThreadsForUser(AUser user); + + /** + * Returns whether or not the {@link AUser} has a {@link ModMailThread} in a state which is not CLOSED + * @param user The {@link AUser} to check for open mod mail treads + * @return Boolean whether or not the {@link AUser} has an open thread + */ + boolean hasOpenModMailThread(AUser user); + + /** + * Retrieves all the open {@link ModMailThread} for the {@link AUserInAServer}, which means only in one guild, this + * should be at most one + * @param aUserInAServer The {@link AUserInAServer} to retrieve the mod mail threads for + * @return A list of {@link ModMailThread} which contains all the current mod mail threads for the member, should be at most one + */ List getModMailThreadForUser(AUserInAServer aUserInAServer); + + /** + * Retrieves the *latest* {@link ModMailThread} of the {@link AUserInAServer}, which means, the latest thread which is in the state + * CLOSED, null other wise. + * @param aUserInAServer The {@link AUserInAServer} to retrieve the latest thread for + * @return If a thread in state CLOSED exists, the latest one, null other wise + */ ModMailThread getLatestModMailThread(AUserInAServer aUserInAServer); + + /** + * Creates an instance of {@link ModMailThread} with the appropriate parameters and returns the created instance. + * @param userInAServer The {@link AUserInAServer} for which the thread was created for + * @param channel An instance of {@link AChannel} in which the conversation with the member is handled + * @return The created instance of {@link ModMailThread} + */ ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel); + + /** + * Updates the {@link ModMailThread} with the new state and saves the instance. + * @param modMailThread The {@link ModMailThread} to change the state for + * @param newState The new {@link ModMailThreadState} to change the thread to + */ void setModMailThreadState(ModMailThread modMailThread, ModMailThreadState newState); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetup.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetup.java index 55cea0c2c..1c5608309 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetup.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetup.java @@ -2,5 +2,8 @@ package dev.sheldan.abstracto.modmail.setup; import dev.sheldan.abstracto.core.interactive.SetupStep; +/** + * Setup step responsible to setup the required {@link java.util.Locale.Category} for mod mail + */ public interface ModMailCategorySetup extends SetupStep { } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidator.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidator.java index b00605e2c..b75854458 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidator.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/validator/ModMailFeatureValidator.java @@ -4,6 +4,15 @@ import dev.sheldan.abstracto.core.models.FeatureValidationResult; import dev.sheldan.abstracto.core.service.FeatureValidator; import net.dv8tion.jda.api.entities.Guild; +/** + * Validator service which validates, whether or not the configured mod mail category is actually a valid category. + */ public interface ModMailFeatureValidator extends FeatureValidator { + /** + * Validates the category and checks if the given ID is a valid category in the given {@link Guild} + * @param validationResult The object in which the result of the validation will be stored + * @param guild The {@link Guild} to check for the category + * @param modMailCategory The configured ID of the category + */ void validateModMailCategory(FeatureValidationResult validationResult, Guild guild, Long modMailCategory); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureValidationServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureValidationServiceBean.java index 032fd01d8..6ea81f6e3 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureValidationServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureValidationServiceBean.java @@ -1,10 +1,10 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.config.PostTargetEnum; -import dev.sheldan.abstracto.core.models.EmoteMissingValidationError; +import dev.sheldan.abstracto.core.models.EmoteMissingValidationErrorModel; import dev.sheldan.abstracto.core.models.FeatureValidationResult; -import dev.sheldan.abstracto.core.models.PostTargetValidationError; -import dev.sheldan.abstracto.core.models.SystemConfigValidationError; +import dev.sheldan.abstracto.core.models.PostTargetValidationErrorModel; +import dev.sheldan.abstracto.core.models.SystemConfigValidationErrorModel; import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.service.management.ConfigManagementService; @@ -38,18 +38,18 @@ public class FeatureValidationServiceBean implements FeatureValidatorService { @Override public void checkPostTarget(PostTargetEnum name, AServer server, FeatureValidationResult featureValidationResult) { if(!postTargetManagement.postTargetExists(name.getKey(), server)) { - PostTargetValidationError validationError = PostTargetValidationError.builder().postTargetName(name.getKey()).build(); + PostTargetValidationErrorModel validationError = PostTargetValidationErrorModel.builder().postTargetName(name.getKey()).build(); featureValidationResult.setValidationResult(false); - featureValidationResult.getValidationErrors().add(validationError); + featureValidationResult.getValidationErrorModels().add(validationError); } } @Override public boolean checkSystemConfig(String name, AServer server, FeatureValidationResult featureValidationResult) { if(!configService.configExists(server, name)) { - SystemConfigValidationError validationError = SystemConfigValidationError.builder().configKey(name).build(); + SystemConfigValidationErrorModel validationError = SystemConfigValidationErrorModel.builder().configKey(name).build(); featureValidationResult.setValidationResult(false); - featureValidationResult.getValidationErrors().add(validationError); + featureValidationResult.getValidationErrorModels().add(validationError); return false; } return true; @@ -79,9 +79,9 @@ public class FeatureValidationServiceBean implements FeatureValidatorService { } private void rejectEmote(String emoteKey, FeatureValidationResult featureValidationResult) { - EmoteMissingValidationError validationError = EmoteMissingValidationError.builder().emoteKey(emoteKey).build(); + EmoteMissingValidationErrorModel validationError = EmoteMissingValidationErrorModel.builder().emoteKey(emoteKey).build(); featureValidationResult.setValidationResult(false); - featureValidationResult.getValidationErrors().add(validationError); + featureValidationResult.getValidationErrorModels().add(validationError); } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/EmoteMissingValidationError.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/EmoteMissingValidationErrorModel.java similarity index 85% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/EmoteMissingValidationError.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/EmoteMissingValidationErrorModel.java index 64c67ca89..0201b90c7 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/EmoteMissingValidationError.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/EmoteMissingValidationErrorModel.java @@ -9,7 +9,7 @@ import java.util.HashMap; @Getter @Setter @Builder -public class EmoteMissingValidationError implements ValidationError { +public class EmoteMissingValidationErrorModel implements ValidationErrorModel { private String emoteKey; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FeatureValidationResult.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FeatureValidationResult.java index 63d2223f2..7cab6ed69 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FeatureValidationResult.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/FeatureValidationResult.java @@ -18,7 +18,7 @@ public class FeatureValidationResult implements Templatable { private FeatureConfig feature; private Boolean validationResult; @Builder.Default - private List validationErrors = new ArrayList<>(); + private List validationErrorModels = new ArrayList<>(); public static FeatureValidationResult validationSuccessful(FeatureConfig featureConfig) { return FeatureValidationResult @@ -37,7 +37,7 @@ public class FeatureValidationResult implements Templatable { public Object getTemplateModel() { HashMap params = new HashMap<>(); params.put("featureTemplate", this.feature.getFeature().getKey() + "_feature"); - params.put("errors", this.validationErrors); + params.put("errors", this.validationErrorModels); return params; } } diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/PostTargetValidationError.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/PostTargetValidationErrorModel.java similarity index 86% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/PostTargetValidationError.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/PostTargetValidationErrorModel.java index a3d142da7..51d17d12d 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/PostTargetValidationError.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/PostTargetValidationErrorModel.java @@ -9,7 +9,7 @@ import java.util.HashMap; @Getter @Setter @Builder -public class PostTargetValidationError implements ValidationError { +public class PostTargetValidationErrorModel implements ValidationErrorModel { private String postTargetName; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/SystemConfigValidationError.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/SystemConfigValidationErrorModel.java similarity index 85% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/SystemConfigValidationError.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/SystemConfigValidationErrorModel.java index 5299d50ee..6dd80f011 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/SystemConfigValidationError.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/SystemConfigValidationErrorModel.java @@ -9,7 +9,7 @@ import java.util.HashMap; @Getter @Setter @Builder -public class SystemConfigValidationError implements ValidationError { +public class SystemConfigValidationErrorModel implements ValidationErrorModel { private String configKey; diff --git a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ValidationError.java b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ValidationErrorModel.java similarity index 62% rename from abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ValidationError.java rename to abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ValidationErrorModel.java index 7828a2dd7..0f5d6f026 100644 --- a/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ValidationError.java +++ b/abstracto-application/core/core-interface/src/main/java/dev/sheldan/abstracto/core/models/ValidationErrorModel.java @@ -2,5 +2,5 @@ package dev.sheldan.abstracto.core.models; import dev.sheldan.abstracto.templating.Templatable; -public interface ValidationError extends Templatable { +public interface ValidationErrorModel extends Templatable { } diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc index 14e507c12..40ed596c8 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/features/modmail.adoc @@ -69,7 +69,7 @@ Closing the mod mail thread without notifying the user:: * Usage: `closeSilently [note]` * Description: Closes the thread, deletes the text channel containing the thread and logs the interactions between the member and the moderators in the `modmailLog` post target. (only if `modmail_logging` is enabled) When closing a thread, a closing header with general information will be send and the note will be displayed there. -Close a thread without logging +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`. diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/features/utility.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/features/utility.adoc index 53bb0dcd9..1a7fbcacf 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/features/utility.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/features/utility.adoc @@ -98,7 +98,7 @@ Displaying information about members:: Displaying information about server:: * Usage: `serverInfo` -Description: Displays information about the server including: ID, server name, owner, member count, creation date, role count, server features and custom emotes of the server. +* Description: Displays information about the server including: ID, server name, owner, member count, creation date, role count, server features and custom emotes of the server. === Link embeds @@ -107,6 +107,6 @@ Description: Displays information about the server including: ID, server name, o This feature enables the automatic embedding of messages containing a message link. If a message contains a link to a discord message this will create an embed containing the the message content. This supports image attachments, but not videos or files. -A reaction is placed on the embedded message can be used to delete this embed. Only the person posting the message link and the person being quoted can use this feature. +A reaction is placed on the embedded message which can be used to delete this embed. Only the original author and the person creating the embed can delete the embed this way. Feature key: `link_embeds` \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/modmail/config/modmail_help_module_info_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/modmail/config/modmail_help_module_info_en_US.ftl new file mode 100644 index 000000000..5190e86fd --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/modmail/config/modmail_help_module_info_en_US.ftl @@ -0,0 +1 @@ +Commands to be used for mod mail. \ No newline at end of file diff --git a/abstracto-application/template-config/src/main/resources/templates/en_US/modmail/exception/modmail_not_in_modmail_thread_en_US.ftl b/abstracto-application/template-config/src/main/resources/templates/en_US/modmail/exception/modmail_not_in_modmail_thread_en_US.ftl new file mode 100644 index 000000000..c38b4ad17 --- /dev/null +++ b/abstracto-application/template-config/src/main/resources/templates/en_US/modmail/exception/modmail_not_in_modmail_thread_en_US.ftl @@ -0,0 +1 @@ +Not in a mod mail thread. \ No newline at end of file