[AB-60] improving java doc for experience module

This commit is contained in:
Sheldan
2021-03-03 16:35:06 +01:00
parent 821971523e
commit 373dfac001
36 changed files with 390 additions and 244 deletions

View File

@@ -34,6 +34,8 @@ public class DisableExpForRole extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
ARole role = (ARole) parameters.get(0); ARole role = (ARole) parameters.get(0);
ARole actualRole = roleManagementService.findRole(role.getId()); ARole actualRole = roleManagementService.findRole(role.getId());
// as we mange experience disabled roles via the existence of them in a table, we should not do anything
// in case it is used a second time as a disabled experience role
if(!disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) { if(!disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) {
disabledExpRoleManagementService.setRoleToBeDisabledForExp(actualRole); disabledExpRoleManagementService.setRoleToBeDisabledForExp(actualRole);
} }

View File

@@ -33,6 +33,7 @@ public class EnableExpForRole extends AbstractConditionableCommand {
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
ARole role = (ARole) commandContext.getParameters().getParameters().get(0); ARole role = (ARole) commandContext.getParameters().getParameters().get(0);
ARole actualRole = roleManagementService.findRole(role.getId()); ARole actualRole = roleManagementService.findRole(role.getId());
// If its not disabled for the role, we can remove it
if(disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) { if(disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) {
disabledExpRoleManagementService.removeRoleToBeDisabledForExp(actualRole); disabledExpRoleManagementService.removeRoleToBeDisabledForExp(actualRole);
} }

View File

@@ -19,7 +19,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Command to enable experience again for a member * Command to enable experience gain for a member
*/ */
@Component @Component
public class EnableExpGain extends AbstractConditionableCommand { public class EnableExpGain extends AbstractConditionableCommand {

View File

@@ -3,6 +3,9 @@ package dev.sheldan.abstracto.experience.config;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
/**
* Config file containing the default configurations related to experience
*/
@Configuration @Configuration
@PropertySource("classpath:experience-config.properties") @PropertySource("classpath:experience-config.properties")
public class ExperienceConfig { public class ExperienceConfig {

View File

@@ -15,7 +15,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
/** /**
* Converter used to convert from {@link LeaderBoard} to a list of {@link LeaderBoardEntryModel} * Converter used to convert from {@link LeaderBoard leaderBoard} to a list of {@link LeaderBoardEntryModel leaderBoardEntryModels}
*/ */
@Component @Component
@Slf4j @Slf4j
@@ -25,15 +25,15 @@ public class LeaderBoardModelConverter {
private MemberService memberService; private MemberService memberService;
/** /**
* Converts the complete {@link LeaderBoard} into a list of {@link LeaderBoardEntryModel} which contain additional * Converts the complete {@link LeaderBoard leaderBoard} into a list of {@link LeaderBoardEntryModel leaderbaordEntryModels} which contain additional
* information available for rendering the leader board ({@link Member} reference and more) * information available for rendering the leader board ({@link Member member} reference and more)
* @param leaderBoard The {@link LeaderBoard} object to be converted * @param leaderBoard The {@link LeaderBoard leaderBoard} object to be converted
* @return The list of {@link LeaderBoardEntryModel} which contain the fully fledged information provided to the * @return The list of {@link LeaderBoardEntryModel leaderboarEntryModels} which contain the fully fledged information provided to the
* leader board template * leader board template
*/ */
public List<CompletableFuture<LeaderBoardEntryModel>> fromLeaderBoard(LeaderBoard leaderBoard) { public List<CompletableFuture<LeaderBoardEntryModel>> fromLeaderBoard(LeaderBoard leaderBoard) {
List<CompletableFuture<LeaderBoardEntryModel>> models = new ArrayList<>(); List<CompletableFuture<LeaderBoardEntryModel>> models = new ArrayList<>();
log.trace("Converting {} entries to a list of leaderbord entries.", leaderBoard.getEntries().size()); log.trace("Converting {} entries to a list of leaderboard entries.", leaderBoard.getEntries().size());
leaderBoard.getEntries().forEach(leaderBoardEntry -> { leaderBoard.getEntries().forEach(leaderBoardEntry -> {
CompletableFuture<LeaderBoardEntryModel> entry = fromLeaderBoardEntry(leaderBoardEntry); CompletableFuture<LeaderBoardEntryModel> entry = fromLeaderBoardEntry(leaderBoardEntry);
models.add(entry); models.add(entry);
@@ -42,10 +42,10 @@ public class LeaderBoardModelConverter {
} }
/** /**
* Converts the given {@link LeaderBoardEntry} to a {@link LeaderBoardEntryModel}, which provides a reference to the * Converts the given {@link LeaderBoardEntry entry} to a {@link LeaderBoardEntryModel model}, which provides a reference to the
* {@link Member} object of the given {@link AUserInAServer} for convenience in the template * {@link Member member} object of the given {@link AUserInAServer user} for convenience in the template
* @param leaderBoardEntry The {@link LeaderBoardEntry} to be converted * @param leaderBoardEntry The {@link LeaderBoardEntry entry} to be converted
* @return The {@link LeaderBoardEntryModel} accompanied with the {@link Member} reference, might be null, if the * @return The {@link LeaderBoardEntryModel model} accompanied with the {@link Member member} reference, might be null, if the
* user left the guild * user left the guild
*/ */
public CompletableFuture<LeaderBoardEntryModel> fromLeaderBoardEntry(LeaderBoardEntry leaderBoardEntry) { public CompletableFuture<LeaderBoardEntryModel> fromLeaderBoardEntry(LeaderBoardEntry leaderBoardEntry) {

View File

@@ -18,7 +18,7 @@ import java.util.Map;
/** /**
* This {@link QuartzJobBean} is executed regularly and calls the the {@link AUserExperienceService} * This {@link QuartzJobBean job} is executed regularly and calls the the {@link AUserExperienceService service}
* store the tracked experience from runtime. This job also cleans up the already processed entries in the runtime * store the tracked experience from runtime. This job also cleans up the already processed entries in the runtime
* experience. * experience.
*/ */

View File

@@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* This {@link MessageReceivedListener} is responsible to execute the {@link AUserExperienceService} in order to track * This {@link MessageReceivedListener listener} is responsible to execute the {@link AUserExperienceService service} in order to track
* that a certain user has send a message, and experience should be awarded. * that a certain user has send a message, and experience should be awarded.
*/ */
@Component @Component

View File

@@ -16,8 +16,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* If a user joins, this {@link JoinListener} retrieves the previously stored {@link AUserExperience} and gives the * If a {@link Member member} joins, this {@link JoinListener listener} retrieves the previously stored {@link AUserExperience experience} and gives the
* {@link Member} the necessary {@link net.dv8tion.jda.api.entities.Role} according to the current configuration * member the necessary {@link net.dv8tion.jda.api.entities.Role role} according to the current configuration, if any
*/ */
@Component @Component
@Slf4j @Slf4j

View File

@@ -9,15 +9,28 @@ import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
/** /**
* Repository to manage the access to the table managed by {@link ADisabledExpRole} * Repository to manage the access to the table managed by {@link ADisabledExpRole disabledRole}
*/ */
@Repository @Repository
public interface DisabledExpRoleRepository extends JpaRepository<ADisabledExpRole, Long> { public interface DisabledExpRoleRepository extends JpaRepository<ADisabledExpRole, Long> {
/**
* Determines if there exists a {@link ADisabledExpRole disabledExpRole} which is defined by the given {@link ARole role}
* @param role The {@link ARole role} to search for
* @return Whether or not a role {@link ADisabledExpRole disabledExpRole} for this {@link ARole role} eixsts
*/
boolean existsByRole(ARole role); boolean existsByRole(ARole role);
ADisabledExpRole findByRole(ARole role); /**
* Deletes the {@link ADisabledExpRole disabledExpRole} defined for this {@link ARole role}, if there is any.
* @param role The {@link ARole} to delete the {@link ADisabledExpRole disabledExpRole} for
*/
void deleteByRole(ARole role); void deleteByRole(ARole role);
/**
* Returns all {@link ADisabledExpRole disabledExpRoles} for the given {@link AServer server}
* @param server The {@link AServer server} to retrieve the {@link ADisabledExpRole disabledExpRoles} for
* @return The list of {@link ADisabledExpRole disabledExpRoles} found, can be empty
*/
List<ADisabledExpRole> getByRole_Server(AServer server); List<ADisabledExpRole> getByRole_Server(AServer server);
} }

View File

@@ -10,18 +10,9 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* Repository to manage the access to the table managed by {@link AExperienceLevel} * Repository to manage the access to the table managed by {@link AExperienceLevel experienceLevel}
*/ */
@Repository @Repository
public interface ExperienceLevelRepository extends JpaRepository<AExperienceLevel, Integer> { public interface ExperienceLevelRepository extends JpaRepository<AExperienceLevel, Integer> {
@NotNull
@Override
Optional<AExperienceLevel> findById(@NonNull Integer aLong);
@Override
boolean existsById(@NonNull Integer aLong);
@NotNull
@Override
List<AExperienceLevel> findAll();
} }

View File

@@ -13,34 +13,31 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* Repository to manage the access to the table managed by {@link AExperienceRole} * Repository to manage the access to the table managed by {@link AExperienceRole experienceRole}
*/ */
@Repository @Repository
public interface ExperienceRoleRepository extends JpaRepository<AExperienceRole, Long> { public interface ExperienceRoleRepository extends JpaRepository<AExperienceRole, Long> {
/** /**
* Finds the {@link AExperienceRole} of the given {@link AServer} and {@link ARole} * Finds the {@link AExperienceRole experienceRole} of the given {@link AServer server} and {@link ARole role}
* @param role The {@link ARole} to filter for * @param role The {@link ARole role} to filter for
* @return The {@link AExperienceRole} found or null if the query did not return any results * @return The {@link AExperienceRole experienceRole} found or null if the query did not return any results
*/ */
Optional<AExperienceRole> findByRole(ARole role); Optional<AExperienceRole> findByRole(ARole role);
/** /**
* Finds a list of {@link AExperienceRole} (if there are multiple ones, because of misconfiguration) of the given * Finds a list of {@link AExperienceRole experienceRoles} (if there are multiple ones, because of misconfiguration) of the given
* {@link AExperienceLevel} and {@link AServer} * {@link AExperienceLevel experienceLevel} and {@link AServer server}
* @param level The {@link AExperienceLevel} to search for * @param level The {@link AExperienceLevel experienceLevel} to search for
* @param server The {@link AServer} to search for * @param server The {@link AServer server} to search for
* @return The list of {@link AExperienceRole} found by the given parameters * @return The list of {@link AExperienceRole experienceRole} found by the given parameters
*/ */
List<AExperienceRole> findByLevelAndRoleServer(AExperienceLevel level, AServer server); List<AExperienceRole> findByLevelAndRoleServer(AExperienceLevel level, AServer server);
/** /**
* Finds all {@link AExperienceRole} of the given {@link AServer} * Finds all {@link AExperienceRole experienceRoles} of the given {@link AServer server}
* @param server The {@link AServer} to load the list of {@link AExperienceRole} for * @param server The {@link AServer server} to load the list of {@link AExperienceRole experienceRoles} for
* @return A list of {@link AExperienceRole} configured to be used on the given {@link AServer} * @return A list of {@link AExperienceRole experienceRoles} configured to be used on the given {@link AServer server}
*/ */
List<AExperienceRole> findByRoleServer(AServer server); List<AExperienceRole> findByRoleServer(AServer server);
@NotNull
@Override
Optional<AExperienceRole> findById(@NonNull Long aLong);
} }

View File

@@ -15,33 +15,34 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* Repository to manage the access to the table managed by {@link AUserExperience} * Repository to manage the access to the table managed by {@link AUserExperience userExperience}
*/ */
@Repository @Repository
public interface UserExperienceRepository extends JpaRepository<AUserExperience, Long> { public interface UserExperienceRepository extends JpaRepository<AUserExperience, Long> {
/** /**
* Finds all {@link AUserExperience} of the given {@link AServer} * Finds all {@link AUserExperience userExperience} of the given {@link AServer server}
* @param server The {@link AServer} to retrieve ethe {@link AUserExperience} for * @param server The {@link AServer server} to retrieve the {@link AUserExperience userExperience} for
* @return A complete list of {@link AUserExperience} of the given {@link AServer} * @return A complete list of {@link AUserExperience} of the given {@link AServer server}
*/ */
List<AUserExperience> findByUser_ServerReference(AServer server); List<AUserExperience> findByUser_ServerReference(AServer server);
/** /**
* Retrieves the {@link AUserExperience} ordered by experience, and applies the {@link Pageable} to only filter out certain pages. * Retrieves the {@link AUserExperience userExperience} ordered by experience, and applies the {@link Pageable pageable} to only filter out certain pages.
* @param server The {@link AServer} to retrieve the {@link AUserExperience} information for * @param server The {@link AServer server} to retrieve the {@link AUserExperience userExperience} information for
* @param pageable A {@link Pageable} object to indicate the pages which should be retrieved, page size is 10 * @param pageable A {@link Pageable pageable} object to indicate the pages which should be retrieved, page size is 10
* @return A list of {@link AUserExperience} of the given {@link AServer} ordered by the experience of the users, paginated by the given * @return A list of {@link AUserExperience userExperience} of the given {@link AServer server} ordered by the experience of the users, paginated by the given
* configuration * configuration
*/ */
List<AUserExperience> findTop10ByUser_ServerReferenceOrderByExperienceDesc(AServer server, Pageable pageable); List<AUserExperience> findTop10ByUser_ServerReferenceOrderByExperienceDesc(AServer server, Pageable pageable);
/** /**
* This returns the {@link LeaderBoardEntryResult} object containing the information about the rank of a user in a server. * This returns the {@link LeaderBoardEntryResult entryResult} object containing the information about the rank of a user in a server.
* This query selects all the experience entries and returns the one associated with the provided user. * This query selects all the experience entries and returns the one associated with the provided user.
* We need to select all of them, in order to find the rank of the member in the server * We need to select all of them, in order to find the rank of the member in the server
* @param id The {@link dev.sheldan.abstracto.core.models.database.AUserInAServer} id to search for * @param id The ID of an {@link dev.sheldan.abstracto.core.models.database.AUserInAServer userInAServer} search for
* @return the {@link LeaderBoardEntryResult} of this {@link dev.sheldan.abstracto.core.models.database.AUserInAServer} * @param serverId The ID of the {@link AServer server} for which we are retrieving the experience
* @return The {@link LeaderBoardEntryResult result} of this {@link dev.sheldan.abstracto.core.models.database.AUserInAServer userInAServer}
* containing rank and experience information * containing rank and experience information
*/ */
@Query(value = "WITH user_experience_ranked AS" + @Query(value = "WITH user_experience_ranked AS" +
@@ -54,7 +55,4 @@ public interface UserExperienceRepository extends JpaRepository<AUserExperience
"WHERE rank.id = :userInServerId", nativeQuery = true) "WHERE rank.id = :userInServerId", nativeQuery = true)
LeaderBoardEntryResult getRankOfUserInServer(@Param("userInServerId") Long id, @Param("serverId") Long serverId); LeaderBoardEntryResult getRankOfUserInServer(@Param("userInServerId") Long id, @Param("serverId") Long serverId);
@NotNull
@Override
Optional<AUserExperience> findById(@NonNull Long aLong);
} }

View File

@@ -88,10 +88,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Autowired @Autowired
private AUserExperienceServiceBean self; private AUserExperienceServiceBean self;
/**
* Creates the user in the runtime experience, if the user was not in yet. Also creates an entry for the minute, if necessary.
* @param userInAServer The {@link AUserInAServer} to be added to the list of users gaining experience
*/
@Override @Override
public void addExperience(AUserInAServer userInAServer) { public void addExperience(AUserInAServer userInAServer) {
runTimeExperienceService.takeLock(); runTimeExperienceService.takeLock();
@@ -124,14 +120,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
} }
/**
* Calculates the level of the given {@link AUserExperience} according to the given {@link AExperienceLevel} list
* @param levels The list of {@link AExperienceLevel} representing the level configuration, this must include the initial level 0
* * This level will be taken as the initial value, and if no other level qualifies, this will be taken.
* The levels must be ordered.
* @param experienceCount
* @return The appropriate level according to the level config
*/
@Override @Override
public AExperienceLevel calculateLevel(List<AExperienceLevel> levels, Long experienceCount) { public AExperienceLevel calculateLevel(List<AExperienceLevel> levels, Long experienceCount) {
AExperienceLevel lastLevel = levels.get(0); AExperienceLevel lastLevel = levels.get(0);
@@ -160,14 +148,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
return false; return false;
} }
/**
* Calculates the actually gained experience for every user in the given servers and adds them to the users.
* This method only actually increases the message count, and calls other methods for experience gain
* and role change.
* Loads the level and role configuration for each server and sorts them for them to be used.
* Only actually updates the role, if the user also changed level.
* @param servers The list of {@link AServer} containing the user which need to gain experience
*/
@Transactional @Transactional
@Override @Override
public CompletableFuture<Void> handleExperienceGain(List<ServerExperience> servers) { public CompletableFuture<Void> handleExperienceGain(List<ServerExperience> servers) {
@@ -249,7 +229,21 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
); );
} }
/**
* Calculates the appropriate {@link AExperienceRole experienceRole} based on the current level and awards the referenced the {@link AUserInAServer userinAServer}
* the {@link net.dv8tion.jda.api.entities.Role role}. If the user already left the guild, this will not award a {@link net.dv8tion.jda.api.entities.Role}, but just
* return the instance in order to be persisted
* @param aUserInAServer The {@link AUserInAServer userInAServer} which does not have a {@link AUserExperience userExperience} object,
* therefore we need to calculate the appropriate role and award the role
* @param roles A list of {@link AExperienceRole experienceRoles} representing the configuration which is used to calculate the appropriate
* {@link AExperienceRole experienceRole}
* @param currentLevel The current level of the user which was reached.
* @return A {@link CompletableFuture future} containing the {@link RoleCalculationResult result} of the role calculation, which completes after the user has been awarded the role.
*/
private CompletableFuture<RoleCalculationResult> applyInitialRole(AUserInAServer aUserInAServer, List<AExperienceRole> roles, Integer currentLevel) { private CompletableFuture<RoleCalculationResult> applyInitialRole(AUserInAServer aUserInAServer, List<AExperienceRole> roles, Integer currentLevel) {
// we are in the process of attributing experience, which means the member should have send a message, therefore is in the case
// if the member is actually _not_ in the guild anymore (would mean, joined, send a message, and left immediately) this check is required
// this is backed by the cache
if(!memberService.isUserInGuild(aUserInAServer)) { if(!memberService.isUserInGuild(aUserInAServer)) {
log.trace("User {} is not in server {} anymore. No role calculation done.", aUserInAServer.getUserInServerId(), aUserInAServer.getServerReference().getId()); log.trace("User {} is not in server {} anymore. No role calculation done.", aUserInAServer.getUserInServerId(), aUserInAServer.getServerReference().getId());
return CompletableFuture.completedFuture(RoleCalculationResult return CompletableFuture.completedFuture(RoleCalculationResult
@@ -279,8 +273,15 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
.build()); .build());
} }
/**
* Persists the list of {@link ExperienceGainResult results} in the database. If the creation of {@link AUserExperience userExperience} object was requested,
* this will happen here, also the correct level is selected
* @param resultFutures A list of {@link ExperienceGainResult results} which define what should be changed for the given {@link AUserExperience userExperience} object:
* The level, experience, experienceRole, message account could change, or the object could not even exist ({@link ExperienceGainResult#createUserExperience})
*/
@Transactional @Transactional
public void persistExperienceChanges(List<ExperienceGainResult> resultFutures) { public void persistExperienceChanges(List<ExperienceGainResult> resultFutures) {
// we do have the _value_ of the level, but we require the actual instance
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig(); List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
log.info("Storing {} experience gain results.", resultFutures.size()); log.info("Storing {} experience gain results.", resultFutures.size());
HashMap<Long, List<AExperienceRole>> serverRoleMapping = new HashMap<>(); HashMap<Long, List<AExperienceRole>> serverRoleMapping = new HashMap<>();
@@ -295,13 +296,18 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
} }
userExperience.setMessageCount(experienceGainResult.getNewMessageCount()); userExperience.setMessageCount(experienceGainResult.getNewMessageCount());
userExperience.setExperience(experienceGainResult.getNewExperience()); userExperience.setExperience(experienceGainResult.getNewExperience());
Optional<AExperienceLevel> foundLevel = levels.stream().filter(level -> level.getLevel().equals(experienceGainResult.getNewLevel())).findFirst(); // only search the levels if the level changed, or if there is no level currently set
if(foundLevel.isPresent()) { boolean userExperienceHasLevel = userExperience.getCurrentLevel() != null;
userExperience.setCurrentLevel(foundLevel.get()); if(!userExperienceHasLevel || !userExperience.getCurrentLevel().getLevel().equals(experienceGainResult.getNewLevel())) {
} else { Optional<AExperienceLevel> foundLevel = levels.stream().filter(level -> level.getLevel().equals(experienceGainResult.getNewLevel())).findFirst();
log.warn("User {} was present, but no level matching the calculation result {} could be found.", userExperience.getUser().getUserReference().getId(), experienceGainResult.getNewLevel()); if(foundLevel.isPresent()) {
userExperience.setCurrentLevel(foundLevel.get());
} else {
log.warn("User {} was present, but no level matching the calculation result {} could be found.", userExperience.getUser().getUserReference().getId(), experienceGainResult.getNewLevel());
}
} }
AServer server = user.getServerReference(); AServer server = user.getServerReference();
// "Caching" the experience roles for this server
if(!serverRoleMapping.containsKey(server.getId())) { if(!serverRoleMapping.containsKey(server.getId())) {
serverRoleMapping.put(server.getId(), experienceRoleManagementService.getExperienceRolesForServer(server)); serverRoleMapping.put(server.getId(), experienceRoleManagementService.getExperienceRolesForServer(server));
} }
@@ -316,14 +322,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}); });
} }
/**
* Calculates the appropriate level of the user and changes the role, if the {@link AExperienceLevel} changes.
* This changes the config in the database, and also gives the {@link net.dv8tion.jda.api.entities.Member} the new
* {@link net.dv8tion.jda.api.entities.Role}. If the user does not warrant an {@link AExperienceRole},
* this method also removes it. The role is only changed, if the user does not have
* @param userExperience The {@link AUserExperience} object to recalculate the {@link AExperienceRole} for
* @param roles The list of {@link AExperienceRole} used as a role configuration
*/
@Override @Override
public CompletableFuture<RoleCalculationResult> updateUserRole(AUserExperience userExperience, List<AExperienceRole> roles, Integer currentLevel) { public CompletableFuture<RoleCalculationResult> updateUserRole(AUserExperience userExperience, List<AExperienceRole> roles, Integer currentLevel) {
AUserInAServer user = userExperience.getUser(); AUserInAServer user = userExperience.getUser();
@@ -390,11 +388,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}); });
} }
/**
* Synchronizes the {@link net.dv8tion.jda.api.entities.Role} of all {@link net.dv8tion.jda.api.entities.Member} in
* the given {@link AServer}. This might take a long time to complete, because there are a lot of role changes.
* @param server The {@link AServer} to update the users for
*/
@Override @Override
public List<CompletableFuture<RoleCalculationResult>> syncUserRoles(AServer server) { public List<CompletableFuture<RoleCalculationResult>> syncUserRoles(AServer server) {
List<CompletableFuture<RoleCalculationResult>> results = new ArrayList<>(); List<CompletableFuture<RoleCalculationResult>> results = new ArrayList<>();
@@ -409,11 +402,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
return results; return results;
} }
/**
* Synchronizes the roles of all the users and provides feedback to the user executing
* @param server The {@link AServer} to update users for
* @param channelId The ID of the channel in which the {@link dev.sheldan.abstracto.experience.models.templates.UserSyncStatusModel} should be posted to
*/
@Override @Override
public CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, Long channelId) { public CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, Long channelId) {
AChannel channel = channelManagementService.loadChannel(channelId); AChannel channel = channelManagementService.loadChannel(channelId);
@@ -432,6 +420,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
*/ */
@Transactional @Transactional
public void syncRolesInStorage(List<RoleCalculationResult> results) { public void syncRolesInStorage(List<RoleCalculationResult> results) {
HashMap<Long, AExperienceRole> experienceRoleHashMap = new HashMap<>();
results.forEach(result -> { results.forEach(result -> {
if(result != null) { if(result != null) {
AUserInAServer user = userInServerManagementService.loadOrCreateUser(result.getUserInServerId()); AUserInAServer user = userInServerManagementService.loadOrCreateUser(result.getUserInServerId());
@@ -439,7 +428,13 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
log.trace("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference().getId(), result.getExperienceRoleId()); log.trace("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference().getId(), result.getExperienceRoleId());
if(result.getExperienceRoleId() != null) { if(result.getExperienceRoleId() != null) {
log.trace("User experience {} gets new experience role with id {}.", userExperience.getId(), result.getExperienceRoleId()); log.trace("User experience {} gets new experience role with id {}.", userExperience.getId(), result.getExperienceRoleId());
AExperienceRole role = experienceRoleManagementService.getExperienceRoleById(result.getExperienceRoleId()); AExperienceRole role;
if(!experienceRoleHashMap.containsKey(result.getExperienceRoleId())) {
role = experienceRoleManagementService.getExperienceRoleById(result.getExperienceRoleId());
experienceRoleHashMap.put(result.getExperienceRoleId(), role);
} else {
role = experienceRoleHashMap.get(result.getExperienceRoleId());
}
userExperience.setCurrentExperienceRole(role); userExperience.setCurrentExperienceRole(role);
} else { } else {
log.trace("User experience {} does not get a user experience role.", userExperience.getId()); log.trace("User experience {} does not get a user experience role.", userExperience.getId());
@@ -449,12 +444,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}); });
} }
/**
* 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 @Override
public CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute) { public CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute) {
List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>(); List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>();
@@ -491,15 +480,18 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
userExperience.setExperienceGainDisabled(false); userExperience.setExperienceGainDisabled(false);
} }
/**
* Renders a {@link MessageToSend messageToSend} to be used as a status message for the ongoing user synchronization
* @param current The amount of users which have been synced
* @param total The total amount of users which will be synced
* @param serverId The ÍD of the {@link AServer server} for which this synchronization is being executed
* @return A {@link MessageToSend messageToSend} which will be used to inform the user executing the synchronization about the new situation
*/
private MessageToSend getUserSyncStatusUpdateModel(Integer current, Integer total, Long serverId) { private MessageToSend getUserSyncStatusUpdateModel(Integer current, Integer total, Long serverId) {
UserSyncStatusModel statusModel = UserSyncStatusModel.builder().currentCount(current).totalUserCount(total).build(); UserSyncStatusModel statusModel = UserSyncStatusModel.builder().currentCount(current).totalUserCount(total).build();
return templateService.renderEmbedTemplate("user_sync_status_message", statusModel, serverId); return templateService.renderEmbedTemplate("user_sync_status_message", statusModel, serverId);
} }
/**
* Retrieves the role configuration and executes the method responsible to sync the experience role of the user
* @param userExperience The {@link AUserExperience} to synchronize the role for
*/
@Override @Override
public CompletableFuture<RoleCalculationResult> syncForSingleUser(AUserExperience userExperience) { public CompletableFuture<RoleCalculationResult> syncForSingleUser(AUserExperience userExperience) {
AUserInAServer user = userExperience.getUser(); AUserInAServer user = userExperience.getUser();
@@ -508,12 +500,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
return updateUserRole(userExperience, roles, userExperience.getLevelOrDefault()); return updateUserRole(userExperience, roles, userExperience.getLevelOrDefault());
} }
/**
* Retrieves the leader board data for the given page of the given server
* @param server The {@link AServer} to retrieve the leader board for
* @param page The desired page on the leader board. The page size is 10
* @return The {@link LeaderBoard} containing all necessary information concerning the leader board
*/
@Override @Override
public LeaderBoard findLeaderBoardData(AServer server, Integer page) { public LeaderBoard findLeaderBoardData(AServer server, Integer page) {
if(page <= 0) { if(page <= 0) {
@@ -532,11 +518,6 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
return LeaderBoard.builder().entries(entries).build(); return LeaderBoard.builder().entries(entries).build();
} }
/**
* Builds an {@link AUserExperience} and loads the appropriate rank of the passed {@link AUserInAServer}
* @param userInAServer The {@link AUserInAServer} to retrieve the {@link LeaderBoardEntry} for
* @return The {@link LeaderBoardEntry} representing one single row in the leader board
*/
@Override @Override
public LeaderBoardEntry getRankOfUserInServer(AUserInAServer userInAServer) { public LeaderBoardEntry getRankOfUserInServer(AUserInAServer userInAServer) {
log.trace("Retrieving rank for {}", userInAServer.getUserReference().getId()); log.trace("Retrieving rank for {}", userInAServer.getUserReference().getId());

View File

@@ -61,6 +61,12 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
); );
} }
/**
* Removes all previous defined {@link AExperienceRole experienceRoles} from the given leve and sets the {@link ARole}
* (defined by its ID) to the level.
* @param level The level which the {@link ARole role} should be set to
* @param roleId The ID of the {@link Role} which should have its level set
*/
@Transactional @Transactional
public void unsetRoleInDb(Integer level, Long roleId) { public void unsetRoleInDb(Integer level, Long roleId) {
log.info("Unsetting role {} from level {}.", roleId, level); log.info("Unsetting role {} from level {}.", roleId, level);
@@ -103,21 +109,22 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
} }
} }
/**
* Stores the changed experience roles for all of the {@link AUserExperience userExperiences} which are referenced in the list of
* {@link RoleCalculationResult results}. This is only executed after a role is being "unset", which means, we also
* have to remove the existing {@link AExperienceRole experienceRole}
* @param results A list of {@link CompletableFuture futures} which each contain a {@link RoleCalculationResult result}, for the members who got
* their {@link AExperienceRole experienceRole} removed
* @param roleId The ID of the {@link AExperienceRole experienceRole} which was removed from the experience roles
*/
@Transactional @Transactional
public void persistData(CompletableFutureList<RoleCalculationResult> results, Long roleId) { public void persistData(CompletableFutureList<RoleCalculationResult> results, Long roleId) {
log.info("Persisting {} role calculation results after changing the role {}.", results.getFutures().size(), roleId); log.info("Persisting {} role calculation results after changing the role {}.", results.getFutures().size(), roleId);
AExperienceRole roleInServer = experienceRoleManagementService.getRoleInServer(roleId); AExperienceRole roleInServer = experienceRoleManagementService.getExperienceRoleById(roleId);
experienceRoleManagementService.unsetRole(roleInServer); experienceRoleManagementService.unsetRole(roleInServer);
userExperienceService.syncRolesInStorage(results.getObjects()); userExperienceService.syncRolesInStorage(results.getObjects());
} }
/**
* Finds the best {@link AExperienceRole} for the level of the passed {@link AUserExperience}, returns null if the passed
* roles are empty/null
* @param roles The role configuration to be used when calculating the appropriate {@link AExperienceRole}
* @param currentLevel
* @return The best fitting {@link AExperienceRole} according to the level of the {@link AUserExperience}
*/
@Override @Override
public AExperienceRole calculateRole(List<AExperienceRole> roles, Integer currentLevel) { public AExperienceRole calculateRole(List<AExperienceRole> roles, Integer currentLevel) {
if(roles == null || roles.isEmpty()) { if(roles == null || roles.isEmpty()) {

View File

@@ -13,6 +13,10 @@ import java.util.Map;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/**
* Responsible for maintaining the data structure containing the IDs of {@link dev.sheldan.abstracto.core.models.database.AUserInAServer}
* for which experience should be given, because they sent messages on their respective servers
*/
@Component @Component
public class RunTimeExperienceService { public class RunTimeExperienceService {
@@ -31,10 +35,16 @@ public class RunTimeExperienceService {
return runtimeExperience; return runtimeExperience;
} }
/**
* Acquires the lock of the runtime experience data structure. Operations on it should only be done, while holding the lock
*/
public void takeLock() { public void takeLock() {
lock.lock(); lock.lock();
} }
/**
* Releases the lock again, and allows others to take the lock, if they want to modify the data structure.
*/
public void releaseLock() { public void releaseLock() {
lock.unlock(); lock.unlock();
} }

View File

@@ -16,12 +16,18 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Optional; import java.util.Optional;
/**
* This condition evaluates whether or not a given {@link AUserExperience userExperience}, defined by the ID of {@link AUserInAServer userInAServer}
* has at least the given level.
*/
@Component @Component
@Slf4j @Slf4j
public class HasLevelCondition implements SystemCondition { public class HasLevelCondition implements SystemCondition {
public static final String USER_ID_VARIABLE = "userId"; public static final String USER_IN_SERVER_ID_VARIABLE_KEY = "userId";
public static final String LEVEL_VARIABLE = "level"; public static final String LEVEL_VARIABLE = "level";
public static final String HAS_LEVEL_CONDITION_KEY = "HAS_LEVEL";
@Autowired @Autowired
private UserExperienceManagementService userExperienceManagementService; private UserExperienceManagementService userExperienceManagementService;
@@ -31,10 +37,10 @@ public class HasLevelCondition implements SystemCondition {
@Override @Override
public boolean checkCondition(ConditionContextInstance conditionContext) { public boolean checkCondition(ConditionContextInstance conditionContext) {
HashMap<String, Object> parameters = conditionContext.getParameters(); HashMap<String, Object> parameters = conditionContext.getParameters();
Long userId = (Long) parameters.get(USER_ID_VARIABLE); Long userInServerId = (Long) parameters.get(USER_IN_SERVER_ID_VARIABLE_KEY);
Integer level = (Integer) parameters.get(LEVEL_VARIABLE); Integer level = (Integer) parameters.get(LEVEL_VARIABLE);
log.info("Evaluating has level condition."); log.info("Evaluating has level condition.");
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserOptional(userId); Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserOptional(userInServerId);
if(userInServerOptional.isPresent()) { if(userInServerOptional.isPresent()) {
AUserInAServer userInServer = userInServerOptional.get(); AUserInAServer userInServer = userInServerOptional.get();
log.info("Evaluating has level condition for user {} in server {} with level {}.", log.info("Evaluating has level condition for user {} in server {} with level {}.",
@@ -49,13 +55,13 @@ public class HasLevelCondition implements SystemCondition {
@Override @Override
public String getConditionName() { public String getConditionName() {
return "HAS_LEVEL"; return HAS_LEVEL_CONDITION_KEY;
} }
@Override @Override
public ConditionContext getExpectedContext() { public ConditionContext getExpectedContext() {
ConditionContextVariable userIdVariable = ConditionContextVariable.builder().name(USER_ID_VARIABLE).type(Long.class).build(); ConditionContextVariable userIdVariable = ConditionContextVariable.builder().name(USER_IN_SERVER_ID_VARIABLE_KEY).type(Long.class).build();
ConditionContextVariable levelVariable = ConditionContextVariable.builder().name(LEVEL_VARIABLE).type(Integer.class).build(); ConditionContextVariable levelVariable = ConditionContextVariable.builder().name(LEVEL_VARIABLE).type(Integer.class).build();
return ConditionContext.builder().expectedVariables(Arrays.asList(userIdVariable, levelVariable)).build(); return ConditionContext.builder().requiredVariables(Arrays.asList(userIdVariable, levelVariable)).build();
} }
} }

View File

@@ -44,6 +44,7 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
@Override @Override
public AExperienceRole getRoleInServer(ARole role) { public AExperienceRole getRoleInServer(ARole role) {
// TODO throw different exception
return this.getRoleInServerOptional(role).orElseThrow(AbstractoRunTimeException::new); return this.getRoleInServerOptional(role).orElseThrow(AbstractoRunTimeException::new);
} }
@@ -52,12 +53,6 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
return experienceRoleRepository.findByRole(role); return experienceRoleRepository.findByRole(role);
} }
@Override
public AExperienceRole getRoleInServer(Long roleId) {
ARole role = roleManagementService.findRole(roleId);
return getRoleInServer(role);
}
@Override @Override
public List<AExperienceRole> getExperienceRolesForServer(AServer server) { public List<AExperienceRole> getExperienceRolesForServer(AServer server) {
return experienceRoleRepository.findByRoleServer(server); return experienceRoleRepository.findByRoleServer(server);
@@ -65,6 +60,7 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
@Override @Override
public AExperienceRole getExperienceRoleById(Long experienceRoleId) { public AExperienceRole getExperienceRoleById(Long experienceRoleId) {
// TODO throw different exception
return getExperienceRoleByIdOptional(experienceRoleId).orElseThrow(() -> new AbstractoRunTimeException("Experience role not found")); return getExperienceRoleByIdOptional(experienceRoleId).orElseThrow(() -> new AbstractoRunTimeException("Experience role not found"));
} }

View File

@@ -42,11 +42,6 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
return findByUserInServerIdOptional(userInServerId).orElseThrow(() -> new UserInServerNotFoundException(userInServerId)); return findByUserInServerIdOptional(userInServerId).orElseThrow(() -> new UserInServerNotFoundException(userInServerId));
} }
/**
* 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 @Override
public AUserExperience createUserInServer(AUserInAServer aUserInAServer) { public AUserExperience createUserInServer(AUserInAServer aUserInAServer) {
log.info("Creating user experience for user {} in server {}.", aUserInAServer.getUserReference().getId(),aUserInAServer.getServerReference().getId()); log.info("Creating user experience for user {} in server {}.", aUserInAServer.getUserReference().getId(),aUserInAServer.getServerReference().getId());

View File

@@ -6,16 +6,44 @@ import lombok.Setter;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
/**
* This object is used to determine the result of calculating the gained experience.
* It is used in the schedule job responsible to calculate the changes after experience has been awarded.
* This changes can include a level or experience role change.
*/
@Getter @Getter
@Setter @Setter
@Builder @Builder
public class ExperienceGainResult { public class ExperienceGainResult {
/**
* The calculation result contained in a {@link CompletableFuture future}. The future is necessary, because the calculation both calculates the new role
* and removes/adds {@link net.dv8tion.jda.api.entities.Role role} to the {@link net.dv8tion.jda.api.entities.Member member}
*/
private CompletableFuture<RoleCalculationResult> calculationResult; private CompletableFuture<RoleCalculationResult> calculationResult;
/**
* The ID of the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} for which this is the result
*/
private Long userInServerId; private Long userInServerId;
/**
* The amount of experience the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} has
*/
private Long newExperience; private Long newExperience;
/**
* The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer server} this calculation took place in
*/
private Long serverId; private Long serverId;
/**
* The new level the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} reached. Might be the same as the old.
*/
private Integer newLevel; private Integer newLevel;
/**
* The new amount of messages of the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} in this server which were counted bý experience tracking
*/
private Long newMessageCount; private Long newMessageCount;
/**
* Whether or not a {@link dev.sheldan.abstracto.experience.models.database.AUserExperience experience} object needs to be created after the calculation.
* This happens if the object did not exist yet, but the calculation was done regardless.
*/
@Builder.Default @Builder.Default
private boolean createUserExperience = false; private boolean createUserExperience = false;
} }

View File

@@ -4,10 +4,20 @@ import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/**
* The result of calculating the appropriate {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole role} for a {@link dev.sheldan.abstracto.experience.models.database.AUserExperience user}
* in a server.
*/
@Getter @Getter
@Setter @Setter
@Builder @Builder
public class RoleCalculationResult { public class RoleCalculationResult {
/**
* The ID of the {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole role} which was given to the user. Can be null, in case no role is given.
*/
private Long experienceRoleId; private Long experienceRoleId;
/**
* The ID of a {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} for who the role was calculated for.
*/
private Long userInServerId; private Long userInServerId;
} }

View File

@@ -7,11 +7,21 @@ import lombok.Setter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* Container object to store the experience in runtime and group it together. This basically is just a list of users who were tracked by experience.
* The actual calculation of the appropriate experience amount is done later.
*/
@Getter @Getter
@Setter @Setter
@Builder @Builder
public class ServerExperience { public class ServerExperience {
/**
* The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer} for which this experience were collected
*/
private Long serverId; private Long serverId;
/**
* A list of IDs of the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer} which should be given experience
*/
@Builder.Default @Builder.Default
private List<Long> userInServerIds = new ArrayList<>(); private List<Long> userInServerIds = new ArrayList<>();
} }

View File

@@ -20,20 +20,29 @@ import java.time.Instant;
@EqualsAndHashCode @EqualsAndHashCode
public class ADisabledExpRole implements Serializable { public class ADisabledExpRole implements Serializable {
/**
* The ID of the {@link ARole role} which is being marked to be used as a marker for {@link net.dv8tion.jda.api.entities.Member} which should not gain experience
*/
@Id @Id
@Column(name = "id") @Column(name = "id")
private Long id; private Long id;
/**
* Reference to the actual {@link ARole} being marked as disabled for experience gain.
*/
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@PrimaryKeyJoinColumn @PrimaryKeyJoinColumn
private ARole role; private ARole role;
/** /**
* Reference to the actual {@link ARole} being marked as disabled for experience gain. * The {@link Instant} this entity was created
*/ */
@Column(name = "created") @Column(name = "created")
private Instant created; private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated") @Column(name = "updated")
private Instant updated; private Instant updated;
} }

View File

@@ -18,21 +18,29 @@ import java.time.Instant;
@Setter @Setter
@EqualsAndHashCode @EqualsAndHashCode
public class AExperienceLevel implements Serializable { public class AExperienceLevel implements Serializable {
/** /**
* The unique level from 0 to as defined in the configuration. Will be created on startup. * The unique level from 0 to as defined in the configuration. Will be created on startup.
*/ */
@Id @Id
@Column(name = "level") @Column(name = "level")
private Integer level; private Integer level;
/** /**
* The total amount of experience needed for this level. * The total amount of experience needed for this level.
*/ */
@Column(name = "experience_needed") @Column(name = "experience_needed")
private Long experienceNeeded; private Long experienceNeeded;
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created") @Column(name = "created")
private Instant created; private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated") @Column(name = "updated")
private Instant updated; private Instant updated;

View File

@@ -25,12 +25,15 @@ import java.util.List;
public class AExperienceRole implements Serializable { public class AExperienceRole implements Serializable {
/** /**
* The abstracto unique id of this experience role. * The ID of the {@link ARole} to be awarded at a certain experience level
*/ */
@Id @Id
@Column(name = "id") @Column(name = "id")
private Long id; private Long id;
/**
* Reference to the {@link ARole} which is being awarded for this configuration
*/
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@PrimaryKeyJoinColumn @PrimaryKeyJoinColumn
private ARole role; private ARole role;
@@ -51,9 +54,15 @@ public class AExperienceRole implements Serializable {
@JoinColumn(name = "server_id", nullable = false) @JoinColumn(name = "server_id", nullable = false)
private AServer server; private AServer server;
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created") @Column(name = "created")
private Instant created; private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated") @Column(name = "updated")
private Instant updated; private Instant updated;

View File

@@ -24,12 +24,15 @@ import java.time.Instant;
public class AUserExperience implements Serializable { public class AUserExperience implements Serializable {
/** /**
* The {@link AUserInAServer} id which is unique for each user in a server. * The ID of the {@link AUserInAServer user} which is represented by this object
*/ */
@Id @Id
@Column(name = "id") @Column(name = "id")
private Long id; private Long id;
/**
* The {@link AUserInAServer user} which is represented by this object
*/
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@PrimaryKeyJoinColumn @PrimaryKeyJoinColumn
private AUserInAServer user; private AUserInAServer user;
@@ -57,22 +60,28 @@ public class AUserExperience implements Serializable {
private Boolean experienceGainDisabled; private Boolean experienceGainDisabled;
/** /**
* The {@link AExperienceLevel } which the user currently has. * The {@link AExperienceLevel level} which the user currently has.
*/ */
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinColumn(name = "level_id", nullable = false) @JoinColumn(name = "level_id", nullable = false)
private AExperienceLevel currentLevel; private AExperienceLevel currentLevel;
/** /**
* The {@link AExperienceRole} the user currently has. Can be null. * The {@link AExperienceRole role} the user currently has. Can be null.
*/ */
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinColumn(name = "role_id") @JoinColumn(name = "role_id")
private AExperienceRole currentExperienceRole; private AExperienceRole currentExperienceRole;
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created") @Column(name = "created")
private Instant created; private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated") @Column(name = "updated")
private Instant updated; private Instant updated;

View File

@@ -9,7 +9,7 @@ public interface LeaderBoardEntryResult {
/** /**
* The {@link dev.sheldan.abstracto.core.models.database.AUserInAServer} id of the user * The {@link dev.sheldan.abstracto.core.models.database.AUserInAServer} id of the user
* @return * @return The ID of the user in a server
*/ */
Long getUserInServerId(); Long getUserInServerId();

View File

@@ -15,6 +15,9 @@ import java.util.List;
@Getter @Getter
@SuperBuilder @SuperBuilder
public class DisabledExperienceRolesModel extends UserInitiatedServerContext { public class DisabledExperienceRolesModel extends UserInitiatedServerContext {
/**
* A list of {@link FullRole roles} for which experience gain is disabled in this server
*/
@Builder.Default @Builder.Default
private List<FullRole> roles = new ArrayList<>(); private List<FullRole> roles = new ArrayList<>();
} }

View File

@@ -15,7 +15,16 @@ import java.io.Serializable;
@Getter @Getter
@Builder @Builder
public class LeaderBoardEntryModel implements Serializable { public class LeaderBoardEntryModel implements Serializable {
/**
* The {@link AUserExperience experience} for this particular user in the server
*/
private AUserExperience experience; private AUserExperience experience;
/**
* The {@link Member member} associated wit this user experience, might be null if the user left he server.
*/
private transient Member member; private transient Member member;
/**
* The position this {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} in this server has, ordered by experience {@link AUserExperience#experience}
*/
private Integer rank; private Integer rank;
} }

View File

@@ -20,7 +20,7 @@ public class RankModel extends SlimUserInitiatedServerContext {
*/ */
private LeaderBoardEntryModel rankUser; private LeaderBoardEntryModel rankUser;
/** /**
* The necessary experience until the next level up. * The necessary experience to the next level up.
*/ */
private Long experienceToNextLevel; private Long experienceToNextLevel;
} }

View File

@@ -19,43 +19,44 @@ import java.util.function.Function;
/** /**
* Service providing the required mechanisms to provide experience tracking. * Service providing the required mechanisms to provide experience tracking.
* This includes manipulations on the {@link AUserExperience} table, container for the runtime experience, synchronizing the * This includes manipulations on the {@link AUserExperience userExperience} table, container for the runtime experience, synchronizing the
* user in the guild and retrieving {@link LeaderBoard} data. * user in the guild and retrieving {@link LeaderBoard leaderboard} data.
*/ */
public interface AUserExperienceService { public interface AUserExperienceService {
/** /**
* Adds the given {@link AUserInAServer} to the list of user who gained experience in the current minute. * Adds the given {@link AUserInAServer userInAServer} to the list of user who gained experience in the current minute.
* Does not add the user to the list of users, if it is already in there. * Does not add the user to the list of users, if it is already in there.
* @param userInAServer The {@link AUserInAServer} to be added to the list of users gaining experience * @param userInAServer The {@link AUserInAServer userInAServer} to be added to the list of users gaining experience
*/ */
void addExperience(AUserInAServer userInAServer); void addExperience(AUserInAServer userInAServer);
/** /**
* Calculates the appropriate level of the given {@link AUserExperience} according to the given {@link AExperienceLevel} * Calculates the appropriate level for the given experience amount according to the given {@link AExperienceLevel levels}
* configuration. * configuration.
* @param levels The list of {@link AExperienceLevel} representing the level configuration, this must include the initial level 0 * @param levels The list of {@link AExperienceLevel levels} representing the level configuration, this must include the initial level 0
* This level will be taken as the initial value, and if no other level qualifies, this will be taken. The levels must be ordered. * This level will be taken as the initial value, and if no other level qualifies, this will be taken. The levels **must** be ordered.
* @param experienceCount * @param experienceCount The amount of experience to calculate the level for
* @return The appropriate level of {@link AUserExperience} according to the provided {@link AExperienceLevel} configuration * @return The appropriate level of the given experience according to the provided {@link AExperienceLevel levels} configuration
*/ */
AExperienceLevel calculateLevel(List<AExperienceLevel> levels, Long experienceCount); AExperienceLevel calculateLevel(List<AExperienceLevel> levels, Long experienceCount);
/** /**
* Calculates the new level of the provided {@link AUserExperience} according * Calculates the new level of the provided {@link AUserExperience userExperience} according
* to the provided list of {@link AExperienceLevel} used as level configuration * to the provided list of {@link AExperienceLevel levels} used as level configuration
* @param userExperience The {@link AUserExperience} to increase the experience for * @param userExperience The {@link AUserExperience userExperience} to increase the experience for
* @param levels The list of {@link AExperienceLevel} to be used as level configuration * @param levels The list of {@link AExperienceLevel levels} to be used as level configuration
* @param experienceCount * @param experienceCount The amount of experience which will be added
* @return Whether or not the user changed level * @return Whether or not the user changed level
*/ */
boolean updateUserLevel(AUserExperience userExperience, List<AExperienceLevel> levels, Long experienceCount); boolean updateUserLevel(AUserExperience userExperience, List<AExperienceLevel> levels, Long experienceCount);
/** /**
* Iterates through the given list of {@link AServer} and increases the experience of the users contained in the * Iterates through the given list of {@link AServer servers} and increases the experience of the users contained in the
* {@link AServer} object, also increments the level and changes the role if necessary. * {@link ServerExperience serverExperience} object, also increments the level and changes the role if necessary.
* This uses the respective configurable max/minExp and multiplier for each {@link AServer} and increases the message count * This uses the respective configurable max/minExp and multiplier for each {@link AServer server} and increases the message count
* of each user by 1. * of each user by 1.
* @param serverExp The list of {@link AServer} containing the users which get experience * @param serverExp The list of {@link AServer servers} containing the users which get experience
* @return A {@link CompletableFuture future} completing when the experience gain was calculated and roles were assigned
*/ */
CompletableFuture<Void> handleExperienceGain(List<ServerExperience> serverExp); CompletableFuture<Void> handleExperienceGain(List<ServerExperience> serverExp);
@@ -63,18 +64,20 @@ public interface AUserExperienceService {
* Calculates the currently appropriate {@link AExperienceRole} for the given user and updates the role on the * Calculates the currently appropriate {@link AExperienceRole} for the given user and updates the role on the
* {@link net.dv8tion.jda.api.entities.Member} and ond the {@link AUserExperience}. Effectively synchronizes the * {@link net.dv8tion.jda.api.entities.Member} and ond the {@link AUserExperience}. Effectively synchronizes the
* state in the server and the database. * state in the server and the database.
* @param userExperience The {@link AUserExperience} object to recalculate the {@link AExperienceRole} for * @param userExperience The {@link AUserExperience userExperience} object to recalculate the {@link AExperienceRole experienceRole} for
* @param roles The list of {@link AExperienceRole} used as a role configuration * @param roles The list of {@link AExperienceRole roles} used as a role configuration
* @return A {@link CompletableFuture future} containing the {@link RoleCalculationResult result} of the role calculation,
* completing after the role of the {@link net.dv8tion.jda.api.entities.Member} has been updated, if any
*/ */
CompletableFuture<RoleCalculationResult> updateUserRole(AUserExperience userExperience, List<AExperienceRole> roles, Integer currentLevel); CompletableFuture<RoleCalculationResult> updateUserRole(AUserExperience userExperience, List<AExperienceRole> roles, Integer currentLevel);
/** /**
* Synchronizes the state ({@link AExperienceRole}, {@link net.dv8tion.jda.api.entities.Role}) * Synchronizes the state ({@link AExperienceRole}, {@link net.dv8tion.jda.api.entities.Role})
* of all the users provided in the {@link AServer} object in the {@link AUserExperience} * of all the users provided in the {@link AServer} object in the {@link AUserExperience}
* and on the {@link net.dv8tion.jda.api.entities.Member} according * and on the {@link net.dv8tion.jda.api.entities.Member} according
* to how much experience the user has. Runs completely in the background. * to how much experience the user has. Runs completely in the background.
* @param server The {@link AServer} to update the users for * @param server The {@link AServer} to update the users for
* @return The list of {@link CompletableFuture futures} for each update of the users in the {@link AServer server}
*/ */
List<CompletableFuture<RoleCalculationResult>> syncUserRoles(AServer server); List<CompletableFuture<RoleCalculationResult>> syncUserRoles(AServer server);
@@ -82,11 +85,12 @@ public interface AUserExperienceService {
* Synchronizes the state ({@link AExperienceRole}, {@link net.dv8tion.jda.api.entities.Role}) * Synchronizes the state ({@link AExperienceRole}, {@link net.dv8tion.jda.api.entities.Role})
* of all the users provided in the {@link AServer} object in the {@link AUserExperience} * of all the users provided in the {@link AServer} object in the {@link AUserExperience}
* and on the {@link net.dv8tion.jda.api.entities.Member} according * and on the {@link net.dv8tion.jda.api.entities.Member} according
* to how much experience the user has. This method provides feedback back to the user in the provided {@link AChannel} * to how much experience the user has. This method provides feedback back to the user in the provided {@link AChannel channel}
* while the process is going own. * while the process is going own.
* @param server The {@link AServer} to update users for * @param server The {@link AServer} to update users for
* @param channel The {@link AChannel} in which the {@link dev.sheldan.abstracto.experience.models.templates.UserSyncStatusModel} * @param channelId The ID of a {@link AChannel channel} in which the {@link dev.sheldan.abstracto.experience.models.templates.UserSyncStatusModel statusUpdate}
* should be posted to * should be posted to
* @return A {@link CompletableFuture future} which completes after all the role changes have been completed
*/ */
CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, Long channelId); CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, Long channelId);
@@ -94,6 +98,7 @@ public interface AUserExperienceService {
* Recalculates the role of a single user in a server and synchronize the {@link net.dv8tion.jda.api.entities.Role} * Recalculates the role of a single user in a server and synchronize the {@link net.dv8tion.jda.api.entities.Role}
* in the {@link net.dv8tion.jda.api.entities.Guild} * in the {@link net.dv8tion.jda.api.entities.Guild}
* @param userExperience The {@link AUserExperience} to synchronize the role for * @param userExperience The {@link AUserExperience} to synchronize the role for
* @return A {@link CompletableFuture future} which completes after the roles have been synced for the given {@link AUserInAServer user}
*/ */
CompletableFuture<RoleCalculationResult> syncForSingleUser(AUserExperience userExperience); CompletableFuture<RoleCalculationResult> syncForSingleUser(AUserExperience userExperience);
@@ -121,7 +126,10 @@ public interface AUserExperienceService {
* template * template
* @param experiences The list of {@link AUserExperience} to be working on * @param experiences The list of {@link AUserExperience} to be working on
* @param channel The {@link AChannel} used to provide feedback to the user * @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 * @param toExecute The {@link Function} which should be executed on each element of the passed list,
* this function needs to take a {@link AUserExperience userExperience} as parameter and returns a {@link CompletableFuture}
* with a {@link RoleCalculationResult} for each of them. These futures are then returned.
* @return A {@link CompletableFutureList completeFutureList} which represents the individual {@link RoleCalculationResult results} and a primary future, which is completed after all of the individual ones are
*/ */
CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute); CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute);
@@ -137,5 +145,9 @@ public interface AUserExperienceService {
*/ */
void enableExperienceForUser(AUserInAServer userInAServer); void enableExperienceForUser(AUserInAServer userInAServer);
/**
* Updates the actually stored experience roles in the database
* @param results The list of {@link RoleCalculationResult} which should be updated in the database
*/
void syncRolesInStorage(List<RoleCalculationResult> results); void syncRolesInStorage(List<RoleCalculationResult> results);
} }

View File

@@ -1,31 +1,31 @@
package dev.sheldan.abstracto.experience.service; package dev.sheldan.abstracto.experience.service;
/** /**
* Service responsible for operations on {@link dev.sheldan.abstracto.experience.models.database.AExperienceLevel} * Service responsible for operations on {@link dev.sheldan.abstracto.experience.models.database.AExperienceLevel experienceLevel}
* This includes creating and calculations. * This includes creating and calculations.
*/ */
public interface ExperienceLevelService { public interface ExperienceLevelService {
/** /**
* Creates all the levels up until the given level. * Creates all the levels up until the given level.
* @param level The max level to create {@link dev.sheldan.abstracto.experience.models.database.AExperienceLevel} for * @param level The max level to create {@link dev.sheldan.abstracto.experience.models.database.AExperienceLevel level} for
*/ */
void createLevelsUntil(Integer level); void createLevelsUntil(Integer level);
/** /**
* Calculates the required experience until the next level is reached according to the current experience and * Calculates the required experience until the next level is reached according to the provided experience and
* current level. * provided level.
* @param level The current level to base the calculation of * @param level The level to base the calculation of
* @param currentExperience The current experience * @param currentExperience The current total experience
* @return The amount of experience required necessary to get to one level higher as currently. * @return The amount of experience required necessary to reach the next level
*/ */
Long calculateExperienceToNextLevel(Integer level, Long currentExperience); Long calculateExperienceToNextLevel(Integer level, Long currentExperience);
/** /**
* Calculates the required experience to reach this level. This calculated experience is relative, in the sense * Calculates the required experience to reach this level. This calculated experience is relative, in the sense that
* the returned experience is the increment from the experience requirement from the level before. * the returned experience is the difference between the level before the provided one
* @param level The level to calculate the experience amount for * @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 * @return The needed experience to reach this level, if the user already has the level below the provided one
*/ */
Long calculateExperienceForLevel(Integer level); Long calculateExperienceForLevel(Integer level);
} }

View File

@@ -11,36 +11,47 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
/** /**
* Service providing several methods surrounding {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole}. * Service providing several methods surrounding {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole experienceRole}.
*/ */
public interface ExperienceRoleService { public interface ExperienceRoleService {
/** /**
* Creates an {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole} according to the given * Creates an {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole experienceRole} according to the given
* parameters * parameters. This actually updates the {@link net.dv8tion.jda.api.entities.Member members}
* @param role The {@link ARole} to set the level to * which currently possessed the given role before and provides a display to see how far the progress is
* @param level The level the {@link ARole} should be awarded at * @param role The {@link ARole role} to set the level to
* @param level The new level the {@link ARole role} should be awarded at
* @param channelId The ID of the {@link dev.sheldan.abstracto.core.models.database.AChannel} in which the status updates
* should be sent to
* @return A {@link CompletableFuture future} which completes, after all the updates on the {@link net.dv8tion.jda.api.entities.Member}
* have been completed
*/ */
CompletableFuture<Void> setRoleToLevel(Role role, Integer level, Long channelId); CompletableFuture<Void> setRoleToLevel(Role role, Integer level, Long channelId);
/** /**
* Removes the role from the {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole} configuration * Removes the role from the {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole} configuration,
* this will also update all the {@link net.dv8tion.jda.api.entities.Member} which previously had this role and re-calculates
* a new {@link AExperienceRole experienceRole} for them while also updating them in the guild
* @param role The {@link ARole} to remove from the {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole} * @param role The {@link ARole} to remove from the {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole}
* configuration * configuration
* @param channelId The ID of the {@link dev.sheldan.abstracto.core.models.database.AChannel} in which the status updates
* should be sent to
* @return A {@link CompletableFuture future} which completes, after all the updates on the {@link net.dv8tion.jda.api.entities.Member}
* have been completed
*/ */
CompletableFuture<Void> unsetRole(ARole role, Long channelId); CompletableFuture<Void> unsetRole(ARole role, Long channelId);
/** /**
* Calculates the appropriate {@link AExperienceRole} based on the provided list of {@link AExperienceRole} * Calculates the appropriate {@link AExperienceRole experienceRole} based on the provided list of {@link AExperienceRole experienceRole}
* @param roles The role configuration to be used when calculating the appropriate {@link AExperienceRole} * @param roles The role configuration to be used when calculating the appropriate {@link AExperienceRole experienceRole}
* @param currentLevel * @param currentLevel The level to calculate the {@link AExperienceRole experienceRole} for
* @return The best matching {@link AExperienceRole} according to the experience in the provided {@link AUserExperience} * @return The best matching {@link AExperienceRole experienceRole} according to the experience in the provided {@link AUserExperience}
*/ */
AExperienceRole calculateRole(List<AExperienceRole> roles, Integer currentLevel); AExperienceRole calculateRole(List<AExperienceRole> roles, Integer currentLevel);
/** /**
* Calculates the level at which the next role for a given level is available. * 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 * 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. * the {@link AExperienceLevel}.
* @param startLevel The {@link AExperienceLevel} to start off at * @param startLevel The {@link AExperienceLevel} to start off at
* @param server The {@link AServer} to use for the {@link AExperienceRole} configuration * @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 * @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

View File

@@ -12,31 +12,31 @@ import java.util.List;
public interface DisabledExpRoleManagementService { 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 * Creates an instance of {@link ADisabledExpRole experienceRole} which marks the {@link ARole role} as disabled. This effectively means, that the experience is disabled for members
* which have the {@link ARole} * which have the {@link ARole role}
* @param role The {@link ARole} which should be used as a role to disable experience * @param role The {@link ARole role} which should be used as a role to disable experience
* @return The create instance of {@link ADisabledExpRole} * @return The created instance of {@link ADisabledExpRole experienceRole}
*/ */
ADisabledExpRole setRoleToBeDisabledForExp(ARole role); 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 * Removes the given {@link ARole role} 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} * {@link ADisabledExpRole roles} and enables experience for the given {@link ARole role}
* @param role The {@link ARole} to enable experience for * @param role The {@link ARole role} to enable experience for
*/ */
void removeRoleToBeDisabledForExp(ARole role); 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 * Retrieves all the {@link ADisabledExpRole experienceRole} roles for a given {@link AServer server}
* @param server The {@link AServer} to retrieve all {@link ADisabledExpRole} for * @param server The {@link AServer server} to retrieve all {@link ADisabledExpRole roles} for
* @return A List of {@link ADisabledExpRole} which are currently on the {@link AServer} * @return A List of {@link ADisabledExpRole roles} which are currently configured for the {@link AServer server}
*/ */
List<ADisabledExpRole> getDisabledRolesForServer(AServer server); List<ADisabledExpRole> getDisabledRolesForServer(AServer server);
/** /**
* Checks if the given {@link ARole} has its experience disabled and returns true if so * Checks if the given {@link ARole role} has its experience disabled and returns true if so
* @param role The {@link ARole} to check for * @param role The {@link ARole role} to check for
* @return Whether or not the given {@link ARole} has the experience disabled. * @return Whether or not the given {@link ARole role} has the experience disabled.
*/ */
boolean isExperienceDisabledForRole(ARole role); boolean isExperienceDisabledForRole(ARole role);
} }

View File

@@ -6,34 +6,34 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* Service responsible to create and retrieve {@link AExperienceLevel} objects in the database. * Service responsible to create and retrieve {@link AExperienceLevel levels} objects in the database.
*/ */
public interface ExperienceLevelManagementService { public interface ExperienceLevelManagementService {
/** /**
* Creates the level referenced by the level and the needed experience in the database. * Creates the level referenced by the level and the needed experience in the database.
* @param level The unique level this level should represent. * @param level The unique level this level should represent.
* @param neededExperience The total amount of experience required to reach this level. * @param neededExperience The total amount of experience required to reach this level.
* @return A newly created {@link AExperienceLevel} instance. * @return A newly created {@link AExperienceLevel level} instance.
*/ */
AExperienceLevel createExperienceLevel(Integer level, Long neededExperience); AExperienceLevel createExperienceLevel(Integer level, Long neededExperience);
/** /**
* Checks if a {@link AExperienceLevel} level indicated by the level exists in the database. Returns true if it does. * Checks if a {@link AExperienceLevel level} indicated by the level exists in the database. Returns true if it does.
* @param level The integer of the level to check for. * @param level The integer of the level to check for.
* @return A boolean indicating whether or not the level exists in the database. * @return A boolean indicating whether or not the level exists in the database.
*/ */
boolean levelExists(Integer level); boolean levelExists(Integer level);
/** /**
* Retrieves a {@link AExperienceLevel} according to the given level. * Retrieves a {@link AExperienceLevel level} according to the given level.
* @param level The level of the wanted {@link AExperienceLevel} to look for * @param level The {@link AExperienceLevel level} of the wanted level number
* @return Returns an optional containing the {@link AExperienceLevel} if it exists, and null otherwise * @return Returns an optional containing the {@link AExperienceLevel level} if it exists, and empty otherwise
*/ */
Optional<AExperienceLevel> getLevel(Integer level); Optional<AExperienceLevel> getLevel(Integer level);
/** /**
* Loads the complete level configuration and returns all found {@link AExperienceLevel} objects from the database. * Loads the complete level configuration and returns all found {@link AExperienceLevel levels} from the database.
* @return A list of {@link AExperienceLevel} objects representing the currently active configuration. * @return A list of {@link AExperienceLevel levels} representing the currently active configuration.
*/ */
List<AExperienceLevel> getLevelConfig(); List<AExperienceLevel> getLevelConfig();
} }

View File

@@ -9,50 +9,66 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* Service responsible to manage the {@link AExperienceRole} configuration of a server. This contains functionality to * Service responsible to manage the {@link AExperienceRole experienceRole} configuration of a server. This contains functionality to
* set/unset a level to a certain role, retrieve {@link AExperienceRole} of a certain role and load all for a given * set/unset a level to a certain role, retrieve a {@link AExperienceRole experienceRole} of a certain role and load all for a given
* server. * server.
*/ */
public interface ExperienceRoleManagementService { public interface ExperienceRoleManagementService {
/** /**
* Sets the given {@link AExperienceLevel} to the given {@link ARole} in the {@link AServer}. This will create an * Sets the given {@link AExperienceLevel level} to the given {@link ARole role} in the {@link AServer server}. This will create an
* {@link AExperienceRole} instance and store it. If the role was already set in the server, this sets this role to * {@link AExperienceRole experienceRole} instance and store it. If the role was already set in the server, this sets this role to
* the new level. * the new level.
* @param level The {@link AExperienceLevel} to set the role for * @param level The {@link AExperienceLevel experienceRole} to set the role for
* @param role The {@link ARole} to set to * @param role The {@link ARole role} to set
* @return the created or updated {@link AExperienceRole} * @return the created or updated {@link AExperienceRole experienceRole}
*/ */
AExperienceRole setLevelToRole(AExperienceLevel level, ARole role); AExperienceRole setLevelToRole(AExperienceLevel level, ARole role);
/** /**
* Deletes *all* (if there are multiple by some chance) roles which were set to be given at the provided {@link AExperienceLevel} in the {@link AServer} * Deletes *all* (if there are multiple by some chance) roles which were set to be given at the provided {@link AExperienceLevel level} in the {@link AServer server}
* @param level The level to remove the roles for * @param level The level to remove the roles for
* @param server The server in which this should happen * @param server The server in which this should happen
*/ */
void removeAllRoleAssignmentsForLevelInServer(AExperienceLevel level, AServer server); void removeAllRoleAssignmentsForLevelInServer(AExperienceLevel level, AServer server);
/** /**
* Deletes a singular {@link AExperienceRole} directly. * Deletes a singular {@link AExperienceRole experienceRole} directly.
* @param role The {@link AExperienceRole} to delete. * @param role The {@link AExperienceRole experienceRole} to delete.
*/ */
void unsetRole(AExperienceRole role); void unsetRole(AExperienceRole role);
/** /**
* Retrieves the {@link AExperienceRole} which uses the given {@link ARole} in the {@link AServer} * Retrieves the {@link AExperienceRole experienceRole} which uses the given {@link ARole role} in the {@link AServer server}
* @param role The {@link ARole} to search for * @param role The {@link ARole role} to search for
* @return the {@link AExperienceRole} which uses the given {@link ARole} * @return the {@link AExperienceRole experienceRole} which uses the given {@link ARole role}
*/ */
AExperienceRole getRoleInServer(ARole role); AExperienceRole getRoleInServer(ARole role);
Optional<AExperienceRole> getRoleInServerOptional(ARole role);
AExperienceRole getRoleInServer(Long roleId);
/** /**
* Retrieves all {@link AExperienceRole} configured in the given {@link AServer} * Retrieves a possible {@link AExperienceRole role}, if it exists, for the given {@link ARole}. Returns an empty Optional if it does not exist
* @param server The server to retrieve the list of {@link AExperienceRole} for * @param role The {@link ARole role} to search for
* @return A list of {@link AExperienceRole} which are currently configured for the {@link AServer} * @return An {@link Optional optional} either empty or containing the {@link AExperienceRole role}
*/
Optional<AExperienceRole> getRoleInServerOptional(ARole role);
/**
* Retrieves all {@link AExperienceRole experienceRoles} configured in the given {@link AServer server}
* @param server The server to retrieve the list of {@link AExperienceRole experienceRoles} for
* @return A list of {@link AExperienceRole experienceRoles} which are currently configured for the {@link AServer server}
*/ */
List<AExperienceRole> getExperienceRolesForServer(AServer server); List<AExperienceRole> getExperienceRolesForServer(AServer server);
/**
* Retrieves the {@link AExperienceRole experienceRole} by the given ID of a {@link ARole}.
* @param experienceRoleId The ID of the {@link ARole role} (which is the same as the {@link AExperienceRole experienceRole}) to retrieve the {@link AExperienceRole experienceRole} for
* @return The found {@link AExperienceRole experienceRole}
*/
AExperienceRole getExperienceRoleById(Long experienceRoleId); AExperienceRole getExperienceRoleById(Long experienceRoleId);
/**
* Retrieves the {@link AExperienceRole experienceRole} in an {@link Optional optional} by the given ID of a {@link ARole}.
* @param experienceRoleId The ID of the {@link ARole role} (which is the same as the {@link AExperienceRole experienceRole}) to retrieve the {@link AExperienceRole experienceRole} for
* @return An {@link Optional optional} containing the found {@link AExperienceRole experienceRole} or empty otherwise
*/
Optional<AExperienceRole> getExperienceRoleByIdOptional(Long experienceRoleId); Optional<AExperienceRole> getExperienceRoleByIdOptional(Long experienceRoleId);
} }

View File

@@ -10,17 +10,29 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* Service used to manage the record in the {@link AUserExperience} table * Service used to manage the record in the {@link AUserExperience userExperience} table
*/ */
public interface UserExperienceManagementService { public interface UserExperienceManagementService {
/** /**
* Retrieves the {@link AUserExperience} object for the given {@link AUserInAServer} * Retrieves the {@link AUserExperience userExperience} object for the given {@link AUserInAServer userInAServer}
* @param aUserInAServer The record in the table referenced by the given {@link AUserInAServer}, if none exists, creates one. * @param aUserInAServer The record in the table referenced by the given {@link AUserInAServer userInAServer}, if none exists, creates one.
* @return The {@link AUserExperience} object representing the {@link AUserInAServer} * @return The {@link AUserExperience userExperience} object representing the {@link AUserInAServer userInAServer}
*/ */
AUserExperience findUserInServer(AUserInAServer aUserInAServer); AUserExperience findUserInServer(AUserInAServer aUserInAServer);
/**
* Retrieves a possible {@link AUserExperience userExperience} for the given ID of the {@link AUserInAServer}.
* If none is found, returns an empty {@link Optional optional}
* @param userInServerId The ID of a {@link AUserInAServer} to search for
* @return An {@link Optional optional} containing a {@link AUserExperience userExperience} object if one is found, none otherwise
*/
Optional<AUserExperience> findByUserInServerIdOptional(Long userInServerId); Optional<AUserExperience> findByUserInServerIdOptional(Long userInServerId);
/**
* Retrieves the {@link AUserExperience userExperience} object for the given ID of an {@link AUserInAServer userInAServer}
* @param userInServerId The ID of a {@link AUserInAServer userInAServer} to retrieve the {@link AUserExperience} for.
* @return The {@link AUserExperience userExperience} object representing the {@link AUserInAServer userInAServer}
*/
AUserExperience findByUserInServerId(Long userInServerId); AUserExperience findByUserInServerId(Long userInServerId);
/** /**
@@ -38,11 +50,11 @@ public interface UserExperienceManagementService {
List<AUserExperience> loadAllUsers(AServer server); List<AUserExperience> loadAllUsers(AServer server);
/** /**
* Retrieves a list of {@link AUserExperience} ordered by {@link AUserExperience.experience} and only returns the positions between {@code start} and @{code end}. * Retrieves a list of {@link AUserExperience} ordered by {@link AUserExperience#experience} and only returns the positions between {@code start} and @{code end}.
* @param server The {@link AServer} to retrieve the users for * @param server The {@link AServer} to retrieve the users for
* @param start The start index in the complete ordered list to return the {@link AUserExperience} elements for * @param start The start index in the complete ordered list to return the {@link AUserExperience} elements for
* @param end The end index for which to return a sublist of {@link AUserExperience} elements for * @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} * @return A list desc ordered by {@link AUserExperience#experience} only containing the elements between {@code start} and @{code end}
*/ */
List<AUserExperience> findLeaderBoardUsersPaginated(AServer server, Integer start, Integer end); List<AUserExperience> findLeaderBoardUsersPaginated(AServer server, Integer start, Integer end);