mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-14 19:56:29 +00:00
added starboard functionality (starboard/starstats)
added module to store/retrieve configuration (double and string values) replaced a few null values with optionals (emote loading) fixed creating channels on startup added delete message/get emote utility to bot service extended emote service to have utility methods to use emotes added reactions to message cache added empty message handling to post target service, in case the template evaluates to empty added ability to edit a message in a post target (standard message and embed) added principle of config listeners, so default config can be created, for example starboard thresholds added abstract reaction listeners for adding/removing/clearing fixed foreign keys between channel and server added emote utils to handle AEmote and Emotes renamed emotes to be camelCase, so they are easier to type
This commit is contained in:
@@ -39,16 +39,25 @@ public class MessageDeletedListener extends ListenerAdapter {
|
||||
@Autowired
|
||||
private PostTargetService postTargetService;
|
||||
|
||||
@Autowired
|
||||
private MessageDeletedListener self;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void onGuildMessageDelete(@Nonnull GuildMessageDeleteEvent event) {
|
||||
CachedMessage messageFromCache = null;
|
||||
try {
|
||||
messageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
log.warn("Failed to load message.", e);
|
||||
return;
|
||||
}
|
||||
messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong())
|
||||
.thenAccept(messageFromCache -> {
|
||||
try {
|
||||
self.logMessage(event, messageFromCache);
|
||||
} catch (Exception e) {
|
||||
log.error("Error when logging message deletion.", e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void logMessage(@Nonnull GuildMessageDeleteEvent event, CachedMessage messageFromCache) {
|
||||
MessageDeletedLog logModel = (MessageDeletedLog) contextUtils.fromMessage(messageFromCache, MessageDeletedLog.class);
|
||||
logModel.setMessage(messageFromCache);
|
||||
String simpleMessageUpdatedMessage = templateService.renderTemplate(MESSAGE_DELETED_TEMPLATE, logModel);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.sheldan.abstracto.moderation.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.MessageTextUpdatedListener;
|
||||
import dev.sheldan.abstracto.core.listener.MessageTextUpdatedListener;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.embed.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.service.MessageCache;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package dev.sheldan.abstracto.utility.command;
|
||||
|
||||
import dev.sheldan.abstracto.command.Command;
|
||||
import dev.sheldan.abstracto.command.HelpInfo;
|
||||
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.models.embed.MessageToSend;
|
||||
import dev.sheldan.abstracto.templating.TemplateService;
|
||||
import dev.sheldan.abstracto.utility.Utility;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsModel;
|
||||
import dev.sheldan.abstracto.utility.service.StarboardService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class StarStats implements Command {
|
||||
|
||||
public static final String STARSTATS_RESPONSE_TEMPLATE = "starStats_response";
|
||||
@Autowired
|
||||
private StarboardService starboardService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Override
|
||||
public Result execute(CommandContext commandContext) {
|
||||
StarStatsModel result = starboardService.retrieveStarStats(commandContext.getGuild().getIdLong());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARSTATS_RESPONSE_TEMPLATE, result);
|
||||
commandContext.getChannel().sendMessage(messageToSend.getEmbed()).queue();
|
||||
return Result.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("starStats")
|
||||
.module(Utility.UTILITY)
|
||||
.templated(true)
|
||||
.causesReaction(false)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package dev.sheldan.abstracto.utility.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "abstracto.starboard")
|
||||
public class StarboardConfig {
|
||||
private List<Integer> lvl = new ArrayList<>();
|
||||
private List<String> badge = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.sheldan.abstracto.utility.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.listener.ServerConfigListener;
|
||||
import dev.sheldan.abstracto.core.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.management.ConfigManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class StarboardConfigListener implements ServerConfigListener {
|
||||
|
||||
@Autowired
|
||||
private StarboardConfig starboardConfig;
|
||||
|
||||
@Autowired
|
||||
private ConfigManagementService configManagementService;
|
||||
|
||||
@Override
|
||||
public void updateServerConfig(AServer server) {
|
||||
for (int i = 0; i < starboardConfig.getLvl().size(); i++) {
|
||||
Integer value = starboardConfig.getLvl().get(i);
|
||||
configManagementService.createIfNotExists(server.getId(), "starLvl" + ( i + 1 ), Double.valueOf(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package dev.sheldan.abstracto.utility.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.listener.ReactedAddedListener;
|
||||
import dev.sheldan.abstracto.core.listener.ReactedRemovedListener;
|
||||
import dev.sheldan.abstracto.core.management.EmoteManagementService;
|
||||
import dev.sheldan.abstracto.core.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedReaction;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.Bot;
|
||||
import dev.sheldan.abstracto.core.management.ConfigManagementService;
|
||||
import dev.sheldan.abstracto.core.service.MessageCache;
|
||||
import dev.sheldan.abstracto.core.utils.EmoteUtils;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.service.StarboardService;
|
||||
import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService;
|
||||
import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class StarboardListener implements ReactedAddedListener, ReactedRemovedListener {
|
||||
|
||||
public static final String STAR_EMOTE = "STAR";
|
||||
|
||||
@Autowired
|
||||
private EmoteManagementService emoteManagementService;
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
@Autowired
|
||||
private MessageCache messageCache;
|
||||
|
||||
@Autowired
|
||||
private ConfigManagementService configManagementService;
|
||||
|
||||
@Autowired
|
||||
private StarboardService starboardService;
|
||||
|
||||
@Autowired
|
||||
private StarboardPostManagementService starboardPostManagementService;
|
||||
|
||||
@Autowired
|
||||
private StarboardPostReactorManagementService starboardPostReactorManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void executeReactionAdded(CachedMessage message, MessageReaction addedReaction, AUserInAServer userAdding) {
|
||||
if(userAdding.getUserReference().getId().equals(message.getAuthorId())) {
|
||||
return;
|
||||
}
|
||||
Long guildId = message.getServerId();
|
||||
Optional<AEmote> aEmote = emoteManagementService.loadEmoteByName(STAR_EMOTE, guildId);
|
||||
if(aEmote.isPresent()) {
|
||||
AEmote emote = aEmote.get();
|
||||
MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote();
|
||||
Emote emoteInGuild = bot.getEmote(guildId, emote);
|
||||
if(EmoteUtils.isReactionEmoteAEmote(reactionEmote, emote, Optional.ofNullable(emoteInGuild))) {
|
||||
Optional<CachedReaction> reactionOptional = EmoteUtils.getReactionFromMessageByEmote(message, emote);
|
||||
updateStarboardPost(message, reactionOptional.orElse(null), userAdding, true);
|
||||
}
|
||||
} else {
|
||||
log.warn("Emote {} is not defined for guild {}. Starboard not functional.", STAR_EMOTE, guildId);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStarboardPost(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting, boolean adding) {
|
||||
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
|
||||
if(reaction != null) {
|
||||
List<AUser> userExceptAuthor = getUsersExcept(reaction.getUsers(), message.getAuthorId());
|
||||
Double starMinimum = getFromConfig("starLvl1", message.getServerId());
|
||||
if (userExceptAuthor.size() >= starMinimum) {
|
||||
AUserInAServer author = userManagementService.loadUser(message.getServerId(), message.getAuthorId());
|
||||
if(starboardPostOptional.isPresent()) {
|
||||
StarboardPost starboardPost = starboardPostOptional.get();
|
||||
starboardService.updateStarboardPost(starboardPost, message, userExceptAuthor);
|
||||
if(adding) {
|
||||
starboardPostReactorManagementService.addReactor(starboardPost, userReacting.getUserReference());
|
||||
} else {
|
||||
starboardPostReactorManagementService.removeReactor(starboardPost, userReacting.getUserReference());
|
||||
}
|
||||
} else {
|
||||
starboardService.createStarboardPost(message, userExceptAuthor, userReacting, author);
|
||||
}
|
||||
} else {
|
||||
starboardPostOptional.ifPresent(starboardPost -> {
|
||||
starboardService.removeStarboardPost(starboardPost);
|
||||
starboardPostReactorManagementService.removeReactors(starboardPost);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
starboardPostOptional.ifPresent(starboardPost -> {
|
||||
starboardService.removeStarboardPost(starboardPost);
|
||||
starboardPostReactorManagementService.removeReactors(starboardPost);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void executeReactionRemoved(CachedMessage message, MessageReaction removedReaction, AUserInAServer userRemoving) {
|
||||
if(message.getAuthorId().equals(userRemoving.getUserReference().getId())) {
|
||||
return;
|
||||
}
|
||||
Long guildId = message.getServerId();
|
||||
Optional<AEmote> aEmote = emoteManagementService.loadEmoteByName(STAR_EMOTE, guildId);
|
||||
if(aEmote.isPresent()) {
|
||||
AEmote emote = aEmote.get();
|
||||
MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote();
|
||||
Emote emoteInGuild = bot.getEmote(guildId, emote);
|
||||
if(EmoteUtils.isReactionEmoteAEmote(reactionEmote, emote, Optional.ofNullable(emoteInGuild))) {
|
||||
Optional<CachedReaction> reactionOptional = EmoteUtils.getReactionFromMessageByEmote(message, emote);
|
||||
updateStarboardPost(message, reactionOptional.orElse(null), userRemoving, false);
|
||||
}
|
||||
} else {
|
||||
log.warn("Emote {} is not defined for guild {}. Starboard not functional.", STAR_EMOTE, guildId);
|
||||
}
|
||||
}
|
||||
|
||||
private Double getFromConfig(String key, Long guildId) {
|
||||
return configManagementService.loadConfig(guildId, key).getDoubleValue();
|
||||
}
|
||||
|
||||
private List<AUser> getUsersExcept(List<AUser> users, Long userId) {
|
||||
return users.stream().filter(user -> !user.getId().equals(userId)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package dev.sheldan.abstracto.utility.repository;
|
||||
|
||||
public interface StarStatsUserResult {
|
||||
Long getUserId();
|
||||
Integer getStarCount();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package dev.sheldan.abstracto.utility.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPostReaction;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StarboardPostReactionRepository extends JpaRepository<StarboardPostReaction, Long> {
|
||||
void deleteByReactorAndStarboardPost(AUser user, StarboardPost post);
|
||||
void deleteByStarboardPost(StarboardPost post);
|
||||
|
||||
@Query(value = "SELECT r.reactor_id as userId, COUNT(*) AS starCount \n" +
|
||||
"FROM starboard_post_reaction r \n" +
|
||||
"INNER JOIN starboard_post p ON p.id = r.post_id\n" +
|
||||
"INNER JOIN channel c ON c.id = p.channel_id\n" +
|
||||
"WHERE c.server_id = :serverId\n" +
|
||||
"GROUP BY r.reactor_id \n" +
|
||||
"ORDER BY starCount DESC \n" +
|
||||
"LIMIT :count", nativeQuery = true)
|
||||
List<StarStatsUserResult> findTopStarGiverInServer(Long serverId, Integer count);
|
||||
|
||||
@Query(value = "SELECT COUNT(*) \n" +
|
||||
"FROM starboard_post_reaction r \n" +
|
||||
"INNER JOIN starboard_post p ON p.id = r.post_id\n" +
|
||||
"INNER JOIN channel c ON c.id = p.channel_id\n" +
|
||||
"WHERE c.server_id = :serverId\n"
|
||||
, nativeQuery = true)
|
||||
Integer getReactionCountByServer(Long serverId);
|
||||
|
||||
@Query(value = "SELECT p.poster as userId, COUNT(*) AS starCount \n" +
|
||||
"FROM starboard_post_reaction r \n" +
|
||||
"INNER JOIN starboard_post p ON p.id = r.post_id\n" +
|
||||
"INNER JOIN channel c ON c.id = p.channel_id\n" +
|
||||
"WHERE c.server_id = :serverId\n" +
|
||||
"GROUP BY p.poster \n" +
|
||||
"ORDER BY starCount DESC \n" +
|
||||
"LIMIT :count", nativeQuery = true)
|
||||
List<StarStatsUserResult> retrieveTopStarReceiverInServer(Long serverId, Integer count);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.utility.repository;
|
||||
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StarboardPostRepository extends JpaRepository<StarboardPost, Long> {
|
||||
StarboardPost findByPostMessageId(Long messageId);
|
||||
List<StarboardPost> findByStarboardChannelServerId(Long serverId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.sheldan.abstracto.utility.repository.converter;
|
||||
|
||||
import dev.sheldan.abstracto.core.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.service.Bot;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsUser;
|
||||
import dev.sheldan.abstracto.utility.repository.StarStatsUserResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class StarStatsUserConverter {
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
public List<StarStatsUser> convertToStarStatsUser(List<StarStatsUserResult> users, Long serverId) {
|
||||
List<StarStatsUser> result = new ArrayList<>();
|
||||
users.forEach(starStatsUserResult -> {
|
||||
StarStatsUser newUser = StarStatsUser
|
||||
.builder()
|
||||
.starCount(starStatsUserResult.getStarCount())
|
||||
.member(bot.getMemberInServer(serverId, starStatsUserResult.getUserId()))
|
||||
.user(AUser.builder().id(starStatsUserResult.getUserId()).build())
|
||||
.build();
|
||||
result.add(newUser);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import dev.sheldan.abstracto.utility.service.management.ReminderManagementServic
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -66,7 +67,12 @@ public class RemindServiceBean implements ReminderService {
|
||||
Reminder reminder = reminderManagementService.createReminder(aServerAChannelAUser, remindText, remindAt, reminderModel.getMessage().getIdLong());
|
||||
reminderModel.setReminder(reminder);
|
||||
MessageToSend message = templateService.renderEmbedTemplate(REMINDER_EMBED_KEY, reminderModel);
|
||||
reminderModel.getTextChannel().sendMessage(message.getMessage()).embed(message.getEmbed()).queue();
|
||||
String messageText = message.getMessage();
|
||||
if(StringUtils.isBlank(messageText)) {
|
||||
reminderModel.getTextChannel().sendMessage(message.getEmbed()).queue();
|
||||
} else {
|
||||
reminderModel.getTextChannel().sendMessage(messageText).embed(message.getEmbed()).queue();
|
||||
}
|
||||
|
||||
if(remindIn.getSeconds() < 60) {
|
||||
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package dev.sheldan.abstracto.utility.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.management.EmoteManagementService;
|
||||
import dev.sheldan.abstracto.core.management.PostTargetManagement;
|
||||
import dev.sheldan.abstracto.core.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.core.models.AServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
import dev.sheldan.abstracto.core.models.embed.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.service.Bot;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.core.service.PostTargetService;
|
||||
import dev.sheldan.abstracto.templating.TemplateService;
|
||||
import dev.sheldan.abstracto.utility.config.StarboardConfig;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsModel;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsPost;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsUser;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarboardPostModel;
|
||||
import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService;
|
||||
import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class StarboardServiceBean implements StarboardService {
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
@Autowired
|
||||
private PostTargetService postTargetService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private EmoteManagementService emoteManagementService;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private StarboardPostManagementService starboardPostManagementService;
|
||||
|
||||
@Autowired
|
||||
private StarboardConfig starboardConfig;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private StarboardPostReactorManagementService starboardPostReactorManagementService;
|
||||
|
||||
@Autowired
|
||||
private PostTargetManagement postTargetManagement;
|
||||
|
||||
@Autowired
|
||||
private EmoteService emoteService;
|
||||
|
||||
@Override
|
||||
public void createStarboardPost(CachedMessage message, List<AUser> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser) {
|
||||
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("starboard_post", starboardPostModel);
|
||||
PostTarget starboard = postTargetManagement.getPostTarget("starboard", message.getServerId());
|
||||
postTargetService.sendEmbedInPostTarget(messageToSend, "starboard", message.getServerId()).thenAccept(message1 -> {
|
||||
AServerChannelMessage aServerChannelMessage = AServerChannelMessage
|
||||
.builder()
|
||||
.messageId(message1.getIdLong())
|
||||
.channel(starboard.getChannelReference())
|
||||
.server(userReacting.getServerReference())
|
||||
.build();
|
||||
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, starredUser, userReacting, aServerChannelMessage);
|
||||
// TODO maybe in bulk, but numbers should be small enough
|
||||
userExceptAuthor.forEach(user -> {
|
||||
starboardPostReactorManagementService.addReactor(starboardPost, user);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private StarboardPostModel buildStarboardPostModel(CachedMessage message, Integer starCount) {
|
||||
Member member = bot.getMemberInServer(message.getServerId(), message.getAuthorId());
|
||||
TextChannel channel = bot.getTextChannelFromServer(message.getServerId(), message.getChannelId());
|
||||
Guild guild = bot.getGuildById(message.getServerId());
|
||||
AChannel aChannel = AChannel.builder().id(message.getChannelId()).build();
|
||||
AUser user = AUser.builder().id(message.getAuthorId()).build();
|
||||
AServer server = AServer.builder().id(message.getServerId()).build();
|
||||
Optional<AEmote> appropriateEmoteOptional = getAppropriateEmote(message.getServerId(), starCount);
|
||||
String emoteText;
|
||||
if(appropriateEmoteOptional.isPresent()) {
|
||||
AEmote emote = appropriateEmoteOptional.get();
|
||||
emoteText = emoteService.getEmoteAsMention(emote, message.getServerId(), "⭐");
|
||||
} else {
|
||||
log.warn("No emote defined to be used for starboard post. Falling back to default.");
|
||||
emoteText = "⭐";
|
||||
}
|
||||
return StarboardPostModel
|
||||
.builder()
|
||||
.message(message)
|
||||
.author(member)
|
||||
.channel(channel)
|
||||
.aChannel(aChannel)
|
||||
.starCount(starCount)
|
||||
.guild(guild)
|
||||
.user(user)
|
||||
.server(server)
|
||||
.starLevelEmote(emoteText)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUser> userExceptAuthor) {
|
||||
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("starboard_post", starboardPostModel);
|
||||
CompletableFuture<Message> future = new CompletableFuture<>();
|
||||
postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, "starboard", message.getServerId(), future);
|
||||
future.thenAccept(newOrOldMessage -> {
|
||||
starboardPostManagementService.setStarboardPostMessageId(post, newOrOldMessage.getIdLong());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeStarboardPost(StarboardPost message) {
|
||||
AChannel starboardChannel = message.getStarboardChannel();
|
||||
bot.deleteMessage(starboardChannel.getServer().getId(), starboardChannel.getId(), message.getStarboardMessageId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StarStatsModel retrieveStarStats(Long serverId) {
|
||||
int count = 3;
|
||||
List<StarboardPost> starboardPosts = starboardPostManagementService.retrieveTopPosts(serverId, count);
|
||||
List<StarStatsUser> topStarGivers = starboardPostReactorManagementService.retrieveTopStarGiver(serverId, count);
|
||||
List<StarStatsPost> starStatsPosts = starboardPosts.stream().map(StarStatsPost::fromStarboardPost).collect(Collectors.toList());
|
||||
List<StarStatsUser> topStarReceiver = starboardPostReactorManagementService.retrieveTopStarReceiver(serverId, count);
|
||||
Integer postCount = starboardPostManagementService.getPostCount(serverId);
|
||||
Integer reactionCount = starboardPostReactorManagementService.getStarCount(serverId);
|
||||
List<String> emotes = new ArrayList<>();
|
||||
for (int i = 1; i < count + 1; i++) {
|
||||
Optional<AEmote> starboardRankingEmote = getStarboardRankingEmote(serverId, i);
|
||||
AEmote emote = starboardRankingEmote.orElse(null);
|
||||
String defaultEmoji = starboardConfig.getBadge().get(i - 1);
|
||||
emotes.add(emoteService.getEmoteAsMention(emote, serverId, defaultEmoji));
|
||||
}
|
||||
|
||||
return StarStatsModel
|
||||
.builder()
|
||||
.badgeEmotes(emotes)
|
||||
.starGiver(topStarGivers)
|
||||
.starReceiver(topStarReceiver)
|
||||
.topPosts(starStatsPosts)
|
||||
.starredMessages(postCount)
|
||||
.totalStars(reactionCount)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Optional<AEmote> getStarboardRankingEmote(Long serverId, Integer position) {
|
||||
return emoteManagementService.loadEmoteByName("starboardBadge" + position, serverId);
|
||||
}
|
||||
|
||||
private Optional<AEmote> getAppropriateEmote(Long serverId, Integer starCount) {
|
||||
for(int i = starboardConfig.getLvl().size(); i > 0; i--) {
|
||||
Double starMinimum = configService.getDoubleValue("starLvl" + i, serverId);
|
||||
if(starCount >= starMinimum) {
|
||||
return emoteManagementService.loadEmoteByName("star" + i, serverId);
|
||||
}
|
||||
}
|
||||
return emoteManagementService.loadEmoteByName("star0", serverId);
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ import java.util.Optional;
|
||||
public class SuggestionServiceBean implements SuggestionService {
|
||||
|
||||
public static final String SUGGESTION_LOG_TEMPLATE = "suggest_log";
|
||||
private static final String SUGGESTION_YES_EMOTE = "SUGGESTION_YES";
|
||||
private static final String SUGGESTION_NO_EMOTE = "SUGGESTION_NO";
|
||||
private static final String SUGGESTION_YES_EMOTE = "suggestionYes";
|
||||
private static final String SUGGESTION_NO_EMOTE = "suggestionNo";
|
||||
public static final String SUGGESTIONS_TARGET = "suggestions";
|
||||
@Autowired
|
||||
private SuggestionManagementService suggestionManagementService;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package dev.sheldan.abstracto.utility.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.AServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.repository.StarboardPostRepository;
|
||||
import dev.sheldan.abstracto.utility.repository.converter.StarStatsUserConverter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class StarboardPostManagementServiceBean implements StarboardPostManagementService {
|
||||
|
||||
@Autowired
|
||||
private StarboardPostRepository repository;
|
||||
|
||||
@Autowired
|
||||
private StarStatsUserConverter converter;
|
||||
|
||||
@Override
|
||||
public StarboardPost createStarboardPost(CachedMessage starredMessage, AUserInAServer starredUser, AUserInAServer starringUser, AServerChannelMessage starboardPost) {
|
||||
StarboardPost post = StarboardPost
|
||||
.builder()
|
||||
.author(starredUser.getUserReference())
|
||||
.deleted(false)
|
||||
.postMessageId(starredMessage.getMessageId())
|
||||
.starboardMessageId(starboardPost.getMessageId())
|
||||
.starboardChannel(starboardPost.getChannel())
|
||||
.starredDate(Instant.now())
|
||||
.build();
|
||||
repository.save(post);
|
||||
return post;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStarboardPostMessageId(StarboardPost post, Long messageId) {
|
||||
post.setStarboardMessageId(messageId);
|
||||
repository.save(post);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StarboardPost> retrieveTopPosts(Long serverId, Integer count) {
|
||||
List<StarboardPost> posts = retrieveAllPosts(serverId);
|
||||
posts.sort(Comparator.comparingInt(o -> o.getReactions().size()));
|
||||
Collections.reverse(posts);
|
||||
return posts.subList(0, Math.min(count, posts.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StarboardPost> retrieveAllPosts(Long serverId) {
|
||||
return repository.findByStarboardChannelServerId(serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPostCount(Long serverId) {
|
||||
return retrieveAllPosts(serverId).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<StarboardPost> findByMessageId(Long messageId) {
|
||||
return Optional.ofNullable(repository.findByPostMessageId(messageId));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package dev.sheldan.abstracto.utility.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPostReaction;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsUser;
|
||||
import dev.sheldan.abstracto.utility.repository.StarStatsUserResult;
|
||||
import dev.sheldan.abstracto.utility.repository.StarboardPostReactionRepository;
|
||||
import dev.sheldan.abstracto.utility.repository.converter.StarStatsUserConverter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class StarboardPostReactorManagementServiceBean implements StarboardPostReactorManagementService {
|
||||
|
||||
@Autowired
|
||||
private StarboardPostReactionRepository repository;
|
||||
|
||||
@Autowired
|
||||
private StarStatsUserConverter converter;
|
||||
|
||||
@Override
|
||||
public void addReactor(StarboardPost post, AUser user) {
|
||||
StarboardPostReaction reactor = StarboardPostReaction
|
||||
.builder()
|
||||
.starboardPost(post)
|
||||
.reactor(user)
|
||||
.build();
|
||||
repository.save(reactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReactor(StarboardPost post, AUser user) {
|
||||
repository.deleteByReactorAndStarboardPost(user, post);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReactors(StarboardPost post) {
|
||||
repository.deleteByStarboardPost(post);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getStarCount(Long serverId) {
|
||||
return repository.getReactionCountByServer(serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StarStatsUser> retrieveTopStarGiver(Long serverId, Integer count) {
|
||||
List<StarStatsUserResult> starGivers = repository.findTopStarGiverInServer(serverId, count);
|
||||
return converter.convertToStarStatsUser(starGivers, serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StarStatsUser> retrieveTopStarReceiver(Long serverId, Integer count) {
|
||||
List<StarStatsUserResult> starReceivers = repository.retrieveTopStarReceiverInServer(serverId, count);
|
||||
return converter.convertToStarStatsUser(starReceivers, serverId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Shows the current leaderboard of starboard posts.
|
||||
@@ -0,0 +1 @@
|
||||
Shows the current leaderboard of starboard posts.
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"title": {
|
||||
"title": "Server starboard stats"
|
||||
},
|
||||
"color" : {
|
||||
"r": 200,
|
||||
"g": 0,
|
||||
"b": 255
|
||||
},
|
||||
"description": "${starredMessages} starred messages with ${totalStars} stars in total",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Top starred posts",
|
||||
"value": "
|
||||
<#list topPosts as post>
|
||||
${badgeEmotes[post?index]} - ${post.starCount} :star: [Jump!](${post.messageUrl})
|
||||
<#else>
|
||||
No starred messages.
|
||||
</#list>
|
||||
"
|
||||
},
|
||||
{
|
||||
"name": "Top starrer",
|
||||
"value": "
|
||||
<#list starGiver as starrer>
|
||||
<#if starrer.member?has_content>
|
||||
${badgeEmotes[starrer?index]} - ${starrer.starCount} :star: ${starrer.member.asMention}
|
||||
<#else>
|
||||
${badgeEmotes[starrer?index]} - ${starrer.starCount} :star: ${starrer.user.id?c} (Left the guild)
|
||||
</#if>
|
||||
<#else>
|
||||
No starred messages.
|
||||
</#list>
|
||||
"
|
||||
},
|
||||
{
|
||||
"name": "Top star receiver",
|
||||
"value": "
|
||||
<#list starReceiver as starred>
|
||||
<#if starred.member?has_content>
|
||||
${badgeEmotes[starred?index]} - ${starred.starCount} :star: ${starred.member.asMention}
|
||||
<#else>
|
||||
${badgeEmotes[starred?index]} - ${starred.starCount} :star: ${starred.user.id?c} (Left the guild)
|
||||
</#if>
|
||||
<#else>
|
||||
No starred messages.
|
||||
</#list>
|
||||
"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
starStats
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"author": {
|
||||
<#if author?has_content>
|
||||
"name": "${author.effectiveName}",
|
||||
"avatar": "${author.user.effectiveAvatarUrl}"
|
||||
<#else>
|
||||
"name": "${user.id?c} (Has left the server)"
|
||||
</#if>
|
||||
},
|
||||
"color" : {
|
||||
"r": 200,
|
||||
"g": 0,
|
||||
"b": 255
|
||||
},
|
||||
<#if message.content?has_content || message.embeds?size gt 0>
|
||||
"description": "${message.content}
|
||||
<#list message.embeds>
|
||||
Embeds:
|
||||
<#items as embed>
|
||||
Description: ${embed.description} <#if embed.imageUrl?has_content> ImageUrl: ${embed.imageUrl} </#if>
|
||||
</#items>
|
||||
</#list>
|
||||
",
|
||||
</#if>
|
||||
<#if channel?has_content>
|
||||
"additionalMessage": "${starLevelEmote} ${starCount} ${channel.asMention} ID: ${message.messageId?c}",
|
||||
<#else>
|
||||
"additionalMessage": "${starLevelEmote} ${starCount} ${aChannel.id?c} ID: ${message.messageId?c}",
|
||||
</#if>
|
||||
<#if message.attachmentUrls?size gt 0>
|
||||
"imageUrl": "${message.attachmentUrls[0]}",
|
||||
</#if>
|
||||
"fields": [
|
||||
{
|
||||
"name": "Original",
|
||||
<#if channel?has_content>
|
||||
"value": "[${channel.name}](${message.messageUrl})"
|
||||
<#else>
|
||||
"value": "[${aChannel.id?c}](${message.messageUrl})"
|
||||
</#if>
|
||||
}
|
||||
],
|
||||
"timeStamp": "${message.timeCreated}"
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
abstracto.postTargets.utility=suggestions
|
||||
abstracto.emoteNames.suggestion=SUGGESTION_YES,SUGGESTION_NO
|
||||
abstracto.postTargets.utility=suggestions,starboard
|
||||
abstracto.emoteNames.suggestion=suggestionYes,suggestionNo
|
||||
abstracto.emoteNames.starboard=star,star1,star2,star3,star4,starboardBadge1,starboardBadge2,starboardBadge3
|
||||
abstracto.starboard.lvl[0]=5
|
||||
abstracto.starboard.lvl[1]=8
|
||||
abstracto.starboard.lvl[2]=13
|
||||
abstracto.starboard.lvl[3]=17
|
||||
abstracto.starboard.badge[0]=\ud83e\udd47
|
||||
abstracto.starboard.badge[1]=\ud83e\udd48
|
||||
abstracto.starboard.badge[2]=\ud83e\udd49
|
||||
|
||||
abstracto.scheduling.jobs.reminderJob.name=reminderJob
|
||||
abstracto.scheduling.jobs.reminderJob.group=utility
|
||||
|
||||
@@ -13,7 +13,8 @@ import java.time.Instant;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter @Setter
|
||||
@Getter
|
||||
@Setter
|
||||
public class Reminder {
|
||||
|
||||
@Id
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package dev.sheldan.abstracto.utility.models;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name="starboard_post")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class StarboardPost {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "poster")
|
||||
private AUser author;
|
||||
|
||||
@Column
|
||||
private Long starboardMessageId;
|
||||
|
||||
@Column
|
||||
private Long postMessageId;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "channelId")
|
||||
private AChannel starboardChannel;
|
||||
|
||||
@Transient
|
||||
private Integer reactionCount;
|
||||
|
||||
@PostLoad
|
||||
private void onLoad() {
|
||||
this.reactionCount = this.reactions.size();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
|
||||
@JoinColumn(name="postId")
|
||||
private List<StarboardPostReaction> reactions;
|
||||
|
||||
@Column
|
||||
private Instant starredDate;
|
||||
|
||||
@Column
|
||||
private boolean deleted;
|
||||
|
||||
public int getReactionCount() {
|
||||
if(this.reactions == null) {
|
||||
return 0;
|
||||
}
|
||||
return this.reactions.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package dev.sheldan.abstracto.utility.models;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name="starboard_post_reaction")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class StarboardPostReaction {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "reactorId")
|
||||
private AUser reactor;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "postId")
|
||||
private StarboardPost starboardPost;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.utility.models.template.starboard;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class StarStatsModel {
|
||||
private List<StarStatsPost> topPosts;
|
||||
private List<StarStatsUser> starReceiver;
|
||||
private List<StarStatsUser> starGiver;
|
||||
private Integer totalStars;
|
||||
private List<String> badgeEmotes;
|
||||
private Integer starredMessages;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.sheldan.abstracto.utility.models.template.starboard;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.utils.MessageUtils;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class StarStatsPost {
|
||||
private Long serverId;
|
||||
private Long channelId;
|
||||
private Long messageId;
|
||||
private Integer starCount;
|
||||
|
||||
public String getMessageUrl() {
|
||||
return MessageUtils.buildMessageUrl(serverId ,channelId, messageId);
|
||||
}
|
||||
|
||||
public static StarStatsPost fromStarboardPost(StarboardPost starboardPost) {
|
||||
AChannel channel = starboardPost.getStarboardChannel();
|
||||
return StarStatsPost
|
||||
.builder()
|
||||
.serverId(channel.getServer().getId())
|
||||
.channelId(channel.getId())
|
||||
.messageId(starboardPost.getPostMessageId())
|
||||
.starCount(starboardPost.getReactions().size())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.utility.models.template.starboard;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class StarStatsUser {
|
||||
private AUser user;
|
||||
private Member member;
|
||||
private Integer starCount;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.abstracto.utility.models.template.starboard;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.ServerContext;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
public class StarboardPostModel extends ServerContext {
|
||||
private Member author;
|
||||
private TextChannel channel;
|
||||
private AUser user;
|
||||
private AChannel aChannel;
|
||||
private CachedMessage message;
|
||||
private Integer starCount;
|
||||
private String starLevelEmote;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.utility.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StarboardService {
|
||||
void createStarboardPost(CachedMessage message, List<AUser> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser);
|
||||
void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUser> userExceptAuthor);
|
||||
void removeStarboardPost(StarboardPost message);
|
||||
StarStatsModel retrieveStarStats(Long serverId);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package dev.sheldan.abstracto.utility.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.AServerChannelMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface StarboardPostManagementService {
|
||||
StarboardPost createStarboardPost(CachedMessage starredMessage, AUserInAServer starredUser, AUserInAServer starringUser, AServerChannelMessage starboardPost);
|
||||
void setStarboardPostMessageId(StarboardPost post, Long messageId);
|
||||
List<StarboardPost> retrieveTopPosts(Long serverId, Integer count);
|
||||
List<StarboardPost> retrieveAllPosts(Long serverId);
|
||||
Integer getPostCount(Long serverId);
|
||||
Optional<StarboardPost> findByMessageId(Long messageId);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.utility.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.utility.models.StarboardPost;
|
||||
import dev.sheldan.abstracto.utility.models.template.starboard.StarStatsUser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StarboardPostReactorManagementService {
|
||||
void addReactor(StarboardPost post, AUser user);
|
||||
void removeReactor(StarboardPost post, AUser user);
|
||||
void removeReactors(StarboardPost post);
|
||||
Integer getStarCount(Long serverId);
|
||||
List<StarStatsUser> retrieveTopStarGiver(Long serverId, Integer count);
|
||||
List<StarStatsUser> retrieveTopStarReceiver(Long serverId, Integer count);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ public class ReactionPostExecution implements PostCommandExecution {
|
||||
}
|
||||
} else {
|
||||
if(command.getConfiguration().isCausesReaction()){
|
||||
commandContext.getMessage().addReaction("⭐").queue();
|
||||
commandContext.getMessage().addReaction("✅").queue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.JDABuilder;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
@@ -55,6 +57,20 @@ public class BotService implements Bot {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessage(Long serverId, Long channelId, Long messageId) {
|
||||
getTextChannelFromServer(serverId, channelId).deleteMessageById(messageId).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Emote getEmote(Long serverId, AEmote emote) {
|
||||
if(!emote.getCustom()) {
|
||||
return null;
|
||||
}
|
||||
Guild guildById = getGuildById(serverId);
|
||||
return guildById.getEmoteById(emote.getEmoteId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextChannel getTextChannelFromServer(Long serverId, Long textChannelId) {
|
||||
Guild guild = getGuildById(serverId);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.management.ConfigManagementService;
|
||||
import dev.sheldan.abstracto.core.models.database.AConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ConfigServiceBean implements ConfigService{
|
||||
|
||||
@Autowired
|
||||
private ConfigManagementService configManagementService;
|
||||
|
||||
@Override
|
||||
public Double getDoubleValue(String name, Long serverId) {
|
||||
return getDoubleValue(name, serverId, 0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDoubleValue(String name, Long serverId, Double defaultValue) {
|
||||
AConfig config = configManagementService.loadConfig(serverId, name);
|
||||
if(config == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return config.getDoubleValue();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class EmoteServiceBean implements EmoteService {
|
||||
|
||||
@Autowired
|
||||
@@ -21,4 +25,36 @@ public class EmoteServiceBean implements EmoteService {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEmote buildAEmoteFromReaction(MessageReaction.ReactionEmote reaction) {
|
||||
if(reaction.isEmote()) {
|
||||
return AEmote.builder().emoteKey(reaction.getName()).custom(true).emoteId(reaction.getEmote().getIdLong()).animated(reaction.getEmote().isAnimated()).build();
|
||||
} else {
|
||||
return AEmote.builder().emoteKey(reaction.getEmoji()).custom(false).build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmoteAsMention(AEmote emote, Long serverId, String defaultText) {
|
||||
if(emote != null && emote.getCustom()) {
|
||||
Emote emote1 = botService.getEmote(serverId, emote);
|
||||
if (emote1 != null) {
|
||||
return emote1.getAsMention();
|
||||
} else {
|
||||
log.warn("Emote {} with name {} in server {} defined, but not usable.", emote.getEmoteId(), emote.getName(), serverId);
|
||||
return defaultText;
|
||||
}
|
||||
} else {
|
||||
if(emote == null) {
|
||||
return defaultText;
|
||||
}
|
||||
return emote.getEmoteKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmoteAsMention(AEmote emote, Long serverId) {
|
||||
return this.getEmoteAsMention(emote, serverId, " ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.management.EmoteManagementService;
|
||||
import dev.sheldan.abstracto.core.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedReaction;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.embed.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.requests.restaction.pagination.ReactionPaginationAction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -18,54 +25,71 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@Component @Slf4j
|
||||
@CacheConfig(cacheNames = {"messages"})
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageCacheBean implements MessageCache {
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private EmoteManagementService emoteManagementService;
|
||||
|
||||
@Autowired
|
||||
private EmoteService emoteService;
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
private MessageCache self;
|
||||
|
||||
@Override
|
||||
@CachePut(key = "#message.id")
|
||||
public CachedMessage putMessageInCache(Message message) {
|
||||
log.debug("Adding message {} to cache", message.getId());
|
||||
return buildCachedMessageFromMessage(message);
|
||||
@CachePut(key = "#message.id", cacheNames = "messages")
|
||||
public CompletableFuture<CachedMessage> putMessageInCache(Message message) {
|
||||
log.info("Adding message {} to cache", message.getId());
|
||||
CompletableFuture<CachedMessage> future = new CompletableFuture<>();
|
||||
self.buildCachedMessageFromMessage(future, message);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
@CachePut(key = "#message.messageId")
|
||||
public CachedMessage putMessageInCache(CachedMessage message) {
|
||||
return message;
|
||||
public CompletableFuture<CachedMessage> putMessageInCache(CachedMessage message) {
|
||||
log.info("Adding cached message to cache");
|
||||
return CompletableFuture.completedFuture(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedMessage getMessageFromCache(Message message) throws ExecutionException, InterruptedException {
|
||||
log.debug("Retrieving message {}", message.getId());
|
||||
@Cacheable(key = "#message.id", cacheNames = "messages")
|
||||
public CompletableFuture<CachedMessage> getMessageFromCache(Message message) {
|
||||
log.info("Retrieving message {}", message.getId());
|
||||
return getMessageFromCache(message.getGuild().getIdLong(), message.getChannel().getIdLong(), message.getIdLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(key = "#messageId.toString()")
|
||||
public CachedMessage getMessageFromCache(Long guildId, Long textChannelId, Long messageId) throws ExecutionException, InterruptedException {
|
||||
@Cacheable(key = "#messageId.toString()", cacheNames = "messages")
|
||||
public CompletableFuture<CachedMessage> getMessageFromCache(Long guildId, Long textChannelId, Long messageId) {
|
||||
log.info("Retrieving message with parameters");
|
||||
|
||||
CompletableFuture<CachedMessage> cachedMessageCompletableFuture =
|
||||
getMessage(guildId, textChannelId, messageId)
|
||||
.thenApply(jdaMessage -> {
|
||||
CachedMessage cachedMessage = buildCachedMessageFromMessage(jdaMessage);
|
||||
putMessageInCache(cachedMessage);
|
||||
return cachedMessage;
|
||||
});
|
||||
CompletableFuture<CachedMessage> cachedMessageCompletableFuture = new CompletableFuture<>();
|
||||
self.loadMessage(cachedMessageCompletableFuture, guildId, textChannelId, messageId);
|
||||
return cachedMessageCompletableFuture;
|
||||
}
|
||||
|
||||
return cachedMessageCompletableFuture.get();
|
||||
@Async
|
||||
@Override
|
||||
public void loadMessage(CompletableFuture<CachedMessage> future, Long guildId, Long textChannelId, Long messageId) {
|
||||
TextChannel textChannelById = bot.getTextChannelFromServer(guildId, textChannelId);
|
||||
textChannelById.retrieveMessageById(messageId).queue(message -> {
|
||||
buildCachedMessageFromMessage(future, message);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> getMessage(Long guildId, Long textChannelId, Long messageId) {
|
||||
TextChannel textChannelById = bot.getTextChannelFromServer(guildId, textChannelId);
|
||||
return textChannelById.retrieveMessageById(messageId).submit();
|
||||
}
|
||||
|
||||
private CachedMessage buildCachedMessageFromMessage(Message message) {
|
||||
@Async
|
||||
public void buildCachedMessageFromMessage(CompletableFuture<CachedMessage> future, Message message) {
|
||||
List<String> attachmentUrls = new ArrayList<>();
|
||||
message.getAttachments().forEach(attachment -> {
|
||||
attachmentUrls.add(attachment.getProxyUrl());
|
||||
@@ -74,16 +98,55 @@ public class MessageCacheBean implements MessageCache {
|
||||
message.getEmbeds().forEach(embed -> {
|
||||
embeds.add(getCachedEmbedFromEmbed(embed));
|
||||
});
|
||||
return CachedMessage.builder()
|
||||
.authorId(message.getAuthor().getIdLong())
|
||||
.serverId(message.getGuild().getIdLong())
|
||||
.messageId(message.getIdLong())
|
||||
.channelId(message.getChannel().getIdLong())
|
||||
.content(message.getContentRaw())
|
||||
.embeds(embeds)
|
||||
.timeCreated(message.getTimeCreated())
|
||||
.attachmentUrls(attachmentUrls)
|
||||
.build();
|
||||
|
||||
List<CompletableFuture<CachedReaction>> futures = new ArrayList<>();
|
||||
message.getReactions().forEach(messageReaction -> {
|
||||
CompletableFuture<CachedReaction> future1 = new CompletableFuture<>();
|
||||
self.getCachedReactionFromReaction(future1, messageReaction);
|
||||
futures.add(future1);
|
||||
});
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
|
||||
future.complete(CachedMessage.builder()
|
||||
.authorId(message.getAuthor().getIdLong())
|
||||
.serverId(message.getGuild().getIdLong())
|
||||
.messageId(message.getIdLong())
|
||||
.channelId(message.getChannel().getIdLong())
|
||||
.content(message.getContentRaw())
|
||||
.embeds(embeds)
|
||||
.reactions(getFutures(futures))
|
||||
.timeCreated(message.getTimeCreated())
|
||||
.attachmentUrls(attachmentUrls)
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
private List<CachedReaction> getFutures(List<CompletableFuture<CachedReaction>> futures) {
|
||||
List<CachedReaction> reactions = new ArrayList<>();
|
||||
futures.forEach(future -> {
|
||||
try {
|
||||
CachedReaction cachedReaction = future.get();
|
||||
reactions.add(cachedReaction);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("Error while executing future to retrieve reaction.", e);
|
||||
}
|
||||
});
|
||||
return reactions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async
|
||||
public void getCachedReactionFromReaction(CompletableFuture<CachedReaction> future, MessageReaction reaction) {
|
||||
ReactionPaginationAction users = reaction.retrieveUsers().cache(false);
|
||||
CachedReaction.CachedReactionBuilder builder = CachedReaction.builder();
|
||||
|
||||
List<AUser> ausers = new ArrayList<>();
|
||||
users.forEachAsync(user -> {
|
||||
ausers.add(AUser.builder().id(user.getIdLong()).build());
|
||||
return false;
|
||||
}).thenAccept(o -> future.complete(builder.build()));
|
||||
builder.users(ausers);
|
||||
builder.emote(emoteService.buildAEmoteFromReaction(reaction.getReactionEmote()));
|
||||
}
|
||||
|
||||
private CachedEmbed getCachedEmbedFromEmbed(MessageEmbed embed) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageServiceBean implements MessageService {
|
||||
@@ -22,16 +24,21 @@ public class MessageServiceBean implements MessageService {
|
||||
@Override
|
||||
public void addReactionToMessage(String emoteKey, Long serverId, Message message) {
|
||||
Guild guildById = bot.getGuildById(serverId);
|
||||
AEmote emote = emoteManagementService.loadEmoteByName(emoteKey, serverId);
|
||||
if(emote.getCustom()) {
|
||||
Emote emoteById = guildById.getEmoteById(emote.getEmoteId());
|
||||
if(emoteById != null) {
|
||||
message.addReaction(emoteById).queue();
|
||||
Optional<AEmote> aEmote = emoteManagementService.loadEmoteByName(emoteKey, serverId);
|
||||
if(aEmote.isPresent()) {
|
||||
AEmote emote = aEmote.get();
|
||||
if(emote.getCustom()) {
|
||||
Emote emoteById = guildById.getEmoteById(emote.getEmoteId());
|
||||
if(emoteById != null) {
|
||||
message.addReaction(emoteById).queue();
|
||||
} else {
|
||||
log.warn("Emote with key {} and id {} for guild {} was not found.", emoteKey, emote.getEmoteId(), guildById.getId());
|
||||
}
|
||||
} else {
|
||||
log.warn("Emote with key {} and id {} for guild {} was not found.", emoteKey, emote.getEmoteId(), guildById.getId());
|
||||
message.addReaction(emote.getEmoteKey()).queue();
|
||||
}
|
||||
} else {
|
||||
message.addReaction(emote.getEmoteKey()).queue();
|
||||
log.warn("Cannot add reaction, emote {} not defined for server {}.", emoteKey, serverId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -93,7 +94,60 @@ public class PostTargetServiceBean implements PostTargetService {
|
||||
@Override
|
||||
public CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, PostTarget target) {
|
||||
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
|
||||
return textChannelForPostTarget.sendMessage(message.getMessage()).embed(message.getEmbed()).submit();
|
||||
String messageText = message.getMessage();
|
||||
if(StringUtils.isBlank(messageText)) {
|
||||
return textChannelForPostTarget.sendMessage(message.getEmbed()).submit();
|
||||
} else {
|
||||
return textChannelForPostTarget.sendMessage(messageText).embed(message.getEmbed()).submit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, PostTarget target) {
|
||||
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
|
||||
String messageText = message.getMessage();
|
||||
if(StringUtils.isBlank(messageText)) {
|
||||
return textChannelForPostTarget.editMessageById(messageId, message.getEmbed()).submit();
|
||||
} else {
|
||||
return textChannelForPostTarget.editMessageById(messageId, messageText).embed(message.getEmbed()).submit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, PostTarget target, CompletableFuture<Message> future) {
|
||||
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
|
||||
if(StringUtils.isBlank(messageToSend.getMessage().trim())) {
|
||||
textChannelForPostTarget
|
||||
.retrieveMessageById(messageId)
|
||||
.queue(
|
||||
existingMessage -> existingMessage
|
||||
.editMessage(messageToSend.getEmbed())
|
||||
.submit().thenAccept(future::complete),
|
||||
throwable -> sendEmbedInPostTarget(messageToSend, target)
|
||||
.thenAccept(future::complete));
|
||||
} else {
|
||||
textChannelForPostTarget
|
||||
.retrieveMessageById(messageId)
|
||||
.queue(
|
||||
existingMessage -> existingMessage
|
||||
.editMessage(messageToSend.getMessage())
|
||||
.embed(messageToSend.getEmbed())
|
||||
.submit().thenAccept(future::complete),
|
||||
throwable -> sendEmbedInPostTarget(messageToSend, target)
|
||||
.thenAccept(future::complete));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, String postTargetName, Long serverId, CompletableFuture<Message> future) {
|
||||
PostTarget postTarget = this.getPostTarget(postTargetName, serverId);
|
||||
this.editOrCreatedInPostTarget(messageId, messageToSend, postTarget, future);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, String postTargetName, Long serverId) {
|
||||
PostTarget postTarget = this.getPostTarget(postTargetName, serverId);
|
||||
return editEmbedInPostTarget(messageId, message, postTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.SnowflakeUtils;
|
||||
import dev.sheldan.abstracto.core.listener.ServerConfigListener;
|
||||
import dev.sheldan.abstracto.core.utils.SnowflakeUtils;
|
||||
import dev.sheldan.abstracto.core.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.core.management.RoleManagementService;
|
||||
import dev.sheldan.abstracto.core.management.ServerManagementService;
|
||||
@@ -42,6 +43,9 @@ public class StartupManager implements Startup {
|
||||
@Autowired
|
||||
private RoleManagementService roleManagementService;
|
||||
|
||||
@Autowired
|
||||
private List<ServerConfigListener> configListeners;
|
||||
|
||||
|
||||
@Override
|
||||
public void startBot() throws LoginException {
|
||||
@@ -68,6 +72,9 @@ public class StartupManager implements Startup {
|
||||
if(newGuild != null){
|
||||
synchronizeRolesOf(newGuild, newAServer);
|
||||
synchronizeChannelsOf(newGuild, newAServer);
|
||||
configListeners.forEach(serverConfigListener -> {
|
||||
serverConfigListener.updateServerConfig(newAServer);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package dev.sheldan.abstracto.core.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.models.database.AConfig;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.management.ConfigManagementService;
|
||||
import dev.sheldan.abstracto.repository.ConfigRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ConfigManagementServiceBean implements ConfigManagementService {
|
||||
|
||||
@Autowired
|
||||
private ConfigRepository configRepository;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Override
|
||||
public void setOrCreateStringValue(Long serverId, String name, String value) {
|
||||
AConfig config = loadConfig(serverId, name);
|
||||
if(config == null) {
|
||||
createConfig(serverId, name, value);
|
||||
} else {
|
||||
config.setStringValue(value);
|
||||
configRepository.save(config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrCreateDoubleValue(Long serverId, String name, Double value) {
|
||||
AConfig config = loadConfig(serverId, name);
|
||||
if(config == null) {
|
||||
createConfig(serverId, name, value);
|
||||
} else {
|
||||
config.setDoubleValue(value);
|
||||
configRepository.save(config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AConfig createConfig(Long serverId, String name, String value) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AConfig config = AConfig
|
||||
.builder()
|
||||
.stringValue(value)
|
||||
.server(server)
|
||||
.name(name)
|
||||
.build();
|
||||
configRepository.save(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AConfig createConfig(Long serverId, String name, Double value) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AConfig config = AConfig
|
||||
.builder()
|
||||
.doubleValue(value)
|
||||
.server(server)
|
||||
.name(name)
|
||||
.build();
|
||||
configRepository.save(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AConfig createIfNotExists(Long serverId, String name, String value) {
|
||||
AConfig config = loadConfig(serverId, name);
|
||||
if(config == null) {
|
||||
return this.createConfig(serverId, name, value);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AConfig createIfNotExists(Long serverId, String name, Double value) {
|
||||
AConfig config = loadConfig(serverId, name);
|
||||
if(config == null) {
|
||||
return this.createConfig(serverId, name, value);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AConfig loadConfig(Long serverId, String name) {
|
||||
return configRepository.findAConfigByServerIdAndName(serverId, name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class EmoteManagementServiceBean implements EmoteManagementService {
|
||||
@@ -73,24 +74,25 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEmote loadEmoteByName(String name, Long serverId) {
|
||||
public Optional<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);
|
||||
public Optional<AEmote> loadEmoteByName(String name, AServer server) {
|
||||
return Optional.ofNullable(repository.findAEmoteByNameAndServerRef(name, server));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEmote setEmoteToCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AEmote emote;
|
||||
if(!emoteExists(name, server)) {
|
||||
Optional<AEmote> emoteOptional = loadEmoteByName(name, server);
|
||||
if(!emoteOptional.isPresent()) {
|
||||
emote = this.createCustomEmote(name, emoteKey, emoteId, animated, server);
|
||||
} else {
|
||||
emote = loadEmoteByName(name, server);
|
||||
emote = emoteOptional.get();
|
||||
emote.setEmoteKey(emoteKey);
|
||||
emote.setEmoteId(emoteId);
|
||||
emote.setAnimated(animated);
|
||||
@@ -104,11 +106,14 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
|
||||
public AEmote setEmoteToCustomEmote(String name, Emote emote, Long serverId) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AEmote emoteBeingSet;
|
||||
if(!emoteExists(name, server)) {
|
||||
emoteBeingSet = this.createDefaultEmote(name, emote.getName(), server);
|
||||
Optional<AEmote> emoteOptional = loadEmoteByName(name, serverId);
|
||||
if(!emoteOptional.isPresent()) {
|
||||
emoteBeingSet = this.createCustomEmote(name, emote.getName(), emote.getIdLong(), emote.isAnimated(), server);
|
||||
} else {
|
||||
emoteBeingSet = loadEmoteByName(name, serverId);
|
||||
emoteBeingSet.setCustom(false);
|
||||
emoteBeingSet = emoteOptional.get();
|
||||
emoteBeingSet.setCustom(true);
|
||||
emoteBeingSet.setEmoteId(emote.getIdLong());
|
||||
emoteBeingSet.setAnimated(emote.isAnimated());
|
||||
emoteBeingSet.setEmoteKey(emote.getName());
|
||||
repository.save(emoteBeingSet);
|
||||
}
|
||||
@@ -117,11 +122,18 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
|
||||
|
||||
@Override
|
||||
public AEmote setEmoteToDefaultEmote(String name, String emoteKey, Long serverId) {
|
||||
AEmote existing = loadEmoteByName(name, serverId);
|
||||
existing.setEmoteKey(emoteKey);
|
||||
existing.setCustom(false);
|
||||
repository.save(existing);
|
||||
return existing;
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AEmote emoteBeingSet;
|
||||
Optional<AEmote> emoteOptional = loadEmoteByName(name, serverId);
|
||||
if(!emoteOptional.isPresent()) {
|
||||
emoteBeingSet = this.createDefaultEmote(name, emoteKey, server);
|
||||
} else {
|
||||
emoteBeingSet = emoteOptional.get();
|
||||
emoteBeingSet.setEmoteKey(emoteKey);
|
||||
emoteBeingSet.setCustom(false);
|
||||
repository.save(emoteBeingSet);
|
||||
}
|
||||
return emoteBeingSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,6 +10,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ServerManagementServiceBean implements ServerManagementService {
|
||||
@@ -43,6 +45,8 @@ public class ServerManagementServiceBean implements ServerManagementService {
|
||||
@Override
|
||||
public void addChannelToServer(AServer server, AChannel channel) {
|
||||
server.getChannels().add(channel);
|
||||
channel.setServer(server);
|
||||
repository.save(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,5 +87,10 @@ public class ServerManagementServiceBean implements ServerManagementService {
|
||||
return getPostTarget(server, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AServer> getAllServers() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto;
|
||||
package dev.sheldan.abstracto.core.utils;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.SnowFlake;
|
||||
import net.dv8tion.jda.api.entities.ISnowflake;
|
||||
@@ -73,13 +73,11 @@ public class MessageEmbedListener extends ListenerAdapter {
|
||||
Long serverIdLong = Long.parseLong(serverId);
|
||||
Long channelIdLong = Long.parseLong(channelId);
|
||||
Long messageIdLong = Long.parseLong(messageId);
|
||||
try {
|
||||
CachedMessage messageFromCache = messageCache.getMessageFromCache(serverIdLong, channelIdLong, messageIdLong);
|
||||
messageRaw = messageRaw.replace(wholeLink, "");
|
||||
self.createEmbedAndPostEmbed(event, messageFromCache);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
log.warn("Failed to load message from cache", e);
|
||||
}
|
||||
messageRaw = messageRaw.replace(wholeLink, "");
|
||||
messageCache.getMessageFromCache(serverIdLong, channelIdLong, messageIdLong).thenAccept(cachedMessage -> {
|
||||
self.createEmbedAndPostEmbed(event, cachedMessage);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
if(StringUtils.isBlank(messageRaw) && matched) {
|
||||
@@ -92,7 +90,11 @@ public class MessageEmbedListener extends ListenerAdapter {
|
||||
public void createEmbedAndPostEmbed(@Nonnull GuildMessageReceivedEvent event, CachedMessage message) {
|
||||
MessageEmbeddedModel messageEmbeddedModel = buildTemplateParameter(event, message);
|
||||
MessageToSend embed = templateService.renderEmbedTemplate(MESSAGE_EMBED_TEMPLATE, messageEmbeddedModel);
|
||||
event.getChannel().sendMessage(embed.getMessage()).embed(embed.getEmbed()).queue();
|
||||
if(StringUtils.isBlank(embed.getMessage())) {
|
||||
event.getChannel().sendMessage(embed.getEmbed()).queue();
|
||||
} else {
|
||||
event.getChannel().sendMessage(embed.getMessage()).embed(embed.getEmbed()).queue();
|
||||
}
|
||||
}
|
||||
|
||||
private MessageEmbeddedModel buildTemplateParameter(GuildMessageReceivedEvent event, CachedMessage embeddedMessage) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.sheldan.abstracto.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.MessageTextUpdatedListener;
|
||||
import dev.sheldan.abstracto.core.listener.MessageTextUpdatedListener;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.service.MessageCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -9,10 +9,10 @@ import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
|
||||
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;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@@ -24,17 +24,23 @@ public class MessageUpdatedListener extends ListenerAdapter {
|
||||
@Autowired
|
||||
private MessageCache messageCache;
|
||||
|
||||
@Autowired
|
||||
private MessageUpdatedListener self;
|
||||
|
||||
@Override
|
||||
public void onGuildMessageUpdate(@Nonnull GuildMessageUpdateEvent event) {
|
||||
Message message = event.getMessage();
|
||||
try {
|
||||
CachedMessage fromCache = messageCache.getMessageFromCache(message.getGuild().getIdLong(), message.getTextChannel().getIdLong(), event.getMessageIdLong());
|
||||
listener.forEach(messageTextUpdatedListener -> {
|
||||
messageTextUpdatedListener.execute(fromCache, message);
|
||||
});
|
||||
messageCache.getMessageFromCache(message.getGuild().getIdLong(), message.getTextChannel().getIdLong(), event.getMessageIdLong()).thenAccept(cachedMessage -> {
|
||||
self.executeListener(message, cachedMessage);
|
||||
messageCache.putMessageInCache(message);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
log.warn("Failed to load message", e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void executeListener(Message message, CachedMessage cachedMessage) {
|
||||
listener.forEach(messageTextUpdatedListener -> {
|
||||
messageTextUpdatedListener.execute(cachedMessage, message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package dev.sheldan.abstracto.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.listener.ReactedAddedListener;
|
||||
import dev.sheldan.abstracto.core.listener.ReactedRemovedListener;
|
||||
import dev.sheldan.abstracto.core.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedReaction;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.core.service.MessageCache;
|
||||
import dev.sheldan.abstracto.core.utils.EmoteUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveAllEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent;
|
||||
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;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ReactionUpdatedListener extends ListenerAdapter {
|
||||
|
||||
@Autowired
|
||||
private MessageCache messageCache;
|
||||
|
||||
@Autowired
|
||||
private EmoteService emoteService;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private List<ReactedAddedListener> addedListenerList;
|
||||
|
||||
@Autowired
|
||||
private List<ReactedRemovedListener> reactionRemovedListener;
|
||||
|
||||
@Autowired
|
||||
private ReactionUpdatedListener self;
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) {
|
||||
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
|
||||
asyncMessageFromCache.thenAccept(cachedMessage -> {
|
||||
CompletableFuture<CachedReaction> future = new CompletableFuture<>();
|
||||
messageCache.getCachedReactionFromReaction(future, event.getReaction());
|
||||
future.thenAccept(reaction -> {
|
||||
self.callAddedListeners(event, cachedMessage, reaction);
|
||||
messageCache.putMessageInCache(cachedMessage);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void addReactionIfNotThere(CachedMessage message, CachedReaction reaction, AUser userReacting) {
|
||||
Optional<CachedReaction> existingReaction = message.getReactions().stream().filter(reaction1 -> {
|
||||
return EmoteUtils.compareAEmote(reaction1.getEmote(), reaction.getEmote());
|
||||
}).findAny();
|
||||
if(!existingReaction.isPresent()) {
|
||||
message.getReactions().add(reaction);
|
||||
} else {
|
||||
CachedReaction cachedReaction = existingReaction.get();
|
||||
Optional<AUser> any = cachedReaction.getUsers().stream().filter(user -> user.getId().equals(userReacting.getId())).findAny();
|
||||
if(!any.isPresent()){
|
||||
cachedReaction.getUsers().add(userReacting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeReactionIfThere(CachedMessage message, CachedReaction reaction, AUser userReacting) {
|
||||
Optional<CachedReaction> existingReaction = message.getReactions().stream().filter(reaction1 -> {
|
||||
return EmoteUtils.compareAEmote(reaction1.getEmote(), reaction.getEmote());
|
||||
}).findAny();
|
||||
if(existingReaction.isPresent()) {
|
||||
CachedReaction cachedReaction = existingReaction.get();
|
||||
cachedReaction.getUsers().removeIf(user -> user.getId().equals(userReacting.getId()));
|
||||
message.getReactions().removeIf(reaction1 -> reaction1.getUsers().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void callAddedListeners(@Nonnull GuildMessageReactionAddEvent event, CachedMessage cachedMessage, CachedReaction reaction) {
|
||||
AUserInAServer userInAServer = userManagementService.loadUser(event.getGuild().getIdLong(), event.getUserIdLong());
|
||||
addReactionIfNotThere(cachedMessage, reaction, userInAServer.getUserReference());
|
||||
try {
|
||||
addedListenerList.forEach(reactedAddedListener -> {
|
||||
reactedAddedListener.executeReactionAdded(cachedMessage, event.getReaction(), userInAServer);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.warn("Exception on reaction added handler:", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void onGuildMessageReactionRemove(@Nonnull GuildMessageReactionRemoveEvent event) {
|
||||
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
|
||||
asyncMessageFromCache.thenAccept(cachedMessage -> {
|
||||
CompletableFuture<CachedReaction> future = new CompletableFuture<>();
|
||||
messageCache.getCachedReactionFromReaction(future, event.getReaction());
|
||||
future.thenAccept(reaction -> {
|
||||
self.callRemoveListeners(event, cachedMessage, reaction);
|
||||
});
|
||||
|
||||
messageCache.putMessageInCache(cachedMessage);
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void callRemoveListeners(@Nonnull GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReaction reaction) {
|
||||
AUserInAServer userInAServer = userManagementService.loadUser(event.getGuild().getIdLong(), event.getUserIdLong());
|
||||
removeReactionIfThere(cachedMessage, reaction, userInAServer.getUserReference());
|
||||
reactionRemovedListener.forEach(reactedAddedListener -> {
|
||||
reactedAddedListener.executeReactionRemoved(cachedMessage, event.getReaction(), userInAServer);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void onGuildMessageReactionRemoveAll(@Nonnull GuildMessageReactionRemoveAllEvent event) {
|
||||
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
|
||||
asyncMessageFromCache.thenAccept(cachedMessage -> {
|
||||
cachedMessage.getReactions().clear();
|
||||
messageCache.putMessageInCache(cachedMessage);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package dev.sheldan.abstracto.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AConfig;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ConfigRepository extends JpaRepository<AConfig, Long> {
|
||||
AConfig findAConfigByServerIdAndName(Long serverId, String name);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "${author.effectiveName}",
|
||||
"avatar": "${author.user.avatarUrl}"
|
||||
"avatar": "${author.user.effectiveAvatarUrl}"
|
||||
},
|
||||
"color" : {
|
||||
"r": 200,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.core;
|
||||
package dev.sheldan.abstracto.core.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.core.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
|
||||
public interface ReactedAddedListener {
|
||||
void executeReactionAdded(CachedMessage message, MessageReaction reaction, AUserInAServer userAdding);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.core.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
|
||||
public interface ReactedRemovedListener {
|
||||
void executeReactionRemoved(CachedMessage message, MessageReaction reaction, AUserInAServer userRemoving);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.sheldan.abstracto.core.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
|
||||
public interface ServerConfigListener {
|
||||
void updateServerConfig(AServer server);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.core.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AConfig;
|
||||
|
||||
public interface ConfigManagementService {
|
||||
void setOrCreateStringValue(Long serverId, String name, String value);
|
||||
void setOrCreateDoubleValue(Long serverId, String name, Double value);
|
||||
AConfig createConfig(Long serverId, String name, String value);
|
||||
AConfig createConfig(Long serverId, String name, Double value);
|
||||
AConfig createIfNotExists(Long serverId, String name, String value);
|
||||
AConfig createIfNotExists(Long serverId, String name, Double value);
|
||||
AConfig loadConfig(Long serverId, String name);
|
||||
}
|
||||
@@ -4,14 +4,16 @@ import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface EmoteManagementService {
|
||||
AEmote loadEmote(Long id);
|
||||
AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId);
|
||||
AEmote createCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, AServer server);
|
||||
AEmote createDefaultEmote(String name, String emoteKey, Long serverId);
|
||||
AEmote createDefaultEmote(String name, String emoteKey, AServer server);
|
||||
AEmote loadEmoteByName(String name, Long serverId);
|
||||
AEmote loadEmoteByName(String name, AServer server);
|
||||
Optional<AEmote> loadEmoteByName(String name, Long serverId);
|
||||
Optional<AEmote> loadEmoteByName(String name, AServer server);
|
||||
AEmote setEmoteToCustomEmote(String name, String emoteKey, Long emoteId, Boolean animated, Long serverId);
|
||||
AEmote setEmoteToCustomEmote(String name, Emote emote, Long serverId);
|
||||
AEmote setEmoteToDefaultEmote(String name, String emoteKey, Long serverId);
|
||||
|
||||
@@ -2,6 +2,8 @@ package dev.sheldan.abstracto.core.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ServerManagementService {
|
||||
AServer createServer(Long id);
|
||||
AServer loadServer(Long id);
|
||||
@@ -12,4 +14,5 @@ public interface ServerManagementService {
|
||||
AChannel getPostTarget(Long serverId, PostTarget target);
|
||||
AChannel getPostTarget(AServer server, PostTarget target);
|
||||
AChannel getPostTarget(AServer server, String name);
|
||||
List<AServer> getAllServers();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.core.models;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class AServerChannelMessage {
|
||||
private AServer server;
|
||||
private AChannel channel;
|
||||
private Long messageId;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@@ -21,6 +22,7 @@ public class CachedMessage {
|
||||
private String content;
|
||||
private List<CachedEmbed> embeds;
|
||||
private List<String> attachmentUrls;
|
||||
private List<CachedReaction> reactions;
|
||||
|
||||
public String getMessageUrl() {
|
||||
return MessageUtils.buildMessageUrl(this.serverId ,this.channelId, this.messageId);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.sheldan.abstracto.core.models;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class CachedReaction {
|
||||
private AEmote emote;
|
||||
private List<AUser> users;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.sheldan.abstracto.core.models;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ServerChannelMessage {
|
||||
private Long serverId;
|
||||
private Long channelId;
|
||||
private Long messageId;
|
||||
}
|
||||
@@ -17,6 +17,7 @@ public class AChannel implements SnowFlake {
|
||||
|
||||
@Id
|
||||
@Getter
|
||||
@Column(name = "id")
|
||||
public Long id;
|
||||
|
||||
@Getter
|
||||
@@ -24,7 +25,9 @@ public class AChannel implements SnowFlake {
|
||||
private Set<AChannelGroup> groups;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@Getter @Setter
|
||||
@Getter
|
||||
@Setter
|
||||
@JoinColumn(name = "server_id")
|
||||
private AServer server;
|
||||
|
||||
@Getter
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package dev.sheldan.abstracto.core.models.database;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name="systemConfig")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
public class AConfig {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer Id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@Setter
|
||||
private String stringValue;
|
||||
|
||||
@Column
|
||||
@Setter
|
||||
private Double doubleValue;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "server_id", nullable = false)
|
||||
@Getter
|
||||
@Setter
|
||||
private AServer server;
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import java.util.List;
|
||||
public class AServer implements SnowFlake {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
@@ -26,10 +27,10 @@ public class AServer implements SnowFlake {
|
||||
|
||||
@OneToMany(
|
||||
fetch = FetchType.LAZY,
|
||||
mappedBy = "server",
|
||||
cascade = CascadeType.ALL,
|
||||
orphanRemoval = true)
|
||||
@Builder.Default
|
||||
@JoinColumn(name = "server_id")
|
||||
private List<AChannel> channels = new ArrayList<>();
|
||||
|
||||
@OneToMany(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerChannelUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
@@ -15,6 +17,8 @@ public interface Bot {
|
||||
JDA getInstance();
|
||||
ServerChannelUser getServerChannelUser(Long serverId, Long channelId, Long userId);
|
||||
Member getMemberInServer(Long serverId, Long memberId);
|
||||
void deleteMessage(Long serverId, Long channelId, Long messageId);
|
||||
Emote getEmote(Long serverId, AEmote emote);
|
||||
TextChannel getTextChannelFromServer(Long serverId, Long textChannelId);
|
||||
Guild getGuildById(Long serverId);
|
||||
void shutdown();
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
public interface ConfigService {
|
||||
Double getDoubleValue(String name, Long serverId);
|
||||
Double getDoubleValue(String name, Long serverId, Double defaultValue);
|
||||
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
|
||||
public interface EmoteService {
|
||||
boolean isEmoteUsableByBot(Emote emote);
|
||||
AEmote buildAEmoteFromReaction(MessageReaction.ReactionEmote reaction);
|
||||
String getEmoteAsMention(AEmote emote, Long serverId, String defaultText);
|
||||
String getEmoteAsMention(AEmote emote, Long serverId);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedReaction;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public interface MessageCache {
|
||||
CachedMessage putMessageInCache(Message message);
|
||||
CachedMessage getMessageFromCache(Message message) throws ExecutionException, InterruptedException;
|
||||
CachedMessage getMessageFromCache(Long guildId, Long textChannelId, Long messageId) throws ExecutionException, InterruptedException;
|
||||
CompletableFuture<Message> getMessage(Long serverId, Long textChannelId, Long messageId);
|
||||
CompletableFuture<CachedMessage> putMessageInCache(Message message);
|
||||
CompletableFuture<CachedMessage> getMessageFromCache(Long guildId, Long textChannelId, Long messageId);
|
||||
CompletableFuture<CachedMessage> getMessageFromCache(Message message);
|
||||
CompletableFuture<CachedMessage> putMessageInCache(CachedMessage message);
|
||||
void loadMessage(CompletableFuture<CachedMessage> future, Long guildId, Long textChannelId, Long messageId);
|
||||
void getCachedReactionFromReaction(CompletableFuture<CachedReaction> future, MessageReaction reaction);
|
||||
void buildCachedMessageFromMessage(CompletableFuture<CachedMessage> future, Message message);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ public interface PostTargetService {
|
||||
CompletableFuture<Message> sendEmbedInPostTarget(MessageEmbed embed, String postTargetName, Long serverId);
|
||||
CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, String postTargetName, Long serverId);
|
||||
CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, PostTarget target);
|
||||
CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, PostTarget target);
|
||||
CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, String postTargetName, Long serverId);
|
||||
void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, PostTarget target, CompletableFuture<Message> future);
|
||||
void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, String postTarget, Long serverId, CompletableFuture<Message> future);
|
||||
boolean validPostTarget(String name);
|
||||
List<String> getAvailablePostTargets();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package dev.sheldan.abstracto.core.utils;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.CachedReaction;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import net.dv8tion.jda.api.entities.Emote;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class EmoteUtils {
|
||||
|
||||
public static boolean isReactionEmoteAEmote(MessageReaction.ReactionEmote reaction, AEmote emote, Optional<Emote> emoteInGuildOptional) {
|
||||
if(reaction.isEmote() && emote.getCustom()) {
|
||||
if(emoteInGuildOptional.isPresent()) {
|
||||
Emote emoteInGuild = emoteInGuildOptional.get();
|
||||
return emoteInGuild.equals(reaction.getEmote());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return reaction.getEmoji().equals(emote.getEmoteKey());
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<CachedReaction> getReactionFromMessageByEmote(CachedMessage message, AEmote emote) {
|
||||
return message.getReactions().stream().filter(reaction -> compareAEmote(reaction.getEmote(), emote)).findFirst();
|
||||
}
|
||||
|
||||
public static boolean compareAEmote(AEmote a, AEmote b) {
|
||||
if(a.getCustom() && b.getCustom()) {
|
||||
return a.getEmoteId().equals(b.getEmoteId());
|
||||
} else {
|
||||
if(!a.getCustom() && !b.getCustom()) {
|
||||
return a.getEmoteKey().equals(b.getEmoteKey());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
spring.quartz.job-store-type=jdbc
|
||||
spring.quartz.jdbc.initialize-schema=never
|
||||
@@ -1,6 +1,3 @@
|
||||
spring.quartz.job-store-type=jdbc
|
||||
spring.quartz.jdbc.initialize-schema=never
|
||||
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceName=quartz-abstracto-app
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceIdGenerator.class=dev.sheldan.abstracto.scheduling.service.IdGenerationService
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
@org.springframework.context.annotation.Configuration
|
||||
public class FreemarkerConfiguration {
|
||||
@@ -20,6 +21,7 @@ public class FreemarkerConfiguration {
|
||||
FreeMarkerConfigurationFactory factory = new FreeMarkerConfigurationFactory();
|
||||
factory.setPreTemplateLoaders(templateLoader);
|
||||
Configuration configuration = factory.createConfiguration();
|
||||
configuration.setEncoding(Locale.getDefault(), "utf-8");
|
||||
// needed to support default methods in interfaces
|
||||
configuration.setIncompatibleImprovements(Configuration.VERSION_2_3_29);
|
||||
return configuration;
|
||||
|
||||
@@ -98,19 +98,6 @@ public class TemplateServiceBean implements TemplateService {
|
||||
.build();
|
||||
}
|
||||
|
||||
private String impromptu(String templateStr, Object model) {
|
||||
try {
|
||||
Template t = new Template("name", new StringReader(templateStr),
|
||||
new Configuration(Configuration.VERSION_2_3_29));
|
||||
return FreeMarkerTemplateUtils.processTemplateIntoString(t, model);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TemplateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String renderTemplate(String key, HashMap<String, Object> parameters) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user