mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-28 19:35:23 +00:00
added ability to delete embedded posts (only the author and the person embedding can delete them) (this requires the embeds to be stored, they are deleted if the embed is deleted)
added filter to only handle reactions not done by the bot introduced completable future to the delete message wrapper fixed multi embed handling always resulting in two embeds added logging of template exceptions refactored link embed handling to be in a service instead of the listener
This commit is contained in:
@@ -1,33 +1,19 @@
|
||||
package dev.sheldan.abstracto.utility.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.listener.MessageReceivedListener;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.listener.models.MessageEmbeddedModel;
|
||||
import dev.sheldan.abstracto.core.service.Bot;
|
||||
import dev.sheldan.abstracto.core.service.MessageCache;
|
||||
import dev.sheldan.abstracto.core.models.MessageToSend;
|
||||
import dev.sheldan.abstracto.templating.TemplateService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.utility.MessageEmbedLink;
|
||||
import dev.sheldan.abstracto.utility.config.UtilityFeatures;
|
||||
import dev.sheldan.abstracto.utility.service.MessageEmbedService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
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;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@@ -38,81 +24,24 @@ public class MessageEmbedListener implements MessageReceivedListener {
|
||||
|
||||
public static final String MESSAGE_EMBED_TEMPLATE = "message";
|
||||
|
||||
private Pattern messageRegex = Pattern.compile("(?<whole>https://discordapp.com/channels/(?<server>\\d+)/(?<channel>\\d+)/(?<message>\\d+)(?:.*?))+");
|
||||
|
||||
@Autowired
|
||||
private MessageEmbedListener self;
|
||||
|
||||
@Autowired
|
||||
private ChannelManagementService channelManagementService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void createEmbedAndPostEmbed(@Nonnull Message postedMessage, CachedMessage message) {
|
||||
MessageEmbeddedModel messageEmbeddedModel = buildTemplateParameter(postedMessage, message);
|
||||
MessageToSend embed = templateService.renderEmbedTemplate(MESSAGE_EMBED_TEMPLATE, messageEmbeddedModel);
|
||||
channelService.sendMessageToEndInTextChannel(embed, postedMessage.getTextChannel());
|
||||
}
|
||||
|
||||
private MessageEmbeddedModel buildTemplateParameter(Message message, CachedMessage embeddedMessage) {
|
||||
AChannel channel = channelManagementService.loadChannel(message.getChannel().getIdLong());
|
||||
AServer server = serverManagementService.loadOrCreate(message.getGuild().getIdLong());
|
||||
AUserInAServer user = userManagementService.loadUser(message.getMember());
|
||||
Member author = bot.getMemberInServer(embeddedMessage.getServerId(), embeddedMessage.getAuthorId());
|
||||
TextChannel sourceChannel = bot.getTextChannelFromServer(embeddedMessage.getServerId(), embeddedMessage.getChannelId()).get();
|
||||
return MessageEmbeddedModel
|
||||
.builder()
|
||||
.channel(channel)
|
||||
.server(server)
|
||||
.member(message.getMember())
|
||||
.aUserInAServer(user)
|
||||
.author(author)
|
||||
.sourceChannel(sourceChannel)
|
||||
.embeddingUser(message.getMember())
|
||||
.user(user.getUserReference())
|
||||
.messageChannel(message.getChannel())
|
||||
.guild(message.getGuild())
|
||||
.embeddedMessage(embeddedMessage)
|
||||
.build();
|
||||
}
|
||||
private MessageEmbedService messageEmbedService;
|
||||
|
||||
@Override
|
||||
public void execute(Message message) {
|
||||
String messageRaw = message.getContentRaw();
|
||||
Matcher matcher = messageRegex.matcher(messageRaw);
|
||||
boolean matched = false;
|
||||
while(matcher.find()) {
|
||||
matched = true;
|
||||
String serverId = matcher.group("server");
|
||||
String channelId = matcher.group("channel");
|
||||
String messageId = matcher.group("message");
|
||||
String wholeLink = matcher.group("whole");
|
||||
if(message.getGuild().getId().equals(serverId)) {
|
||||
Long serverIdLong = Long.parseLong(serverId);
|
||||
Long channelIdLong = Long.parseLong(channelId);
|
||||
Long messageIdLong = Long.parseLong(messageId);
|
||||
messageRaw = messageRaw.replace(wholeLink, "");
|
||||
messageCache.getMessageFromCache(serverIdLong, channelIdLong, messageIdLong).thenAccept(cachedMessage -> {
|
||||
self.createEmbedAndPostEmbed(message, cachedMessage);
|
||||
});
|
||||
|
||||
}
|
||||
List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw);
|
||||
for (MessageEmbedLink messageEmbedLink : links) {
|
||||
messageRaw = messageRaw.replace(messageEmbedLink.getWholeUrl(), "");
|
||||
AUserInAServer cause = userManagementService.loadUser(message.getMember());
|
||||
messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId()).thenAccept(cachedMessage -> {
|
||||
messageEmbedService.embedLink(cachedMessage, message.getTextChannel(), cause, message);
|
||||
});
|
||||
}
|
||||
if(StringUtils.isBlank(messageRaw) && matched) {
|
||||
if(StringUtils.isBlank(messageRaw) && links.size() > 0) {
|
||||
message.delete().queue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package dev.sheldan.abstracto.utility.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.listener.ReactedAddedListener;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.Bot;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.management.EmoteManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.EmoteUtils;
|
||||
import dev.sheldan.abstracto.utility.config.UtilityFeatures;
|
||||
import dev.sheldan.abstracto.utility.models.EmbeddedMessage;
|
||||
import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService;
|
||||
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 java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageEmbedRemovalReactionListener implements ReactedAddedListener {
|
||||
|
||||
public static final String REMOVAL_EMOTE = "removeEmbed";
|
||||
|
||||
@Autowired
|
||||
private EmoteManagementService emoteManagementService;
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
@Autowired
|
||||
private MessageEmbedPostManagementService messageEmbedPostManagementService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Override
|
||||
public void executeReactionAdded(CachedMessage message, MessageReaction reaction, AUserInAServer userAdding) {
|
||||
Long guildId = message.getServerId();
|
||||
Optional<AEmote> aEmote = emoteManagementService.loadEmoteByName(REMOVAL_EMOTE, guildId);
|
||||
if(aEmote.isPresent()) {
|
||||
AEmote emote = aEmote.get();
|
||||
MessageReaction.ReactionEmote reactionEmote = reaction.getReactionEmote();
|
||||
Optional<Emote> emoteInGuild = bot.getEmote(guildId, emote);
|
||||
if(EmoteUtils.isReactionEmoteAEmote(reactionEmote, emote, emoteInGuild.orElse(null))) {
|
||||
Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
|
||||
if(embeddedMessageOptional.isPresent()) {
|
||||
EmbeddedMessage embeddedMessage = embeddedMessageOptional.get();
|
||||
if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(userAdding.getUserReference().getId())
|
||||
|| embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(userAdding.getUserReference().getId())
|
||||
) {
|
||||
messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid -> {
|
||||
messageEmbedPostManagementService.deleteEmbeddedMessageTransactional(embeddedMessage);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("Emote {} is not defined for guild {}. Embed link deletion not functional.", REMOVAL_EMOTE, guildId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeature() {
|
||||
return UtilityFeatures.LINK_EMBEDS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package dev.sheldan.abstracto.utility.repository;
|
||||
|
||||
import dev.sheldan.abstracto.utility.models.EmbeddedMessage;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface EmbeddedMessageRepository extends JpaRepository<EmbeddedMessage, Long> {
|
||||
EmbeddedMessage findByEmbeddingMessageId(Long messageId);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package dev.sheldan.abstracto.utility.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.listener.models.MessageEmbeddedModel;
|
||||
import dev.sheldan.abstracto.core.models.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.Bot;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MessageCache;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.templating.TemplateService;
|
||||
import dev.sheldan.abstracto.utility.MessageEmbedLink;
|
||||
import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageEmbedServiceBean implements MessageEmbedService {
|
||||
|
||||
private Pattern messageRegex = Pattern.compile("(?<whole>https://discordapp.com/channels/(?<server>\\d+)/(?<channel>\\d+)/(?<message>\\d+)(?:.*?))+");
|
||||
|
||||
public static final String MESSAGE_EMBED_TEMPLATE = "message";
|
||||
public static final String REMOVAL_EMOTE = "removeEmbed";
|
||||
|
||||
@Autowired
|
||||
private ChannelManagementService channelManagementService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private Bot bot;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private MessageEmbedService self;
|
||||
|
||||
@Autowired
|
||||
private MessageCache messageCache;
|
||||
|
||||
@Autowired
|
||||
private MessageEmbedPostManagementService messageEmbedPostManagementService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Override
|
||||
public List<MessageEmbedLink> getLinksInMessage(String message) {
|
||||
List<MessageEmbedLink> links = new ArrayList<>();
|
||||
Matcher matcher = messageRegex.matcher(message);
|
||||
while(matcher.find()) {
|
||||
String serverId = matcher.group("server");
|
||||
String channelId = matcher.group("channel");
|
||||
String messageId = matcher.group("message");
|
||||
String wholeLink = matcher.group("whole");
|
||||
Long serverIdLong = Long.parseLong(serverId);
|
||||
Long channelIdLong = Long.parseLong(channelId);
|
||||
Long messageIdLong = Long.parseLong(messageId);
|
||||
MessageEmbedLink messageEmbedLink = MessageEmbedLink
|
||||
.builder()
|
||||
.serverId(serverIdLong)
|
||||
.channelId(channelIdLong)
|
||||
.messageId(messageIdLong)
|
||||
.wholeUrl(wholeLink)
|
||||
.build();
|
||||
links.add(messageEmbedLink);
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embedLinks(List<MessageEmbedLink> linksToEmbed, TextChannel target, AUserInAServer reason, Message embeddingMessage) {
|
||||
linksToEmbed.forEach(messageEmbedLink -> {
|
||||
messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId())
|
||||
.thenAccept(cachedMessage -> {
|
||||
self.embedLink(cachedMessage, target, reason, embeddingMessage);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void embedLink(CachedMessage cachedMessage, TextChannel target, AUserInAServer cause, Message embeddingMessage) {
|
||||
MessageEmbeddedModel messageEmbeddedModel = buildTemplateParameter(embeddingMessage, cachedMessage);
|
||||
MessageToSend embed = templateService.renderEmbedTemplate(MESSAGE_EMBED_TEMPLATE, messageEmbeddedModel);
|
||||
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToEndInTextChannel(embed, target);
|
||||
|
||||
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
|
||||
try {
|
||||
Message createdMessage = completableFutures.get(0).get();
|
||||
messageEmbedPostManagementService.createMessageEmbed(cachedMessage, createdMessage, cause);
|
||||
messageService.addReactionToMessage(REMOVAL_EMOTE, cachedMessage.getServerId(), createdMessage);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("Failed to post message embed.", e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private MessageEmbeddedModel buildTemplateParameter(Message message, CachedMessage embeddedMessage) {
|
||||
AChannel channel = channelManagementService.loadChannel(message.getChannel().getIdLong());
|
||||
AServer server = serverManagementService.loadOrCreate(message.getGuild().getIdLong());
|
||||
AUserInAServer user = userManagementService.loadUser(message.getMember());
|
||||
Member author = bot.getMemberInServer(embeddedMessage.getServerId(), embeddedMessage.getAuthorId());
|
||||
TextChannel sourceChannel = bot.getTextChannelFromServer(embeddedMessage.getServerId(), embeddedMessage.getChannelId()).get();
|
||||
return MessageEmbeddedModel
|
||||
.builder()
|
||||
.channel(channel)
|
||||
.server(server)
|
||||
.member(message.getMember())
|
||||
.aUserInAServer(user)
|
||||
.author(author)
|
||||
.sourceChannel(sourceChannel)
|
||||
.embeddingUser(message.getMember())
|
||||
.user(user.getUserReference())
|
||||
.messageChannel(message.getChannel())
|
||||
.guild(message.getGuild())
|
||||
.embeddedMessage(embeddedMessage)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package dev.sheldan.abstracto.utility.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserManagementService;
|
||||
import dev.sheldan.abstracto.utility.models.EmbeddedMessage;
|
||||
import dev.sheldan.abstracto.utility.repository.EmbeddedMessageRepository;
|
||||
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 org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostManagementService {
|
||||
|
||||
@Autowired
|
||||
private EmbeddedMessageRepository embeddedMessageRepository;
|
||||
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void createMessageEmbed(CachedMessage embeddedMessage, Message messageContainingEmbed, AUserInAServer cause) {
|
||||
AServer embeddedServer = AServer.builder().id(embeddedMessage.getServerId()).build();
|
||||
AChannel embeddedChannel = AChannel.builder().id(embeddedMessage.getChannelId()).build();
|
||||
AServer embeddingServer = AServer.builder().id(messageContainingEmbed.getGuild().getIdLong()).build();
|
||||
AChannel embeddingChannel = AChannel.builder().id(messageContainingEmbed.getTextChannel().getIdLong()).build();
|
||||
AUserInAServer embeddedAuthor = userManagementService.loadUser(embeddedMessage.getServerId(), embeddedMessage.getAuthorId());
|
||||
EmbeddedMessage messageEmbedPost = EmbeddedMessage
|
||||
.builder()
|
||||
.embeddedMessageId(embeddedMessage.getMessageId())
|
||||
.embeddedChannel(embeddedChannel)
|
||||
.embeddedServer(embeddedServer)
|
||||
.embeddingServer(embeddingServer)
|
||||
.embeddingChannel(embeddingChannel)
|
||||
.embeddingMessageId(messageContainingEmbed.getIdLong())
|
||||
.embeddedUser(embeddedAuthor)
|
||||
.embeddingUser(cause)
|
||||
.build();
|
||||
|
||||
embeddedMessageRepository.save(messageEmbedPost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<EmbeddedMessage> findEmbeddedPostByMessageId(Long messageId) {
|
||||
return Optional.ofNullable(embeddedMessageRepository.findByEmbeddingMessageId(messageId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteEmbeddedMessage(EmbeddedMessage embeddedMessage) {
|
||||
embeddedMessageRepository.delete(embeddedMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteEmbeddedMessageTransactional(EmbeddedMessage embeddedMessage) {
|
||||
this.deleteEmbeddedMessage(embeddedMessage);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "${author.effectiveName}",
|
||||
"avatar": "${author.user.effectiveAvatarUrl}"
|
||||
},
|
||||
"color" : {
|
||||
"r": 200,
|
||||
"g": 0,
|
||||
"b": 255
|
||||
},
|
||||
<#if embeddedMessage.content?has_content || embeddedMessage.embeds?size gt 0>
|
||||
"description": "${embeddedMessage.content}
|
||||
<#list embeddedMessage.embeds>
|
||||
Embeds:
|
||||
<#items as embed>
|
||||
Description: ${embed.description} <#if embed.imageUrl?has_content> ImageUrl: ${embed.imageUrl} </#if>
|
||||
</#items>
|
||||
</#list>
|
||||
",
|
||||
</#if>
|
||||
<#if embeddedMessage.attachmentUrls?size gt 0>
|
||||
"imageUrl": "${embeddedMessage.attachmentUrls[0]}",
|
||||
</#if>
|
||||
"fields": [
|
||||
{
|
||||
"name": "Quoted by",
|
||||
"value": "${embeddingUser.asMention} from [${sourceChannel.name}](${embeddedMessage.messageUrl})"
|
||||
}
|
||||
],
|
||||
"timeStamp": "${embeddedMessage.timeCreated}"
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
abstracto.postTargets.utility=suggestions,starboard
|
||||
abstracto.emoteNames.suggestion=suggestionYes,suggestionNo
|
||||
abstracto.emoteNames.starboard=star,star1,star2,star3,star4,starboardBadge1,starboardBadge2,starboardBadge3
|
||||
abstracto.emoteNames.embed=removeEmbed
|
||||
abstracto.starboard.lvl[0]=5
|
||||
abstracto.starboard.lvl[1]=8
|
||||
abstracto.starboard.lvl[2]=13
|
||||
|
||||
Reference in New Issue
Block a user