mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-14 03:45:57 +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.UtilityModuleDefinition;
|
||||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
||||||
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
|
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
|
||||||
<property name="youtubeFeature" value="(SELECT id FROM feature WHERE key = 'youtube')"/>
|
<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">
|
<changeSet author="Sheldan" id="webservices_youtube-commands">
|
||||||
<insert tableName="command">
|
<insert tableName="command">
|
||||||
@@ -17,4 +18,12 @@
|
|||||||
</insert>
|
</insert>
|
||||||
</changeSet>
|
</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>
|
</databaseChangeLog>
|
||||||
@@ -10,5 +10,8 @@
|
|||||||
<insert tableName="feature">
|
<insert tableName="feature">
|
||||||
<column name="key" value="youtube"/>
|
<column name="key" value="youtube"/>
|
||||||
</insert>
|
</insert>
|
||||||
|
<insert tableName="feature">
|
||||||
|
<column name="key" value="urban"/>
|
||||||
|
</insert>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
@@ -6,5 +6,5 @@
|
|||||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
|
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/dbchangelog-ext dbchangelog-3.8.xsd
|
||||||
http://www.liquibase.org/xml/ns/pro 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>
|
</databaseChangeLog>
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
abstracto.featureFlags.youtube.featureName=youtube
|
abstracto.featureFlags.youtube.featureName=youtube
|
||||||
abstracto.featureFlags.youtube.enabled=false
|
abstracto.featureFlags.youtube.enabled=false
|
||||||
|
|
||||||
|
abstracto.featureFlags.urban.featureName=urban
|
||||||
|
abstracto.featureFlags.urban.enabled=false
|
||||||
|
|
||||||
abstracto.feature.youtube.apiKey=${YOUTUBE_API_KEY}
|
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
|
@Getter
|
||||||
public enum WebserviceFeatureDefinition implements FeatureDefinition {
|
public enum WebserviceFeatureDefinition implements FeatureDefinition {
|
||||||
YOUTUBE("youtube");
|
YOUTUBE("youtube"), URBAN_DICTIONARY("urban");
|
||||||
|
|
||||||
private String key;
|
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.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@@ -35,6 +36,7 @@ public class CoreConfig {
|
|||||||
public Gson gson() {
|
public Gson gson() {
|
||||||
return new GsonBuilder()
|
return new GsonBuilder()
|
||||||
.registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
|
.registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
|
||||||
|
.registerTypeAdapter(Instant.class, new InstantTimeAdapter())
|
||||||
.setPrettyPrinting().create();
|
.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.JsonDeserializationContext;
|
||||||
import com.google.gson.JsonDeserializer;
|
import com.google.gson.JsonDeserializer;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -15,7 +14,7 @@ import java.time.temporal.TemporalAccessor;
|
|||||||
public class OffsetDateTimeAdapter implements JsonDeserializer<OffsetDateTime> {
|
public class OffsetDateTimeAdapter implements JsonDeserializer<OffsetDateTime> {
|
||||||
|
|
||||||
@Override
|
@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());
|
TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse(jsonElement.getAsString());
|
||||||
Instant i = Instant.from(ta);
|
Instant i = Instant.from(ta);
|
||||||
return OffsetDateTime.ofInstant(i, ZoneId.systemDefault());
|
return OffsetDateTime.ofInstant(i, ZoneId.systemDefault());
|
||||||
|
|||||||
@@ -11,3 +11,12 @@ Search for a youtube video::
|
|||||||
* Usage: `youtubeSearch <query>`
|
* Usage: `youtubeSearch <query>`
|
||||||
* Aliases: `yt`
|
* Aliases: `yt`
|
||||||
* Description: Searches youtube for a video with this query, and returns the link with additional information.
|
* 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