added experience tracking and automatic role assigning at given levels

includes: set role command to set a role to a given level (it clears out previous levels)
automatic level config generation on startup
min/max/multiplier configuration
job to persist the xp of the previous minute
added delayed scheduler start, so that events have a discord context in order to function
added role listener to automatically add and mark roles when they are created/deleted
fixed user in a server not being created correctly
added role service to give users role given by id
added server reference to role
This commit is contained in:
Sheldan
2020-04-11 17:21:55 +02:00
parent 87c97d5069
commit 6a31dfde8a
72 changed files with 1165 additions and 80 deletions

View File

@@ -82,6 +82,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.scheduling</groupId>
<artifactId>scheduling-int</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.service.Bot;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
@@ -51,12 +51,12 @@ public class ReactionUpdatedListener extends ListenerAdapter {
private FeatureFlagService featureFlagService;
@Autowired
private Bot bot;
private BotService botService;
@Override
@Transactional
public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) {
if(event.getUserIdLong() == bot.getInstance().getSelfUser().getIdLong()) {
if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) {
return;
}
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
@@ -115,7 +115,7 @@ public class ReactionUpdatedListener extends ListenerAdapter {
@Override
@Transactional
public void onGuildMessageReactionRemove(@Nonnull GuildMessageReactionRemoveEvent event) {
if(event.getUserIdLong() == bot.getInstance().getSelfUser().getIdLong()) {
if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) {
return;
}
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.service.StartupServiceBean;
import dev.sheldan.abstracto.scheduling.service.SchedulerService;
import net.dv8tion.jda.api.events.ReadyEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,10 +19,14 @@ public class ReadyListener extends ListenerAdapter {
@Value("${abstracto.startup.synchronize}")
private boolean synchronize;
@Autowired
private SchedulerService schedulerService;
@Override
public void onReady(@Nonnull ReadyEvent event) {
if(synchronize){
startup.synchronize();
}
schedulerService.startScheduler();
}
}

View File

@@ -0,0 +1,42 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.role.RoleCreateEvent;
import net.dv8tion.jda.api.events.role.RoleDeleteEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
@Component
@Slf4j
public class RoleListener extends ListenerAdapter {
@Autowired
private RoleManagementService service;
@Autowired
private RoleService roleService;
@Autowired
private ServerManagementService serverManagementService;
@Override
@Transactional
public void onRoleCreate(@Nonnull RoleCreateEvent event) {
AServer server = serverManagementService.loadOrCreate(event.getGuild().getIdLong());
service.createRole(event.getRole().getIdLong(), server);
}
@Override
@Transactional
public void onRoleDelete(@Nonnull RoleDeleteEvent event) {
roleService.markDeleted(event.getRole());
}
}

View File

@@ -21,7 +21,7 @@ import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
public class BotServiceBean implements Bot {
public class BotServiceBean implements BotService {
private JDA instance;

View File

@@ -23,7 +23,7 @@ import java.util.concurrent.CompletableFuture;
public class ChannelServiceBean implements ChannelService {
@Autowired
private Bot botService;
private BotService botService;
@Override
public void sendTextInAChannel(String text, AChannel channel) {

View File

@@ -24,4 +24,9 @@ public class ConfigServiceBean implements ConfigService{
}
return config.getDoubleValue();
}
@Override
public void createDoubleValueIfNotExist(String name, Long serverId, Double value) {
configManagementService.createIfNotExists(serverId, name, value);
}
}

View File

@@ -18,7 +18,7 @@ import java.util.Optional;
public class EmoteServiceBean implements EmoteService {
@Autowired
private Bot botService;
private BotService botService;
@Autowired
private EmoteManagementService emoteManagementService;

View File

@@ -30,7 +30,7 @@ import java.util.concurrent.ExecutionException;
public class MessageCacheBean implements MessageCache {
@Autowired
private Bot bot;
private BotService botService;
@Autowired
private UserManagementService userManagementService;
@@ -81,9 +81,9 @@ public class MessageCacheBean implements MessageCache {
@Async
@Override
public void loadMessage(CompletableFuture<CachedMessage> future, Long guildId, Long textChannelId, Long messageId) {
Optional<Guild> guildOptional = bot.getGuildById(guildId);
Optional<Guild> guildOptional = botService.getGuildById(guildId);
if(guildOptional.isPresent()) {
Optional<TextChannel> textChannelByIdOptional = bot.getTextChannelFromServer(guildOptional.get(), textChannelId);
Optional<TextChannel> textChannelByIdOptional = botService.getTextChannelFromServer(guildOptional.get(), textChannelId);
if(textChannelByIdOptional.isPresent()) {
TextChannel textChannel = textChannelByIdOptional.get();
textChannel.retrieveMessageById(messageId).queue(message -> {

View File

@@ -19,7 +19,7 @@ import java.util.concurrent.CompletableFuture;
public class MessageServiceBean implements MessageService {
@Autowired
private Bot bot;
private BotService botService;
@Autowired
private EmoteManagementService emoteManagementService;
@@ -29,14 +29,14 @@ public class MessageServiceBean implements MessageService {
@Override
public void addReactionToMessage(String emoteKey, Long serverId, Message message) {
Optional<Guild> guildByIdOptional = bot.getGuildById(serverId);
Optional<Guild> guildByIdOptional = botService.getGuildById(serverId);
Optional<AEmote> aEmote = emoteManagementService.loadEmoteByName(emoteKey, serverId);
if(guildByIdOptional.isPresent()) {
Guild guild = guildByIdOptional.get();
if(aEmote.isPresent()) {
AEmote emote = aEmote.get();
if(emote.getCustom()) {
Emote emoteById = bot.getInstance().getEmoteById(emote.getEmoteId());
Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId());
if(emoteById != null) {
message.addReaction(emoteById).queue();
} else {
@@ -57,6 +57,6 @@ public class MessageServiceBean implements MessageService {
@Override
public CompletableFuture<Void> deleteMessageInChannelInServer(Long serverId, Long channelId, Long messageId) {
return bot.deleteMessage(serverId, channelId, messageId);
return botService.deleteMessage(serverId, channelId, messageId);
}
}

View File

@@ -32,7 +32,7 @@ public class PostTargetServiceBean implements PostTargetService {
private PostTargetManagement postTargetManagement;
@Autowired
private Bot botService;
private BotService botService;
@Autowired
private DynamicKeyLoader dynamicKeyLoader;

View File

@@ -0,0 +1,72 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.exception.GuildException;
import dev.sheldan.abstracto.core.exception.RoleException;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class RoleServiceBean implements RoleService {
@Autowired
private BotService botService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public void addRoleToUser(AUserInAServer aUserInAServer, ARole role) {
Optional<Guild> guildById = botService.getGuildById(aUserInAServer.getServerReference().getId());
if(guildById.isPresent()) {
Guild guild = guildById.get();
Role roleById = guild.getRoleById(role.getId());
if(roleById != null) {
guild.addRoleToMember(aUserInAServer.getUserReference().getId(), roleById).queue();
} else {
throw new RoleException(String.format("Failed to load role %s in guild %s", role.getId(), aUserInAServer.getServerReference().getId()));
}
} else {
throw new GuildException(String.format("Failed to load guild %s.", aUserInAServer.getServerReference().getId()));
}
}
@Override
public void removeRoleFromUser(AUserInAServer aUserInAServer, ARole role) {
Optional<Guild> guildById = botService.getGuildById(aUserInAServer.getServerReference().getId());
if(guildById.isPresent()) {
Guild guild = guildById.get();
Role roleById = guild.getRoleById(role.getId());
if(roleById != null) {
guild.removeRoleFromMember(aUserInAServer.getUserReference().getId(), roleById).queue();
} else {
throw new RoleException(String.format("Failed to load role %s in guild %s", role.getId(), aUserInAServer.getServerReference().getId()));
}
} else {
throw new GuildException(String.format("Failed to load guild %s.", aUserInAServer.getServerReference().getId()));
}
}
@Override
public void markDeleted(Role role) {
markDeleted(role.getIdLong());
}
@Override
public void markDeleted(Long id) {
ARole role = roleManagementService.findRole(id);
if(role != null) {
roleManagementService.markDeleted(role);
} else {
throw new RoleException(String.format("Cannot find role %s to mark as deleted.", id));
}
}
}

View File

@@ -30,7 +30,7 @@ import java.util.stream.Collectors;
public class StartupServiceBean implements Startup {
@Autowired
private Bot service;
private BotService service;
@Autowired
private List<? extends ListenerAdapter> listeners;
@@ -88,7 +88,7 @@ public class StartupServiceBean implements Startup {
Set<Long> availableRoles = SnowflakeUtils.getSnowflakeIds(existingRoles);
Set<Long> newRoles = SetUtils.disjunction(availableRoles, knownRolesId);
newRoles.forEach(aLong -> {
ARole newRole = roleManagementService.createRole(aLong);
ARole newRole = roleManagementService.createRole(aLong, existingAServer);
log.debug("Adding new role: {}", aLong);
existingAServer.getRoles().add(newRole);
});

View File

@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.DynamicKeyLoader;
import dev.sheldan.abstracto.core.exception.EmoteException;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.Bot;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.repository.EmoteRepository;
import net.dv8tion.jda.api.entities.Emote;
import org.springframework.beans.factory.annotation.Autowired;
@@ -26,7 +26,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
private DynamicKeyLoader dynamicKeyLoader;
@Autowired
private Bot botService;
private BotService botService;
@Override
public AEmote loadEmote(Long id) {

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.repository.RoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -12,7 +13,18 @@ public class RoleManagementServiceBean implements RoleManagementService {
private RoleRepository repository;
@Override
public ARole createRole(Long id) {
return repository.save(ARole.builder().id(id).build());
public ARole createRole(Long id, AServer server) {
return repository.save(ARole.builder().id(id).server(server).deleted(false).build());
}
@Override
public ARole findRole(Long id) {
return repository.getOne(id);
}
@Override
public void markDeleted(ARole role) {
role.setDeleted(true);
repository.save(role);
}
}

View File

@@ -52,7 +52,9 @@ public class UserManagementServiceBean implements UserManagementService {
@Override
public AUserInAServer createUserInServer(Long guildId, Long userId) {
return serverManagementService.addUserToServer(guildId, userId);
AUserInAServer aUserInAServer = serverManagementService.addUserToServer(guildId, userId);
userInServerRepository.save(aUserInAServer);
return aUserInAServer;
}
@Override