diff --git a/app/Http/Controllers/OpenBanking/AuthorizationController.php b/app/Http/Controllers/OpenBanking/AuthorizationController.php index 47afb3fe..d04f8dde 100644 --- a/app/Http/Controllers/OpenBanking/AuthorizationController.php +++ b/app/Http/Controllers/OpenBanking/AuthorizationController.php @@ -60,6 +60,12 @@ class AuthorizationController extends Controller 'description' => $request->query('error_description'), ]); + auth()->user()->bankingConnections() + ->where('status', BankingConnectionStatus::Pending) + ->latest() + ->first() + ?->delete(); + return redirect()->route('settings.connections.index') ->with('error', $request->query('error_description', 'Authorization was denied or cancelled.')); } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 1bd03533..c138f20d 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -45,6 +45,10 @@ class HandleInertiaRequests extends Middleware return [ ...parent::share($request), + 'flash' => [ + 'success' => $request->session()->get('success'), + 'error' => $request->session()->get('error'), + ], 'name' => config('app.name'), 'appUrl' => config('app.url'), 'version' => json_decode(file_get_contents(base_path('package.json')))->version ?? '0.0.0', diff --git a/resources/js/pages/settings/connections.tsx b/resources/js/pages/settings/connections.tsx index b69f017f..abb623dc 100644 --- a/resources/js/pages/settings/connections.tsx +++ b/resources/js/pages/settings/connections.tsx @@ -25,13 +25,14 @@ import { __ } from '@/utils/i18n'; import { Head, router, usePage, usePoll } from '@inertiajs/react'; import { ArrowRight, MoreHorizontal, RefreshCw, Unplug } from 'lucide-react'; import { useEffect, useState } from 'react'; +import { toast } from 'sonner'; interface Props { connections: BankingConnection[]; } export default function ConnectionsPage({ connections }: Props) { - const { auth } = usePage().props; + const { auth, flash } = usePage().props; const isDemoAccount = auth?.isDemoAccount ?? false; const [connectDialogOpen, setConnectDialogOpen] = useState(false); const [disconnectConnection, setDisconnectConnection] = @@ -43,6 +44,15 @@ export default function ConnectionsPage({ connections }: Props) { const { start, stop } = usePoll(5000, {}, { autoStart: false }); + useEffect(() => { + if (flash?.error) { + toast.error(flash.error); + } + if (flash?.success) { + toast.success(flash.success); + } + }, [flash?.error, flash?.success]); + useEffect(() => { if (hasSyncing) { start(); diff --git a/resources/js/types/index.d.ts b/resources/js/types/index.d.ts index c0dc7f76..b555f25a 100644 --- a/resources/js/types/index.d.ts +++ b/resources/js/types/index.d.ts @@ -45,12 +45,18 @@ export interface Features { 'account-mapping': boolean; } +export interface Flash { + success: string | null; + error: string | null; +} + export interface SharedData { name: string; appUrl: string; version: string; quote: { message: string; author: string }; auth: Auth; + flash: Flash; subscriptionsEnabled: boolean; pricing: PricingConfig; sidebarOpen: boolean; diff --git a/tests/Feature/OpenBanking/AuthorizationControllerTest.php b/tests/Feature/OpenBanking/AuthorizationControllerTest.php index db7c53ac..1a124e63 100644 --- a/tests/Feature/OpenBanking/AuthorizationControllerTest.php +++ b/tests/Feature/OpenBanking/AuthorizationControllerTest.php @@ -57,15 +57,22 @@ test('authorization requires aspsp_name and country', function () { $response->assertJsonValidationErrors(['aspsp_name', 'country']); }); -test('callback with error redirects with error message', function () { +test('callback with error redirects with error message and deletes pending connection', function () { $user = User::factory()->onboarded()->create(); Feature::for($user)->activate('open-banking'); + $connection = BankingConnection::factory()->pending()->create([ + 'user_id' => $user->id, + ]); + $response = $this->actingAs($user) ->get('/open-banking/callback?error=access_denied&error_description=User+denied+access'); $response->assertRedirect(route('settings.connections.index')); - $response->assertSessionHas('error'); + $response->assertSessionHas('error', 'User denied access'); + + $connection->refresh(); + expect($connection->trashed())->toBeTrue(); }); test('callback without code redirects with error', function () {