Edit login suoerAdmin

This commit is contained in:
2026-09-19 22:42:51 +03:30
parent b016b4754f
commit 605e1d3340
19 changed files with 717 additions and 43 deletions
+130
View File
@@ -5,6 +5,7 @@ import {
NotFoundException,
} from '@nestjs/common';
import type {
PlatformAdminDto,
PlatformOrganizationDto,
PlatformStatsDto,
PlatformUserDto,
@@ -19,7 +20,9 @@ import { OrgRolesService } from '../org-roles/org-roles.service';
import { PipelinesService } from '../pipelines/pipelines.service';
import { PrismaService } from '../prisma/prisma.service';
import type {
CreatePlatformAdminDto,
CreatePlatformOrganizationDto,
ResetPlatformAdminPasswordDto,
ResetPlatformUserPasswordDto,
UpdatePlatformOrganizationDto,
} from './dto';
@@ -472,6 +475,133 @@ export class PlatformService {
return this.getUser(row.userId);
}
async listAdmins(): Promise<PlatformAdminDto[]> {
const rows = await this.prisma.platformAdmin.findMany({
orderBy: { createdAt: 'asc' },
});
return rows.map((row) => this.adminToDto(row));
}
async createAdmin(dto: CreatePlatformAdminDto): Promise<PlatformAdminDto> {
const fullName = dto.fullName.trim();
if (fullName.length < 2) {
throw new BadRequestException('نام معتبر نیست');
}
const mobile = normalizeMobile(dto.mobile);
if (!mobile) {
throw new BadRequestException('شماره موبایل معتبر نیست');
}
const password = dto.password.trim();
if (password.length < 8) {
throw new BadRequestException('رمز عبور حداقل ۸ کاراکتر لازم است');
}
const email = dto.email?.trim().toLowerCase() || null;
const existingMobile = await this.prisma.platformAdmin.findUnique({
where: { mobile },
select: { id: true },
});
if (existingMobile) {
throw new ConflictException('این شماره موبایل قبلاً ثبت شده است');
}
if (email) {
const existingEmail = await this.prisma.platformAdmin.findUnique({
where: { email },
select: { id: true },
});
if (existingEmail) {
throw new ConflictException('این ایمیل قبلاً ثبت شده است');
}
}
const passwordHash = await bcrypt.hash(password, 10);
try {
const created = await this.prisma.platformAdmin.create({
data: {
fullName,
mobile,
email,
passwordHash,
},
});
return this.adminToDto(created);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
throw new ConflictException('موبایل یا ایمیل تکراری است');
}
throw e;
}
}
async setAdminActive(
id: string,
isActive: boolean,
actorId: string,
): Promise<PlatformAdminDto> {
const existing = await this.prisma.platformAdmin.findUnique({
where: { id },
select: { id: true },
});
if (!existing) throw new NotFoundException('ادمین پیدا نشد');
if (!isActive && id === actorId) {
throw new BadRequestException('نمی‌توانید حساب خودتان را غیرفعال کنید');
}
if (!isActive) {
const activeCount = await this.prisma.platformAdmin.count({
where: { isActive: true, id: { not: id } },
});
if (activeCount < 1) {
throw new BadRequestException('حداقل یک سوپرادمین فعال لازم است');
}
}
const updated = await this.prisma.platformAdmin.update({
where: { id },
data: { isActive },
});
return this.adminToDto(updated);
}
async resetAdminPassword(
id: string,
dto: ResetPlatformAdminPasswordDto,
): Promise<{ ok: true }> {
const existing = await this.prisma.platformAdmin.findUnique({
where: { id },
select: { id: true },
});
if (!existing) throw new NotFoundException('ادمین پیدا نشد');
const password = dto.password.trim();
if (password.length < 8) {
throw new BadRequestException('رمز عبور حداقل ۸ کاراکتر لازم است');
}
const passwordHash = await bcrypt.hash(password, 10);
await this.prisma.platformAdmin.update({
where: { id },
data: { passwordHash },
});
return { ok: true };
}
private adminToDto(row: {
id: string;
mobile: string | null;
email: string | null;
fullName: string;
isActive: boolean;
lastLoginAt: Date | null;
createdAt: Date;
}): PlatformAdminDto {
return {
id: row.id,
mobile: row.mobile,
email: row.email,
fullName: row.fullName,
isActive: row.isActive,
lastLoginAt: row.lastLoginAt?.toISOString() ?? null,
createdAt: row.createdAt.toISOString(),
};
}
private orgToDto(row: {
id: string;
name: string;