From 7901a55fd75fe7f7aadef1554a818c20aae5c376 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Mon, 19 Aug 2024 16:02:46 +0800 Subject: [PATCH] feat: integrate editor record for snapshots --- .../migration.sql | 11 ++------- packages/backend/server/schema.prisma | 7 +++--- .../server/src/core/doc/adapters/userspace.ts | 12 +++++++++- .../server/src/core/doc/adapters/workspace.ts | 23 +++++++++++++++---- .../server/src/core/doc/storage/doc.ts | 4 ++-- 5 files changed, 38 insertions(+), 19 deletions(-) rename packages/backend/server/migrations/{20240819092355_editor_record => 20240819100204_editor_record}/migration.sql (74%) diff --git a/packages/backend/server/migrations/20240819092355_editor_record/migration.sql b/packages/backend/server/migrations/20240819100204_editor_record/migration.sql similarity index 74% rename from packages/backend/server/migrations/20240819092355_editor_record/migration.sql rename to packages/backend/server/migrations/20240819100204_editor_record/migration.sql index 4ca781dadd..143ab9e23f 100644 --- a/packages/backend/server/migrations/20240819092355_editor_record/migration.sql +++ b/packages/backend/server/migrations/20240819100204_editor_record/migration.sql @@ -1,19 +1,12 @@ -/* - Warnings: - - - Added the required column `created_by` to the `snapshot_histories` table without a default value. This is not possible if the table is not empty. - - Added the required column `created_by` to the `updates` table without a default value. This is not possible if the table is not empty. - -*/ -- AlterTable -ALTER TABLE "snapshot_histories" ADD COLUMN "created_by" VARCHAR NOT NULL; +ALTER TABLE "snapshot_histories" ADD COLUMN "created_by" VARCHAR; -- AlterTable ALTER TABLE "snapshots" ADD COLUMN "created_by" VARCHAR, ADD COLUMN "updated_by" VARCHAR; -- AlterTable -ALTER TABLE "updates" ADD COLUMN "created_by" VARCHAR NOT NULL; +ALTER TABLE "updates" ADD COLUMN "created_by" VARCHAR NOT NULL DEFAULT 'system'; -- AddForeignKey ALTER TABLE "snapshots" ADD CONSTRAINT "snapshots_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/backend/server/schema.prisma b/packages/backend/server/schema.prisma index 26ad2009d6..20ce000960 100644 --- a/packages/backend/server/schema.prisma +++ b/packages/backend/server/schema.prisma @@ -285,7 +285,8 @@ model Update { id String @map("guid") @db.VarChar blob Bytes @db.ByteA createdAt DateTime @map("created_at") @db.Timestamptz(3) - createdBy String @map("created_by") @db.VarChar + // TODO(@darkskygit): fullfill old update, remove default value in next release + createdBy String @map("created_by") @db.VarChar @default("system") // delete update if createor's account is deleted createdByUser User @relation(name: "createdUpdate", fields: [createdBy], references: [id], onDelete: Cascade) @@ -304,10 +305,10 @@ model SnapshotHistory { blob Bytes @db.ByteA state Bytes? @db.ByteA expiredAt DateTime @map("expired_at") @db.Timestamptz(3) - createdBy String @map("created_by") @db.VarChar + createdBy String? @map("created_by") @db.VarChar // delete history if creator's account is deleted - createdByUser User @relation(name: "createdHistory", fields: [createdBy], references: [id], onDelete: Cascade) + createdByUser User? @relation(name: "createdHistory", fields: [createdBy], references: [id], onDelete: Cascade) @@id([workspaceId, id, timestamp]) @@map("snapshot_histories") diff --git a/packages/backend/server/src/core/doc/adapters/userspace.ts b/packages/backend/server/src/core/doc/adapters/userspace.ts index b5fd9a2655..f11c10a9dd 100644 --- a/packages/backend/server/src/core/doc/adapters/userspace.ts +++ b/packages/backend/server/src/core/doc/adapters/userspace.ts @@ -45,7 +45,12 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter { return this.getDocSnapshot(spaceId, docId); } - async pushDocUpdates(userId: string, docId: string, updates: Uint8Array[]) { + async pushDocUpdates( + editorId: string, + userId: string, + docId: string, + updates: Uint8Array[] + ) { if (!updates.length) { return 0; } @@ -67,6 +72,7 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter { docId, bin, timestamp, + editor: editorId, }); return timestamp; @@ -135,6 +141,7 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter { docId, bin: snapshot.blob, timestamp: snapshot.updatedAt.getTime(), + editor: snapshot.userId, }; } @@ -151,6 +158,7 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter { update: { blob: Buffer.from(snapshot.bin), updatedAt: new Date(snapshot.timestamp), + updatedBy: snapshot.editor, }, create: { userId: snapshot.spaceId, @@ -158,6 +166,8 @@ export class PgUserspaceDocStorageAdapter extends DocStorageAdapter { blob: Buffer.from(snapshot.bin), createdAt: new Date(snapshot.timestamp), updatedAt: new Date(snapshot.timestamp), + createdBy: snapshot.editor, + updatedBy: snapshot.editor, }, }); diff --git a/packages/backend/server/src/core/doc/adapters/workspace.ts b/packages/backend/server/src/core/doc/adapters/workspace.ts index 2325595c08..b9ecb928bb 100644 --- a/packages/backend/server/src/core/doc/adapters/workspace.ts +++ b/packages/backend/server/src/core/doc/adapters/workspace.ts @@ -36,6 +36,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { } async pushDocUpdates( + editorId: string, workspaceId: string, docId: string, updates: Uint8Array[] @@ -82,6 +83,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { blob: Buffer.from(update), seq, createdAt: new Date(createdAt), + createdBy: editorId, }; }), }); @@ -113,6 +115,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { return rows.map(row => ({ bin: row.blob, timestamp: row.createdAt.getTime(), + editor: row.createdBy, })); } @@ -253,10 +256,12 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { docId, bin: history.blob, timestamp, + editor: history.createdBy || undefined, }; } override async rollbackDoc( + editorId: string, spaceId: string, docId: string, timestamp: number @@ -274,7 +279,14 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { } // force create a new history record after rollback - await this.createDocHistory(fromSnapshot, true); + await this.createDocHistory( + { + ...fromSnapshot, + // override the editor to the one who requested the rollback + editor: editorId, + }, + true + ); // WARN: // we should never do the snapshot updating in recovering, // which is not the solution in CRDT. @@ -331,6 +343,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { id: snapshot.docId, timestamp: new Date(snapshot.timestamp), blob: Buffer.from(snapshot.bin), + createdBy: snapshot.editor, expiredAt: new Date( Date.now() + (await this.options.historyMaxAge(snapshot.spaceId)) ), @@ -374,6 +387,8 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { docId, bin: snapshot.blob, timestamp: snapshot.updatedAt.getTime(), + // creator and editor may null if their account is deleted + editor: snapshot.updatedBy || snapshot.createdBy || undefined, }; } @@ -396,10 +411,10 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter { // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ try { const result: { updatedAt: Date }[] = await this.db.$queryRaw` - INSERT INTO "snapshots" ("workspace_id", "guid", "blob", "created_at", "updated_at") - VALUES (${spaceId}, ${docId}, ${bin}, DEFAULT, ${updatedAt}) + INSERT INTO "snapshots" ("workspace_id", "guid", "blob", "created_at", "updated_at", "created_by", "updated_by") + VALUES (${spaceId}, ${docId}, ${bin}, DEFAULT, ${updatedAt}, ${snapshot.editor}, ${snapshot.editor}) ON CONFLICT ("workspace_id", "guid") - DO UPDATE SET "blob" = ${bin}, "updated_at" = ${updatedAt} + DO UPDATE SET "blob" = ${bin}, "updated_at" = ${updatedAt}, "updated_by" = ${snapshot.editor} WHERE "snapshots"."workspace_id" = ${spaceId} AND "snapshots"."guid" = ${docId} AND "snapshots"."updated_at" <= ${updatedAt} RETURNING "snapshots"."workspace_id" as "workspaceId", "snapshots"."guid" as "id", "snapshots"."updated_at" as "updatedAt" `; diff --git a/packages/backend/server/src/core/doc/storage/doc.ts b/packages/backend/server/src/core/doc/storage/doc.ts index 8e439e7320..50c79b4199 100644 --- a/packages/backend/server/src/core/doc/storage/doc.ts +++ b/packages/backend/server/src/core/doc/storage/doc.ts @@ -16,13 +16,13 @@ export interface DocRecord { docId: string; bin: Uint8Array; timestamp: number; - editor: string; + editor?: string; } export interface DocUpdate { bin: Uint8Array; timestamp: number; - editor: string; + editor?: string; } export interface HistoryFilter {