feat(auth): Refactor AuthRepositoryImpl and ProfileSetupRepositoryImpl to use DataConnectService for authentication and data operations
This commit is contained in:
@@ -10,20 +10,14 @@ import '../../domain/ui_entities/auth_mode.dart';
|
||||
import '../../domain/repositories/auth_repository_interface.dart';
|
||||
|
||||
/// Implementation of [AuthRepositoryInterface].
|
||||
class AuthRepositoryImpl
|
||||
with DataErrorHandler
|
||||
implements AuthRepositoryInterface {
|
||||
AuthRepositoryImpl({
|
||||
required this.firebaseAuth,
|
||||
required this.dataConnect,
|
||||
});
|
||||
class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
AuthRepositoryImpl() : _service = DataConnectService.instance;
|
||||
|
||||
final FirebaseAuth firebaseAuth;
|
||||
final ExampleConnector dataConnect;
|
||||
final DataConnectService _service;
|
||||
Completer<String?>? _pendingVerification;
|
||||
|
||||
@override
|
||||
Stream<domain.User?> get currentUser => firebaseAuth
|
||||
Stream<domain.User?> get currentUser => _service.auth
|
||||
.authStateChanges()
|
||||
.map((User? firebaseUser) {
|
||||
if (firebaseUser == null) {
|
||||
@@ -44,7 +38,7 @@ class AuthRepositoryImpl
|
||||
final Completer<String?> completer = Completer<String?>();
|
||||
_pendingVerification = completer;
|
||||
|
||||
await firebaseAuth.verifyPhoneNumber(
|
||||
await _service.auth.verifyPhoneNumber(
|
||||
phoneNumber: phoneNumber,
|
||||
verificationCompleted: (PhoneAuthCredential credential) {
|
||||
// Skip auto-verification for test numbers to allow manual code entry
|
||||
@@ -101,7 +95,8 @@ class AuthRepositoryImpl
|
||||
@override
|
||||
Future<void> signOut() {
|
||||
StaffSessionStore.instance.clear();
|
||||
return firebaseAuth.signOut();
|
||||
_service.clearCache();
|
||||
return _service.auth.signOut();
|
||||
}
|
||||
|
||||
/// Verifies an OTP code and returns the authenticated user.
|
||||
@@ -115,10 +110,10 @@ class AuthRepositoryImpl
|
||||
verificationId: verificationId,
|
||||
smsCode: smsCode,
|
||||
);
|
||||
final UserCredential userCredential = await executeProtected(
|
||||
final UserCredential userCredential = await _service.run(
|
||||
() async {
|
||||
try {
|
||||
return await firebaseAuth.signInWithCredential(credential);
|
||||
return await _service.auth.signInWithCredential(credential);
|
||||
} on FirebaseAuthException catch (e) {
|
||||
if (e.code == 'invalid-verification-code') {
|
||||
throw const domain.InvalidCredentialsException(
|
||||
@@ -128,45 +123,56 @@ class AuthRepositoryImpl
|
||||
rethrow;
|
||||
}
|
||||
},
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
final User? firebaseUser = userCredential.user;
|
||||
if (firebaseUser == null) {
|
||||
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 =
|
||||
await executeProtected(() => dataConnect
|
||||
.getUserById(
|
||||
id: firebaseUser.uid,
|
||||
)
|
||||
.execute());
|
||||
await _service.run(
|
||||
() => _service.connector
|
||||
.getUserById(
|
||||
id: firebaseUser.uid,
|
||||
)
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
final GetUserByIdUser? user = response.data.user;
|
||||
|
||||
GetStaffByUserIdStaffs? staffRecord;
|
||||
|
||||
if (mode == AuthMode.signup) {
|
||||
if (user == null) {
|
||||
await executeProtected(() => dataConnect
|
||||
.createUser(
|
||||
id: firebaseUser.uid,
|
||||
role: UserBaseRole.USER,
|
||||
)
|
||||
.userRole('STAFF')
|
||||
.execute());
|
||||
await _service.run(
|
||||
() => _service.connector
|
||||
.createUser(
|
||||
id: firebaseUser.uid,
|
||||
role: UserBaseRole.USER,
|
||||
)
|
||||
.userRole('STAFF')
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
} else {
|
||||
// User exists in PostgreSQL. Check if they have a STAFF profile.
|
||||
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables>
|
||||
staffResponse = await executeProtected(() => dataConnect
|
||||
.getStaffByUserId(
|
||||
userId: firebaseUser.uid,
|
||||
)
|
||||
.execute());
|
||||
staffResponse = await _service.run(
|
||||
() => _service.connector
|
||||
.getStaffByUserId(
|
||||
userId: firebaseUser.uid,
|
||||
)
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
|
||||
if (staffResponse.data.staffs.isNotEmpty) {
|
||||
// If profile exists, they should use Login mode.
|
||||
await firebaseAuth.signOut();
|
||||
await _service.auth.signOut();
|
||||
throw const domain.AccountExistsException(
|
||||
technicalMessage:
|
||||
'This user already has a staff profile. Please log in.',
|
||||
@@ -177,35 +183,44 @@ class AuthRepositoryImpl
|
||||
// they are allowed to "Sign Up" for Staff.
|
||||
// We update their userRole to 'BOTH'.
|
||||
if (user.userRole == 'BUSINESS') {
|
||||
await executeProtected(() =>
|
||||
dataConnect.updateUser(id: firebaseUser.uid).userRole('BOTH').execute());
|
||||
await _service.run(
|
||||
() => _service.connector
|
||||
.updateUser(id: firebaseUser.uid)
|
||||
.userRole('BOTH')
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (user == null) {
|
||||
await firebaseAuth.signOut();
|
||||
await _service.auth.signOut();
|
||||
throw const domain.UserNotFoundException(
|
||||
technicalMessage: 'Authenticated user profile not found in database.',
|
||||
);
|
||||
}
|
||||
// Allow STAFF or BOTH roles to log in to the Staff App
|
||||
if (user.userRole != 'STAFF' && user.userRole != 'BOTH') {
|
||||
await firebaseAuth.signOut();
|
||||
await _service.auth.signOut();
|
||||
throw const domain.UnauthorizedAppException(
|
||||
technicalMessage: 'User is not authorized for this app.',
|
||||
);
|
||||
}
|
||||
|
||||
final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables>
|
||||
staffResponse = await executeProtected(() => dataConnect
|
||||
.getStaffByUserId(
|
||||
userId: firebaseUser.uid,
|
||||
)
|
||||
.execute());
|
||||
staffResponse = await _service.run(
|
||||
() => _service.connector
|
||||
.getStaffByUserId(
|
||||
userId: firebaseUser.uid,
|
||||
)
|
||||
.execute(),
|
||||
requiresAuthentication: false,
|
||||
);
|
||||
if (staffResponse.data.staffs.isEmpty) {
|
||||
await firebaseAuth.signOut();
|
||||
await _service.auth.signOut();
|
||||
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;
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart' as auth;
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart' as auth;
|
||||
import '../../domain/repositories/profile_setup_repository.dart';
|
||||
|
||||
class ProfileSetupRepositoryImpl implements ProfileSetupRepository {
|
||||
final auth.FirebaseAuth _firebaseAuth;
|
||||
final ExampleConnector _dataConnect;
|
||||
final DataConnectService _service;
|
||||
|
||||
ProfileSetupRepositoryImpl({
|
||||
required auth.FirebaseAuth firebaseAuth,
|
||||
required ExampleConnector dataConnect,
|
||||
}) : _firebaseAuth = firebaseAuth,
|
||||
_dataConnect = dataConnect;
|
||||
ProfileSetupRepositoryImpl() : _service = DataConnectService.instance;
|
||||
|
||||
@override
|
||||
Future<void> submitProfile({
|
||||
@@ -23,17 +18,19 @@ class ProfileSetupRepositoryImpl implements ProfileSetupRepository {
|
||||
required List<String> industries,
|
||||
required List<String> skills,
|
||||
}) async {
|
||||
final auth.User? firebaseUser = _firebaseAuth.currentUser;
|
||||
if (firebaseUser == null) {
|
||||
throw Exception('User not authenticated.');
|
||||
}
|
||||
return _service.run(() async {
|
||||
final auth.User? firebaseUser = _service.auth.currentUser;
|
||||
if (firebaseUser == null) {
|
||||
throw const NotAuthenticatedException(
|
||||
technicalMessage: 'User not authenticated.');
|
||||
}
|
||||
|
||||
final StaffSession? session = StaffSessionStore.instance.session;
|
||||
final String email = session?.user.email ?? '';
|
||||
final String? phone = firebaseUser.phoneNumber;
|
||||
final StaffSession? session = StaffSessionStore.instance.session;
|
||||
final String email = session?.user.email ?? '';
|
||||
final String? phone = firebaseUser.phoneNumber;
|
||||
|
||||
final fdc.OperationResult<CreateStaffData, CreateStaffVariables>
|
||||
result = await _dataConnect
|
||||
final fdc.OperationResult<CreateStaffData, CreateStaffVariables> result =
|
||||
await _service.connector
|
||||
.createStaff(
|
||||
userId: firebaseUser.uid,
|
||||
fullName: fullName,
|
||||
@@ -63,5 +60,6 @@ class ProfileSetupRepositoryImpl implements ProfileSetupRepository {
|
||||
StaffSession(user: session.user, staff: staff, ownerId: session.ownerId),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.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/domain/repositories/auth_repository_interface.dart';
|
||||
import 'package:staff_authentication/src/domain/usecases/sign_in_with_phone_usecase.dart';
|
||||
@@ -28,18 +27,8 @@ class StaffAuthenticationModule extends Module {
|
||||
@override
|
||||
void binds(Injector i) {
|
||||
// Repositories
|
||||
i.addLazySingleton<AuthRepositoryInterface>(
|
||||
() => AuthRepositoryImpl(
|
||||
firebaseAuth: firebase.FirebaseAuth.instance,
|
||||
dataConnect: ExampleConnector.instance,
|
||||
),
|
||||
);
|
||||
i.addLazySingleton<ProfileSetupRepository>(
|
||||
() => ProfileSetupRepositoryImpl(
|
||||
firebaseAuth: firebase.FirebaseAuth.instance,
|
||||
dataConnect: ExampleConnector.instance,
|
||||
),
|
||||
);
|
||||
i.addLazySingleton<AuthRepositoryInterface>(AuthRepositoryImpl.new);
|
||||
i.addLazySingleton<ProfileSetupRepository>(ProfileSetupRepositoryImpl.new);
|
||||
i.addLazySingleton<PlaceRepository>(PlaceRepositoryImpl.new);
|
||||
|
||||
// UseCases
|
||||
|
||||
Reference in New Issue
Block a user