feat(server): ban account (#10761)

close CLOUD-158
This commit is contained in:
forehalo
2025-03-12 02:52:18 +00:00
parent cd63e0ed8b
commit ea72599bde
15 changed files with 215 additions and 76 deletions

View File

@@ -10,11 +10,11 @@ import type { CurrentUser } from './session';
export function sessionUser(
user: Pick<
User,
'id' | 'email' | 'avatarUrl' | 'name' | 'emailVerifiedAt'
'id' | 'email' | 'avatarUrl' | 'name' | 'emailVerifiedAt' | 'disabled'
> & { password?: string | null }
): CurrentUser {
// use pick to avoid unexpected fields
return assign(pick(user, 'id', 'email', 'avatarUrl', 'name'), {
return assign(pick(user, 'id', 'email', 'avatarUrl', 'name', 'disabled'), {
hasPassword: user.password !== null,
emailVerified: user.emailVerifiedAt !== null,
});
@@ -105,7 +105,7 @@ export class AuthService implements OnApplicationBootstrap {
if (!userId) {
await this.models.session.deleteSession(sessionId);
} else {
await this.models.session.deleteUserSession(userId, sessionId);
await this.models.session.deleteUserSessions(userId, sessionId);
}
}
@@ -195,7 +195,7 @@ export class AuthService implements OnApplicationBootstrap {
}
async revokeUserSessions(userId: string) {
return await this.models.session.deleteUserSession(userId);
return await this.models.session.deleteUserSessions(userId);
}
getSessionOptionsFromRequest(req: Request) {

View File

@@ -45,7 +45,7 @@ export const CurrentUser = createParamDecorator(
);
export interface CurrentUser
extends Pick<User, 'id' | 'email' | 'avatarUrl' | 'name'> {
extends Pick<User, 'id' | 'email' | 'avatarUrl' | 'name' | 'disabled'> {
hasPassword: boolean | null;
emailVerified: boolean;
}

View File

@@ -202,7 +202,9 @@ export class UserManagementResolver {
description: 'Get user by id',
})
async getUser(@Args('id') id: string) {
const user = await this.models.user.get(id);
const user = await this.models.user.get(id, {
withDisabled: true,
});
if (!user) {
return null;
@@ -217,7 +219,9 @@ export class UserManagementResolver {
nullable: true,
})
async getUserByEmail(@Args('email') email: string) {
const user = await this.models.user.getUserByEmail(email);
const user = await this.models.user.getUserByEmail(email, {
withDisabled: true,
});
if (!user) {
return null;
@@ -256,7 +260,7 @@ export class UserManagementResolver {
}
@Mutation(() => UserType, {
description: 'Update a user',
description: 'Update an user',
})
async updateUser(
@Args('id') id: string,
@@ -282,4 +286,18 @@ export class UserManagementResolver {
})
);
}
@Mutation(() => UserType, {
description: 'Ban an user',
})
async banUser(@Args('id') id: string): Promise<UserType> {
return sessionUser(await this.models.user.ban(id));
}
@Mutation(() => UserType, {
description: 'Reenable an banned user',
})
async enableUser(@Args('id') id: string): Promise<UserType> {
return sessionUser(await this.models.user.enable(id));
}
}

View File

@@ -41,6 +41,11 @@ export class UserType implements CurrentUser {
nullable: true,
})
createdAt?: Date | null;
@Field(() => Boolean, {
description: 'User is disabled',
})
disabled!: boolean;
}
@ObjectType()