[AB-xxx] adding wikipedia and dictionary features

This commit is contained in:
Sheldan
2023-12-28 22:27:33 +01:00
parent 8924b75530
commit d4f07bd719
34 changed files with 850 additions and 8 deletions

View File

@@ -9,11 +9,6 @@
<artifactId>webservices-impl</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>

View File

@@ -0,0 +1,137 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.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.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
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.WebServicesSlashCommandNames;
import dev.sheldan.abstracto.webservices.config.WebserviceFeatureDefinition;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.template.DictionaryMeaning;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.template.DictionaryDefinition;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.WordMeaning;
import dev.sheldan.abstracto.webservices.dictionaryapi.service.DictionaryApiService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
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 DictionaryApiDefinitionCommand extends AbstractConditionableCommand {
private static final String DICTIONARY_DEFINITION_RESPONSE_MODEL_TEMPLATE_KEY = "dictionaryDefinition_response";
private static final String DICTIONARY_DEFINITION_COMMAND = "dictionaryDefinition";
private static final String SEARCH_QUERY_PARAMETER = "searchQuery";
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired
private DictionaryApiService dictionaryApiService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
String parameter = (String) commandContext.getParameters().getParameters().get(0);
try {
MessageToSend message = getMessageToSend(commandContext.getGuild().getIdLong(), parameter);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(message, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
} catch (IOException e) {
throw new AbstractoRunTimeException(e);
}
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String query = slashCommandParameterService.getCommandOption(SEARCH_QUERY_PARAMETER, event, String.class);
try {
MessageToSend messageToSend = getMessageToSend(event.getGuild().getIdLong(), query);
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} catch (IOException e) {
throw new AbstractoRunTimeException(e);
}
}
private MessageToSend getMessageToSend(Long serverId, String searchInput) throws IOException {
WordMeaning meaning = dictionaryApiService.getDefinitions(searchInput);
List<DictionaryDefinition> definitions = meaning
.getDefinitions()
.stream().map(DictionaryDefinition::fromWordDefinition).toList();
DictionaryMeaning model = DictionaryMeaning
.builder()
.definitions(definitions)
.word(meaning.getWord())
.build();
return templateService.renderEmbedTemplate(DICTIONARY_DEFINITION_RESPONSE_MODEL_TEMPLATE_KEY, model, serverId);
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Parameter searchQueryParameter = Parameter
.builder()
.name(SEARCH_QUERY_PARAMETER)
.type(String.class)
.templated(true)
.remainder(true)
.build();
parameters.add(searchQueryParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
List<String> aliases = Arrays.asList("dict");
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(WebServicesSlashCommandNames.DICTIONARY)
.commandName("definition")
.build();
return CommandConfiguration.builder()
.name(DICTIONARY_DEFINITION_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true)
.aliases(aliases)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return WebserviceFeatureDefinition.DICTIONARY;
}
}

View File

@@ -0,0 +1,73 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.service;
import com.google.api.client.http.HttpStatusCodes;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import dev.sheldan.abstracto.webservices.dictionaryapi.exception.DictionaryApiRequestException;
import dev.sheldan.abstracto.webservices.dictionaryapi.exception.NoDictionaryApiDefinitionFoundException;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.WordDefinition;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.WordMeaning;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.api.DictionaryApiResponseItem;
import lombok.extern.slf4j.Slf4j;
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;
import java.util.List;
@Component
@Slf4j
public class DictionaryApiServiceBean implements DictionaryApiService {
@Autowired
private OkHttpClient okHttpClient;
@Value("${abstracto.feature.webservices.dictionaryapi.definitionURL}")
private String dictionaryDefinitionURL;
@Autowired
private Gson gson;
@Override
public WordMeaning getDefinitions(String query) throws IOException {
String formattedUrl = dictionaryDefinitionURL.replace("{1}", query);
Request request = new Request.Builder()
.url(formattedUrl)
.get()
.build();
Response response = okHttpClient.newCall(request).execute();
if(response.code() == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
throw new NoDictionaryApiDefinitionFoundException();
}
if(!response.isSuccessful()) {
if(log.isDebugEnabled()) {
log.error("Failed to retrieve dictionary api definition. Response had code {} with body {}.",
response.code(), response.body());
}
throw new DictionaryApiRequestException(response.code());
}
List<DictionaryApiResponseItem> dictionaryapiResponse = gson.fromJson(response.body().string(), new TypeToken<List<DictionaryApiResponseItem>>(){}.getType());
DictionaryApiResponseItem selectedWord = dictionaryapiResponse.get(0);
if(dictionaryapiResponse.size() > 1) {
log.warn("Dictionary had multiple words. One example {}.", selectedWord.getWord());
}
List<WordDefinition> wordDefinitions = selectedWord
.getMeanings()
.stream()
.flatMap(dictionaryApiWordMeaning ->
dictionaryApiWordMeaning
.getDefinitions()
.stream()
.map(WordDefinition::fromResponseDefinition))
.toList();
return WordMeaning
.builder()
.word(selectedWord.getWord())
.definitions(wordDefinitions)
.build();
}
}

View File

@@ -26,7 +26,6 @@ import dev.sheldan.abstracto.webservices.openweathermap.service.OpenWeatherMapSe
import dev.sheldan.abstracto.webservices.openweathermap.service.WeatherService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.checkerframework.checker.index.qual.SameLen;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@@ -0,0 +1,158 @@
package dev.sheldan.abstracto.webservices.wikipedia.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.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.ConfigService;
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.WebServicesSlashCommandNames;
import dev.sheldan.abstracto.webservices.config.WebserviceFeatureDefinition;
import dev.sheldan.abstracto.webservices.wikipedia.config.WikipediaFeatureConfig;
import dev.sheldan.abstracto.webservices.wikipedia.model.WikipediaArticleSummary;
import dev.sheldan.abstracto.webservices.wikipedia.model.template.WikipediaArticleSummaryModel;
import dev.sheldan.abstracto.webservices.wikipedia.service.WikipediaService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
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 WikipediaArticleSummaryCommand extends AbstractConditionableCommand {
private static final String WIKIPEDIA_ARTICLE_SUMMARY_RESPONSE_MODEL_TEMPLATE_KEY = "wikipediaArticleSummary_response";
private static final String WIKIPEDIA_ARTICLE_SUMMARY_COMMAND = "wikipediaArticleSummary";
private static final String SEARCH_QUERY_PARAMETER = "searchQuery";
private static final String LANGUAGE_PARAMETER = "language";
@Autowired
private WikipediaService wikipediaService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired
private ConfigService configService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
String parameter = (String) commandContext.getParameters().getParameters().get(0);
try {
MessageToSend message = getMessageToSend(commandContext.getGuild().getIdLong(), parameter, null);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(message, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
} catch (IOException e) {
throw new AbstractoRunTimeException(e);
}
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String query = slashCommandParameterService.getCommandOption(SEARCH_QUERY_PARAMETER, event, String.class);
String language;
if(slashCommandParameterService.hasCommandOption(LANGUAGE_PARAMETER, event)) {
language = slashCommandParameterService.getCommandOption(LANGUAGE_PARAMETER, event, String.class);
} else {
language = null;
}
try {
MessageToSend messageToSend = getMessageToSend(event.getGuild().getIdLong(), query, language);
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} catch (IOException e) {
throw new AbstractoRunTimeException(e);
}
}
private MessageToSend getMessageToSend(Long serverId, String searchInput, String language) throws IOException {
String languageKey = language != null ? language :
configService.getStringValueOrConfigDefault(WikipediaFeatureConfig.WIKIPEDIA_LANGUAGE_KEY_SYSTEM_CONFIG_KEY, serverId);
WikipediaArticleSummary definition = wikipediaService.getSummary(searchInput, languageKey);
WikipediaArticleSummaryModel model = WikipediaArticleSummaryModel
.builder()
.summary(definition.getSummary())
.fullURL(definition.getFullURL())
.title(definition.getTitle())
.build();
return templateService.renderEmbedTemplate(WIKIPEDIA_ARTICLE_SUMMARY_RESPONSE_MODEL_TEMPLATE_KEY, model, serverId);
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Parameter searchQueryParameter = Parameter
.builder()
.name(SEARCH_QUERY_PARAMETER)
.type(String.class)
.remainder(true)
.templated(true)
.build();
parameters.add(searchQueryParameter);
Parameter languageParameter = Parameter
.builder()
.name(LANGUAGE_PARAMETER)
.type(String.class)
.slashCommandOnly(true)
.optional(true)
.templated(true)
.build();
parameters.add(languageParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
List<String> aliases = Arrays.asList("wiki");
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(WebServicesSlashCommandNames.WIKIPEDIA)
.groupName("article")
.commandName("summary")
.build();
return CommandConfiguration.builder()
.name(WIKIPEDIA_ARTICLE_SUMMARY_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true)
.aliases(aliases)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return WebserviceFeatureDefinition.WIKIPEDIA;
}
}

View File

@@ -0,0 +1,64 @@
package dev.sheldan.abstracto.webservices.wikipedia.service;
import com.google.gson.Gson;
import dev.sheldan.abstracto.webservices.wikipedia.exception.NoWikipediaArticleFoundException;
import dev.sheldan.abstracto.webservices.wikipedia.exception.WikipediaRequestException;
import dev.sheldan.abstracto.webservices.wikipedia.model.WikipediaArticleSummary;
import dev.sheldan.abstracto.webservices.wikipedia.model.api.WikipediaResponse;
import dev.sheldan.abstracto.webservices.wikipedia.model.api.WikipediaResponsePage;
import lombok.extern.slf4j.Slf4j;
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
@Slf4j
public class WikipediaServiceBean implements WikipediaService {
@Autowired
private OkHttpClient okHttpClient;
@Value("${abstracto.feature.webservices.wikipedia.summaryURL}")
private String articleSummaryUrl;
@Autowired
private Gson gson;
@Override
public WikipediaArticleSummary getSummary(String query, String language) throws IOException {
String formattedUrl = articleSummaryUrl.replace("{1}", language).replace("{2}", query);
Request request = new Request.Builder()
.url(formattedUrl)
.get()
.build();
Response response = okHttpClient.newCall(request).execute();
if(!response.isSuccessful()) {
if(log.isDebugEnabled()) {
log.error("Failed to retrieve wikipedia summary. Response had code {} with body {}.",
response.code(), response.body());
}
throw new WikipediaRequestException(response.code());
}
WikipediaResponse wikipediaResponse = gson.fromJson(response.body().string(), WikipediaResponse.class);
if(wikipediaResponse.getQuery() == null
|| wikipediaResponse.getQuery().getPages() == null
|| (wikipediaResponse.getQuery().getPages().stream().anyMatch(wikipediaResponsePageModel -> wikipediaResponsePageModel.getPageId().equals(-1L))
&& wikipediaResponse.getQuery().getPages().size() == 1)
) {
throw new NoWikipediaArticleFoundException();
} else {
WikipediaResponsePage page = wikipediaResponse.getQuery().getPages().get(0);
return WikipediaArticleSummary
.builder()
.title(page.getTitle())
.summary(page.getExtract())
.fullURL(page.getFullUrl())
.build();
}
}
}

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,26 @@
<?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="wikipediaFeature" value="(SELECT id FROM feature WHERE key = 'wikipedia')"/>
<property name="dictionaryFeature" value="(SELECT id FROM feature WHERE key = 'dictionary')"/>
<changeSet author="Sheldan" id="wikiArticleSummaryDictionary-commands">
<insert tableName="command">
<column name="name" value="wikipediaArticleSummary"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${wikipediaFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="dictionaryDefinition"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${dictionaryFeature}"/>
</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,17 @@
<?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="wikipedia_feature-insertion">
<insert tableName="feature">
<column name="key" value="wikipedia"/>
</insert>
<insert tableName="feature">
<column name="key" value="dictionary"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -9,4 +9,5 @@
<include file="1.2.5-webservices/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.7/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.22/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.20/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -27,4 +27,17 @@ abstracto.featureFlags.openWeatherMap.featureName=openWeatherMap
abstracto.featureFlags.openWeatherMap.enabled=false
abstracto.systemConfigs.openWeatherMapLanguageKey.name=openWeatherMapLanguageKey
abstracto.systemConfigs.openWeatherMapLanguageKey.stringValue=en
abstracto.systemConfigs.openWeatherMapLanguageKey.stringValue=en
abstracto.featureFlags.wikipedia.featureName=wikipedia
abstracto.featureFlags.wikipedia.enabled=false
abstracto.feature.webservices.wikipedia.summaryURL=https://{1}.wikipedia.org/w/api.php?action=query&format=json&prop=pageprops%7Cextracts%7Cinfo&list=&meta=&inprop=url&redirects=1&formatversion=2&ppprop=disambiguation&exintro=1&explaintext=1&titles={2}
abstracto.systemConfigs.wikipediaLanguageKey.name=wikipediaLanguageKey
abstracto.systemConfigs.wikipediaLanguageKey.stringValue=en
abstracto.featureFlags.dictionary.featureName=dictionary
abstracto.featureFlags.dictionary.enabled=false
abstracto.feature.webservices.dictionaryapi.definitionURL=https://api.dictionaryapi.dev/api/v2/entries/en/{1}

View File

@@ -4,4 +4,6 @@ public class WebServicesSlashCommandNames {
public static final String YOUTUBE = "youtube";
public static final String URBAN = "urban";
public static final String WEATHER = "weather";
public static final String WIKIPEDIA = "wikipedia";
public static final String DICTIONARY = "dictionary";
}

View File

@@ -8,7 +8,9 @@ public enum WebserviceFeatureDefinition implements FeatureDefinition {
YOUTUBE("youtube"),
URBAN_DICTIONARY("urban"),
THREAD_READER("threadReader"),
OPEN_WEATHER_MAP("openWeatherMap");
OPEN_WEATHER_MAP("openWeatherMap"),
WIKIPEDIA("wikipedia"),
DICTIONARY("dictionary");
private String key;

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.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 DictionaryApiFeatureConfig implements FeatureConfig {
@Override
public FeatureDefinition getFeature() {
return WebserviceFeatureDefinition.DICTIONARY;
}
}

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class DictionaryApiRequestException extends AbstractoRunTimeException implements Templatable {
public DictionaryApiRequestException(Integer responseCode) {
super(String.format("Request failure towards dictionary api %s.", responseCode));
}
@Override
public String getTemplateName() {
return "dictionary_api_request_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class NoDictionaryApiDefinitionFoundException extends AbstractoRunTimeException implements Templatable {
public NoDictionaryApiDefinitionFoundException() {
super("No dictionary api definition found.");
}
@Override
public String getTemplateName() {
return "no_dictionary_api_definition_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,22 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.api.DictionaryApiWordDefinition;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Builder
@Setter
public class WordDefinition {
private String definition;
private String example;
public static WordDefinition fromResponseDefinition(DictionaryApiWordDefinition responseItem) {
return WordDefinition
.builder()
.example(responseItem.getExample())
.definition(responseItem.getDefinition())
.build();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Builder
@Setter
public class WordMeaning {
private String word;
private List<WordDefinition> definitions;
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model.api;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Builder
@Setter
public class DictionaryApiResponseItem {
private String word;
private String origin;
private List<DictionaryApiWordMeaning> meanings;
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model.api;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class DictionaryApiWordDefinition {
private String definition;
private String example;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model.api;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@Builder
public class DictionaryApiWordMeaning {
private String partOfSpeech;
private List<DictionaryApiWordDefinition> definitions;
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model.template;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.WordDefinition;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class DictionaryDefinition {
private String definition;
private String example;
public static DictionaryDefinition fromWordDefinition(WordDefinition definition) {
return DictionaryDefinition
.builder()
.example(definition.getExample())
.definition(definition.getDefinition())
.build();
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.model.template;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Getter
@Builder
public class DictionaryMeaning {
private String word;
private List<DictionaryDefinition> definitions;
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.webservices.dictionaryapi.service;
import dev.sheldan.abstracto.webservices.dictionaryapi.model.WordMeaning;
import java.io.IOException;
public interface DictionaryApiService {
WordMeaning getDefinitions(String query) throws IOException;
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.webservices.wikipedia.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;
import java.util.Arrays;
import java.util.List;
@Component
public class WikipediaFeatureConfig implements FeatureConfig {
public static final String WIKIPEDIA_LANGUAGE_KEY_SYSTEM_CONFIG_KEY = "wikipediaLanguageKey";
@Override
public FeatureDefinition getFeature() {
return WebserviceFeatureDefinition.WIKIPEDIA;
}
@Override
public List<String> getRequiredSystemConfigKeys() {
return Arrays.asList(WIKIPEDIA_LANGUAGE_KEY_SYSTEM_CONFIG_KEY);
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.webservices.wikipedia.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class NoWikipediaArticleFoundException extends AbstractoRunTimeException implements Templatable {
public NoWikipediaArticleFoundException() {
super("No wikipedia article found.");
}
@Override
public String getTemplateName() {
return "no_wikipedia_article_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.webservices.wikipedia.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class WikipediaRequestException extends AbstractoRunTimeException implements Templatable {
public WikipediaRequestException(Integer responseCode) {
super(String.format("Request failure towards wikipedia %s.", responseCode));
}
@Override
public String getTemplateName() {
return "wikipedia_request_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.webservices.wikipedia.model;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class WikipediaArticleSummary {
private String title;
private String summary;
private String fullURL;
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.webservices.wikipedia.model.api;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class WikipediaResponse {
private WikipediaResponseQuery query;
}

View File

@@ -0,0 +1,25 @@
package dev.sheldan.abstracto.webservices.wikipedia.model.api;
import com.google.gson.annotations.SerializedName;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Getter
@Setter
@Builder
public class WikipediaResponsePage {
@SerializedName("pageid")
private Long pageId;
private String title;
private String extract;
@SerializedName("fullurl")
private String fullUrl;
private Map<String, String> pageprops;
public boolean isDisambiguation() {
return pageprops != null && pageprops.containsKey("disambiguation");
}
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.webservices.wikipedia.model.api;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@Builder
public class WikipediaResponseQuery {
private List<WikipediaResponsePage> pages;
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.webservices.wikipedia.model.template;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class WikipediaArticleSummaryModel {
private String summary;
private String title;
private String fullURL;
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.webservices.wikipedia.service;
import dev.sheldan.abstracto.webservices.wikipedia.model.WikipediaArticleSummary;
import java.io.IOException;
public interface WikipediaService {
WikipediaArticleSummary getSummary(String query, String language) throws IOException;
}