mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-28 08:38:52 +00:00
[AB-82] adding urban dictionary api with a command
adding Instant handling to GSON
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.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.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.webservices.config.WebserviceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.webservices.urban.model.UrbanDefinition;
|
||||
import dev.sheldan.abstracto.webservices.urban.model.UrbanResponseModel;
|
||||
import dev.sheldan.abstracto.webservices.urban.service.UrbanService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class UrbanDefine extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private UrbanService urbanService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
private static final String URBAN_DEFINE_RESPONSE_MODEL_TEMPLATE_KEY = "urban_define_response_model";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
String parameter = (String) commandContext.getParameters().getParameters().get(0);
|
||||
try {
|
||||
UrbanDefinition definition = urbanService.getUrbanDefinition(parameter);
|
||||
UrbanResponseModel model = (UrbanResponseModel) ContextConverter.slimFromCommandContext(commandContext, UrbanResponseModel.class);
|
||||
model.setDefinition(definition);
|
||||
MessageToSend message = templateService.renderEmbedTemplate(URBAN_DEFINE_RESPONSE_MODEL_TEMPLATE_KEY, model);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(message, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
} catch (IOException e) {
|
||||
throw new AbstractoRunTimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("searchQuery").type(String.class).remainder(true).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
List<String> aliases = Arrays.asList("ud");
|
||||
return CommandConfiguration.builder()
|
||||
.name("urbanDefine")
|
||||
.module(UtilityModuleDefinition.UTILITY)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.aliases(aliases)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(false)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return WebserviceFeatureDefinition.URBAN_DICTIONARY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class UrbanResponse {
|
||||
private List<UrbanResponseDefinition> list;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class UrbanResponseDefinition {
|
||||
private String definition;
|
||||
private String permalink;
|
||||
private Long thumbs_up;
|
||||
private Long thumbs_down;
|
||||
private String author;
|
||||
private String word;
|
||||
private Long defid;
|
||||
private Instant written_on;
|
||||
private String example;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.service;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.webservices.urban.exception.NoUrbanDefinitionFoundException;
|
||||
import dev.sheldan.abstracto.webservices.urban.model.UrbanDefinition;
|
||||
import dev.sheldan.abstracto.webservices.urban.model.UrbanResponse;
|
||||
import dev.sheldan.abstracto.webservices.urban.model.UrbanResponseDefinition;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class UrbanServiceBean implements UrbanService {
|
||||
|
||||
@Autowired
|
||||
private OkHttpClient okHttpClient;
|
||||
|
||||
@Value("${abstracto.feature.webservices.urban.requestURL}")
|
||||
private String requestUrl;
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public UrbanDefinition getUrbanDefinition(String query) throws IOException {
|
||||
Request request = new Request.Builder().url(String.format(requestUrl, query)).get().build();
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
UrbanResponse urbanResponse = gson.fromJson(response.body().string(), UrbanResponse.class);
|
||||
if(urbanResponse.getList().isEmpty()) {
|
||||
throw new NoUrbanDefinitionFoundException();
|
||||
} else {
|
||||
UrbanResponseDefinition definition = urbanResponse.getList().get(0);
|
||||
return UrbanDefinition
|
||||
.builder()
|
||||
.definition(definition.getDefinition())
|
||||
.author(definition.getAuthor())
|
||||
.url(definition.getPermalink())
|
||||
.creationDate(definition.getWritten_on())
|
||||
.downVoteCount(definition.getThumbs_down())
|
||||
.upvoteCount(definition.getThumbs_up())
|
||||
.example(definition.getExample())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.webservices.youtube.commands;
|
||||
package dev.sheldan.abstracto.webservices.youtube.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
@@ -8,6 +8,7 @@
|
||||
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
||||
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
|
||||
<property name="youtubeFeature" value="(SELECT id FROM feature WHERE key = 'youtube')"/>
|
||||
<property name="urbanFeature" value="(SELECT id FROM feature WHERE key = 'urban')"/>
|
||||
|
||||
<changeSet author="Sheldan" id="webservices_youtube-commands">
|
||||
<insert tableName="command">
|
||||
@@ -17,4 +18,12 @@
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="Sheldan" id="webservices_urban-commands">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="urbanDefine"/>
|
||||
<column name="module_id" valueComputed="${utilityModule}"/>
|
||||
<column name="feature_id" valueComputed="${urbanFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -10,5 +10,8 @@
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="youtube"/>
|
||||
</insert>
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="urban"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -6,5 +6,5 @@
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
|
||||
<include file="1.0-webservices/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.5-webservices/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -1,4 +1,9 @@
|
||||
abstracto.featureFlags.youtube.featureName=youtube
|
||||
abstracto.featureFlags.youtube.enabled=false
|
||||
|
||||
abstracto.feature.youtube.apiKey=${YOUTUBE_API_KEY}
|
||||
abstracto.featureFlags.urban.featureName=urban
|
||||
abstracto.featureFlags.urban.enabled=false
|
||||
|
||||
abstracto.feature.youtube.apiKey=${YOUTUBE_API_KEY}
|
||||
|
||||
abstracto.feature.webservices.urban.requestURL=https://api.urbandictionary.com/v0/define?term=%s
|
||||
@@ -5,7 +5,7 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum WebserviceFeatureDefinition implements FeatureDefinition {
|
||||
YOUTUBE("youtube");
|
||||
YOUTUBE("youtube"), URBAN_DICTIONARY("urban");
|
||||
|
||||
private String key;
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.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 UrbanFeatureConfig implements FeatureConfig {
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return WebserviceFeatureDefinition.URBAN_DICTIONARY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public class NoUrbanDefinitionFoundException extends AbstractoRunTimeException implements Templatable {
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "no_urban_definition_found_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class UrbanDefinition {
|
||||
private String definition;
|
||||
private String author;
|
||||
private String example;
|
||||
private Instant creationDate;
|
||||
private String url;
|
||||
private Long upvoteCount;
|
||||
private Long downVoteCount;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.model;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
public class UrbanResponseModel extends SlimUserInitiatedServerContext {
|
||||
private UrbanDefinition definition;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.webservices.urban.service;
|
||||
|
||||
import dev.sheldan.abstracto.webservices.urban.model.UrbanDefinition;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface UrbanService {
|
||||
UrbanDefinition getUrbanDefinition(String query) throws IOException;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -35,6 +36,7 @@ public class CoreConfig {
|
||||
public Gson gson() {
|
||||
return new GsonBuilder()
|
||||
.registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
|
||||
.registerTypeAdapter(Instant.class, new InstantTimeAdapter())
|
||||
.setPrettyPrinting().create();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.core.config;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
public class InstantTimeAdapter implements JsonDeserializer<Instant> {
|
||||
|
||||
@Override
|
||||
public Instant deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) {
|
||||
TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse(jsonElement.getAsString());
|
||||
return Instant.from(ta);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package dev.sheldan.abstracto.core.config;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.Instant;
|
||||
@@ -15,7 +14,7 @@ import java.time.temporal.TemporalAccessor;
|
||||
public class OffsetDateTimeAdapter implements JsonDeserializer<OffsetDateTime> {
|
||||
|
||||
@Override
|
||||
public OffsetDateTime deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
|
||||
public OffsetDateTime deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) {
|
||||
TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse(jsonElement.getAsString());
|
||||
Instant i = Instant.from(ta);
|
||||
return OffsetDateTime.ofInstant(i, ZoneId.systemDefault());
|
||||
|
||||
@@ -11,3 +11,12 @@ Search for a youtube video::
|
||||
* Usage: `youtubeSearch <query>`
|
||||
* Aliases: `yt`
|
||||
* Description: Searches youtube for a video with this query, and returns the link with additional information.
|
||||
|
||||
=== Urban dictionary
|
||||
Feature key: `urban`
|
||||
|
||||
==== Command
|
||||
Search for an urban dictionary definition::
|
||||
* Usage: `urbanDefine <query>`
|
||||
* Aliases: `ud`
|
||||
* Description: Searches an urban dictionary definition, and returns the definition, with an example and meta information.
|
||||
Reference in New Issue
Block a user