diff --git a/app/Http/Controllers/Import/PrerequisitesController.php b/app/Http/Controllers/Import/PrerequisitesController.php index 256d94e828..e7b46c4f7d 100644 --- a/app/Http/Controllers/Import/PrerequisitesController.php +++ b/app/Http/Controllers/Import/PrerequisitesController.php @@ -85,10 +85,10 @@ class PrerequisitesController extends Controller * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * @throws FireflyException */ - public function postPrerequisites(Request $request, string $bank) + public function post(Request $request, string $bank) { Log::debug(sprintf('Now in postPrerequisites for %s', $bank)); - $class = config(sprintf('firefly.import_pre.%s', $bank)); + $class = strval(config(sprintf('import.prerequisites.%s', $bank))); if (!class_exists($class)) { throw new FireflyException(sprintf('Cannot find class %s', $class)); } diff --git a/app/Import/Prerequisites/SpectrePrerequisites.php b/app/Import/Prerequisites/SpectrePrerequisites.php index cf03ba0048..f9a1102def 100644 --- a/app/Import/Prerequisites/SpectrePrerequisites.php +++ b/app/Import/Prerequisites/SpectrePrerequisites.php @@ -56,7 +56,7 @@ class SpectrePrerequisites implements PrerequisitesInterface public function getViewParameters(): array { $publicKey = $this->getPublicKey(); - $subTitle = strval(trans('bank.spectre_title')); + $subTitle = strval(trans('import.spectre_title')); $subTitleIcon = 'fa-archive'; return compact('publicKey', 'subTitle', 'subTitleIcon'); diff --git a/app/Import/Routine/SpectreRoutine.php b/app/Import/Routine/SpectreRoutine.php new file mode 100644 index 0000000000..5306237cc3 --- /dev/null +++ b/app/Import/Routine/SpectreRoutine.php @@ -0,0 +1,133 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Import\Routine; + +use FireflyIII\Models\ImportJob; +use FireflyIII\Services\Spectre\Object\Customer; +use FireflyIII\Services\Spectre\Request\NewCustomerRequest; +use Preferences; +use Illuminate\Support\Collection; +use Log; + +/** + * Class FileRoutine + */ +class SpectreRoutine implements RoutineInterface +{ + /** @var Collection */ + public $errors; + /** @var Collection */ + public $journals; + /** @var int */ + public $lines = 0; + /** @var ImportJob */ + private $job; + + /** + * ImportRoutine constructor. + */ + public function __construct() + { + $this->journals = new Collection; + $this->errors = new Collection; + } + + /** + * @return Collection + */ + public function getErrors(): Collection + { + return $this->errors; + } + + /** + * @return Collection + */ + public function getJournals(): Collection + { + return $this->journals; + } + + /** + * @return int + */ + public function getLines(): int + { + return $this->lines; + } + + /** + * + */ + public function run(): bool + { + if ('configured' !== $this->job->status) { + Log::error(sprintf('Job %s is in state "%s" so it cannot be started.', $this->job->key, $this->job->status)); + + return false; + } + set_time_limit(0); + Log::info(sprintf('Start with import job %s using Spectre.', $this->job->key)); + // create customer if user does not have one: + $customer = $this->getCustomer(); + + + return true; + } + + /** + * @param ImportJob $job + */ + public function setJob(ImportJob $job) + { + $this->job = $job; + } + + /** + * @return Customer + */ + protected function createCustomer(): Customer + { + $newCustomerRequest = new NewCustomerRequest($this->job->user); + $newCustomerRequest->call(); + echo '
'; + print_r($newCustomerRequest->getCustomer()); + exit; + + } + + /** + * @return Customer + */ + protected function getCustomer(): Customer + { + $preference = Preferences::getForUser($this->job->user, 'spectre_customer', null); + if (is_null($preference)) { + return $this->createCustomer(); + } + var_dump($preference->data); + exit; + } + + +} diff --git a/app/Services/Spectre/Object/Customer.php b/app/Services/Spectre/Object/Customer.php new file mode 100644 index 0000000000..21f2f2f0f2 --- /dev/null +++ b/app/Services/Spectre/Object/Customer.php @@ -0,0 +1,90 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Object; + +/** + * Class Customer + */ +class Customer extends SpectreObject +{ + /** @var int */ + private $id; + /** @var string */ + private $identifier; + /** @var string */ + private $secret; + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @param int $id + */ + public function setId(int $id): void + { + $this->id = $id; + } + + /** + * @return string + */ + public function getIdentifier(): string + { + return $this->identifier; + } + + /** + * @param string $identifier + */ + public function setIdentifier(string $identifier): void + { + $this->identifier = $identifier; + } + + /** + * @return string + */ + public function getSecret(): string + { + return $this->secret; + } + + /** + * @param string $secret + */ + public function setSecret(string $secret): void + { + $this->secret = $secret; + } + + + + + +} \ No newline at end of file diff --git a/app/Services/Spectre/Object/SpectreObject.php b/app/Services/Spectre/Object/SpectreObject.php new file mode 100644 index 0000000000..e41db10601 --- /dev/null +++ b/app/Services/Spectre/Object/SpectreObject.php @@ -0,0 +1,32 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Object; + +/** + * Class SpectreObject + */ +class SpectreObject +{ + +} \ No newline at end of file diff --git a/app/Services/Spectre/Request/NewCustomerRequest.php b/app/Services/Spectre/Request/NewCustomerRequest.php new file mode 100644 index 0000000000..93cbef13c7 --- /dev/null +++ b/app/Services/Spectre/Request/NewCustomerRequest.php @@ -0,0 +1,63 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Spectre\Request; + +/** + * Class NewCustomerRequest + */ +class NewCustomerRequest extends SpectreRequest +{ + /** @var array */ + protected $customer = []; + + /** + * + * @throws \FireflyIII\Exceptions\FireflyException + */ + public function call(): void + { + $data = [ + 'data' => [ + 'identifier' => 'default_ff3_customer', + ], + ]; + $uri = '/api/v3/customers/'; + $response = $this->sendSignedSpectrePost($uri, $data); + + // create customer: + $this->customer = $response['data']; + + return; + } + + /** + * @return array + */ + public function getCustomer(): array + { + return $this->customer; + } + + +} \ No newline at end of file diff --git a/app/Services/Spectre/Request/SpectreRequest.php b/app/Services/Spectre/Request/SpectreRequest.php index eaaa284694..c93e77c036 100644 --- a/app/Services/Spectre/Request/SpectreRequest.php +++ b/app/Services/Spectre/Request/SpectreRequest.php @@ -28,6 +28,7 @@ use FireflyIII\User; use Log; use Requests; use Requests_Exception; +use Requests_Response; //use FireflyIII\Services\Bunq\Object\ServerPublicKey; @@ -37,7 +38,7 @@ use Requests_Exception; abstract class SpectreRequest { /** @var string */ - protected $clientId = ''; + protected $clientId = ''; /** * @var int */ @@ -174,7 +175,7 @@ abstract class SpectreRequest // base64(sha1_signature(private_key, "Expires-at|request_method|original_url|post_body|md5_of_uploaded_file|"))) // Prepare the signature $toSign = $this->expiresAt . '|' . strtoupper($method) . '|' . $uri . '|' . $data . ''; // no file so no content there. - Log::debug(sprintf('String to sign: %s', $toSign)); + Log::debug(sprintf('String to sign: "%s"', $toSign)); $signature = ''; // Sign the data @@ -202,92 +203,12 @@ abstract class SpectreRequest ]; } - /** - * @param string $uri - * @param array $headers - * - * @return array - * - * @throws Exception - */ - protected function sendSignedBunqDelete(string $uri, array $headers): array - { - if (0 === strlen($this->server)) { - throw new FireflyException('No bunq server defined'); - } - - $fullUri = $this->server . $uri; - $signature = $this->generateSignature('delete', $uri, $headers, ''); - $headers['X-Bunq-Client-Signature'] = $signature; - try { - $response = Requests::delete($fullUri, $headers); - } catch (Requests_Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = intval($response->status_code); - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - Log::debug(sprintf('Response to DELETE %s is %s', $fullUri, $body)); - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { - throw new FireflyException(sprintf('Could not verify signature for request to "%s"', $uri)); - } - - return $array; - } - /** * @param string $uri * @param array $data - * @param array $headers * * @return array * - * @throws Exception - */ - protected function sendSignedBunqPost(string $uri, array $data, array $headers): array - { - $body = json_encode($data); - $fullUri = $this->server . $uri; - $signature = $this->generateSignature('post', $uri, $headers, $body); - $headers['X-Bunq-Client-Signature'] = $signature; - try { - $response = Requests::post($fullUri, $headers, $body); - } catch (Requests_Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = intval($response->status_code); - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } - - if (!$this->verifyServerSignature($body, $responseHeaders, $statusCode)) { - throw new FireflyException(sprintf('Could not verify signature for request to "%s"', $uri)); - } - - return $array; - } - - /** - * @param string $uri - * @param array $data - * @return array - * * @throws FireflyException */ protected function sendSignedSpectreGet(string $uri, array $data): array @@ -308,11 +229,9 @@ abstract class SpectreRequest } catch (Requests_Exception $e) { throw new FireflyException(sprintf('Request Exception: %s', $e->getMessage())); } + $this->detectError($response); $statusCode = intval($response->status_code); - if ($statusCode !== 200) { - throw new FireflyException(sprintf('Status code %d: %s', $statusCode, $response->body)); - } $body = $response->body; $array = json_decode($body, true); @@ -320,32 +239,9 @@ abstract class SpectreRequest $array['ResponseHeaders'] = $responseHeaders; $array['ResponseStatusCode'] = $statusCode; - return $array; - } - - /** - * @param string $uri - * @param array $headers - * - * @return array - */ - protected function sendUnsignedBunqDelete(string $uri, array $headers): array - { - $fullUri = $this->server . $uri; - try { - $response = Requests::delete($fullUri, $headers); - } catch (Requests_Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; - } - $body = $response->body; - $array = json_decode($body, true); - $responseHeaders = $response->headers->getAll(); - $statusCode = $response->status_code; - $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); + if (isset($array['error_class'])) { + $message = $array['error_message'] ?? '(no message)'; + throw new FireflyException(sprintf('Error of class %s: %s', $array['error_class'], $message)); } return $array; @@ -354,30 +250,59 @@ abstract class SpectreRequest /** * @param string $uri * @param array $data - * @param array $headers * * @return array + * + * @throws FireflyException */ - protected function sendUnsignedBunqPost(string $uri, array $data, array $headers): array + protected function sendSignedSpectrePost(string $uri, array $data): array { - $body = json_encode($data); - $fullUri = $this->server . $uri; - try { - $response = Requests::post($fullUri, $headers, $body); - } catch (Requests_Exception $e) { - return ['Error' => [0 => ['error_description' => $e->getMessage(), 'error_description_translated' => $e->getMessage()]]]; + if (0 === strlen($this->server)) { + throw new FireflyException('No Spectre server defined'); } + + $headers = $this->getDefaultHeaders(); + $body = json_encode($data); + $fullUri = $this->server . $uri; + $signature = $this->generateSignature('post', $fullUri, $body); + $headers['Signature'] = $signature; + + Log::debug('Final headers for spectre signed POST request:', $headers); + try { + $response = Requests::get($fullUri, $headers); + } catch (Requests_Exception $e) { + throw new FireflyException(sprintf('Request Exception: %s', $e->getMessage())); + } + $this->detectError($response); $body = $response->body; $array = json_decode($body, true); $responseHeaders = $response->headers->getAll(); - $statusCode = $response->status_code; $array['ResponseHeaders'] = $responseHeaders; - $array['ResponseStatusCode'] = $statusCode; - - if ($this->isErrorResponse($array)) { - $this->throwResponseError($array); - } + $array['ResponseStatusCode'] = $response->status_code; return $array; } + + /** + * @param Requests_Response $response + * + * @throws FireflyException + */ + private function detectError(Requests_Response $response): void + { + $body = $response->body; + $array = json_decode($body, true); + if (isset($array['error_class'])) { + $message = $array['error_message'] ?? '(no message)'; + + throw new FireflyException(sprintf('Error of class %s: %s', $array['error_class'], $message)); + } + + $statusCode = intval($response->status_code); + if ($statusCode !== 200) { + throw new FireflyException(sprintf('Status code %d: %s', $statusCode, $response->body)); + } + + return; + } } diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 6b7076a00c..84f57f87fc 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -200,6 +200,7 @@ return [ 'app_secret' => 'App secret', 'public_key' => 'Public key', 'country_code' => 'Country code', + 'provider_code' => 'Bank or data-provider', 'due_date' => 'Due date', diff --git a/resources/views/import/spectre/input-fields.twig b/resources/views/import/spectre/input-fields.twig index 03aae3faf2..93c21d595d 100644 --- a/resources/views/import/spectre/input-fields.twig +++ b/resources/views/import/spectre/input-fields.twig @@ -10,18 +10,18 @@-{{ trans('bank.spectre_input_fields_title') }}
+{{ trans('import.spectre_input_fields_title') }}
diff --git a/resources/views/import/spectre/prerequisites.twig b/resources/views/import/spectre/prerequisites.twig index 1b225e6a12..c521d532f0 100644 --- a/resources/views/import/spectre/prerequisites.twig +++ b/resources/views/import/spectre/prerequisites.twig @@ -5,18 +5,18 @@ {% endblock %} {% block content %}- {{ trans('bank.spectre_input_fields_text',{provider: data.provider.data.name, country: data.country})|raw }} + {{ trans('import.spectre_input_fields_text',{provider: data.provider.data.name, country: data.country})|raw }}
- {{ trans('bank.spectre_instructions_english') }} + {{ trans('import.spectre_instructions_english') }}
-+
{{ data.provider.data.instruction|nl2br }}
-