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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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