import { ConflictException, Injectable, UnauthorizedException, } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bcrypt from 'bcryptjs'; import type { AuthUserDto, LoginResponse } from '@mento/shared'; import { PrismaService } from '../prisma/prisma.service'; import { LoginDto, RegisterOrganizationDto } from './dto'; function slugify(input: string): string { return input .trim() .toLowerCase() .replace(/[^\w\u0600-\u06FF]+/g, '-') .replace(/^-+|-+$/g, '') .slice(0, 48) || `org-${Date.now()}`; } @Injectable() export class AuthService { constructor( private readonly prisma: PrismaService, private readonly jwt: JwtService, ) {} async registerOrganization(dto: RegisterOrganizationDto): Promise { const baseSlug = slugify(dto.organizationName); let slug = baseSlug; let i = 1; while (await this.prisma.organization.findUnique({ where: { slug } })) { slug = `${baseSlug}-${i++}`; } const existing = await this.prisma.user.findFirst({ where: { email: dto.email.toLowerCase() }, }); if (existing) { throw new ConflictException('این ایمیل قبلاً ثبت شده است'); } const passwordHash = await bcrypt.hash(dto.password, 10); const organization = await this.prisma.organization.create({ data: { name: dto.organizationName, slug, businessField: dto.businessField, users: { create: { email: dto.email.toLowerCase(), fullName: dto.fullName, passwordHash, role: 'owner', }, }, }, include: { users: true }, }); const user = organization.users[0]; return this.buildLoginResponse(user); } async login(dto: LoginDto): Promise { const user = await this.prisma.user.findFirst({ where: { email: dto.email.toLowerCase() }, }); if (!user) { throw new UnauthorizedException('ایمیل یا رمز عبور نادرست است'); } const ok = await bcrypt.compare(dto.password, user.passwordHash); if (!ok) { throw new UnauthorizedException('ایمیل یا رمز عبور نادرست است'); } return this.buildLoginResponse(user); } async me(userId: string): Promise { const user = await this.prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new UnauthorizedException(); } return this.toAuthUser(user); } private buildLoginResponse(user: { id: string; email: string; fullName: string; role: AuthUserDto['role']; organizationId: string; }): LoginResponse { const payload = { sub: user.id, organizationId: user.organizationId, role: user.role, }; return { accessToken: this.jwt.sign(payload), user: this.toAuthUser(user), }; } private toAuthUser(user: { id: string; email: string; fullName: string; role: AuthUserDto['role']; organizationId: string; }): AuthUserDto { return { id: user.id, email: user.email, fullName: user.fullName, role: user.role, organizationId: user.organizationId, }; } }