From b83275aaf634569b636da22f795ddfea4a39b345 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 8 Feb 2023 13:37:52 +0100 Subject: [PATCH] feat(authentication): remove session wrapper for AuthenticationSession --- .../authentication/authentication_cubit.dart | 2 +- .../presentation/features/home/home_page.dart | 7 +- .../extensions/build_context_extension.dart | 84 +++++++++++++++---- ...hentication_firebase_data_source_impl.dart | 27 ++++-- .../authentication_repository_impl.dart | 22 +++-- .../authentication_remote_data_source.dart | 10 +-- .../lib/src/domain/entities/auth_session.dart | 60 +++++++++++++ .../authenticated_change_event.dart} | 22 ++--- .../authentication_change_event.dart | 11 +-- .../reauthenticated_event.dart | 13 +-- .../refreshed_event.dart | 11 +-- .../signed_in_event.dart | 9 +- .../signed_in_from_cache_event.dart | 9 +- .../signed_up_event.dart | 9 +- .../updated_event.dart | 9 +- .../lib/src/domain/entities/entities.dart | 3 +- .../src/domain/entities/session_wrapper.dart | 38 --------- .../authentication_repository.dart | 11 ++- .../builder/authentication_builder.dart | 8 +- .../cubit/authentication_cubit.dart | 74 ++++++++-------- .../cubit/authentication_state.dart | 10 +-- .../edit_account/cubit/mixin/edit_email.dart | 9 +- .../cubit/mixin/edit_password.dart | 9 +- .../cubit/email_verification_cubit.dart | 15 ++-- .../cubit/email_verification_state.dart | 9 +- .../cubit/mixin/sign_in_anonymously.dart | 9 +- .../mixin/sign_in_with_email_password.dart | 9 +- .../cubit/mixin/sign_in_with_google.dart | 9 +- .../mixin/sign_up_with_email_password.dart | 9 +- .../authentication_cubit_test.dart | 18 ++-- .../authentication_state_test.dart | 19 ++--- .../email_verification_cubit_test.dart | 17 +++- 32 files changed, 319 insertions(+), 262 deletions(-) create mode 100644 packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart rename packages/wyatt_authentication_bloc/lib/src/domain/entities/{session.dart => authentication_change_event/authenticated_change_event.dart} (61%) delete mode 100644 packages/wyatt_authentication_bloc/lib/src/domain/entities/session_wrapper.dart diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart index 5f03c2f7..ba34a213 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart @@ -37,7 +37,7 @@ class ExampleAuthenticationCubit extends AuthenticationCubit { } @override - FutureOrResult onSignInFromCache(SessionWrapper wrapper) { + FutureOrResult onSignInFromCache(AuthenticationSession session) { print('onSignInFromCache'); return const Ok(1); diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart index dade25b8..463ea902 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/home/home_page.dart @@ -30,8 +30,7 @@ class HomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text( - 'Home | ${context.account, int>()?.email}'), + title: Text('Home | ${context.watchAccount()?.email}'), actions: [ IconButton( onPressed: () => @@ -44,8 +43,8 @@ class HomePage extends StatelessWidget { child: ListView( children: [ AuthenticationBuilder( - authenticated: (context, sessionWrapper) => Text( - 'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'), + authenticated: (context, session) => Text( + 'Logged as ${session.account?.email} | GeneratedId is ${session.data}'), unauthenticated: (context) => const Text('Not logged (unauthenticated)'), unknown: (context) => const Text('Not logged (unknown)'), diff --git a/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart b/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart index c7753da4..83a4867c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart @@ -17,26 +17,82 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/session.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.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_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart'; /// Extension that helps to quickly access useful resources like wrapper, /// session, account or data. extension BuildContextExtension on BuildContext { - /// Returns session wrapper - SessionWrapper? wrapper, Data>() => - watch().currentSession(); + /// Read session in context from a specific AuthenticationCubit type [T] + AuthenticationSession? + readSessionFrom, Data>() => + read().currentSession(); - /// Returns session - Session? session, Data>() => - watch().currentSession()?.session; + /// Watch session in context from a specific AuthenticationCubit type [T] + AuthenticationSession? + watchSessionFrom, Data>() => + watch().currentSession(); - /// Returns account - Account? account, Data>() => - watch().currentSession()?.session?.account; + /// Read session in context from generic AuthenticationCubit type + AuthenticationSession? readSession() => + read>().currentSession(); - /// Returns associated data - Data? data, Data>() => - watch().currentSession()?.session?.data; + /// Watch session in context from generic AuthenticationCubit type + AuthenticationSession? watchSession() => + watch>().currentSession(); + + /// Read event in context from a specific AuthenticationCubit type [T] + AuthenticationChangeEvent? + readEventFrom, Data>() => + readSessionFrom()?.latestEvent; + + /// Watch event in context from a specific AuthenticationCubit type [T] + AuthenticationChangeEvent? + watchEventFrom, Data>() => + watchSessionFrom()?.latestEvent; + + /// Read event in context from generic AuthenticationCubit type + AuthenticationChangeEvent? readEvent() => + readSession()?.latestEvent; + + /// Watch event in context from generic AuthenticationCubit type + AuthenticationChangeEvent? watchEvent() => + watchSession()?.latestEvent; + + /// Read account in context from a specific AuthenticationCubit type [T] + Account? readAccountFrom, Data>() => + readSessionFrom()?.account; + + /// Watch account in context from a specific AuthenticationCubit type [T] + Account? watchAccountFrom, Data>() => + watchSessionFrom()?.account; + + /// Read account in context from generic AuthenticationCubit type + Account? readAccount() => readSession()?.account; + + /// Watch account in context from generic AuthenticationCubit type + Account? watchAccount() => watchSession()?.account; + + /// Read data in context from a specific AuthenticationCubit type [T] + Data? readDataFrom, Data>() => + readSessionFrom()?.data; + + /// Watch data in context from a specific AuthenticationCubit type [T] + Data? watchDataFrom, Data>() => + watchSessionFrom()?.data; + + /// Read data in context from generic AuthenticationCubit type + Data? readData() => readSession()?.data; + + /// Watch data in context from generic AuthenticationCubit type + Data? watchData() => watchSession()?.data; + + /// Check if user is authenticated from a + /// specific AuthenticationCubit type [T] + bool isAuthenticatedFrom, Data>() => + readEventFrom() is AuthenticatedChangeEvent; + + /// Check if user is authenticated from generic AuthenticationCubit type + bool isAuthenticated() => readEvent() is AuthenticatedChangeEvent; } 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 b2c9d4f2..f745e8cf 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,8 +23,8 @@ 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_authentication_bloc/src/domain/entities/session_wrapper.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; class AuthenticationFirebaseDataSourceImpl @@ -41,7 +41,7 @@ class AuthenticationFirebaseDataSourceImpl _checkForCachedAccount(); } - late StreamController> _sessionStream; + late StreamController> _sessionStream; late StreamController _latestCredentials; final FirebaseAuth _firebaseAuth; @@ -51,8 +51,11 @@ class AuthenticationFirebaseDataSourceImpl final currentUser = _firebaseAuth.currentUser; if (currentUser == null) { - _sessionStream - .add(const SessionWrapper(event: UnknownAuthenticationEvent())); + _sessionStream.add( + const AuthenticationSession( + latestEvent: UnknownAuthenticationEvent(), + ), + ); return; } @@ -62,7 +65,9 @@ class AuthenticationFirebaseDataSourceImpl accessToken: jwt, ); _sessionStream.add( - SessionWrapper(event: SignedInFromCacheEvent(account: currentAccount)), + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: currentAccount), + ), ); return; } @@ -78,19 +83,23 @@ class AuthenticationFirebaseDataSourceImpl return account; } - // Stream related methods =================================================== + // Session related methods =================================================== /// {@macro add_session} @override - void addSession(SessionWrapper wrapper) { - _sessionStream.add(wrapper); + void addSession(AuthenticationSession session) { + _sessionStream.add(session); } /// {@macro session_stream} @override - Stream> sessionStream() => + 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/repositories/authentication_repository_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/authentication_repository_impl.dart index 4d3a3f4e..3b2c8481 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 @@ -18,7 +18,7 @@ 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/session_wrapper.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_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; @@ -73,18 +73,30 @@ class AuthenticationRepositoryImpl @override FormRepository get formRepository => _formRepository; - // Stream related methods =================================================== + // Session related methods =================================================== /// {@macro add_session} @override - void addSession(SessionWrapper wrapper) => - authenticationRemoteDataSource.addSession(wrapper); + void addSession(AuthenticationSession session) => + authenticationRemoteDataSource.addSession(session); /// {@macro session_stream} @override - Stream> sessionStream() => + Stream> sessionStream() => authenticationRemoteDataSource.sessionStream(); + /// {@macro current_session} + @override + FutureOrResult> currentSession() => + Result.tryCatchAsync, AppException, + AppException>( + () async { + final session = await authenticationRemoteDataSource.currentSession(); + return session; + }, + (error) => error, + ); + // SignUp/SignIn methods ==================================================== /// {@macro signup_pwd} 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 6bec3426..91cb2550 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,16 +16,16 @@ 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/session_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; /// Is responsible for abstracting the provenance of the data. abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource { - // Stream related methods =================================================== + // Session related methods =================================================== - void addSession(SessionWrapper wrapper); - - Stream> sessionStream(); + void addSession(AuthenticationSession session); + Stream> sessionStream(); + Future> currentSession(); // SignUp/SignIn methods ==================================================== diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart new file mode 100644 index 00000000..a5a37cf2 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_session.dart @@ -0,0 +1,60 @@ +// 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:equatable/equatable.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; + +/// The [AuthenticationSession] object is used to transport and propagate +/// the last event issued by an authentication state change, a user account +/// if connected, and the associated data. +class AuthenticationSession extends Equatable { + const AuthenticationSession({ + required this.latestEvent, + this.account, + this.data, + }); + + factory AuthenticationSession.fromEvent( + AuthenticationChangeEvent latestEvent, { + Data? data, + }) { + if (latestEvent is AuthenticatedChangeEvent) { + return AuthenticationSession( + latestEvent: latestEvent, + account: latestEvent.account, + data: data, + ); + } + return AuthenticationSession( + latestEvent: latestEvent, + data: data, + ); + } + + final AuthenticationChangeEvent latestEvent; + final Account? account; + final Data? data; + + @override + List get props => [ + latestEvent, + account, + data, + ]; + + @override + bool? get stringify => true; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/session.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authenticated_change_event.dart similarity index 61% rename from packages/wyatt_authentication_bloc/lib/src/domain/entities/session.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authenticated_change_event.dart index 61162ee8..03bb2d50 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/session.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authenticated_change_event.dart @@ -14,23 +14,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:equatable/equatable.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +part of 'authentication_change_event.dart'; + + +/// Represents every event where user is authenticated. +abstract class AuthenticatedChangeEvent extends AuthenticationChangeEvent { + const AuthenticatedChangeEvent({required this.account}); -/// The [Session] object is used to transport and propagate -/// the connected user [Account] and personalized [Data] in the application. -class Session extends Equatable { - const Session({ - required this.account, - this.data, - }); - final Account account; - final Data? data; - - @override - List get props => [account, data]; @override - bool? get stringify => true; + List get props => [account]; } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart index 51d6e511..08312b7c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart @@ -18,15 +18,16 @@ import 'package:equatable/equatable.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +part 'authenticated_change_event.dart'; +part 'deleted_event.dart'; +part 'reauthenticated_event.dart'; +part 'refreshed_event.dart'; part 'signed_in_event.dart'; +part 'signed_in_from_cache_event.dart'; part 'signed_out_event.dart'; part 'signed_up_event.dart'; -part 'refreshed_event.dart'; -part 'reauthenticated_event.dart'; -part 'updated_event.dart'; part 'unknown_authentication_event.dart'; -part 'signed_in_from_cache_event.dart'; -part 'deleted_event.dart'; +part 'updated_event.dart'; /// Represents an event initiated by a change in /// the user's authentication status. diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart index 2ad9c96f..4cd8e13c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart @@ -16,14 +16,9 @@ part of 'authentication_change_event.dart'; -/// When a user re-authenticates (from the logged in state to the -/// logged in state with a different and fresh access +/// When a user re-authenticates (from the logged in state to the +/// logged in state with a different and fresh access /// token and a different login time) -class ReauthenticatedEvent extends AuthenticationChangeEvent { - const ReauthenticatedEvent({required this.account}); - - final Account account; - - @override - List get props => [account]; +class ReauthenticatedEvent extends AuthenticatedChangeEvent { + const ReauthenticatedEvent({required super.account}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart index ce8651d3..e2971cc4 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart @@ -16,13 +16,8 @@ part of 'authentication_change_event.dart'; -/// When a user access token is refreshed (from the logged in state to the +/// When a user access token is refreshed (from the logged in state to the /// logged in state with a different access token) -class RefreshedEvent extends AuthenticationChangeEvent { - const RefreshedEvent({required this.account}); - - final Account account; - - @override - List get props => [account]; +class RefreshedEvent extends AuthenticatedChangeEvent { + const RefreshedEvent({required super.account}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart index 22cd6296..8d2fa0e3 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart @@ -17,11 +17,6 @@ part of 'authentication_change_event.dart'; /// When a user authenticates (from not logged in to logged in). -class SignedInEvent extends AuthenticationChangeEvent { - const SignedInEvent({required this.account}); - - final Account account; - - @override - List get props => [account]; +class SignedInEvent extends AuthenticatedChangeEvent { + const SignedInEvent({required super.account}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart index b32f098a..a4e57dda 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart @@ -17,11 +17,6 @@ part of 'authentication_change_event.dart'; /// When a user authenticates automatically (from not logged in to logged in). -class SignedInFromCacheEvent extends AuthenticationChangeEvent { - const SignedInFromCacheEvent({required this.account}); - - final Account account; - - @override - List get props => [account]; +class SignedInFromCacheEvent extends AuthenticatedChangeEvent { + const SignedInFromCacheEvent({required super.account}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart index 6683e0fa..903adbf1 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart @@ -17,11 +17,6 @@ part of 'authentication_change_event.dart'; /// When a user creates an account. -class SignedUpEvent extends AuthenticationChangeEvent { - const SignedUpEvent({required this.account}); - - final Account account; - - @override - List get props => [account]; +class SignedUpEvent extends AuthenticatedChangeEvent { + const SignedUpEvent({required super.account}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart index f64e6c74..117cc725 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart @@ -17,11 +17,6 @@ part of 'authentication_change_event.dart'; /// When the user's account has been updated. -class UpdatedEvent extends AuthenticationChangeEvent { - const UpdatedEvent({required this.account}); - - final Account account; - - @override - List get props => [account]; +class UpdatedEvent extends AuthenticatedChangeEvent { + const UpdatedEvent({required super.account}); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart index a466a036..a1afb54e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart @@ -15,6 +15,5 @@ // along with this program. If not, see . export 'account.dart'; +export 'auth_session.dart'; export 'authentication_change_event/authentication_change_event.dart'; -export 'session.dart'; -export 'session_wrapper.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/session_wrapper.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/session_wrapper.dart deleted file mode 100644 index 4fa2b924..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/session_wrapper.dart +++ /dev/null @@ -1,38 +0,0 @@ -// 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:equatable/equatable.dart'; -import 'package:wyatt_architecture/wyatt_architecture.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/authentication_change_event/authentication_change_event.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/session.dart'; - -/// Contains the [AuthenticationChangeEvent] initiating the state -/// change and the current [Session]. -class SessionWrapper extends Equatable implements Entity { - const SessionWrapper({ - required this.event, - this.session, - }); - - final AuthenticationChangeEvent event; - final Session? session; - - @override - List get props => [event, session]; - - @override - bool get stringify => true; -} 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 1eb6fc25..ab32e322 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 @@ -16,7 +16,7 @@ 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/session_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; abstract class AuthenticationRepository extends BaseRepository { @@ -30,12 +30,17 @@ abstract class AuthenticationRepository extends BaseRepository { /// {@template add_session} /// Add a new authentication event. /// {@endtemplate} - void addSession(SessionWrapper wrapper); + void addSession(AuthenticationSession session); /// {@template session_stream} /// Authentication state change event stream. /// {@endtemplate} - Stream> sessionStream(); + Stream> sessionStream(); + + /// {@template current_session} + /// Latest session issued by the session stream. + /// {@endtemplate} + FutureOrResult> currentSession(); // SignUp/SignIn methods ==================================================== diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart index 19e77c20..3c9f1999 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/builder/authentication_builder.dart @@ -17,7 +17,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:wyatt_authentication_bloc/src/core/enums/authentication_status.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/auth_session.dart'; import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart'; class AuthenticationBuilder extends StatelessWidget { @@ -30,7 +30,7 @@ class AuthenticationBuilder extends StatelessWidget { final Widget Function( BuildContext context, - SessionWrapper sessionWrapper, + AuthenticationSession session, ) authenticated; final Widget Function(BuildContext context) unauthenticated; final Widget Function(BuildContext context) unknown; @@ -40,8 +40,8 @@ class AuthenticationBuilder extends StatelessWidget { BlocBuilder, AuthenticationState>( builder: (context, state) { if (state.status == AuthenticationStatus.authenticated) { - if (state.wrapper != null) { - return authenticated(context, state.wrapper!); + if (state.session != null) { + return authenticated(context, state.session!); } else { return unauthenticated(context); } 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 c90ab44f..e6748680 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 @@ -42,35 +42,31 @@ abstract class AuthenticationCubit } final AuthenticationRepository authenticationRepository; - SessionWrapper? _latestSession; + AuthenticationSession? _latestSession; void _listenForAuthenticationChanges() { - authenticationRepository.sessionStream().asyncMap((wrapper) async { - final event = wrapper.event; + authenticationRepository.sessionStream().asyncMap((session) async { + final event = session.latestEvent; if (event is SignedInFromCacheEvent) { - final customRoutineResult = await onSignInFromCache(wrapper); + final customRoutineResult = await onSignInFromCache(session); if (customRoutineResult.isOk) { final account = event.account; final sessionData = customRoutineResult.ok; - final signedInSession = SessionWrapper( - event: SignedInFromCacheEvent(account: account), - session: Session( - account: account, - data: sessionData, - ), + final signedInSession = AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: account), + data: sessionData, ); return signedInSession; } } - return wrapper; - }).listen((wrapper) async { - _latestSession = wrapper; - final session = wrapper.session; - if (session != null) { - emit(AuthenticationState.authenticated(wrapper)); + return session; + }).listen((session) async { + _latestSession = session; + if (session.account != null) { + emit(AuthenticationState.authenticated(session)); return; } emit(AuthenticationState.unauthenticated()); @@ -80,19 +76,16 @@ abstract class AuthenticationCubit /// {@macro refresh} FutureOr refresh() async => CustomRoutine( - routine: authenticationRepository.refresh, - attachedLogic: onRefresh, - onError: addError, - onSuccess: (result, data) => authenticationRepository.addSession( - SessionWrapper( - event: RefreshedEvent(account: result), - session: Session( - account: result, + routine: authenticationRepository.refresh, + attachedLogic: onRefresh, + onError: addError, + onSuccess: (result, data) => authenticationRepository.addSession( + AuthenticationSession.fromEvent( + RefreshedEvent(account: result), data: data, ), ), - ), - ).call(); + ).call(); /// {@macro reauthenticate} FutureOr reauthenticate() async => CustomRoutine( @@ -100,12 +93,9 @@ abstract class AuthenticationCubit attachedLogic: onReauthenticate, onError: addError, onSuccess: (result, data) => authenticationRepository.addSession( - SessionWrapper( - event: ReauthenticatedEvent(account: result), - session: Session( - account: result, - data: data, - ), + AuthenticationSession.fromEvent( + ReauthenticatedEvent(account: result), + data: data, ), ), ).call(); @@ -115,8 +105,11 @@ abstract class AuthenticationCubit routine: authenticationRepository.signOut, attachedLogic: (routineResult) => onSignOut(), onError: addError, - onSuccess: (result, data) => authenticationRepository - .addSession(SessionWrapper(event: const SignedOutEvent())), + onSuccess: (result, data) => authenticationRepository.addSession( + const AuthenticationSession( + latestEvent: SignedOutEvent(), + ), + ), ).call(); /// {@macro delete} @@ -124,20 +117,23 @@ abstract class AuthenticationCubit routine: authenticationRepository.delete, attachedLogic: (routineResult) => onDelete(), onError: addError, - onSuccess: (result, data) => authenticationRepository - .addSession(SessionWrapper(event: const DeletedEvent())), + onSuccess: (result, data) => authenticationRepository.addSession( + const AuthenticationSession( + latestEvent: DeletedEvent(), + ), + ), ).call(); - /// Returns latest session wrapper. + /// Returns latest session. /// /// Contains latest event and latest session data (account + extra data) - SessionWrapper? currentSession() => _latestSession; + AuthenticationSession? currentSession() => _latestSession; /// This callback is triggered when the user is automaticcaly logged in from /// the cache. /// /// For example: when the user is sign in from the Firebase cache. - FutureOrResult onSignInFromCache(SessionWrapper wrapper); + FutureOrResult onSignInFromCache(AuthenticationSession session); /// This callback is triggered when the account is refreshed. /// diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart index cf672a4c..1f3a1c72 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/cubit/authentication_state.dart @@ -17,25 +17,25 @@ part of 'authentication_cubit.dart'; class AuthenticationState extends Equatable { - const AuthenticationState._(this.status, this.wrapper); + const AuthenticationState._(this.status, this.session); const AuthenticationState.unauthenticated() : this._(AuthenticationStatus.unauthenticated, null); - const AuthenticationState.authenticated(SessionWrapper sessionWrapper) + const AuthenticationState.authenticated(AuthenticationSession session) : this._( AuthenticationStatus.authenticated, - sessionWrapper, + session, ); const AuthenticationState.unknown() : this._(AuthenticationStatus.unknown, null); final AuthenticationStatus status; - final SessionWrapper? wrapper; + final AuthenticationSession? session; @override - List get props => [status, wrapper]; + List get props => [status, session]; @override bool? get stringify => true; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart index 47aecb30..c755838f 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_email.dart @@ -111,12 +111,9 @@ mixin UpdateEmail on BaseEditAccountCubit { }, onSuccess: (account, data) { authenticationRepository.addSession( - SessionWrapper( - event: UpdatedEvent(account: account), - session: Session( - account: account, - data: data, - ), + AuthenticationSession.fromEvent( + UpdatedEvent(account: account), + data: data, ), ); emit( diff --git a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart index 3b270800..31dcb20d 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/edit_account/cubit/mixin/edit_password.dart @@ -110,12 +110,9 @@ mixin UpdatePassword on BaseEditAccountCubit { }, onSuccess: (account, data) { authenticationRepository.addSession( - SessionWrapper( - event: SignedInEvent(account: account), - session: Session( - account: account, - data: data, - ), + AuthenticationSession.fromEvent( + UpdatedEvent(account: account), + data: data, ), ); emit( diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart index 986b2bc9..56297baa 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_cubit.dart @@ -31,12 +31,13 @@ class EmailVerificationCubit extends Cubit { final AuthenticationRepository authenticationRepository; FutureOr sendEmailVerification() async { - emit(state.copyWith(status: FormStatus.submissionInProgress)); + emit(const EmailVerificationState(status: FormStatus.submissionInProgress)); final response = await authenticationRepository.sendEmailVerification(); emit( response.fold( - (value) => state.copyWith(status: FormStatus.submissionSuccess), - (error) => state.copyWith( + (value) => + const EmailVerificationState(status: FormStatus.submissionSuccess), + (error) => EmailVerificationState( errorMessage: error.message, status: FormStatus.submissionFailure, ), @@ -45,7 +46,7 @@ class EmailVerificationCubit extends Cubit { } FutureOr checkEmailVerification() async { - emit(state.copyWith(status: FormStatus.submissionInProgress)); + emit(const EmailVerificationState(status: FormStatus.submissionInProgress)); final refresh = await authenticationRepository.refresh(); if (refresh.isErr) { @@ -59,11 +60,11 @@ class EmailVerificationCubit extends Cubit { return; } - final wrapper = await authenticationRepository.sessionStream().last; - final currentAccount = wrapper.session?.account; + final session = await authenticationRepository.currentSession(); + final currentAccount = session.ok?.account; if (currentAccount != null) { emit( - state.copyWith( + EmailVerificationState( isVerified: currentAccount.emailVerified, status: FormStatus.submissionSuccess, ), diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart index c78db5b7..aa12191d 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/cubit/email_verification_state.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // @@ -18,16 +17,16 @@ part of 'email_verification_cubit.dart'; class EmailVerificationState extends Equatable { - final FormStatus status; - final bool isVerified; - final String? errorMessage; - const EmailVerificationState({ this.isVerified = false, this.status = FormStatus.pure, this.errorMessage, }); + final FormStatus status; + final bool isVerified; + final String? errorMessage; + EmailVerificationState copyWith({ FormStatus? status, bool? isVerified, diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart index 2adf2f2f..fde28872 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart @@ -63,12 +63,9 @@ mixin SignInAnonymously on BaseSignInCubit { }, onSuccess: (account, data) { authenticationRepository.addSession( - SessionWrapper( - event: SignedInEvent(account: account), - session: Session( - account: account, - data: data, - ), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: data, ), ); emit( diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart index 36e7372b..616cde9b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart @@ -136,12 +136,9 @@ mixin SignInWithEmailPassword on BaseSignInCubit { }, onSuccess: (account, data) { authenticationRepository.addSession( - SessionWrapper( - event: SignedInEvent(account: account), - session: Session( - account: account, - data: data, - ), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: data, ), ); emit( diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart index 458844fe..1d814d19 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/mixin/sign_in_with_google.dart @@ -62,12 +62,9 @@ mixin SignInWithGoogle on BaseSignInCubit { }, onSuccess: (account, data) { authenticationRepository.addSession( - SessionWrapper( - event: SignedInEvent(account: account), - session: Session( - account: account, - data: data, - ), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: data, ), ); emit( diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart index 7c2f39f0..80d56b7b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/mixin/sign_up_with_email_password.dart @@ -126,12 +126,9 @@ mixin SignUpWithEmailPassword on BaseSignUpCubit { }, onSuccess: (account, data) { authenticationRepository.addSession( - SessionWrapper( - event: SignedUpEvent(account: account), - session: Session( - account: account, - data: data, - ), + AuthenticationSession.fromEvent( + SignedUpEvent(account: account), + data: data, ), ); emit( diff --git a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart index af1d17d7..f5c26033 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart @@ -43,7 +43,9 @@ class TestAuthenticationCubit extends AuthenticationCubit { const Ok(null); @override - FutureOrResult onSignInFromCache(SessionWrapper wrapper) async => + FutureOrResult onSignInFromCache( + AuthenticationSession session, + ) async => const Ok(null); @override @@ -53,9 +55,10 @@ class TestAuthenticationCubit extends AuthenticationCubit { void main() { group('AuthenticationCubit', () { final MockAccount account = MockAccount(); - final SessionWrapper wrapper = SessionWrapper( - event: const UnknownAuthenticationEvent(), - session: Session(account: account, data: 10), + final AuthenticationSession session = AuthenticationSession( + latestEvent: const UnknownAuthenticationEvent(), + account: account, + data: 10, ); late AuthenticationRepository authenticationRepository; @@ -80,14 +83,14 @@ void main() { 'emits authenticated when stream contains session', setUp: () { when(() => authenticationRepository.sessionStream()).thenAnswer( - (_) => Stream.fromIterable([wrapper]), + (_) => Stream.fromIterable([session]), ); }, build: () => TestAuthenticationCubit( authenticationRepository: authenticationRepository, ), seed: () => const AuthenticationState.unknown(), - expect: () => [AuthenticationState.authenticated(wrapper)], + expect: () => [AuthenticationState.authenticated(session)], ); blocTest, AuthenticationState>( @@ -95,7 +98,8 @@ void main() { setUp: () { when(() => authenticationRepository.sessionStream()).thenAnswer( (_) => Stream.fromIterable( - [const SessionWrapper(event: SignedOutEvent())],), + [const AuthenticationSession(latestEvent: SignedOutEvent())], + ), ); }, build: () => TestAuthenticationCubit( diff --git a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart index 92bd5258..9566f2f3 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart @@ -27,7 +27,7 @@ void main() { const AuthenticationState state = AuthenticationState.unauthenticated(); expect(state.status, AuthenticationStatus.unauthenticated); - expect(state.wrapper, null); + expect(state.session, null); }); }); @@ -36,13 +36,12 @@ void main() { final MockAccount account = MockAccount(); final AuthenticationState state = AuthenticationState.authenticated( - SessionWrapper( - event: SignedInEvent(account: account), - session: Session(account: account), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), ), ); expect(state.status, AuthenticationStatus.authenticated); - expect(state.wrapper?.session?.account, account); + expect(state.session?.account, account); }); }); @@ -52,14 +51,14 @@ void main() { const String extra = 'AwesomeExtraData'; final AuthenticationState state = AuthenticationState.authenticated( - SessionWrapper( - event: SignedInEvent(account: account), - session: Session(account: account, data: extra), + AuthenticationSession.fromEvent( + SignedInEvent(account: account), + data: extra, ), ); expect(state.status, AuthenticationStatus.authenticated); - expect(state.wrapper?.session?.account, account); - expect(state.wrapper?.session?.data, extra); + expect(state.session?.account, account); + expect(state.session?.data, extra); }); }); }); diff --git a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart index e1000d56..c6b944c5 100644 --- a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_cubit_test.dart @@ -43,13 +43,24 @@ void main() { when(() => authenticationRepository.sessionStream()).thenAnswer( (_) => Stream.fromIterable([ - SessionWrapper( - event: SignedInFromCacheEvent(account: account), - session: Session(account: account, data: 10), + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: account), + data: 10, ) ]), ); + when( + () => authenticationRepository.currentSession(), + ).thenAnswer( + (_) async => Ok( + AuthenticationSession.fromEvent( + SignedInFromCacheEvent(account: account), + data: 10, + ), + ), + ); + when( () => authenticationRepository.refresh(), ).thenAnswer((_) async => Ok(account));