移除账号启用状态统一使用归档

This commit is contained in:
2026-07-24 09:53:04 +08:00
parent a9c6578569
commit 13ef357448
13 changed files with 86 additions and 67 deletions

View File

@@ -1,7 +1,6 @@
import {
ArrayUnique,
IsArray,
IsBoolean,
IsInt,
IsOptional,
IsString,
@@ -70,10 +69,6 @@ export class UpdateUserDto {
@IsString()
name?: string;
@IsOptional()
@IsBoolean()
isActive?: boolean;
@IsOptional()
@IsArray()
@ArrayUnique()

View File

@@ -92,4 +92,10 @@ describe('RBAC DTO id arrays', () => {
])('rejects invalid, duplicate, or non-positive ids for %p', async (metatype, value) => {
await expect(pipe.transform(value, { type: 'body', metatype })).rejects.toBeDefined();
});
it('strips the retired isActive field from account updates', async () => {
await expect(
pipe.transform({ name: 'Alice', isActive: false }, { type: 'body', metatype: UpdateUserDto }),
).resolves.toEqual({ name: 'Alice' });
});
});

View File

@@ -35,7 +35,12 @@ describe('RbacService seedData', () => {
save: jest.fn(async (value: any) => value),
find: jest.fn(async () => [systemAdminRole]),
};
const userRepo = { count: jest.fn(async () => 1), create: jest.fn(), save: jest.fn() };
const userRepo = {
update: jest.fn(async () => ({ affected: 0 })),
count: jest.fn(async () => 1),
create: jest.fn(),
save: jest.fn(),
};
const service = new RbacService(
permRepo as never,
@@ -101,7 +106,12 @@ describe('RbacService seedData', () => {
save: jest.fn(async (value) => value),
find: jest.fn(async () => [teacherRole]),
};
const userRepo = { count: jest.fn(async () => 1), create: jest.fn(), save: jest.fn() };
const userRepo = {
update: jest.fn(async () => ({ affected: 0 })),
count: jest.fn(async () => 1),
create: jest.fn(),
save: jest.fn(),
};
const service = new RbacService(
permRepo as never,
@@ -184,6 +194,7 @@ describe('RbacService legacy role consolidation', () => {
remove: jest.fn(async (value) => value),
};
const userRepo = {
update: jest.fn(async () => ({ affected: 0 })),
count: jest.fn(async () => 1),
findOne: jest.fn(async () => user),
save: jest.fn(async (value) => value),

View File

@@ -296,6 +296,13 @@ export class RbacService {
}
async seedData(): Promise<void> {
const restoredLegacyUsers = await this.userRepo.update({ isActive: false }, { isActive: true });
if (restoredLegacyUsers.affected) {
this.logger.log(
`已恢复 ${restoredLegacyUsers.affected} 个旧版禁用账号,账号状态现统一由归档管理`,
);
}
// Step 1: 幂等插入所有权限点(先查后插,兼容 SQLite/MySQL
for (const p of PRESET_PERMISSIONS) {
const exists = await this.permRepo.findOne({ where: { code: p.code } });
@@ -568,7 +575,6 @@ export class RbacService {
id: u.id,
username: u.username,
name: u.name,
isActive: u.isActive,
isArchived: u.isArchived,
studentStatus: statusMap.get(u.id) || null,
lastLoginAt: u.lastLoginAt,
@@ -597,7 +603,7 @@ export class RbacService {
async updateUser(
id: number,
dto: { username?: string; name?: string; isActive?: boolean; roleIds?: number[] },
dto: { username?: string; name?: string; roleIds?: number[] },
) {
const user = await this.userRepo.findOne({ where: { id }, relations: ['roles'] });
if (!user) throw new Error('用户不存在');
@@ -607,7 +613,6 @@ export class RbacService {
user.username = dto.username;
}
if (dto.name !== undefined) user.name = dto.name;
if (dto.isActive !== undefined) user.isActive = dto.isActive;
if (dto.roleIds !== undefined) {
user.roles = dto.roleIds.length > 0 ? await this.resolveRoles(dto.roleIds) : [];
}
@@ -634,7 +639,7 @@ export class RbacService {
async restoreUser(id: number) {
const user = await this.userRepo.findOne({ where: { id } });
if (!user) throw new Error('用户不存在');
await this.userRepo.update(id, { isArchived: false });
await this.userRepo.update(id, { isArchived: false, isActive: true });
return { message: '用户已恢复' };
}
@@ -766,7 +771,8 @@ export class RbacService {
.where('(role.code IN (:...roleCodes) OR role.name IN (:...roleNames))', {
roleCodes: teacherRoleCodes,
roleNames: teacherRoleNames,
});
})
.andWhere('u.isArchived = :isArchived', { isArchived: false });
if (query?.search) {
qb.andWhere('(u.name LIKE :s OR u.username LIKE :s)', { s: `%${query.search}%` });
@@ -795,7 +801,6 @@ export class RbacService {
id: u.id,
username: u.username,
name: u.name,
isActive: u.isActive,
profile: u.profile,
lastLoginAt: u.lastLoginAt,
roles: u.roles || [],