last part of auth

This commit is contained in:
José Salazar
2026-01-22 09:34:33 -05:00
parent e4986c2aee
commit 1b67bb21c8
3 changed files with 141 additions and 24 deletions

View File

@@ -6,9 +6,8 @@
/// TODO: These mocks currently do not implement any specific interfaces.
/// They will implement interfaces defined in feature packages once those are created.
export 'src/mocks/auth_repository_mock.dart';
// export 'src/mocks/auth_repository_mock.dart'; // Comentado, usaremos la implementación real
export 'src/mocks/staff_repository_mock.dart';
export 'src/mocks/business_repository_mock.dart';
export 'src/mocks/event_repository_mock.dart';
export 'src/mocks/skill_repository_mock.dart';
export 'src/mocks/financial_repository_mock.dart';
@@ -16,3 +15,6 @@ export 'src/mocks/rating_repository_mock.dart';
export 'src/mocks/support_repository_mock.dart';
export 'src/mocks/home_repository_mock.dart';
export 'src/data_connect_module.dart';
// Export the generated Data Connect SDK
export 'src/dataconnect_generated/generated.dart';

View File

@@ -1,5 +1,6 @@
library client_authentication;
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'src/data/repositories_impl/auth_repository_impl.dart';
@@ -28,7 +29,10 @@ class ClientAuthenticationModule extends Module {
void binds(Injector i) {
// Repositories
i.addLazySingleton<AuthRepositoryInterface>(
() => AuthRepositoryImpl(dataSource: i.get<AuthRepositoryMock>()),
() => AuthRepositoryImpl(
firebaseAuth: firebase.FirebaseAuth.instance,
dataConnect: ExampleConnector.instance,
),
);
// UseCases

View File

@@ -1,43 +1,154 @@
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_domain/krow_domain.dart';
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import 'package:krow_domain/krow_domain.dart' as domain;
import '../../domain/repositories/auth_repository_interface.dart';
/// Production-ready implementation of the [AuthRepositoryInterface].
/// Production-ready implementation of the [AuthRepositoryInterface] for the client app.
///
/// This implementation integrates with the [krow_data_connect] package to provide
/// authentication services. It delegates actual data operations to the
/// [AuthRepositoryMock] (or eventually the real implementation) injected from the app layer.
/// This implementation integrates with Firebase Authentication for user
/// identity management and Krow's Data Connect SDK for storing user profile data.
class AuthRepositoryImpl implements AuthRepositoryInterface {
/// The data source used for authentication operations.
final AuthRepositoryMock _dataSource;
final firebase.FirebaseAuth _firebaseAuth;
final dc.ExampleConnector _dataConnect;
/// Creates an [AuthRepositoryImpl] with the injected [dataSource] dependency.
AuthRepositoryImpl({required AuthRepositoryMock dataSource})
: _dataSource = dataSource;
/// Creates an [AuthRepositoryImpl] with the real dependencies.
AuthRepositoryImpl({
required firebase.FirebaseAuth firebaseAuth,
required dc.ExampleConnector dataConnect,
}) : _firebaseAuth = firebaseAuth,
_dataConnect = dataConnect;
@override
Future<User> signInWithEmail({
Future<domain.User> signInWithEmail({
required String email,
required String password,
}) {
return _dataSource.signInWithEmail(email, password);
}) async {
try {
final credential = await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
final firebaseUser = credential.user;
if (firebaseUser == null) {
throw Exception('Sign-in failed, no Firebase user received.');
}
return _getUserProfile(
firebaseUserId: firebaseUser.uid,
fallbackEmail: firebaseUser.email ?? email,
);
} on firebase.FirebaseAuthException catch (e) {
if (e.code == 'user-not-found' || e.code == 'wrong-password') {
throw Exception('Incorrect email or password.');
} else {
throw Exception('Authentication error: ${e.message}');
}
} catch (e) {
throw Exception('Failed to sign in and fetch user data: ${e.toString()}');
}
}
@override
Future<User> signUpWithEmail({
Future<domain.User> signUpWithEmail({
required String companyName,
required String email,
required String password,
}) {
return _dataSource.signUpWithEmail(email, password, companyName);
}) async {
try {
final credential = await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
final firebaseUser = credential.user;
if (firebaseUser == null) {
throw Exception('Sign-up failed, Firebase user could not be created.');
}
// Client-specific business logic:
// 1. Create a `Business` entity.
// 2. Create a `User` entity associated with the business.
final createBusinessResponse = await _dataConnect.createBusiness(
businessName: companyName,
userId: firebaseUser.uid,
rateGroup: dc.BusinessRateGroup.STANDARD,
status: dc.BusinessStatus.PENDING,
).execute();
final businessData = createBusinessResponse.data?.business_insert;
if (businessData == null) {
await firebaseUser.delete(); // Rollback if business creation fails
throw Exception('Business creation failed after Firebase user registration.');
}
final createUserResponse = await _dataConnect.createUser(
id: firebaseUser.uid,
role: dc.UserBaseRole.USER,
)
.email(email)
.userRole('BUSINESS')
.execute();
final newUserData = createUserResponse.data?.user_insert;
if (newUserData == null) {
await firebaseUser.delete(); // Rollback if user profile creation fails
// TODO: Also delete the created Business if this fails
throw Exception('User profile creation failed after Firebase user registration.');
}
return _getUserProfile(
firebaseUserId: firebaseUser.uid,
fallbackEmail: firebaseUser.email ?? email,
);
} on firebase.FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
throw Exception('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
throw Exception('An account already exists for that email address.');
} else {
throw Exception('Sign-up error: ${e.message}');
}
} catch (e) {
throw Exception('Failed to sign up and create user data: ${e.toString()}');
}
}
@override
Future<User> signInWithSocial({required String provider}) {
return _dataSource.signInWithSocial(provider);
Future<void> signOut() async {
try {
await _firebaseAuth.signOut();
} catch (e) {
throw Exception('Error signing out: ${e.toString()}');
}
}
@override
Future<void> signOut() => _dataSource.signOut();
Future<domain.User> signInWithSocial({required String provider}) {
throw UnimplementedError('Social authentication with $provider is not yet implemented.');
}
Future<domain.User> _getUserProfile({
required String firebaseUserId,
required String? fallbackEmail,
}) async {
final response = await _dataConnect.getUserById(id: firebaseUserId).execute();
final user = response.data?.user;
if (user == null) {
throw Exception('Authenticated user profile not found in database.');
}
final email = user.email ?? fallbackEmail;
if (email == null || email.isEmpty) {
throw Exception('User email is missing in profile data.');
}
return domain.User(
id: user.id,
email: email,
role: user.role.stringValue,
);
}
}