You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

159 lines
5.1 KiB

<?php
/*
* SimpleFINRequest.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of the Firefly III Data Importer
* (https://github.com/firefly-iii/data-importer).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\SimpleFIN\Request;
use App\Exceptions\ImporterErrorException;
use App\Exceptions\ImporterHttpException;
use App\Services\Session\Constants;
use App\Services\Shared\Response\ResponseInterface as SharedResponseInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\ServerException;
use Psr\Http\Message\ResponseInterface;
/**
* Class SimpleFINRequest
*/
abstract class SimpleFINRequest
{
private string $apiUrl;
private string $token;
private array $parameters = [];
private float $timeOut;
/**
* @throws ImporterHttpException
*/
abstract public function get(): SharedResponseInterface;
public function setApiUrl(string $apiUrl): void
{
$this->apiUrl = rtrim($apiUrl, '/');
}
public function setToken(string $token): void
{
$this->token = $token;
}
public function setParameters(array $parameters): void
{
app('log')->debug('SimpleFIN request parameters set to: ', $parameters);
$this->parameters = $parameters;
}
public function setTimeOut(float $timeOut): void
{
$this->timeOut = $timeOut;
}
protected function authenticatedGet(string $endpoint): ResponseInterface
{
app('log')->debug(sprintf('SimpleFIN authenticated GET to %s%s', $this->apiUrl, $endpoint));
$client = new Client();
$fullUrl = sprintf('%s%s', $this->apiUrl, $endpoint);
$origin = session()->get(Constants::SIMPLEFIN_BRIDGE_URL);
$options = [
'timeout' => $this->timeOut,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Origin' => $origin,
],
];
// Only add basic auth if userinfo is not already in the apiUrl
// and a token is provided. SimpleFIN typically uses userinfo in the Access URL.
if (strpos($this->apiUrl, '@') === false && !empty($this->token)) {
$options['auth'] = [$this->token, ''];
}
if (!empty($this->parameters)) {
$options['query'] = $this->parameters;
}
try {
$response = $client->get($fullUrl, $options);
} catch (ClientException $e) {
app('log')->error(sprintf('SimpleFIN ClientException: %s', $e->getMessage()));
$this->handleClientException($e);
throw new ImporterHttpException($e->getMessage(), $e->getCode(), $e);
} catch (ServerException $e) {
app('log')->error(sprintf('SimpleFIN ServerException: %s', $e->getMessage()));
throw new ImporterHttpException($e->getMessage(), $e->getCode(), $e);
} catch (GuzzleException $e) {
app('log')->error(sprintf('SimpleFIN GuzzleException: %s', $e->getMessage()));
throw new ImporterHttpException($e->getMessage(), $e->getCode(), $e);
}
return $response;
}
private function handleClientException(ClientException $e): void
{
$statusCode = $e->getResponse()->getStatusCode();
$body = (string) $e->getResponse()->getBody();
app('log')->error(sprintf('SimpleFIN HTTP %d error: %s', $statusCode, $body));
switch ($statusCode) {
case 401:
throw new ImporterErrorException('Invalid SimpleFIN token or authentication failed');
case 403:
throw new ImporterErrorException('Access denied to SimpleFIN resource');
case 404:
throw new ImporterErrorException('SimpleFIN resource not found');
case 429:
throw new ImporterErrorException('SimpleFIN rate limit exceeded');
default:
throw new ImporterErrorException(sprintf('SimpleFIN API error (HTTP %d): %s', $statusCode, $body));
}
}
protected function getApiUrl(): string
{
return $this->apiUrl;
}
protected function getToken(): string
{
return $this->token;
}
protected function getParameters(): array
{
return $this->parameters;
}
protected function getTimeOut(): float
{
return $this->timeOut;
}
}