fix sso core folder
This commit is contained in:
136
apps/sso-core/src/domain/admin.service.ts
Normal file
136
apps/sso-core/src/domain/admin.service.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { UserStatus } from '../generated/prisma/client';
|
||||
import { PrismaService } from '../infra/prisma.service';
|
||||
import { AccessService } from './access.service';
|
||||
|
||||
@Injectable()
|
||||
export class AdminService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly access: AccessService
|
||||
) {}
|
||||
|
||||
async listUsers(search?: string) {
|
||||
const users = await this.prisma.user.findMany({
|
||||
where: search
|
||||
? {
|
||||
OR: [
|
||||
{ email: { contains: search, mode: 'insensitive' } },
|
||||
{ phone: { contains: search, mode: 'insensitive' } },
|
||||
{ displayName: { contains: search, mode: 'insensitive' } },
|
||||
{ username: { contains: search, mode: 'insensitive' } }
|
||||
]
|
||||
}
|
||||
: undefined,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
include: { userRoles: { include: { role: true } } }
|
||||
});
|
||||
|
||||
return users.map((user) => this.toAdminUser(user));
|
||||
}
|
||||
|
||||
async updateUserProfile(userId: string, data: { displayName?: string; email?: string; phone?: string; backupEmail?: string; backupPhone?: string; status?: UserStatus }) {
|
||||
await this.ensureUserExists(userId);
|
||||
const user = await this.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data,
|
||||
include: { userRoles: { include: { role: true } } }
|
||||
});
|
||||
return this.toAdminUser(user);
|
||||
}
|
||||
|
||||
async resetPassword(userId: string, newPassword: string) {
|
||||
if (newPassword.length < 8) {
|
||||
throw new BadRequestException('Пароль должен содержать минимум 8 символов');
|
||||
}
|
||||
|
||||
await this.ensureUserExists(userId);
|
||||
const user = await this.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: { passwordHash: await bcrypt.hash(newPassword, 12) },
|
||||
include: { userRoles: { include: { role: true } } }
|
||||
});
|
||||
return this.toAdminUser(user);
|
||||
}
|
||||
|
||||
async suspendUser(userId: string) {
|
||||
await this.ensureUserExists(userId);
|
||||
await this.prisma.session.updateMany({ where: { userId }, data: { status: 'REVOKED' } });
|
||||
const user = await this.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: { status: UserStatus.SUSPENDED },
|
||||
include: { userRoles: { include: { role: true } } }
|
||||
});
|
||||
return this.toAdminUser(user);
|
||||
}
|
||||
|
||||
async setSuperAdmin(actorUserId: string, userId: string, isSuperAdmin: boolean) {
|
||||
await this.access.assertSuperAdmin(actorUserId);
|
||||
await this.ensureUserExists(userId);
|
||||
|
||||
const target = await this.prisma.user.findUnique({ where: { id: userId } });
|
||||
if (!target) {
|
||||
throw new NotFoundException('Пользователь не найден');
|
||||
}
|
||||
|
||||
if (target.isSuperAdmin && !isSuperAdmin) {
|
||||
const superAdmins = await this.prisma.user.count({ where: { isSuperAdmin: true, status: UserStatus.ACTIVE } });
|
||||
if (superAdmins <= 1) {
|
||||
throw new BadRequestException('Нельзя снять права у единственного супер-администратора');
|
||||
}
|
||||
}
|
||||
|
||||
const user = await this.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: { isSuperAdmin },
|
||||
include: { userRoles: { include: { role: true } } }
|
||||
});
|
||||
return this.toAdminUser(user);
|
||||
}
|
||||
|
||||
async deleteUser(userId: string) {
|
||||
await this.ensureUserExists(userId);
|
||||
const user = await this.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: { status: UserStatus.DELETED, deletedAt: new Date() },
|
||||
include: { userRoles: { include: { role: true } } }
|
||||
});
|
||||
return this.toAdminUser(user);
|
||||
}
|
||||
|
||||
private toAdminUser(user: {
|
||||
id: string;
|
||||
email: string | null;
|
||||
phone: string | null;
|
||||
backupEmail: string | null;
|
||||
backupPhone: string | null;
|
||||
displayName: string;
|
||||
username: string | null;
|
||||
isSuperAdmin: boolean;
|
||||
status: UserStatus;
|
||||
createdAt: Date;
|
||||
userRoles?: { role: { slug: string } }[];
|
||||
}) {
|
||||
return {
|
||||
id: user.id,
|
||||
email: user.email ?? undefined,
|
||||
phone: user.phone ?? undefined,
|
||||
backupEmail: user.backupEmail ?? undefined,
|
||||
backupPhone: user.backupPhone ?? undefined,
|
||||
displayName: user.displayName,
|
||||
username: user.username ?? undefined,
|
||||
isSuperAdmin: user.isSuperAdmin,
|
||||
status: user.status,
|
||||
createdAt: user.createdAt.toISOString(),
|
||||
roles: user.userRoles?.map((link) => link.role.slug) ?? []
|
||||
};
|
||||
}
|
||||
|
||||
private async ensureUserExists(userId: string) {
|
||||
const user = await this.prisma.user.findUnique({ where: { id: userId } });
|
||||
if (!user) {
|
||||
throw new NotFoundException('Пользователь не найден');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user