AI Implementation feature(820): Project Scaffold and Platform Foundations (#1)
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { EntityManager, Repository } from 'typeorm';
|
||||
import { UserEntity, UserRole } from '../../database/entities/user.entity';
|
||||
import { ApiError } from '../../common/errors/api-error';
|
||||
import { ERROR_CODES } from '../../common/errors/error-codes';
|
||||
|
||||
type UserRepoLike = Repository<UserEntity> | EntityManager;
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(@InjectRepository(UserEntity) private readonly repo: Repository<UserEntity>) {}
|
||||
|
||||
countAdmins(manager?: EntityManager): Promise<number> {
|
||||
return this.getRepo(manager).count({ where: { role: 'admin' } });
|
||||
}
|
||||
|
||||
findById(id: string, manager?: EntityManager): Promise<UserEntity | null> {
|
||||
return this.getRepo(manager).findOne({ where: { id } });
|
||||
}
|
||||
|
||||
listAll(): Promise<UserEntity[]> {
|
||||
return this.repo.find({ order: { createdAt: 'ASC' } });
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify, inside an open transaction, that demoting/deleting the given user
|
||||
* would not leave the system with zero admins. Throws ApiError(LAST_ADMIN)
|
||||
* if so. Must be invoked from a `dataSource.transaction(...)` callback.
|
||||
*/
|
||||
async enforceLastAdminInvariant(manager: EntityManager, targetId: string, nextRole?: UserRole): Promise<void> {
|
||||
const repo = manager.getRepository(UserEntity);
|
||||
const target = await repo.findOne({ where: { id: targetId } });
|
||||
if (!target) throw ApiError.notFound('User not found');
|
||||
|
||||
const wouldDemoteOrDelete =
|
||||
target.role === 'admin' && (nextRole === undefined || nextRole !== 'admin');
|
||||
if (!wouldDemoteOrDelete) return;
|
||||
|
||||
const adminCount = await repo.count({ where: { role: 'admin' } });
|
||||
if (adminCount <= 1) {
|
||||
throw ApiError.conflict(ERROR_CODES.LAST_ADMIN, 'Cannot delete or demote the last admin');
|
||||
}
|
||||
}
|
||||
|
||||
private getRepo(manager?: EntityManager): Repository<UserEntity> {
|
||||
return manager ? manager.getRepository(UserEntity) : this.repo;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user