mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 09:06:19 +08:00
feat(server): handle account deleting properly (#12399)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Users are now prevented from deleting their account if they own one or more team workspaces. A clear error message instructs users to transfer ownership or delete those workspaces first. - Disabled (banned) users are explicitly prevented from signing in or re-registering. - Added new error messages and translations to improve clarity around account deletion restrictions. - **Bug Fixes** - Disabled users are now explicitly handled to prevent sign-in attempts. - **Tests** - Introduced comprehensive end-to-end tests covering account deletion, banning, and re-registration scenarios. - **Chores** - Improved event handling for user deletion and subscription cancellation. - Updated localization resources with new error messages. - Renamed payment event handler class for clarity. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -154,12 +154,10 @@ export class TestingApp extends NestApplication {
|
||||
}
|
||||
|
||||
async login(user: MockedUser) {
|
||||
await this.POST('/api/auth/sign-in')
|
||||
.send({
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
})
|
||||
.expect(200);
|
||||
return await this.POST('/api/auth/sign-in').send({
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
});
|
||||
}
|
||||
|
||||
async switchUser(userOrId: string | { id: string }) {
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
import {
|
||||
deleteAccountMutation,
|
||||
disableUserMutation,
|
||||
getCurrentUserQuery,
|
||||
getWorkspaceQuery,
|
||||
} from '@affine/graphql';
|
||||
|
||||
import { app, e2e, Mockers } from '../test';
|
||||
|
||||
const admin = await app.create(Mockers.User, {
|
||||
feature: 'administrator',
|
||||
});
|
||||
|
||||
e2e('should be able to delete account', async t => {
|
||||
const user = await app.signup();
|
||||
const user2 = await app.create(Mockers.User);
|
||||
const ws = await app.create(Mockers.Workspace, {
|
||||
owner: user,
|
||||
});
|
||||
|
||||
await app.create(Mockers.WorkspaceUser, {
|
||||
workspaceId: ws.id,
|
||||
userId: user2.id,
|
||||
});
|
||||
|
||||
await app.gql({
|
||||
query: deleteAccountMutation,
|
||||
});
|
||||
|
||||
// assert session removed
|
||||
const { currentUser } = await app.gql({
|
||||
query: getCurrentUserQuery,
|
||||
});
|
||||
|
||||
t.is(currentUser, null);
|
||||
|
||||
// assert login failed
|
||||
const res = await app.login(user);
|
||||
t.is(res.status, 400);
|
||||
t.like(res.body, {
|
||||
message: `Wrong user email or password: ${user.email}`,
|
||||
});
|
||||
|
||||
// assert workspace access deleted
|
||||
await app.login(user2);
|
||||
await t.throwsAsync(
|
||||
app.gql({
|
||||
query: getWorkspaceQuery,
|
||||
variables: {
|
||||
id: ws.id,
|
||||
},
|
||||
}),
|
||||
{
|
||||
message: `You do not have permission to access Space ${ws.id}.`,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
e2e('should not delete account if is owner of team workspace', async t => {
|
||||
const user = await app.signup();
|
||||
const ws = await app.create(Mockers.Workspace, {
|
||||
owner: user,
|
||||
});
|
||||
|
||||
await app.create(Mockers.TeamWorkspace, {
|
||||
id: ws.id,
|
||||
});
|
||||
|
||||
await t.throwsAsync(
|
||||
app.gql({
|
||||
query: deleteAccountMutation,
|
||||
}),
|
||||
{
|
||||
message:
|
||||
'Cannot delete account. You are the owner of one or more team workspaces. Please transfer ownership or delete them first.',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
e2e('should register deleted account again', async t => {
|
||||
const user = await app.signup();
|
||||
await app.gql({
|
||||
query: deleteAccountMutation,
|
||||
});
|
||||
|
||||
const res = await app.POST('/api/auth/sign-in').send({
|
||||
email: user.email,
|
||||
});
|
||||
t.is(res.status, 200);
|
||||
t.like(await app.mails.waitFor('SignUp'), {
|
||||
to: user.email,
|
||||
});
|
||||
});
|
||||
|
||||
e2e('should ban account', async t => {
|
||||
const user = await app.create(Mockers.User);
|
||||
|
||||
await app.login(admin);
|
||||
|
||||
const { banUser } = await app.gql({
|
||||
query: disableUserMutation,
|
||||
variables: {
|
||||
id: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
t.is(banUser.disabled, true);
|
||||
});
|
||||
|
||||
e2e('should not login banned account', async t => {
|
||||
const user = await app.create(Mockers.User);
|
||||
|
||||
await app.login(admin);
|
||||
|
||||
await app.gql({
|
||||
query: disableUserMutation,
|
||||
variables: {
|
||||
id: user.id,
|
||||
},
|
||||
});
|
||||
await app.logout();
|
||||
|
||||
const res = await app.login(user);
|
||||
t.is(res.status, 400);
|
||||
t.like(res.body, {
|
||||
message: `Wrong user email or password: ${user.email}`,
|
||||
});
|
||||
});
|
||||
|
||||
e2e('should not signup banned account', async t => {
|
||||
const user = await app.create(Mockers.User);
|
||||
|
||||
await app.login(admin);
|
||||
|
||||
await app.gql({
|
||||
query: disableUserMutation,
|
||||
variables: {
|
||||
id: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
const res = await app.POST('/api/auth/sign-in').send({
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
t.is(res.status, 400);
|
||||
t.like(res.body, {
|
||||
message: `Wrong user email or password: ${user.email}`,
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user