From dd9694890ae25d55e96140fe103214c91d93a7a4 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 25 Mar 2018 09:00:45 +0200 Subject: [PATCH] Code for #1291 --- .env.docker | 4 +- .env.example | 4 +- .env.heroku | 4 +- .env.sandstorm | 4 +- .env.testing | 2 +- .../Controllers/Json/ExchangeController.php | 20 +++- app/Providers/FireflyServiceProvider.php | 3 + app/Services/Currency/FixerIOv2.php | 113 ++++++++++++++++++ 8 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 app/Services/Currency/FixerIOv2.php diff --git a/.env.docker b/.env.docker index c176b40fce..8b96edf6f8 100644 --- a/.env.docker +++ b/.env.docker @@ -65,6 +65,9 @@ SEND_ERROR_MESSAGE=false # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY=${MAPBOX_API_KEY} +# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates. +FIXER_API_KEY=${FIXER_API_KEY} + # If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here. ANALYTICS_ID=${ANALYTICS_ID} @@ -82,7 +85,6 @@ REDIS_PASSWORD=null REDIS_PORT=6379 CACHE_PREFIX=firefly SEARCH_RESULT_LIMIT=50 -EXCHANGE_RATE_SERVICE=fixerio PUSHER_KEY= PUSHER_SECRET= PUSHER_ID= diff --git a/.env.example b/.env.example index f90ed5b26d..5e0f5d98a2 100644 --- a/.env.example +++ b/.env.example @@ -69,6 +69,9 @@ SEND_ERROR_MESSAGE=true # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= +# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates. +FIXER_API_KEY= + # If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here. ANALYTICS_ID= @@ -86,7 +89,6 @@ REDIS_PASSWORD=null REDIS_PORT=6379 CACHE_PREFIX=firefly SEARCH_RESULT_LIMIT=50 -EXCHANGE_RATE_SERVICE=fixerio PUSHER_KEY= PUSHER_SECRET= PUSHER_ID= diff --git a/.env.heroku b/.env.heroku index b1d6a763f5..cf2f0b623c 100644 --- a/.env.heroku +++ b/.env.heroku @@ -69,6 +69,9 @@ SEND_ERROR_MESSAGE=true # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= +# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates. +FIXER_API_KEY= + # If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here. ANALYTICS_ID= @@ -86,7 +89,6 @@ REDIS_PASSWORD=null REDIS_PORT=6379 CACHE_PREFIX=firefly SEARCH_RESULT_LIMIT=50 -EXCHANGE_RATE_SERVICE=fixerio PUSHER_KEY= PUSHER_SECRET= PUSHER_ID= diff --git a/.env.sandstorm b/.env.sandstorm index 811c71e343..8b6262c761 100755 --- a/.env.sandstorm +++ b/.env.sandstorm @@ -69,6 +69,9 @@ SEND_ERROR_MESSAGE=true # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= +# Set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates. +FIXER_API_KEY= + # If you wish to track your own behavior over Firefly III, set a valid analytics tracker ID here. ANALYTICS_ID= @@ -86,7 +89,6 @@ REDIS_PASSWORD=null REDIS_PORT=6379 CACHE_PREFIX=firefly SEARCH_RESULT_LIMIT=50 -EXCHANGE_RATE_SERVICE=fixerio PUSHER_KEY= PUSHER_SECRET= PUSHER_ID= diff --git a/.env.testing b/.env.testing index 2e91b05f20..b83b5c5d0a 100644 --- a/.env.testing +++ b/.env.testing @@ -45,9 +45,9 @@ SEND_ERROR_MESSAGE=false CACHE_PREFIX=firefly SEARCH_RESULT_LIMIT=50 -EXCHANGE_RATE_SERVICE=fixerio MAPBOX_API_KEY= +FIXER_API_KEY= ANALYTICS_ID= SITE_OWNER=mail@example.com USE_ENCRYPTION=true diff --git a/app/Http/Controllers/Json/ExchangeController.php b/app/Http/Controllers/Json/ExchangeController.php index 06fbb4ac9e..7752fec71e 100644 --- a/app/Http/Controllers/Json/ExchangeController.php +++ b/app/Http/Controllers/Json/ExchangeController.php @@ -48,15 +48,23 @@ class ExchangeController extends Controller /** @var CurrencyRepositoryInterface $repository */ $repository = app(CurrencyRepositoryInterface::class); $rate = $repository->getExchangeRate($fromCurrency, $toCurrency, $date); + + + + + if (null === $rate->id) { Log::debug(sprintf('No cached exchange rate in database for %s to %s on %s', $fromCurrency->code, $toCurrency->code, $date->format('Y-m-d'))); - $preferred = env('EXCHANGE_RATE_SERVICE', config('firefly.preferred_exchange_service')); - $class = config('firefly.currency_exchange_services.' . $preferred); - /** @var ExchangeRateInterface $object */ - $object = app($class); - $object->setUser(auth()->user()); - $rate = $object->getRate($fromCurrency, $toCurrency, $date); + + // create service: + /** @var ExchangeRateInterface $service */ + $service = app(ExchangeRateInterface::class); + $service->setUser(auth()->user()); + + // get rate: + $rate = $service->getRate($fromCurrency, $toCurrency, $date); } + $return = $rate->toArray(); $return['amount'] = null; if (null !== $request->get('amount')) { diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index a058b10eb9..5a9c83b109 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -46,6 +46,8 @@ use FireflyIII\Repositories\TransactionType\TransactionTypeRepository; use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface; use FireflyIII\Repositories\User\UserRepository; use FireflyIII\Repositories\User\UserRepositoryInterface; +use FireflyIII\Services\Currency\ExchangeRateInterface; +use FireflyIII\Services\Currency\FixerIOv2; use FireflyIII\Services\Password\PwndVerifierV2; use FireflyIII\Services\Password\Verifier; use FireflyIII\Support\Amount; @@ -174,6 +176,7 @@ class FireflyServiceProvider extends ServiceProvider $this->app->bind(FiscalHelperInterface::class, FiscalHelper::class); $this->app->bind(BalanceReportHelperInterface::class, BalanceReportHelper::class); $this->app->bind(BudgetReportHelperInterface::class, BudgetReportHelper::class); + $this->app->bind(ExchangeRateInterface::class, FixerIOv2::class); // password verifier thing $this->app->bind(Verifier::class, PwndVerifierV2::class); diff --git a/app/Services/Currency/FixerIOv2.php b/app/Services/Currency/FixerIOv2.php new file mode 100644 index 0000000000..eb43ba6cf9 --- /dev/null +++ b/app/Services/Currency/FixerIOv2.php @@ -0,0 +1,113 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Services\Currency; + +use Carbon\Carbon; +use FireflyIII\Models\CurrencyExchangeRate; +use FireflyIII\Models\TransactionCurrency; +use FireflyIII\User; +use Log; +use Requests; +use Requests_Exception; + +/** + * Class FixerIOv2. + */ +class FixerIOv2 implements ExchangeRateInterface +{ + /** @var User */ + protected $user; + + /** + * @param TransactionCurrency $fromCurrency + * @param TransactionCurrency $toCurrency + * @param Carbon $date + * + * @return CurrencyExchangeRate + */ + public function getRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date): CurrencyExchangeRate + { + // create new exchange rate with default values. + // create new currency exchange rate object: + $exchangeRate = new CurrencyExchangeRate; + $exchangeRate->user()->associate($this->user); + $exchangeRate->fromCurrency()->associate($fromCurrency); + $exchangeRate->toCurrency()->associate($toCurrency); + $exchangeRate->date = $date; + $exchangeRate->rate = 0; + + // get API key + $apiKey = env('FIXER_API_KEY', ''); + + // if no API key, return unsaved exchange rate. + if (strlen($apiKey) === 0) { + return $exchangeRate; + } + + // build URI + $uri = sprintf( + 'http://data.fixer.io/api/%s?access_key=%s&base=%s&symbols=%s', + $date->format('Y-m-d'), $apiKey, $fromCurrency->code, $toCurrency->code + ); + $statusCode = -1; + Log::debug(sprintf('Going to request exchange rate using URI %s', str_replace($apiKey, 'xxxx', $uri))); + try { + $result = Requests::get($uri); + $statusCode = $result->status_code; + $body = $result->body; + Log::debug(sprintf('Result status code is %d', $statusCode)); + } catch (Requests_Exception $e) { + // don't care about error + $body = sprintf('Requests_Exception: %s', $e->getMessage()); + } + + // Requests_Exception + $content = null; + if (200 !== $statusCode) { + Log::error(sprintf('Something went wrong. Received error code %d and body "%s" from FixerIO.', $statusCode, $body)); + } + // get rate from body: + if (200 === $statusCode) { + $content = json_decode($body, true); + } + if (null !== $content) { + $code = $toCurrency->code; + $rate = isset($content['rates'][$code]) ? $content['rates'][$code] : '0'; + } + Log::debug('Got the following rates from Fixer: ', $content['rates'] ?? []); + $exchangeRate->rate = $rate; + $exchangeRate->save(); + + return $exchangeRate; + } + + /** + * @param User $user + * + * @return mixed|void + */ + public function setUser(User $user) + { + $this->user = $user; + } +}