feat(server): role changed email (#9227)

This commit is contained in:
darkskygit
2024-12-23 10:13:04 +00:00
parent 067469aa98
commit aacdb71ee2
21 changed files with 238 additions and 155 deletions

View File

@@ -147,13 +147,7 @@ test('should create session correctly', async t => {
);
});
const inviteId = await inviteUser(
app,
token,
id,
'darksky@affine.pro',
'Admin'
);
const inviteId = await inviteUser(app, token, id, 'darksky@affine.pro');
await acceptInviteById(app, id, inviteId, false);
await assertCreateSession(
id,
@@ -240,13 +234,7 @@ test('should fork session correctly', async t => {
}
);
const inviteId = await inviteUser(
app,
token,
id,
'test@affine.pro',
'Admin'
);
const inviteId = await inviteUser(app, token, id, 'test@affine.pro');
await acceptInviteById(app, id, inviteId, false);
await assertForkSession(
newToken,
@@ -609,8 +597,7 @@ test('should reject request that user have not permission', async t => {
app,
anotherToken,
workspaceId,
'darksky@affine.pro',
'Admin'
'darksky@affine.pro'
);
await acceptInviteById(app, workspaceId, inviteId, false);

View File

@@ -44,14 +44,7 @@ test('should send invite email', async t => {
const stub = Sinon.stub(mail, 'sendMail');
await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin',
true
);
await inviteUser(app, u1.token.token, workspace.id, u2.email, true);
t.true(stub.calledOnce);

View File

@@ -120,7 +120,6 @@ const init = async (
owner.token.token,
workspace.id,
member.email,
permission,
shouldSendEmail
);
await acceptInviteById(app, workspace.id, inviteId, shouldSendEmail);
@@ -133,10 +132,16 @@ const init = async (
owner.token.token,
teamWorkspace.id,
member.email,
permission,
shouldSendEmail
);
await acceptInviteById(app, teamWorkspace.id, inviteId, shouldSendEmail);
await grantMember(
app,
owner.token.token,
teamWorkspace.id,
member.id,
permission
);
}
return member;
@@ -437,8 +442,11 @@ test('should be able to manage invite link', async t => {
read,
} = await init(app, 4);
for (const workspace of [ws, tws]) {
for (const manager of [owner, admin]) {
for (const [workspace, managers] of [
[ws, [owner]],
[tws, [owner, admin]],
] as const) {
for (const manager of managers) {
const { link } = await createInviteLink(
app,
manager.token.token,
@@ -646,16 +654,21 @@ test('should be able to emit events', async t => {
const { teamWorkspace: tws, inviteBatch } = await init(app, 4);
await inviteBatch(['m1@affine.pro', 'm2@affine.pro']);
t.true(
event.emit.calledOnceWith('workspace.members.updated', {
const [membersUpdated] = event.emit
.getCalls()
.map(call => call.args)
.toReversed();
t.deepEqual(membersUpdated, [
'workspace.members.updated',
{
workspaceId: tws.id,
count: 6,
})
);
},
]);
}
{
const { teamWorkspace: tws, owner, createInviteLink } = await init(app, 10);
const { teamWorkspace: tws, owner, createInviteLink } = await init(app);
const [, invite] = await createInviteLink(tws);
const user = await invite('m3@affine.pro');
const { members } = await getWorkspace(app, owner.token.token, tws.id);
@@ -679,4 +692,39 @@ test('should be able to emit events', async t => {
'should emit review requested event'
);
}
{
const { teamWorkspace: tws, owner, read } = await init(app);
await grantMember(app, owner.token.token, tws.id, read.id, 'Admin');
t.deepEqual(
event.emit.lastCall.args,
[
'workspace.members.roleChanged',
{ userId: read.id, workspaceId: tws.id, permission: Permission.Admin },
],
'should emit role changed event'
);
await grantMember(app, owner.token.token, tws.id, read.id, 'Owner');
const [ownerTransferred, roleChanged] = event.emit
.getCalls()
.map(call => call.args)
.toReversed();
t.deepEqual(
roleChanged,
[
'workspace.members.roleChanged',
{ userId: read.id, workspaceId: tws.id, permission: Permission.Owner },
],
'should emit role changed event'
);
t.deepEqual(
ownerTransferred,
[
'workspace.members.ownerTransferred',
{ email: owner.email, workspaceId: tws.id },
],
'should emit owner transferred event'
);
}
});

View File

@@ -3,14 +3,12 @@ import request from 'supertest';
import type { InvitationType } from '../../src/core/workspaces';
import { gql } from './common';
import { PermissionEnum } from './utils';
export async function inviteUser(
app: INestApplication,
token: string,
workspaceId: string,
email: string,
permission: PermissionEnum,
sendInviteMail = false
): Promise<string> {
const res = await request(app.getHttpServer())
@@ -20,7 +18,7 @@ export async function inviteUser(
.send({
query: `
mutation {
invite(workspaceId: "${workspaceId}", email: "${email}", permission: ${permission}, sendInviteMail: ${sendInviteMail})
invite(workspaceId: "${workspaceId}", email: "${email}", sendInviteMail: ${sendInviteMail})
}
`,
})

View File

@@ -52,13 +52,7 @@ test('should invite a user', async t => {
const workspace = await createWorkspace(app, u1.token.token);
const invite = await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin'
);
const invite = await inviteUser(app, u1.token.token, workspace.id, u2.email);
t.truthy(invite, 'failed to invite user');
});
@@ -68,13 +62,7 @@ test('should leave a workspace', async t => {
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
const workspace = await createWorkspace(app, u1.token.token);
const id = await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin'
);
const id = await inviteUser(app, u1.token.token, workspace.id, u2.email);
await acceptInviteById(app, workspace.id, id, false);
const leave = await leaveWorkspace(app, u2.token.token, workspace.id);
@@ -89,7 +77,7 @@ test('should revoke a user', async t => {
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
const workspace = await createWorkspace(app, u1.token.token);
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
await inviteUser(app, u1.token.token, workspace.id, u2.email);
const currWorkspace = await getWorkspace(app, u1.token.token, workspace.id);
t.is(currWorkspace.members.length, 2, 'failed to invite user');
@@ -104,7 +92,7 @@ test('should create user if not exist', async t => {
const workspace = await createWorkspace(app, u1.token.token);
await inviteUser(app, u1.token.token, workspace.id, 'u2@affine.pro', 'Admin');
await inviteUser(app, u1.token.token, workspace.id, 'u2@affine.pro');
const u2 = await user.findUserByEmail('u2@affine.pro');
t.not(u2, undefined, 'failed to create user');
@@ -118,24 +106,12 @@ test('should invite a user by link', async t => {
const workspace = await createWorkspace(app, u1.token.token);
const invite = await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin'
);
const invite = await inviteUser(app, u1.token.token, workspace.id, u2.email);
const accept = await acceptInviteById(app, workspace.id, invite);
t.true(accept, 'failed to accept invite');
const invite1 = await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin'
);
const invite1 = await inviteUser(app, u1.token.token, workspace.id, u2.email);
t.is(invite, invite1, 'repeat the invitation must return same id');
@@ -159,7 +135,6 @@ test('should send email', async t => {
u1.token.token,
workspace.id,
u2.email,
'Admin',
true
);
@@ -224,20 +199,8 @@ test('should support pagination for member', async t => {
const u3 = await signUp(app, 'u3', 'u3@affine.pro', '1');
const workspace = await createWorkspace(app, u1.token.token);
const invite1 = await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin'
);
const invite2 = await inviteUser(
app,
u1.token.token,
workspace.id,
u3.email,
'Admin'
);
const invite1 = await inviteUser(app, u1.token.token, workspace.id, u2.email);
const invite2 = await inviteUser(app, u1.token.token, workspace.id, u3.email);
await acceptInviteById(app, workspace.id, invite1, false);
await acceptInviteById(app, workspace.id, invite2, false);
@@ -267,13 +230,7 @@ test('should limit member count correctly', async t => {
const workspace = await createWorkspace(app, u1.token.token);
await Promise.allSettled(
Array.from({ length: 10 }).map(async (_, i) =>
inviteUser(
app,
u1.token.token,
workspace.id,
`u${i}@affine.pro`,
'Admin'
)
inviteUser(app, u1.token.token, workspace.id, `u${i}@affine.pro`)
)
);

View File

@@ -134,7 +134,7 @@ test('should share a page', async t => {
await acceptInviteById(
app,
workspace.id,
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin')
await inviteUser(app, u1.token.token, workspace.id, u2.email)
);
const invited = await publishPage(app, u2.token.token, workspace.id, 'page2');
t.is(invited.id, 'page2', 'failed to share page');
@@ -211,7 +211,7 @@ test('should can get workspace doc', async t => {
await acceptInviteById(
app,
workspace.id,
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin')
await inviteUser(app, u1.token.token, workspace.id, u2.email)
);
const res2 = await request(app.getHttpServer())