mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
feat(server): doc level permission (#9760)
close CLOUD-89 CLOUD-90 CLOUD-91 CLOUD-92
This commit is contained in:
@@ -3,7 +3,8 @@ import { PrismaClient } from '@prisma/client';
|
||||
import ava, { TestFn } from 'ava';
|
||||
|
||||
import { Config } from '../../base/config';
|
||||
import { Permission, PublicPageMode } from '../../models/common';
|
||||
import { WorkspaceRole } from '../../core/permission';
|
||||
import { PublicPageMode } from '../../models/common';
|
||||
import { PageModel } from '../../models/page';
|
||||
import { type User, UserModel } from '../../models/user';
|
||||
import { type Workspace, WorkspaceModel } from '../../models/workspace';
|
||||
@@ -131,7 +132,7 @@ test('should grant a member to access a page', async t => {
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.false(hasAccess);
|
||||
// grant write permission
|
||||
@@ -139,20 +140,20 @@ test('should grant a member to access a page', async t => {
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
hasAccess = await t.context.page.isMember(
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.true(hasAccess);
|
||||
hasAccess = await t.context.page.isMember(
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Read
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.true(hasAccess);
|
||||
// delete member
|
||||
@@ -174,14 +175,14 @@ test('should change the page owner', async t => {
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.true(
|
||||
await t.context.page.isMember(
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
)
|
||||
);
|
||||
|
||||
@@ -193,14 +194,14 @@ test('should change the page owner', async t => {
|
||||
workspace.id,
|
||||
'page1',
|
||||
otherUser.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.true(
|
||||
await t.context.page.isMember(
|
||||
workspace.id,
|
||||
'page1',
|
||||
otherUser.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
)
|
||||
);
|
||||
t.false(
|
||||
@@ -208,7 +209,7 @@ test('should change the page owner', async t => {
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
)
|
||||
);
|
||||
});
|
||||
@@ -221,7 +222,7 @@ test('should not delete owner from page', async t => {
|
||||
workspace.id,
|
||||
'page1',
|
||||
user.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
const count = await t.context.page.deleteMember(
|
||||
workspace.id,
|
||||
|
||||
@@ -4,7 +4,7 @@ import ava, { TestFn } from 'ava';
|
||||
import Sinon from 'sinon';
|
||||
|
||||
import { EmailAlreadyUsed, EventBus } from '../../base';
|
||||
import { Permission } from '../../models/common';
|
||||
import { WorkspaceRole } from '../../core/permission';
|
||||
import { UserModel } from '../../models/user';
|
||||
import { WorkspaceMemberStatus } from '../../models/workspace';
|
||||
import { createTestingModule, initTestingDB } from '../utils';
|
||||
@@ -263,7 +263,7 @@ test('should trigger user.deleted event', async t => {
|
||||
public: false,
|
||||
},
|
||||
},
|
||||
type: Permission.Owner,
|
||||
type: WorkspaceRole.Owner,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import ava, { TestFn } from 'ava';
|
||||
import Sinon from 'sinon';
|
||||
|
||||
import { Config, EventBus } from '../../base';
|
||||
import { Permission } from '../../models/common';
|
||||
import { WorkspaceRole } from '../../core/permission';
|
||||
import { UserModel } from '../../models/user';
|
||||
import { WorkspaceModel } from '../../models/workspace';
|
||||
import { createTestingModule, initTestingDB } from '../utils';
|
||||
@@ -92,25 +92,25 @@ test('should workspace owner has all permissions', async t => {
|
||||
let allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
user.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.is(allowed, true);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
user.id,
|
||||
Permission.Admin
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
t.is(allowed, true);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
user.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
user.id,
|
||||
Permission.Read
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
});
|
||||
@@ -127,32 +127,32 @@ test('should workspace admin has all permissions except owner', async t => {
|
||||
data: {
|
||||
workspaceId: workspace.id,
|
||||
userId: otherUser.id,
|
||||
type: Permission.Admin,
|
||||
type: WorkspaceRole.Admin,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
},
|
||||
});
|
||||
let allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Admin
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
t.is(allowed, true);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
});
|
||||
@@ -169,32 +169,32 @@ test('should workspace write has write and read permissions', async t => {
|
||||
data: {
|
||||
workspaceId: workspace.id,
|
||||
userId: otherUser.id,
|
||||
type: Permission.Write,
|
||||
type: WorkspaceRole.Collaborator,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
},
|
||||
});
|
||||
let allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Admin
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
});
|
||||
@@ -211,32 +211,26 @@ test('should workspace read has read permission only', async t => {
|
||||
data: {
|
||||
workspaceId: workspace.id,
|
||||
userId: otherUser.id,
|
||||
type: Permission.Read,
|
||||
type: WorkspaceRole.Collaborator,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
},
|
||||
});
|
||||
let allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Admin
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Write
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, true);
|
||||
});
|
||||
@@ -252,25 +246,25 @@ test('should user not in workspace has no permissions', async t => {
|
||||
let allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Owner
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Admin
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Write
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, false);
|
||||
allowed = await t.context.workspace.isMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
t.is(allowed, false);
|
||||
});
|
||||
@@ -313,7 +307,7 @@ test('should grant member with read permission and Pending status by default', a
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.Pending);
|
||||
|
||||
// grant again should do nothing
|
||||
@@ -344,18 +338,18 @@ test('should grant Pending status member to Accepted status', async t => {
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.Pending);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Read);
|
||||
t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -370,27 +364,27 @@ test('should grant new owner and change exists owner to admin', async t => {
|
||||
const member1 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.Accepted);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Owner,
|
||||
WorkspaceRole.Owner,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Owner);
|
||||
t.is(member2.type, WorkspaceRole.Owner);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Accepted);
|
||||
// check old owner
|
||||
const owner = await t.context.workspace.getMember(workspace.id, user.id);
|
||||
t.is(owner!.type, Permission.Admin);
|
||||
t.is(owner!.type, WorkspaceRole.Admin);
|
||||
t.is(owner!.status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -405,23 +399,23 @@ test('should grant write permission on exists member', async t => {
|
||||
const member1 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.Accepted);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Write,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Write);
|
||||
t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -436,23 +430,23 @@ test('should grant UnderReview status member to Accepted status', async t => {
|
||||
const member1 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.UnderReview
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.UnderReview);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Read);
|
||||
t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -467,23 +461,23 @@ test('should grant NeedMoreSeat status member to Pending status', async t => {
|
||||
const member1 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.NeedMoreSeat
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.NeedMoreSeat);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Pending
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Read);
|
||||
t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Pending);
|
||||
});
|
||||
|
||||
@@ -498,23 +492,23 @@ test('should grant NeedMoreSeatAndReview status member to UnderReview status', a
|
||||
const member1 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.NeedMoreSeatAndReview
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.NeedMoreSeatAndReview);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.UnderReview
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Read);
|
||||
t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.UnderReview);
|
||||
});
|
||||
|
||||
@@ -532,19 +526,19 @@ test('should grant Pending status member to write permission and Accepted status
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.Pending);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Write,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
// TODO(fengmk2): fix this
|
||||
// t.is(member2.type, Permission.Write);
|
||||
// t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -559,23 +553,23 @@ test('should grant no thing on invalid status', async t => {
|
||||
const member1 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.NeedMoreSeat
|
||||
);
|
||||
t.is(member1.workspaceId, workspace.id);
|
||||
t.is(member1.userId, otherUser.id);
|
||||
t.is(member1.type, Permission.Read);
|
||||
t.is(member1.type, WorkspaceRole.Collaborator);
|
||||
t.is(member1.status, WorkspaceMemberStatus.NeedMoreSeat);
|
||||
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.workspaceId, workspace.id);
|
||||
t.is(member2.userId, otherUser.id);
|
||||
t.is(member2.type, Permission.Read);
|
||||
t.is(member2.type, WorkspaceRole.Collaborator);
|
||||
t.is(member2.status, WorkspaceMemberStatus.NeedMoreSeat);
|
||||
});
|
||||
|
||||
@@ -590,7 +584,7 @@ test('should get the accepted status workspace member', async t => {
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
const member = await t.context.workspace.getMember(
|
||||
@@ -599,7 +593,7 @@ test('should get the accepted status workspace member', async t => {
|
||||
);
|
||||
t.is(member!.workspaceId, workspace.id);
|
||||
t.is(member!.userId, otherUser.id);
|
||||
t.is(member!.type, Permission.Read);
|
||||
t.is(member!.type, WorkspaceRole.Collaborator);
|
||||
t.is(member!.status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -614,7 +608,7 @@ test('should get any status workspace member, including pending and accepted', a
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Pending
|
||||
);
|
||||
const member = await t.context.workspace.getMemberInAnyStatus(
|
||||
@@ -623,7 +617,7 @@ test('should get any status workspace member, including pending and accepted', a
|
||||
);
|
||||
t.is(member!.workspaceId, workspace.id);
|
||||
t.is(member!.userId, otherUser.id);
|
||||
t.is(member!.type, Permission.Read);
|
||||
t.is(member!.type, WorkspaceRole.Collaborator);
|
||||
t.is(member!.status, WorkspaceMemberStatus.Pending);
|
||||
});
|
||||
|
||||
@@ -635,7 +629,7 @@ test('should get workspace owner by workspace id', async t => {
|
||||
const owner = await t.context.workspace.getOwner(workspace.id);
|
||||
t.is(owner!.workspaceId, workspace.id);
|
||||
t.is(owner!.userId, user.id);
|
||||
t.is(owner!.type, Permission.Owner);
|
||||
t.is(owner!.type, WorkspaceRole.Owner);
|
||||
t.is(owner!.status, WorkspaceMemberStatus.Accepted);
|
||||
t.truthy(owner!.user);
|
||||
t.deepEqual(owner!.user, user);
|
||||
@@ -658,27 +652,27 @@ test('should find workspace admin by workspace id', async t => {
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser1.id,
|
||||
Permission.Admin,
|
||||
WorkspaceRole.Admin,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser2.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
// pending member should not be admin
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser3.id,
|
||||
Permission.Admin,
|
||||
WorkspaceRole.Admin,
|
||||
WorkspaceMemberStatus.Pending
|
||||
);
|
||||
const members = await t.context.workspace.findAdmins(workspace.id);
|
||||
t.is(members.length, 1);
|
||||
t.is(members[0].workspaceId, workspace.id);
|
||||
t.is(members[0].userId, otherUser1.id);
|
||||
t.is(members[0].type, Permission.Admin);
|
||||
t.is(members[0].type, WorkspaceRole.Admin);
|
||||
t.is(members[0].status, WorkspaceMemberStatus.Accepted);
|
||||
});
|
||||
|
||||
@@ -710,13 +704,13 @@ test('should the workspace member total count, including pending and accepted',
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser1.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Pending
|
||||
);
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser2.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
const count = await t.context.workspace.getMemberTotalCount(workspace.id);
|
||||
@@ -737,13 +731,13 @@ test('should the workspace member used count, only count the accepted member', a
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser1.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Pending
|
||||
);
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser2.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
const count = await t.context.workspace.getMemberUsedCount(workspace.id);
|
||||
@@ -855,7 +849,7 @@ test('should delete workspace member in Pending, Accepted status', async t => {
|
||||
const member2 = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
t.is(member2.status, WorkspaceMemberStatus.Accepted);
|
||||
@@ -874,7 +868,7 @@ test('should trigger workspace.members.requestDeclined event when delete workspa
|
||||
const member = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.UnderReview
|
||||
);
|
||||
t.is(member.status, WorkspaceMemberStatus.UnderReview);
|
||||
@@ -919,7 +913,7 @@ test('should trigger workspace.members.requestDeclined event when delete workspa
|
||||
const member = await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.NeedMoreSeatAndReview
|
||||
);
|
||||
t.is(member.status, WorkspaceMemberStatus.NeedMoreSeatAndReview);
|
||||
@@ -970,19 +964,19 @@ test('should refresh member seat status', async t => {
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser1.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.NeedMoreSeatAndReview
|
||||
);
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser2.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Pending
|
||||
);
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser3.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.NeedMoreSeat
|
||||
);
|
||||
let count = await t.context.db.workspaceUserPermission.count({
|
||||
@@ -1043,30 +1037,30 @@ test('should find the workspace members order by type:desc and createdAt:asc', a
|
||||
await t.context.workspace.grantMember(
|
||||
workspace.id,
|
||||
otherUser.id,
|
||||
Permission.Read,
|
||||
WorkspaceRole.Collaborator,
|
||||
WorkspaceMemberStatus.Accepted
|
||||
);
|
||||
}
|
||||
let members = await t.context.workspace.findMembers(workspace.id);
|
||||
t.is(members.length, 8);
|
||||
t.is(members[0].type, Permission.Owner);
|
||||
t.is(members[0].type, WorkspaceRole.Owner);
|
||||
t.is(members[0].status, WorkspaceMemberStatus.Accepted);
|
||||
for (let i = 1; i < 8; i++) {
|
||||
t.is(members[i].type, Permission.Read);
|
||||
t.is(members[i].type, WorkspaceRole.Collaborator);
|
||||
t.is(members[i].status, WorkspaceMemberStatus.Accepted);
|
||||
}
|
||||
members = await t.context.workspace.findMembers(workspace.id, { take: 100 });
|
||||
t.is(members.length, 11);
|
||||
t.is(members[0].type, Permission.Owner);
|
||||
t.is(members[0].type, WorkspaceRole.Owner);
|
||||
t.is(members[0].status, WorkspaceMemberStatus.Accepted);
|
||||
for (let i = 1; i < 11; i++) {
|
||||
t.is(members[i].type, Permission.Read);
|
||||
t.is(members[i].type, WorkspaceRole.Collaborator);
|
||||
t.is(members[i].status, WorkspaceMemberStatus.Accepted);
|
||||
}
|
||||
// skip should work
|
||||
members = await t.context.workspace.findMembers(workspace.id, { skip: 5 });
|
||||
t.is(members.length, 6);
|
||||
t.is(members[0].type, Permission.Read);
|
||||
t.is(members[0].type, WorkspaceRole.Collaborator);
|
||||
});
|
||||
|
||||
test('should get the workspace member invitation', async t => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AppModule } from '../app.module';
|
||||
import { EventBus } from '../base';
|
||||
import { AuthService } from '../core/auth';
|
||||
import { DocContentService } from '../core/doc-renderer';
|
||||
import { Permission, PermissionService } from '../core/permission';
|
||||
import { PermissionService, WorkspaceRole } from '../core/permission';
|
||||
import { QuotaManagementService, QuotaService, QuotaType } from '../core/quota';
|
||||
import { WorkspaceType } from '../core/workspaces';
|
||||
import {
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
inviteUser,
|
||||
inviteUsers,
|
||||
leaveWorkspace,
|
||||
PermissionEnum,
|
||||
revokeInviteLink,
|
||||
revokeMember,
|
||||
revokeUser,
|
||||
@@ -105,7 +104,7 @@ const init = async (
|
||||
|
||||
const invite = async (
|
||||
email: string,
|
||||
permission: PermissionEnum = 'Write',
|
||||
permission: WorkspaceRole = WorkspaceRole.Collaborator,
|
||||
shouldSendEmail: boolean = false
|
||||
) => {
|
||||
const member = await signUp(app, email.split('@')[0], email, '123456');
|
||||
@@ -193,9 +192,12 @@ const init = async (
|
||||
] as const;
|
||||
};
|
||||
|
||||
const admin = await invite(`${prefix}admin@affine.pro`, 'Admin');
|
||||
const admin = await invite(`${prefix}admin@affine.pro`, WorkspaceRole.Admin);
|
||||
const write = await invite(`${prefix}write@affine.pro`);
|
||||
const read = await invite(`${prefix}read@affine.pro`, 'Read');
|
||||
const read = await invite(
|
||||
`${prefix}read@affine.pro`,
|
||||
WorkspaceRole.Collaborator
|
||||
);
|
||||
|
||||
return {
|
||||
invite,
|
||||
@@ -268,7 +270,7 @@ test('should be able to check seat limit', async t => {
|
||||
{
|
||||
// invite
|
||||
await t.throwsAsync(
|
||||
invite('member3@affine.pro', 'Read'),
|
||||
invite('member3@affine.pro', WorkspaceRole.Collaborator),
|
||||
{ message: 'You have exceeded your workspace member quota.' },
|
||||
'should throw error if exceed member limit'
|
||||
);
|
||||
@@ -276,7 +278,7 @@ test('should be able to check seat limit', async t => {
|
||||
memberLimit: 5,
|
||||
});
|
||||
await t.notThrowsAsync(
|
||||
invite('member4@affine.pro', 'Read'),
|
||||
invite('member4@affine.pro', WorkspaceRole.Collaborator),
|
||||
'should not throw error if not exceed member limit'
|
||||
);
|
||||
}
|
||||
@@ -324,17 +326,35 @@ test('should be able to grant team member permission', async t => {
|
||||
const { owner, teamWorkspace: ws, admin, write, read } = await init(app);
|
||||
|
||||
await t.throwsAsync(
|
||||
grantMember(app, read.token.token, ws.id, write.id, 'Write'),
|
||||
grantMember(
|
||||
app,
|
||||
read.token.token,
|
||||
ws.id,
|
||||
write.id,
|
||||
WorkspaceRole.Collaborator
|
||||
),
|
||||
{ instanceOf: Error },
|
||||
'should throw error if not owner'
|
||||
);
|
||||
await t.throwsAsync(
|
||||
grantMember(app, write.token.token, ws.id, read.id, 'Write'),
|
||||
grantMember(
|
||||
app,
|
||||
write.token.token,
|
||||
ws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Collaborator
|
||||
),
|
||||
{ instanceOf: Error },
|
||||
'should throw error if not owner'
|
||||
);
|
||||
await t.throwsAsync(
|
||||
grantMember(app, admin.token.token, ws.id, read.id, 'Write'),
|
||||
grantMember(
|
||||
app,
|
||||
admin.token.token,
|
||||
ws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Collaborator
|
||||
),
|
||||
{ instanceOf: Error },
|
||||
'should throw error if not owner'
|
||||
);
|
||||
@@ -342,15 +362,29 @@ test('should be able to grant team member permission', async t => {
|
||||
{
|
||||
// owner should be able to grant permission
|
||||
t.true(
|
||||
await permissions.tryCheckWorkspaceIs(ws.id, read.id, Permission.Read),
|
||||
await permissions.tryCheckWorkspaceIs(
|
||||
ws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Collaborator
|
||||
),
|
||||
'should be able to check permission'
|
||||
);
|
||||
t.truthy(
|
||||
await grantMember(app, owner.token.token, ws.id, read.id, 'Admin'),
|
||||
await grantMember(
|
||||
app,
|
||||
owner.token.token,
|
||||
ws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Admin
|
||||
),
|
||||
'should be able to grant permission'
|
||||
);
|
||||
t.true(
|
||||
await permissions.tryCheckWorkspaceIs(ws.id, read.id, Permission.Admin),
|
||||
await permissions.tryCheckWorkspaceIs(
|
||||
ws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Admin
|
||||
),
|
||||
'should be able to check permission'
|
||||
);
|
||||
}
|
||||
@@ -692,17 +726,33 @@ test('should be able to emit events', async t => {
|
||||
|
||||
{
|
||||
const { teamWorkspace: tws, owner, read } = await init(app);
|
||||
await grantMember(app, owner.token.token, tws.id, read.id, 'Admin');
|
||||
await grantMember(
|
||||
app,
|
||||
owner.token.token,
|
||||
tws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
t.deepEqual(
|
||||
event.emit.lastCall.args,
|
||||
[
|
||||
'workspace.members.roleChanged',
|
||||
{ userId: read.id, workspaceId: tws.id, permission: Permission.Admin },
|
||||
{
|
||||
userId: read.id,
|
||||
workspaceId: tws.id,
|
||||
permission: WorkspaceRole.Admin,
|
||||
},
|
||||
],
|
||||
'should emit role changed event'
|
||||
);
|
||||
|
||||
await grantMember(app, owner.token.token, tws.id, read.id, 'Owner');
|
||||
await grantMember(
|
||||
app,
|
||||
owner.token.token,
|
||||
tws.id,
|
||||
read.id,
|
||||
WorkspaceRole.Owner
|
||||
);
|
||||
const [ownershipTransferred] = event.emit
|
||||
.getCalls()
|
||||
.map(call => call.args)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaClient, WorkspaceMemberStatus } from '@prisma/client';
|
||||
|
||||
import { Permission } from '../../core/permission';
|
||||
import { WorkspaceRole } from '../../core/permission';
|
||||
import { UserType } from '../../core/user/types';
|
||||
|
||||
@Injectable()
|
||||
@@ -14,7 +14,7 @@ export class WorkspaceResolverMock {
|
||||
public: false,
|
||||
permissions: {
|
||||
create: {
|
||||
type: Permission.Owner,
|
||||
type: WorkspaceRole.Owner,
|
||||
userId: user.id,
|
||||
accepted: true,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { INestApplication, ModuleMetadata } from '@nestjs/common';
|
||||
import {
|
||||
ConsoleLogger,
|
||||
INestApplication,
|
||||
ModuleMetadata,
|
||||
} from '@nestjs/common';
|
||||
import { APP_GUARD } from '@nestjs/core';
|
||||
import { Query, Resolver } from '@nestjs/graphql';
|
||||
import { Test, TestingModuleBuilder } from '@nestjs/testing';
|
||||
@@ -15,8 +19,6 @@ import { AuthGuard, AuthModule } from '../../core/auth';
|
||||
import { UserFeaturesInit1698652531198 } from '../../data/migrations/1698652531198-user-features-init';
|
||||
import { ModelsModule } from '../../models';
|
||||
|
||||
export type PermissionEnum = 'Owner' | 'Admin' | 'Write' | 'Read';
|
||||
|
||||
async function flushDB(client: PrismaClient) {
|
||||
const result: { tablename: string }[] =
|
||||
await client.$queryRaw`SELECT tablename
|
||||
@@ -133,8 +135,11 @@ export async function createTestingApp(moduleDef: TestingModuleMeatdata = {}) {
|
||||
cors: true,
|
||||
bodyParser: true,
|
||||
rawBody: true,
|
||||
logger: ['fatal'],
|
||||
});
|
||||
const logger = new ConsoleLogger();
|
||||
|
||||
logger.setLogLevels(['fatal']);
|
||||
app.useLogger(logger);
|
||||
|
||||
app.useGlobalFilters(new GlobalExceptionFilter(app.getHttpAdapter()));
|
||||
app.use(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { INestApplication } from '@nestjs/common';
|
||||
import request from 'supertest';
|
||||
|
||||
import { WorkspaceRole } from '../../core/permission/types';
|
||||
import type { WorkspaceType } from '../../core/workspaces';
|
||||
import { gql } from './common';
|
||||
import { PermissionEnum } from './utils';
|
||||
|
||||
export async function createWorkspace(
|
||||
app: INestApplication,
|
||||
@@ -157,7 +157,7 @@ export async function grantMember(
|
||||
token: string,
|
||||
workspaceId: string,
|
||||
userId: string,
|
||||
permission: PermissionEnum
|
||||
permission: WorkspaceRole
|
||||
) {
|
||||
const res = await request(app.getHttpServer())
|
||||
.post(gql)
|
||||
@@ -169,7 +169,7 @@ export async function grantMember(
|
||||
grantMember(
|
||||
workspaceId: "${workspaceId}"
|
||||
userId: "${userId}"
|
||||
permission: ${permission}
|
||||
permission: ${WorkspaceRole[permission]}
|
||||
)
|
||||
}
|
||||
`,
|
||||
|
||||
@@ -5,11 +5,13 @@ import ava from 'ava';
|
||||
import request from 'supertest';
|
||||
|
||||
import { AppModule } from '../app.module';
|
||||
import { WorkspaceRole } from '../core/permission/types';
|
||||
import {
|
||||
acceptInviteById,
|
||||
createTestingApp,
|
||||
createWorkspace,
|
||||
getWorkspacePublicPages,
|
||||
grantMember,
|
||||
inviteUser,
|
||||
publishPage,
|
||||
revokePublicPage,
|
||||
@@ -116,7 +118,7 @@ test('should share a page', async t => {
|
||||
const msg1 = await publishPage(app, u2.token.token, 'not_exists_ws', 'page2');
|
||||
t.is(
|
||||
msg1,
|
||||
'You do not have permission to access Space not_exists_ws.',
|
||||
'You do not have permission to access doc page2 under Space not_exists_ws.',
|
||||
'unauthorized user can share page'
|
||||
);
|
||||
const msg2 = await revokePublicPage(
|
||||
@@ -127,7 +129,7 @@ test('should share a page', async t => {
|
||||
);
|
||||
t.is(
|
||||
msg2,
|
||||
'You do not have permission to access Space not_exists_ws.',
|
||||
'You do not have permission to access doc page2 under Space not_exists_ws.',
|
||||
'unauthorized user can share page'
|
||||
);
|
||||
|
||||
@@ -136,6 +138,21 @@ test('should share a page', async t => {
|
||||
workspace.id,
|
||||
await inviteUser(app, u1.token.token, workspace.id, u2.email)
|
||||
);
|
||||
const msg3 = await publishPage(app, u2.token.token, workspace.id, 'page2');
|
||||
t.is(
|
||||
msg3,
|
||||
`You do not have permission to access doc page2 under Space ${workspace.id}.`,
|
||||
'WorkspaceRole and PageRole is lower than required'
|
||||
);
|
||||
|
||||
await grantMember(
|
||||
app,
|
||||
u1.token.token,
|
||||
workspace.id,
|
||||
u2.id,
|
||||
WorkspaceRole.Admin
|
||||
);
|
||||
|
||||
const invited = await publishPage(app, u2.token.token, workspace.id, 'page2');
|
||||
t.is(invited.id, 'page2', 'failed to share page');
|
||||
|
||||
@@ -154,21 +171,21 @@ test('should share a page', async t => {
|
||||
t.is(pages2.length, 1, 'failed to get shared pages');
|
||||
t.is(pages2[0].id, 'page2', 'failed to get shared page: page2');
|
||||
|
||||
const msg3 = await revokePublicPage(
|
||||
const msg4 = await revokePublicPage(
|
||||
app,
|
||||
u1.token.token,
|
||||
workspace.id,
|
||||
'page3'
|
||||
);
|
||||
t.is(msg3, 'Page is not public');
|
||||
t.is(msg4, 'Page is not public');
|
||||
|
||||
const msg4 = await revokePublicPage(
|
||||
const revoked = await revokePublicPage(
|
||||
app,
|
||||
u1.token.token,
|
||||
workspace.id,
|
||||
'page2'
|
||||
);
|
||||
t.false(msg4.public, 'failed to revoke page');
|
||||
t.false(revoked.public, 'failed to revoke page');
|
||||
const page3 = await getWorkspacePublicPages(
|
||||
app,
|
||||
u1.token.token,
|
||||
@@ -177,7 +194,7 @@ test('should share a page', async t => {
|
||||
t.is(page3.length, 0, 'failed to get shared pages');
|
||||
});
|
||||
|
||||
test('should can get workspace doc', async t => {
|
||||
test('should be able to get workspace doc', async t => {
|
||||
const { app } = t.context;
|
||||
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
||||
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '2');
|
||||
|
||||
Reference in New Issue
Block a user