first steps for auth in staff app

This commit is contained in:
José Salazar
2026-01-22 17:09:13 -05:00
parent 6e8578c3d7
commit 1b8bdf6bfe
2 changed files with 95 additions and 12 deletions

View File

@@ -1,34 +1,113 @@
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_domain/krow_domain.dart';
import 'dart:async';
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';
/// Implementation of [AuthRepositoryInterface].
class AuthRepositoryImpl implements AuthRepositoryInterface {
final AuthRepositoryMock mock;
final firebase.FirebaseAuth _firebaseAuth;
final dc.ExampleConnector _dataConnect;
AuthRepositoryImpl({required this.mock});
AuthRepositoryImpl({
required firebase.FirebaseAuth firebaseAuth,
required dc.ExampleConnector dataConnect,
}) : _firebaseAuth = firebaseAuth,
_dataConnect = dataConnect;
@override
Stream<User?> get currentUser => mock.currentUser;
Stream<domain.User?> get currentUser => _firebaseAuth
.authStateChanges()
.map((firebaseUser) {
if (firebaseUser == null) {
return null;
}
return domain.User(
id: firebaseUser.uid,
email: firebaseUser.email ?? '',
phone: firebaseUser.phoneNumber,
role: 'staff',
);
});
/// Signs in with a phone number and returns a verification ID.
@override
Future<String?> signInWithPhone({required String phoneNumber}) {
return mock.signInWithPhone(phoneNumber);
Future<String?> signInWithPhone({required String phoneNumber}) async {
final completer = Completer<String?>();
await _firebaseAuth.verifyPhoneNumber(
phoneNumber: phoneNumber,
verificationCompleted: (_) {},
verificationFailed: (e) {
if (!completer.isCompleted) {
completer.completeError(
Exception(e.message ?? 'Phone verification failed.'),
);
}
},
codeSent: (verificationId, _) {
if (!completer.isCompleted) {
completer.complete(verificationId);
}
},
codeAutoRetrievalTimeout: (verificationId) {
if (!completer.isCompleted) {
completer.complete(verificationId);
}
},
);
return completer.future;
}
/// Signs out the current user.
@override
Future<void> signOut() {
return mock.signOut();
return _firebaseAuth.signOut();
}
/// Verifies an OTP code and returns the authenticated user.
@override
Future<User?> verifyOtp({
Future<domain.User?> verifyOtp({
required String verificationId,
required String smsCode,
}) {
return mock.verifyOtp(verificationId, smsCode);
}) async {
final credential = firebase.PhoneAuthProvider.credential(
verificationId: verificationId,
smsCode: smsCode,
);
final userCredential = await _firebaseAuth.signInWithCredential(credential);
final firebaseUser = userCredential.user;
if (firebaseUser == null) {
throw Exception('Phone verification failed, no Firebase user received.');
}
final response = await _dataConnect.getUserById(
id: firebaseUser.uid,
).execute();
final user = response.data?.user;
if (user == null) {
await _firebaseAuth.signOut();
throw Exception('Authenticated user profile not found in database.');
}
if (user.userRole != 'STAFF') {
await _firebaseAuth.signOut();
throw Exception('User is not authorized for this app.');
}
final email = user.email ?? '';
if (email.isEmpty) {
await _firebaseAuth.signOut();
throw Exception('User email is missing in profile data.');
}
return domain.User(
id: user.id,
email: email,
phone: firebaseUser.phoneNumber,
role: user.role.stringValue,
);
}
}

View File

@@ -2,6 +2,7 @@ library staff_authentication;
import 'package:flutter_modular/flutter_modular.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,7 +29,10 @@ class StaffAuthenticationModule extends Module {
void binds(Injector i) {
// Repositories
i.addLazySingleton<AuthRepositoryInterface>(
() => AuthRepositoryImpl(mock: i.get<AuthRepositoryMock>()),
() => AuthRepositoryImpl(
firebaseAuth: firebase.FirebaseAuth.instance,
dataConnect: ExampleConnector.instance,
),
);
// UseCases