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

Merge pull request #10739 from overleaf/em-history-mongo-backend

Send a history id from web when creating a project

GitOrigin-RevId: dd1417ae734c76990931885df1864a81a9439da0
Eric Mc Sween 3 лет назад
Родитель
Сommit
38df974ce1

+ 3 - 1
services/web/app/src/Features/History/HistoryManager.js

@@ -4,7 +4,7 @@ const settings = require('@overleaf/settings')
 const OError = require('@overleaf/o-error')
 const OError = require('@overleaf/o-error')
 const UserGetter = require('../User/UserGetter')
 const UserGetter = require('../User/UserGetter')
 
 
-async function initializeProject() {
+async function initializeProject(projectId) {
   if (
   if (
     !(
     !(
       settings.apis.project_history &&
       settings.apis.project_history &&
@@ -16,8 +16,10 @@ async function initializeProject() {
   const response = await fetch(`${settings.apis.project_history.url}/project`, {
   const response = await fetch(`${settings.apis.project_history.url}/project`, {
     method: 'POST',
     method: 'POST',
     headers: {
     headers: {
+      'Content-Type': 'application/json',
       Accept: 'application/json',
       Accept: 'application/json',
     },
     },
+    body: JSON.stringify({ historyId: projectId.toString() }),
   })
   })
   if (!response.ok) {
   if (!response.ok) {
     throw new OError('failed to initialize project history', {
     throw new OError('failed to initialize project history', {

+ 11 - 12
services/web/app/src/Features/Project/ProjectCreationHandler.js

@@ -152,33 +152,32 @@ async function _createBlankProject(
   const timer = new metrics.Timer('project-creation')
   const timer = new metrics.Timer('project-creation')
   await ProjectDetailsHandler.promises.validateProjectName(projectName)
   await ProjectDetailsHandler.promises.validateProjectName(projectName)
 
 
-  if (!attributes.overleaf) {
-    const historyId = await HistoryManager.promises.initializeProject()
-    if (historyId != null) {
-      attributes.overleaf = {
-        history: { id: historyId },
-      }
-    }
-  }
-
   const rootFolder = new Folder({ name: 'rootFolder' })
   const rootFolder = new Folder({ name: 'rootFolder' })
 
 
   attributes.lastUpdatedBy = attributes.owner_ref = new ObjectId(ownerId)
   attributes.lastUpdatedBy = attributes.owner_ref = new ObjectId(ownerId)
   attributes.name = projectName
   attributes.name = projectName
   const project = new Project(attributes)
   const project = new Project(attributes)
 
 
-  Object.assign(project, attributes)
+  if (project.overleaf.history.id == null) {
+    const historyId = await HistoryManager.promises.initializeProject(
+      project._id
+    )
+    if (historyId != null) {
+      project.overleaf.history.id = historyId
+    }
+  }
 
 
   // only display full project history when the project has the overleaf history id attribute
   // only display full project history when the project has the overleaf history id attribute
   // (to allow scripted creation of projects without full project history)
   // (to allow scripted creation of projects without full project history)
-  const historyId = _.get(attributes, ['overleaf', 'history', 'id'])
+  const historyId = project.overleaf.history.id
   if (
   if (
     Features.hasFeature('history-v1') &&
     Features.hasFeature('history-v1') &&
     Settings.apis.project_history.displayHistoryForNewProjects &&
     Settings.apis.project_history.displayHistoryForNewProjects &&
-    historyId
+    historyId != null
   ) {
   ) {
     project.overleaf.history.display = true
     project.overleaf.history.display = true
   }
   }
+
   if (Settings.currentImageName) {
   if (Settings.currentImageName) {
     // avoid clobbering any imageName already set in attributes (e.g. importedImageName)
     // avoid clobbering any imageName already set in attributes (e.g. importedImageName)
     if (!project.imageName) {
     if (!project.imageName) {

+ 30 - 27
services/web/app/src/Features/Project/ProjectHistoryHandler.js

@@ -26,8 +26,8 @@ const ProjectHistoryHandler = {
     if (callback == null) {
     if (callback == null) {
       callback = function () {}
       callback = function () {}
     }
     }
-    if (!history_id || typeof history_id !== 'number') {
-      return callback(new Error('invalid history id'))
+    if (history_id == null) {
+      return callback(new Error('missing history id'))
     }
     }
     // use $exists:false to prevent overwriting any existing history id, atomically
     // use $exists:false to prevent overwriting any existing history id, atomically
     return Project.updateOne(
     return Project.updateOne(
@@ -154,32 +154,35 @@ const ProjectHistoryHandler = {
         if (history_id != null) {
         if (history_id != null) {
           return callback()
           return callback()
         } // history already exists, success
         } // history already exists, success
-        return HistoryManager.initializeProject(function (err, historyId) {
-          if (err != null) {
-            return callback(err)
-          }
-          if (historyId == null) {
-            return callback(new Error('failed to initialize history id'))
-          }
-          return ProjectHistoryHandler.setHistoryId(
-            project_id,
-            historyId,
-            function (err) {
-              if (err != null) {
-                return callback(err)
-              }
-              return ProjectEntityUpdateHandler.resyncProjectHistory(
-                project_id,
-                function (err) {
-                  if (err != null) {
-                    return callback(err)
-                  }
-                  return HistoryManager.flushProject(project_id, callback)
-                }
-              )
+        return HistoryManager.initializeProject(
+          project_id,
+          function (err, historyId) {
+            if (err != null) {
+              return callback(err)
             }
             }
-          )
-        })
+            if (historyId == null) {
+              return callback(new Error('failed to initialize history id'))
+            }
+            return ProjectHistoryHandler.setHistoryId(
+              project_id,
+              historyId,
+              function (err) {
+                if (err != null) {
+                  return callback(err)
+                }
+                return ProjectEntityUpdateHandler.resyncProjectHistory(
+                  project_id,
+                  function (err) {
+                    if (err != null) {
+                      return callback(err)
+                    }
+                    return HistoryManager.flushProject(project_id, callback)
+                  }
+                )
+              }
+            )
+          }
+        )
       }
       }
     )
     )
   },
   },

+ 1 - 1
services/web/app/src/models/Project.js

@@ -88,7 +88,7 @@ const ProjectSchema = new Schema({
     token: { type: String },
     token: { type: String },
     read_token: { type: String },
     read_token: { type: String },
     history: {
     history: {
-      id: { type: Number },
+      id: { type: Schema.Types.Mixed },
       display: { type: Boolean },
       display: { type: Boolean },
       upgradedAt: { type: Date },
       upgradedAt: { type: Date },
       allowDowngrade: { type: Boolean },
       allowDowngrade: { type: Boolean },

+ 1 - 1
services/web/scripts/history/HistoryUpgradeHelper.js

@@ -176,7 +176,7 @@ async function doUpgradeForNoneWithoutConversion(project) {
     // of a resync request to doc-updater
     // of a resync request to doc-updater
     let historyId = await ProjectHistoryHandler.promises.getHistoryId(projectId)
     let historyId = await ProjectHistoryHandler.promises.getHistoryId(projectId)
     if (historyId == null) {
     if (historyId == null) {
-      historyId = await HistoryManager.promises.initializeProject()
+      historyId = await HistoryManager.promises.initializeProject(projectId)
       if (historyId != null) {
       if (historyId != null) {
         await ProjectHistoryHandler.promises.setHistoryId(projectId, historyId)
         await ProjectHistoryHandler.promises.setHistoryId(projectId, historyId)
       }
       }

+ 1 - 1
services/web/scripts/history/upgrade_none_without_conversion_if_no_sl_history.js

@@ -121,7 +121,7 @@ async function doUpgradeForNoneWithoutConversion(project) {
         projectId
         projectId
       )
       )
       if (historyId == null) {
       if (historyId == null) {
-        historyId = await HistoryManager.promises.initializeProject()
+        historyId = await HistoryManager.promises.initializeProject(projectId)
         if (historyId != null) {
         if (historyId != null) {
           await ProjectHistoryHandler.promises.setHistoryId(
           await ProjectHistoryHandler.promises.setHistoryId(
             projectId,
             projectId,

+ 15 - 10
services/web/test/unit/src/History/HistoryManagerTests.js

@@ -8,6 +8,7 @@ const MODULE_PATH = '../../../../app/src/Features/History/HistoryManager'
 describe('HistoryManager', function () {
 describe('HistoryManager', function () {
   beforeEach(function () {
   beforeEach(function () {
     this.user_id = 'user-id-123'
     this.user_id = 'user-id-123'
+    this.historyId = ObjectId().toString()
     this.AuthenticationController = {
     this.AuthenticationController = {
       getLoggedInUserId: sinon.stub().returns(this.user_id),
       getLoggedInUserId: sinon.stub().returns(this.user_id),
     }
     }
@@ -61,9 +62,10 @@ describe('HistoryManager', function () {
 
 
       describe('project history returns a successful response', function () {
       describe('project history returns a successful response', function () {
         beforeEach(async function () {
         beforeEach(async function () {
-          this.overleaf_id = 1234
-          this.response.json.resolves({ project: { id: this.overleaf_id } })
-          this.result = await this.HistoryManager.promises.initializeProject()
+          this.response.json.resolves({ project: { id: this.historyId } })
+          this.result = await this.HistoryManager.promises.initializeProject(
+            this.historyId
+          )
         })
         })
 
 
         it('should call the project history api', function () {
         it('should call the project history api', function () {
@@ -74,23 +76,25 @@ describe('HistoryManager', function () {
         })
         })
 
 
         it('should return the overleaf id', function () {
         it('should return the overleaf id', function () {
-          expect(this.result).to.deep.equal(this.overleaf_id)
+          expect(this.result).to.equal(this.historyId)
         })
         })
       })
       })
 
 
       describe('project history returns a response without the project id', function () {
       describe('project history returns a response without the project id', function () {
         it('should throw an error', async function () {
         it('should throw an error', async function () {
           this.response.json.resolves({ project: {} })
           this.response.json.resolves({ project: {} })
-          await expect(this.HistoryManager.promises.initializeProject()).to.be
-            .rejected
+          await expect(
+            this.HistoryManager.promises.initializeProject(this.historyId)
+          ).to.be.rejected
         })
         })
       })
       })
 
 
       describe('project history errors', function () {
       describe('project history errors', function () {
         it('should propagate the error', async function () {
         it('should propagate the error', async function () {
           this.fetch.rejects(new Error('problem connecting'))
           this.fetch.rejects(new Error('problem connecting'))
-          await expect(this.HistoryManager.promises.initializeProject()).to.be
-            .rejected
+          await expect(
+            this.HistoryManager.promises.initializeProject(this.historyId)
+          ).to.be.rejected
         })
         })
       })
       })
     })
     })
@@ -98,8 +102,9 @@ describe('HistoryManager', function () {
     describe('with project history disabled', function () {
     describe('with project history disabled', function () {
       it('should return without errors', async function () {
       it('should return without errors', async function () {
         this.settings.apis.project_history.initializeHistoryForNewProjects = false
         this.settings.apis.project_history.initializeHistoryForNewProjects = false
-        await expect(this.HistoryManager.promises.initializeProject()).to.be
-          .fulfilled
+        await expect(
+          this.HistoryManager.promises.initializeProject(this.historyId)
+        ).to.be.fulfilled
       })
       })
     })
     })
   })
   })

+ 3 - 3
services/web/test/unit/src/Project/ProjectHistoryHandlerTests.js

@@ -39,6 +39,7 @@ describe('ProjectHistoryHandler', function () {
       return Project
       return Project
     })()
     })()
     this.project = new this.ProjectModel()
     this.project = new this.ProjectModel()
+    this.historyId = this.project._id.toString()
 
 
     this.callback = sinon.stub()
     this.callback = sinon.stub()
 
 
@@ -57,10 +58,9 @@ describe('ProjectHistoryHandler', function () {
 
 
   describe('starting history for an existing project', function () {
   describe('starting history for an existing project', function () {
     beforeEach(function () {
     beforeEach(function () {
-      this.newHistoryId = 123456789
       this.HistoryManager.initializeProject = sinon
       this.HistoryManager.initializeProject = sinon
         .stub()
         .stub()
-        .callsArgWith(0, null, this.newHistoryId)
+        .yields(null, this.historyId)
       this.HistoryManager.flushProject = sinon.stub().callsArg(1)
       this.HistoryManager.flushProject = sinon.stub().callsArg(1)
       return (this.ProjectEntityUpdateHandler.resyncProjectHistory = sinon
       return (this.ProjectEntityUpdateHandler.resyncProjectHistory = sinon
         .stub()
         .stub()
@@ -96,7 +96,7 @@ describe('ProjectHistoryHandler', function () {
         return this.ProjectModel.updateOne
         return this.ProjectModel.updateOne
           .calledWith(
           .calledWith(
             { _id: project_id, 'overleaf.history.id': { $exists: false } },
             { _id: project_id, 'overleaf.history.id': { $exists: false } },
-            { 'overleaf.history.id': this.newHistoryId }
+            { 'overleaf.history.id': this.historyId }
           )
           )
           .should.equal(true)
           .should.equal(true)
       })
       })