[AB-177] adding ability to restrict the allowed mentions and configure them via commands on a server basis, default is defined via property file

This commit is contained in:
Sheldan
2021-02-06 04:05:55 +01:00
parent b838678c15
commit 7aa5cbe304
23 changed files with 764 additions and 18 deletions

View File

@@ -0,0 +1,53 @@
package dev.sheldan.abstracto.core.commands.config.mention;
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.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.service.AllowedMentionService;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class AllowMention extends AbstractConditionableCommand {
@Autowired
private AllowedMentionService allowedMentionService;
@Override
public CommandResult execute(CommandContext commandContext) {
String mentionTypeInput = (String) commandContext.getParameters().getParameters().get(0);
Message.MentionType mentionType = allowedMentionService.getMentionTypeFromString(mentionTypeInput);
allowedMentionService.allowMentionForServer(mentionType, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter mentionTypeParameter = Parameter.builder().name("mentionType").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(mentionTypeParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("allowMention")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,55 @@
package dev.sheldan.abstracto.core.commands.config.mention;
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.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.service.AllowedMentionService;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class DisallowMention extends AbstractConditionableCommand {
@Autowired
private AllowedMentionService allowedMentionService;
@Override
public CommandResult execute(CommandContext commandContext) {
String mentionTypeInput = (String) commandContext.getParameters().getParameters().get(0);
Message.MentionType mentionType = allowedMentionService.getMentionTypeFromString(mentionTypeInput);
allowedMentionService.disAllowMentionForServer(mentionType, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter mentionTypeParameter = Parameter.builder().name("mentionType").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(mentionTypeParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("disallowMention")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -1,6 +1,5 @@
package dev.sheldan.abstracto.core.commands.utility;
import dev.sheldan.abstracto.core.command.UtilityModuleInterface;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
@@ -10,6 +9,7 @@ import dev.sheldan.abstracto.core.command.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.command.config.validator.MaxStringLengthValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.service.EmoteService;
@@ -47,7 +47,7 @@ public class SetEmote extends AbstractConditionableCommand {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("setEmote")
.module(UtilityModuleInterface.UTILITY)
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.core.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "abstracto.allowedmention")
public class AllowedMentionConfig {
private Boolean everyone;
private Boolean role;
private Boolean user;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AllowedMention;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface AllowedMentionRepository extends JpaRepository<AllowedMention, Long> {
Optional<AllowedMention> findByServer(AServer server);
}

View File

@@ -5,11 +5,13 @@ import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.stereotype.Repository;
import javax.persistence.QueryHint;
import java.util.List;
import java.util.Optional;
@Repository
public interface ChannelGroupRepository extends JpaRepository<AChannelGroup, Long> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))

View File

@@ -0,0 +1,125 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.config.AllowedMentionConfig;
import dev.sheldan.abstracto.core.models.database.AllowedMention;
import dev.sheldan.abstracto.core.exception.UnknownMentionTypeException;
import dev.sheldan.abstracto.core.service.management.AllowedMentionManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class AllowedMentionServiceBean implements AllowedMentionService {
public static final String EVERYONE_MENTION_KEY = "everyone";
public static final String ROLE_MENTION_KEY = "role";
public static final String USER_MENTION_KEY = "user";
@Autowired
private AllowedMentionConfig allowedMentionConfig;
@Autowired
private AllowedMentionManagementService allowedMentionManagementService;
private final HashMap<String, Message.MentionType> ALL_MENTION_TYPES = new HashMap<>();
@Override
public boolean allMentionsAllowed(Long serverId) {
return getEffectiveAllowedMention(serverId).allAllowed();
}
@Override
public List<Message.MentionType> getAllowedMentionTypesForServer(Long serverId) {
AllowedMention allowedMention = getEffectiveAllowedMention(serverId);
return mapAllowedMentionToMentionType(allowedMention);
}
@Override
public void allowMentionForServer(Message.MentionType mentionType, Long serverId) {
log.info("Allowing mention {} for server {}.", mentionType, serverId);
setOrInitializeAllowedMention(mentionType, serverId, true);
}
@Override
public void disAllowMentionForServer(Message.MentionType mentionType, Long serverId) {
log.info("Disallowing mention {} for server {}.", mentionType, serverId);
setOrInitializeAllowedMention(mentionType, serverId, false);
}
@Override
public AllowedMention getDefaultAllowedMention() {
return AllowedMention
.builder()
.everyone(allowedMentionConfig.getEveryone())
.role(allowedMentionConfig.getRole())
.user(allowedMentionConfig.getUser())
.build();
}
@Override
public AllowedMention getEffectiveAllowedMention(Long serverId) {
Optional<AllowedMention> customAllowMentions = allowedMentionManagementService.getCustomAllowedMentionFor(serverId);
return customAllowMentions.orElseGet(this::getDefaultAllowedMention);
}
@Override
public Message.MentionType getMentionTypeFromString(String input) {
input = input.toLowerCase();
if (ALL_MENTION_TYPES.containsKey(input)) {
return ALL_MENTION_TYPES.get(input);
}
throw new UnknownMentionTypeException();
}
private List<Message.MentionType> mapAllowedMentionToMentionType(AllowedMention allowedMention) {
// if all are allowed, we dont want to restrict it
if(allowedMention.allAllowed()) {
return null;
}
List<Message.MentionType> types = new ArrayList<>();
if(allowedMention.getEveryone()) {
types.add(Message.MentionType.EVERYONE);
}
if(allowedMention.getRole()) {
types.add(Message.MentionType.ROLE);
}
if(allowedMention.getUser()) {
types.add(Message.MentionType.USER);
}
return types;
}
private void setOrInitializeAllowedMention(Message.MentionType mentionType, Long serverId, boolean initialMentionValue) {
Optional<AllowedMention> customAllowedMentionOptional = allowedMentionManagementService.getCustomAllowedMentionFor(serverId);
AllowedMention customAllowedMention = customAllowedMentionOptional.orElseGet(this::getDefaultAllowedMention);
switch (mentionType) {
case EVERYONE:
customAllowedMention.setEveryone(initialMentionValue);
break;
case ROLE:
customAllowedMention.setRole(initialMentionValue);
break;
case USER:
customAllowedMention.setUser(initialMentionValue);
break;
}
if (!customAllowedMentionOptional.isPresent()) {
allowedMentionManagementService.createCustomAllowedMention(serverId, customAllowedMention);
}
}
@PostConstruct
public void postConstruct() {
ALL_MENTION_TYPES.put(EVERYONE_MENTION_KEY, Message.MentionType.EVERYONE);
ALL_MENTION_TYPES.put(ROLE_MENTION_KEY, Message.MentionType.ROLE);
ALL_MENTION_TYPES.put(USER_MENTION_KEY, Message.MentionType.USER);
}
}

View File

@@ -44,6 +44,9 @@ public class ChannelServiceBean implements ChannelService {
@Autowired
private TemplateService templateService;
@Autowired
private AllowedMentionService allowedMentionService;
@Autowired
private MetricService metricService;
@@ -119,14 +122,21 @@ public class ChannelServiceBean implements ChannelService {
log.trace("Sending message {} from channel {} and server {} to channel {}.",
message.getId(), message.getChannel().getId(), message.getGuild().getId(), channel.getId());
metricService.incrementCounter(MESSAGE_SEND_METRIC);
return channel.sendMessage(message).submit();
return channel.sendMessage(message).allowedMentions(getAllowedMentionsFor(channel)).submit();
}
private List<Message.MentionType> getAllowedMentionsFor(MessageChannel channel) {
if(channel instanceof GuildChannel) {
return allowedMentionService.getAllowedMentionTypesForServer(((GuildChannel) channel).getGuild().getIdLong());
}
return null;
}
@Override
public CompletableFuture<Message> sendTextToChannel(String text, MessageChannel channel) {
log.trace("Sending text to channel {}.", channel.getId());
metricService.incrementCounter(MESSAGE_SEND_METRIC);
return channel.sendMessage(text).submit();
return channel.sendMessage(text).allowedMentions(getAllowedMentionsFor(channel)).submit();
}
@Override
@@ -155,7 +165,7 @@ public class ChannelServiceBean implements ChannelService {
@Override
public MessageAction sendEmbedToChannelInComplete(MessageEmbed embed, MessageChannel channel) {
metricService.incrementCounter(MESSAGE_SEND_METRIC);
return channel.sendMessage(embed);
return channel.sendMessage(embed).allowedMentions(getAllowedMentionsFor(channel));
}
@Override
@@ -213,8 +223,9 @@ public class ChannelServiceBean implements ChannelService {
}
}
allMessageActions.add(0, firstMessageAction);
List<Message.MentionType> allowedMentions = getAllowedMentionsFor(textChannel);
allMessageActions.forEach(messageAction ->
futures.add(messageAction.submit())
futures.add(messageAction.allowedMentions(allowedMentions).submit())
);
return futures;
}

View File

@@ -56,7 +56,7 @@ public class StartupServiceBean implements Startup {
}
@Override
@Transactional(isolation = Isolation.SERIALIZABLE)
@Transactional
public void synchronize() {
log.info("Synchronizing servers.");
synchronizeServers();
@@ -70,7 +70,7 @@ public class StartupServiceBean implements Startup {
availableServers.forEach(aLong -> {
AServer newAServer = serverManagementService.loadOrCreate(aLong);
Guild newGuild = instance.getGuildById(aLong);
log.trace("Synchronizing server: {}", aLong);
log.info("Synchronizing server: {}", aLong);
if(newGuild != null){
synchronizeRolesOf(newGuild, newAServer);
synchronizeChannelsOf(newGuild, newAServer);
@@ -91,7 +91,6 @@ public class StartupServiceBean implements Startup {
Set<Long> newRoles = SetUtils.difference(availableRoles, knownRolesId);
newRoles.forEach(aLong -> {
roleManagementService.createRole(aLong, existingAServer);
log.trace("Adding new role: {}", aLong);
});
}
@@ -103,7 +102,6 @@ public class StartupServiceBean implements Startup {
Set<Long> newChannels = SetUtils.difference(existingChannelsIds, knownChannelsIds);
newChannels.forEach(aLong -> {
GuildChannel channel1 = available.stream().filter(channel -> channel.getIdLong() == aLong).findFirst().get();
log.trace("Adding new channel: {}", aLong);
AChannelType type = AChannelType.getAChannelType(channel1.getType());
channelManagementService.createChannel(channel1.getIdLong(), type, existingServer);
});

View File

@@ -0,0 +1,55 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AllowedMention;
import dev.sheldan.abstracto.core.repository.AllowedMentionRepository;
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 AllowedMentionManagementServiceBean implements AllowedMentionManagementService {
@Autowired
private AllowedMentionRepository allowedMentionRepository;
@Autowired
private ServerManagementService serverManagementServiceBean;
@Override
public Optional<AllowedMention> getCustomAllowedMentionFor(Long serverId) {
return allowedMentionRepository.findById(serverId);
}
@Override
public Optional<AllowedMention> getCustomAllowedMentionFor(AServer server) {
return allowedMentionRepository.findByServer(server);
}
@Override
public boolean hasCustomAllowedMention(Long serverId) {
return getCustomAllowedMentionFor(serverId).isPresent();
}
@Override
public AllowedMention createCustomAllowedMention(Long serverId, AllowedMention base) {
log.info("Creating custom allowed mention for server {} based on {}.", serverId, base);
AServer server = serverManagementServiceBean.loadOrCreate(serverId);
AllowedMention allowedMention = AllowedMention
.builder()
.everyone(base.getEveryone())
.role(base.getRole())
.user(base.getUser())
.server(server).build();
allowedMentionRepository.save(allowedMention);
return allowedMention;
}
@Override
public void deleteCustomAllowedMention(Long serverId) {
allowedMentionRepository.deleteById(serverId);
}
}

View File

@@ -25,7 +25,6 @@ public class RoleManagementServiceBean implements RoleManagementService {
.server(server)
.deleted(false)
.build();
server.getRoles().add(build);
log.info("Creating role {} in server {}.", id, server.getId());
return repository.save(build);
}

View File

@@ -1,4 +1,9 @@
abstracto.startup.synchronize=true
abstracto.eventWaiter.threads=10
server.port=8080
server.port=8080
abstracto.allowedmention.everyone=false
abstracto.allowedmention.role=true
abstracto.allowedmention.user=true

View File

@@ -33,12 +33,6 @@
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="setEmote"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
<changeSet author="Sheldan" id="core-channels-commands" >
<insert tableName="command">
@@ -187,5 +181,23 @@
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="setEmote"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="allowMention"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
<insert tableName="command">
<column name="name" value="disallowMention"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
<column name="created" valueComputed="${today}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,26 @@
<?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="allowed_mention-table">
<createTable tableName="allowed_mention">
<column name="server_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="allowed_mention_pkey"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="everyone_mention" type="BOOLEAN"/>
<column name="user_mention" type="BOOLEAN"/>
<column name="role_mention" type="BOOLEAN"/>
</createTable>
</changeSet>
<changeSet author="Sheldan" id="allowed_mention-fk_allowed_mention_server">
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="allowed_mention" constraintName="fk_allowed_mention_server"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
</changeSet>
</databaseChangeLog>

View File

@@ -27,4 +27,5 @@
<include file="system_config.xml" relativeToChangelogFile="true"/>
<include file="auser.xml" relativeToChangelogFile="true"/>
<include file="counter.xml" relativeToChangelogFile="true"/>
<include file="allowed_mention.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>