281 lines
9.2 KiB
Dart
281 lines
9.2 KiB
Dart
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'session_service.dart';
|
|
|
|
/// Service for handling Firebase Authentication
|
|
class AuthService {
|
|
static final FirebaseAuth _auth = FirebaseAuth.instance;
|
|
static final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
|
|
|
/// Get current user
|
|
static User? get currentUser {
|
|
return _auth.currentUser;
|
|
}
|
|
|
|
/// Criar documento do usuário na Firestore após signup
|
|
static Future<void> createUserRole(
|
|
String uid,
|
|
String role, {
|
|
String? classId,
|
|
String? schoolClassId,
|
|
String? displayName,
|
|
}) async {
|
|
try {
|
|
print('DEBUG: Criando documento users/$uid com role: $role');
|
|
final Map<String, dynamic> data = {
|
|
'role': role,
|
|
'createdAt': FieldValue.serverTimestamp(),
|
|
};
|
|
if (classId != null && classId.isNotEmpty) {
|
|
data['classId'] = classId;
|
|
}
|
|
if (schoolClassId != null && schoolClassId.isNotEmpty) {
|
|
data['schoolClassId'] = schoolClassId;
|
|
}
|
|
if (displayName != null && displayName.isNotEmpty) {
|
|
data['displayName'] = displayName;
|
|
}
|
|
await _firestore.collection('users').doc(uid).set(data);
|
|
print('DEBUG: Documento criado com sucesso');
|
|
} catch (e) {
|
|
print('DEBUG: Erro ao criar documento: $e');
|
|
throw Exception('Erro ao criar perfil do usuário');
|
|
}
|
|
}
|
|
|
|
/// Criar inscrição do aluno na turma escolhida
|
|
static Future<void> createEnrollment({
|
|
required String studentId,
|
|
required String classId,
|
|
required String studentName,
|
|
}) async {
|
|
try {
|
|
print(
|
|
'DEBUG: Criando enrollment para student=$studentId, class=$classId',
|
|
);
|
|
final existing = await _firestore
|
|
.collection('enrollments')
|
|
.where('studentId', isEqualTo: studentId)
|
|
.where('classId', isEqualTo: classId)
|
|
.limit(1)
|
|
.get();
|
|
if (existing.docs.isNotEmpty) {
|
|
print('DEBUG: Enrollment já existe, ignorando');
|
|
return;
|
|
}
|
|
await _firestore.collection('enrollments').add({
|
|
'classId': classId,
|
|
'studentId': studentId,
|
|
'studentName': studentName,
|
|
'joinedAt': FieldValue.serverTimestamp(),
|
|
});
|
|
print('DEBUG: Enrollment criado com sucesso');
|
|
} catch (e) {
|
|
print('DEBUG: Erro ao criar enrollment: $e');
|
|
throw Exception('Erro ao associar aluno à turma');
|
|
}
|
|
}
|
|
|
|
/// Ler classId do aluno na Firestore
|
|
static Future<String?> getStudentClassId(String uid) async {
|
|
try {
|
|
final doc = await _firestore.collection('users').doc(uid).get();
|
|
if (doc.exists) {
|
|
return doc.data()?['classId'] as String?;
|
|
}
|
|
return null;
|
|
} catch (e) {
|
|
print('DEBUG: Erro ao ler classId: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Ler role do usuário na Firestore
|
|
static Future<String?> getUserRole(String uid) async {
|
|
try {
|
|
print('DEBUG: Lendo documento users/$uid');
|
|
final doc = await _firestore.collection('users').doc(uid).get();
|
|
if (doc.exists) {
|
|
final role = doc.data()?['role'] as String?;
|
|
print('DEBUG: Role encontrado: $role');
|
|
return role;
|
|
}
|
|
print('DEBUG: Documento não existe');
|
|
return null;
|
|
} catch (e) {
|
|
print('DEBUG: Erro ao ler documento: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Get auth state changes stream
|
|
static Stream<User?> get authStateChanges {
|
|
return _auth.authStateChanges();
|
|
}
|
|
|
|
/// Sign up with email and password
|
|
static Future<UserCredential?> signUpWithEmailAndPassword({
|
|
required String email,
|
|
required String password,
|
|
String? displayName,
|
|
String? role,
|
|
String? classId,
|
|
String? schoolClassId,
|
|
}) async {
|
|
try {
|
|
print('DEBUG: Tentando criar conta para email: $email');
|
|
print('DEBUG: Password length: ${password.length}');
|
|
|
|
UserCredential result = await _auth.createUserWithEmailAndPassword(
|
|
email: email,
|
|
password: password,
|
|
);
|
|
|
|
print('DEBUG: Conta criada com sucesso para: ${result.user?.email}');
|
|
print('DEBUG: User ID: ${result.user?.uid}');
|
|
print('DEBUG: Email verified: ${result.user?.emailVerified}');
|
|
|
|
// Update user profile with display name
|
|
if (displayName != null && displayName.isNotEmpty) {
|
|
await result.user?.updateDisplayName(displayName);
|
|
print('DEBUG: Display name atualizado para: $displayName');
|
|
}
|
|
|
|
// Criar documento na Firestore com role (e classId se aluno)
|
|
if (role != null && result.user != null) {
|
|
await createUserRole(
|
|
result.user!.uid,
|
|
role,
|
|
classId: classId,
|
|
schoolClassId: schoolClassId,
|
|
displayName: displayName,
|
|
);
|
|
}
|
|
|
|
// Verificar se o email foi verificado
|
|
if (result.user != null && !result.user!.emailVerified) {
|
|
print('DEBUG: Email não verificado, tentando enviar verificação...');
|
|
await result.user!.sendEmailVerification();
|
|
print('DEBUG: Email de verificação enviado');
|
|
}
|
|
|
|
return result;
|
|
} on FirebaseAuthException catch (e) {
|
|
print('DEBUG: Erro Firebase ao criar conta: ${e.code} - ${e.message}');
|
|
String errorMessage = _getErrorMessage(e.code);
|
|
print('DEBUG: Mensagem de erro: $errorMessage');
|
|
throw Exception(errorMessage);
|
|
} catch (e) {
|
|
print('DEBUG: Erro genérico ao criar conta: $e');
|
|
throw Exception('Ocorreu um problema. Tente novamente');
|
|
}
|
|
}
|
|
|
|
/// Sign in with email and password
|
|
static Future<UserCredential?> signInWithEmailAndPassword({
|
|
required String email,
|
|
required String password,
|
|
}) async {
|
|
try {
|
|
print('DEBUG: Tentando login para email: $email');
|
|
print('DEBUG: Password length: ${password.length}');
|
|
|
|
// Verificar se há usuário atual
|
|
User? currentUser = _auth.currentUser;
|
|
print('DEBUG: Usuário atual: ${currentUser?.email}');
|
|
|
|
UserCredential result = await _auth.signInWithEmailAndPassword(
|
|
email: email,
|
|
password: password,
|
|
);
|
|
|
|
print('DEBUG: Login realizado com sucesso para: ${result.user?.email}');
|
|
print('DEBUG: User ID: ${result.user?.uid}');
|
|
print('DEBUG: Email verified: ${result.user?.emailVerified}');
|
|
print('DEBUG: Display name: ${result.user?.displayName}');
|
|
|
|
// Reload user data to ensure we have the latest information
|
|
await result.user?.reload();
|
|
print('DEBUG: User data reloaded');
|
|
print('DEBUG: Display name after reload: ${result.user?.displayName}');
|
|
|
|
return result;
|
|
} on FirebaseAuthException catch (e) {
|
|
print('DEBUG: Erro Firebase ao fazer login: ${e.code} - ${e.message}');
|
|
String errorMessage = _getErrorMessage(e.code);
|
|
print('DEBUG: Mensagem de erro: $errorMessage');
|
|
throw Exception(errorMessage);
|
|
} catch (e) {
|
|
print('DEBUG: Erro genérico ao fazer login: $e');
|
|
throw Exception('Ocorreu um problema. Tente novamente');
|
|
}
|
|
}
|
|
|
|
/// Sign out
|
|
static Future<void> signOut() async {
|
|
try {
|
|
print('DEBUG: Tentando fazer logout');
|
|
await _auth.signOut();
|
|
|
|
// Clear saved session
|
|
await SessionService.clearSession();
|
|
|
|
print('DEBUG: Logout e limpeza de sessão realizados com sucesso');
|
|
} catch (e) {
|
|
print('DEBUG: Erro ao fazer logout: $e');
|
|
}
|
|
}
|
|
|
|
/// Attempt auto-login with saved credentials
|
|
static Future<bool> attemptAutoLogin() async {
|
|
try {
|
|
final sessionData = await SessionService.shouldAutoLogin();
|
|
|
|
if (sessionData['shouldAutoLogin'] == true) {
|
|
final email = sessionData['email'];
|
|
print('DEBUG: Attempting auto-login for: $email');
|
|
|
|
// Note: For security reasons, we cannot auto-login without password
|
|
// This method just checks if auto-login is available
|
|
// The actual login still requires user to enter password
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} catch (e) {
|
|
print('DEBUG: Error in auto-login attempt: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Get user-friendly error message
|
|
static String _getErrorMessage(String code) {
|
|
print('DEBUG: Processando código de erro: $code');
|
|
|
|
switch (code) {
|
|
case 'weak-password':
|
|
return 'A palavra-passe é muito fraca. Use pelo menos 8 caracteres.';
|
|
case 'invalid-email':
|
|
return 'O email fornecido é inválido. Verifique o formato.';
|
|
case 'user-disabled':
|
|
return 'Esta conta foi desativada. Contacte o suporte.';
|
|
case 'user-not-found':
|
|
return 'Nenhum utilizador encontrado com este email. Verifique os dados.';
|
|
case 'wrong-password':
|
|
return 'Palavra-passe incorreta. Tente novamente.';
|
|
case 'email-already-in-use':
|
|
return 'O email inserido já se encontra registrado';
|
|
case 'operation-not-allowed':
|
|
return 'Operação não permitida. Tente novamente.';
|
|
case 'invalid-credential':
|
|
return 'Credenciais inválidos. Verifique email e palavra-passe.';
|
|
case 'too-many-requests':
|
|
return 'Muitas tentativas. Aguarde alguns minutos antes de tentar novamente.';
|
|
case 'network-request-failed':
|
|
return 'Falha de conexão. Verifique sua internet e tente novamente.';
|
|
default:
|
|
return 'Ocorreu um problema. Tente novamente';
|
|
}
|
|
}
|
|
}
|