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';
|
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;
|
||||||
|
|||||||
@@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user