소스 검색

Merge pull request #29965 from overleaf/acf-migration1-validation

Add Zod validation (replaces swagger-validator + swagger-metadata)

GitOrigin-RevId: 2e4ed742e401bdfe49c6f7dc9d0fceeba20cfc7f
Anna Claire Fields 8 달 전
부모
커밋
c25e49782f
5개의 변경된 파일227개의 추가작업 그리고 0개의 파일을 삭제
  1. 1 0
      package-lock.json
  2. 2 0
      services/history-v1/Dockerfile
  3. 1 0
      services/history-v1/Makefile
  4. 222 0
      services/history-v1/api/schema.js
  5. 1 0
      services/history-v1/package.json

+ 1 - 0
package-lock.json

@@ -54683,6 +54683,7 @@
         "@overleaf/redis-wrapper": "*",
         "@overleaf/settings": "*",
         "@overleaf/stream-utils": "^0.1.0",
+        "@overleaf/validation-tools": "*",
         "archiver": "^5.3.0",
         "basic-auth": "^2.0.1",
         "bluebird": "^3.7.2",

+ 2 - 0
services/history-v1/Dockerfile

@@ -29,6 +29,7 @@ COPY libraries/promise-utils/package.json /overleaf/libraries/promise-utils/pack
 COPY libraries/redis-wrapper/package.json /overleaf/libraries/redis-wrapper/package.json
 COPY libraries/settings/package.json /overleaf/libraries/settings/package.json
 COPY libraries/stream-utils/package.json /overleaf/libraries/stream-utils/package.json
+COPY libraries/validation-tools/package.json /overleaf/libraries/validation-tools/package.json
 COPY services/history-v1/package.json /overleaf/services/history-v1/package.json
 COPY tools/migrations/package.json /overleaf/tools/migrations/package.json
 COPY patches/ /overleaf/patches/
@@ -46,6 +47,7 @@ COPY libraries/promise-utils/ /overleaf/libraries/promise-utils/
 COPY libraries/redis-wrapper/ /overleaf/libraries/redis-wrapper/
 COPY libraries/settings/ /overleaf/libraries/settings/
 COPY libraries/stream-utils/ /overleaf/libraries/stream-utils/
+COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/
 COPY services/history-v1/ /overleaf/services/history-v1/
 COPY tools/migrations/ /overleaf/tools/migrations/
 

+ 1 - 0
services/history-v1/Makefile

@@ -26,6 +26,7 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
 	$(MONOREPO)/libraries/redis-wrapper/package.json \
 	$(MONOREPO)/libraries/settings/package.json \
 	$(MONOREPO)/libraries/stream-utils/package.json \
+	$(MONOREPO)/libraries/validation-tools/package.json \
 	$(MONOREPO)/services/history-v1/package.json \
 	$(MONOREPO)/tools/migrations/package.json \
 	$(MONOREPO)/patches/* \

+ 222 - 0
services/history-v1/api/schema.js

@@ -0,0 +1,222 @@
+'use strict'
+
+const { z } = require('@overleaf/validation-tools')
+const Blob = require('overleaf-editor-core').Blob
+
+const hexHashPattern = new RegExp(Blob.HEX_HASH_RX_STRING)
+
+const fileSchema = z.object({
+  hash: z.string().optional(),
+  byteLength: z.number().int().nullable().optional(),
+  stringLength: z.number().int().nullable().optional(),
+})
+
+const snapshotSchema = z.object({
+  files: z.record(z.string(), fileSchema),
+})
+
+const v2DocVersionsSchema = z.object({
+  pathname: z.string().optional(),
+  v: z.number().int().optional(),
+})
+
+const operationSchema = z.object({
+  pathname: z.string().optional(),
+  newPathname: z.string().optional(),
+  blob: z
+    .object({
+      hash: z.string(),
+    })
+    .optional(),
+  textOperation: z.array(z.any()).optional(),
+  file: fileSchema.optional(),
+})
+
+const changeSchema = z.object({
+  timestamp: z.string(),
+  operations: z.array(operationSchema),
+  authors: z.array(z.number().int().nullable()).optional(),
+  v2Authors: z.array(z.string().nullable()).optional(),
+  projectVersion: z.string().optional(),
+  v2DocVersions: z.record(v2DocVersionsSchema).optional(),
+})
+
+const schemas = {
+  initializeProject: z.object({
+    body: z
+      .object({
+        projectId: z.string().optional(),
+      })
+      .optional(),
+  }),
+
+  getProjectBlobsStats: z.object({
+    body: z.object({
+      projectIds: z.array(z.string()),
+    }),
+  }),
+
+  getBlobStats: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    body: z.object({
+      blobHashes: z.array(z.string()),
+    }),
+  }),
+
+  deleteProject: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    body: z.any().optional(),
+  }),
+
+  getProjectBlob: z.object({
+    params: z.object({
+      project_id: z.string(),
+      hash: z.string().regex(hexHashPattern),
+    }),
+    headers: z.object({
+      range: z.string().optional(),
+    }),
+  }),
+
+  headProjectBlob: z.object({
+    params: z.object({
+      project_id: z.string(),
+      hash: z.string().regex(hexHashPattern),
+    }),
+  }),
+
+  createProjectBlob: z.object({
+    params: z.object({
+      project_id: z.string(),
+      hash: z.string().regex(hexHashPattern),
+    }),
+    body: z.any().optional(),
+  }),
+
+  copyProjectBlob: z.object({
+    params: z.object({
+      project_id: z.string(),
+      hash: z.string().regex(hexHashPattern),
+    }),
+    query: z.object({
+      copyFrom: z.string(),
+    }),
+    body: z.any().optional(),
+  }),
+
+  getLatestContent: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+  }),
+
+  getLatestHashedContent: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+  }),
+
+  getLatestHistory: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+  }),
+
+  getLatestHistoryRaw: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    query: z.object({
+      readOnly: z.boolean().optional(),
+    }),
+  }),
+
+  getLatestPersistedHistory: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+  }),
+
+  getHistory: z.object({
+    params: z.object({
+      project_id: z.string(),
+      version: z.coerce.number(),
+    }),
+  }),
+
+  getContentAtVersion: z.object({
+    params: z.object({
+      project_id: z.string(),
+      version: z.coerce.number(),
+    }),
+  }),
+
+  getHistoryBefore: z.object({
+    params: z.object({
+      project_id: z.string(),
+      timestamp: z.iso.datetime(),
+    }),
+  }),
+
+  getZip: z.object({
+    params: z.object({
+      project_id: z.string(),
+      version: z.coerce.number(),
+    }),
+  }),
+
+  createZip: z.object({
+    params: z.object({
+      project_id: z.string(),
+      version: z.coerce.number(),
+    }),
+    body: z.any().optional(),
+  }),
+
+  getChanges: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    query: z.object({
+      since: z.coerce.number().optional(),
+    }),
+  }),
+
+  importSnapshot: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    body: snapshotSchema,
+  }),
+
+  importChanges: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    query: z.object({
+      end_version: z.coerce.number(),
+      return_snapshot: z.enum(['hashed', 'none']).optional(),
+    }),
+    body: z.array(changeSchema),
+  }),
+
+  flushChanges: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    body: z.any().optional(),
+  }),
+
+  expireProject: z.object({
+    params: z.object({
+      project_id: z.string(),
+    }),
+    body: z.any().optional(),
+  }),
+}
+
+module.exports = schemas

+ 1 - 0
services/history-v1/package.json

@@ -17,6 +17,7 @@
     "@overleaf/redis-wrapper": "*",
     "@overleaf/settings": "*",
     "@overleaf/stream-utils": "^0.1.0",
+    "@overleaf/validation-tools": "*",
     "archiver": "^5.3.0",
     "basic-auth": "^2.0.1",
     "bluebird": "^3.7.2",