feat: Implement email service with welcome, password reset, and verification templates, and add application logo.
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
ForgotPasswordDto,
|
||||
ResetPasswordDto,
|
||||
RefreshTokenDto,
|
||||
VerifyEmailDto,
|
||||
} from './dto';
|
||||
import { UserRole, AuthProvider, UserStatus } from '@prisma/client';
|
||||
|
||||
@@ -88,11 +89,13 @@ export class AuthService {
|
||||
// Create session
|
||||
await this.createSession(user.id, tokens.accessToken, tokens.refreshToken);
|
||||
|
||||
// Emit event for email verification (can be handled by email service)
|
||||
// Emit event for email verification (handled by email service)
|
||||
this.eventEmitter.emit('user.registered', {
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
firstName: dto.firstName,
|
||||
lastName: dto.lastName,
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -404,6 +407,110 @@ export class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// VERIFY EMAIL
|
||||
// ==========================================
|
||||
async verifyEmail(dto: VerifyEmailDto) {
|
||||
try {
|
||||
const payload = this.jwtService.verify(dto.token, {
|
||||
secret: this.configService.get<string>('jwt.secret'),
|
||||
});
|
||||
|
||||
if (payload.type !== 'email-verification') {
|
||||
throw new BadRequestException('Invalid verification token');
|
||||
}
|
||||
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { id: payload.sub },
|
||||
include: {
|
||||
userProfile: true,
|
||||
agentProfile: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
|
||||
if (user.emailVerified) {
|
||||
return {
|
||||
message: 'Email is already verified',
|
||||
};
|
||||
}
|
||||
|
||||
// Update user as verified
|
||||
await this.prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: {
|
||||
emailVerified: true,
|
||||
emailVerifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Get profile for name
|
||||
const profile =
|
||||
user.role === UserRole.AGENT ? user.agentProfile : user.userProfile;
|
||||
|
||||
// Emit event for welcome email
|
||||
this.eventEmitter.emit('user.email-verified', {
|
||||
email: user.email,
|
||||
name: profile?.firstName,
|
||||
});
|
||||
|
||||
return {
|
||||
message: 'Email verified successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
if (error.name === 'TokenExpiredError') {
|
||||
throw new BadRequestException('Verification token has expired');
|
||||
}
|
||||
if (error.name === 'JsonWebTokenError') {
|
||||
throw new BadRequestException('Invalid verification token');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// RESEND VERIFICATION EMAIL
|
||||
// ==========================================
|
||||
async resendVerificationEmail(userId: string) {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
include: {
|
||||
userProfile: true,
|
||||
agentProfile: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
|
||||
if (user.emailVerified) {
|
||||
return {
|
||||
message: 'Email is already verified',
|
||||
};
|
||||
}
|
||||
|
||||
// Get profile for name
|
||||
const profile =
|
||||
user.role === UserRole.AGENT ? user.agentProfile : user.userProfile;
|
||||
|
||||
// Emit event for email service to send verification
|
||||
this.eventEmitter.emit('user.registered', {
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
firstName: profile?.firstName,
|
||||
lastName: profile?.lastName,
|
||||
});
|
||||
|
||||
return {
|
||||
message: 'Verification email sent',
|
||||
};
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// REFRESH TOKEN
|
||||
// ==========================================
|
||||
@@ -597,8 +704,16 @@ export class AuthService {
|
||||
),
|
||||
);
|
||||
|
||||
await this.prisma.session.create({
|
||||
data: {
|
||||
// Use upsert to handle potential duplicate tokens
|
||||
await this.prisma.session.upsert({
|
||||
where: { token: accessToken },
|
||||
update: {
|
||||
refreshToken,
|
||||
userAgent,
|
||||
ipAddress,
|
||||
expiresAt,
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
token: accessToken,
|
||||
refreshToken,
|
||||
|
||||
Reference in New Issue
Block a user