feat(auth): Refactor AuthRepositoryImpl and ProfileSetupRepositoryImpl to use DataConnectService for authentication and data operations

This commit is contained in:
Achintha Isuru
2026-02-16 15:47:01 -05:00
parent 3245c957f6
commit d0585d12ab
3 changed files with 76 additions and 74 deletions

View File

@@ -10,20 +10,14 @@ import '../../domain/ui_entities/auth_mode.dart';
import '../../domain/repositories/auth_repository_interface.dart'; import '../../domain/repositories/auth_repository_interface.dart';
/// Implementation of [AuthRepositoryInterface]. /// Implementation of [AuthRepositoryInterface].
class AuthRepositoryImpl class AuthRepositoryImpl implements AuthRepositoryInterface {
with DataErrorHandler AuthRepositoryImpl() : _service = DataConnectService.instance;
implements AuthRepositoryInterface {
AuthRepositoryImpl({
required this.firebaseAuth,
required this.dataConnect,
});
final FirebaseAuth firebaseAuth; final DataConnectService _service;
final ExampleConnector dataConnect;
Completer<String?>? _pendingVerification; Completer<String?>? _pendingVerification;
@override @override
Stream<domain.User?> get currentUser => firebaseAuth Stream<domain.User?> get currentUser => _service.auth
.authStateChanges() .authStateChanges()
.map((User? firebaseUser) { .map((User? firebaseUser) {
if (firebaseUser == null) { if (firebaseUser == null) {
@@ -44,7 +38,7 @@ class AuthRepositoryImpl
final Completer<String?> completer = Completer<String?>(); final Completer<String?> completer = Completer<String?>();
_pendingVerification = completer; _pendingVerification = completer;
await firebaseAuth.verifyPhoneNumber( await _service.auth.verifyPhoneNumber(
phoneNumber: phoneNumber, phoneNumber: phoneNumber,
verificationCompleted: (PhoneAuthCredential credential) { verificationCompleted: (PhoneAuthCredential credential) {
// Skip auto-verification for test numbers to allow manual code entry // Skip auto-verification for test numbers to allow manual code entry
@@ -101,7 +95,8 @@ class AuthRepositoryImpl
@override @override
Future<void> signOut() { Future<void> signOut() {
StaffSessionStore.instance.clear(); StaffSessionStore.instance.clear();
return firebaseAuth.signOut(); _service.clearCache();
return _service.auth.signOut();
} }
/// Verifies an OTP code and returns the authenticated user. /// Verifies an OTP code and returns the authenticated user.
@@ -115,10 +110,10 @@ class AuthRepositoryImpl
verificationId: verificationId, verificationId: verificationId,
smsCode: smsCode, smsCode: smsCode,
); );
final UserCredential userCredential = await executeProtected( final UserCredential userCredential = await _service.run(
() async { () async {
try { try {
return await firebaseAuth.signInWithCredential(credential); return await _service.auth.signInWithCredential(credential);
} on FirebaseAuthException catch (e) { } on FirebaseAuthException catch (e) {
if (e.code == 'invalid-verification-code') { if (e.code == 'invalid-verification-code') {
throw const domain.InvalidCredentialsException( throw const domain.InvalidCredentialsException(
@@ -128,45 +123,56 @@ class AuthRepositoryImpl
rethrow; rethrow;
} }
}, },
requiresAuthentication: false,
); );
final User? firebaseUser = userCredential.user; final User? firebaseUser = userCredential.user;
if (firebaseUser == null) { if (firebaseUser == null) {
throw const domain.SignInFailedException( throw const domain.SignInFailedException(
technicalMessage: 'Phone verification failed, no Firebase user received.', technicalMessage:
'Phone verification failed, no Firebase user received.',
); );
} }
final QueryResult<GetUserByIdData, GetUserByIdVariables> response = final QueryResult<GetUserByIdData, GetUserByIdVariables> response =
await executeProtected(() => dataConnect await _service.run(
.getUserById( () => _service.connector
id: firebaseUser.uid, .getUserById(
) id: firebaseUser.uid,
.execute()); )
.execute(),
requiresAuthentication: false,
);
final GetUserByIdUser? user = response.data.user; final GetUserByIdUser? user = response.data.user;
GetStaffByUserIdStaffs? staffRecord; GetStaffByUserIdStaffs? staffRecord;
if (mode == AuthMode.signup) { if (mode == AuthMode.signup) {
if (user == null) { if (user == null) {
await executeProtected(() => dataConnect await _service.run(
.createUser( () => _service.connector
id: firebaseUser.uid, .createUser(
role: UserBaseRole.USER, id: firebaseUser.uid,
) role: UserBaseRole.USER,
.userRole('STAFF') )
.execute()); .userRole('STAFF')
.execute(),
requiresAuthentication: false,
);
} else { } else {
// User exists in PostgreSQL. Check if they have a STAFF profile. // User exists in PostgreSQL. Check if they have a STAFF profile.
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables> final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables>
staffResponse = await executeProtected(() => dataConnect staffResponse = await _service.run(
.getStaffByUserId( () => _service.connector
userId: firebaseUser.uid, .getStaffByUserId(
) userId: firebaseUser.uid,
.execute()); )
.execute(),
requiresAuthentication: false,
);
if (staffResponse.data.staffs.isNotEmpty) { if (staffResponse.data.staffs.isNotEmpty) {
// If profile exists, they should use Login mode. // If profile exists, they should use Login mode.
await firebaseAuth.signOut(); await _service.auth.signOut();
throw const domain.AccountExistsException( throw const domain.AccountExistsException(
technicalMessage: technicalMessage:
'This user already has a staff profile. Please log in.', 'This user already has a staff profile. Please log in.',
@@ -177,35 +183,44 @@ class AuthRepositoryImpl
// they are allowed to "Sign Up" for Staff. // they are allowed to "Sign Up" for Staff.
// We update their userRole to 'BOTH'. // We update their userRole to 'BOTH'.
if (user.userRole == 'BUSINESS') { if (user.userRole == 'BUSINESS') {
await executeProtected(() => await _service.run(
dataConnect.updateUser(id: firebaseUser.uid).userRole('BOTH').execute()); () => _service.connector
.updateUser(id: firebaseUser.uid)
.userRole('BOTH')
.execute(),
requiresAuthentication: false,
);
} }
} }
} else { } else {
if (user == null) { if (user == null) {
await firebaseAuth.signOut(); await _service.auth.signOut();
throw const domain.UserNotFoundException( throw const domain.UserNotFoundException(
technicalMessage: 'Authenticated user profile not found in database.', technicalMessage: 'Authenticated user profile not found in database.',
); );
} }
// Allow STAFF or BOTH roles to log in to the Staff App // Allow STAFF or BOTH roles to log in to the Staff App
if (user.userRole != 'STAFF' && user.userRole != 'BOTH') { if (user.userRole != 'STAFF' && user.userRole != 'BOTH') {
await firebaseAuth.signOut(); await _service.auth.signOut();
throw const domain.UnauthorizedAppException( throw const domain.UnauthorizedAppException(
technicalMessage: 'User is not authorized for this app.', technicalMessage: 'User is not authorized for this app.',
); );
} }
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables> final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables>
staffResponse = await executeProtected(() => dataConnect staffResponse = await _service.run(
.getStaffByUserId( () => _service.connector
userId: firebaseUser.uid, .getStaffByUserId(
) userId: firebaseUser.uid,
.execute()); )
.execute(),
requiresAuthentication: false,
);
if (staffResponse.data.staffs.isEmpty) { if (staffResponse.data.staffs.isEmpty) {
await firebaseAuth.signOut(); await _service.auth.signOut();
throw const domain.UserNotFoundException( throw const domain.UserNotFoundException(
technicalMessage: 'Your account is not registered yet. Please register first.', technicalMessage:
'Your account is not registered yet. Please register first.',
); );
} }
staffRecord = staffResponse.data.staffs.first; staffRecord = staffResponse.data.staffs.first;

View File

@@ -1,18 +1,13 @@
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:krow_data_connect/krow_data_connect.dart'; import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc; import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:krow_domain/krow_domain.dart'; import 'package:krow_domain/krow_domain.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import '../../domain/repositories/profile_setup_repository.dart'; import '../../domain/repositories/profile_setup_repository.dart';
class ProfileSetupRepositoryImpl implements ProfileSetupRepository { class ProfileSetupRepositoryImpl implements ProfileSetupRepository {
final auth.FirebaseAuth _firebaseAuth; final DataConnectService _service;
final ExampleConnector _dataConnect;
ProfileSetupRepositoryImpl({ ProfileSetupRepositoryImpl() : _service = DataConnectService.instance;
required auth.FirebaseAuth firebaseAuth,
required ExampleConnector dataConnect,
}) : _firebaseAuth = firebaseAuth,
_dataConnect = dataConnect;
@override @override
Future<void> submitProfile({ Future<void> submitProfile({
@@ -23,17 +18,19 @@ class ProfileSetupRepositoryImpl implements ProfileSetupRepository {
required List<String> industries, required List<String> industries,
required List<String> skills, required List<String> skills,
}) async { }) async {
final auth.User? firebaseUser = _firebaseAuth.currentUser; return _service.run(() async {
if (firebaseUser == null) { final auth.User? firebaseUser = _service.auth.currentUser;
throw Exception('User not authenticated.'); if (firebaseUser == null) {
} throw const NotAuthenticatedException(
technicalMessage: 'User not authenticated.');
}
final StaffSession? session = StaffSessionStore.instance.session; final StaffSession? session = StaffSessionStore.instance.session;
final String email = session?.user.email ?? ''; final String email = session?.user.email ?? '';
final String? phone = firebaseUser.phoneNumber; final String? phone = firebaseUser.phoneNumber;
final fdc.OperationResult<CreateStaffData, CreateStaffVariables> final fdc.OperationResult<CreateStaffData, CreateStaffVariables> result =
result = await _dataConnect await _service.connector
.createStaff( .createStaff(
userId: firebaseUser.uid, userId: firebaseUser.uid,
fullName: fullName, fullName: fullName,
@@ -63,5 +60,6 @@ class ProfileSetupRepositoryImpl implements ProfileSetupRepository {
StaffSession(user: session.user, staff: staff, ownerId: session.ownerId), StaffSession(user: session.user, staff: staff, ownerId: session.ownerId),
); );
} }
});
} }
} }

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_core/core.dart'; import 'package:krow_core/core.dart';
import 'package:krow_data_connect/krow_data_connect.dart'; import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:staff_authentication/src/data/repositories_impl/auth_repository_impl.dart'; import 'package:staff_authentication/src/data/repositories_impl/auth_repository_impl.dart';
import 'package:staff_authentication/src/domain/repositories/auth_repository_interface.dart'; import 'package:staff_authentication/src/domain/repositories/auth_repository_interface.dart';
import 'package:staff_authentication/src/domain/usecases/sign_in_with_phone_usecase.dart'; import 'package:staff_authentication/src/domain/usecases/sign_in_with_phone_usecase.dart';
@@ -28,18 +27,8 @@ class StaffAuthenticationModule extends Module {
@override @override
void binds(Injector i) { void binds(Injector i) {
// Repositories // Repositories
i.addLazySingleton<AuthRepositoryInterface>( i.addLazySingleton<AuthRepositoryInterface>(AuthRepositoryImpl.new);
() => AuthRepositoryImpl( i.addLazySingleton<ProfileSetupRepository>(ProfileSetupRepositoryImpl.new);
firebaseAuth: firebase.FirebaseAuth.instance,
dataConnect: ExampleConnector.instance,
),
);
i.addLazySingleton<ProfileSetupRepository>(
() => ProfileSetupRepositoryImpl(
firebaseAuth: firebase.FirebaseAuth.instance,
dataConnect: ExampleConnector.instance,
),
);
i.addLazySingleton<PlaceRepository>(PlaceRepositoryImpl.new); i.addLazySingleton<PlaceRepository>(PlaceRepositoryImpl.new);
// UseCases // UseCases