fix(server): default page owner (#10015)

This commit is contained in:
forehalo
2025-02-07 07:31:56 +00:00
parent 9fd547d484
commit 4b1c931503
7 changed files with 97 additions and 36 deletions

View File

@@ -39,15 +39,16 @@ export class PaginationInput {
'returns the elements in the list that come after the specified cursor.',
middleware: [parseCursorMiddleware],
})
after!: string | null;
after?: string | null;
@Field(() => String, {
nullable: true,
description:
'returns the elements in the list that come before the specified cursor.',
middleware: [parseCursorMiddleware],
})
before!: string | null;
// NOT IMPLEMENTED YET
// @Field(() => String, {
// nullable: true,
// description:
// 'returns the elements in the list that come before the specified cursor.',
// middleware: [parseCursorMiddleware],
// })
// before?: string | null;
}
const encode = (input: string) => Buffer.from(input).toString('base64');

View File

@@ -1,17 +1,23 @@
import { Type } from '@nestjs/common';
import { Field, ObjectType } from '@nestjs/graphql';
import { Field, FieldOptions, ObjectType } from '@nestjs/graphql';
import { ApplyType } from '../utils/types';
export function registerObjectType<T>(
fields: Record<string, Type<any>>,
fields: Record<
string,
{
type: () => Type<any>;
options?: FieldOptions;
}
>,
options: {
name: string;
}
) {
const Inner = ApplyType<T>();
for (const [key, value] of Object.entries(fields)) {
Field(() => value)(Inner.prototype, key);
for (const [key, { type, options }] of Object.entries(fields)) {
Field(type, options)(Inner.prototype, key);
}
ObjectType(options.name)(Inner);

View File

@@ -32,7 +32,7 @@ declare global {
workspaceId: string;
docId: string;
};
'doc.update.pushed': {
'doc.created': {
workspaceId: string;
docId: string;
editor?: string;
@@ -63,6 +63,8 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
return 0;
}
const isNewDoc = !(await this.docExisted(workspaceId, docId));
let pendings = updates;
let done = 0;
let timestamp = Date.now();
@@ -110,11 +112,14 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
await this.updateCachedUpdatesCount(workspaceId, docId, batch.length);
}
});
this.event.emit('doc.update.pushed', {
workspaceId,
docId,
editor: editorId,
});
if (isNewDoc) {
this.event.emit('doc.created', {
workspaceId,
docId,
editor: editorId,
});
}
} catch (e) {
this.logger.error('Failed to insert doc updates', e);
metrics.doc.counter('doc_update_insert_failed').add(1);
@@ -589,6 +594,27 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
}
}
private async docExisted(workspaceId: string, docId: string) {
const snapshot = await this.db.snapshot.count({
where: {
workspaceId,
id: docId,
},
});
if (snapshot > 0) {
return true;
}
const updates = await this.db.update.count({
where: {
workspaceId,
id: docId,
},
});
return updates > 0;
}
/**
* @deprecated
*/

View File

@@ -30,16 +30,23 @@ export class PermissionService {
private readonly event: EventBus
) {}
@OnEvent('doc.update.pushed')
async onDocUpdatePushed(payload: Events['doc.update.pushed']) {
@OnEvent('doc.created')
async setDefaultPageOwner(payload: Events['doc.created']) {
const { workspaceId, docId, editor } = payload;
await this.prisma.$queryRaw`
INSERT INTO "workspace_page_user_permissions" ("workspace_id", "page_id", "user_id", "type", "created_at")
VALUES (${workspaceId}, ${docId}, ${editor}, ${DocRole.Owner}, now())
ON CONFLICT ("workspace_id", "page_id", "user_id")
DO NOTHING
`;
if (!editor) {
return;
}
await this.prisma.workspacePageUserPermission.createMany({
data: {
workspaceId,
pageId: docId,
userId: editor,
type: DocRole.Owner,
createdAt: new Date(),
},
});
}
private get acceptedCondition() {

View File

@@ -130,7 +130,15 @@ class PaginatedGrantedDocUserType extends Paginated(GrantedDocUserType) {}
const DocPermissions = registerObjectType<DocActionPermissions>(
Object.fromEntries(
DOC_ACTIONS.map(action => [action.replaceAll('.', '_'), Boolean])
DOC_ACTIONS.map(action => [
action,
{
type: () => Boolean,
options: {
name: action.replaceAll('.', '_'),
},
},
])
),
{ name: 'DocPermissions' }
);
@@ -281,10 +289,20 @@ export class PagePermissionResolver {
where: {
workspaceId: workspace.id,
pageId: docId.guid,
createdAt: pagination.after
? {
gt: pagination.after,
}
: undefined,
},
orderBy: {
createdAt: 'desc',
},
orderBy: [
{
type: 'desc',
},
{
createdAt: 'desc',
},
],
take: pagination.first,
skip: pagination.offset,
}),

View File

@@ -77,7 +77,15 @@ class WorkspacePageMeta {
const WorkspacePermissions = registerObjectType<WorkspaceActionPermissions>(
Object.fromEntries(
WORKSPACE_ACTIONS.map(action => [action.replaceAll('.', '_'), Boolean])
WORKSPACE_ACTIONS.map(action => [
action,
{
type: () => Boolean,
options: {
name: action.replaceAll('.', '_'),
},
},
])
),
{ name: 'WorkspacePermissions' }
);

View File

@@ -699,11 +699,6 @@ input PaginationInput {
"""returns the elements in the list that come after the specified cursor."""
after: String
"""
returns the elements in the list that come before the specified cursor.
"""
before: String
"""returns the first n elements from the list."""
first: Int = 10