mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-11 23:26:30 +08:00
feat(server): port resolvers to node server (#2026)
Co-authored-by: Himself65 <himself65@outlook.com>
This commit is contained in:
@@ -1,85 +1,206 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
import { ForbiddenException, NotFoundException } from '@nestjs/common';
|
||||
import {
|
||||
Args,
|
||||
Field,
|
||||
ID,
|
||||
InputType,
|
||||
Int,
|
||||
Mutation,
|
||||
ObjectType,
|
||||
Parent,
|
||||
PartialType,
|
||||
PickType,
|
||||
Query,
|
||||
registerEnumType,
|
||||
ResolveField,
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
import type { workspaces } from '@prisma/client';
|
||||
import type { User, Workspace } from '@prisma/client';
|
||||
|
||||
import { PrismaService } from '../../prisma/service';
|
||||
import { PrismaService } from '../../prisma';
|
||||
import { Auth, CurrentUser } from '../auth';
|
||||
import { UserType } from '../users/resolver';
|
||||
import { PermissionService } from './permission';
|
||||
import { Permission } from './types';
|
||||
|
||||
export enum WorkspaceType {
|
||||
Private = 0,
|
||||
Normal = 1,
|
||||
}
|
||||
|
||||
registerEnumType(WorkspaceType, {
|
||||
name: 'WorkspaceType',
|
||||
description: 'Workspace type',
|
||||
valuesMap: {
|
||||
Normal: {
|
||||
description: 'Normal workspace',
|
||||
},
|
||||
Private: {
|
||||
description: 'Private workspace',
|
||||
},
|
||||
},
|
||||
registerEnumType(Permission, {
|
||||
name: 'Permission',
|
||||
description: 'User permission in workspace',
|
||||
});
|
||||
|
||||
@ObjectType()
|
||||
export class Workspace implements workspaces {
|
||||
export class WorkspaceType implements Partial<Workspace> {
|
||||
@Field(() => ID)
|
||||
id!: string;
|
||||
|
||||
@Field({ description: 'is Public workspace' })
|
||||
public!: boolean;
|
||||
@Field(() => WorkspaceType, { description: 'Workspace type' })
|
||||
type!: WorkspaceType;
|
||||
|
||||
@Field({ description: 'Workspace created date' })
|
||||
created_at!: Date;
|
||||
createdAt!: Date;
|
||||
}
|
||||
|
||||
@Resolver(() => Workspace)
|
||||
@InputType()
|
||||
export class UpdateWorkspaceInput extends PickType(
|
||||
PartialType(WorkspaceType),
|
||||
['public'],
|
||||
InputType
|
||||
) {
|
||||
@Field(() => ID)
|
||||
id!: string;
|
||||
}
|
||||
|
||||
@Auth()
|
||||
@Resolver(() => WorkspaceType)
|
||||
export class WorkspaceResolver {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly permissionProvider: PermissionService
|
||||
) {}
|
||||
|
||||
// debug only query should be removed
|
||||
@Query(() => [Workspace], {
|
||||
name: 'workspaces',
|
||||
description: 'Get all workspaces',
|
||||
@ResolveField(() => Permission, {
|
||||
description: 'Permission of current signed in user in workspace',
|
||||
complexity: 2,
|
||||
})
|
||||
async workspaces() {
|
||||
return this.prisma.workspaces.findMany();
|
||||
async permission(
|
||||
@CurrentUser() user: User,
|
||||
@Parent() workspace: WorkspaceType
|
||||
) {
|
||||
// may applied in workspaces query
|
||||
if ('permission' in workspace) {
|
||||
return workspace.permission;
|
||||
}
|
||||
|
||||
const permission = this.permissionProvider.get(workspace.id, user.id);
|
||||
|
||||
if (!permission) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
@Query(() => Workspace, {
|
||||
name: 'workspace',
|
||||
description: 'Get workspace by id',
|
||||
@ResolveField(() => Int, {
|
||||
description: 'member count of workspace',
|
||||
complexity: 2,
|
||||
})
|
||||
async workspace(@Args('id') id: string) {
|
||||
return this.prisma.workspaces.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
// create workspace
|
||||
@Mutation(() => Workspace, {
|
||||
name: 'createWorkspace',
|
||||
description: 'Create workspace',
|
||||
})
|
||||
async createWorkspace() {
|
||||
return this.prisma.workspaces.create({
|
||||
data: {
|
||||
id: randomUUID(),
|
||||
type: WorkspaceType.Private,
|
||||
public: false,
|
||||
created_at: new Date(),
|
||||
memberCount(@Parent() workspace: WorkspaceType) {
|
||||
return this.prisma.userWorkspacePermission.count({
|
||||
where: {
|
||||
workspaceId: workspace.id,
|
||||
accepted: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => UserType, {
|
||||
description: 'Owner of workspace',
|
||||
complexity: 2,
|
||||
})
|
||||
async owner(@Parent() workspace: WorkspaceType) {
|
||||
const data = await this.prisma.userWorkspacePermission.findFirstOrThrow({
|
||||
where: {
|
||||
workspaceId: workspace.id,
|
||||
type: Permission.Owner,
|
||||
},
|
||||
include: {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
|
||||
return data.user;
|
||||
}
|
||||
|
||||
@Query(() => [WorkspaceType], {
|
||||
description: 'Get all accessible workspaces for current user',
|
||||
complexity: 2,
|
||||
})
|
||||
async workspaces(@CurrentUser() user: User) {
|
||||
const data = await this.prisma.userWorkspacePermission.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
accepted: true,
|
||||
},
|
||||
include: {
|
||||
workspace: true,
|
||||
},
|
||||
});
|
||||
|
||||
return data.map(({ workspace, type }) => {
|
||||
return {
|
||||
...workspace,
|
||||
permission: type,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => WorkspaceType, {
|
||||
description: 'Get workspace by id',
|
||||
})
|
||||
async workspace(@CurrentUser() user: UserType, @Args('id') id: string) {
|
||||
await this.permissionProvider.check(id, user.id);
|
||||
const workspace = await this.prisma.workspace.findUnique({ where: { id } });
|
||||
|
||||
if (!workspace) {
|
||||
throw new NotFoundException("Workspace doesn't exist");
|
||||
}
|
||||
|
||||
return workspace;
|
||||
}
|
||||
|
||||
@Mutation(() => WorkspaceType, {
|
||||
description: 'Create a new workspace',
|
||||
})
|
||||
async createWorkspace(@CurrentUser() user: User) {
|
||||
return this.prisma.workspace.create({
|
||||
data: {
|
||||
public: false,
|
||||
users: {
|
||||
create: {
|
||||
type: Permission.Owner,
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
},
|
||||
},
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => WorkspaceType, {
|
||||
description: 'Update workspace',
|
||||
})
|
||||
async updateWorkspace(
|
||||
@CurrentUser() user: User,
|
||||
@Args({ name: 'input', type: () => UpdateWorkspaceInput })
|
||||
{ id, ...updates }: UpdateWorkspaceInput
|
||||
) {
|
||||
await this.permissionProvider.check('id', user.id, Permission.Admin);
|
||||
|
||||
return this.prisma.workspace.update({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
data: updates,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
async deleteWorkspace(@CurrentUser() user: User, @Args('id') id: string) {
|
||||
await this.permissionProvider.check(id, user.id, Permission.Owner);
|
||||
|
||||
await this.prisma.workspace.delete({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
// TODO:
|
||||
// delete all related data, like websocket connections, blobs, etc.
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user