diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml index 56169d9ac..ebf5e144c 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml @@ -48,6 +48,16 @@ com.google.apis google-api-services-youtube + + + org.ehcache + ehcache + jakarta + + + org.springframework + spring-context-support + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/command/ConvertCurrency.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/command/ConvertCurrency.java new file mode 100644 index 000000000..791d78ffa --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/command/ConvertCurrency.java @@ -0,0 +1,150 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.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.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.interaction.InteractionService; +import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig; +import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandAutoCompleteService; +import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService; +import dev.sheldan.abstracto.webservices.config.WebServicesSlashCommandNames; +import dev.sheldan.abstracto.webservices.config.WebserviceFeatureDefinition; +import dev.sheldan.abstracto.webservices.currencyconversion.model.ConvertCurrencyResponseModel; +import dev.sheldan.abstracto.webservices.currencyconversion.model.Currency; +import dev.sheldan.abstracto.webservices.currencyconversion.service.CurrencyConversionApiService; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ConvertCurrency extends AbstractConditionableCommand { + + private static final String SOURCE_CURRENCY_PARAMETER = "sourceCurrency"; + private static final String TARGET_CURRENCY_PARAMETER = "targetCurrency"; + private static final String VALUE_PARAMETER = "value"; + private static final String CONVERT_CURRENCY_RESPONSE_TEMPLATE = "convertCurrency_response"; + + @Autowired + private InteractionService interactionService; + + @Autowired + private SlashCommandParameterService slashCommandParameterService; + + @Autowired + private CurrencyConversionApiService currencyConversionApiService; + + @Autowired + private SlashCommandAutoCompleteService slashCommandAutoCompleteService; + + @Override + public CompletableFuture executeSlash(SlashCommandInteractionEvent event) { + String sourceCurrencyText = slashCommandParameterService.getCommandOption(SOURCE_CURRENCY_PARAMETER, event, String.class); + String targetCurrencyText = slashCommandParameterService.getCommandOption(TARGET_CURRENCY_PARAMETER, event, String.class); + Double value = slashCommandParameterService.getCommandOption(VALUE_PARAMETER, event, Double.class); + Currency sourceCurrency = currencyConversionApiService.getCurrencyForString(sourceCurrencyText); + Currency targetCurrency = currencyConversionApiService.getCurrencyForString(targetCurrencyText); + Double convertedValue = currencyConversionApiService.convertCurrency(sourceCurrency, targetCurrency, value); + ConvertCurrencyResponseModel responseModel = ConvertCurrencyResponseModel + .builder() + .sourceCurrency(sourceCurrency) + .targetCurrency(targetCurrency) + .sourceValue(value) + .targetValue(convertedValue) + .build(); + return interactionService.replyEmbed(CONVERT_CURRENCY_RESPONSE_TEMPLATE, responseModel, event) + .thenApply(interactionHook -> CommandResult.fromSuccess()); + } + + @Override + public List performAutoComplete(CommandAutoCompleteInteractionEvent event) { + if(slashCommandAutoCompleteService.matchesParameter(event.getFocusedOption(), SOURCE_CURRENCY_PARAMETER) + || slashCommandAutoCompleteService.matchesParameter(event.getFocusedOption(), TARGET_CURRENCY_PARAMETER)) { + String input = event.getFocusedOption().getValue().toLowerCase(); + List supportedCurrencies = currencyConversionApiService.getSupportedCurrencies(); + Set currencies = new HashSet<>(); + supportedCurrencies.forEach(currency -> { + currencies.add(currency.getCode().toLowerCase()); + currencies.add(currency.getName().toLowerCase()); + currencies.add(currency.getSymbol().toLowerCase()); + if(currency.getSymbolNative() != null) { + currencies.add(currency.getSymbolNative().toLowerCase()); + } + }); + if(!input.isEmpty()) { + return currencies.stream().filter(s -> s.contains(input)).toList(); + } else { + return currencies.stream().toList(); + } + } else { + return new ArrayList<>(); + } + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + Parameter sourceCurrencyParameter = Parameter + .builder() + .name(SOURCE_CURRENCY_PARAMETER) + .type(String.class) + .supportsAutoComplete(true) + .templated(true) + .build(); + parameters.add(sourceCurrencyParameter); + Parameter targetCurrencyParameter = Parameter + .builder() + .name(TARGET_CURRENCY_PARAMETER) + .type(String.class) + .supportsAutoComplete(true) + .templated(true) + .build(); + parameters.add(targetCurrencyParameter); + Parameter valueParameter = Parameter + .builder() + .name(VALUE_PARAMETER) + .type(Double.class) + .templated(true) + .build(); + parameters.add(valueParameter); + HelpInfo helpInfo = HelpInfo + .builder() + .templated(true) + .build(); + + + SlashCommandConfig slashCommandConfig = SlashCommandConfig + .builder() + .enabled(true) + .rootCommandName(WebServicesSlashCommandNames.CONVERSION) + .commandName("currency") + .build(); + + return CommandConfiguration.builder() + .name("convertCurrency") + .module(UtilityModuleDefinition.UTILITY) + .templated(true) + .slashCommandConfig(slashCommandConfig) + .async(true) + .supportsEmbedException(true) + .slashCommandOnly(true) + .causesReaction(false) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureDefinition getFeature() { + return WebserviceFeatureDefinition.CURRENCY_CONVERSION; + } +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/config/CurrencyCacheConfig.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/config/CurrencyCacheConfig.java new file mode 100644 index 000000000..ae0b944cf --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/config/CurrencyCacheConfig.java @@ -0,0 +1,28 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.config; + +import java.net.URL; +import lombok.extern.slf4j.Slf4j; +import org.ehcache.config.builders.CacheManagerBuilder; +import org.ehcache.jsr107.Eh107Configuration; +import org.ehcache.xml.XmlConfiguration; +import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Slf4j +public class CurrencyCacheConfig { + @Bean + public JCacheManagerCustomizer currencyCacheManagerCustomizer() { + URL myUrl = getClass().getResource("/currency-cache-config.xml"); + XmlConfiguration xmlConfig = new XmlConfiguration(myUrl); + org.ehcache.CacheManager myCacheManager = CacheManagerBuilder.newCacheManager(xmlConfig); + return cm -> { + myCacheManager.getRuntimeConfiguration().getCacheConfigurations().entrySet().forEach(cacheConfiguration -> { + javax.cache.configuration.Configuration jConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration.getValue()); + log.info("Creating custom cache: " + cacheConfiguration.getKey()); + cm.createCache(cacheConfiguration.getKey(), jConfiguration); + }); + }; + } +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyLatestExchangeResponse.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyLatestExchangeResponse.java new file mode 100644 index 000000000..52cd0723e --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyLatestExchangeResponse.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.model.api; + +import java.util.Map; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CurrencyLatestExchangeResponse { + private Map data; +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyListCurrency.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyListCurrency.java new file mode 100644 index 000000000..5f6defd19 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyListCurrency.java @@ -0,0 +1,20 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.model.api; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CurrencyListCurrency { + private String symbol; + private String name; + @SerializedName("symbol_native") + private String symbolNative; + @SerializedName("decimal_digits") + private String decimalDigits; + private String rounding; + private String code; + @SerializedName("name_plural") + private String namePlural; +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyListResponse.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyListResponse.java new file mode 100644 index 000000000..5a2f910cd --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/api/CurrencyListResponse.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.model.api; + +import java.util.Map; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CurrencyListResponse { + private Map data; +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConversionApiServiceBean.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConversionApiServiceBean.java new file mode 100644 index 000000000..b8f7a3f14 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConversionApiServiceBean.java @@ -0,0 +1,120 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.service; + +import com.google.gson.Gson; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.webservices.currencyconversion.exception.CurrencyNotFoundException; +import dev.sheldan.abstracto.webservices.currencyconversion.model.Currency; +import dev.sheldan.abstracto.webservices.currencyconversion.model.api.CurrencyLatestExchangeResponse; +import dev.sheldan.abstracto.webservices.currencyconversion.model.api.CurrencyListResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +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.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class CurrencyConversionApiServiceBean implements CurrencyConversionApiService { + + @Autowired + private OkHttpClient okHttpClient; + + @Value("${abstracto.feature.webservices.currencyConversion.currencyURL}") + private String currencyUrl; + + @Value("${abstracto.feature.webservices.currencyConversion.conversionURL}") + private String conversionUrl; + + @Value("${abstracto.feature.webservices.currencyConversion.apiKey}") + private String apiKey; + + @Autowired + private Gson gson; + + @Autowired + private CurrencyConversionApiService self; + + @Autowired + private CurrencyConverter currencyConverter; + + @Override + @Cacheable(value = "currency-cache") + public List getSupportedCurrencies() { + String formattedUrl = currencyUrl; + Request request = new Request.Builder() + .url(formattedUrl) + .header("apikey", apiKey) + .get() + .build(); + Response response = null; + log.info("Loading available currencies."); + try { + response = okHttpClient.newCall(request).execute(); + CurrencyListResponse currencyListResponse = gson.fromJson(response.body().string(), CurrencyListResponse.class); + List currencies = new ArrayList<>(); + currencyListResponse.getData().forEach((s, currencyListCurrency) -> currencies.add(currencyConverter.fromResponseObject(currencyListCurrency))); + return currencies; + } catch (IOException e) { + log.error("Failed to load currencies.", e); + throw new AbstractoRunTimeException(e); + } + } + + @Override + public Currency getCurrencyForString(String input) { + List supportedCurrencies = self.getSupportedCurrencies(); + String lowerInput = input.toLowerCase(); + return supportedCurrencies + .stream() + .filter(currency -> currency.getCode().toLowerCase().equals(lowerInput) + || currency.getName().toLowerCase().equals(lowerInput) + || currency.getSymbol().toLowerCase().equals(lowerInput) + || currency.getSymbolNative().toLowerCase().equals(lowerInput)) + .findFirst() + .orElseThrow(CurrencyNotFoundException::new); + } + + @Override + public Double convertCurrency(String sourceCurrencyString, String targetCurrencyString, Double amount) { + Currency sourceCurrency = getCurrencyForString(sourceCurrencyString); + Currency targetCurrency = getCurrencyForString(targetCurrencyString); + return convertCurrency(sourceCurrency, targetCurrency, amount); + } + + @Override + @Cacheable(value = "currency-conversion-cache") + public Map getExchangeRates(Currency sourceCurrency) { + String formattedUrl = String.format(conversionUrl, sourceCurrency.getCode()); + Request request = new Request.Builder() + .url(formattedUrl) + .header("apikey", apiKey) + .get() + .build(); + log.info("Loading exchange rate for {}.", sourceCurrency); + try { + Response response = okHttpClient.newCall(request).execute(); + CurrencyLatestExchangeResponse currencyLatestExchangeResponse = gson.fromJson(response.body().string(), CurrencyLatestExchangeResponse.class); + return currencyLatestExchangeResponse.getData(); + } catch (IOException e) { + log.error("Failed to load currency exchange rate for {}.", sourceCurrency, e); + throw new AbstractoRunTimeException(e); + } + } + + @Override + public Double convertCurrency(Currency sourceCurrency, Currency targetCurrency, Double amount) { + Map receivedCurrencies = self.getExchangeRates(sourceCurrency); + if(!receivedCurrencies.containsKey(targetCurrency.getCode())) { + throw new CurrencyNotFoundException(); + } + Double targetCurrencyValue = receivedCurrencies.get(targetCurrency.getCode()); + return amount * targetCurrencyValue; + } +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConverter.java b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConverter.java new file mode 100644 index 000000000..98f7acdf6 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConverter.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.service; + +import dev.sheldan.abstracto.webservices.currencyconversion.model.Currency; +import dev.sheldan.abstracto.webservices.currencyconversion.model.api.CurrencyListCurrency; +import org.springframework.stereotype.Component; + +@Component +public class CurrencyConverter { + public Currency fromResponseObject(CurrencyListCurrency currencyListCurrency) { + return Currency + .builder() + .code(currencyListCurrency.getCode()) + .name(currencyListCurrency.getName()) + .symbol(currencyListCurrency.getSymbol()) + .symbolNative(currencyListCurrency.getSymbolNative()) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/currency-cache-config.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/currency-cache-config.xml new file mode 100644 index 000000000..6b0f25c8c --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/currency-cache-config.xml @@ -0,0 +1,33 @@ + + + + 43200 + + + + 5 + + + + + 43200 + + + + 5 + + + + + 43200 + + + 50 + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/collection.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/collection.xml new file mode 100644 index 000000000..b14512a81 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/collection.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/command.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/command.xml new file mode 100644 index 000000000..8f2b02995 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/command.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/data.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/data.xml new file mode 100644 index 000000000..b7dcd429c --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/data.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/feature.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/feature.xml new file mode 100644 index 000000000..da2de52ac --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/1.5.57/seedData/feature.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/webservices-changeLog.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/webservices-changeLog.xml index cb5ef07bf..bf358a4b9 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/webservices-changeLog.xml +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/migrations/webservices-changeLog.xml @@ -6,4 +6,5 @@ + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/webservices-config.properties b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/webservices-config.properties index 0299ed368..85704d2dc 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/webservices-config.properties +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/src/main/resources/webservices-config.properties @@ -40,4 +40,10 @@ 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} \ No newline at end of file +abstracto.featureFlags.currencyConversion.featureName=currencyConversion +abstracto.featureFlags.currencyConversion.enabled=false + +abstracto.feature.webservices.dictionaryapi.definitionURL=https://api.dictionaryapi.dev/api/v2/entries/en/{1} +abstracto.feature.webservices.currencyConversion.currencyURL=https://api.freecurrencyapi.com/v1/currencies +abstracto.feature.webservices.currencyConversion.conversionURL=https://api.freecurrencyapi.com/v1/latest?base_currency=%s +abstracto.feature.webservices.currencyConversion.apiKey=${FREE_CURRENCY_API_API_KEY} \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebServicesSlashCommandNames.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebServicesSlashCommandNames.java index 9f5195e71..3f7502c86 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebServicesSlashCommandNames.java +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebServicesSlashCommandNames.java @@ -5,5 +5,6 @@ public class WebServicesSlashCommandNames { public static final String URBAN = "urban"; public static final String WEATHER = "weather"; public static final String WIKIPEDIA = "wikipedia"; + public static final String CONVERSION = "conversion"; public static final String DICTIONARY = "dictionary"; } diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebserviceFeatureDefinition.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebserviceFeatureDefinition.java index fa9edb685..e284a95a0 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebserviceFeatureDefinition.java +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/config/WebserviceFeatureDefinition.java @@ -10,7 +10,8 @@ public enum WebserviceFeatureDefinition implements FeatureDefinition { THREAD_READER("threadReader"), OPEN_WEATHER_MAP("openWeatherMap"), WIKIPEDIA("wikipedia"), - DICTIONARY("dictionary"); + DICTIONARY("dictionary"), + CURRENCY_CONVERSION("currencyConversion"); private String key; diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/config/CurrencyConversionApiFeatureConfig.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/config/CurrencyConversionApiFeatureConfig.java new file mode 100644 index 000000000..e4619f266 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/config/CurrencyConversionApiFeatureConfig.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.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 CurrencyConversionApiFeatureConfig implements FeatureConfig { + + @Override + public FeatureDefinition getFeature() { + return WebserviceFeatureDefinition.CURRENCY_CONVERSION; + } + +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/exception/CurrencyNotFoundException.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/exception/CurrencyNotFoundException.java new file mode 100644 index 000000000..148851a60 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/exception/CurrencyNotFoundException.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.exception; + +import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; + +public class CurrencyNotFoundException extends AbstractoTemplatedException { + public CurrencyNotFoundException() { + super("Currency not found", "currency_conversion_currency_not_found_exception"); + } +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/ConvertCurrencyResponseModel.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/ConvertCurrencyResponseModel.java new file mode 100644 index 000000000..a01672487 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/ConvertCurrencyResponseModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.model; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class ConvertCurrencyResponseModel { + private Currency sourceCurrency; + private Currency targetCurrency; + private Double sourceValue; + private Double targetValue; +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/Currency.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/Currency.java new file mode 100644 index 000000000..ed7ffba5b --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/model/Currency.java @@ -0,0 +1,19 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.model; + +import java.util.Map; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Builder +@Getter +@EqualsAndHashCode +@ToString +public class Currency { + private String symbol; + private String symbolNative; + private String name; + private String code; + private Map exchangeRates; +} diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConversionApiService.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConversionApiService.java new file mode 100644 index 000000000..1f55990e1 --- /dev/null +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/currencyconversion/service/CurrencyConversionApiService.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.webservices.currencyconversion.service; + +import dev.sheldan.abstracto.webservices.currencyconversion.model.Currency; +import java.util.List; +import java.util.Map; + +public interface CurrencyConversionApiService { + List getSupportedCurrencies(); + Currency getCurrencyForString(String input); + Double convertCurrency(String sourceCurrency, String targetCurrency, Double amount); + Map getExchangeRates(Currency sourceCurrency); + Double convertCurrency(Currency sourceCurrency, Currency targetCurrency, Double amount); +}