ソースを参照

[project-history] update schemas to accept numeric project IDs

GitOrigin-RevId: 4dac763223f42eb772c30f34e0da0d22464055dd
Domagoj Kriskovic 9 ヶ月 前
親
コミット
859c21b4dd

+ 20 - 20
services/project-history/app/js/HttpController.js

@@ -63,7 +63,7 @@ export function initializeProject(req, res, next) {
 
 
 const flushProjectSchema = z.object({
 const flushProjectSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     debug: z.stringbool().default(false),
     debug: z.stringbool().default(false),
@@ -110,7 +110,7 @@ export function flushProject(req, res, next) {
 
 
 const dumpProjectSchema = z.object({
 const dumpProjectSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     count: z.coerce.number().int().optional(),
     count: z.coerce.number().int().optional(),
@@ -165,7 +165,7 @@ export function flushOld(req, res, next) {
 
 
 const getDiffSchema = z.object({
 const getDiffSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     pathname: z.string(),
     pathname: z.string(),
@@ -190,7 +190,7 @@ export function getDiff(req, res, next) {
 
 
 const getFileTreeDiffSchema = z.object({
 const getFileTreeDiffSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     from: z.coerce.number().int(),
     from: z.coerce.number().int(),
@@ -213,7 +213,7 @@ export function getFileTreeDiff(req, res, next) {
 
 
 const getUpdatesSchema = z.object({
 const getUpdatesSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     before: z.coerce.number().int().optional(),
     before: z.coerce.number().int().optional(),
@@ -246,7 +246,7 @@ export function getUpdates(req, res, next) {
 
 
 const latestVersionSchema = z.object({
 const latestVersionSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
 })
 })
 
 
@@ -282,7 +282,7 @@ export function latestVersion(req, res, next) {
 
 
 const getFileSnapshotSchema = z.object({
 const getFileSnapshotSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     version: z.coerce.number().int(),
     version: z.coerce.number().int(),
     pathname: z.string(),
     pathname: z.string(),
   }),
   }),
@@ -309,7 +309,7 @@ export function getFileSnapshot(req, res, next) {
 
 
 const getRangesSnapshotSchema = z.object({
 const getRangesSnapshotSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     version: z.coerce.number().int(),
     version: z.coerce.number().int(),
     pathname: z.string(),
     pathname: z.string(),
   }),
   }),
@@ -333,7 +333,7 @@ export function getRangesSnapshot(req, res, next) {
 
 
 const getFileMetadataSnapshotSchema = z.object({
 const getFileMetadataSnapshotSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     version: z.coerce.number().int(),
     version: z.coerce.number().int(),
     pathname: z.string(),
     pathname: z.string(),
   }),
   }),
@@ -357,7 +357,7 @@ export function getFileMetadataSnapshot(req, res, next) {
 
 
 const getLatestSnapshotSchema = z.object({
 const getLatestSnapshotSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
 })
 })
 
 
@@ -382,7 +382,7 @@ export function getLatestSnapshot(req, res, next) {
 
 
 const getChangesInChunkSinceSchema = z.object({
 const getChangesInChunkSinceSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     since: z.coerce.number().int().min(0),
     since: z.coerce.number().int().min(0),
@@ -415,7 +415,7 @@ export function getChangesInChunkSince(req, res, next) {
 
 
 const getProjectSnapshotSchema = z.object({
 const getProjectSnapshotSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     version: z.coerce.number().int(),
     version: z.coerce.number().int(),
   }),
   }),
 })
 })
@@ -437,7 +437,7 @@ export function getProjectSnapshot(req, res, next) {
 
 
 const getPathsAtVersionSchema = z.object({
 const getPathsAtVersionSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     version: z.coerce.number().int(),
     version: z.coerce.number().int(),
   }),
   }),
 })
 })
@@ -477,7 +477,7 @@ export function checkLock(req, res) {
 
 
 const resyncProjectSchema = z.object({
 const resyncProjectSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     force: z.stringbool().default(false),
     force: z.stringbool().default(false),
@@ -536,7 +536,7 @@ export function resyncProject(req, res, next) {
 
 
 const forceDebugProjectSchema = z.object({
 const forceDebugProjectSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
   query: z.object({
   query: z.object({
     clear: z.stringbool().default(false),
     clear: z.stringbool().default(false),
@@ -582,7 +582,7 @@ export function getQueueCounts(req, res, next) {
 
 
 const getLabelsSchema = z.object({
 const getLabelsSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
 })
 })
 
 
@@ -611,7 +611,7 @@ export function getLabels(req, res, next) {
 
 
 const createLabelSchema = z.object({
 const createLabelSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     user_id: zz.objectId().optional(),
     user_id: zz.objectId().optional(),
   }),
   }),
   body: z.object({
   body: z.object({
@@ -683,7 +683,7 @@ export function createLabel(req, res, next) {
  */
  */
 const deleteLabelForUserSchema = z.object({
 const deleteLabelForUserSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     user_id: zz.objectId(),
     user_id: zz.objectId(),
     label_id: zz.objectId(),
     label_id: zz.objectId(),
   }),
   }),
@@ -703,7 +703,7 @@ export function deleteLabelForUser(req, res, next) {
 
 
 const deleteLabelSchema = z.object({
 const deleteLabelSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
     label_id: zz.objectId(),
     label_id: zz.objectId(),
   }),
   }),
 })
 })
@@ -785,7 +785,7 @@ export function transferLabels(req, res, next) {
 
 
 const deleteProjectSchema = z.object({
 const deleteProjectSchema = z.object({
   params: z.object({
   params: z.object({
-    project_id: zz.objectId(),
+    project_id: zz.objectId().or(z.coerce.number()),
   }),
   }),
 })
 })
 
 

+ 139 - 0
services/project-history/test/acceptance/js/NumericProjectIdTests.js

@@ -0,0 +1,139 @@
+import { expect } from 'chai'
+import nock from 'nock'
+import request from 'request'
+import * as ProjectHistoryApp from './helpers/ProjectHistoryApp.js'
+import * as ProjectHistoryClient from './helpers/ProjectHistoryClient.js'
+
+const MockHistoryStore = () => nock('http://127.0.0.1:3100')
+const MockWeb = () => nock('http://127.0.0.1:3000')
+
+const fixture = path => new URL(`../fixtures/${path}`, import.meta.url)
+
+/**
+ * These tests verify that endpoints accept numeric project IDs (in addition to ObjectId strings).
+ * This is needed for v1 history projects which use numeric project IDs.
+ */
+describe('NumericProjectId', function () {
+  beforeEach(async function () {
+    await ProjectHistoryApp.ensureRunning()
+
+    // Use a numeric project ID (simulating v1 history projects)
+    this.numericProjectId = 123456
+
+    MockHistoryStore().post('/api/projects').reply(200, {
+      projectId: this.numericProjectId,
+    })
+
+    const olProject = await ProjectHistoryClient.initializeProject(
+      this.numericProjectId
+    )
+    this.historyId = olProject.id
+
+    MockWeb()
+      .get(`/project/${this.numericProjectId}/details`)
+      .reply(200, {
+        name: 'Test Project',
+        overleaf: { history: { id: this.historyId } },
+      })
+      .persist()
+
+    MockHistoryStore()
+      .get(`/api/projects/${this.historyId}/latest/history`)
+      .replyWithFile(200, fixture('chunks/7-8.json'))
+      .persist()
+
+    MockHistoryStore()
+      .get(`/api/projects/${this.historyId}/versions/7/history`)
+      .replyWithFile(200, fixture('chunks/7-8.json'))
+      .persist()
+
+    MockHistoryStore()
+      .get(`/api/projects/${this.historyId}/versions/8/history`)
+      .replyWithFile(200, fixture('chunks/7-8.json'))
+      .persist()
+  })
+
+  afterEach(function () {
+    nock.cleanAll()
+  })
+
+  function makeRequest(options) {
+    return new Promise((resolve, reject) => {
+      request(options, (error, response, body) => {
+        if (error) return reject(error)
+        resolve({ response, body })
+      })
+    })
+  }
+
+  it('should accept numeric project_id for flush', async function () {
+    const { response } = await makeRequest({
+      method: 'POST',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/flush`,
+    })
+    expect(response.statusCode).to.equal(204)
+  })
+
+  it('should accept numeric project_id for dump', async function () {
+    const { response } = await makeRequest({
+      method: 'GET',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/dump`,
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+
+  it('should accept numeric project_id for filetree diff', async function () {
+    const { response } = await makeRequest({
+      method: 'GET',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/filetree/diff`,
+      qs: { from: 7, to: 8 },
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+
+  it('should accept numeric project_id for updates', async function () {
+    const { response } = await makeRequest({
+      method: 'GET',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/updates`,
+      qs: { min_count: 1 },
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+
+  it('should accept numeric project_id for version', async function () {
+    const { response } = await makeRequest({
+      method: 'GET',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/version`,
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+
+  it('should accept numeric project_id for snapshot', async function () {
+    const { response } = await makeRequest({
+      method: 'GET',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/snapshot`,
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+
+  it('should accept numeric project_id for getLabels', async function () {
+    const { response } = await makeRequest({
+      method: 'GET',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/labels`,
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+
+  it('should accept numeric project_id for createLabel', async function () {
+    const { response } = await makeRequest({
+      method: 'POST',
+      url: `http://127.0.0.1:3054/project/${this.numericProjectId}/labels`,
+      json: {
+        comment: 'test label',
+        version: 7,
+        user_id: '507f1f77bcf86cd799439011',
+      },
+    })
+    expect(response.statusCode).to.equal(200)
+  })
+})