Files
CRM_Montzar/apps/api/src/users/users.service.ts
T

114 lines
3.3 KiB
TypeScript
Raw Normal View History

import {
BadRequestException,
ConflictException,
ForbiddenException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import type { InviteUserRequest, OrgUserDto, UserRole } from '@mento/shared';
import * as bcrypt from 'bcryptjs';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class UsersService {
constructor(private readonly prisma: PrismaService) {}
async list(organizationId: string): Promise<OrgUserDto[]> {
const rows = await this.prisma.user.findMany({
where: { organizationId },
orderBy: [{ role: 'asc' }, { fullName: 'asc' }],
});
return rows.map((u) => this.toDto(u));
}
async invite(
organizationId: string,
actorRole: UserRole,
dto: InviteUserRequest,
): Promise<OrgUserDto> {
if (actorRole !== 'owner' && actorRole !== 'admin') {
throw new ForbiddenException('فقط مالک یا مدیر می‌تواند کاربر اضافه کند');
}
const email = dto.email.trim().toLowerCase();
const existing = await this.prisma.user.findFirst({
where: { organizationId, email },
});
if (existing) {
throw new ConflictException('این ایمیل در سازمان شما وجود دارد');
}
const global = await this.prisma.user.findFirst({ where: { email } });
if (global) {
throw new ConflictException('این ایمیل قبلاً در سیستم ثبت شده است');
}
const passwordHash = await bcrypt.hash(dto.password, 10);
const row = await this.prisma.user.create({
data: {
organizationId,
email,
fullName: dto.fullName.trim(),
passwordHash,
role: dto.role,
},
});
return this.toDto(row);
}
async updateRole(
organizationId: string,
actor: { userId: string; role: UserRole },
targetId: string,
nextRole: UserRole,
): Promise<OrgUserDto> {
if (actor.role !== 'owner' && actor.role !== 'admin') {
throw new ForbiddenException('فقط مالک یا مدیر می‌تواند نقش را تغییر دهد');
}
const target = await this.prisma.user.findFirst({
where: { id: targetId, organizationId },
});
if (!target) throw new NotFoundException('کاربر پیدا نشد');
if (actor.role === 'admin') {
if (target.role === 'owner' || nextRole === 'owner') {
throw new ForbiddenException('مدیر نمی‌تواند نقش مالک را تغییر دهد');
}
}
if (target.role === 'owner' && nextRole !== 'owner') {
const owners = await this.prisma.user.count({
where: { organizationId, role: 'owner' },
});
if (owners <= 1) {
throw new BadRequestException(
'حداقل یک مالک برای سازمان لازم است؛ ابتدا مالک دیگری تعیین کنید',
);
}
}
const row = await this.prisma.user.update({
where: { id: target.id },
data: { role: nextRole },
});
return this.toDto(row);
}
private toDto(row: {
id: string;
email: string;
fullName: string;
role: UserRole;
createdAt: Date;
}): OrgUserDto {
return {
id: row.id,
email: row.email,
fullName: row.fullName,
role: row.role,
createdAt: row.createdAt.toISOString(),
};
}
}