mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-11-22 08:56:39 -06:00
First code for YNAB import #145
This commit is contained in:
parent
a1005d91df
commit
8efbeb14d2
70
app/Http/Controllers/Import/CallbackController.php
Normal file
70
app/Http/Controllers/Import/CallbackController.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* CallbackController.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Import;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class CallbackController
|
||||
*/
|
||||
class CallbackController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @param ImportJobRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
|
||||
*/
|
||||
public function ynab(Request $request, ImportJobRepositoryInterface $repository)
|
||||
{
|
||||
$code = (string)$request->get('code');
|
||||
$jobKey = (string)$request->get('state');
|
||||
$importJob = $repository->findByKey($jobKey);
|
||||
if ('' === $code) {
|
||||
return view('error')->with('message', 'You Need A Budget did not reply with a valid authorization code. Firefly III cannot continue.');
|
||||
}
|
||||
if ('' === $jobKey || null === $importJob) {
|
||||
return view('error')->with('message', 'You Need A Budget did not reply with the correct state identifier. Firefly III cannot continue.');
|
||||
}
|
||||
Log::debug(sprintf('Got a code from YNAB: %s', $code));
|
||||
|
||||
// we have a code. Make the job ready for the next step, and then redirect the user.
|
||||
$configuration = $repository->getConfiguration($importJob);
|
||||
$configuration['auth_code'] = $code;
|
||||
$repository->setConfiguration($importJob, $configuration);
|
||||
|
||||
// set stage to make the import routine take the correct action:
|
||||
$repository->setStatus($importJob, 'ready_to_run');
|
||||
$repository->setStage($importJob, 'get_access_token');
|
||||
|
||||
return redirect(route('import.job.status.index', [$importJob->key]));
|
||||
}
|
||||
|
||||
}
|
@ -78,9 +78,15 @@ class IndexController extends Controller
|
||||
{
|
||||
Log::debug(sprintf('Will create job for provider "%s"', $importProvider));
|
||||
|
||||
$importJob = $this->repository->create($importProvider);
|
||||
$hasPreReq = (bool)config(sprintf('import.has_prereq.%s', $importProvider));
|
||||
$hasConfig = (bool)config(sprintf('import.has_job_config.%s', $importProvider));
|
||||
$importJob = $this->repository->create($importProvider);
|
||||
$hasPreReq = (bool)config(sprintf('import.has_prereq.%s', $importProvider));
|
||||
$hasConfig = (bool)config(sprintf('import.has_job_config.%s', $importProvider));
|
||||
$allowedForDemo = (bool)config(sprintf('import.allowed_for_demo.%s', $importProvider));
|
||||
$isDemoUser = $this->userRepository->hasRole(auth()->user(), 'demo');
|
||||
|
||||
if ($isDemoUser && !$allowedForDemo) {
|
||||
return redirect(route('import.index'));
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Created job #%d for provider %s', $importJob->id, $importProvider));
|
||||
|
||||
@ -180,7 +186,8 @@ class IndexController extends Controller
|
||||
$providers = $this->providers;
|
||||
$subTitle = (string)trans('import.index_breadcrumb');
|
||||
$subTitleIcon = 'fa-home';
|
||||
$isDemoUser = $this->userRepository->hasRole(auth()->user(), 'demo');
|
||||
|
||||
return view('import.index', compact('subTitle', 'subTitleIcon', 'providers'));
|
||||
return view('import.index', compact('subTitle', 'subTitleIcon', 'providers', 'isDemoUser'));
|
||||
}
|
||||
}
|
||||
|
125
app/Import/JobConfiguration/YnabJobConfiguration.php
Normal file
125
app/Import/JobConfiguration/YnabJobConfiguration.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* YnabJobConfiguration.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Import\JobConfiguration;
|
||||
|
||||
use FireflyIII\Models\ImportJob;
|
||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class YnabJobConfiguration
|
||||
*/
|
||||
class YnabJobConfiguration implements JobConfigurationInterface
|
||||
{
|
||||
/** @var ImportJob The import job */
|
||||
private $importJob;
|
||||
/** @var ImportJobRepositoryInterface Import job repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* Returns true when the initial configuration for this job is complete.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function configurationComplete(): bool
|
||||
{
|
||||
// config is only needed when the job is in stage "new".
|
||||
if ($this->importJob->stage === 'new') {
|
||||
Log::debug('YNAB configurationComplete: stage is new, return false');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Log::debug('YNAB configurationComplete: stage is not new, return true');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store any data from the $data array into the job. Anything in the message bag will be flashed
|
||||
* as an error to the user, regardless of its content.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return MessageBag
|
||||
*/
|
||||
public function configureJob(array $data): MessageBag
|
||||
{
|
||||
Log::debug('YNAB configureJob: nothing to do.');
|
||||
|
||||
// there is never anything to store from this job.
|
||||
return new MessageBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data required for the next step in the job configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getNextData(): array
|
||||
{
|
||||
$data = [];
|
||||
// here we update the job so it can redirect properly to YNAB
|
||||
if ($this->importJob->stage === 'new') {
|
||||
|
||||
// update stage to make sure we catch the token.
|
||||
$this->repository->setStage($this->importJob, 'catch-auth-code');
|
||||
$clientId = (string)config('import.options.ynab.client_id');
|
||||
$callBackUri = route('import.callback.ynab');
|
||||
$uri = sprintf(
|
||||
'https://app.youneedabudget.com/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&state=%s', $clientId, $callBackUri,
|
||||
$this->importJob->key
|
||||
);
|
||||
$data['token-url'] = $uri;
|
||||
Log::debug(sprintf('YNAB getNextData: URI to redirect to is %s', $uri));
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view of the next step in the job configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNextView(): string
|
||||
{
|
||||
Log::debug('Return YNAB redirect view.');
|
||||
return 'import.ynab.redirect';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set import job.
|
||||
*
|
||||
* @param ImportJob $importJob
|
||||
*/
|
||||
public function setImportJob(ImportJob $importJob): void
|
||||
{
|
||||
$this->importJob = $importJob;
|
||||
$this->repository = app(ImportJobRepositoryInterface::class);
|
||||
$this->repository->setUser($importJob->user);
|
||||
}
|
||||
}
|
145
app/Import/Prerequisites/YnabPrerequisites.php
Normal file
145
app/Import/Prerequisites/YnabPrerequisites.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* YnabPrerequisites.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Import\Prerequisites;
|
||||
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class YnabPrerequisites
|
||||
*/
|
||||
class YnabPrerequisites implements PrerequisitesInterface
|
||||
{
|
||||
/** @var User The current user */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Returns view name that allows user to fill in prerequisites.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getView(): string
|
||||
{
|
||||
return 'import.ynab.prerequisites';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any values required for the prerequisites-view.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getViewParameters(): array
|
||||
{
|
||||
Log::debug('Now in YnabPrerequisites::getViewParameters()');
|
||||
$clientId = '';
|
||||
$clientSecret = '';
|
||||
if ($this->hasClientId()) {
|
||||
$clientId = app('preferences')->getForUser($this->user, 'ynab_client_id', null)->data;
|
||||
}
|
||||
if ($this->hasClientSecret()) {
|
||||
$clientSecret = app('preferences')->getForUser($this->user, 'ynab_client_secret', null)->data;
|
||||
}
|
||||
|
||||
$callBackUri = route('import.callback.ynab');
|
||||
|
||||
return ['client_id' => $clientId, 'client_secret' => $clientSecret, 'callback_uri' => $callBackUri];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if all prerequisites have been met.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isComplete(): bool
|
||||
{
|
||||
return $this->hasClientId() && $this->hasClientSecret();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
|
||||
*
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method responds to the user's submission of an API key. Should do nothing but store the value.
|
||||
*
|
||||
* Errors must be returned in the message bag under the field name they are requested by.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return MessageBag
|
||||
*/
|
||||
public function storePrerequisites(array $data): MessageBag
|
||||
{
|
||||
$clientId = $data['client_id'] ?? '';
|
||||
$clientSecret = $data['client_secret'] ?? '';
|
||||
Log::debug('Storing YNAB client data');
|
||||
app('preferences')->setForUser($this->user, 'ynab_client_id', $clientId);
|
||||
app('preferences')->setForUser($this->user, 'ynab_client_secret', $clientSecret);
|
||||
|
||||
return new MessageBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have the client ID.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasClientId(): bool
|
||||
{
|
||||
$clientId = app('preferences')->getForUser($this->user, 'ynab_client_id', null);
|
||||
if (null === $clientId) {
|
||||
return false;
|
||||
}
|
||||
if ('' === (string)$clientId->data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have the client secret
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasClientSecret(): bool
|
||||
{
|
||||
$clientSecret = app('preferences')->getForUser($this->user, 'ynab_client_secret', null);
|
||||
if (null === $clientSecret) {
|
||||
return false;
|
||||
}
|
||||
if ('' === (string)$clientSecret->data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -50,12 +50,12 @@ class BunqRoutine implements RoutineInterface
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
Log::debug(sprintf('Now in SpectreRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
|
||||
Log::debug(sprintf('Now in BunqRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
|
||||
$valid = ['ready_to_run']; // should be only ready_to_run
|
||||
if (\in_array($this->importJob->status, $valid, true)) {
|
||||
switch ($this->importJob->stage) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('SpectreRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore
|
||||
throw new FireflyException(sprintf('BunqRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore
|
||||
case 'new':
|
||||
// list all of the users accounts.
|
||||
$this->repository->setStatus($this->importJob, 'running');
|
||||
|
85
app/Import/Routine/YnabRoutine.php
Normal file
85
app/Import/Routine/YnabRoutine.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* YnabRoutine.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Import\Routine;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\ImportJob;
|
||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use FireflyIII\Support\Import\Routine\Ynab\StageGetAccessHandler;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class YnabRoutine
|
||||
*/
|
||||
class YnabRoutine implements RoutineInterface
|
||||
{
|
||||
/** @var ImportJob The import job */
|
||||
private $importJob;
|
||||
|
||||
/** @var ImportJobRepositoryInterface Import job repository */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* At the end of each run(), the import routine must set the job to the expected status.
|
||||
*
|
||||
* The final status of the routine must be "provider_finished".
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
Log::debug(sprintf('Now in YNAB routine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
|
||||
$valid = ['ready_to_run']; // should be only ready_to_run
|
||||
if (\in_array($this->importJob->status, $valid, true)) {
|
||||
|
||||
// get access token from YNAB
|
||||
if ('get_access_token' === $this->importJob->stage) {
|
||||
// list all of the users accounts.
|
||||
$this->repository->setStatus($this->importJob, 'running');
|
||||
/** @var StageGetAccessHandler $handler */
|
||||
$handler = app(StageGetAccessHandler::class);
|
||||
$handler->setImportJob($this->importJob);
|
||||
$handler->run();
|
||||
$this->repository->setStage($this->importJob, 'get_transactions');
|
||||
return;
|
||||
}
|
||||
throw new FireflyException(sprintf('YNAB import routine cannot handle stage "%s"', $this->importJob->stage));
|
||||
}
|
||||
throw new FireflyException(sprintf('YNAB import routine cannot handle status "%s"', $this->importJob->status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the import job.
|
||||
*
|
||||
* @param ImportJob $importJob
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setImportJob(ImportJob $importJob): void
|
||||
{
|
||||
$this->importJob = $importJob;
|
||||
$this->repository = app(ImportJobRepositoryInterface::class);
|
||||
$this->repository->setUser($importJob->user);
|
||||
}
|
||||
}
|
@ -54,21 +54,18 @@ class ImportProvider implements BinderInterface
|
||||
foreach ($providerNames as $providerName) {
|
||||
// only consider enabled providers
|
||||
$enabled = (bool)config(sprintf('import.enabled.%s', $providerName));
|
||||
$allowedForDemo = (bool)config(sprintf('import.allowed_for_demo.%s', $providerName));
|
||||
$allowedForUser = (bool)config(sprintf('import.allowed_for_user.%s', $providerName));
|
||||
if (false === $enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true === $isDemoUser && false === $allowedForDemo) {
|
||||
continue;
|
||||
}
|
||||
if (false === $isDemoUser && false === $allowedForUser && false === $isDebug) {
|
||||
continue; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$providers[$providerName] = [
|
||||
'has_prereq' => (bool)config('import.has_prereq.' . $providerName),
|
||||
'has_prereq' => (bool)config('import.has_prereq.' . $providerName),
|
||||
'allowed_for_demo' => (bool)config(sprintf('import.allowed_for_demo.%s', $providerName)),
|
||||
];
|
||||
$class = (string)config(sprintf('import.prerequisites.%s', $providerName));
|
||||
$result = false;
|
||||
|
86
app/Support/Import/Routine/Ynab/StageGetAccessHandler.php
Normal file
86
app/Support/Import/Routine/Ynab/StageGetAccessHandler.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* StageGetAccessHandler.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Import\Routine\Ynab;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\ImportJob;
|
||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class StageGetAccessHandler
|
||||
*/
|
||||
class StageGetAccessHandler
|
||||
{
|
||||
/** @var ImportJob */
|
||||
private $importJob;
|
||||
/** @var ImportJobRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* Send a token request to YNAB. Return with access token (if all goes well).
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$config = $this->repository->getConfiguration($this->importJob);
|
||||
$clientId = app('preferences')->get('ynab_client_id', '')->data;
|
||||
$clientSecret = app('preferences')->get('ynab_client_secret', '')->data;
|
||||
$redirectUri = route('import.callback.ynab');
|
||||
$code = $config['auth_code'];
|
||||
$uri = sprintf(
|
||||
'https://app.youneedabudget.com/oauth/token?client_id=%s&client_secret=%s&redirect_uri=%s&grant_type=authorization_code&code=%s', $clientId,
|
||||
$clientSecret, $redirectUri, $code
|
||||
);
|
||||
$client = new Client;
|
||||
try {
|
||||
$res = $client->request('POST', $uri);
|
||||
} catch (GuzzleException|Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($e->getMessage());
|
||||
}
|
||||
$statusCode = $res->getStatusCode();
|
||||
$content = trim($res->getBody()->getContents());
|
||||
$json = json_decode($content, true) ?? [];
|
||||
Log::debug(sprintf('Status code from YNAB is %d', $statusCode));
|
||||
Log::debug(sprintf('Body of result is %s', $content), $json);
|
||||
Log::error('Hard exit');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImportJob $importJob
|
||||
*/
|
||||
public function setImportJob(ImportJob $importJob): void
|
||||
{
|
||||
$this->importJob = $importJob;
|
||||
$this->repository = app(ImportJobRepositoryInterface::class);
|
||||
$this->repository->setUser($importJob->user);
|
||||
}
|
||||
}
|
@ -26,13 +26,16 @@ use FireflyIII\Import\JobConfiguration\BunqJobConfiguration;
|
||||
use FireflyIII\Import\JobConfiguration\FakeJobConfiguration;
|
||||
use FireflyIII\Import\JobConfiguration\FileJobConfiguration;
|
||||
use FireflyIII\Import\JobConfiguration\SpectreJobConfiguration;
|
||||
use FireflyIII\Import\JobConfiguration\YnabJobConfiguration;
|
||||
use FireflyIII\Import\Prerequisites\BunqPrerequisites;
|
||||
use FireflyIII\Import\Prerequisites\FakePrerequisites;
|
||||
use FireflyIII\Import\Prerequisites\SpectrePrerequisites;
|
||||
use FireflyIII\Import\Prerequisites\YnabPrerequisites;
|
||||
use FireflyIII\Import\Routine\BunqRoutine;
|
||||
use FireflyIII\Import\Routine\FakeRoutine;
|
||||
use FireflyIII\Import\Routine\FileRoutine;
|
||||
use FireflyIII\Import\Routine\SpectreRoutine;
|
||||
use FireflyIII\Import\Routine\YnabRoutine;
|
||||
use FireflyIII\Support\Import\Routine\File\CSVProcessor;
|
||||
|
||||
return [
|
||||
@ -42,6 +45,7 @@ return [
|
||||
'file' => true,
|
||||
'bunq' => true,
|
||||
'spectre' => true,
|
||||
'ynab' => true,
|
||||
'plaid' => false,
|
||||
'quovo' => false,
|
||||
'yodlee' => false,
|
||||
@ -53,6 +57,7 @@ return [
|
||||
'file' => false,
|
||||
'bunq' => false,
|
||||
'spectre' => false,
|
||||
'ynab' => false,
|
||||
'plaid' => false,
|
||||
'quovo' => false,
|
||||
'yodlee' => false,
|
||||
@ -63,6 +68,7 @@ return [
|
||||
'file' => true,
|
||||
'bunq' => true,
|
||||
'spectre' => true,
|
||||
'ynab' => true,
|
||||
'plaid' => true,
|
||||
'quovo' => true,
|
||||
'yodlee' => true,
|
||||
@ -73,6 +79,7 @@ return [
|
||||
'file' => false,
|
||||
'bunq' => true,
|
||||
'spectre' => true,
|
||||
'ynab' => true,
|
||||
'plaid' => true,
|
||||
'quovo' => true,
|
||||
'yodlee' => true,
|
||||
@ -83,6 +90,7 @@ return [
|
||||
'file' => false,
|
||||
'bunq' => BunqPrerequisites::class,
|
||||
'spectre' => SpectrePrerequisites::class,
|
||||
'ynab' => YnabPrerequisites::class,
|
||||
'plaid' => false,
|
||||
'quovo' => false,
|
||||
'yodlee' => false,
|
||||
@ -93,6 +101,7 @@ return [
|
||||
'file' => true,
|
||||
'bunq' => true,
|
||||
'spectre' => true,
|
||||
'ynab' => true,
|
||||
'plaid' => false,
|
||||
'quovo' => false,
|
||||
'yodlee' => false,
|
||||
@ -103,6 +112,7 @@ return [
|
||||
'file' => FileJobConfiguration::class,
|
||||
'bunq' => BunqJobConfiguration::class,
|
||||
'spectre' => SpectreJobConfiguration::class,
|
||||
'ynab' => YnabJobConfiguration::class,
|
||||
'plaid' => false,
|
||||
'quovo' => false,
|
||||
'yodlee' => false,
|
||||
@ -113,6 +123,7 @@ return [
|
||||
'file' => FileRoutine::class,
|
||||
'bunq' => BunqRoutine::class,
|
||||
'spectre' => SpectreRoutine::class,
|
||||
'ynab' => YnabRoutine::class,
|
||||
'plaid' => false,
|
||||
'quovo' => false,
|
||||
'yodlee' => false,
|
||||
@ -140,6 +151,9 @@ return [
|
||||
'spectre' => [
|
||||
'server' => 'www.saltedge.com',
|
||||
],
|
||||
'ynab' => [
|
||||
'client_id' => '666db19f6c5a2299bf44999a6ea802e96a5f488c3a5c8a5cbb417b59dcf18b72',
|
||||
],
|
||||
'plaid' => [],
|
||||
'quovo' => [],
|
||||
'yodlee' => [],
|
||||
|
@ -237,5 +237,6 @@ return [
|
||||
'repetitions' => 'Repetitions',
|
||||
'calendar' => 'Calendar',
|
||||
'weekend' => 'Weekend',
|
||||
'client_secret' => 'Client secret',
|
||||
|
||||
];
|
||||
|
@ -28,9 +28,11 @@ return [
|
||||
'prerequisites_breadcrumb_fake' => 'Prerequisites for the fake import provider',
|
||||
'prerequisites_breadcrumb_spectre' => 'Prerequisites for Spectre',
|
||||
'prerequisites_breadcrumb_bunq' => 'Prerequisites for bunq',
|
||||
'prerequisites_breadcrumb_ynab' => 'Prerequisites for YNAB',
|
||||
'job_configuration_breadcrumb' => 'Configuration for ":key"',
|
||||
'job_status_breadcrumb' => 'Import status for ":key"',
|
||||
'cannot_create_for_provider' => 'Firefly III cannot create a job for the ":provider"-provider.',
|
||||
'disabled_for_demo_user' => 'disabled in demo',
|
||||
|
||||
// index page:
|
||||
'general_index_title' => 'Import a file',
|
||||
@ -43,6 +45,7 @@ return [
|
||||
'button_plaid' => 'Import using Plaid',
|
||||
'button_yodlee' => 'Import using Yodlee',
|
||||
'button_quovo' => 'Import using Quovo',
|
||||
'button_ynab' => 'Import from You Need A Budget',
|
||||
// global config box (index)
|
||||
'global_config_title' => 'Global import configuration',
|
||||
'global_config_text' => 'In the future, this box will feature preferences that apply to ALL import providers above.',
|
||||
@ -76,10 +79,14 @@ return [
|
||||
'prereq_bunq_title' => 'Prerequisites for an import from bunq',
|
||||
'prereq_bunq_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.',
|
||||
'prereq_bunq_ip' => 'bunq requires your externally facing IP address. Firefly III has tried to fill this in using <a href="https://www.ipify.org/">the ipify service</a>. Make sure this IP address is correct, or the import will fail.',
|
||||
'prereq_ynab_title' => 'Prerequisites for an import from YNAB',
|
||||
'prereq_ynab_text' => 'In order to be able to download transactions from YNAB, please create a new application on your <a href="https://app.youneedabudget.com/settings/developer">Developer Settings Page</a> and enter the client ID and secret on this page.',
|
||||
'prereq_ynab_redirect' => 'To complete the configuration, enter the following URL at the <a href="https://app.youneedabudget.com/settings/developer">Developer Settings Page</a> under the "Redirect URI(s)".',
|
||||
// prerequisites success messages:
|
||||
'prerequisites_saved_for_fake' => 'Fake API key stored successfully!',
|
||||
'prerequisites_saved_for_spectre' => 'App ID and secret stored!',
|
||||
'prerequisites_saved_for_bunq' => 'API key and IP stored!',
|
||||
'prerequisites_saved_for_ynab' => 'YNAB client ID and secret stored!',
|
||||
|
||||
// job configuration:
|
||||
'job_config_apply_rules_title' => 'Job configuration - apply your rules?',
|
||||
@ -219,7 +226,7 @@ return [
|
||||
'column_account-iban' => 'Asset account (IBAN)',
|
||||
'column_account-id' => 'Asset account ID (matching FF3)',
|
||||
'column_account-name' => 'Asset account (name)',
|
||||
'column_account-bic' => 'Asset account (BIC)',
|
||||
'column_account-bic' => 'Asset account (BIC)',
|
||||
'column_amount' => 'Amount',
|
||||
'column_amount_foreign' => 'Amount (in foreign currency)',
|
||||
'column_amount_debit' => 'Amount (debit column)',
|
||||
|
@ -18,11 +18,18 @@
|
||||
{% for name, provider in providers %}
|
||||
{# button for each import thing: #}
|
||||
<div class="col-lg-1 col-md-4 col-sm-6 text-center">
|
||||
{% if not provider.allowed_for_demo and isDemoUser %}
|
||||
<img src="images/logos/{{ name }}.png" alt="{{ trans(('import.button_'~name)) }}"/><br/>
|
||||
{{ trans(('import.button_'~name)) }}<br>
|
||||
({{ trans('import.disabled_for_demo_user') }})
|
||||
{% else %}
|
||||
<a href="{{ route('import.create', [name]) }}">
|
||||
<img src="images/logos/{{ name }}.png" alt="{{ trans(('import.button_'~name)) }}"/><br/>
|
||||
{{ trans(('import.button_'~name)) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,4 +11,4 @@
|
||||
<body>
|
||||
If you are not redirected automatically, follow this <a href='{{ data['token-url'] }}'>link to Spectre.</a>.
|
||||
</body>
|
||||
</html>#}
|
||||
</html>
|
||||
|
53
resources/views/import/ynab/prerequisites.twig
Normal file
53
resources/views/import/ynab/prerequisites.twig
Normal file
@ -0,0 +1,53 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.render }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<form class="form-horizontal" action="{{ route('import.prerequisites.post',['ynab', importJob.key]) }}" method="post">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ trans('import.prereq_ynab_title') }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<p>
|
||||
{{ trans('import.prereq_ynab_text')|raw }}
|
||||
</p>
|
||||
<p>
|
||||
{{ trans('import.prereq_ynab_redirect')|raw }}
|
||||
<br /><br />
|
||||
<code>{{ callback_uri }}</code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
{{ ExpandedForm.text('client_id', client_id) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
{{ ExpandedForm.text('client_secret', client_secret) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn pull-right btn-success">
|
||||
{{ ('submit')|_ }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
||||
{% block styles %}
|
||||
{% endblock %}
|
14
resources/views/import/ynab/redirect.twig
Normal file
14
resources/views/import/ynab/redirect.twig
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh" content="0; url={{ data['token-url'] }}">
|
||||
<script type="text/javascript">
|
||||
window.location.href = "{{ data['token-url'] }}";
|
||||
</script>
|
||||
<title>Page Redirection</title>
|
||||
</head>
|
||||
<body>
|
||||
If you are not redirected automatically, follow this <a href='{{ data['token-url'] }}'>link to YNAB.</a>.
|
||||
</body>
|
||||
</html>
|
@ -503,6 +503,9 @@ Route::group(
|
||||
|
||||
// download config:
|
||||
Route::get('download/{importJob}', ['uses' => 'Import\IndexController@download', 'as' => 'job.download']);
|
||||
|
||||
// callback URI for YNAB OAuth. Sadly, needs a custom solution.
|
||||
Route::get('ynab-callback', ['uses' => 'Import\CallbackController@ynab', 'as' => 'callback.ynab']);
|
||||
}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user