[AB-197] splitting utility maven module into separate maven modules

aligning some package names
removing some unnecessary computed values from liquibase
This commit is contained in:
Sheldan
2021-03-12 17:29:49 +01:00
parent e2da800d84
commit 2ed456c164
835 changed files with 12790 additions and 3310 deletions

View File

@@ -0,0 +1,18 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>liquibase</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>.</outputDirectory>
<directory>${project.basedir}/src/main/resources/migrations</directory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,73 @@
package dev.sheldan.abstracto.starboard.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.starboard.config.StarboardFeatureDefinition;
import dev.sheldan.abstracto.starboard.model.template.MemberStarStatsModel;
import dev.sheldan.abstracto.starboard.service.StarboardService;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class StarStats extends AbstractConditionableCommand {
public static final String STARSTATS_RESPONSE_TEMPLATE = "starStats_response";
public static final String STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE = "starStats_single_member_response";
@Autowired
private StarboardService starboardService;
@Autowired
private ChannelService channelService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
if(parameters.isEmpty()) {
return starboardService.retrieveStarStats(commandContext.getGuild().getIdLong())
.thenCompose(starStatsModel ->
FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(STARSTATS_RESPONSE_TEMPLATE, starStatsModel, commandContext.getChannel()))
).thenApply(o -> CommandResult.fromIgnored());
} else {
Member targetMember = (Member) parameters.get(0);
MemberStarStatsModel memberStarStatsModel = starboardService.retrieveStarStatsForMember(targetMember);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE, memberStarStatsModel, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
}
}
@Override
public CommandConfiguration getConfiguration() {
Parameter memberParameter = Parameter.builder().templated(true).name("member").type(Member.class).optional(true).build();
List<Parameter> parameters = Collections.singletonList(memberParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("starStats")
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return StarboardFeatureDefinition.STARBOARD;
}
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.starboard.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:starboard-config.properties")
public class StarboardConfig {
}

View File

@@ -0,0 +1,56 @@
package dev.sheldan.abstracto.starboard.converter;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
import dev.sheldan.abstracto.starboard.model.template.StarStatsUser;
import dev.sheldan.abstracto.starboard.repository.result.StarStatsGuildUserResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class StarStatsUserConverter {
@Autowired
private MemberService memberService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private UserManagementService userManagementService;
@Autowired
private StarStatsUserConverter self;
public List<CompletableFuture<StarStatsUser>> convertToStarStatsUser(List<StarStatsGuildUserResult> users, Long serverId) {
List<CompletableFuture<StarStatsUser>> result = new ArrayList<>();
users.forEach(starStatsUserResult ->
result.add(createStarStatsUser(serverId, starStatsUserResult))
);
return result;
}
private CompletableFuture<StarStatsUser> createStarStatsUser(Long serverId, StarStatsGuildUserResult starStatsGuildUserResult) {
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(starStatsGuildUserResult.getUserId());
return memberService.getMemberInServerAsync(serverId, aUserInAServer.getUserReference().getId())
.thenApply(member -> self.loadStarStatsUser(starStatsGuildUserResult, member))
.exceptionally(throwable -> self.loadStarStatsUser(starStatsGuildUserResult, null));
}
@Transactional
public StarStatsUser loadStarStatsUser(StarStatsGuildUserResult starStatsGuildUserResult, net.dv8tion.jda.api.entities.Member member) {
return StarStatsUser
.builder()
.starCount(starStatsGuildUserResult.getStarCount())
.member(member)
.user(userInServerManagementService.loadOrCreateUser(starStatsGuildUserResult.getUserId()))
.build();
}
}

View File

@@ -0,0 +1,213 @@
package dev.sheldan.abstracto.starboard.listener;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionClearedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionRemovedListener;
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.metric.service.MetricTag;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.starboard.config.StarboardFeature;
import dev.sheldan.abstracto.starboard.config.StarboardFeatureDefinition;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import dev.sheldan.abstracto.starboard.service.StarboardService;
import dev.sheldan.abstracto.starboard.service.management.StarboardPostManagementService;
import dev.sheldan.abstracto.starboard.service.management.StarboardPostReactorManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
@Slf4j
public class StarboardListener implements AsyncReactionAddedListener, AsyncReactionRemovedListener, AsyncReactionClearedListener {
public static final String FIRST_LEVEL_THRESHOLD_KEY = "starLvl1";
@Autowired
private BotService botService;
@Autowired
private ConfigManagementService configManagementService;
@Autowired
private StarboardService starboardService;
@Autowired
private StarboardPostManagementService starboardPostManagementService;
@Autowired
private StarboardPostReactorManagementService starboardPostReactorManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private EmoteService emoteService;
@Autowired
private MetricService metricService;
public static final String STARBOARD_STARS = "starboard.stars";
public static final String STARBOARD_POSTS = "starboard.posts";
public static final String STAR_ACTION = "action";
private static final CounterMetric STARBOARD_STARS_ADDED = CounterMetric
.builder()
.name(STARBOARD_STARS)
.tagList(Arrays.asList(MetricTag.getTag(STAR_ACTION, "added")))
.build();
private static final CounterMetric STARBOARD_STARS_REMOVED = CounterMetric
.builder()
.name(STARBOARD_STARS)
.tagList(Arrays.asList(MetricTag.getTag(STAR_ACTION, "removed")))
.build();
private static final CounterMetric STARBOARD_STARS_THRESHOLD_REACHED = CounterMetric
.builder()
.name(STARBOARD_POSTS)
.tagList(Arrays.asList(MetricTag.getTag(STAR_ACTION, "threshold.reached")))
.build();
private static final CounterMetric STARBOARD_STARS_THRESHOLD_FELL = CounterMetric
.builder()
.name(STARBOARD_POSTS)
.tagList(Arrays.asList(MetricTag.getTag(STAR_ACTION, "threshold.below")))
.build();
@Override
@Transactional
public void executeReactionAdded(CachedMessage message, CachedReactions cachedReaction, ServerUser serverUser) {
if(serverUser.getUserId().equals(message.getAuthor().getAuthorId())) {
return;
}
Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(StarboardFeature.STAR_EMOTE, guildId);
if(emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), aEmote)) {
metricService.incrementCounter(STARBOARD_STARS_ADDED);
log.info("User {} in server {} reacted with star to put a message {} from channel {} on starboard.", serverUser.getUserId(), message.getServerId(), message.getMessageId(), message.getChannelId());
Optional<CachedReactions> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), serverUser, true);
}
}
private void handleStarboardPostChange(CachedMessage message, CachedReactions reaction, ServerUser serverUser, boolean adding) {
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
if(reaction != null) {
AUserInAServer author = userInServerManagementService.loadOrCreateUser(message.getServerId(), message.getAuthor().getAuthorId());
List<AUserInAServer> userExceptAuthor = getUsersExcept(reaction.getUsers(), author);
Long starMinimum = getFromConfig(FIRST_LEVEL_THRESHOLD_KEY, message.getServerId());
AUserInAServer userAddingReaction = userInServerManagementService.loadOrCreateUser(serverUser);
if (userExceptAuthor.size() >= starMinimum) {
log.info("Post reached starboard minimum. Message {} in channel {} in server {} will be starred/updated.",
message.getMessageId(), message.getChannelId(), message.getServerId());
if(starboardPostOptional.isPresent()) {
updateStarboardPost(message, userAddingReaction, adding, starboardPostOptional.get(), userExceptAuthor);
} else {
metricService.incrementCounter(STARBOARD_STARS_THRESHOLD_REACHED);
log.info("Creating starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
starboardService.createStarboardPost(message, userExceptAuthor, userAddingReaction, author);
}
} else {
if(starboardPostOptional.isPresent()) {
metricService.incrementCounter(STARBOARD_STARS_THRESHOLD_FELL);
log.info("Removing starboard post for message {} in channel {} in server {}. It fell under the threshold {}", message.getMessageId(), message.getChannelId(), message.getServerId(), starMinimum);
starboardPostOptional.ifPresent(this::completelyRemoveStarboardPost);
}
}
} else {
if(starboardPostOptional.isPresent()) {
log.info("Removing starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
starboardPostOptional.ifPresent(this::completelyRemoveStarboardPost);
}
}
}
private void updateStarboardPost(CachedMessage message, AUserInAServer userReacting, boolean adding, StarboardPost starboardPost, List<AUserInAServer> userExceptAuthor) {
starboardPost.setIgnored(false);
// TODO handle futures correctly
starboardService.updateStarboardPost(starboardPost, message, userExceptAuthor);
if(adding) {
log.trace("Adding reactor {} from message {}", userReacting.getUserReference().getId(), message.getMessageId());
starboardPostReactorManagementService.addReactor(starboardPost, userReacting);
} else {
log.trace("Removing reactor {} from message {}", userReacting.getUserReference().getId(), message.getMessageId());
starboardPostReactorManagementService.removeReactor(starboardPost, userReacting);
}
}
private void completelyRemoveStarboardPost(StarboardPost starboardPost) {
starboardService.deleteStarboardMessagePost(starboardPost);
starboardPostManagementService.removePost(starboardPost);
}
@Override
@Transactional
public void executeReactionRemoved(CachedMessage message, CachedReactions removedReaction, ServerUser userRemoving) {
if(message.getAuthor().getAuthorId().equals(userRemoving.getUserId())) {
return;
}
Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(StarboardFeature.STAR_EMOTE, guildId);
if(emoteService.compareCachedEmoteWithAEmote(removedReaction.getEmote(), aEmote)) {
metricService.incrementCounter(STARBOARD_STARS_REMOVED);
log.info("User {} in server {} removed star reaction from message {} on starboard.",
userRemoving.getUserId(), message.getServerId(), message.getMessageId());
Optional<CachedReactions> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false);
}
}
private Long getFromConfig(String key, Long guildId) {
return configManagementService.loadConfig(guildId, key).getLongValue();
}
private List<AUserInAServer> getUsersExcept(List<ServerUser> users, AUserInAServer author) {
return users.stream().filter(user -> !(user.getServerId().equals(author.getServerReference().getId()) && user.getUserId().equals(author.getUserReference().getId()))).map(serverUser -> {
Optional<AUserInAServer> aUserInAServer = userInServerManagementService.loadUserOptional(serverUser.getServerId(), serverUser.getUserId());
return aUserInAServer.orElse(null);
}).filter(Objects::nonNull).collect(Collectors.toList());
}
@Override
public FeatureDefinition getFeature() {
return StarboardFeatureDefinition.STARBOARD;
}
@Override
public void executeReactionCleared(CachedMessage message) {
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
starboardPostOptional.ifPresent(starboardPost -> {
log.info("Reactions on message {} in channel {} in server {} were cleared. Completely deleting the starboard post {}.",
message.getMessageId(), message.getChannelId(), message.getServerId(), starboardPost.getId());
starboardPostReactorManagementService.removeReactors(starboardPost);
completelyRemoveStarboardPost(starboardPost);
});
}
@PostConstruct
public void postConstruct() {
metricService.registerCounter(STARBOARD_STARS_ADDED, "Star reaction added");
metricService.registerCounter(STARBOARD_STARS_REMOVED, "Star reaction removed");
metricService.registerCounter(STARBOARD_STARS_THRESHOLD_REACHED, "Starboard posts reaching threshold");
metricService.registerCounter(STARBOARD_STARS_THRESHOLD_FELL, "Starboard posts falling below threshold");
}
}

View File

@@ -0,0 +1,38 @@
package dev.sheldan.abstracto.starboard.listener;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.starboard.config.StarboardFeatureDefinition;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import dev.sheldan.abstracto.starboard.service.management.StarboardPostManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class StarboardPostDeletedListener implements AsyncMessageDeletedListener {
@Autowired
private StarboardPostManagementService starboardPostManagementService;
@Override
public void execute(CachedMessage messageBefore) {
Optional<StarboardPost> byStarboardPostId = starboardPostManagementService.findByStarboardPostId(messageBefore.getMessageId());
if(byStarboardPostId.isPresent()) {
StarboardPost post = byStarboardPostId.get();
log.info("Removing starboard post: message {}, channel {}, server {}, because the message was deleted",
post.getPostMessageId(), post.getSourceChannel().getId(), messageBefore.getServerId());
starboardPostManagementService.setStarboardPostIgnored(messageBefore.getMessageId(), true);
}
}
@Override
public FeatureDefinition getFeature() {
return StarboardFeatureDefinition.STARBOARD;
}
}

View File

@@ -0,0 +1,44 @@
package dev.sheldan.abstracto.starboard.repository;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import dev.sheldan.abstracto.starboard.model.database.StarboardPostReaction;
import dev.sheldan.abstracto.starboard.repository.result.StarStatsGuildUserResult;
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(AUserInAServer user, StarboardPost post);
void deleteByStarboardPost(StarboardPost post);
@Query(value = "SELECT r.reactor_user_in_server_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" +
"WHERE p.server_id = :serverId\n" +
" AND p.ignored = false\n" +
"GROUP BY r.reactor_user_in_server_id \n" +
"ORDER BY starCount DESC \n" +
"LIMIT :count", nativeQuery = true)
List<StarStatsGuildUserResult> 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" +
"WHERE p.server_id = :serverId\n"
, nativeQuery = true)
Integer getReactionCountByServer(Long serverId);
@Query(value = "SELECT p.author_user_in_server_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" +
"WHERE p.server_id = :serverId\n" +
" AND p.ignored = false\n" +
"GROUP BY p.author_user_in_server_id \n" +
"ORDER BY starCount DESC \n" +
"LIMIT :count", nativeQuery = true)
List<StarStatsGuildUserResult> retrieveTopStarReceiverInServer(Long serverId, Integer count);
}

View File

@@ -0,0 +1,52 @@
package dev.sheldan.abstracto.starboard.repository;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface StarboardPostRepository extends JpaRepository<StarboardPost, Long> {
StarboardPost findByPostMessageId(Long messageId);
StarboardPost findByStarboardMessageId(Long messageId);
boolean existsByStarboardMessageId(Long messageId);
List<StarboardPost> findByServer_Id(Long serverId);
@Query(value = "SELECT p.id, COUNT(*) AS starCount \n" +
" FROM starboard_post p \n" +
" INNER JOIN starboard_post_reaction r ON p.id = r.post_id\n" +
" INNER JOIN user_in_server usi ON usi.user_in_server_id = p.author_user_in_server_id\n" +
" WHERE p.server_id = :serverId\n" +
" AND p.ignored = false\n" +
" AND usi.user_id = :userId\n" +
" GROUP BY p.id \n" +
" ORDER BY starCount DESC \n" +
" LIMIT :count", nativeQuery = true)
List<Long> getTopStarboardPostsForUser(Long serverId, Long userId, Integer count);
@Query(value = "SELECT COUNT(*) AS starCount\n" +
"FROM starboard_post_reaction r \n" +
" INNER JOIN starboard_post p ON p.id = r.post_id \n" +
" INNER JOIN user_in_server usi ON usi.user_in_server_id = r.reactor_user_in_server_id \n" +
" WHERE usi.user_id = :userId \n" +
" AND p.ignored = false\n" +
" AND r.server_id = :serverId", nativeQuery = true)
Long getGivenStarsOfUserInServer(Long serverId, Long userId);
@Query(value = "SELECT COUNT(*) AS starCount\n" +
" FROM starboard_post_reaction r \n" +
" INNER JOIN starboard_post p ON p.id = r.post_id \n" +
" INNER JOIN user_in_server usi ON usi.user_in_server_id = p.author_user_in_server_id \n" +
" WHERE p.author_user_in_server_id = usi.user_in_server_id \n" +
" AND usi.user_id = :userId \n" +
" AND p.ignored = false\n" +
" AND r.server_id = :serverId", nativeQuery = true)
Long getReceivedStarsOfUserInServer(Long serverId, Long userId);
}

View File

@@ -0,0 +1,7 @@
package dev.sheldan.abstracto.starboard.repository.result;
public interface StarStatsGuildUserResult {
// this is the User in Server Id
Long getUserId();
Integer getStarCount();
}

View File

@@ -0,0 +1,264 @@
package dev.sheldan.abstracto.starboard.service;
import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException;
import dev.sheldan.abstracto.core.models.AServerAChannelMessage;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.database.PostTarget;
import dev.sheldan.abstracto.core.models.property.SystemConfigProperty;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import dev.sheldan.abstracto.core.service.management.PostTargetManagement;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.starboard.config.StarboardFeature;
import dev.sheldan.abstracto.starboard.config.StarboardPostTarget;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import dev.sheldan.abstracto.starboard.model.template.*;
import dev.sheldan.abstracto.starboard.service.management.StarboardPostManagementService;
import dev.sheldan.abstracto.starboard.service.management.StarboardPostReactorManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
@Component
@Slf4j
public class StarboardServiceBean implements StarboardService {
public static final String STARBOARD_POST_TEMPLATE = "starboard_post";
@Autowired
private MemberService memberService;
@Autowired
private GuildService guildService;
@Autowired
private ChannelService channelService;
@Autowired
private PostTargetService postTargetService;
@Autowired
private TemplateService templateService;
@Autowired
private ConfigService configService;
@Autowired
private StarboardPostManagementService starboardPostManagementService;
@Autowired
private StarboardPostReactorManagementService starboardPostReactorManagementService;
@Autowired
private PostTargetManagement postTargetManagement;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private EmoteService emoteService;
@Autowired
private DefaultConfigManagementService defaultConfigManagementService;
@Autowired
private MessageService messageService;
@Autowired
private StarboardServiceBean self;
@Override
public CompletableFuture<Void> createStarboardPost(CachedMessage message, List<AUserInAServer> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser) {
Long starredUserId = starredUser.getUserInServerId();
List<Long> userExceptAuthorIds = userExceptAuthor.stream().map(AUserInAServer::getUserInServerId).collect(Collectors.toList());
return buildStarboardPostModel(message, userExceptAuthor.size()).thenCompose(starboardPostModel ->
self.sendStarboardPostAndStore(message, starredUserId, userExceptAuthorIds, starboardPostModel)
);
}
@Transactional
public CompletionStage<Void> sendStarboardPostAndStore(CachedMessage message, Long starredUserId, List<Long> userExceptAuthorIds, StarboardPostModel starboardPostModel) {
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
PostTarget starboard = postTargetManagement.getPostTarget(StarboardPostTarget.STARBOARD.getKey(), message.getServerId());
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, StarboardPostTarget.STARBOARD, message.getServerId());
Long starboardChannelId = starboard.getChannelReference().getId();
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid ->
self.persistPost(message, userExceptAuthorIds, completableFutures, starboardChannelId, starredUserId)
);
}
@Transactional
public void persistPost(CachedMessage message, List<Long> userExceptAuthorIds, List<CompletableFuture<Message>> completableFutures, Long starboardChannelId, Long starredUserId) {
AUserInAServer innerStarredUser = userInServerManagementService.loadUserOptional(starredUserId).orElseThrow(() -> new UserInServerNotFoundException(starredUserId));
AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId);
Message message1 = completableFutures.get(0).join();
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboardChannel)
.server(starboardChannel.getServer())
.build();
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, innerStarredUser, aServerAChannelMessage);
log.info("Persisting starboard post in channel {} with message {} with {} reactors.", message1.getId(),starboardChannelId, userExceptAuthorIds.size());
if(userExceptAuthorIds.isEmpty()) {
log.warn("There are no user ids except the author for the reactions in post {} in guild {} for message {} in channel {}.", starboardPost.getId(), message.getChannelId(), message.getMessageId(), message.getChannelId());
}
userExceptAuthorIds.forEach(aLong -> {
AUserInAServer user = userInServerManagementService.loadUserOptional(aLong).orElseThrow(() -> new UserInServerNotFoundException(aLong));
starboardPostReactorManagementService.addReactor(starboardPost, user);
});
}
private CompletableFuture<StarboardPostModel> buildStarboardPostModel(CachedMessage message, Integer starCount) {
return memberService.getMemberInServerAsync(message.getServerId(), message.getAuthor().getAuthorId()).thenApply(member -> {
Optional<TextChannel> channel = channelService.getTextChannelFromServerOptional(message.getServerId(), message.getChannelId());
Optional<Guild> guild = guildService.getGuildByIdOptional(message.getServerId());
// TODO use model objects instead of building entity models
AChannel aChannel = AChannel.builder().id(message.getChannelId()).build();
AUser user = AUser.builder().id(message.getAuthor().getAuthorId()).build();
String starLevelEmote = getAppropriateEmote(message.getServerId(), starCount);
return StarboardPostModel
.builder()
.message(message)
.author(member)
.channel(channel.orElse(null))
.aChannel(aChannel)
.starCount(starCount)
.guild(guild.orElse(null))
.user(user)
.starLevelEmote(starLevelEmote)
.build();
});
}
@Override
public CompletableFuture<Void> updateStarboardPost(StarboardPost post, CachedMessage message, List<AUserInAServer> userExceptAuthor) {
int starCount = userExceptAuthor.size();
log.info("Updating starboard post {} in server {} with reactors {}.", post.getId(), post.getSourceChannel().getServer().getId(), starCount);
return buildStarboardPostModel(message, starCount).thenCompose(starboardPostModel -> {
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
List<CompletableFuture<Message>> futures = postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, StarboardPostTarget.STARBOARD, message.getServerId());
Long starboardPostId = post.getId();
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
Optional<StarboardPost> innerPost = starboardPostManagementService.findByStarboardPostId(starboardPostId);
innerPost.ifPresent(starboardPost -> starboardPostManagementService.setStarboardPostMessageId(starboardPost, futures.get(0).join().getIdLong()));
});
});
}
@Override
public void deleteStarboardMessagePost(StarboardPost message) {
AChannel starboardChannel = message.getStarboardChannel();
log.info("Deleting starboard post {} in server {}", message.getId(), message.getSourceChannel().getServer().getId());
messageService.deleteMessageInChannelInServer(starboardChannel.getServer().getId(), starboardChannel.getId(), message.getStarboardMessageId());
}
@Override
public CompletableFuture<GuildStarStatsModel> retrieveStarStats(Long serverId) {
int count = 3;
List<CompletableFuture<StarStatsUser>> topStarGiverFutures = starboardPostReactorManagementService.retrieveTopStarGiver(serverId, count);
List<CompletableFuture<StarStatsUser>> topStarReceiverFutures = starboardPostReactorManagementService.retrieveTopStarReceiver(serverId, count);
List<CompletableFuture> allFutures = new ArrayList<>();
allFutures.addAll(topStarGiverFutures);
allFutures.addAll(topStarReceiverFutures);
return FutureUtils.toSingleFuture(allFutures).thenApply(aVoid -> {
List<StarboardPost> starboardPosts = starboardPostManagementService.retrieveTopPosts(serverId, count);
List<StarStatsPost> starStatsPosts = starboardPosts.stream().map(this::fromStarboardPost).collect(Collectors.toList());
Integer postCount = starboardPostManagementService.getPostCount(serverId);
Integer reactionCount = starboardPostReactorManagementService.getStarCount(serverId);
List<String> emotes = new ArrayList<>();
for (int i = 1; i < count + 1; i++) {
emotes.add(getStarboardRankingEmote(serverId, i));
}
List<StarStatsUser> topStarGivers = topStarGiverFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
List<StarStatsUser> topStarReceiver = topStarReceiverFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
return GuildStarStatsModel
.builder()
.badgeEmotes(emotes)
.starGiver(topStarGivers)
.starReceiver(topStarReceiver)
.topPosts(starStatsPosts)
.starredMessages(postCount)
.totalStars(reactionCount)
.build();
});
}
@Override
public MemberStarStatsModel retrieveStarStatsForMember(Member member) {
int count = 3;
Long receivedStars = starboardPostManagementService.retrieveReceivedStarsOfUserInServer(member.getGuild().getIdLong(), member.getIdLong());
Long givenStars = starboardPostManagementService.retrieveGivenStarsOfUserInServer(member.getGuild().getIdLong(), member.getIdLong());
List<StarboardPost> topPosts = starboardPostManagementService.retrieveTopPostsForUserInServer(member.getGuild().getIdLong(), member.getIdLong(), count);
List<StarStatsPost> starStatsPosts = topPosts.stream().map(this::fromStarboardPost).collect(Collectors.toList());
List<String> emotes = new ArrayList<>();
for (int i = 1; i < count + 1; i++) {
emotes.add(getStarboardRankingEmote(member.getGuild().getIdLong(), i));
}
return MemberStarStatsModel
.builder()
.member(member)
.topPosts(starStatsPosts)
.badgeEmotes(emotes)
.receivedStars(receivedStars)
.givenStars(givenStars)
.build();
}
public StarStatsPost fromStarboardPost(StarboardPost starboardPost) {
AChannel channel = starboardPost.getStarboardChannel();
return StarStatsPost
.builder()
.serverId(starboardPost.getServer().getId())
.channelId(channel.getId())
.messageId(starboardPost.getPostMessageId())
.starCount(starboardPost.getReactions().size())
.build();
}
private String getStarboardRankingEmote(Long serverId, Integer position) {
return emoteService.getUsableEmoteOrDefault(serverId, buildBadgeName(position));
}
private String buildBadgeName(Integer position) {
return StarboardFeature.STAR_BADGE_EMOTE_PREFIX + position;
}
private String getAppropriateEmote(Long serverId, Integer starCount) {
int maxLevels = defaultConfigManagementService.getDefaultConfig(StarboardFeature.STAR_LEVELS_CONFIG_KEY).getLongValue().intValue();
for(int i = maxLevels; i > 0; i--) {
String key = StarboardFeature.STAR_LVL_CONFIG_PREFIX + i;
SystemConfigProperty defaultStars = defaultConfigManagementService.getDefaultConfig(key);
Long starMinimum = configService.getLongValue(key, serverId, defaultStars.getLongValue());
if(starCount >= starMinimum) {
return emoteService.getUsableEmoteOrDefault(serverId, StarboardFeature.STAR_EMOTE_PREFIX + i);
}
}
return emoteService.getUsableEmoteOrDefault(serverId, StarboardFeature.STAR_EMOTE_PREFIX);
}
}

View File

@@ -0,0 +1,125 @@
package dev.sheldan.abstracto.starboard.service.management;
import dev.sheldan.abstracto.core.models.AServerAChannelMessage;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import dev.sheldan.abstracto.starboard.repository.StarboardPostRepository;
import lombok.extern.slf4j.Slf4j;
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
@Slf4j
public class StarboardPostManagementServiceBean implements StarboardPostManagementService {
@Autowired
private StarboardPostRepository repository;
@Autowired
private ChannelManagementService channelManagementService;
@Override
public StarboardPost createStarboardPost(CachedMessage starredMessage, AUserInAServer starredUser, AServerAChannelMessage starboardPost) {
AChannel build = channelManagementService.loadChannel(starredMessage.getChannelId());
StarboardPost post = StarboardPost
.builder()
.author(starredUser)
.postMessageId(starredMessage.getMessageId())
.sourceChannel(build)
.ignored(false)
.server(starboardPost.getServer())
.starboardMessageId(starboardPost.getMessageId())
.starboardChannel(starboardPost.getChannel())
.starredDate(Instant.now())
.build();
log.info("Persisting starboard post for message {} in channel {} in server {} on starboard at message {} in channel {} and server {} of user {}.",
starredMessage.getMessageId(), starredMessage.getChannelId(), starredMessage.getServerId(),
starboardPost.getMessageId(), starboardPost.getChannel().getId(), starboardPost.getServer().getId(),
starredUser.getUserReference().getId());
repository.save(post);
return post;
}
@Override
public StarboardPost createStarboardPost(StarboardPost post) {
return repository.save(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> retrieveTopPostsForUserInServer(Long serverId, Long userId, Integer count) {
List<Long> topPostIds = repository.getTopStarboardPostsForUser(serverId, userId, count);
return repository.findAllById(topPostIds);
}
@Override
public Long retrieveGivenStarsOfUserInServer(Long serverId, Long userId) {
return repository.getGivenStarsOfUserInServer(serverId, userId);
}
@Override
public Long retrieveReceivedStarsOfUserInServer(Long serverId, Long userId) {
return repository.getReceivedStarsOfUserInServer(serverId, userId);
}
@Override
public List<StarboardPost> retrieveAllPosts(Long serverId) {
return repository.findByServer_Id(serverId);
}
@Override
public Integer getPostCount(Long serverId) {
return retrieveAllPosts(serverId).size();
}
@Override
public Optional<StarboardPost> findByMessageId(Long messageId) {
return Optional.ofNullable(repository.findByPostMessageId(messageId));
}
@Override
public Optional<StarboardPost> findByStarboardPostId(Long postId) {
return Optional.ofNullable(repository.findByStarboardMessageId(postId));
}
@Override
public void setStarboardPostIgnored(Long messageId, Boolean newValue) {
StarboardPost post = repository.findByStarboardMessageId(messageId);
post.setIgnored(newValue);
repository.save(post);
}
@Override
public boolean isStarboardPost(Long messageId) {
return repository.existsByStarboardMessageId(messageId);
}
@Override
public void removePost(StarboardPost starboardPost) {
starboardPost.getReactions().clear();
repository.delete(starboardPost);
}
}

View File

@@ -0,0 +1,69 @@
package dev.sheldan.abstracto.starboard.service.management;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.starboard.converter.StarStatsUserConverter;
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
import dev.sheldan.abstracto.starboard.model.database.StarboardPostReaction;
import dev.sheldan.abstracto.starboard.model.template.StarStatsUser;
import dev.sheldan.abstracto.starboard.repository.result.StarStatsGuildUserResult;
import dev.sheldan.abstracto.starboard.repository.StarboardPostReactionRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class StarboardPostReactorManagementServiceBean implements StarboardPostReactorManagementService {
@Autowired
private StarboardPostReactionRepository repository;
@Autowired
private StarStatsUserConverter converter;
@Override
public StarboardPostReaction addReactor(StarboardPost post, AUserInAServer user) {
StarboardPostReaction reactor = StarboardPostReaction
.builder()
.starboardPost(post)
.reactor(user)
.server(user.getServerReference())
.build();
log.info("Persisting the reactor {} for starboard post {} in server {}.", user.getUserReference().getId(), post.getId(), user.getServerReference().getId());
repository.save(reactor);
return reactor;
}
@Override
public void removeReactor(StarboardPost post, AUserInAServer user) {
log.info("Removing reactor {} from post {} in server {}.", user.getUserReference().getId(), post.getId(), user.getServerReference().getId());
repository.deleteByReactorAndStarboardPost(user, post);
}
@Override
public void removeReactors(StarboardPost post) {
log.info("Removing all {} reactors from starboard post {}", post.getReactions().size(), post.getId());
repository.deleteByStarboardPost(post);
}
@Override
public Integer getStarCount(Long serverId) {
return repository.getReactionCountByServer(serverId);
}
@Override
public List<CompletableFuture<StarStatsUser>> retrieveTopStarGiver(Long serverId, Integer count) {
List<StarStatsGuildUserResult> starGivers = repository.findTopStarGiverInServer(serverId, count);
return converter.convertToStarStatsUser(starGivers, serverId);
}
@Override
public List<CompletableFuture<StarStatsUser>> retrieveTopStarReceiver(Long serverId, Integer count) {
List<StarStatsGuildUserResult> starReceivers = repository.retrieveTopStarReceiverInServer(serverId, count);
return converter.convertToStarStatsUser(starReceivers, serverId);
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../dbchangelog-3.8.xsd" >
<include file="starboard-tables/tables.xml" relativeToChangelogFile="true"/>
<include file="starboard-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,21 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<property name="starboardFeature" value="(SELECT id FROM feature WHERE key = 'starboard')"/>
<changeSet author="Sheldan" id="starboard-commands">
<insert tableName="command">
<column name="name" value="starStats"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${starboardFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,12 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<include file="default_emote.xml" relativeToChangelogFile="true"/>
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,43 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="starboard_default_emote-insert">
<insert tableName="default_emote">
<column name="emote_key" value="star"/>
<column name="name" value="⭐"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="star1"/>
<column name="name" value="⭐"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="star2"/>
<column name="name" value="🌟"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="star3"/>
<column name="name" value="💫"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="star4"/>
<column name="name" value="🌠"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="starboardBadge1"/>
<column name="name" value="🥇"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="starboardBadge2"/>
<column name="name" value="🥈"/>
</insert>
<insert tableName="default_emote">
<column name="emote_key" value="starboardBadge3"/>
<column name="name" value="🥉"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,14 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="starboard_feature-insertion">
<insert tableName="feature">
<column name="key" value="starboard"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,69 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="starboard-table">
<createTable tableName="starboard_post">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="starboard_post_pkey"/>
</column>
<column name="ignored" type="BOOLEAN">
<constraints nullable="true"/>
</column>
<column name="post_message_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="starboard_message_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="starred_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="author_user_in_server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="source_channel_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="channel_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
</createTable>
<createIndex indexName="idx_starboard_post_message" tableName="starboard_post">
<column name="post_message_id"/>
</createIndex>
<createIndex indexName="idx_starboard_starboard_message" tableName="starboard_post">
<column name="starboard_message_id"/>
</createIndex>
<createIndex indexName="idx_starboard_server" tableName="starboard_post">
<column name="server_id"/>
</createIndex>
<addForeignKeyConstraint baseColumnNames="author_user_in_server_id" baseTableName="starboard_post" constraintName="fk_starboard_post_author_user_in_server_id" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="channel_id" baseTableName="starboard_post" constraintName="fk_starboard_post_channel" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel" validate="true"/>
<addForeignKeyConstraint baseColumnNames="source_channel_id" baseTableName="starboard_post" constraintName="fk_starboard_post_source_channel" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel" validate="true"/>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="starboard_post" constraintName="fk_starboard_post_server"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
referencedTableName="server" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS starboard_post_update_trigger ON starboard_post;
CREATE TRIGGER starboard_post_update_trigger BEFORE UPDATE ON starboard_post FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS starboard_insert_trigger ON starboard_post;
CREATE TRIGGER starboard_post_insert_trigger BEFORE INSERT ON starboard_post FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,42 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="starboard_post_reaction-table">
<createTable tableName="starboard_post_reaction">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="starboard_post_reaction_pkey"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="reactor_user_in_server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="post_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseColumnNames="reactor_user_in_server_id" baseTableName="starboard_post_reaction" constraintName="fk_starboard_post_reaction_reactor" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="post_id" baseTableName="starboard_post_reaction" constraintName="fk_starboard_post_reaction_post" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="starboard_post" validate="true"/>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="starboard_post_reaction" constraintName="fk_starboard_post_reaction_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS starboard_post_reaction_update_trigger ON starboard_post_reaction;
CREATE TRIGGER starboard_post_reaction_update_trigger BEFORE UPDATE ON starboard_post_reaction FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS starboard_post_reaction_insert_trigger ON starboard_post_reaction;
CREATE TRIGGER starboard_post_reaction_insert_trigger BEFORE INSERT ON starboard_post_reaction FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<include file="starboard_post.xml" relativeToChangelogFile="true"/>
<include file="starboard_post_reaction.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
<include file="1.0-starboard/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,19 @@
abstracto.systemConfigs.starLvl1.name=starLvl1
abstracto.systemConfigs.starLvl1.longValue=5
abstracto.systemConfigs.starLvl2.name=starLvl2
abstracto.systemConfigs.starLvl2.longValue=8
abstracto.systemConfigs.starLvl3.name=starLvl3
abstracto.systemConfigs.starLvl3.longValue=13
abstracto.systemConfigs.starLvl4.name=starLvl4
abstracto.systemConfigs.starLvl4.longValue=17
abstracto.systemConfigs.starLvls.name=starLvls
abstracto.systemConfigs.starLvls.longValue=4
abstracto.featureFlags.starboard.featureName=starboard
abstracto.featureFlags.starboard.enabled=false
abstracto.postTargets.starboard.name=starboard