diff --git a/packages/wyatt_authentication_bloc/example/firebase.json b/packages/wyatt_authentication_bloc/example/firebase.json index cdcf8e18..c8738c2c 100644 --- a/packages/wyatt_authentication_bloc/example/firebase.json +++ b/packages/wyatt_authentication_bloc/example/firebase.json @@ -8,6 +8,7 @@ }, "ui": { "enabled": true - } + }, + "singleProjectMode": true } } diff --git a/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj b/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj index 11d0d0ad..85497888 100644 --- a/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/wyatt_authentication_bloc/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -200,6 +200,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -236,6 +237,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); diff --git a/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart b/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart index 8cf305fd..05ee6358 100644 --- a/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart +++ b/packages/wyatt_authentication_bloc/example/lib/bootstrap.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart index 917131da..d111abaf 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_field.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart index b41b7335..1ff68488 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/constants/form_name.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart b/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart index 2528fa87..1490523f 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/dependency_injection/get_it.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,49 +14,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:example_router/bootstrap.dart'; import 'package:example_router/firebase_options.dart'; import 'package:get_it/get_it.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -import 'package:wyatt_type_utils/wyatt_type_utils.dart'; final getIt = GetIt.I; abstract class GetItInitializer { static Future init() async { - getIt - ..registerLazySingleton( - MockSettings.isEnable() - ? () => AuthenticationMockDataSourceImpl(registeredAccounts: [ - Pair( - AccountModel( - uid: '1', - emailVerified: true, - isAnonymous: false, - providerId: 'wyatt', - email: 'toto@test.fr', - ), - 'toto1234', - ), - Pair( - AccountModel( - uid: '2', - emailVerified: false, - isAnonymous: false, - providerId: 'wyatt', - email: 'tata@test.fr', - ), - 'tata1234', - ), - ]) - : () => AuthenticationFirebaseDataSourceImpl( - firebaseAuth: FirebaseAuth.instance, - googleSignIn: GoogleSignIn( - clientId: DefaultFirebaseOptions.ios.iosClientId)), - ) - ..registerLazySingleton>( - () => AuthenticationCacheDataSourceImpl(), - ); + getIt.registerLazySingleton>( + () => AuthenticationFirebaseDataSourceImpl( + firebaseAuth: FirebaseAuth.instance, + googleSignIn: + GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)), + ); await getIt.allReady(); } diff --git a/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart b/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart index 657d3917..51297a01 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/routes/router.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:example_router/presentation/features/edit_profile/edit_profile_page.dart'; import 'package:example_router/presentation/features/home/home_page.dart'; import 'package:example_router/presentation/features/sign_in/sign_in_page.dart'; import 'package:example_router/presentation/features/sign_up/sign_up_page.dart'; @@ -83,14 +82,5 @@ class AppRouter { const SubPage(), ), ), - GoRoute( - path: '/home/edit', - name: EditProfilePage.pageName, - pageBuilder: (context, state) => defaultTransition( - context, - state, - const EditProfilePage(), - ), - ), ]; } diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart index 1a25acfd..abc209cb 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/app_bloc_observer.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart index d80b6d3e..a7e1c7c8 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/custom_password.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart b/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart index abfc6857..49fdfa9a 100644 --- a/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart +++ b/packages/wyatt_authentication_bloc/example/lib/core/utils/forms.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/main.dart b/packages/wyatt_authentication_bloc/example/lib/main.dart index ddc4cb52..a7967932 100644 --- a/packages/wyatt_authentication_bloc/example/lib/main.dart +++ b/packages/wyatt_authentication_bloc/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/main_firebase.dart b/packages/wyatt_authentication_bloc/example/lib/main_firebase.dart index d53f0050..62ee35ec 100644 --- a/packages/wyatt_authentication_bloc/example/lib/main_firebase.dart +++ b/packages/wyatt_authentication_bloc/example/lib/main_firebase.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart index 9fa89f49..1264aa73 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/app/app.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,41 +15,39 @@ // along with this program. If not, see . import 'dart:async'; -import 'dart:math'; import 'package:example_router/core/constants/form_field.dart'; import 'package:example_router/core/dependency_injection/get_it.dart'; import 'package:example_router/core/routes/router.dart'; import 'package:example_router/core/utils/custom_password.dart'; import 'package:example_router/core/utils/forms.dart'; +import 'package:example_router/presentation/features/authentication/authentication_cubit.dart'; +import 'package:example_router/presentation/features/sign_in/blocs/custom_sign_in_cubit.dart'; import 'package:example_router/presentation/features/sign_up/blocs/custom_sign_up_cubit.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; -import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -FutureOrResult onAccountChanges( - AuthenticationRepository repo, - AuthChangeEvent? authEvent, -) async { - final id = Random().nextInt(1000); - final token = - await repo.getIdentityToken().fold((value) => value, (error) => 'null'); +// FutureOrResult onAccountChanges( +// AuthenticationRepository repo, +// AuthChangeEvent? authEvent, +// ) async { +// final id = Random().nextInt(1000); +// final token = +// await repo.getIdentityToken().fold((value) => value, (error) => 'null'); - debugPrint( - 'onAccountChanges: ${authEvent?.account}, type: ${authEvent.runtimeType}, token: $token, generatedId: $id'); - return Ok(id); -} +// debugPrint( +// 'onAccountChanges: ${authEvent?.account}, type: ${authEvent.runtimeType}, token: $token, generatedId: $id'); +// return Ok(id); +// } class App extends StatelessWidget { final AuthenticationRepository authenticationRepository = AuthenticationRepositoryImpl( - authenticationCacheDataSource: getIt>(), - authenticationRemoteDataSource: getIt(), - onAuthChange: onAccountChanges, + authenticationRemoteDataSource: + getIt>(), customPasswordValidator: const CustomPassword.pure(), extraSignUpInputs: [ FormInput( @@ -66,8 +64,7 @@ class App extends StatelessWidget { Widget build(BuildContext context) { AuthenticationState? previous; - final AuthenticationCubit authenticationCubit = - AuthenticationCubit(authenticationRepository: authenticationRepository); + final AuthenticationCubit authenticationCubit = ExampleAuthenticationCubit(authenticationRepository: authenticationRepository); final GoRouter router = GoRouter( initialLocation: '/', @@ -119,7 +116,7 @@ class App extends StatelessWidget { ), ), BlocProvider>( - create: (_) => SignInCubit( + create: (_) => CustomSignInCubit( authenticationRepository: authenticationRepository, ), ), diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_cache_data_source_impl.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart similarity index 50% rename from packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_cache_data_source_impl.dart rename to packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart index abcb673a..869be269 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/local/authentication_cache_data_source_impl.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/authentication/authentication_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,49 +18,35 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -class AuthenticationCacheDataSourceImpl - extends AuthenticationCacheDataSource { - AuthenticationCacheDataSourceImpl(); - Account? _account; - T? _data; +class ExampleAuthenticationCubit extends AuthenticationCubit { + ExampleAuthenticationCubit({required super.authenticationRepository}); @override - Future storeAccount(Account? account) async { - _account = account; + FutureOrResult onReauthenticate( + Result result) async { + print('onReauthenticate'); + + return const Ok(1); } @override - Future storeData(T? data) async { - _data = data; + FutureOrResult onRefresh(Result result) { + print('onRefresh'); + + return const Ok(1); } @override - Future loadAccount() async { - if (_account.isNotNull) { - return _account!; - } - throw ClientException('Cached account is invalid'); + FutureOrResult onSignInFromCache(SessionWrapper wrapper) { + print('onSignInFromCache'); + + return const Ok(1); } @override - Future loadData() async { - if (_data.isNotNull) { - return _data!; - } - throw ClientException('Cached data is invalid'); - } + FutureOrResult onSignOut() { + print('onSignOut'); - @override - Future destroy() async { - _data = null; - _account = null; - } - - @override - Future> load() async { - if (_account.isNull) { - throw ClientException('Cached account is invalid'); - } - return AccountWrapperModel(_account, _data); + return const Ok(null); } } diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart deleted file mode 100644 index c92aa597..00000000 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/blocs/edit_profile_cubit.dart +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2022 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:example_router/core/constants/form_field.dart'; -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -import 'package:wyatt_type_utils/wyatt_type_utils.dart'; - -class EditProfileCubit extends FormDataCubitImpl { - final AuthenticationRepository authenticationRepository; - - EditProfileCubit( - super._formRepository, - super._formName, { - required this.authenticationRepository, - }) : super(); - - @override - Future submit() async { - emit( - state.copyWith( - status: FormStatus.submissionInProgress, - ), - ); - final user = (await authenticationRepository.getAccount()).ok; - - final form = state.form; - final email = form.valueOf(AuthFormField.email); - final oldPassword = form.valueOf(AppFormField.oldPassword); - final newPassword = form.valueOf(AuthFormField.password); - - if (email.isNullOrEmpty || - oldPassword.isNullOrEmpty || - newPassword.isNullOrEmpty) { - emit( - state.copyWith( - errorMessage: 'An error occured while retrieving data from the form.', - status: FormStatus.submissionFailure, - ), - ); - } - - try { - // await authenticationRepository.signInWithEmailAndPassword( - // email: user?.email ?? '', - // password: oldPassword ?? '', - // ); - // await authenticationRepository.reauthenticateWithCredential(); - await authenticationRepository.updateEmail(email: email!); - await authenticationRepository.updatePassword(password: newPassword!); - } on Exception catch (e) { - emit( - state.copyWith( - status: FormStatus.submissionFailure, - errorMessage: e.toString(), - ), - ); - } - emit(state.copyWith(status: FormStatus.submissionSuccess)); - } -} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart deleted file mode 100644 index a557d338..00000000 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/edit_profile_page.dart +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2022 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:example_router/core/constants/form_name.dart'; -import 'package:example_router/presentation/features/edit_profile/blocs/edit_profile_cubit.dart'; -import 'package:example_router/presentation/features/edit_profile/widgets/edit_profile_form.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; - -class EditProfilePage extends StatelessWidget { - const EditProfilePage({Key? key}) : super(key: key); - - static String pageName = 'EditProfile'; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Edit Profile')), - body: Padding( - padding: const EdgeInsets.all(8), - child: SingleChildScrollView( - child: BlocProvider( - create: (context) => EditProfileCubit( - context.read(), - AppFormName.editProfile, - authenticationRepository: - context.read>(), - )..dataChanged( - AuthFormField.email, - Email.dirty( - context - .read>() - .state - .accountWrapper - ?.account - ?.email ?? - '', - ), - ), - child: const EditProfileForm(), - ), - ), - ), - ); - } -} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart deleted file mode 100644 index 726e51a4..00000000 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/edit_profile/widgets/edit_profile_form.dart +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) 2022 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:example_router/core/constants/form_field.dart'; -import 'package:example_router/core/utils/custom_password.dart'; -import 'package:example_router/presentation/features/edit_profile/blocs/edit_profile_cubit.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; - -class _EmailInput extends StatelessWidget { - @override - Widget build(BuildContext context) { - return InputBuilderTextController( - field: AuthFormField.email, - builder: ((context, cubit, state, field, input, controller, extra) { - return TextField( - onChanged: (email) => cubit.dataChanged( - AuthFormField.email, Email.dirty(email)), - keyboardType: TextInputType.emailAddress, - controller: controller, - decoration: InputDecoration( - labelText: 'Email', - helperText: '', - errorText: input.validator.invalid ? 'Invalid email' : null, - ), - ); - }), - ); - } -} - -class _OldPasswordInput extends StatelessWidget { - @override - Widget build(BuildContext context) { - return InputBuilder( - field: AppFormField.oldPassword, - builder: ((context, cubit, state, field, input) { - return TextField( - onChanged: (pwd) => cubit.dataChanged( - AppFormField.oldPassword, CustomPassword.dirty(pwd)), - obscureText: true, - decoration: InputDecoration( - labelText: 'Old Password', - helperText: '', - errorText: input.validator.invalid ? 'Invalid password' : null, - ), - ); - }), - ); - } -} - -class _NewPasswordInput extends StatelessWidget { - @override - Widget build(BuildContext context) { - return InputBuilder( - field: AuthFormField.password, - builder: ((context, cubit, state, field, input) { - return TextField( - onChanged: (pwd) => cubit.dataChanged( - AuthFormField.password, CustomPassword.dirty(pwd)), - obscureText: true, - decoration: InputDecoration( - labelText: 'New Password', - helperText: '', - errorText: input.validator.invalid ? 'Invalid password' : null, - ), - ); - }), - ); - } -} - -class _EditButton extends StatelessWidget { - @override - Widget build(BuildContext context) { - return SubmitBuilder( - builder: ((context, cubit, status) { - return status.isSubmissionInProgress - ? const CircularProgressIndicator() - : ElevatedButton( - onPressed: status.isValidated ? () => cubit.submit() : null, - child: const Text('Edit profile'), - ); - }), - ); - } -} - -class EditProfileForm extends StatelessWidget { - const EditProfileForm({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return BlocListener( - listener: (context, state) { - if (state.status == FormStatus.submissionFailure) { - ScaffoldMessenger.of(context) - ..hideCurrentSnackBar() - ..showSnackBar( - SnackBar(content: Text(state.errorMessage ?? 'Edit Failure')), - ); - } - }, - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _EmailInput(), - const SizedBox(height: 8), - _OldPasswordInput(), - const SizedBox(height: 8), - _NewPasswordInput(), - const SizedBox(height: 16), - _EditButton(), - ], - ), - ), - ); - } -} 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 a015690b..a66a38a0 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'package:example_router/presentation/features/edit_profile/edit_profile_page.dart'; import 'package:example_router/presentation/features/sub/sub_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -30,7 +29,7 @@ class HomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Home'), + title: Text('Home | ${context.account, int>()?.email}'), actions: [ IconButton( onPressed: () => @@ -44,8 +43,8 @@ class HomePage extends StatelessWidget { child: Column( children: [ AuthenticationBuilder( - authenticated: (context, accountWrapper) => Text( - 'Logged as ${accountWrapper.account?.email} | GeneratedId is ${accountWrapper.data}'), + authenticated: (context, sessionWrapper) => Text( + 'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'), unauthenticated: (context) => const Text('Not logged (unauthenticated)'), unknown: (context) => const Text('Not logged (unknown)'), @@ -57,10 +56,10 @@ class HomePage extends StatelessWidget { onPressed: () => context.pushNamed(SubPage.pageName), child: const Text('Go to sub page'), ), - ElevatedButton( - onPressed: () => context.pushNamed(EditProfilePage.pageName), - child: const Text('Go to edit profile page'), - ), + // ElevatedButton( + // onPressed: () => context.pushNamed(EditProfilePage.pageName), + // child: const Text('Go to edit profile page'), + // ), ], ), ), diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/blocs/custom_sign_in_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/blocs/custom_sign_in_cubit.dart new file mode 100644 index 00000000..882cfd35 --- /dev/null +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/blocs/custom_sign_in_cubit.dart @@ -0,0 +1,48 @@ +// 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/src/domain/usecases/usecase.dart'; +import 'package:wyatt_architecture/src/core/exceptions/exceptions.dart'; +import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +import 'package:wyatt_type_utils/src/either/either_base.dart'; +import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart'; + +class CustomSignInCubit extends SignInCubit { + CustomSignInCubit({ + required super.authenticationRepository, + }); + + @override + FutureOrResult onSignInWithEmailAndPassword(Result result, WyattForm form) { + print('onSignInWithEmailAndPassword'); + + return const Ok(1); + } + + @override + FutureOrResult onSignInAnonymously(Result result, WyattForm form) { + print('onSignInAnonymously'); + + return const Ok(1); + } + + @override + FutureOrResult onSignInWithGoogle(Result result, WyattForm form) { + print('onSignInWithGoogle'); + + return const Ok(1); + } +} diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart index 19dfd0b6..5ac3770b 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/sign_in_page.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart index f0e1dfa9..bf39991c 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_in/widgets/sign_in_form.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/blocs/custom_sign_up_cubit.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/blocs/custom_sign_up_cubit.dart index 7e5f1e6d..d49e6056 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/blocs/custom_sign_up_cubit.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/blocs/custom_sign_up_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,33 +14,34 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'dart:async'; -import 'package:example_router/core/constants/form_field.dart'; -import 'package:flutter/foundation.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -class CustomSignUpCubit extends SignUpCubit{ +class CustomSignUpCubit extends SignUpCubit { CustomSignUpCubit({ required super.authenticationRepository, }); - + @override - FutureOrResult onSignUpWithEmailAndPassword( - Result result, WyattForm form) async { - if (result.isOk) { - await Future.delayed(const Duration(seconds: 3)); - const id = -1; - final confirmedPassword = - form.valueOf(AppFormField.confirmedPassword); + FutureOrResult onSignUpWithEmailAndPassword(Result result, WyattForm form) async { + // if (result.isOk) { + // await Future.delayed(const Duration(seconds: 3)); + // const id = -1; + // final confirmedPassword = + // form.valueOf(AppFormField.confirmedPassword); - debugPrint( - 'onSignUpSuccess: ${result.ok}, generatedId: $id, intFormData: $confirmedPassword'); - return const Ok(id); - } - return const Ok(null); + // debugPrint( + // 'onSignUpSuccess: ${result.ok}, generatedId: $id, intFormData: $confirmedPassword'); + // return const Ok(id); + // } + // return const Ok(null); + print('onSignUpWithEmailAndPassword'); + + return const Ok(1); } + + } diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart index ff232348..2f0f6ce5 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/sign_up_page.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart index a4f44a48..23b9884d 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sign_up/widgets/sign_up_form.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart index a5c8a6b6..9cdfad53 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/sub/sub_page.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart b/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart index 10d5c0cc..29e97aa4 100644 --- a/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart +++ b/packages/wyatt_authentication_bloc/example/lib/presentation/features/welcome/welcome_page.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart index 295cfc2f..aa1ed36a 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_field.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,7 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Default authentication form fields name abstract class AuthFormField { + /// Email field: `wyattEmailField` static const email = 'wyattEmailField'; + /// Password field: `wyattPasswordField` static const password = 'wyattPasswordField'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart index af623e70..3eca89e0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/constants/form_name.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,8 +14,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Default authentication form name abstract class AuthFormName { + /// Sign Up form: `wyattSignUpForm` static const String signUpForm = 'wyattSignUpForm'; + /// Sign In form: `wyattSignInForm` static const String signInForm = 'wyattSignInForm'; + /// Password reset form: `wyattPasswordResetForm` static const String passwordResetForm = 'wyattPasswordResetForm'; } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/core.dart b/packages/wyatt_authentication_bloc/lib/src/core/core.dart index 2d4165fc..da22baa1 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/core.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/core.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,3 +18,5 @@ export 'constants/form_field.dart'; export 'constants/form_name.dart'; export 'enums/enums.dart'; export 'exceptions/exceptions.dart'; +export 'extensions/build_context_extension.dart'; +export 'utils/custom_routine.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart b/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart index 11386588..b88a7407 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/enums/authentication_status.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,8 +14,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +/// Different authentication status enum AuthenticationStatus { + /// At the application launch. unknown, + /// When the user is logged authenticated, + /// When the user is not logged unauthenticated, } diff --git a/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart b/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart index db37d714..de021091 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/enums/enums.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart index f60c915e..e10faebe 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ import 'package:wyatt_architecture/wyatt_architecture.dart'; part 'exceptions_firebase.dart'; +/// Base exception used in Wyatt Authentication abstract class AuthenticationFailureInterface extends AppException implements Exception { AuthenticationFailureInterface(this.code, this.msg); @@ -249,13 +250,9 @@ abstract class SignOutFailureInterface extends AuthenticationFailureInterface { SignOutFailureInterface.fromCode(super.code) : super.fromCode(); } -abstract class GetIdTokenFailureInterface - extends AuthenticationFailureInterface { - GetIdTokenFailureInterface(super.code, super.msg); - - GetIdTokenFailureInterface.fromCode(super.code) : super.fromCode(); -} - +/// {@template reauthenticate_failure} +/// Thrown during the reauthentication process if a failure occurs. +/// {@endtemplate} abstract class ReauthenticateFailureInterface extends AuthenticationFailureInterface { ReauthenticateFailureInterface(super.code, super.msg); @@ -263,6 +260,9 @@ abstract class ReauthenticateFailureInterface ReauthenticateFailureInterface.fromCode(super.code) : super.fromCode(); } +/// {@template update_email_failure} +/// Thrown during the email modification process if a failure occurs. +/// {@endtemplate} abstract class UpdateEmailFailureInterface extends AuthenticationFailureInterface { UpdateEmailFailureInterface(super.code, super.msg); @@ -270,6 +270,9 @@ abstract class UpdateEmailFailureInterface UpdateEmailFailureInterface.fromCode(super.code) : super.fromCode(); } +/// {@template update_password_failure} +/// Thrown during the password modification process if a failure occurs. +/// {@endtemplate} abstract class UpdatePasswordFailureInterface extends AuthenticationFailureInterface { UpdatePasswordFailureInterface(super.code, super.msg); @@ -277,9 +280,22 @@ abstract class UpdatePasswordFailureInterface UpdatePasswordFailureInterface.fromCode(super.code) : super.fromCode(); } +/// {@template model_parsing_failure} +/// Thrown during the model parsing process if a failure occurs. +/// {@endtemplate} abstract class ModelParsingFailureInterface extends AuthenticationFailureInterface { ModelParsingFailureInterface(super.code, super.msg); ModelParsingFailureInterface.fromCode(super.code) : super.fromCode(); } + +/// {@template delete_account_failure} +/// Thrown during the account deletion if a failure occurs. +/// {@endtemplate} +abstract class DeleteAccountFailureInterface + extends AuthenticationFailureInterface { + DeleteAccountFailureInterface(super.code, super.msg); + + DeleteAccountFailureInterface.fromCode(super.code) : super.fromCode(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart index 58e3c409..7b17e606 100644 --- a/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart +++ b/packages/wyatt_authentication_bloc/lib/src/core/exceptions/exceptions_firebase.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ part of 'exceptions.dart'; +/// {@macro apply_action_code_failure} class ApplyActionCodeFailureFirebase extends ApplyActionCodeFailureInterface { ApplyActionCodeFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -41,6 +42,7 @@ class ApplyActionCodeFailureFirebase extends ApplyActionCodeFailureInterface { } } +/// {@macro sign_up_with_email_and_password_failure} class SignUpWithEmailAndPasswordFailureFirebase extends SignUpWithEmailAndPasswordFailureInterface { SignUpWithEmailAndPasswordFailureFirebase([String? code, String? msg]) @@ -70,6 +72,7 @@ class SignUpWithEmailAndPasswordFailureFirebase } } +/// {@macro fetch_sign_in_methods_failure} class FetchSignInMethodsForEmailFailureFirebase extends FetchSignInMethodsForEmailFailureInterface { FetchSignInMethodsForEmailFailureFirebase([String? code, String? msg]) @@ -87,6 +90,7 @@ class FetchSignInMethodsForEmailFailureFirebase } } +/// {@macro sign_in_anonymously_failure} class SignInAnonymouslyFailureFirebase extends SignInAnonymouslyFailureInterface { SignInAnonymouslyFailureFirebase([String? code, String? msg]) @@ -104,6 +108,7 @@ class SignInAnonymouslyFailureFirebase } } +/// {@macro sign_in_with_credential_failure} class SignInWithCredentialFailureFirebase extends SignInWithCredentialFailureInterface { SignInWithCredentialFailureFirebase([String? code, String? msg]) @@ -142,6 +147,7 @@ class SignInWithCredentialFailureFirebase } } +/// {@macro sign_in_with_google_failure} class SignInWithGoogleFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithGoogleFailureInterface { @@ -149,6 +155,7 @@ class SignInWithGoogleFailureFirebase SignInWithGoogleFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_facebook_failure} class SignInWithFacebookFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithFacebookFailureInterface { @@ -156,12 +163,14 @@ class SignInWithFacebookFailureFirebase SignInWithFacebookFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_apple_failure} class SignInWithAppleFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithAppleFailureInterface { SignInWithAppleFailureFirebase([super.code, super.msg]); SignInWithAppleFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_twitter_failure} class SignInWithTwitterFailureFirebase extends SignInWithCredentialFailureFirebase implements SignInWithAppleFailureInterface { @@ -169,6 +178,7 @@ class SignInWithTwitterFailureFirebase SignInWithTwitterFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_in_with_email_link_failure} class SignInWithEmailLinkFailureFirebase extends SignInWithEmailLinkFailureInterface { SignInWithEmailLinkFailureFirebase([String? code, String? msg]) @@ -192,6 +202,7 @@ class SignInWithEmailLinkFailureFirebase } } +/// {@macro sign_in_with_email_and_password_failure} class SignInWithEmailAndPasswordFailureFirebase extends SignInWithEmailAndPasswordFailureInterface { SignInWithEmailAndPasswordFailureFirebase([String? code, String? msg]) @@ -218,6 +229,7 @@ class SignInWithEmailAndPasswordFailureFirebase } } +/// {@macro send_email_verification_failure} class SendEmailVerificationFailureFirebase extends SendEmailVerificationFailureInterface { SendEmailVerificationFailureFirebase([String? code, String? msg]) @@ -226,6 +238,7 @@ class SendEmailVerificationFailureFirebase SendEmailVerificationFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro send_password_reset_email_failure} class SendPasswordResetEmailFailureFirebase extends SendPasswordResetEmailFailureInterface { SendPasswordResetEmailFailureFirebase([String? code, String? msg]) @@ -233,6 +246,7 @@ class SendPasswordResetEmailFailureFirebase SendPasswordResetEmailFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro send_sign_in_link_email_failure} class SendSignInLinkEmailFailureFirebase extends SendSignInLinkEmailFailureInterface { SendSignInLinkEmailFailureFirebase([String? code, String? msg]) @@ -241,6 +255,7 @@ class SendSignInLinkEmailFailureFirebase SendSignInLinkEmailFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro confirm_password_reset_failure} class ConfirmPasswordResetFailureFirebase extends ConfirmPasswordResetFailureInterface { ConfirmPasswordResetFailureFirebase([String? code, String? msg]) @@ -249,6 +264,7 @@ class ConfirmPasswordResetFailureFirebase ConfirmPasswordResetFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro verify_password_reset_code_failure} class VerifyPasswordResetCodeFailureFirebase extends VerifyPasswordResetCodeFailureInterface { VerifyPasswordResetCodeFailureFirebase([String? code, String? msg]) @@ -258,12 +274,14 @@ class VerifyPasswordResetCodeFailureFirebase : super.fromCode(); } +/// {@macro refresh_failure} class RefreshFailureFirebase extends RefreshFailureInterface { RefreshFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); RefreshFailureFirebase.fromCode(super.code) : super.fromCode(); } +/// {@macro sign_out_failure} class SignOutFailureFirebase extends SignOutFailureInterface { SignOutFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -271,13 +289,7 @@ class SignOutFailureFirebase extends SignOutFailureInterface { SignOutFailureFirebase.fromCode(super.code) : super.fromCode(); } -class GetIdTokenFailureFirebase extends GetIdTokenFailureInterface { - GetIdTokenFailureFirebase([String? code, String? msg]) - : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); - - GetIdTokenFailureFirebase.fromCode(super.code) : super.fromCode(); -} - +/// {@macro reauthenticate_failure} class ReauthenticateFailureFirebase extends ReauthenticateFailureInterface { ReauthenticateFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -311,6 +323,7 @@ class ReauthenticateFailureFirebase extends ReauthenticateFailureInterface { } } +/// {@macro update_email_failure} class UpdateEmailFailureFirebase extends UpdateEmailFailureInterface { UpdateEmailFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -332,6 +345,7 @@ class UpdateEmailFailureFirebase extends UpdateEmailFailureInterface { } } +/// {@macro update_password_failure} class UpdatePasswordFailureFirebase extends UpdatePasswordFailureInterface { UpdatePasswordFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); @@ -350,9 +364,27 @@ class UpdatePasswordFailureFirebase extends UpdatePasswordFailureInterface { } } +/// {@macro model_parsing_failure} class ModelParsingFailureFirebase extends ModelParsingFailureInterface { ModelParsingFailureFirebase([String? code, String? msg]) : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); ModelParsingFailureFirebase.fromCode(super.code) : super.fromCode(); } + +/// {@macro delete_account_failure} +class DeleteAccountFailureFirebase extends DeleteAccountFailureInterface { + DeleteAccountFailureFirebase([String? code, String? msg]) + : super(code ?? 'unknown', msg ?? 'An unknown error occurred.'); + + DeleteAccountFailureFirebase.fromCode(String code) : super.fromCode(code) { + switch (code) { + case 'requires-recent-login': + msg = "User's last sign-in time does not meet the security threshold."; + break; + default: + this.code = 'unknown'; + msg = 'An unknown error occurred.'; + } + } +} 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 new file mode 100644 index 00000000..c7753da4 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/extensions/build_context_extension.dart @@ -0,0 +1,42 @@ +// 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: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/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(); + + /// Returns session + Session? session, Data>() => + watch().currentSession()?.session; + + /// Returns account + Account? account, Data>() => + watch().currentSession()?.session?.account; + + /// Returns associated data + Data? data, Data>() => + watch().currentSession()?.session?.data; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/core/utils/custom_routine.dart b/packages/wyatt_authentication_bloc/lib/src/core/utils/custom_routine.dart new file mode 100644 index 00000000..db8b4265 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/core/utils/custom_routine.dart @@ -0,0 +1,62 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// 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:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_type_utils/wyatt_type_utils.dart'; + +/// Calls on each cubit action of this package. +/// +/// Useful to register custom logic on pre-implemented logic. +class CustomRoutine { + const CustomRoutine({ + required this.routine, + required this.attachedLogic, + required this.onError, + required this.onSuccess, + }); + + final FutureOr> Function() routine; + final FutureOr> Function( + Result routineResult, + ) attachedLogic; + final void Function(AppException? exception) onError; + final void Function(R result, Data? data) onSuccess; + + FutureOr call() async { + final result = await routine.call(); + + // Call custom logic + final customRoutineResult = await attachedLogic.call(result); + + // Check for errors + if (result.isErr) { + onError.call(result.err); + + return; + } + if (customRoutineResult.isErr) { + onError.call(customRoutineResult.err); + + return; + } + + // If no error + return onSuccess.call(result.ok as Input, customRoutineResult.ok); + } +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data.dart b/packages/wyatt_authentication_bloc/lib/src/data/data.dart index 35d3fdd1..581cd9c5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/data.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/data.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 24eff56f..65cebddf 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,6 +14,4 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'local/authentication_cache_data_source_impl.dart'; export 'remote/authentication_firebase_data_source_impl.dart'; -export 'remote/authentication_mock_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 5bc23a2d..2d75d36a 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,33 +16,109 @@ import 'dart:async'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:google_sign_in/google_sign_in.dart'; import 'package:rxdart/subjects.dart'; -import 'package:wyatt_authentication_bloc/src/data/models/account_model_firebase.dart'; -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; +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/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 - extends AuthenticationRemoteDataSource { +class AuthenticationFirebaseDataSourceImpl + extends AuthenticationRemoteDataSource { AuthenticationFirebaseDataSourceImpl({ FirebaseAuth? firebaseAuth, GoogleSignIn? googleSignIn, }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance, _googleSignIn = googleSignIn ?? GoogleSignIn() { - // _accountStream = StreamController(); - _accountStream = BehaviorSubject(); + _latestCredentials = BehaviorSubject(); + _sessionStream = BehaviorSubject(); + // Check for account in memory (persistence) - final currentAccount = (_firebaseAuth.currentUser != null) - ? AccountModelFirebase.fromFirebaseUser(_firebaseAuth.currentUser) - : null; - _accountStream.add(currentAccount); + _checkForCachedAccount(); } - late StreamController _accountStream; + late StreamController> _sessionStream; + late StreamController _latestCredentials; final FirebaseAuth _firebaseAuth; final GoogleSignIn _googleSignIn; - UserCredential? _latestCreds; + Future _checkForCachedAccount() async { + final currentUser = _firebaseAuth.currentUser; + + if (currentUser == null) { + _sessionStream + .add(const SessionWrapper(event: UnknownAuthenticationEvent())); + return; + } + + final jwt = await currentUser.getIdToken(true); + final currentAccount = AccountModel.fromFirebaseUser( + currentUser, + accessToken: jwt, + ); + _sessionStream.add( + SessionWrapper(event: SignedInFromCacheEvent(account: currentAccount)), + ); + return; + } + + Account _addToStream( + UserCredential userCredential, + AuthenticationChangeEvent Function(Account account) eventBuilder, + ) { + final account = AccountModel.fromFirebaseUserCredential(userCredential); + + _latestCredentials.add(userCredential); + + return account; + } + + // Stream related methods =================================================== + + /// {@macro add_session} + @override + void addSession(SessionWrapper wrapper) { + _sessionStream.add(wrapper); + } + + /// {@macro session_stream} + @override + Stream> sessionStream() => + _sessionStream.stream.asBroadcastStream(); + + // SignUp/SignIn methods ==================================================== + + /// {@macro signup_pwd} + @override + Future signUpWithEmailAndPassword({ + required String email, + required String password, + }) async { + try { + final userCredential = await _firebaseAuth.createUserWithEmailAndPassword( + email: email, + password: password, + ); + + return _addToStream( + userCredential, + (account) => SignedUpEvent( + account: account, + ), + ); + } on FirebaseAuthException catch (e) { + throw SignUpWithEmailAndPasswordFailureFirebase.fromCode(e.code); + } catch (_) { + throw SignUpWithEmailAndPasswordFailureFirebase(); + } + } + + /// {@macro signin_pwd} @override Future signInWithEmailAndPassword({ required String email, @@ -53,11 +129,13 @@ class AuthenticationFirebaseDataSourceImpl email: email, password: password, ); - _latestCreds = userCredential; - final account = - AccountModelFirebase.fromFirebaseUserCredential(userCredential); - _accountStream.add(account); - return account; + + return _addToStream( + userCredential, + (account) => SignedInEvent( + account: account, + ), + ); } on FirebaseAuthException catch (e) { throw SignInWithEmailAndPasswordFailureFirebase.fromCode(e.code); } catch (_) { @@ -65,107 +143,18 @@ class AuthenticationFirebaseDataSourceImpl } } - /// {@macro signup} - @override - Future signUp({ - required String email, - required String password, - }) async { - try { - final userCredential = await _firebaseAuth.createUserWithEmailAndPassword( - email: email, - password: password, - ); - _latestCreds = userCredential; - final account = - AccountModelFirebase.fromFirebaseUserCredential(userCredential); - _accountStream.add(account); - return account; - } on FirebaseAuthException catch (e) { - throw SignUpWithEmailAndPasswordFailureFirebase.fromCode(e.code); - } catch (_) { - throw SignUpWithEmailAndPasswordFailureFirebase(); - } - } - - @override - Future signOut() async { - try { - _latestCreds = null; - await _firebaseAuth.signOut(); - _accountStream.add(null); - } catch (_) { - throw SignOutFailureFirebase(); - } - } - - @override - Future getIdentityToken() async { - try { - final token = await _firebaseAuth.currentUser?.getIdToken(); - if (token.isNotNull) { - return token!; - } else { - throw Exception(); // Get caught just after. - } - } on FirebaseAuthException catch (e) { - throw GetIdTokenFailureFirebase.fromCode(e.code); - } catch (_) { - throw GetIdTokenFailureFirebase(); - } - } - - @override - Stream streamAccount() => _accountStream.stream.asBroadcastStream(); - - @override - Future confirmPasswordReset({ - required String code, - required String newPassword, - }) async { - try { - await _firebaseAuth.confirmPasswordReset( - code: code, - newPassword: newPassword, - ); - } on FirebaseAuthException catch (e) { - throw ConfirmPasswordResetFailureFirebase.fromCode(e.code); - } catch (_) { - throw ConfirmPasswordResetFailureFirebase(); - } - } - - @override - Future sendEmailVerification() async { - try { - await _firebaseAuth.currentUser!.sendEmailVerification(); - } on FirebaseAuthException catch (e) { - throw SendEmailVerificationFailureFirebase.fromCode(e.code); - } catch (_) { - throw SendEmailVerificationFailureFirebase(); - } - } - - @override - Future sendPasswordResetEmail({required String email}) async { - try { - await _firebaseAuth.sendPasswordResetEmail(email: email); - } on FirebaseAuthException catch (e) { - throw SendPasswordResetEmailFailureFirebase.fromCode(e.code); - } catch (_) { - throw SendPasswordResetEmailFailureFirebase(); - } - } - + /// {@macro signin_anom} @override Future signInAnonymously() async { try { final userCredential = await _firebaseAuth.signInAnonymously(); - _latestCreds = userCredential; - final account = - AccountModelFirebase.fromFirebaseUserCredential(userCredential); - _accountStream.add(account); - return account; + + return _addToStream( + userCredential, + (account) => SignedInEvent( + account: account, + ), + ); } on FirebaseAuthException catch (e) { throw SignInAnonymouslyFailureFirebase.fromCode(e.code); } catch (_) { @@ -173,6 +162,7 @@ class AuthenticationFirebaseDataSourceImpl } } + /// {@macro signin_google} @override Future signInWithGoogle() async { try { @@ -192,11 +182,12 @@ class AuthenticationFirebaseDataSourceImpl final userCredential = await _firebaseAuth.signInWithCredential(credential); - _latestCreds = userCredential; - final account = - AccountModelFirebase.fromFirebaseUserCredential(userCredential); - _accountStream.add(account); - return account; + return _addToStream( + userCredential, + (account) => SignedInEvent( + account: account, + ), + ); } on FirebaseAuthException catch (e) { throw SignInWithGoogleFailureFirebase.fromCode(e.code); } catch (_) { @@ -204,6 +195,147 @@ class AuthenticationFirebaseDataSourceImpl } } + /// {@macro signout} + @override + Future signOut() async { + try { + _latestCredentials.add(null); + await _firebaseAuth.signOut(); + } catch (_) { + throw SignOutFailureFirebase(); + } + } + + // Account management methods =============================================== + + /// {@macro refresh} + @override + Future refresh() async { + try { + final jwt = await _firebaseAuth.currentUser?.getIdToken(true); + final account = AccountModel.fromFirebaseUser( + _firebaseAuth.currentUser, + accessToken: jwt, + ); + + return account; + } on FirebaseAuthException catch (e) { + throw RefreshFailureFirebase.fromCode(e.code); + } catch (_) { + throw RefreshFailureFirebase(); + } + } + + /// {@macro reauthenticate} + @override + Future reauthenticate() async { + final latestCreds = + await _latestCredentials.stream.asBroadcastStream().last; + try { + if (latestCreds?.credential != null) { + await _firebaseAuth.currentUser + ?.reauthenticateWithCredential(latestCreds!.credential!); + } else { + throw Exception(); // Get caught just after. + } + + final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser); + + return account; + } on FirebaseAuthException catch (e) { + throw ReauthenticateFailureFirebase.fromCode(e.code); + } catch (_) { + throw ReauthenticateFailureFirebase(); + } + } + + /// {@macro update_email} + @override + Future updateEmail({required String email}) async { + try { + await _firebaseAuth.currentUser!.updateEmail(email); + final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser); + + return account; + } on FirebaseAuthException catch (e) { + throw UpdateEmailFailureFirebase.fromCode(e.code); + } catch (_) { + throw UpdateEmailFailureFirebase(); + } + } + + /// {@macro update_password} + @override + Future updatePassword({required String password}) async { + try { + await _firebaseAuth.currentUser!.updatePassword(password); + final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser); + + return account; + } on FirebaseAuthException catch (e) { + throw UpdatePasswordFailureFirebase.fromCode(e.code); + } catch (_) { + throw UpdatePasswordFailureFirebase(); + } + } + + /// {@macro delete} + @override + Future delete() async { + try { + await _firebaseAuth.currentUser!.delete(); + } on FirebaseAuthException catch (e) { + throw DeleteAccountFailureFirebase.fromCode(e.code); + } catch (_) { + throw DeleteAccountFailureFirebase(); + } + } + + // Email related stuff ====================================================== + + /// {@macro send_email_verification} + @override + Future sendEmailVerification() async { + try { + await _firebaseAuth.currentUser!.sendEmailVerification(); + } on FirebaseAuthException catch (e) { + throw SendEmailVerificationFailureFirebase.fromCode(e.code); + } catch (_) { + throw SendEmailVerificationFailureFirebase(); + } + } + + /// {@macro send_password_reset_email} + @override + Future sendPasswordResetEmail({required String email}) async { + try { + await _firebaseAuth.sendPasswordResetEmail(email: email); + } on FirebaseAuthException catch (e) { + throw SendPasswordResetEmailFailureFirebase.fromCode(e.code); + } catch (_) { + throw SendPasswordResetEmailFailureFirebase(); + } + } + + /// {@macro confirm_password_reset} + @override + Future confirmPasswordReset({ + required String code, + required String newPassword, + }) async { + try { + await _firebaseAuth.confirmPasswordReset( + code: code, + newPassword: newPassword, + ); + } on FirebaseAuthException catch (e) { + throw ConfirmPasswordResetFailureFirebase.fromCode(e.code); + } catch (_) { + throw ConfirmPasswordResetFailureFirebase(); + } + } + + /// {@macro verify_password_reset_code} @override Future verifyPasswordResetCode({required String code}) async { try { @@ -215,68 +347,4 @@ class AuthenticationFirebaseDataSourceImpl throw VerifyPasswordResetCodeFailureFirebase(); } } - - @override - Future refresh() async { - try { - await _firebaseAuth.currentUser!.reload(); - final account = - AccountModelFirebase.fromFirebaseUser(_firebaseAuth.currentUser); - _accountStream.add(account); - } on FirebaseAuthException catch (e) { - throw RefreshFailureFirebase.fromCode(e.code); - } catch (_) { - throw RefreshFailureFirebase(); - } - } - - @override - Future reauthenticateWithCredential() async { - try { - if (_latestCreds?.credential != null) { - await _firebaseAuth.currentUser - ?.reauthenticateWithCredential(_latestCreds!.credential!); - } else { - throw Exception(); // Get caught just after. - } - final account = - AccountModelFirebase.fromFirebaseUser(_firebaseAuth.currentUser); - _accountStream.add(account); - return account; - } on FirebaseAuthException catch (e) { - throw ReauthenticateFailureFirebase.fromCode(e.code); - } catch (_) { - throw ReauthenticateFailureFirebase(); - } - } - - @override - Future updateEmail({required String email}) async { - try { - await _firebaseAuth.currentUser!.updateEmail(email); - final account = - AccountModelFirebase.fromFirebaseUser(_firebaseAuth.currentUser); - _accountStream.add(account); - return account; - } on FirebaseAuthException catch (e) { - throw UpdateEmailFailureFirebase.fromCode(e.code); - } catch (_) { - throw UpdateEmailFailureFirebase(); - } - } - - @override - Future updatePassword({required String password}) async { - try { - await _firebaseAuth.currentUser!.updatePassword(password); - final account = - AccountModelFirebase.fromFirebaseUser(_firebaseAuth.currentUser); - _accountStream.add(account); - return account; - } on FirebaseAuthException catch (e) { - throw UpdatePasswordFailureFirebase.fromCode(e.code); - } catch (_) { - throw UpdatePasswordFailureFirebase(); - } - } } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart b/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart deleted file mode 100644 index 1ee3a767..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/data/data_sources/remote/authentication_mock_data_source_impl.dart +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (C) 2022 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 'dart:math'; - -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; -import 'package:wyatt_type_utils/wyatt_type_utils.dart'; - -class AuthenticationMockDataSourceImpl extends AuthenticationRemoteDataSource { - AuthenticationMockDataSourceImpl({ - this.idToken = 'fake-id-token', - this.registeredAccounts, - }); - Pair? _connectedMock; - Pair? _registeredMock; - DateTime _lastSignInTime = DateTime.now(); - final StreamController _streamAccount = StreamController() - ..add(null); - - final List>? registeredAccounts; - final String idToken; - - Future _randomDelay() async { - await Future.delayed( - Duration(milliseconds: Random().nextInt(400) + 200), - ); - return; - } - - @override - Future confirmPasswordReset({ - required String code, - required String newPassword, - }) async { - await _randomDelay(); - } - - @override - Future getIdentityToken() async { - await _randomDelay(); - return idToken; - } - - @override - Future refresh() async { - await _randomDelay(); - if (_connectedMock.isNull) { - throw RefreshFailureFirebase(); - } - final refresh = DateTime.now(); - final mock = (_connectedMock?.left as AccountModel?) - ?.copyWith(lastSignInTime: refresh); - _connectedMock = _connectedMock?.copyWith(left: mock); - _streamAccount.add(mock); - } - - @override - Future sendEmailVerification() async { - await _randomDelay(); - if (_connectedMock.isNotNull) { - final refresh = DateTime.now(); - final mock = (_connectedMock?.left as AccountModel?)?.copyWith( - emailVerified: false, - lastSignInTime: refresh, - ); - _streamAccount.add(mock); - _connectedMock = _connectedMock?.copyWith(left: mock); - return; - } - throw SendEmailVerificationFailureFirebase(); - } - - @override - Future sendPasswordResetEmail({required String email}) async { - await _randomDelay(); - if (registeredAccounts.isNotNull) { - final accounts = - registeredAccounts?.where((pair) => pair.left?.email == email); - if (accounts.isNotNullOrEmpty) { - return; - } - } - if (_registeredMock.isNotNull) { - if (_registeredMock?.left?.email != email) { - throw SendPasswordResetEmailFailureFirebase(); - } - return; - } - throw SendPasswordResetEmailFailureFirebase(); - } - - @override - Future signInAnonymously() async { - await _randomDelay(); - final creation = DateTime.now(); - final mock = AccountModel( - uid: 'mock-id-anom', - emailVerified: false, - isAnonymous: true, - providerId: 'wyatt-studio.fr', - creationTime: creation, - lastSignInTime: creation, - isNewUser: creation == creation, - ); - _streamAccount.add(mock); - _connectedMock = _connectedMock?.copyWith(left: mock); - _lastSignInTime = DateTime.now(); - return Future.value(mock); - } - - @override - Future signInWithGoogle() async { - await _randomDelay(); - final creation = DateTime.now(); - final mock = AccountModel( - uid: 'mock-id-google', - emailVerified: true, - isAnonymous: false, - providerId: 'google.com', - creationTime: creation, - lastSignInTime: creation, - isNewUser: creation == creation, - ); - _streamAccount.add(mock); - _connectedMock = _connectedMock?.copyWith(left: mock); - _lastSignInTime = DateTime.now(); - return Future.value(mock); - } - - @override - Future signInWithEmailAndPassword({ - required String email, - required String password, - }) async { - await _randomDelay(); - if (registeredAccounts.isNotNull) { - final accounts = - registeredAccounts?.where((pair) => pair.left?.email == email); - if (accounts.isNotNullOrEmpty) { - final account = accounts?.first; - if (account?.right != password) { - throw SignInWithCredentialFailureFirebase.fromCode('wrong-password'); - } - _streamAccount.add(account!.left); - _connectedMock = account.copyWith(); - return account.left!; - } - } - if (_registeredMock.isNotNull) { - if (_registeredMock?.left?.email != email) { - throw SignInWithCredentialFailureFirebase.fromCode('user-not-found'); - } - if (_registeredMock?.right != password) { - throw SignInWithCredentialFailureFirebase.fromCode('wrong-password'); - } - _streamAccount.add(_registeredMock!.left); - _connectedMock = _registeredMock!.copyWith(); - _lastSignInTime = DateTime.now(); - return _registeredMock!.left!; - } - throw SignInWithCredentialFailureFirebase(); - } - - @override - Future signOut() async { - _connectedMock = null; - _streamAccount.add(null); - } - - @override - Future signUp({ - required String email, - required String password, - }) async { - await _randomDelay(); - if (registeredAccounts.isNotNull) { - final accounts = - registeredAccounts?.where((pair) => pair.left?.email == email); - if (accounts.isNotNullOrEmpty) { - throw SignUpWithEmailAndPasswordFailureFirebase.fromCode( - 'email-already-in-use', - ); - } - } - if (_registeredMock?.left?.email == email) { - throw SignUpWithEmailAndPasswordFailureFirebase.fromCode( - 'email-already-in-use', - ); - } - final creation = DateTime.now(); - final mock = AccountModel( - uid: 'mock-id-email', - emailVerified: false, - isAnonymous: false, - providerId: 'wyatt', - email: email, - creationTime: creation, - lastSignInTime: creation, - isNewUser: creation == creation, - ); - _streamAccount.add(mock); - _registeredMock = Pair(mock, password); - _connectedMock = _registeredMock!.copyWith(); - _lastSignInTime = DateTime.now(); - return Future.value(mock); - } - - @override - Stream streamAccount() => _streamAccount.stream.asBroadcastStream(); - - @override - Future verifyPasswordResetCode({required String code}) async { - await _randomDelay(); - return true; - } - - @override - Future reauthenticateWithCredential() async { - await _randomDelay(); - if (_connectedMock.isNull) { - throw ReauthenticateFailureFirebase(); - } - await refresh(); - _lastSignInTime = DateTime.now(); - return Future.value(_connectedMock?.left); - } - - @override - Future updateEmail({required String email}) { - final before = DateTime.now().subtract(const Duration(seconds: 10)); - if (_lastSignInTime.isBefore(before)) { - throw UpdateEmailFailureFirebase('requires-recent-login'); - } - final refresh = DateTime.now(); - final mock = (_connectedMock?.left as AccountModel?) - ?.copyWith(lastSignInTime: refresh, email: email); - _connectedMock = _connectedMock?.copyWith(left: mock); - _registeredMock = _registeredMock?.copyWith(left: mock); - _streamAccount.add(mock); - return Future.value(_connectedMock?.left); - } - - @override - Future updatePassword({required String password}) { - final before = DateTime.now().subtract(const Duration(seconds: 10)); - if (_lastSignInTime.isBefore(before)) { - throw UpdatePasswordFailureFirebase('requires-recent-login'); - } - final refresh = DateTime.now(); - final mock = (_connectedMock?.left as AccountModel?) - ?.copyWith(lastSignInTime: refresh); - _connectedMock = _connectedMock?.copyWith(left: mock, right: password); - _registeredMock = _registeredMock?.copyWith(left: mock, right: password); - _streamAccount.add(mock); - return Future.value(_connectedMock?.left); - } -} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart index 0077378b..c79d54e8 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model.dart @@ -1,5 +1,4 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,74 +14,77 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +/// Account Model to parse Firebase User data class AccountModel extends Account { - @override - final String uid; + factory AccountModel.fromFirebaseUserCredential( + UserCredential? userCredential, + ) { + final user = userCredential?.user; + if (user != null) { + final providerId = + (user.providerData.isEmpty) ? '' : user.providerData.first.providerId; + return AccountModel._( + user: user, + id: user.uid, + emailVerified: user.emailVerified, + isAnonymous: user.isAnonymous, + providerId: providerId, + creationTime: user.metadata.creationTime, + lastSignInTime: user.metadata.lastSignInTime, + isNewUser: userCredential?.additionalUserInfo?.isNewUser, + email: user.email, + phoneNumber: user.phoneNumber, + photoURL: user.photoURL, + accessToken: userCredential?.credential?.accessToken, + ); + } else { + throw ModelParsingFailureFirebase('null-user', 'User cannot be null'); + } + } - @override - final String? email; - - @override - final DateTime? creationTime; - - @override - final bool emailVerified; - - @override - final bool isAnonymous; - - @override - final bool? isNewUser; - - @override - final DateTime? lastSignInTime; - - @override - final String? phoneNumber; - - @override - final String? photoURL; - - @override - final String providerId; - - AccountModel({ - required this.uid, - required this.emailVerified, - required this.isAnonymous, - required this.providerId, - this.lastSignInTime, - this.creationTime, - this.isNewUser, - this.email, - this.phoneNumber, - this.photoURL, + factory AccountModel.fromFirebaseUser(User? user, {String? accessToken}) { + if (user != null) { + final providerId = + (user.providerData.isEmpty) ? '' : user.providerData.first.providerId; + return AccountModel._( + user: user, + id: user.uid, + emailVerified: user.emailVerified, + isAnonymous: user.isAnonymous, + providerId: providerId, + creationTime: user.metadata.creationTime, + lastSignInTime: user.metadata.lastSignInTime, + isNewUser: false, + email: user.email, + phoneNumber: user.phoneNumber, + photoURL: user.photoURL, + accessToken: accessToken, + ); + } else { + throw ModelParsingFailureFirebase('null-user', 'User cannot be null'); + } + } + const AccountModel._({ + required this.user, + required super.id, + required super.emailVerified, + required super.isAnonymous, + required super.providerId, + super.lastSignInTime, + super.creationTime, + super.isNewUser, + super.email, + super.phoneNumber, + super.photoURL, + super.accessToken, }); - AccountModel copyWith({ - String? uid, - String? email, - DateTime? creationTime, - bool? emailVerified, - bool? isAnonymous, - bool? isNewUser, - DateTime? lastSignInTime, - String? phoneNumber, - String? photoURL, - String? providerId, - }) => - AccountModel( - uid: uid ?? this.uid, - email: email ?? this.email, - creationTime: creationTime ?? this.creationTime, - emailVerified: emailVerified ?? this.emailVerified, - isAnonymous: isAnonymous ?? this.isAnonymous, - isNewUser: isNewUser ?? this.isNewUser, - lastSignInTime: lastSignInTime ?? this.lastSignInTime, - phoneNumber: phoneNumber ?? this.phoneNumber, - photoURL: photoURL ?? this.photoURL, - providerId: providerId ?? this.providerId, - ); + final User? user; + + @override + String? get refreshToken => user?.refreshToken; } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model_firebase.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/account_model_firebase.dart deleted file mode 100644 index 07e5b5a0..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/account_model_firebase.dart +++ /dev/null @@ -1,80 +0,0 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// Copyright (C) 2022 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:firebase_auth/firebase_auth.dart'; -import 'package:wyatt_authentication_bloc/src/core/exceptions/exceptions.dart'; -import 'package:wyatt_authentication_bloc/src/data/models/account_model.dart'; - -class AccountModelFirebase extends AccountModel { - AccountModelFirebase._({ - required super.uid, - required super.emailVerified, - required super.isAnonymous, - required super.providerId, - super.lastSignInTime, - super.creationTime, - super.isNewUser, - super.email, - super.phoneNumber, - super.photoURL, - }); - - factory AccountModelFirebase.fromFirebaseUser(User? user) { - if (user != null) { - final providerId = - (user.providerData.isEmpty) ? '' : user.providerData.first.providerId; - return AccountModelFirebase._( - uid: user.uid, - emailVerified: user.emailVerified, - isAnonymous: user.isAnonymous, - providerId: providerId, - creationTime: user.metadata.creationTime, - lastSignInTime: user.metadata.lastSignInTime, - isNewUser: false, - email: user.email, - phoneNumber: user.phoneNumber, - photoURL: user.photoURL, - ); - } else { - throw ModelParsingFailureFirebase('null-user', 'User cannot be null'); - } - } - - factory AccountModelFirebase.fromFirebaseUserCredential( - UserCredential? userCredential, - ) { - final user = userCredential?.user; - if (user != null) { - final providerId = - (user.providerData.isEmpty) ? '' : user.providerData.first.providerId; - return AccountModelFirebase._( - uid: user.uid, - emailVerified: user.emailVerified, - isAnonymous: user.isAnonymous, - providerId: providerId, - creationTime: user.metadata.creationTime, - lastSignInTime: user.metadata.lastSignInTime, - isNewUser: userCredential?.additionalUserInfo?.isNewUser, - email: user.email, - phoneNumber: user.phoneNumber, - photoURL: user.photoURL, - ); - } else { - throw ModelParsingFailureFirebase('null-user', 'User cannot be null'); - } - } -} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart b/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart index 14f991fe..3efbdbc0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/models/models.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,4 +15,3 @@ // along with this program. If not, see . export 'account_model.dart'; -export 'account_wrapper_model.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 686be61a..2c25e1bc 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,49 +14,28 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import 'dart:async'; - import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; -import 'package:wyatt_authentication_bloc/src/data/models/account_wrapper_model.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/remote/authentication_remote_data_source.dart'; import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/auth_change_event.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.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'; -class AuthenticationRepositoryImpl - extends AuthenticationRepository { +class AuthenticationRepositoryImpl + extends AuthenticationRepository { AuthenticationRepositoryImpl({ - required this.authenticationCacheDataSource, required this.authenticationRemoteDataSource, FormRepository? formRepository, // ignore: strict_raw_type List? extraSignUpInputs, FormInputValidator? customEmailValidator, FormInputValidator? customPasswordValidator, - AuthChangeListener? onAuthChange, - AccountStreamTransformer? accountStreamTransformer, - }) : _authChangeListener = onAuthChange, - _accountStreamTransformer = accountStreamTransformer { + }) { _formRepository = formRepository ?? FormRepositoryImpl(); - _accountStreamTransformer ??= (input) => input - .where((event) => event is! SignUpAuthChangeEvent) - .map>>((event) async { - if (listener == null) { - return Ok(AccountWrapperModel(event.account, null)); - } - // Handle sign in, sign out and refresh - final dataResult = await listener!.call(this, event); - return dataResult.map((data) { - authenticationCacheDataSource.storeData(data); - return AccountWrapperModel(event.account, data); - }); - }); + if (formRepository != null) { return; } @@ -104,20 +83,47 @@ class AuthenticationRepositoryImpl ), ); } - final AuthenticationCacheDataSource authenticationCacheDataSource; - final AuthenticationRemoteDataSource authenticationRemoteDataSource; + final AuthenticationRemoteDataSource authenticationRemoteDataSource; late FormRepository _formRepository; - AuthChangeListener? _authChangeListener; - AccountStreamTransformer? _accountStreamTransformer; - + /// {@macro form_repo} @override FormRepository get formRepository => _formRepository; - @override - AuthChangeListener? get listener => _authChangeListener; + // Stream related methods =================================================== + /// {@macro add_session} + @override + void addSession(SessionWrapper wrapper) => + authenticationRemoteDataSource.addSession(wrapper); + + /// {@macro session_stream} + @override + Stream> sessionStream() => + authenticationRemoteDataSource.sessionStream(); + + // SignUp/SignIn methods ==================================================== + + /// {@macro signup_pwd} + @override + FutureOrResult signUpWithEmailAndPassword({ + required String email, + required String password, + }) => + Result.tryCatchAsync( + () async { + final account = + await authenticationRemoteDataSource.signUpWithEmailAndPassword( + email: email, + password: password, + ); + return account; + }, + (error) => error, + ); + + /// {@macro signin_pwd} @override FutureOrResult signInWithEmailAndPassword({ required String email, @@ -130,100 +136,127 @@ class AuthenticationRepositoryImpl email: email, password: password, ); - await authenticationCacheDataSource.storeAccount(account); return account; }, (error) => error, ); + /// {@macro signin_anom} + @override + FutureOrResult signInAnonymously() => + Result.tryCatchAsync( + () async { + final account = + await authenticationRemoteDataSource.signInAnonymously(); + return account; + }, + (error) => error, + ); + + /// {@macro signin_google} + @override + FutureOrResult signInWithGoogle() => + Result.tryCatchAsync( + () async { + final account = + await authenticationRemoteDataSource.signInWithGoogle(); + return account; + }, + (error) => error, + ); + + /// {@macro signout} @override FutureOrResult signOut() => Result.tryCatchAsync( () async { await authenticationRemoteDataSource.signOut(); - await authenticationCacheDataSource.destroy(); }, (error) => error, ); + // Account management methods =============================================== + + /// {@macro refresh} @override - FutureOrResult signUp({ - required String email, - required String password, - }) => + FutureOrResult refresh() => Result.tryCatchAsync( () async { - final account = await authenticationRemoteDataSource.signUp( - email: email, - password: password, - ); - await authenticationCacheDataSource.storeAccount(account); + final account = await authenticationRemoteDataSource.refresh(); return account; }, (error) => error, ); + /// {@macro reauthenticate} @override - FutureOrResult destroyCache() => - Result.tryCatchAsync( - authenticationCacheDataSource.destroy, - (error) => error, - ); - - @override - FutureOrResult> getCache() => - Result.tryCatchAsync, AppException, AppException>( - authenticationCacheDataSource.load, - (error) => error, - ); - - @override - FutureOrResult getAccount() => + FutureOrResult reauthenticate() => Result.tryCatchAsync( - authenticationCacheDataSource.loadAccount, - (error) => error, - ); - - @override - FutureOrResult setAccount( - Account account, - ) => - Result.tryCatchAsync( () async { - await authenticationCacheDataSource.storeAccount(account); + final account = await authenticationRemoteDataSource.reauthenticate(); + return account; }, (error) => error, ); + /// {@macro update_email} @override - FutureOrResult getData() => - Result.tryCatchAsync( - authenticationCacheDataSource.loadData, - (error) => error, - ); - - @override - FutureOrResult setData( - T? data, - ) => - Result.tryCatchAsync( + FutureOrResult updateEmail({required String email}) => + Result.tryCatchAsync( () async { - await authenticationCacheDataSource.storeData(data); + final account = + await authenticationRemoteDataSource.updateEmail(email: email); + return account; }, (error) => error, ); + /// {@macro update_password} @override - FutureOrResult getIdentityToken() => - Result.tryCatchAsync( - authenticationRemoteDataSource.getIdentityToken, + FutureOrResult updatePassword({required String password}) => + Result.tryCatchAsync( + () async { + final account = await authenticationRemoteDataSource.updatePassword( + password: password, + ); + return account; + }, (error) => error, ); + /// {@macro delete} @override - Stream>> streamAccount() => - _accountStreamTransformer!.call(changes()); + FutureOrResult delete() => + Result.tryCatchAsync( + () async => authenticationRemoteDataSource.delete(), + (error) => error, + ); + // Email related stuff ====================================================== + + /// {@macro send_email_verification} + @override + FutureOrResult sendEmailVerification() => + Result.tryCatchAsync( + () async { + await authenticationRemoteDataSource.sendEmailVerification(); + }, + (error) => error, + ); + + /// {@macro send_password_reset_email} + @override + FutureOrResult sendPasswordResetEmail({required String email}) => + Result.tryCatchAsync( + () async { + await authenticationRemoteDataSource.sendPasswordResetEmail( + email: email, + ); + }, + (error) => error, + ); + + /// {@macro confirm_password_reset} @override FutureOrResult confirmPasswordReset({ required String code, @@ -239,48 +272,7 @@ class AuthenticationRepositoryImpl (error) => error, ); - @override - FutureOrResult sendEmailVerification() => - Result.tryCatchAsync( - () async { - await authenticationRemoteDataSource.sendEmailVerification(); - }, - (error) => error, - ); - - @override - FutureOrResult sendPasswordResetEmail({required String email}) => - Result.tryCatchAsync( - () async { - await authenticationRemoteDataSource.sendPasswordResetEmail( - email: email, - ); - }, - (error) => error, - ); - - @override - FutureOrResult signInAnonymously() => - Result.tryCatchAsync( - () async { - final account = - await authenticationRemoteDataSource.signInAnonymously(); - return account; - }, - (error) => error, - ); - - @override - FutureOrResult signInWithGoogle() => - Result.tryCatchAsync( - () async { - final account = - await authenticationRemoteDataSource.signInWithGoogle(); - return account; - }, - (error) => error, - ); - + /// {@macro verify_password_reset_code} @override FutureOrResult verifyPasswordResetCode({required String code}) => Result.tryCatchAsync( @@ -291,91 +283,4 @@ class AuthenticationRepositoryImpl }, (error) => error, ); - - @override - FutureOrResult refresh() => - Result.tryCatchAsync( - () async { - await authenticationRemoteDataSource.refresh(); - }, - (error) => error, - ); - - @override - FutureOrResult reauthenticateWithCredential() => - Result.tryCatchAsync( - () async { - final account = await authenticationRemoteDataSource - .reauthenticateWithCredential(); - return account; - }, - (error) => error, - ); - - @override - FutureOrResult updateEmail({required String email}) => - Result.tryCatchAsync( - () async { - final account = - await authenticationRemoteDataSource.updateEmail(email: email); - return account; - }, - (error) => error, - ); - - @override - FutureOrResult updatePassword({required String password}) => - Result.tryCatchAsync( - () async { - final account = await authenticationRemoteDataSource.updatePassword( - password: password, - ); - return account; - }, - (error) => error, - ); - - Account? _lastChange; - - @override - Stream changes() => authenticationRemoteDataSource - .streamAccount() - .map((account) { - if (_lastChange != null && account == null) { - _lastChange = null; - return SignOutAuthChangeEvent(); - } - if (_lastChange == null && account != null) { - _lastChange = account; - if (account.isNewUser ?? false) { - if (account.isAnonymous) { - return AnonymousSignInAuthChangeEvent(account); - } - return SignUpAuthChangeEvent(account); - } - return SignInAuthChangeEvent(account); - } - if (_lastChange != null && account != null) { - _lastChange = account; - return RefreshAuthChangeEvent(account); - } - if (_lastChange == null && account == null) { - _lastChange = account; - return StillUnauthenticatedAuthChangeEvent(); - } - _lastChange = account; - return RefreshAuthChangeEvent(account); - }); - - @override - FutureOrResult addAuthChangeListener(AuthChangeListener listener) { - _authChangeListener = listener; - return const Ok(null); - } - - @override - FutureOrResult removeAuthChangeListener() { - _authChangeListener = null; - return const Ok(null); - } } diff --git a/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart b/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart index d5979688..0081a38c 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart +++ b/packages/wyatt_authentication_bloc/lib/src/data/repositories/repositories.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 11efe02d..4a8f3011 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,5 +14,4 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'local/authentication_cache_data_source.dart'; export 'remote/authentication_remote_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 8205bd8d..6bec3426 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,9 +16,20 @@ 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'; -abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource { - Future signUp({ +/// Is responsible for abstracting the provenance of the data. +abstract class AuthenticationRemoteDataSource + extends BaseRemoteDataSource { + // Stream related methods =================================================== + + void addSession(SessionWrapper wrapper); + + Stream> sessionStream(); + + // SignUp/SignIn methods ==================================================== + + Future signUpWithEmailAndPassword({ required String email, required String password, }); @@ -27,33 +38,27 @@ abstract class AuthenticationRemoteDataSource extends BaseRemoteDataSource { required String email, required String password, }); + Future signInAnonymously(); + Future signInWithGoogle(); Future signOut(); - Future refresh(); + // Account management methods =============================================== + + // Future linkCurrentUserWith(AuthenticationProvider anotherProvider); + Future refresh(); + Future reauthenticate(); + Future updateEmail({required String email}); + Future updatePassword({required String password}); + Future delete(); - Stream streamAccount(); - - Future getIdentityToken(); + // Email related stuff ====================================================== Future sendEmailVerification(); - Future sendPasswordResetEmail({required String email}); - Future confirmPasswordReset({ required String code, required String newPassword, }); - Future verifyPasswordResetCode({required String code}); - - Future signInAnonymously(); - - Future signInWithGoogle(); - - Future updateEmail({required String email}); - - Future updatePassword({required String password}); - - Future reauthenticateWithCredential(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart b/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart index 6f4ec438..25af7843 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/domain.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart index 5723d3a5..ee6cd353 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/account.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,67 +17,88 @@ import 'package:equatable/equatable.dart'; import 'package:wyatt_architecture/wyatt_architecture.dart'; -abstract class Account extends Equatable implements Entity { +/// Represents a user [Account] in the +/// various identity provisioning systems. +class Account extends Equatable implements Entity { + const Account({ + required this.id, + required this.isAnonymous, + required this.emailVerified, + required this.providerId, + this.email, + this.phoneNumber, + this.photoURL, + this.creationTime, + this.lastSignInTime, + this.isNewUser, + this.accessToken, + this.refreshToken, + }); + /// The user's unique ID. - String get uid; + final String id; + + /// Returns whether the user is a anonymous. + final bool isAnonymous; /// The users email address. /// /// Will be `null` if signing in anonymously. - String? get email; + final String? email; /// Returns whether the users email address has been verified. /// /// To send a verification email, see `SendEmailVerification`. - bool get emailVerified; - - /// Returns whether the user is a anonymous. - bool get isAnonymous; - - /// Returns the users account creation time. - /// - /// When this account was created as dictated by the server clock. - DateTime? get creationTime; - - /// When the user last signed in as dictated by the server clock. - DateTime? get lastSignInTime; + final bool emailVerified; /// Returns the users phone number. /// /// This property will be `null` if the user has not signed in or been has /// their phone number linked. - String? get phoneNumber; + final String? phoneNumber; /// Returns a photo URL for the user. /// /// This property will be populated if the user has signed in or been linked /// with a 3rd party OAuth provider (such as Google). - String? get photoURL; + final String? photoURL; - /// The provider ID for the user. - String get providerId; + /// Returns the users account creation time. + /// + /// When this account was created as dictated by the server clock. + final DateTime? creationTime; + + /// When the user last signed in as dictated by the server clock. + final DateTime? lastSignInTime; /// Whether the user account has been recently created. - bool? get isNewUser; + final bool? isNewUser; + + /// The provider ID for the user. + final String providerId; + + /// The user access token + final String? accessToken; + + /// The user refresh token + final String? refreshToken; @override List get props => [ - uid, + id, + isAnonymous, email, emailVerified, - isAnonymous, - creationTime, - lastSignInTime, phoneNumber, photoURL, + creationTime, + lastSignInTime, providerId, isNewUser, + accessToken, + refreshToken, ]; @override - String toString() => 'AccountModel(uid: $uid, email: $email, ' - 'creationTime: $creationTime, emailVerified: $emailVerified, ' - 'isAnonymous: $isAnonymous, isNewUser: $isNewUser, lastSignInTime: ' - '$lastSignInTime, phoneNumber: $phoneNumber, photoURL: $photoURL, ' - 'providerId: $providerId)'; + bool get stringify => true; } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_change_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_change_event.dart deleted file mode 100644 index d2e38a33..00000000 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/auth_change_event.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2022 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/entities/account.dart'; - -abstract class AuthChangeEvent { - AuthChangeEvent(this.account); - - final Account? account; -} - -class SignInAuthChangeEvent extends AuthChangeEvent { - SignInAuthChangeEvent(super.account); -} - -class AnonymousSignInAuthChangeEvent extends AuthChangeEvent { - AnonymousSignInAuthChangeEvent(super.account); -} - -class ProviderSignInAuthChangeEvent extends AuthChangeEvent { - ProviderSignInAuthChangeEvent(super.account); -} - -class SignUpAuthChangeEvent extends AuthChangeEvent { - SignUpAuthChangeEvent(super.account); -} - -class RefreshAuthChangeEvent extends AuthChangeEvent { - RefreshAuthChangeEvent(super.account); -} - -class StillUnauthenticatedAuthChangeEvent extends AuthChangeEvent { - StillUnauthenticatedAuthChangeEvent() : super(null); -} - -class SignOutAuthChangeEvent extends AuthChangeEvent { - SignOutAuthChangeEvent() : super(null); -} 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/entities/authentication_change_event/authentication_change_event.dart similarity index 55% rename from packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart index c4d357e5..51d6e511 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/data_sources/local/authentication_cache_data_source.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/authentication_change_event.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,16 +14,28 @@ // 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/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; -abstract class AuthenticationCacheDataSource - extends BaseLocalDataSource { - Future storeAccount(Account? account); - Future storeData(T? data); - Future loadAccount(); - Future loadData(); - Future> load(); - Future destroy(); +part 'signed_in_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'; + +/// Represents an event initiated by a change in +/// the user's authentication status. +abstract class AuthenticationChangeEvent extends Equatable implements Entity { + const AuthenticationChangeEvent(); + + @override + List get props => []; + + @override + bool get stringify => true; } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/deleted_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/deleted_event.dart new file mode 100644 index 00000000..2eff8187 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/deleted_event.dart @@ -0,0 +1,22 @@ +// 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 . + +part of 'authentication_change_event.dart'; + +/// When a user deleted his account. +class DeletedEvent extends AuthenticationChangeEvent { + const DeletedEvent(); +} diff --git a/packages/wyatt_authentication_bloc/lib/src/data/models/account_wrapper_model.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart similarity index 53% rename from packages/wyatt_authentication_bloc/lib/src/data/models/account_wrapper_model.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart index 4dae7f6b..2ad9c96f 100644 --- a/packages/wyatt_authentication_bloc/lib/src/data/models/account_wrapper_model.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/reauthenticated_event.dart @@ -1,5 +1,4 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,23 +14,16 @@ // 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/entities/account.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; +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 +/// token and a different login time) +class ReauthenticatedEvent extends AuthenticationChangeEvent { + const ReauthenticatedEvent({required this.account}); + + final Account account; -class AccountWrapperModel extends AccountWrapper { @override - final Account? account; - @override - final T? data; - - AccountWrapperModel(this.account, this.data); - - AccountWrapperModel copyWith({ - Account? account, - T? data, - }) => - AccountWrapperModel( - account ?? this.account, - data ?? this.data, - ); + List get props => [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 new file mode 100644 index 00000000..ce8651d3 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/refreshed_event.dart @@ -0,0 +1,28 @@ +// 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 . + +part of 'authentication_change_event.dart'; + +/// 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]; +} 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 new file mode 100644 index 00000000..22cd6296 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_event.dart @@ -0,0 +1,27 @@ +// 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 . + +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]; +} 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 new file mode 100644 index 00000000..b32f098a --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_in_from_cache_event.dart @@ -0,0 +1,27 @@ +// 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 . + +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]; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_out_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_out_event.dart new file mode 100644 index 00000000..e7579097 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_out_event.dart @@ -0,0 +1,22 @@ +// 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 . + +part of 'authentication_change_event.dart'; + +/// When a user logs out. +class SignedOutEvent extends AuthenticationChangeEvent { + const SignedOutEvent(); +} 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 new file mode 100644 index 00000000..6683e0fa --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/signed_up_event.dart @@ -0,0 +1,27 @@ +// 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 . + +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]; +} diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/unknown_authentication_event.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/unknown_authentication_event.dart new file mode 100644 index 00000000..93c56dec --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/unknown_authentication_event.dart @@ -0,0 +1,22 @@ +// 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 . + +part of 'authentication_change_event.dart'; + +/// When a user's login status is unknown. +class UnknownAuthenticationEvent extends AuthenticationChangeEvent { + const UnknownAuthenticationEvent(); +} 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 new file mode 100644 index 00000000..f64e6c74 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/authentication_change_event/updated_event.dart @@ -0,0 +1,27 @@ +// 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 . + +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]; +} 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 9c83225f..a466a036 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/entities.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,5 +15,6 @@ // along with this program. If not, see . export 'account.dart'; -export 'account_wrapper.dart'; -export 'auth_change_event.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/account_wrapper.dart b/packages/wyatt_authentication_bloc/lib/src/domain/entities/session.dart similarity index 70% rename from packages/wyatt_authentication_bloc/lib/src/domain/entities/account_wrapper.dart rename to packages/wyatt_authentication_bloc/lib/src/domain/entities/session.dart index 0788e03e..61162ee8 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/entities/account_wrapper.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/session.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -15,16 +15,22 @@ // 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/account.dart'; -abstract class AccountWrapper extends Equatable implements Entity { - Account? get account; - T? get data; - +/// 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 - String toString() => 'AccountWrapper($account, data: $data)'; + bool? get stringify => true; } 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 new file mode 100644 index 00000000..4fa2b924 --- /dev/null +++ b/packages/wyatt_authentication_bloc/lib/src/domain/entities/session_wrapper.dart @@ -0,0 +1,38 @@ +// 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 3e958f78..1eb6fc25 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,31 +16,30 @@ 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/account_wrapper.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/auth_change_event.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; -typedef SignUpCallback = FutureOrResult Function( - AuthenticationRepository repo, - Account? account, - WyattForm form, -); - -typedef AuthChangeListener = FutureOrResult Function( - AuthenticationRepository repo, - AuthChangeEvent? authEvent, -); - -typedef AccountStreamTransformer - = Stream>> Function( - Stream input, -); - -abstract class AuthenticationRepository extends BaseRepository { +abstract class AuthenticationRepository extends BaseRepository { + /// {@template form_repo} + /// Form repository used in different authentication cubits/blocs + /// {@endtemplate} FormRepository get formRepository; - AuthChangeListener? get listener; - /// {@template signup} + // Stream related methods =================================================== + + /// {@template add_session} + /// Add a new authentication event. + /// {@endtemplate} + void addSession(SessionWrapper wrapper); + + /// {@template session_stream} + /// Authentication state change event stream. + /// {@endtemplate} + Stream> sessionStream(); + + // SignUp/SignIn methods ==================================================== + + /// {@template signup_pwd} /// Creates a new user with the provided [email] and [password]. /// /// Returns the newly created user's unique identifier. @@ -48,11 +47,89 @@ abstract class AuthenticationRepository extends BaseRepository { /// Throws a SignUpWithEmailAndPasswordFailureInterface if /// an exception occurs. /// {@endtemplate} - FutureOrResult signUp({ + FutureOrResult signUpWithEmailAndPassword({ required String email, required String password, }); + /// {@template signin_pwd} + /// Signs in with the provided [email] and [password]. + /// + /// Throws a SignInWithEmailAndPasswordFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult signInWithEmailAndPassword({ + required String email, + required String password, + }); + + /// {@template signin_anom} + /// Sign in anonymously. + /// + /// Throws a SignInAnonymouslyFailureInterface if an exception occurs. + /// {@endtemplate} + FutureOrResult signInAnonymously(); + + /// {@template signin_google} + /// Starts the Sign In with Google Flow. + /// + /// Throws a SignInWithGoogleFailureInterface if an exception occurs. + /// {@endtemplate} + FutureOrResult signInWithGoogle(); + + /// {@template signout} + /// Signs out the current user. + /// It also clears the cache and the associated data. + /// {@endtemplate} + FutureOrResult signOut(); + + // Account management methods =============================================== + + /// {@template refresh} + /// Refreshes the current user, if signed in. + /// {@endtemplate} + FutureOrResult refresh(); + + /// {@template reauthenticate} + /// Some security-sensitive actions—such as deleting an account, + /// setting a primary email address, and changing a password—require that + /// the user has recently signed in. + /// + /// Throws a ReauthenticateFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult reauthenticate(); + + /// {@template update_email} + /// Update or add [email]. + /// + /// Throws a UpdateEmailFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult updateEmail({ + required String email, + }); + + /// {@template update_password} + /// Update or add [password]. + /// + /// Throws a UpdatePasswordFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult updatePassword({ + required String password, + }); + + /// {@template delete} + /// Delete account. + /// + /// Throws a DeleteAccountFailureInterface if + /// an exception occurs. + /// {@endtemplate} + FutureOrResult delete(); + + // Email related stuff ====================================================== + /// {@template send_email_verification} /// Sends verification email to the account email. /// @@ -83,95 +160,4 @@ abstract class AuthenticationRepository extends BaseRepository { /// Throws a VerifyPasswordResetCodeFailureInterface if an exception occurs. /// {@endtemplate} FutureOrResult verifyPasswordResetCode({required String code}); - - /// {@template signin_anom} - /// Sign in anonymously. - /// - /// Throws a SignInAnonymouslyFailureInterface if an exception occurs. - /// {@endtemplate} - FutureOrResult signInAnonymously(); - - /// {@template signin_google} - /// Starts the Sign In with Google Flow. - /// - /// Throws a SignInWithGoogleFailureInterface if an exception occurs. - /// {@endtemplate} - FutureOrResult signInWithGoogle(); - - /// {@template signin_pwd} - /// Signs in with the provided [email] and [password]. - /// - /// Throws a SignInWithEmailAndPasswordFailureInterface if - /// an exception occurs. - /// {@endtemplate} - FutureOrResult signInWithEmailAndPassword({ - required String email, - required String password, - }); - - /// {@template update_email} - /// Update or add [email]. - /// - /// Throws a UpdateEmailFailureInterface if - /// an exception occurs. - /// {@endtemplate} - FutureOrResult updateEmail({ - required String email, - }); - - /// {@template update_password} - /// Update or add [password]. - /// - /// Throws a UpdatePasswordFailureInterface if - /// an exception occurs. - /// {@endtemplate} - FutureOrResult updatePassword({ - required String password, - }); - - /// {@template reauthenticate} - /// Some security-sensitive actions—such as deleting an account, - /// setting a primary email address, and changing a password—require that - /// the user has recently signed in. - /// - /// Throws a ReauthenticateFailureInterface if - /// an exception occurs. - /// {@endtemplate} - FutureOrResult reauthenticateWithCredential(); - - /// {@template signout} - /// Signs out the current user. - /// It also clears the cache and the associated data. - /// {@endtemplate} - FutureOrResult signOut(); - - /// {@template refresh} - /// Refreshes the current user, if signed in. - /// {@endtemplate} - FutureOrResult refresh(); - - /// {@template stream_account} - /// Stream of [AccountWrapper] which will emit the current account when - /// the authentication state changes. - /// - /// Emits [AccountWrapper] with null [Account] if the user is not - /// authenticated. - /// {@endtemplate} - Stream>> streamAccount(); - - Stream changes(); - - FutureOrResult getIdentityToken(); - - FutureOrResult getAccount(); - FutureOrResult setAccount(Account account); - - FutureOrResult getData(); - FutureOrResult setData(T? data); - - FutureOrResult> getCache(); - FutureOrResult destroyCache(); - - FutureOrResult addAuthChangeListener(AuthChangeListener listener); - FutureOrResult removeAuthChangeListener(); } diff --git a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart index 8ff4eae1..8565338e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart +++ b/packages/wyatt_authentication_bloc/lib/src/domain/repositories/repositories.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart b/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart index 95e85224..478b8ad0 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/authentication/authentication.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 4a19e6a9..19e77c20 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,10 +17,10 @@ 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/account_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart'; import 'package:wyatt_authentication_bloc/src/features/authentication/cubit/authentication_cubit.dart'; -class AuthenticationBuilder extends StatelessWidget { +class AuthenticationBuilder extends StatelessWidget { const AuthenticationBuilder({ required this.authenticated, required this.unauthenticated, @@ -30,18 +30,18 @@ class AuthenticationBuilder extends StatelessWidget { final Widget Function( BuildContext context, - AccountWrapper accountWrapper, + SessionWrapper sessionWrapper, ) authenticated; final Widget Function(BuildContext context) unauthenticated; final Widget Function(BuildContext context) unknown; @override Widget build(BuildContext context) => - BlocBuilder, AuthenticationState>( + BlocBuilder, AuthenticationState>( builder: (context, state) { if (state.status == AuthenticationStatus.authenticated) { - if (state.accountWrapper != null) { - return authenticated(context, state.accountWrapper!); + if (state.wrapper != null) { + return authenticated(context, state.wrapper!); } 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 32b00997..8a7dc406 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,56 +18,230 @@ import 'dart:async'; import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/enums/authentication_status.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account_wrapper.dart'; +import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart'; import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; part 'authentication_state.dart'; -class AuthenticationCubit extends 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. +abstract class AuthenticationCubit + extends Cubit> { AuthenticationCubit({ required this.authenticationRepository, }) : super(const AuthenticationState.unknown()) { _listenForAuthenticationChanges(); } - final AuthenticationRepository authenticationRepository; + final AuthenticationRepository authenticationRepository; + + SessionWrapper? latestSession; void _listenForAuthenticationChanges() { - authenticationRepository.streamAccount().listen((accountFutureResult) { - accountFutureResult.fold( - (value) { - if (value.account.isNotNull) { - emit(AuthenticationState.authenticated(value)); - return; - } - authenticationRepository.destroyCache(); - emit(AuthenticationState.unauthenticated()); - return; - }, - (error) { - authenticationRepository.destroyCache(); - emit(AuthenticationState.unauthenticated()); - return; - }, - ); + authenticationRepository.sessionStream().asyncMap((wrapper) async { + final event = wrapper.event; + if (event is SignedInFromCacheEvent) { + final customRoutineResult = await onSignInFromCache(wrapper); + + if (customRoutineResult.isOk) { + final account = event.account; + final sessionData = customRoutineResult.ok; + + final signedInSession = SessionWrapper( + event: SignedInFromCacheEvent(account: account), + session: Session( + 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; + } + emit(AuthenticationState.unauthenticated()); + return; }); } - /// If authenticated, re-emits state with data freshly loaded from cache. - FutureOr reloadCache() async { - if (state.status == AuthenticationStatus.authenticated) { - final data = await authenticationRepository.getCache(); - emit( - data.fold( - AuthenticationState.authenticated, - (error) => state, + /// {@macro refresh} + FutureOr refresh() async { + final refreshedAccount = await authenticationRepository.refresh(); + final customRoutineResult = await onRefresh(refreshedAccount); + + if (refreshedAccount.isOk && customRoutineResult.isOk) { + final account = refreshedAccount.ok!; + final sessionData = customRoutineResult.ok; + + final refreshedSession = SessionWrapper( + event: RefreshedEvent(account: account), + session: Session( + account: account, + data: sessionData, ), ); + + authenticationRepository.addSession(refreshedSession); + + return; + } + + if (refreshedAccount.isErr) { + addError(refreshedAccount.err!); + + return; + } + + if (customRoutineResult.isErr) { + addError(customRoutineResult.err!); + + return; } } - FutureOr signOut() { - authenticationRepository.signOut(); + /// {@macro reauthenticate} + FutureOr reauthenticate() async { + final reauthenticatedAccount = + await authenticationRepository.reauthenticate(); + final customRoutineResult = await onReauthenticate(reauthenticatedAccount); + + if (reauthenticatedAccount.isOk && customRoutineResult.isOk) { + final account = reauthenticatedAccount.ok!; + final sessionData = customRoutineResult.ok; + + final reauthenticatedSession = SessionWrapper( + event: ReauthenticatedEvent(account: account), + session: Session( + account: account, + data: sessionData, + ), + ); + + authenticationRepository.addSession(reauthenticatedSession); + + return; + } + + if (reauthenticatedAccount.isErr) { + addError(reauthenticatedAccount.err!); + + return; + } + + if (customRoutineResult.isErr) { + addError(customRoutineResult.err!); + + return; + } } + + /// {@macro signout} + FutureOr signOut() async { + final customRoutine = CustomRoutine( + // ignore: unnecessary_lambdas + routine: () => authenticationRepository.signOut(), + attachedLogic: (routineResult) => onSignOut(), + onError: (error) => addError(error!), + onSuccess: (result, data) => authenticationRepository + .addSession(const SessionWrapper(event: SignedOutEvent())), + ); + + customRoutine.call(); + + final signOut = await authenticationRepository.signOut(); + + final customRoutineResult = await onSignOut(); + + if (signOut.isOk && customRoutineResult.isOk) { + authenticationRepository + .addSession(const SessionWrapper(event: SignedOutEvent())); + + return; + } + + if (signOut.isErr) { + addError(signOut.err!); + + return; + } + + if (customRoutineResult.isErr) { + addError(customRoutineResult.err!); + + return; + } + } + + /// {@macro delete} + FutureOr delete() async { + final signOut = await authenticationRepository.delete(); + + final customRoutineResult = await onDelete(); + + if (signOut.isOk && customRoutineResult.isOk) { + authenticationRepository + .addSession(const SessionWrapper(event: DeletedEvent())); + + return; + } + + if (signOut.isErr) { + addError(signOut.err!); + + return; + } + + if (customRoutineResult.isErr) { + addError(customRoutineResult.err!); + + return; + } + } + + /// Returns latest session wrapper. + /// + /// Contains latest event and latest session data (account + extra data) + SessionWrapper? 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); + + /// This callback is triggered when the account is refreshed. + /// + /// For example: when the access token is refreshed. + FutureOrResult onRefresh(Result result); + + /// This callback is triggered when the account is re-authenticated + /// + /// For example: when the user is logged in and sign in + /// from an another provider + FutureOrResult onReauthenticate(Result result); + + /// This callback is triggered when the user is logged out. + /// + /// For example: when the user clicks on the logout button. + FutureOrResult onSignOut(); + + /// This callback is triggered when the current account is deleted from + /// the remote. + /// + /// For example: when the user wants to delete his account from Firebase + FutureOrResult onDelete(); } 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 a5733bf2..cf672a4c 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,27 +16,27 @@ part of 'authentication_cubit.dart'; -class AuthenticationState extends Equatable { - const AuthenticationState.unauthenticated() - : this._(status: AuthenticationStatus.unauthenticated); +class AuthenticationState extends Equatable { + const AuthenticationState._(this.status, this.wrapper); - const AuthenticationState.authenticated(AccountWrapper accountWrapper) + const AuthenticationState.unauthenticated() + : this._(AuthenticationStatus.unauthenticated, null); + + const AuthenticationState.authenticated(SessionWrapper sessionWrapper) : this._( - status: AuthenticationStatus.authenticated, - accountWrapper: accountWrapper, + AuthenticationStatus.authenticated, + sessionWrapper, ); const AuthenticationState.unknown() - : this._(status: AuthenticationStatus.unknown); + : this._(AuthenticationStatus.unknown, null); - const AuthenticationState._({required this.status, this.accountWrapper}); final AuthenticationStatus status; - final AccountWrapper? accountWrapper; + final SessionWrapper? wrapper; @override - List get props => [status, accountWrapper]; + List get props => [status, wrapper]; @override - String toString() => - 'AuthenticationState(status: $status, accountWrapper: $accountWrapper)'; + bool? get stringify => true; } diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart index 2bb77e9c..0de3bdf3 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/builder/email_verification_builder.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 bb40411b..986b2bc9 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -23,12 +23,12 @@ import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; part 'email_verification_state.dart'; -class EmailVerificationCubit extends Cubit { +class EmailVerificationCubit extends Cubit { EmailVerificationCubit({ required this.authenticationRepository, }) : super(const EmailVerificationState()); - final AuthenticationRepository authenticationRepository; + final AuthenticationRepository authenticationRepository; FutureOr sendEmailVerification() async { emit(state.copyWith(status: FormStatus.submissionInProgress)); @@ -59,18 +59,20 @@ class EmailVerificationCubit extends Cubit { return; } - final currentAccount = await authenticationRepository.getAccount(); - emit( - currentAccount.fold( - (value) => state.copyWith( - isVerified: value.emailVerified, + final wrapper = await authenticationRepository.sessionStream().last; + final currentAccount = wrapper.session?.account; + if (currentAccount != null) { + emit( + state.copyWith( + isVerified: currentAccount.emailVerified, status: FormStatus.submissionSuccess, ), - (error) => EmailVerificationState( - errorMessage: error.message, - status: FormStatus.submissionFailure, - ), - ), - ); + ); + } else { + const EmailVerificationState( + errorMessage: 'No current session', + status: FormStatus.submissionFailure, + ); + } } } 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 5f9382ac..c78db5b7 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,5 +1,5 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart index 5624d94e..13ff15c5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/email_verification/email_verification.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/features.dart b/packages/wyatt_authentication_bloc/lib/src/features/features.dart index bd39a7f6..435d4d30 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/features.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/features.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart index fd942bdf..160f10db 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart index 5c5205dd..cace663f 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/cubit/password_reset_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart index 43919e02..f9039274 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/password_reset/password_reset.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart index b1446b36..03392126 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/base_sign_in_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ part of 'sign_in_cubit.dart'; -abstract class BaseSignInCubit extends FormDataCubit { +abstract class BaseSignInCubit extends FormDataCubit { BaseSignInCubit({ required this.authenticationRepository, }) : super( @@ -25,7 +25,7 @@ abstract class BaseSignInCubit extends FormDataCubit { .accessForm(AuthFormName.signInForm), ), ); - final AuthenticationRepository authenticationRepository; + final AuthenticationRepository authenticationRepository; FormRepository get formRepository => authenticationRepository.formRepository; @override 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 486ed946..97df97e0 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,13 +17,13 @@ import 'dart:async'; 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/entities.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -mixin SignInAnonymously on BaseSignInCubit { - FutureOrResult onSignInAnonymously( +mixin SignInAnonymously on BaseSignInCubit { + FutureOrResult onSignInAnonymously( Result result, WyattForm form, ); @@ -38,10 +38,10 @@ mixin SignInAnonymously on BaseSignInCubit { final result = await authenticationRepository.signInAnonymously(); - // Here custom code - final callbackResponse = await onSignInAnonymously(result, form); - if (callbackResponse.isErr) { - final error = callbackResponse.err!; + // Custom routine + final customRoutineResult = await onSignInAnonymously(result, form); + if (customRoutineResult.isErr) { + final error = customRoutineResult.err!; emit( SignInState( form: form, @@ -49,8 +49,34 @@ mixin SignInAnonymously on BaseSignInCubit { status: FormStatus.submissionFailure, ), ); + addError(error); } + // Check result + if (result.isErr) { + final error = result.err!; + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + } + + final account = result.ok!; + + final signedInSession = SessionWrapper( + event: SignedInEvent(account: account), + session: Session( + account: account, + data: customRoutineResult.ok, + ), + ); + + authenticationRepository.addSession(signedInSession); + emit( result.fold( (value) => 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 9a1d66e3..4c868911 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,13 +18,13 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/domain/domain.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -mixin SignInWithEmailPassword on BaseSignInCubit { - FutureOrResult onSignInWithEmailAndPassword( +mixin SignInWithEmailPassword on BaseSignInCubit { + FutureOrResult onSignInWithEmailAndPassword( Result result, WyattForm form, ); @@ -111,10 +111,13 @@ mixin SignInWithEmailPassword on BaseSignInCubit { password: password!, ); - // Here custom code - final callbackResponse = await onSignInWithEmailAndPassword(result, form); - if (callbackResponse.isErr) { - final error = callbackResponse.err!; + // Custom routine + final customRoutineResult = await onSignInWithEmailAndPassword( + result, + form, + ); + if (customRoutineResult.isErr) { + final error = customRoutineResult.err!; emit( SignInState( form: form, @@ -122,8 +125,34 @@ mixin SignInWithEmailPassword on BaseSignInCubit { status: FormStatus.submissionFailure, ), ); + addError(error); } + // Check result + if (result.isErr) { + final error = result.err!; + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + } + + final account = result.ok!; + + final signedInSession = SessionWrapper( + event: SignedInEvent(account: account), + session: Session( + account: account, + data: customRoutineResult.ok, + ), + ); + + authenticationRepository.addSession(signedInSession); + emit( result.fold( (value) => 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 b625534a..444e35c3 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -17,13 +17,13 @@ import 'dart:async'; 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/entities.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -mixin SignInWithGoogle on BaseSignInCubit { - FutureOrResult onSignInWithGoogle( +mixin SignInWithGoogle on BaseSignInCubit { + FutureOrResult onSignInWithGoogle( Result result, WyattForm form, ); @@ -37,10 +37,13 @@ mixin SignInWithGoogle on BaseSignInCubit { final result = await authenticationRepository.signInWithGoogle(); - // Here custom code - final callbackResponse = await onSignInWithGoogle(result, form); - if (callbackResponse.isErr) { - final error = callbackResponse.err!; + // Custom routine + final customRoutineResult = await onSignInWithGoogle( + result, + form, + ); + if (customRoutineResult.isErr) { + final error = customRoutineResult.err!; emit( SignInState( form: form, @@ -48,8 +51,34 @@ mixin SignInWithGoogle on BaseSignInCubit { status: FormStatus.submissionFailure, ), ); + addError(error); } + // Check result + if (result.isErr) { + final error = result.err!; + emit( + SignInState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + } + + final account = result.ok!; + + final signedInSession = SessionWrapper( + event: SignedInEvent(account: account), + session: Session( + account: account, + data: customRoutineResult.ok, + ), + ); + + authenticationRepository.addSession(signedInSession); + emit( result.fold( (value) => diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart index 3d171f9d..b67f4db6 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,39 +18,43 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; +import 'package:wyatt_authentication_bloc/src/core/constants/form_name.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_anonymously.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_with_email_password.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/mixin/sign_in_with_google.dart'; -import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; part 'base_sign_in_cubit.dart'; part 'sign_in_state.dart'; -class SignInCubit extends BaseSignInCubit +/// Fully featured sign in cubit. +class SignInCubit extends BaseSignInCubit with - SignInAnonymously, - SignInWithEmailPassword, - SignInWithGoogle { + SignInAnonymously, + SignInWithEmailPassword, + SignInWithGoogle { SignInCubit({required super.authenticationRepository}); @override - FutureOrResult onSignInAnonymously( + FutureOrResult onSignInAnonymously( Result result, WyattForm form, ) => const Ok(null); @override - FutureOrResult onSignInWithEmailAndPassword( + FutureOrResult onSignInWithEmailAndPassword( Result result, WyattForm form, ) => const Ok(null); @override - FutureOrResult onSignInWithGoogle( + FutureOrResult onSignInWithGoogle( Result result, WyattForm form, ) => diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart index d98472ad..18f5b6da 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/cubit/sign_in_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart index e51a1edd..d399142e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/listener/sign_in_listener.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart index 88fb9a39..37336de7 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_in/sign_in.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,5 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +export 'cubit/mixin/sign_in_anonymously.dart'; +export 'cubit/mixin/sign_in_with_email_password.dart'; +export 'cubit/mixin/sign_in_with_google.dart'; export 'cubit/sign_in_cubit.dart'; export 'listener/sign_in_listener.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart index 9aaad484..3040d1ab 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/base_sign_up_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ part of 'sign_up_cubit.dart'; -abstract class BaseSignUpCubit extends FormDataCubit { +abstract class BaseSignUpCubit extends FormDataCubit { BaseSignUpCubit({ required this.authenticationRepository, }) : super( @@ -25,7 +25,7 @@ abstract class BaseSignUpCubit extends FormDataCubit { .accessForm(AuthFormName.signUpForm), ), ); - final AuthenticationRepository authenticationRepository; + final AuthenticationRepository authenticationRepository; FormRepository get formRepository => authenticationRepository.formRepository; @override 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 6952a01c..9c17deac 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -18,13 +18,13 @@ import 'dart:async'; import 'package:wyatt_architecture/wyatt_architecture.dart'; import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart'; -import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart'; +import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart'; import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/sign_up_cubit.dart'; import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; import 'package:wyatt_type_utils/wyatt_type_utils.dart'; -mixin SignUpWithEmailPassword on BaseSignUpCubit { - FutureOrResult onSignUpWithEmailAndPassword( +mixin SignUpWithEmailPassword on BaseSignUpCubit { + FutureOrResult onSignUpWithEmailAndPassword( Result result, WyattForm form, ); @@ -97,15 +97,18 @@ mixin SignUpWithEmailPassword on BaseSignUpCubit { ); } - final result = await authenticationRepository.signUp( + final result = await authenticationRepository.signUpWithEmailAndPassword( email: email!, password: password!, ); - // Here custom code on sign up - final callbackResponse = await onSignUpWithEmailAndPassword(result, form); - if (callbackResponse.isErr) { - final error = callbackResponse.err!; + // Custom routine + final customRoutineResult = await onSignUpWithEmailAndPassword( + result, + form, + ); + if (customRoutineResult.isErr) { + final error = customRoutineResult.err!; emit( SignUpState( form: form, @@ -113,13 +116,34 @@ mixin SignUpWithEmailPassword on BaseSignUpCubit { status: FormStatus.submissionFailure, ), ); + addError(error); } - await authenticationRepository.signInWithEmailAndPassword( - email: email, - password: password, + // Check result + if (result.isErr) { + final error = result.err!; + emit( + SignUpState( + form: form, + errorMessage: error.message, + status: FormStatus.submissionFailure, + ), + ); + addError(error); + } + + final account = result.ok!; + + final signedUpSession = SessionWrapper( + event: SignedUpEvent(account: account), + session: Session( + account: account, + data: customRoutineResult.ok, + ), ); + authenticationRepository.addSession(signedUpSession); + emit( result.fold( (value) => SignUpState( diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart index df2766ac..49052a16 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_cubit.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -28,12 +28,12 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart'; part 'base_sign_up_cubit.dart'; part 'sign_up_state.dart'; -class SignUpCubit extends BaseSignUpCubit - with SignUpWithEmailPassword { +class SignUpCubit extends BaseSignUpCubit + with SignUpWithEmailPassword { SignUpCubit({required super.authenticationRepository}); @override - FutureOrResult onSignUpWithEmailAndPassword( + FutureOrResult onSignUpWithEmailAndPassword( Result result, WyattForm form, ) => diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart index 40c870c5..3edd1fe5 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/cubit/sign_up_state.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart index 925f0294..1e4cc616 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/listener/sign_up_listener.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart index 0eb01f0e..21c5895e 100644 --- a/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart +++ b/packages/wyatt_authentication_bloc/lib/src/features/sign_up/sign_up.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify @@ -14,5 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +export 'cubit/mixin/sign_up_with_email_password.dart'; export 'cubit/sign_up_cubit.dart'; export 'listener/sign_up_listener.dart'; diff --git a/packages/wyatt_authentication_bloc/lib/src/src.dart b/packages/wyatt_authentication_bloc/lib/src/src.dart index 3a660ea4..18df157b 100644 --- a/packages/wyatt_authentication_bloc/lib/src/src.dart +++ b/packages/wyatt_authentication_bloc/lib/src/src.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart b/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart index d853a49b..f8151ff0 100644 --- a/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart +++ b/packages/wyatt_authentication_bloc/lib/wyatt_authentication_bloc.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 e836bd4f..45f478ba 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 a85c7998..8f9897f2 100644 --- a/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/authentication/authentication_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify 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 e07a4f2d..6d2891d8 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 @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart index 37e030b4..cf779daa 100644 --- a/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/email_verification/email_verification_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart index e28ecb73..670fd175 100644 --- a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart index 661ea241..518be2dc 100644 --- a/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/password_reset/password_reset_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart index fd5623a0..a8d7feef 100644 --- a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart index e55d92bd..30f40cb7 100644 --- a/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_in/sign_in_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart index 7cf7d02e..3c717085 100644 --- a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_cubit_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify diff --git a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart index 6e67399a..89380d66 100644 --- a/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart +++ b/packages/wyatt_authentication_bloc/test/sign_up/sign_up_state_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2022 WYATT GROUP +// Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify