From d53e7b80da619fb844e6213bc70ba71ba112ccab Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 8 Mar 2023 12:57:24 +0100 Subject: [PATCH] refactor(authentication)!: split data sources (cache, session, external) --- .../src/data/data_sources/data_sources.dart | 3 +- ...ation_firebase_cache_data_source_impl.dart | 56 +++++++++++++++++++ ...thentication_session_data_source_impl.dart | 45 +++++++++++++++ .../src/data/data_sources/local/local.dart | 18 ++++++ ...hentication_firebase_data_source_impl.dart | 53 ++---------------- .../src/data/data_sources/remote/remote.dart | 17 ++++++ .../authentication_repository_impl.dart | 54 +++++++++++++++--- .../src/domain/data_sources/data_sources.dart | 3 +- .../authentication_cache_data_source.dart | 40 +++++++++++++ .../authentication_session_data_source.dart | 36 ++++++++++++ .../src/domain/data_sources/local/local.dart | 18 ++++++ .../authentication_remote_data_source.dart | 40 ++++++++++--- .../domain/data_sources/remote/remote.dart | 17 ++++++ .../authentication_repository.dart | 14 ++++- .../cubit/authentication_cubit.dart | 26 ++++++++- 15 files changed, 371 insertions(+), 69 deletions(-) create mode 100644 packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart create mode 100644 packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart index 65cebddf..843f681b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/data_sources.dart @@ -14,4 +14,5 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'remote/authentication_firebase_data_source_impl.dart'; +export 'local/local.dart'; +export 'remote/remote.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart new file mode 100644 index 00000000..910887c2 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_firebase_cache_data_source_impl.dart @@ -0,0 +1,56 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_cache_data_source.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_firebase_cache_data_source_impl} +/// A data source that manages the cache strategy. +/// This implementation uses Firebase. +/// {@endtemplate} +class AuthenticationFirebaseCacheDataSourceImpl + extends AuthenticationCacheDataSource { + /// {@macro authentication_firebase_cache_data_source_impl} + AuthenticationFirebaseCacheDataSourceImpl({ + FirebaseAuth? firebaseAuth, + }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance; + + final FirebaseAuth _firebaseAuth; + + // Already done by Firebase + @override + Future cacheAccount(Account account) => Future.value(); + + @override + Future getCachedAccount() async { + final currentUser = _firebaseAuth.currentUser; + if (currentUser == null) { + return null; + } + + final jwt = await currentUser.getIdToken(true); + final currentAccount = AccountModel.fromFirebaseUser( + currentUser, + accessToken: jwt, + ); + + return currentAccount; + } + + // Already done by Firebase + @override + Future removeCachedAccount() => Future.value(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart new file mode 100644 index 00000000..1287d889 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_session_data_source_impl.dart @@ -0,0 +1,45 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +import 'dart:async'; + +import 'package:rxdart/subjects.dart'; +import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_session_data_source.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; + +/// {@template authentication_session_data_source_impl} +/// A data source that manages the current session. +/// {@endtemplate} +class AuthenticationSessionDataSourceImpl + extends AuthenticationSessionDataSource { + /// {@macro authentication_session_data_source_impl} + AuthenticationSessionDataSourceImpl(); + + final StreamController> _sessionStream = + BehaviorSubject(); + + @override + void addSession(AuthenticationSession session) { + _sessionStream.add(session); + } + + @override + Future> currentSession() => sessionStream().last; + + @override + Stream> sessionStream() => + _sessionStream.stream.asBroadcastStream(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart new file mode 100644 index 00000000..ba60b5e6 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/local.dart @@ -0,0 +1,18 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +export 'authentication_firebase_cache_data_source_impl.dart'; +export 'authentication_session_data_source_impl.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart index de644d5e..f2552b87 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_firebase_data_source_impl.dart @@ -23,55 +23,27 @@ import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; import 'package:wyatt_authentication_bloc/src/data/models/models.dart'; import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +/// {@template authentication_firebase_data_source_impl} +/// Implementation of [AuthenticationRemoteDataSource] using Firebase. +/// {@endtemplate} class AuthenticationFirebaseDataSourceImpl extends AuthenticationRemoteDataSource { + /// {@macro authentication_firebase_data_source_impl} AuthenticationFirebaseDataSourceImpl({ FirebaseAuth? firebaseAuth, GoogleSignIn? googleSignIn, }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance, _googleSignIn = googleSignIn ?? GoogleSignIn() { _latestCredentials = BehaviorSubject(); - _sessionStream = BehaviorSubject(); - - // Check for account in memory (persistence) - _checkForCachedAccount(); } - late StreamController> _sessionStream; late StreamController _latestCredentials; final FirebaseAuth _firebaseAuth; final GoogleSignIn _googleSignIn; - Future _checkForCachedAccount() async { - final currentUser = _firebaseAuth.currentUser; - - if (currentUser == null) { - _sessionStream.add( - const AuthenticationSession( - latestEvent: UnknownAuthenticationEvent(), - ), - ); - return; - } - - final jwt = await currentUser.getIdToken(true); - final currentAccount = AccountModel.fromFirebaseUser( - currentUser, - accessToken: jwt, - ); - _sessionStream.add( - AuthenticationSession.fromEvent( - SignedInFromCacheEvent(account: currentAccount), - ), - ); - return; - } - Future _addToCredentialStream( UserCredential userCredential, ) async { @@ -87,23 +59,6 @@ class AuthenticationFirebaseDataSourceImpl return account; } - // Session related methods =================================================== - - /// {@macro add_session} - @override - void addSession(AuthenticationSession session) { - _sessionStream.add(session); - } - - /// {@macro session_stream} - @override - Stream> sessionStream() => - _sessionStream.stream.asBroadcastStream(); - - /// {@macro current_session} - @override - Future> currentSession() => sessionStream().last; - // SignUp/SignIn methods ==================================================== /// {@macro signup_pwd} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart new file mode 100644 index 00000000..5a8c8679 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/remote.dart @@ -0,0 +1,17 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +export 'authentication_firebase_data_source_impl.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart index 3b2c8481..652cca7a 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart @@ -16,17 +16,22 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/utils/forms.dart'; -import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; -import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; +import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_cache_data_source.dart'; +import 'package:wyatt_authentication_bloc/src/domain/data_sources/local/authentication_session_data_source.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; +/// {@template authentication_repository_impl} +/// The default implementation of [AuthenticationRepository]. +/// {@endtemplate} class AuthenticationRepositoryImpl extends AuthenticationRepository { + /// {@macro authentication_repository_impl} AuthenticationRepositoryImpl({ required this.authenticationRemoteDataSource, + required this.authenticationCacheDataSource, + required this.authenticationSessionDataSource, FormRepository? formRepository, // ignore: strict_raw_type List? extraSignUpInputs, @@ -66,24 +71,57 @@ class AuthenticationRepositoryImpl ); } + /// The remote data source used to perform the authentication process. final AuthenticationRemoteDataSource authenticationRemoteDataSource; + + /// The cache data source used to cache the current account. + final AuthenticationCacheDataSource authenticationCacheDataSource; + + /// The session data source used to manage the current session. + final AuthenticationSessionDataSource authenticationSessionDataSource; + late FormRepository _formRepository; /// {@macro form_repo} @override FormRepository get formRepository => _formRepository; + // Cache related methods ==================================================== + + /// {@macro check_cache_account} + @override + Future checkForCachedAccount() async { + final cachedAccount = + await authenticationCacheDataSource.getCachedAccount(); + + if (cachedAccount == null) { + addSession( + const AuthenticationSession( + latestEvent: UnknownAuthenticationEvent(), + ), + ); + return; + } + + addSession( + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: cachedAccount), + ), + ); + return; + } + // Session related methods =================================================== /// {@macro add_session} @override void addSession(AuthenticationSession session) => - authenticationRemoteDataSource.addSession(session); + authenticationSessionDataSource.addSession(session); /// {@macro session_stream} @override Stream> sessionStream() => - authenticationRemoteDataSource.sessionStream(); + authenticationSessionDataSource.sessionStream(); /// {@macro current_session} @override @@ -91,7 +129,9 @@ class AuthenticationRepositoryImpl Result.tryCatchAsync, AppException, AppException>( () async { - final session = await authenticationRemoteDataSource.currentSession(); + final session = + await authenticationSessionDataSource.currentSession(); + return session; }, (error) => error, diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart index 4a8f3011..843f681b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/data_sources.dart @@ -14,4 +14,5 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'remote/authentication_remote_data_source.dart'; +export 'local/local.dart'; +export 'remote/remote.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart new file mode 100644 index 00000000..911ec217 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart @@ -0,0 +1,40 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; + +/// {@template authentication_cache_data_source} +/// A data source that manages the cache strategy. +/// {@endtemplate} +abstract class AuthenticationCacheDataSource extends BaseLocalDataSource { + /// {@macro authentication_cache_data_source} + const AuthenticationCacheDataSource(); + + /// Returns the cached account if it exists. + Future getCachedAccount(); + + /// Adds the current account to the cache. + /// + /// If an account is already cached, it will be replaced. + Future cacheAccount(Account account); + + /// Removes the current account from the cache. + /// + /// The cache will be empty after this operation. + /// If no account is cached, nothing will happen. + Future removeCachedAccount(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart new file mode 100644 index 00000000..c24d859a --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_session_data_source.dart @@ -0,0 +1,36 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// {@template authentication_session_data_source} +/// A data source that manages the current session. +/// {@endtemplate} +abstract class AuthenticationSessionDataSource + extends BaseLocalDataSource { + /// {@macro authentication_session_data_source} + const AuthenticationSessionDataSource(); + + /// Adds a new session to the data source. + void addSession(AuthenticationSession session); + + /// Returns a stream of sessions. + Stream> sessionStream(); + + /// Returns the current session. + Future> currentSession(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart new file mode 100644 index 00000000..739d4717 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/local.dart @@ -0,0 +1,18 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +export 'authentication_cache_data_source.dart'; +export 'authentication_session_data_source.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart index 91cb2550..8d9afab5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/authentication_remote_data_source.dart @@ -16,49 +16,71 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; -/// Is responsible for abstracting the provenance of the data. +/// {@template authentication_remote_data_source} +/// A remote data source for authentication. +/// It is responsible for all the external communication with the authentication +/// providers. +/// {@endtemplate} abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource { - // Session related methods =================================================== - - void addSession(AuthenticationSession session); - Stream> sessionStream(); - Future> currentSession(); + /// {@macro authentication_remote_data_source} + const AuthenticationRemoteDataSource(); // SignUp/SignIn methods ==================================================== + /// Sign up with email and password. Future signUpWithEmailAndPassword({ required String email, required String password, }); + /// Sign in with email and password. Future signInWithEmailAndPassword({ required String email, required String password, }); + + /// Sign in anonymously. Future signInAnonymously(); + + /// Sign in with Google. Future signInWithGoogle(); + /// Sign out. Future signOut(); // Account management methods =============================================== - - // Future linkCurrentUserWith(AuthenticationProvider anotherProvider); + + /// Refresh the current account. Future refresh(); + + /// Reauthenticate the current account. Future reauthenticate(); + + /// Update the current account's email. Future updateEmail({required String email}); + + /// Update the current account's password. Future updatePassword({required String password}); + + /// Delete the current account. Future delete(); // Email related stuff ====================================================== + /// Send an email verification. Future sendEmailVerification(); + + /// Send a password reset email. Future sendPasswordResetEmail({required String email}); + + /// Confirm password reset. Future confirmPasswordReset({ required String code, required String newPassword, }); + + /// Verify password reset code. Future verifyPasswordResetCode({required String code}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart new file mode 100644 index 00000000..7d684507 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/remote/remote.dart @@ -0,0 +1,17 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program 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 +// any later version. +// +// This program 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 this program. If not, see . + +export 'authentication_remote_data_source.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart index ab32e322..a4f8769c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/authentication_repository.dart @@ -19,13 +19,25 @@ import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; +/// {@template auth_repo} +/// Authentication repository interface. +/// {@endtemplate} abstract class AuthenticationRepository extends BaseRepository { /// {@template form_repo} /// Form repository used in different authentication cubits/blocs /// {@endtemplate} FormRepository get formRepository; - // Stream related methods =================================================== + // Cache related methods ==================================================== + + /// {@template check_cache_account} + /// Checks if there is a cached account. + /// And if there is, it will sign in the user automatically by + /// emitting an event. + /// {@endtemplate} + Future checkForCachedAccount(); + + // Session related methods =================================================== /// {@template add_session} /// Add a new authentication event. diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart index e6748680..e5abf6ec 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_cubit.dart @@ -27,27 +27,45 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; part 'authentication_state.dart'; +/// {@template authentication_cubit} /// Abstract authentication cubit class needs to be implemented in application. /// /// This cubit is in charge of managing the global authentication state of /// the application. /// /// Its here you can override every callbacks and add your custom logic. +/// {@endtemplate} abstract class AuthenticationCubit extends Cubit> { + /// {@macro authentication_cubit} AuthenticationCubit({ required this.authenticationRepository, }) : super(const AuthenticationState.unknown()) { - _listenForAuthenticationChanges(); + _init(); } + + /// The authentication repository. final AuthenticationRepository authenticationRepository; + /// The latest session. AuthenticationSession? _latestSession; + /// Method that is called when the cubit is initialized. + Future _init() async { + /// Setup listeners. + _listenForAuthenticationChanges(); + + /// Check if there is a cached account. + await authenticationRepository.checkForCachedAccount(); + } + void _listenForAuthenticationChanges() { authenticationRepository.sessionStream().asyncMap((session) async { final event = session.latestEvent; + + /// If the session is signed in from cache. if (event is SignedInFromCacheEvent) { + /// Call the custom routine. final customRoutineResult = await onSignInFromCache(session); if (customRoutineResult.isOk) { @@ -64,12 +82,18 @@ abstract class AuthenticationCubit } return session; }).listen((session) async { + /// Save the latest session. _latestSession = session; + + /// If there is an account: emit authenticated state. if (session.account != null) { emit(AuthenticationState.authenticated(session)); return; } + + /// If there is no account: emit unauthenticated state. emit(AuthenticationState.unauthenticated()); + return; }); }