mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-13 11:31:38 +00:00
[AB-97] adding react command
we are now actively loading messages in case its a parameter, because the provided message is only partially available
This commit is contained in:
@@ -57,6 +57,10 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.ChooseResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -13,7 +13,7 @@ import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.EightBallResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -12,7 +12,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.LoveCalcResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -13,7 +13,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.MockResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.MockResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package dev.sheldan.abstracto.entertainment.command;
|
||||
|
||||
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.ReactionService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.exception.ReactTooManyReactionsException;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class React extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@Autowired
|
||||
private ReactionService reactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Message message = (Message) parameters.get(0);
|
||||
String text = (String) parameters.get(1);
|
||||
|
||||
List<String> reactionChars = entertainmentService.convertTextToEmojis(text);
|
||||
int existingReactions = message.getReactions().size();
|
||||
if(reactionChars.size() + existingReactions > Message.MAX_REACTIONS) {
|
||||
throw new ReactTooManyReactionsException();
|
||||
}
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
reactionChars.forEach(s -> futures.add(reactionService.addDefaultReactionToMessageAsync(s, message)));
|
||||
return FutureUtils.toSingleFutureGeneric(futures)
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("message").type(Message.class).templated(true).build());
|
||||
parameters.add(Parameter.builder().name("text").type(String.class).remainder(true).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("react")
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.causesReaction(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ENTERTAINMENT;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.RollResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -12,7 +12,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.RouletteResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
package dev.sheldan.abstracto.entertainment.service;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
|
||||
import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException;
|
||||
import dev.sheldan.abstracto.entertainment.model.ReactMapping;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class EntertainmentServiceBean implements EntertainmentService {
|
||||
|
||||
public static final List<String> EIGHT_BALL_ANSWER_KEYS = Arrays.asList(
|
||||
@@ -20,12 +30,20 @@ public class EntertainmentServiceBean implements EntertainmentService {
|
||||
"DONT_COUNT", "REPLY_NO", "SOURCES_NO", "OUTLOOK_NOT_GOOD", "DOUBTFUL" // negative
|
||||
);
|
||||
|
||||
private ReactMapping reactMapping;
|
||||
|
||||
@Autowired
|
||||
private SecureRandom secureRandom;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Value("classpath:react_mappings.json")
|
||||
private Resource reactMappingSource;
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public String getEightBallValue(String text) {
|
||||
return EIGHT_BALL_ANSWER_KEYS.get(secureRandom.nextInt(EIGHT_BALL_ANSWER_KEYS.size()));
|
||||
@@ -57,6 +75,9 @@ public class EntertainmentServiceBean implements EntertainmentService {
|
||||
|
||||
@Override
|
||||
public String createMockText(String text, Member memberExecuting, Member mockedUser) {
|
||||
if(text == null) {
|
||||
return "";
|
||||
}
|
||||
char[] textChars = text.toLowerCase().toCharArray();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0, textCharsLength = textChars.length; i < textCharsLength; i++) {
|
||||
@@ -69,4 +90,101 @@ public class EntertainmentServiceBean implements EntertainmentService {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> convertTextToEmojis(String text) {
|
||||
return convertTextToEmojis(text, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertTextToEmojisAString(String text) {
|
||||
return String.join("", convertTextToEmojis(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> convertTextToEmojis(String text, boolean allowDuplicates) {
|
||||
if(text == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
text = text.toLowerCase();
|
||||
// we have to have a separate set to check for combo duplicates, because the checks are different:
|
||||
// first check is if we already used it as an replacement
|
||||
// the second check below is whether or not we used it as a replacement, that way we allow
|
||||
// unicode cars from users as well, this leads to things like sos[sos] not being allowed, because the
|
||||
// unicode chars get removed, and the first sos gets replaced with the unicode
|
||||
Set<String> replacedCombos = new HashSet<>();
|
||||
List<String> result = new ArrayList<>();
|
||||
// this is used to replace the replacements for more than one character
|
||||
for (String s : this.reactMapping.getCombinationKeys()) {
|
||||
if (text.contains(s)) {
|
||||
String replacement = this.reactMapping.getCombination().get(s);
|
||||
if(!replacedCombos.contains(replacement) || allowDuplicates) {
|
||||
if(allowDuplicates) {
|
||||
text = text.replaceAll(s, replacement);
|
||||
} else {
|
||||
text = text.replaceFirst(s, replacement);
|
||||
}
|
||||
replacedCombos.add(replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> usedReplacements = new HashSet<>();
|
||||
char[] split = text.toCharArray();
|
||||
|
||||
for (int i = 0, splitLength = split.length; i < splitLength; i++) {
|
||||
char normalCharacter = split[i];
|
||||
String charAsString = Character.toString(normalCharacter);
|
||||
// the split, also splits surrogate chars (naturally), therefore we need this additional checks
|
||||
// to ignore the first part, and connect the chars again in order to check them
|
||||
if(Character.isHighSurrogate(normalCharacter)) {
|
||||
continue;
|
||||
}
|
||||
// in this case we already have unicode, this can either come from the multiple char replacement
|
||||
// or because we already got unicode to begin with (multi char only), in that case, we also do a duplicate check
|
||||
// and add it directly
|
||||
if(Character.isLowSurrogate(normalCharacter)) {
|
||||
String usedUnicode = split[i - 1] + charAsString;
|
||||
if(!usedReplacements.contains(usedUnicode) || allowDuplicates) {
|
||||
usedReplacements.add(usedUnicode);
|
||||
result.add(usedUnicode);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// reject any other character, as the ones we can deal with
|
||||
if (!this.reactMapping.getSingle().containsKey(charAsString)) {
|
||||
continue;
|
||||
}
|
||||
List<String> listToUse = this.reactMapping.getSingle().get(charAsString);
|
||||
boolean foundReplacement = false;
|
||||
for (String replacementChar : listToUse) {
|
||||
if (!usedReplacements.contains(replacementChar) || allowDuplicates) {
|
||||
result.add(replacementChar);
|
||||
usedReplacements.add(replacementChar);
|
||||
foundReplacement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundReplacement) {
|
||||
throw new ReactDuplicateCharacterException();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertTextToEmojisAsString(String text, boolean allowDuplicates) {
|
||||
return String.join("", convertTextToEmojis(text, allowDuplicates));
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
try {
|
||||
JsonReader reader = new JsonReader(new InputStreamReader(reactMappingSource.getInputStream()));
|
||||
this.reactMapping = gson.fromJson(reader, ReactMapping.class);
|
||||
this.reactMapping.populateKeys();
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to load react bindings.", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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="entertainment-seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?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="entertainmentModule" value="(SELECT id FROM module WHERE name = 'entertainment')"/>
|
||||
<property name="entertainmentFeature" value="(SELECT id FROM feature WHERE key = 'entertainment')"/>
|
||||
|
||||
<changeSet author="Sheldan" id="react-command">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="react"/>
|
||||
<column name="module_id" valueComputed="${entertainmentModule}"/>
|
||||
<column name="feature_id" valueComputed="${entertainmentFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -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="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -8,4 +8,5 @@
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
|
||||
<include file="1.0-entertainment/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.8-entertainment/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.9-entertainment/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,280 @@
|
||||
{
|
||||
"source": "https://github.com/TrustyJAID/Trusty-cogs/blob/master/fun/constants.py with additions",
|
||||
"single": {
|
||||
"a": [
|
||||
"🇦",
|
||||
"🅰",
|
||||
"🍙",
|
||||
"🔼",
|
||||
"4⃣",
|
||||
"🇱🇨",
|
||||
"🎄",
|
||||
"🌲",
|
||||
"🖇️",
|
||||
"🔼"
|
||||
],
|
||||
"b": [
|
||||
"🇧",
|
||||
"🅱",
|
||||
"8⃣"
|
||||
],
|
||||
"c": [
|
||||
"🇨",
|
||||
"🗜"
|
||||
],
|
||||
"d": [
|
||||
"🇩",
|
||||
"↩"
|
||||
],
|
||||
"e": [
|
||||
"🇪",
|
||||
"3⃣",
|
||||
"📧",
|
||||
"💶"
|
||||
],
|
||||
"f": [
|
||||
"🇫",
|
||||
"🎏",
|
||||
"🚩",
|
||||
"🏳️️",
|
||||
"🏴",
|
||||
"🏁"
|
||||
],
|
||||
"g": [
|
||||
"🇬",
|
||||
"🗜",
|
||||
"6️⃣",
|
||||
"9⃣",
|
||||
"⛽"
|
||||
],
|
||||
"h": [
|
||||
"🇭",
|
||||
"♓",
|
||||
"🏩",
|
||||
"⛩️",
|
||||
"🪜"
|
||||
],
|
||||
"i": [
|
||||
"🇮",
|
||||
"ℹ",
|
||||
"🚹",
|
||||
"1⃣",
|
||||
"📍"
|
||||
],
|
||||
"j": [
|
||||
"🇯",
|
||||
"🗾"
|
||||
],
|
||||
"k": [
|
||||
"🇰",
|
||||
"🎋"
|
||||
],
|
||||
"l": [
|
||||
"🇱",
|
||||
"1⃣",
|
||||
"🇮",
|
||||
"👢",
|
||||
"💷"
|
||||
],
|
||||
"m": [
|
||||
"🇲",
|
||||
"Ⓜ",
|
||||
"📉"
|
||||
],
|
||||
"n": [
|
||||
"🇳",
|
||||
"♑",
|
||||
"🎵"
|
||||
],
|
||||
"o": [
|
||||
"🇴",
|
||||
"🅾",
|
||||
"0⃣",
|
||||
"⭕",
|
||||
"🔘",
|
||||
"⏺",
|
||||
"⚪",
|
||||
"⚫",
|
||||
"🔵",
|
||||
"🔴",
|
||||
"💫",
|
||||
"⚽",
|
||||
"🏀",
|
||||
"⚾",
|
||||
"🥎",
|
||||
"🎾",
|
||||
"🏐",
|
||||
"💿",
|
||||
"📀",
|
||||
"🧭",
|
||||
"☯️"
|
||||
],
|
||||
"p": [
|
||||
"🇵",
|
||||
"🅿",
|
||||
"🚏"
|
||||
],
|
||||
"q": [
|
||||
"🇶",
|
||||
"♌"
|
||||
],
|
||||
"r": [
|
||||
"🇷"
|
||||
],
|
||||
"s": [
|
||||
"🇸",
|
||||
"💲",
|
||||
"5⃣",
|
||||
"⚡",
|
||||
"💰",
|
||||
"💵"
|
||||
],
|
||||
"t": [
|
||||
"🇹",
|
||||
"✝",
|
||||
"➕",
|
||||
"🎚",
|
||||
"🌴",
|
||||
"7⃣"
|
||||
],
|
||||
"u": [
|
||||
"🇺",
|
||||
"⛎",
|
||||
"🐉"
|
||||
],
|
||||
"v": [
|
||||
"🇻",
|
||||
"♈",
|
||||
"☑"
|
||||
],
|
||||
"w": [
|
||||
"🇼",
|
||||
"〰",
|
||||
"📈"
|
||||
],
|
||||
"x": [
|
||||
"🇽",
|
||||
"❎",
|
||||
"✖",
|
||||
"❌",
|
||||
"⚒",
|
||||
"🏴☠",
|
||||
"✂️️"
|
||||
],
|
||||
"y": [
|
||||
"🇾",
|
||||
"✌",
|
||||
"💴"
|
||||
],
|
||||
"z": [
|
||||
"🇿",
|
||||
"2⃣"
|
||||
],
|
||||
"0": [
|
||||
"0⃣",
|
||||
"🅾",
|
||||
"0⃣",
|
||||
"⭕",
|
||||
"🔘",
|
||||
"⏺",
|
||||
"⚪",
|
||||
"⚫",
|
||||
"🔵",
|
||||
"🔴",
|
||||
"💫",
|
||||
"⚽",
|
||||
"🏀",
|
||||
"⚾",
|
||||
"🥎",
|
||||
"🎾",
|
||||
"🏐",
|
||||
"💿",
|
||||
"📀",
|
||||
"🧭",
|
||||
"☯️"
|
||||
],
|
||||
"1": [
|
||||
"1⃣",
|
||||
"🇮"
|
||||
],
|
||||
"2": [
|
||||
"2⃣",
|
||||
"🇿"
|
||||
],
|
||||
"3": [
|
||||
"3⃣"
|
||||
],
|
||||
"4": [
|
||||
"4⃣"
|
||||
],
|
||||
"5": [
|
||||
"5⃣",
|
||||
"🇸",
|
||||
"💲",
|
||||
"⚡"
|
||||
],
|
||||
"6": [
|
||||
"6⃣"
|
||||
],
|
||||
"7": [
|
||||
"7⃣"
|
||||
],
|
||||
"8": [
|
||||
"8⃣",
|
||||
"🎱",
|
||||
"🇧",
|
||||
"🅱"
|
||||
],
|
||||
"9": [
|
||||
"9⃣"
|
||||
],
|
||||
"?": [
|
||||
"❓"
|
||||
],
|
||||
"!": [
|
||||
"❗",
|
||||
"❕",
|
||||
"⚠",
|
||||
"❣"
|
||||
]
|
||||
},
|
||||
"combination": {
|
||||
"abcd": "🔠",
|
||||
"1234": "🔢",
|
||||
"cool": "🆒",
|
||||
"back": "🔙",
|
||||
"777": "🎰",
|
||||
"soon": "🔜",
|
||||
"free": "🆓",
|
||||
"end": "🔚",
|
||||
"top": "🔝",
|
||||
"abc": "🔤",
|
||||
"atm": "🏧",
|
||||
"new": "🆕",
|
||||
"sos": "🆘",
|
||||
"100": "💯",
|
||||
"loo": "💯",
|
||||
"zzz": "💤",
|
||||
"...": "💬",
|
||||
"ng": "🆖",
|
||||
"id": "🆔",
|
||||
"vs": "🆚",
|
||||
"wc": "🚾",
|
||||
"ab": "🆎",
|
||||
"cl": "🆑",
|
||||
"ok": "🆗",
|
||||
"up": "🆙",
|
||||
"10": "🔟",
|
||||
"24": "🏪",
|
||||
"11": "⏸",
|
||||
"ll": "⏸",
|
||||
"ii": "⏸",
|
||||
"18": "🏪",
|
||||
"tm": "™",
|
||||
"on": "🔛",
|
||||
"oo": "🈁",
|
||||
"!?": "⁉",
|
||||
"!!": "‼",
|
||||
"17": "📅"
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
|
||||
import dev.sheldan.abstracto.entertainment.model.ChooseResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
|
||||
import dev.sheldan.abstracto.entertainment.model.EightBallResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
|
||||
import dev.sheldan.abstracto.entertainment.model.LoveCalcResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
|
||||
import dev.sheldan.abstracto.entertainment.model.RollResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
|
||||
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
|
||||
import dev.sheldan.abstracto.entertainment.model.RouletteResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
package dev.sheldan.abstracto.entertainment.service;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
|
||||
import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException;
|
||||
import dev.sheldan.abstracto.entertainment.model.ReactMapping;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -29,6 +42,19 @@ public class EntertainmentServiceBeanTest {
|
||||
@Mock
|
||||
private ConfigService configService;
|
||||
|
||||
// requires the org.mockito.plugins.MockMaker file
|
||||
@Mock
|
||||
private Gson gson;
|
||||
|
||||
@Mock
|
||||
private Resource resource;
|
||||
|
||||
@Mock
|
||||
private Member member;
|
||||
|
||||
@Mock
|
||||
private Member secondMember;
|
||||
|
||||
private static final String INPUT_TEXT = "input";
|
||||
private static final int RANDOM_VALUE = 0;
|
||||
|
||||
@@ -94,4 +120,99 @@ public class EntertainmentServiceBeanTest {
|
||||
Assert.assertEquals(choices.get(0), choiceTaken);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMocking() {
|
||||
Assert.assertEquals("AsDf", testUnit.createMockText("asdf", member, secondMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMockingUpperCase() {
|
||||
Assert.assertEquals("AsDf", testUnit.createMockText("ASDF", member, secondMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMockingNull() {
|
||||
Assert.assertEquals("", testUnit.createMockText(null, member, secondMember));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojis() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("bceg", testUnit.convertTextToEmojisAsString("asdf", false));
|
||||
}
|
||||
|
||||
@Test(expected = ReactDuplicateCharacterException.class)
|
||||
public void testConvertTextToEmojisDuplicateReplacement() throws IOException {
|
||||
setupMappings();
|
||||
testUnit.convertTextToEmojisAsString("aa", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisNoReplacementFound() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("", testUnit.convertTextToEmojisAsString("e", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisNullInput() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("", testUnit.convertTextToEmojisAsString(null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisDoubleUnicodePassThrough() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("\uD83C\uDD98", testUnit.convertTextToEmojisAsString("\uD83C\uDD98", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisDuplicate() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("bb", testUnit.convertTextToEmojisAsString("aa", true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisCombinations() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("\uD83C\uDD98", testUnit.convertTextToEmojisAsString("kk", true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisCombinationWithNormalText() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("\uD83C\uDD98l", testUnit.convertTextToEmojisAsString("kkk", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisCombinationWithNormalTextMixed() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("\uD83C\uDD98lm", testUnit.convertTextToEmojisAsString("kkkk", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertTextToEmojisCombinationDuplicates() throws IOException {
|
||||
setupMappings();
|
||||
Assert.assertEquals("\uD83C\uDD98\uD83C\uDD98", testUnit.convertTextToEmojisAsString("kkkk", true));
|
||||
}
|
||||
|
||||
private void setupMappings() throws IOException {
|
||||
ReactMapping mapping = Mockito.mock(ReactMapping.class);
|
||||
HashMap<String, List<String>> singleMappings = new HashMap<>();
|
||||
singleMappings.put("a", Arrays.asList("b"));
|
||||
singleMappings.put("s", Arrays.asList("c"));
|
||||
singleMappings.put("d", Arrays.asList("e"));
|
||||
singleMappings.put("f", Arrays.asList("g"));
|
||||
singleMappings.put("k", Arrays.asList("l", "m"));
|
||||
when(resource.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[]{1}));
|
||||
when(mapping.getSingle()).thenReturn(singleMappings);
|
||||
HashMap<String, String> combinations = new HashMap<>();
|
||||
combinations.put("kk", "\uD83C\uDD98");
|
||||
when(mapping.getCombination()).thenReturn(combinations);
|
||||
TreeSet<String> combinationKeys = new TreeSet<>();
|
||||
combinationKeys.add("kk");
|
||||
when(mapping.getCombinationKeys()).thenReturn(combinationKeys);
|
||||
when(gson.fromJson(any(JsonReader.class), eq(ReactMapping.class))).thenReturn(mapping);
|
||||
testUnit.postConstruct();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
mock-maker-inline
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.sheldan.abstracto.entertainment.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public class ReactDuplicateCharacterException extends AbstractoRunTimeException implements Templatable {
|
||||
|
||||
public ReactDuplicateCharacterException() {
|
||||
super("Could not replace all characters to be duplicate free.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "react_duplicate_character_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.sheldan.abstracto.entertainment.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public class ReactTooManyReactionsException extends AbstractoRunTimeException implements Templatable {
|
||||
|
||||
public ReactTooManyReactionsException() {
|
||||
super("Adding reactions would lead to too many reactions.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "react_too_many_reactions_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReactMapping {
|
||||
@Builder.Default
|
||||
private HashMap<String, List<String>> single = new HashMap<>();
|
||||
|
||||
@Builder.Default
|
||||
private HashMap<String, String> combination = new HashMap<>();
|
||||
|
||||
@Builder.Default
|
||||
private SortedSet<String> combinationKeys = new TreeSet<>((o1, o2) -> {
|
||||
if(o2.length() == o1.length()) {
|
||||
return o2.compareTo(o1);
|
||||
} else {
|
||||
return Integer.compare(o2.length(), o1.length());
|
||||
}
|
||||
});
|
||||
|
||||
@Builder.Default
|
||||
private Set<String> combinationReplacements = new HashSet<>();
|
||||
|
||||
public void populateKeys() {
|
||||
combinationKeys.addAll(combination.keySet());
|
||||
combinationKeys.forEach(s -> combinationReplacements.add(this.combination.get(s)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
package dev.sheldan.abstracto.entertainment.model.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
package dev.sheldan.abstracto.entertainment.model.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
package dev.sheldan.abstracto.entertainment.model.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
package dev.sheldan.abstracto.entertainment.model.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
package dev.sheldan.abstracto.entertainment.model.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.entertainment.model;
|
||||
package dev.sheldan.abstracto.entertainment.model.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.entertainment.service;
|
||||
|
||||
import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
import java.util.List;
|
||||
@@ -11,4 +12,64 @@ public interface EntertainmentService {
|
||||
boolean executeRoulette(Member memberExecuting);
|
||||
String takeChoice(List<String> choices, Member memberExecuting);
|
||||
String createMockText(String text, Member memberExecuting, Member mockedUser);
|
||||
|
||||
/**
|
||||
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
|
||||
* characters as a list. If the given text is null, an empty list will be returned. This method will actively try
|
||||
* to avoid duplicates, and try to use alternatives, and throw an exception in case it was not possible to return unique values.
|
||||
* The size of the list might not be equal to the length of the provided string, because sometimes multiple
|
||||
* characters are combined into one unicode char.
|
||||
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
|
||||
* in case there too many duplicated characters
|
||||
* @param text The text to convert
|
||||
* @return A {@link List} of unicode characters, represented as strings, which look similar to the individual characters
|
||||
* from the text
|
||||
*/
|
||||
List<String> convertTextToEmojis(String text);
|
||||
|
||||
/**
|
||||
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
|
||||
* characters as a string. If the given text is null, an empty string will be returned. This method will actively try
|
||||
* to avoid duplicates, and try to use alternatives, and throw an exception in case it was not possible to return unique values.
|
||||
* The length of the string might not be equal to the length of the provided string, because sometimes multiple
|
||||
* characters are combined into one unicode char.
|
||||
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
|
||||
* in case there too many duplicated characters
|
||||
* @param text The text to convert
|
||||
* @return A string of unicode characters which look similar to the individual characters from the text
|
||||
*/
|
||||
String convertTextToEmojisAString(String text);
|
||||
|
||||
/**
|
||||
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
|
||||
* characters as a list. If the given text is null, an empty list will be returned. This method will actively try
|
||||
* to avoid duplicates (if requested), and try to use alternatives, and throw an exception in case it was not possible
|
||||
* to return unique values. In case duplicates are allowed, the first possible replacement value will be used,
|
||||
* leading to all 1:1 replacements being of the same character.
|
||||
* The size of the list might not be equal to the length of the provided string, because sometimes multiple
|
||||
* characters are combined into one unicode char.
|
||||
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
|
||||
* in case there too many duplicated characters
|
||||
* @param text The text to convert
|
||||
* @param allowDuplicates Whether or not to allow duplicates
|
||||
* @return A list of characters, represented as strings, which look similar to the individual characters
|
||||
* from the text, possible with duplicates, if requested
|
||||
*/
|
||||
List<String> convertTextToEmojis(String text, boolean allowDuplicates);
|
||||
|
||||
/**
|
||||
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
|
||||
* characters as a string. If the given text is null, an empty string will be returned. This method will actively try
|
||||
* to avoid duplicates (if requested), and try to use alternatives, and throw an exception in case it was not possible
|
||||
* to return unique values. In case duplicates are allowed, the first possible replacement value will be used,
|
||||
* leading to all 1:1 replacements being of the same character.
|
||||
* The length of the string might not be equal to the length of the provided string, because sometimes multiple
|
||||
* characters are combined into one unicode char.
|
||||
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
|
||||
* in case there too many duplicated characters
|
||||
* @param text The text to convert
|
||||
* @param allowDuplicates Whether or not to allow duplicates
|
||||
* @return A string of unicode characters which look similar to the individual characters from the text
|
||||
*/
|
||||
String convertTextToEmojisAsString(String text, boolean allowDuplicates);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user