[AB-75] adding thread reader command

This commit is contained in:
Sheldan
2022-10-22 14:55:18 +02:00
parent 4fe81c0ea2
commit e3dd89b0ef
14 changed files with 227 additions and 4 deletions

View File

@@ -0,0 +1,91 @@
package dev.sheldan.abstracto.webservices.threadreader.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.webservices.config.WebserviceFeatureDefinition;
import dev.sheldan.abstracto.webservices.threadreader.exception.NoTwitterLinkFoundException;
import dev.sheldan.abstracto.webservices.threadreader.model.ThreadReaderCommandResponseModel;
import dev.sheldan.abstracto.webservices.threadreader.service.ThreadReaderService;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
public class ThreadReaderCommand extends AbstractConditionableCommand {
public static final String THREAD_READER_RESPONSE_TEMPLATE_KEY = "threadReader_response";
public static final String THREAD_READER_COMMAND = "threadReader";
public static final String MESSAGE_PARAMETER = "message";
@Autowired
private ThreadReaderService threadReaderService;
@Autowired
private ChannelService channelService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
Message message = (Message) parameters.get(0);
String messageText = message.getContentRaw();
Optional<Long> tweetIdOptional = threadReaderService.extractTweetId(messageText);
if(!tweetIdOptional.isPresent()) {
throw new NoTwitterLinkFoundException();
}
Long tweetId = tweetIdOptional.get();
ThreadReaderCommandResponseModel model = ThreadReaderCommandResponseModel
.builder()
.tweetId(tweetId)
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(THREAD_READER_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public FeatureDefinition getFeature() {
return WebserviceFeatureDefinition.THREAD_READER;
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Parameter messageParameter = Parameter
.builder()
.name(MESSAGE_PARAMETER)
.type(Message.class)
.remainder(true)
.templated(true)
.build();
parameters.add(messageParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name(THREAD_READER_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.webservices.threadreader.service;
import org.springframework.stereotype.Component;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public class ThreadReaderServiceBean implements ThreadReaderService {
private static final Pattern TWITTER_STATUS_REGEX = Pattern.compile(".*?https?://twitter\\.com/(?:#!/)?(\\w+)/status(es)?/(?<tweetId>\\d+).*", Pattern.DOTALL);
@Override
public boolean containsTwitterLink(String text) {
return TWITTER_STATUS_REGEX.matcher(text).matches();
}
@Override
public Optional<Long> extractTweetId(String text) {
Matcher matcher = TWITTER_STATUS_REGEX.matcher(text);
return matcher.matches() ? Optional.of(Long.parseLong(matcher.group("tweetId"))) : Optional.empty();
}
}

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.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd">
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -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.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<property name="threadReaderFeature" value="(SELECT id FROM feature WHERE key = 'threadReader')"/>
<changeSet author="Sheldan" id="threadReader-command">
<insert tableName="command">
<column name="name" value="threadReader"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${threadReaderFeature}"/>
</insert>
</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.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>
</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.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="threadReader_feature-insertion">
<insert tableName="feature">
<column name="key" value="threadReader"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -7,4 +7,5 @@
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.2.5-webservices/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.7/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -12,4 +12,7 @@ abstracto.feature.webservices.urban.requestURL=https://api.urbandictionary.com/v
abstracto.featureModes.videoDetails.featureName=youtube
abstracto.featureModes.videoDetails.mode=videoDetails
abstracto.featureModes.videoDetails.enabled=false
abstracto.featureModes.videoDetails.enabled=false
abstracto.featureFlags.threadReader.featureName=threadReader
abstracto.featureFlags.threadReader.enabled=false

View File

@@ -5,7 +5,7 @@ import lombok.Getter;
@Getter
public enum WebserviceFeatureDefinition implements FeatureDefinition {
YOUTUBE("youtube"), URBAN_DICTIONARY("urban");
YOUTUBE("youtube"), URBAN_DICTIONARY("urban"), THREAD_READER("threadReader");
private String key;

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.webservices.threadreader.config;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.webservices.config.WebserviceFeatureDefinition;
import org.springframework.stereotype.Component;
@Component
public class ThreadReaderConfig implements FeatureConfig {
@Override
public FeatureDefinition getFeature() {
return WebserviceFeatureDefinition.THREAD_READER;
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.webservices.threadreader.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class NoTwitterLinkFoundException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "no_twitter_link_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.webservices.threadreader.model;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class ThreadReaderCommandResponseModel {
private Long tweetId;
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.abstracto.webservices.threadreader.service;
import java.util.Optional;
public interface ThreadReaderService {
boolean containsTwitterLink(String text);
Optional<Long> extractTweetId(String text);
}

View File

@@ -43,6 +43,7 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.UnexpectedRollbackException;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@@ -143,8 +144,10 @@ public class CommandReceivedHandler extends ListenerAdapter {
try {
self.executeCommand(event, parsedParameters.getCommand(), parsedParameters.getParameters());
} catch (Exception e) {
reportException(event, null, e, String.format("Exception when executing command from message %d in message %d in guild %d."
, message.getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong()));
if(!(e instanceof UnexpectedRollbackException)) {
reportException(event, null, e, String.format("Exception when executing command from message %d in message %d in guild %d."
, message.getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong()));
}
}
});
parsingFuture.exceptionally(throwable -> {