From 6450fe0a8c83a33c4c465e8264184888e9a70c30 Mon Sep 17 00:00:00 2001 From: Mathias Jakobsen Date: Thu, 28 Mar 2024 09:17:01 +0000 Subject: [PATCH] [web] Add current history tab to admin panel (#17482) * [web] Add current history tab to admin panel GitOrigin-RevId: 95a479d01bdf2ca65cd9b18077823d895cc12501 --- .../src/Features/History/HistoryManager.js | 31 +++++++++++++++++++ .../unit/src/History/HistoryManagerTests.js | 15 +++++++++ 2 files changed, 46 insertions(+) diff --git a/services/web/app/src/Features/History/HistoryManager.js b/services/web/app/src/Features/History/HistoryManager.js index b59ba5e8dd..4debeb6179 100644 --- a/services/web/app/src/Features/History/HistoryManager.js +++ b/services/web/app/src/Features/History/HistoryManager.js @@ -3,6 +3,7 @@ const { fetchJson, fetchNothing } = require('@overleaf/fetch-utils') const settings = require('@overleaf/settings') const OError = require('@overleaf/o-error') const UserGetter = require('../User/UserGetter') +const { Project } = require('../../models/Project') async function initializeProject(projectId) { const body = await fetchJson(`${settings.apis.project_history.url}/project`, { @@ -107,6 +108,34 @@ async function _deleteProjectInFullProjectHistory(historyId) { } } +/** + * Warning: Don't use this method for large projects. It will eagerly load all + * the history data and apply all operations. + * @param {string} projectId + * @returns Promise + */ +async function getCurrentContent(projectId) { + const project = await Project.findById(projectId).exec() + 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}/latest/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', { historyId }) + } +} + async function injectUserDetails(data) { // data can be either: // { @@ -192,6 +221,7 @@ module.exports = { deleteProject: callbackify(deleteProject), deleteProjectHistory: callbackify(deleteProjectHistory), injectUserDetails: callbackify(injectUserDetails), + getCurrentContent: callbackify(getCurrentContent), promises: { initializeProject, flushProject, @@ -199,5 +229,6 @@ module.exports = { deleteProject, injectUserDetails, deleteProjectHistory, + getCurrentContent, }, } diff --git a/services/web/test/unit/src/History/HistoryManagerTests.js b/services/web/test/unit/src/History/HistoryManagerTests.js index 955bbf72da..461e66c904 100644 --- a/services/web/test/unit/src/History/HistoryManagerTests.js +++ b/services/web/test/unit/src/History/HistoryManagerTests.js @@ -40,11 +40,26 @@ describe('HistoryManager', function () { }, } + this.project = { + overleaf: { + history: { + id: this.historyId, + }, + }, + } + + this.ProjectModel = { + Project: { + findById: sinon.stub().returns(sinon.stub().resolves(this.project)), + }, + } + this.HistoryManager = SandboxedModule.require(MODULE_PATH, { requires: { '@overleaf/fetch-utils': this.FetchUtils, '@overleaf/settings': this.settings, '../User/UserGetter': this.UserGetter, + '../../models/Project': this.ProjectModel, }, }) })