Cleanup, add return types, normalise quotes

This commit is contained in:
Dave Shoreman 2024-12-22 00:41:02 +00:00
parent 66f197b857
commit 3204163e70
No known key found for this signature in database
GPG Key ID: C920D1D63709F443
4 changed files with 78 additions and 60 deletions

View File

@ -33,7 +33,7 @@ class Nordigen
{ {
public bool $test_mode; // https://developer.gocardless.com/bank-account-data/sandbox public bool $test_mode; // https://developer.gocardless.com/bank-account-data/sandbox
public string $sandbox_institutionId = "SANDBOXFINANCE_SFIN0000"; public string $sandbox_institutionId = 'SANDBOXFINANCE_SFIN0000';
protected \Nordigen\NordigenPHP\API\NordigenClient $client; protected \Nordigen\NordigenPHP\API\NordigenClient $client;
@ -167,7 +167,7 @@ class Nordigen
try { try {
return $this->client->requisition->getRequisition($requisitionId); return $this->client->requisition->getRequisition($requisitionId);
} catch (\Exception $e) { } catch (\Exception $e) {
if (strpos($e->getMessage(), "Invalid Requisition ID") !== false) { if (strpos($e->getMessage(), 'Invalid Requisition ID') !== false) {
return false; return false;
} }
@ -181,10 +181,10 @@ class Nordigen
try { try {
$out = new \stdClass(); $out = new \stdClass();
$out->data = $this->client->account($account_id)->getAccountDetails()["account"]; $out->data = $this->client->account($account_id)->getAccountDetails()['account'];
$out->metadata = $this->client->account($account_id)->getAccountMetaData(); $out->metadata = $this->client->account($account_id)->getAccountMetaData();
$out->balances = $this->client->account($account_id)->getAccountBalances()["balances"]; $out->balances = $this->client->account($account_id)->getAccountBalances()['balances'];
$out->institution = $this->client->institution->getInstitution($out->metadata["institution_id"]); $out->institution = $this->client->institution->getInstitution($out->metadata['institution_id']);
$it = new AccountTransformer(); $it = new AccountTransformer();
return $it->transform($out); return $it->transform($out);
@ -216,8 +216,9 @@ class Nordigen
try { try {
$account = $this->client->account($account_id)->getAccountMetaData(); $account = $this->client->account($account_id)->getAccountMetaData();
if ($account["status"] != "READY") { if ($account['status'] != 'READY') {
nlog('nordigen account was not in status ready. accountId: ' . $account_id . ' status: ' . $account["status"]); nlog("Nordigen account '{$account_id}' is not ready (status={$account['status']})");
return false; return false;
} }
@ -226,7 +227,7 @@ class Nordigen
nlog("Nordigen:: AccountActiveStatus:: {$e->getMessage()} {$e->getCode()}"); nlog("Nordigen:: AccountActiveStatus:: {$e->getMessage()} {$e->getCode()}");
if (strpos($e->getMessage(), "Invalid Account ID") !== false) { if (strpos($e->getMessage(), 'Invalid Account ID') !== false) {
return false; return false;
} }

View File

@ -21,8 +21,10 @@ use App\Models\Company;
use App\Utils\Ninja; use App\Utils\Ninja;
use Cache; use Cache;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\View\View;
use Nordigen\NordigenPHP\Exceptions\NordigenExceptions\NordigenException; use Nordigen\NordigenPHP\Exceptions\NordigenExceptions\NordigenException;
class NordigenController extends BaseController class NordigenController extends BaseController
@ -30,11 +32,9 @@ class NordigenController extends BaseController
/** /**
* Handles the initial bank connection flow * Handles the initial bank connection flow
*/ */
public function connect(ConnectNordigenBankIntegrationRequest $request) public function connect(ConnectNordigenBankIntegrationRequest $request): View|RedirectResponse
{ {
$data = $request->all(); $data = $request->all();
/** @var array $context */
$context = $request->getTokenContent(); $context = $request->getTokenContent();
if (!$context) { if (!$context) {
@ -42,21 +42,18 @@ class NordigenController extends BaseController
} }
$company = $request->getCompany(); $company = $request->getCompany();
$context["redirect"] = $data["redirect"]; $context['redirect'] = $data['redirect'];
$context["lang"] = $lang = substr($company->locale(), 0, 2); $context['lang'] = $lang = substr($company->locale(), 0, 2);
if ($context["context"] != "nordigen" || array_key_exists("requisitionId", $context)) { if ($context['context'] != 'nordigen' || array_key_exists('requisitionId', $context)) {
return $this->failed('token-invalid', $context); return $this->failed('token-invalid', $context);
} }
$company = $request->getCompany();
$account = $company->account;
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key'))) { if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key'))) {
return $this->failed('account-config-invalid', $context, $company); return $this->failed('account-config-invalid', $context, $company);
} }
if (!(Ninja::isSelfHost() || (Ninja::isHosted() && $account->isEnterprisePaidClient()))) { if (!(Ninja::isSelfHost() || (Ninja::isHosted() && $company->account->isEnterprisePaidClient()))) {
return $this->failed('not-available', $context, $company); return $this->failed('not-available', $context, $company);
} }
@ -64,13 +61,13 @@ class NordigenController extends BaseController
$institutions = $nordigen->getInstitutions(); $institutions = $nordigen->getInstitutions();
// show bank_selection_screen, when institution_id is not present // show bank_selection_screen, when institution_id is not present
if (!array_key_exists("institution_id", $data)) { if (!array_key_exists('institution_id', $data)) {
return view('bank.nordigen.handler', [ return view('bank.nordigen.handler', [
'lang' => $lang, 'lang' => $lang,
'company' => $company, 'company' => $company,
'account' => $company->account, 'account' => $company->account,
'institutions' => $institutions, 'institutions' => $institutions,
'redirectUrl' => $context["redirect"] . "?action=nordigen_connect&status=user-aborted" 'redirectUrl' => $context['redirect'] . '?action=nordigen_connect&status=user-aborted'
]); ]);
} }
@ -114,36 +111,35 @@ class NordigenController extends BaseController
return $this->failed('token-invalid', $context, $company); return $this->failed('token-invalid', $context, $company);
} }
nlog("Unknown Error from nordigen: " . $e); nlog("Unknown Error from nordigen: {$e}");
nlog($responseBody); nlog($responseBody);
return $this->failed('unknown', $context, $company); return $this->failed('unknown', $context, $company);
} }
// save cache // save cache
$context["requisitionId"] = $requisition["id"]; $context['requisitionId'] = $requisition['id'];
Cache::put($request->token, $context, 3600); Cache::put($request->token, $context, 3600);
return response()->redirectTo($requisition["link"]); return response()->redirectTo($requisition['link']);
} }
/** /**
* Handles the OAuth redirect and account setup after bank authentication * Handles the OAuth redirect and account setup after bank authentication
*/ */
public function confirm(ConfirmNordigenBankIntegrationRequest $request) public function confirm(ConfirmNordigenBankIntegrationRequest $request): View|RedirectResponse
{ {
$data = $request->all(); $data = $request->all();
$company = $request->getCompany(); $company = $request->getCompany();
$account = $company->account;
$lang = substr($company->locale(), 0, 2); $lang = substr($company->locale(), 0, 2);
/** @var array $context */ /** @var array $context */
$context = $request->getTokenContent(); $context = $request->getTokenContent();
if (!array_key_exists('lang', $data) && $context['lang'] != 'en') { if (!array_key_exists('lang', $data) && $context['lang'] != 'en') {
return redirect()->route('nordigen.confirm', array_merge(["lang" => $context['lang']], $request->query())); return redirect()->route('nordigen.confirm', array_merge(['lang' => $context['lang']], $request->query()));
} }
if (!$context || $context["context"] != "nordigen" || !array_key_exists("requisitionId", $context)) { if (!$context || $context['context'] != 'nordigen' || !array_key_exists('requisitionId', $context)) {
return $this->failed('ref-invalid', $context); return $this->failed('ref-invalid', $context);
} }
@ -151,28 +147,28 @@ class NordigenController extends BaseController
return $this->failed('account-config-invalid', $context, $company); return $this->failed('account-config-invalid', $context, $company);
} }
if (!(Ninja::isSelfHost() || (Ninja::isHosted() && $account->isEnterprisePaidClient()))) { if (!(Ninja::isSelfHost() || (Ninja::isHosted() && $company->account->isEnterprisePaidClient()))) {
return $this->failed('not-available', $context, $company); return $this->failed('not-available', $context, $company);
} }
// fetch requisition // fetch requisition
$nordigen = new Nordigen(); $nordigen = new Nordigen();
$requisition = $nordigen->getRequisition($context["requisitionId"]); $requisition = $nordigen->getRequisition($context['requisitionId']);
// check validity of requisition // check validity of requisition
if (!$requisition) { if (!$requisition) {
return $this->failed('requisition-not-found', $context, $company); return $this->failed('requisition-not-found', $context, $company);
} }
if ($requisition["status"] != "LN") { if ($requisition['status'] != 'LN') {
return $this->failed('requisition-invalid-status&status=' . $requisition['status'], $context, $company); return $this->failed('requisition-invalid-status&status=' . $requisition['status'], $context, $company);
} }
if (sizeof($requisition["accounts"]) == 0) { if (sizeof($requisition['accounts']) == 0) {
return $this->failed('requisition-no-accounts', $context, $company); return $this->failed('requisition-no-accounts', $context, $company);
} }
// connect new accounts // connect new accounts
$bank_integration_ids = []; $bank_integration_ids = [];
foreach ($requisition["accounts"] as $nordigenAccountId) { foreach ($requisition['accounts'] as $nordigenAccountId) {
$nordigen_account = $nordigen->getAccount($nordigenAccountId); $nordigen_account = $nordigen->getAccount($nordigenAccountId);
if (isset($nordigen_account['error'])) { if (isset($nordigen_account['error'])) {
@ -213,17 +209,17 @@ class NordigenController extends BaseController
// perform update in background // perform update in background
$company->account->bank_integrations $company->account->bank_integrations
->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN) ->where('integration_type', BankIntegration::INTEGRATION_TYPE_NORDIGEN)
->where('auto_sync', true) ->where('auto_sync', true)
->each(function ($bank_integration) { ->each(function ($bank_integration) {
ProcessBankTransactionsNordigen::dispatch($bank_integration); ProcessBankTransactionsNordigen::dispatch($bank_integration);
}); });
// prevent rerun of this method with same ref // prevent rerun of this method with same ref
Cache::delete($data["ref"]); Cache::delete($data['ref']);
// Successfull Response => Redirect // Successfull Response => Redirect
return response()->redirectTo($context["redirect"] . "?action=nordigen_connect&status=success&bank_integrations=" . implode(',', $bank_integration_ids)); return response()->redirectTo($context['redirect'] . '?action=nordigen_connect&status=success&bank_integrations=' . implode(',', $bank_integration_ids));
} }
/** /**
@ -300,7 +296,7 @@ class NordigenController extends BaseController
* ), * ),
* ) * )
*/ */
public function institutions(Request $request) public function institutions(Request $request): JsonResponse
{ {
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key'))) { if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key'))) {
return response()->json(['message' => 'Not yet authenticated with Nordigen Bank Integration service'], 400); return response()->json(['message' => 'Not yet authenticated with Nordigen Bank Integration service'], 400);

View File

@ -21,27 +21,36 @@ class ConfirmNordigenBankIntegrationRequest extends Request
{ {
/** /**
* Determine if the user is authorized to make this request. * Determine if the user is authorized to make this request.
*
* @return bool
*/ */
public function authorize() public function authorize(): bool
{ {
return true; return true;
} }
/** /**
* Get the validation rules that apply to the request. * Get the validation rules that apply to the request.
*
* @return array
*/ */
public function rules() public function rules(): array
{ {
return [ return [
'ref' => 'required|string', // nordigen redirects only with the ref-property 'ref' => 'required|string', // nordigen redirects only with the ref-property
'lang' => 'string', 'lang' => 'string',
]; ];
} }
public function getTokenContent()
/**
* @return array{
* user_id: int,
* company_key: string,
* context: string,
* is_react: bool,
* institution_id: string,
* lang: string,
* redirect: string,
* requisitionId: string
* }
*/
public function getTokenContent(): array
{ {
$input = $this->all(); $input = $this->all();
@ -50,10 +59,12 @@ class ConfirmNordigenBankIntegrationRequest extends Request
return $data; return $data;
} }
public function getCompany() public function getCompany(): Company
{ {
MultiDB::findAndSetDbByCompanyKey($this->getTokenContent()['company_key']); $key = $this->getTokenContent()['company_key'];
return Company::where('company_key', $this->getTokenContent()['company_key'])->firstOrFail(); MultiDB::findAndSetDbByCompanyKey($key);
return Company::where('company_key', $key)->firstOrFail();
} }
} }

View File

@ -21,26 +21,22 @@ class ConnectNordigenBankIntegrationRequest extends Request
{ {
/** /**
* Determine if the user is authorized to make this request. * Determine if the user is authorized to make this request.
*
* @return bool
*/ */
public function authorize() public function authorize(): bool
{ {
return true; return true;
} }
/** /**
* Get the validation rules that apply to the request. * Get the validation rules that apply to the request.
*
* @return array
*/ */
public function rules() public function rules(): array
{ {
return [ return [
]; ];
} }
public function prepareForValidation() public function prepareForValidation(): void
{ {
$input = $this->all(); $input = $this->all();
@ -50,12 +46,24 @@ class ConnectNordigenBankIntegrationRequest extends Request
$input['institution_id'] = $context['institution_id']; $input['institution_id'] = $context['institution_id'];
} }
$input["redirect"] = isset($context["is_react"]) && $context['is_react'] ? config('ninja.react_url') . "/#/settings/bank_accounts" : config('ninja.app_url'); $input['redirect'] = ($context['is_react'] ?? false)
? config('ninja.react_url') . '/#/settings/bank_accounts'
: config('ninja.app_url');
$this->replace($input); $this->replace($input);
} }
public function getTokenContent()
/**
* @return array{
* user_id: int,
* company_key: string,
* context: string,
* is_react: bool,
* institution_id: string,
* requisitionId?: string
* }
*/
public function getTokenContent(): ?array
{ {
if ($this->state) { if ($this->state) {
$this->token = $this->state; $this->token = $this->state;
@ -66,10 +74,12 @@ class ConnectNordigenBankIntegrationRequest extends Request
return $data; return $data;
} }
public function getCompany() public function getCompany(): Company
{ {
MultiDB::findAndSetDbByCompanyKey($this->getTokenContent()['company_key']); $key = $this->getTokenContent()['company_key'];
return Company::where('company_key', $this->getTokenContent()['company_key'])->firstOrFail(); MultiDB::findAndSetDbByCompanyKey($key);
return Company::where('company_key', $key)->firstOrFail();
} }
} }