feat: implement email verification and password reset features
- Add EmailTokenService for handling email verification and password reset tokens. - Create EmailService for sending verification and reset emails via SMTP. - Update AuthService to handle email verification status during login. - Modify user registration to redirect to a check email screen instead of issuing a token. - Implement resend verification email functionality. - Add deep link handling for email verification and password reset in the mobile app. - Update mobile app routes and components to support new email verification flow. - Enhance error handling for unverified emails during login attempts. - Update configuration to include SMTP settings for email service.
This commit is contained in:
@@ -12,9 +12,8 @@ export class ApiAuthRepository implements AuthRepository {
|
||||
return this.fetchSession(data.access_token as string, data.refresh_token as string);
|
||||
}
|
||||
|
||||
async register(input: RegisterInput): Promise<AuthSession> {
|
||||
const { data } = await httpClient.post('/auth/register', input);
|
||||
return this.fetchSession(data.access_token as string, data.refresh_token as string);
|
||||
async register(input: RegisterInput): Promise<void> {
|
||||
await httpClient.post('/auth/register', input);
|
||||
}
|
||||
|
||||
async loginWithGoogle(input: GoogleOAuthInput): Promise<AuthSession> {
|
||||
@@ -36,6 +35,10 @@ export class ApiAuthRepository implements AuthRepository {
|
||||
});
|
||||
}
|
||||
|
||||
async resendVerification(email: string): Promise<void> {
|
||||
await httpClient.post('/auth/resend-verification', { email });
|
||||
}
|
||||
|
||||
async forgotPassword(email: string): Promise<void> {
|
||||
await httpClient.post('/auth/forgot-password', { email });
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ export class LoginUseCase {
|
||||
export class RegisterUseCase {
|
||||
constructor(private readonly authRepo: AuthRepository) {}
|
||||
|
||||
async execute(input: RegisterInput): Promise<AuthSession> {
|
||||
async execute(input: RegisterInput): Promise<void> {
|
||||
if (!input.email || !input.password) {
|
||||
throw new Error('E-mail e senha são obrigatórios.');
|
||||
}
|
||||
if (input.password.length < 8) {
|
||||
throw new Error('A senha deve ter ao menos 8 caracteres.');
|
||||
}
|
||||
return this.authRepo.register(input);
|
||||
await this.authRepo.register(input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,18 @@ export class LogoutUseCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caso de uso: Reenviar e-mail de verificação de conta.
|
||||
*/
|
||||
export class ResendVerificationUseCase {
|
||||
constructor(private readonly authRepo: AuthRepository) {}
|
||||
|
||||
async execute(email: string): Promise<void> {
|
||||
if (!email) throw new Error('E-mail obrigatório.');
|
||||
await this.authRepo.resendVerification(email);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caso de uso: Solicitar redefinição de senha.
|
||||
*/
|
||||
@@ -65,6 +77,18 @@ export class ForgotPasswordUseCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caso de uso: Verificar e-mail com token recebido por deep link.
|
||||
*/
|
||||
export class VerifyEmailUseCase {
|
||||
constructor(private readonly authRepo: AuthRepository) {}
|
||||
|
||||
async execute(token: string): Promise<void> {
|
||||
if (!token) throw new Error('Token inválido.');
|
||||
await this.authRepo.verifyEmail(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caso de uso: Redefinir senha com token.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,9 @@ import {
|
||||
LoginUseCase,
|
||||
RegisterUseCase,
|
||||
ForgotPasswordUseCase,
|
||||
ResendVerificationUseCase,
|
||||
ResetPasswordUseCase,
|
||||
VerifyEmailUseCase,
|
||||
LogoutUseCase,
|
||||
} from '@application/auth/AuthUseCases';
|
||||
import { CreateFilamentUseCase } from '@application/filament/CreateFilamentUseCase';
|
||||
@@ -30,8 +32,10 @@ const presetRepository = new ApiSpoolPresetRepository();
|
||||
// Use cases de autenticação
|
||||
export const loginUseCase = new LoginUseCase(authRepository);
|
||||
export const registerUseCase = new RegisterUseCase(authRepository);
|
||||
export const resendVerificationUseCase = new ResendVerificationUseCase(authRepository);
|
||||
export const forgotPasswordUseCase = new ForgotPasswordUseCase(authRepository);
|
||||
export const resetPasswordUseCase = new ResetPasswordUseCase(authRepository);
|
||||
export const verifyEmailUseCase = new VerifyEmailUseCase(authRepository);
|
||||
export const logoutUseCase = new LogoutUseCase(authRepository);
|
||||
|
||||
// Use cases de filamento
|
||||
|
||||
@@ -6,10 +6,11 @@ import type { AuthSession, LoginInput, RegisterInput, GoogleOAuthInput } from '@
|
||||
*/
|
||||
export interface AuthRepository {
|
||||
login(input: LoginInput): Promise<AuthSession>;
|
||||
register(input: RegisterInput): Promise<AuthSession>;
|
||||
register(input: RegisterInput): Promise<void>;
|
||||
loginWithGoogle(input: GoogleOAuthInput): Promise<AuthSession>;
|
||||
refreshToken(refreshToken: string): Promise<Pick<AuthSession, 'accessToken' | 'refreshToken'>>;
|
||||
logout(accessToken: string): Promise<void>;
|
||||
resendVerification(email: string): Promise<void>;
|
||||
forgotPassword(email: string): Promise<void>;
|
||||
verifyEmail(token: string): Promise<void>;
|
||||
resetPassword(token: string, newPassword: string): Promise<void>;
|
||||
|
||||
Reference in New Issue
Block a user