From 3a7c457f7390678c5d72721b88cbf23dc7508d0e Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 20 Nov 2024 14:08:59 +0100 Subject: [PATCH] feat(account_repository): Allow registering callback to be executed before an account is logged out Signed-off-by: provokateurin --- .../lib/src/account_repository.dart | 22 +++++++++++++++- .../test/account_repository_test.dart | 25 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/neon_framework/packages/account_repository/lib/src/account_repository.dart b/packages/neon_framework/packages/account_repository/lib/src/account_repository.dart index a8bdc465372..f176d25326b 100644 --- a/packages/neon_framework/packages/account_repository/lib/src/account_repository.dart +++ b/packages/neon_framework/packages/account_repository/lib/src/account_repository.dart @@ -14,6 +14,9 @@ import 'package:rxdart/rxdart.dart'; part 'account_storage.dart'; +/// Signature of a callback that executed right before the [account] is logged out. +typedef BeforeLogOutCallback = Future Function(Account account); + /// {@template account_failure} /// A base failure for the account repository failures. /// {@endtemplate} @@ -86,6 +89,7 @@ class AccountRepository { final String _userAgent; final http.Client _httpClient; final AccountStorage _storage; + final List _beforeLogOutCallbacks = []; final BehaviorSubject<({String? active, BuiltMap accounts})> _accounts = BehaviorSubject.seeded((active: null, accounts: BuiltMap())); @@ -272,6 +276,18 @@ class AccountRepository { ]); } + /// Registers a new [callback] that is executed right before an account is logged out. + /// + /// The callback must not throw any exceptions and handle them gracefully itself. + void registerBeforeLogOutCallback(BeforeLogOutCallback callback) { + _beforeLogOutCallbacks.add(callback); + } + + /// Unregisters a [callback] that was previously registered with [registerBeforeLogOutCallback]. + void unregisterBeforeLogOutCallback(BeforeLogOutCallback callback) { + _beforeLogOutCallbacks.remove(callback); + } + /// Logs out the user from the server. /// /// May throw a [DeleteCredentialsFailure]. @@ -299,8 +315,12 @@ class AccountRepository { _accounts.add((active: active, accounts: accounts)); + for (final callback in _beforeLogOutCallbacks) { + await callback(account!); + } + try { - await account?.client.authentication.appPassword.deleteAppPassword(); + await account!.client.authentication.appPassword.deleteAppPassword(); } on http.ClientException catch (error, stackTrace) { Error.throwWithStackTrace(DeleteCredentialsFailure(error), stackTrace); } diff --git a/packages/neon_framework/packages/account_repository/test/account_repository_test.dart b/packages/neon_framework/packages/account_repository/test/account_repository_test.dart index 3a2c0c0a647..af755b49118 100644 --- a/packages/neon_framework/packages/account_repository/test/account_repository_test.dart +++ b/packages/neon_framework/packages/account_repository/test/account_repository_test.dart @@ -40,6 +40,12 @@ class _UsersClientMock extends Mock implements provisioning_api.$UsersClient {} class _AccountStorageMock extends Mock implements AccountStorage {} +class _FakeAccount extends Fake implements Account {} + +class _BeforeLogOutCallbackMock extends Mock { + Future call(Account account); +} + typedef _AccountStream = ({BuiltList accounts, Account? active}); void main() { @@ -54,6 +60,7 @@ void main() { setUpAll(() { registerFallbackValue(_FakeUri()); registerFallbackValue(_FakePollRequest()); + registerFallbackValue(_FakeAccount()); MockNeonStorage(); }); @@ -506,6 +513,20 @@ void main() { when(() => appPassword.deleteAppPassword()).thenAnswer( (_) async => _DynamiteResponseMock(), ); + + final callback1 = _BeforeLogOutCallbackMock(); + when(() => callback1.call(any())).thenAnswer((_) async {}); + repository.registerBeforeLogOutCallback(callback1.call); + + final callback2 = _BeforeLogOutCallbackMock(); + repository + ..registerBeforeLogOutCallback(callback2.call) + ..unregisterBeforeLogOutCallback(callback2.call); + + final callback3 = _BeforeLogOutCallbackMock(); + when(() => callback3.call(any())).thenAnswer((_) async {}); + repository.registerBeforeLogOutCallback(callback3.call); + await repository.logOut(credentialsList.first.id); await expectLater( @@ -517,6 +538,10 @@ void main() { ), ); + verify(() => callback1(accountsList.first)).called(1); + verifyNever(() => callback2(accountsList.first)); + verify(() => callback3(accountsList.first)).called(1); + verify(() => appPassword.deleteAppPassword()).called(1); verify(() => storage.saveLastAccount(credentialsList[1].id)).called(1); verify(() => storage.saveCredentials(any(that: equals([credentialsList[1]])))).called(1);