Просмотр исходного кода

Merge pull request #20592 from overleaf/em-mj-load-history-version

Load a specific version in the admin history debugging panel

GitOrigin-RevId: 302832b981688a6697c21122372230c285911d24
Eric Mc Sween 1 год назад
Родитель
Сommit
9648c6711c

+ 10 - 0
services/history-v1/api/controllers/projects.js

@@ -50,6 +50,15 @@ async function getLatestContent(req, res, next) {
   res.json(snapshot.toRaw())
 }
 
+async function getContentAtVersion(req, res, next) {
+  const projectId = req.swagger.params.project_id.value
+  const version = req.swagger.params.version.value
+  const blobStore = new BlobStore(projectId)
+  const snapshot = await getSnapshotAtVersion(projectId, version)
+  await snapshot.loadFiles('eager', blobStore)
+  res.json(snapshot.toRaw())
+}
+
 async function getLatestHashedContent(req, res, next) {
   const projectId = req.swagger.params.project_id.value
   const blobStore = new HashCheckBlobStore(new BlobStore(projectId))
@@ -227,6 +236,7 @@ async function getSnapshotAtVersion(projectId, version) {
 module.exports = {
   initializeProject: expressify(initializeProject),
   getLatestContent: expressify(getLatestContent),
+  getContentAtVersion: expressify(getContentAtVersion),
   getLatestHashedContent: expressify(getLatestHashedContent),
   getLatestPersistedHistory: expressify(getLatestHistory),
   getLatestHistory: expressify(getLatestHistory),

+ 38 - 0
services/history-v1/api/swagger/projects.js

@@ -309,6 +309,44 @@ exports.paths = {
       },
     },
   },
+  '/projects/{project_id}/versions/{version}/content': {
+    get: {
+      'x-swagger-router-controller': 'projects',
+      operationId: 'getContentAtVersion',
+      tags: ['Project'],
+      description: 'Get full content at the given version',
+      parameters: [
+        {
+          name: 'project_id',
+          in: 'path',
+          description: 'project id',
+          required: true,
+          type: 'string',
+        },
+        {
+          name: 'version',
+          in: 'path',
+          description: 'numeric version',
+          required: true,
+          type: 'number',
+        },
+      ],
+      responses: {
+        200: {
+          description: 'Success',
+          schema: {
+            $ref: '#/definitions/Snapshot',
+          },
+        },
+        404: {
+          description: 'Not Found',
+          schema: {
+            $ref: '#/definitions/Error',
+          },
+        },
+      },
+    },
+  },
   '/projects/{project_id}/timestamp/{timestamp}/history': {
     get: {
       'x-swagger-router-controller': 'projects',

+ 37 - 0
services/web/app/src/Features/History/HistoryManager.js

@@ -141,6 +141,42 @@ async function getCurrentContent(projectId) {
   }
 }
 
+/**
+ * Warning: Don't use this method for large projects. It will eagerly load all
+ * the history data and apply all operations.
+ * @param {string} projectId
+ * @param {number} version
+ *
+ * @returns Promise<object>
+ */
+async function getContentAtVersion(projectId, version) {
+  const project = await ProjectGetter.promises.getProject(projectId, {
+    overleaf: true,
+  })
+  const historyId = project?.overleaf?.history?.id
+  if (!historyId) {
+    throw new OError('project does not have a history id', { projectId })
+  }
+  try {
+    return await fetchJson(
+      `${settings.apis.v1_history.url}/projects/${historyId}/versions/${version}/content`,
+      {
+        method: 'GET',
+        basicAuth: {
+          user: settings.apis.v1_history.user,
+          password: settings.apis.v1_history.pass,
+        },
+      }
+    )
+  } catch (err) {
+    throw OError.tag(
+      err,
+      'failed to load project history snapshot at version',
+      { historyId, version }
+    )
+  }
+}
+
 async function injectUserDetails(data) {
   // data can be either:
   // {
@@ -235,5 +271,6 @@ module.exports = {
     injectUserDetails,
     deleteProjectHistory,
     getCurrentContent,
+    getContentAtVersion,
   },
 }