added mechanism to dynamically load properties defining postTargets and valid emoteNames

changed the output of the exception message
refactored emote management service
added service to define whether or not an emote is usable by the bot
This commit is contained in:
Sheldan
2020-03-22 10:26:58 +01:00
parent 9e9eb615c0
commit d95382b589
25 changed files with 246 additions and 100 deletions

View File

@@ -0,0 +1,40 @@
package dev.sheldan.abstracto.core;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@Component
@Getter
@Setter
@ConfigurationProperties(prefix = "abstracto")
public class DynamicKeyLoader {
private HashMap<String, String> postTargets = new HashMap<>();
private HashMap<String, String> emoteNames = new HashMap<>();
public List<String> getPostTargetsAsList() {
return getHashMapAsList(postTargets);
}
public List<String> getEmoteNamesAsList() {
return getHashMapAsList(emoteNames);
}
@NotNull
private List<String> getHashMapAsList(HashMap<String, String> emoteNames) {
List<String> emotes = new ArrayList<>();
if (emoteNames == null || emoteNames.size() == 0) {
return emotes;
}
emoteNames.values().forEach(s -> emotes.addAll(Arrays.asList(s.split(","))));
return emotes;
}
}

View File

@@ -1,31 +0,0 @@
package dev.sheldan.abstracto.core;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@Component
@Getter
@Setter
@PropertySource("classpath:abstracto.properties")
@ConfigurationProperties(prefix = "abstracto")
public class PostTargetLoader {
private HashMap<String, String> postTargets = new HashMap<>();
public List<String> getPostTargetsAsList() {
List<String> targets = new ArrayList<>();
if(postTargets == null || postTargets.size() == 0) {
return targets;
}
postTargets.values().forEach(s -> targets.addAll(Arrays.asList(s.split(","))));
return targets;
}
}

View File

@@ -5,7 +5,9 @@ import dev.sheldan.abstracto.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.command.execution.CommandContext;
import dev.sheldan.abstracto.command.execution.Parameter;
import dev.sheldan.abstracto.command.execution.Result;
import dev.sheldan.abstracto.core.exception.ConfigurationException;
import dev.sheldan.abstracto.core.management.EmoteManagementService;
import dev.sheldan.abstracto.core.service.EmoteService;
import net.dv8tion.jda.api.entities.Emote;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -19,6 +21,9 @@ public class SetEmote implements Command {
@Autowired
private EmoteManagementService emoteManagementService;
@Autowired
private EmoteService emoteService;
@Override
public Result execute(CommandContext commandContext) {
String emoteKey = (String) commandContext.getParameters().getParameters().get(0);
@@ -28,7 +33,11 @@ public class SetEmote implements Command {
emoteManagementService.setEmoteToDefaultEmote(emoteKey, emote, commandContext.getGuild().getIdLong());
} else {
Emote emote = (Emote) o;
emoteManagementService.setEmoteToCustomEmote(emoteKey, emote, commandContext.getGuild().getIdLong());
if(emoteService.isEmoteUsableByBot(emote)) {
emoteManagementService.setEmoteToCustomEmote(emoteKey, emote, commandContext.getGuild().getIdLong());
} else {
throw new ConfigurationException("Emote is not usable by bot.");
}
}
return Result.fromSuccess();
}

View File

@@ -1,7 +0,0 @@
package dev.sheldan.abstracto.core.exception;
public class PostTargetException extends RuntimeException {
public PostTargetException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.core.service;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EmoteServiceBean implements EmoteService {
@Autowired
private Bot botService;
@Override
public boolean isEmoteUsableByBot(Emote emote) {
for (Guild guild : botService.getInstance().getGuilds()) {
Emote emoteById = guild.getEmoteById(emote.getId());
if(emoteById != null) {
return true;
}
}
return false;
}
}

View File

@@ -1,5 +1,7 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.DynamicKeyLoader;
import dev.sheldan.abstracto.core.exception.ConfigurationException;
import dev.sheldan.abstracto.core.management.EmoteManagementService;
import dev.sheldan.abstracto.core.management.ServerManagementService;
import dev.sheldan.abstracto.core.models.database.AEmote;
@@ -9,6 +11,8 @@ import net.dv8tion.jda.api.entities.Emote;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class EmoteManagementServiceBean implements EmoteManagementService {
@@ -18,37 +22,97 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private DynamicKeyLoader dynamicKeyLoader;
@Override
public AEmote loadEmote(Long id) {
return repository.getOne(id);
}
@Override
public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId) {
AServer server = serverManagementService.loadServer(serverId);
return this.createCustomEmote(name, emoteKey, emoteId, animated, server);
}
@Override
public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, AServer server) {
validateEmoteName(name);
AEmote emoteToCreate = AEmote
.builder()
.custom(true)
.name(name)
.animated(animated)
.emoteId(emoteId)
.emoteKey(emoteKey)
.serverRef(server)
.build();
repository.save(emoteToCreate);
return emoteToCreate;
}
@Override
public AEmote createDefaultEmote(String name, String emoteKey, Long serverId) {
AServer server = serverManagementService.loadServer(serverId);
return createDefaultEmote(name, emoteKey, server);
}
@Override
public AEmote createDefaultEmote(String name, String emoteKey, AServer server) {
validateEmoteName(name);
AEmote emoteToCreate = AEmote
.builder()
.custom(false)
.name(name)
.emoteKey(emoteKey)
.serverRef(server)
.build();
repository.save(emoteToCreate);
return emoteToCreate;
}
@Override
public AEmote loadEmoteByName(String name, Long serverId) {
AServer server = serverManagementService.loadServer(serverId);
return loadEmoteByName(name, server);
}
@Override
public AEmote loadEmoteByName(String name, AServer server) {
return repository.findAEmoteByNameAndServerRef(name, server);
}
@Override
public AEmote setEmoteToCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId) {
AEmote existing = loadEmoteByName(name, serverId);
existing.setEmoteKey(emoteKey);
existing.setEmoteId(emoteId);
existing.setAnimated(animated);
existing.setCustom(true);
repository.save(existing);
return existing;
AServer server = serverManagementService.loadServer(serverId);
AEmote emote;
if(!emoteExists(name, server)) {
emote = this.createCustomEmote(name, emoteKey, emoteId, animated, server);
} else {
emote = loadEmoteByName(name, server);
emote.setEmoteKey(emoteKey);
emote.setEmoteId(emoteId);
emote.setAnimated(animated);
emote.setCustom(true);
repository.save(emote);
}
return emote;
}
@Override
public AEmote setEmoteToCustomEmote(String name, Emote emote, Long serverId) {
AEmote existing = loadEmoteByName(name, serverId);
existing.setCustom(true);
existing.setAnimated(emote.isAnimated());
existing.setEmoteId(emote.getIdLong());
existing.setEmoteKey(emote.getName());
repository.save(existing);
return existing;
AServer server = serverManagementService.loadServer(serverId);
AEmote emoteBeingSet;
if(!emoteExists(name, server)) {
emoteBeingSet = this.createDefaultEmote(name, emote.getName(), server);
} else {
emoteBeingSet = loadEmoteByName(name, serverId);
emoteBeingSet.setCustom(false);
emoteBeingSet.setEmoteKey(emote.getName());
repository.save(emoteBeingSet);
}
return emoteBeingSet;
}
@Override
@@ -60,6 +124,17 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
return existing;
}
@Override
public boolean emoteExists(String name, Long serverId) {
AServer server = serverManagementService.loadServer(serverId);
return emoteExists(name, server);
}
@Override
public boolean emoteExists(String name, AServer server) {
return repository.existsByNameAndServerRef(name, server);
}
@Override
public AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated) {
AEmote emote = AEmote.builder()
@@ -83,4 +158,11 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
repository.save(emote);
return emote;
}
private void validateEmoteName(String name) {
List<String> possibleEmotes = dynamicKeyLoader.getEmoteNamesAsList();
if(!possibleEmotes.contains(name)) {
throw new ConfigurationException("Emote `" + name + "` is not defined. Possible values are: " + String.join(", ", possibleEmotes));
}
}
}

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.PostTargetLoader;
import dev.sheldan.abstracto.core.exception.PostTargetException;
import dev.sheldan.abstracto.core.DynamicKeyLoader;
import dev.sheldan.abstracto.core.exception.ConfigurationException;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.PostTarget;
@@ -14,6 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Slf4j
public class PostTargetManagementBean implements PostTargetManagement {
@@ -27,12 +29,13 @@ public class PostTargetManagementBean implements PostTargetManagement {
private ServerManagementService serverManagementService;
@Autowired
private PostTargetLoader postTargetLoader;
private DynamicKeyLoader dynamicKeyLoader;
@Override
public void createPostTarget(String name, AServer server, AChannel targetChannel) {
if(!postTargetLoader.getPostTargetsAsList().contains(name)) {
throw new PostTargetException("PostTarget not found");
List<String> possiblePostTargets = dynamicKeyLoader.getPostTargetsAsList();
if(!possiblePostTargets.contains(name)) {
throw new ConfigurationException("PostTarget not found. Possible values are: " + String.join(", ", possiblePostTargets));
}
log.info("Creating post target {} pointing towards {}", name, targetChannel);
postTargetRepository.save(PostTarget.builder().name(name).channelReference(targetChannel).serverReference(server).build());

View File

@@ -1,6 +1,5 @@
package dev.sheldan.abstracto.listener;
import dev.sheldan.abstracto.core.models.database.PostTarget;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.management.ServerManagementService;
import dev.sheldan.abstracto.templating.TemplateService;
@@ -23,6 +22,8 @@ public class JoinLeaveListener extends ListenerAdapter {
private static final String USER_JOIN_TEMPLATE = "user_join";
private static final String USER_LEAVE_TEMPLATE = "user_leave";
private static final String JOIN_LOG_TARGET = "joinLog";
private static final String LEAVE_LOG_TARGET = "leaveLog";
@Autowired
private ServerManagementService serverManagementService;
@@ -37,14 +38,14 @@ public class JoinLeaveListener extends ListenerAdapter {
@Transactional
public void onGuildMemberJoin(@Nonnull GuildMemberJoinEvent event) {
String text = getRenderedEvent(event.getUser(), USER_JOIN_TEMPLATE);
postTargetService.sendTextInPostTarget(text, PostTarget.JOIN_LOG, event.getGuild().getIdLong());
postTargetService.sendTextInPostTarget(text, JOIN_LOG_TARGET, event.getGuild().getIdLong());
}
@Override
@Transactional
public void onGuildMemberLeave(@Nonnull GuildMemberLeaveEvent event) {
String text = getRenderedEvent(event.getUser(), USER_LEAVE_TEMPLATE);
postTargetService.sendTextInPostTarget(text, PostTarget.LEAVE_LOG, event.getGuild().getIdLong());
postTargetService.sendTextInPostTarget(text, LEAVE_LOG_TARGET, event.getGuild().getIdLong());
}
@NotNull

View File

@@ -2,10 +2,12 @@ package dev.sheldan.abstracto.repository;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface EmoteRepository extends JpaRepository<AEmote, Long> {
AEmote findAEmoteByNameAndServerRef(String name, AServer server);
boolean existsByNameAndServerRef(String name, AServer server);
}