canina/backend/src/auth/auth.service.ts

219 lines
5.9 KiB
TypeScript

import { Injectable, BadRequestException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../prisma/prisma.service';
import { RedisService } from '../redis/redis.service';
import { SendOtpDto } from './dto/send-otp.dto';
import { VerifyOtpDto } from './dto/verify-otp.dto';
import { SmsService } from '../common/services/sms.service';
import * as bcrypt from 'bcryptjs';
@Injectable()
export class AuthService {
constructor(
private prisma: PrismaService,
private jwtService: JwtService,
private redisService: RedisService,
private smsService: SmsService,
) {}
async sendOtp(sendOtpDto: SendOtpDto) {
const { phoneNumber } = sendOtpDto;
const code = Math.floor(10000 + Math.random() * 90000).toString();
await this.redisService.set(`otp:${phoneNumber}`, code, 120);
// Dispatch OTP via MeliPayamak Pattern SMS
await this.smsService.sendOtp(phoneNumber, code);
return {
success: true,
message: 'کد تایید با موفقیت به شماره شما پیامک شد.',
};
}
async verifyOtp(verifyOtpDto: VerifyOtpDto) {
const { phoneNumber, code } = verifyOtpDto;
const savedCode = await this.redisService.get(`otp:${phoneNumber}`);
if (!savedCode) {
throw new BadRequestException({
message: 'کد تایید منقضی شده است',
error: 'OTP_EXPIRED',
});
}
if (savedCode !== code) {
throw new BadRequestException({
message: 'کد تایید اشتباه است',
error: 'OTP_INVALID',
});
}
await this.redisService.del(`otp:${phoneNumber}`);
let user = await this.prisma.user.findUnique({
where: { mobile: phoneNumber },
});
if (!user) {
user = await this.prisma.user.create({
data: {
mobile: phoneNumber,
firstName: 'کاربر',
lastName: 'جدید',
email: `${phoneNumber}@temp.local`,
},
});
}
const payload = { sub: user.id, phoneNumber: user.mobile };
const accessToken = this.jwtService.sign(payload);
return {
success: true,
data: {
user,
accessToken,
},
};
}
async register(registerDto: any) {
const { firstName, lastName, email, mobile, password } = registerDto;
const existingUser = await this.prisma.user.findUnique({
where: { mobile },
});
if (existingUser) {
throw new BadRequestException({
message: 'کاربری با این شماره موبایل قبلا ثبت نام کرده است',
error: 'MOBILE_EXISTS',
});
}
if (email) {
const existingEmail = await this.prisma.user.findUnique({
where: { email },
});
if (existingEmail) {
throw new BadRequestException({
message: 'کاربری با این ایمیل قبلا ثبت نام کرده است',
error: 'EMAIL_EXISTS',
});
}
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = await this.prisma.user.create({
data: {
firstName,
lastName,
email: email || null,
mobile,
password: hashedPassword,
},
});
const payload = { sub: user.id, phoneNumber: user.mobile };
const accessToken = this.jwtService.sign(payload);
return {
success: true,
data: {
user,
accessToken,
},
};
}
async login(loginDto: any) {
const { mobile, password } = loginDto;
const user = await this.prisma.user.findUnique({ where: { mobile } });
if (!user) {
throw new BadRequestException({
message: 'نام کاربری یا رمز عبور اشتباه است',
error: 'INVALID_CREDENTIALS',
});
}
if (!user.password) {
throw new BadRequestException({
message: 'شما با رمز عبور ثبت نام نکرده‌اید. لطفاً با موبایل وارد شوید',
error: 'NO_PASSWORD',
});
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
throw new BadRequestException({
message: 'نام کاربری یا رمز عبور اشتباه است',
error: 'INVALID_CREDENTIALS',
});
}
const payload = { sub: user.id, phoneNumber: user.mobile };
const accessToken = this.jwtService.sign(payload);
return {
success: true,
data: {
user,
accessToken,
},
};
}
async adminLogin(body: any) {
const adminEmail = process.env.ADMIN_EMAIL || 'admin@canina-iran.com';
const adminPassword = process.env.ADMIN_PASSWORD || 'admin123';
// First check database for user with role 'Admin' or 'SUPER_ADMIN'
const dbAdmin = await this.prisma.user.findFirst({
where: { email: body.email, role: { in: ['Admin', 'SUPER_ADMIN', 'ADMIN'] } },
});
if (dbAdmin && dbAdmin.password) {
const isMatch = await bcrypt.compare(body.password, dbAdmin.password);
if (isMatch) {
const payload = { sub: dbAdmin.id, email: dbAdmin.email, role: dbAdmin.role };
return {
success: true,
data: {
user: dbAdmin,
accessToken: this.jwtService.sign(payload),
},
};
}
}
// Fallback to validated environment variable credentials
if (body.email === adminEmail && body.password === adminPassword) {
const payload = {
sub: '12345678-1234-1234-1234-123456789012',
email: body.email,
role: 'Admin',
};
return {
success: true,
data: {
user: {
id: '12345678-1234-1234-1234-123456789012',
email: body.email,
role: 'Admin',
},
accessToken: this.jwtService.sign(payload),
},
};
}
throw new BadRequestException({
message: 'ایمیل یا رمز عبور اشتباه است',
error: 'INVALID_CREDENTIALS',
});
}
}