mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-08 04:36:13 +08:00
feat(server): team quota (#8955)
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaClient, WorkspaceMemberStatus } from '@prisma/client';
|
||||
|
||||
import { Permission } from '../../src/core/permission';
|
||||
import { UserType } from '../../src/core/user/types';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceResolverMock {
|
||||
constructor(private readonly prisma: PrismaClient) {}
|
||||
|
||||
async createWorkspace(user: UserType, _init: null) {
|
||||
const workspace = await this.prisma.workspace.create({
|
||||
data: {
|
||||
public: false,
|
||||
permissions: {
|
||||
create: {
|
||||
type: Permission.Owner,
|
||||
userId: user.id,
|
||||
accepted: true,
|
||||
status: WorkspaceMemberStatus.Accepted,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return workspace;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,14 @@ 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: string,
|
||||
permission: PermissionEnum,
|
||||
sendInviteMail = false
|
||||
): Promise<string> {
|
||||
const res = await request(app.getHttpServer())
|
||||
@@ -24,18 +25,81 @@ export async function inviteUser(
|
||||
`,
|
||||
})
|
||||
.expect(200);
|
||||
if (res.body.errors) {
|
||||
throw new Error(res.body.errors[0].message);
|
||||
}
|
||||
return res.body.data.invite;
|
||||
}
|
||||
|
||||
export async function inviteUsers(
|
||||
app: INestApplication,
|
||||
token: string,
|
||||
workspaceId: string,
|
||||
emails: string[],
|
||||
sendInviteMail = false
|
||||
): Promise<Array<{ email: string; inviteId?: string; sentSuccess?: boolean }>> {
|
||||
const res = await request(app.getHttpServer())
|
||||
.post(gql)
|
||||
.auth(token, { type: 'bearer' })
|
||||
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
||||
.send({
|
||||
query: `
|
||||
mutation inviteBatch($workspaceId: String!, $emails: [String!]!, $sendInviteMail: Boolean) {
|
||||
inviteBatch(
|
||||
workspaceId: $workspaceId
|
||||
emails: $emails
|
||||
sendInviteMail: $sendInviteMail
|
||||
) {
|
||||
email
|
||||
inviteId
|
||||
sentSuccess
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { workspaceId, emails, sendInviteMail },
|
||||
})
|
||||
.expect(200);
|
||||
if (res.body.errors) {
|
||||
throw new Error(res.body.errors[0].message);
|
||||
}
|
||||
return res.body.data.inviteBatch;
|
||||
}
|
||||
|
||||
export async function inviteLink(
|
||||
app: INestApplication,
|
||||
token: string,
|
||||
workspaceId: string,
|
||||
expireTime: 'OneDay' | 'ThreeDays' | 'OneWeek' | 'OneMonth'
|
||||
): Promise<string> {
|
||||
const res = await request(app.getHttpServer())
|
||||
.post(gql)
|
||||
.auth(token, { type: 'bearer' })
|
||||
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
||||
.send({
|
||||
query: `
|
||||
mutation {
|
||||
inviteLink(workspaceId: "${workspaceId}", expireTime: ${expireTime})
|
||||
}
|
||||
`,
|
||||
})
|
||||
.expect(200);
|
||||
if (res.body.errors) {
|
||||
throw new Error(res.body.errors[0].message);
|
||||
}
|
||||
return res.body.data.inviteLink;
|
||||
}
|
||||
|
||||
export async function acceptInviteById(
|
||||
app: INestApplication,
|
||||
workspaceId: string,
|
||||
inviteId: string,
|
||||
sendAcceptMail = false
|
||||
sendAcceptMail = false,
|
||||
token: string = ''
|
||||
): Promise<boolean> {
|
||||
const res = await request(app.getHttpServer())
|
||||
.post(gql)
|
||||
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
||||
.auth(token, { type: 'bearer' })
|
||||
.send({
|
||||
query: `
|
||||
mutation {
|
||||
@@ -44,6 +108,9 @@ export async function acceptInviteById(
|
||||
`,
|
||||
})
|
||||
.expect(200);
|
||||
if (res.body.errors) {
|
||||
throw new Error(res.body.errors[0].message);
|
||||
}
|
||||
return res.body.data.acceptInviteById;
|
||||
}
|
||||
|
||||
@@ -65,6 +132,9 @@ export async function leaveWorkspace(
|
||||
`,
|
||||
})
|
||||
.expect(200);
|
||||
if (res.body.errors) {
|
||||
throw new Error(res.body.errors[0].message);
|
||||
}
|
||||
return res.body.data.leaveWorkspace;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import { sessionUser } from '../../src/core/auth/service';
|
||||
import { UserService, type UserType } from '../../src/core/user';
|
||||
import { gql } from './common';
|
||||
|
||||
export type UserAuthedType = UserType & { token: ClientTokenType };
|
||||
|
||||
export async function internalSignIn(app: INestApplication, userId: string) {
|
||||
const auth = app.get(AuthService);
|
||||
|
||||
@@ -49,7 +51,7 @@ export async function signUp(
|
||||
email: string,
|
||||
password: string,
|
||||
autoVerifyEmail = true
|
||||
): Promise<UserType & { token: ClientTokenType }> {
|
||||
): Promise<UserAuthedType> {
|
||||
const user = await app.get(UserService).createUser({
|
||||
name,
|
||||
email,
|
||||
@@ -176,7 +178,7 @@ export async function changeEmail(
|
||||
userToken: string,
|
||||
token: string,
|
||||
email: string
|
||||
): Promise<UserType & { token: ClientTokenType }> {
|
||||
): Promise<UserAuthedType> {
|
||||
const res = await request(app.getHttpServer())
|
||||
.post(gql)
|
||||
.auth(userToken, { type: 'bearer' })
|
||||
|
||||
@@ -14,6 +14,8 @@ import { UserFeaturesInit1698652531198 } from '../../src/data/migrations/1698652
|
||||
import { Config, GlobalExceptionFilter } from '../../src/fundamentals';
|
||||
import { GqlModule } from '../../src/fundamentals/graphql';
|
||||
|
||||
export type PermissionEnum = 'Owner' | 'Admin' | 'Write' | 'Read';
|
||||
|
||||
async function flushDB(client: PrismaClient) {
|
||||
const result: { tablename: string }[] =
|
||||
await client.$queryRaw`SELECT tablename
|
||||
|
||||
@@ -3,6 +3,7 @@ import request from 'supertest';
|
||||
|
||||
import type { WorkspaceType } from '../../src/core/workspaces';
|
||||
import { gql } from './common';
|
||||
import { PermissionEnum } from './utils';
|
||||
|
||||
export async function createWorkspace(
|
||||
app: INestApplication,
|
||||
@@ -150,3 +151,32 @@ export async function revokePublicPage(
|
||||
.expect(200);
|
||||
return res.body.errors?.[0]?.message || res.body.data?.revokePublicPage;
|
||||
}
|
||||
|
||||
export async function grantMember(
|
||||
app: INestApplication,
|
||||
token: string,
|
||||
workspaceId: string,
|
||||
userId: string,
|
||||
permission: PermissionEnum
|
||||
) {
|
||||
const res = await request(app.getHttpServer())
|
||||
.post(gql)
|
||||
.auth(token, { type: 'bearer' })
|
||||
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
||||
.send({
|
||||
query: `
|
||||
mutation {
|
||||
grantMember(
|
||||
workspaceId: "${workspaceId}"
|
||||
userId: "${userId}"
|
||||
permission: ${permission}
|
||||
)
|
||||
}
|
||||
`,
|
||||
})
|
||||
.expect(200);
|
||||
if (res.body.errors) {
|
||||
throw new Error(res.body.errors[0].message);
|
||||
}
|
||||
return res.body.data?.grantMember;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user