Files
dsc-api/src/modules/auth/providers/auth.service.ts
T
2025-06-01 11:11:33 +03:30

286 lines
10 KiB
TypeScript
Executable File

import { BadRequestException, Injectable } from "@nestjs/common";
import { DataSource } from "typeorm";
import { TokensService } from "./tokens.service";
import { AuthMessage, UserMessage } from "../../../common/enums/message.enum";
import { NotificationQueue } from "../../notifications/queue/notification.queue";
import { ReferralsService } from "../../referrals/providers/referrals.service";
import { Role } from "../../users/entities/role.entity";
import { AdminsService } from "../../users/providers/admins.service";
import { UsersService } from "../../users/providers/users.service";
import { OTPService } from "../../utils/providers/otp.service";
import { PasswordService } from "../../utils/providers/password.service";
import { ChangePasswordDto } from "../DTO/change-password.dto";
import { CompleteRegistrationDto } from "../DTO/complete-register.dto";
import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto";
import { RequestOtpDto } from "../DTO/request-otp.dto";
import { VerifyOtpDto } from "../DTO/verify-otp.dto";
@Injectable()
export class AuthService {
constructor(
private readonly usersService: UsersService,
private readonly adminsService: AdminsService,
private readonly passwordService: PasswordService,
private readonly otpService: OTPService,
private readonly tokensService: TokensService,
private readonly dataSource: DataSource,
private readonly notificationQueue: NotificationQueue,
private readonly referralsService: ReferralsService,
) {}
//****************** */
//****************** */
async initiateRegistration(requestOtpDto: RequestOtpDto) {
const { phone } = requestOtpDto;
const existUser = await this.usersService.findOneWithPhone(phone);
if (existUser) throw new BadRequestException(AuthMessage.PHONE_EXISTS);
const existCode = await this.otpService.checkExistOtp(phone, "REGISTER");
if (existCode) {
return {
message: AuthMessage.OTP_ALREADY_SENT,
ttlSecond: existCode,
};
}
const otpCode = await this.otpService.generateAndSetInCache(phone, "REGISTER");
//
// await this.smsService.sendSmsVerifyCode(phone, otpCode);
await this.notificationQueue.addLoginOtpNotification({ phone, code: otpCode });
return {
message: AuthMessage.OTP_SENT,
};
}
//****************** */
//****************** */
async completeRegistration(completeRegistrationDto: CompleteRegistrationDto) {
const { phone, code, referralCode } = completeRegistrationDto;
const queryRunner = this.dataSource.createQueryRunner();
try {
await queryRunner.connect();
await queryRunner.startTransaction();
//
const isValid = await this.otpService.verifyOtp(phone, code, "REGISTER");
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
const existUser = await this.usersService.findOneWithPhone(phone);
if (existUser) throw new BadRequestException(AuthMessage.PHONE_EXISTS);
const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password);
const user = await this.usersService.createUser(completeRegistrationDto, hashedPassword, queryRunner);
if (referralCode) await this.referralsService.useReferralCode({ referralCode, userId: user.id }, queryRunner);
const tokens = await this.tokensService.generateTokens(user, queryRunner);
const superAdmins = await this.adminsService.getSuperAdmins(queryRunner);
for (const admin of superAdmins) {
await this.notificationQueue.addNewCustomerNotification(admin.id, {
userPhone: admin.phone,
userEmail: admin.email,
fullName: `${user.firstName} ${user.lastName}`,
mobile: user.phone,
});
}
await this.otpService.delOtpFormCache(phone, "REGISTER");
await queryRunner.commitTransaction();
return {
message: AuthMessage.USER_REGISTER_SUCCESS,
...tokens,
};
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
//****************** */
//****************** */
async loginWithPassword(loginDto: LoginPasswordDTO) {
const { email, password } = loginDto;
const user = await this.checkUserLoginCredentialWithEmail(email, password);
if (!user.roles.some((role) => !role.isAdmin)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
const tokens = await this.tokensService.generateTokens(user);
await this.notificationQueue.addLoginNotification(user.id, { userPhone: user.phone });
return {
message: AuthMessage.PASSWORD_LOGIN_SUCCESS,
...tokens,
};
}
//****************** */
//****************** */
async adminLoginWithPassword(loginDto: LoginPasswordDTO) {
const { email, password } = loginDto;
const user = await this.checkUserLoginCredentialWithEmail(email, password);
const isAdmin = this.checkUserIsAdmin(user.roles);
if (!isAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN);
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
const tokens = await this.tokensService.generateTokens(user);
return {
message: AuthMessage.PASSWORD_LOGIN_SUCCESS,
...tokens,
};
}
//****************** */
//****************** */
async checkUserExist(checkUserExistDto: CheckUserExistDto) {
const user = await this.usersService.findOneWithEmail(checkUserExistDto.email);
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
return { message: UserMessage.USER_EXISTS };
}
//****************** */
//****************** */
async requestLoginOtp(requestOtpDto: RequestOtpDto, isAdmin: boolean = false) {
const { phone } = requestOtpDto;
const user = await this.usersService.findOneWithPhone(phone);
if (!user) throw new BadRequestException(AuthMessage.PHONE_NOT_FOUND);
//check the if the method call is from admin or not
const isUserAdmin = this.checkUserIsAdmin(user.roles);
if (isAdmin && !isUserAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN);
const existCode = await this.otpService.checkExistOtp(phone, "LOGIN");
if (existCode) {
return {
message: AuthMessage.OTP_ALREADY_SENT,
ttlSecond: existCode,
};
}
const otpCode = await this.otpService.generateAndSetInCache(phone, "LOGIN");
//
// await this.smsService.sendSmsVerifyCode(phone, otpCode);
await this.notificationQueue.addLoginOtpNotification({ phone, code: otpCode });
return {
message: AuthMessage.OTP_SENT,
};
}
//****************** */
//****************** */
async verifyLoginOtp(verifyOtpDto: VerifyOtpDto) {
const { code, phone } = verifyOtpDto;
const user = await this.checkUserLoginCredentialWithPhone(phone, code);
if (!user.roles.some((role) => !role.isAdmin)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
// if (user.roles.some((role) => role.isAdmin)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
const tokens = await this.tokensService.generateTokens(user);
await this.notificationQueue.addLoginNotification(user.id, { userPhone: user.phone, userEmail: user.email });
return {
message: AuthMessage.LOGIN_SUCCESS,
...tokens,
};
}
//****************** */
async adminVerifyLoginOtp(verifyOtpDto: VerifyOtpDto) {
const { code, phone } = verifyOtpDto;
const user = await this.checkUserLoginCredentialWithPhone(phone, code);
const isUserAdmin = this.checkUserIsAdmin(user.roles);
if (!isUserAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN);
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
const tokens = await this.tokensService.generateTokens(user);
return {
message: AuthMessage.LOGIN_SUCCESS,
...tokens,
};
}
//****************** */
async changePassword(userId: string, updateDto: ChangePasswordDto) {
const { user } = await this.usersService.findOneById(userId);
const passCompare = await this.passwordService.comparePassword(updateDto.password, user.password);
if (!passCompare) throw new BadRequestException(AuthMessage.CURRENT_PASSWORD_INVALID);
if (updateDto.newPassword !== updateDto.repeatPassword) throw new BadRequestException(AuthMessage.INVALID_REAPET_PASSWORD);
const hashedPassword = await this.passwordService.hashPassword(updateDto.newPassword);
await this.usersService.updateUserPassword(user.id, hashedPassword);
return {
message: AuthMessage.PASSWORD_CHANGED_SUCCESSFULLY,
};
}
//****************** */
async refreshToken(oldRefreshToken: string) {
return this.tokensService.refreshToken(oldRefreshToken);
}
//****************** */
async logout(userId: string) {
await this.tokensService.invalidateRefreshToken(userId);
return {
message: AuthMessage.LOGOUT_SUCCESS,
};
}
//****************** */
private async checkUserLoginCredentialWithEmail(email: string, password: string) {
const user = await this.usersService.findOneWithEmail(email);
if (!user) throw new BadRequestException(AuthMessage.INVALID_PASSWORD);
const passCompare = await this.passwordService.comparePassword(password, user.password);
if (!passCompare) throw new BadRequestException(AuthMessage.INVALID_PASSWORD);
return user;
}
//****************** */
//****************** */
private async checkUserLoginCredentialWithPhone(phone: string, otpCode: string) {
const isValid = await this.otpService.verifyOtp(phone, otpCode, "LOGIN");
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
await this.otpService.delOtpFormCache(phone, "LOGIN");
const user = await this.usersService.findOneWithPhone(phone);
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
return user;
}
// private checkUserPerm(user: User, perm: PermissionEnum) {
// return user.roles.some((role) => role?.permissions?.some((p) => p.name === perm));
// }
//****************** */
//****************** */
private checkUserIsAdmin(roles: Role[]) {
return roles.some((role) => role.isAdmin);
}
}