From ab10336110c136590815fac6345972125d08f331 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 10 Sep 2018 11:18:15 +0100 Subject: [PATCH] Record last update time and user from project-history --- .../Features/History/HistoryController.coffee | 9 ++++ .../Features/Project/ProjectController.coffee | 7 +++- .../Project/ProjectEntityUpdateHandler.coffee | 2 - .../Project/ProjectUpdateHandler.coffee | 23 ++++------ services/web/app/coffee/models/Project.coffee | 1 + services/web/app/coffee/router.coffee | 1 + .../coffee/ProjectLastUpdatedTests.coffee | 42 +++++++++++++++++++ .../History/HistoryControllerTests.coffee | 1 + .../ProjectEntityUpdateHandlerTests.coffee | 5 --- .../Project/ProjectUpdateHandlerTests.coffee | 15 ++++--- 10 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 services/web/test/acceptance/coffee/ProjectLastUpdatedTests.coffee diff --git a/services/web/app/coffee/Features/History/HistoryController.coffee b/services/web/app/coffee/Features/History/HistoryController.coffee index 189e07b0f5..8b014751f9 100644 --- a/services/web/app/coffee/Features/History/HistoryController.coffee +++ b/services/web/app/coffee/Features/History/HistoryController.coffee @@ -7,6 +7,7 @@ HistoryManager = require "./HistoryManager" ProjectDetailsHandler = require "../Project/ProjectDetailsHandler" ProjectEntityUpdateHandler = require "../Project/ProjectEntityUpdateHandler" RestoreManager = require "./RestoreManager" +ProjectUpdateHandler = require "../Project/ProjectUpdateHandler" module.exports = HistoryController = selectHistoryApi: (req, res, next = (error) ->) -> @@ -143,3 +144,11 @@ module.exports = HistoryController = error = new Error("history api responded with non-success code: #{response.statusCode}") logger.error err: error, "project-history api responded with non-success code: #{response.statusCode}" callback(error) + + setLastUpdated: (req, res, next) -> + {project_id} = req.params + {user_id, timestamp} = req.body + logger.log {project_id, user_id, timestamp}, 'updating last updated date' + ProjectUpdateHandler.markAsUpdated project_id, user_id, timestamp, (error) -> + return next(error) if error? + res.sendStatus 200 diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 59c0647c19..ed5e219e3f 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -184,7 +184,7 @@ module.exports = ProjectController = notifications: (cb)-> NotificationsHandler.getUserNotifications user_id, cb projects: (cb)-> - ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb + ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated lastUpdatedBy publicAccesLevel archived owner_ref tokens', cb v1Projects: (cb) -> Modules.hooks.fire "findAllV1Projects", user_id, (error, projects = []) -> if error? and error instanceof V1ConnectionError @@ -392,6 +392,7 @@ module.exports = ProjectController = id: project._id name: project.name lastUpdated: project.lastUpdated + lastUpdatedBy: project.lastUpdatedBy publicAccessLevel: project.publicAccesLevel accessLevel: accessLevel source: source @@ -430,6 +431,8 @@ module.exports = ProjectController = for project in projects if project.owner_ref? users[project.owner_ref.toString()] = true + if project.lastUpdatedBy? + users[project.lastUpdatedBy] = true jobs = [] for user_id, _ of users @@ -444,6 +447,8 @@ module.exports = ProjectController = for project in projects if project.owner_ref? project.owner = users[project.owner_ref.toString()] + if project.lastUpdatedBy? + project.lastUpdatedBy = users[project.lastUpdatedBy.toString()] callback null, projects _buildWarningsList: (v1ProjectData = {}) -> diff --git a/services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee b/services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee index b7be80cb47..4800de05d4 100644 --- a/services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee +++ b/services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee @@ -114,8 +114,6 @@ module.exports = ProjectEntityUpdateHandler = self = logger.log {project_id, doc_id, modified}, "finished updating doc lines" # path will only be present if the doc is not deleted if modified && !isDeletedDoc - # Don't need to block for marking as updated - ProjectUpdateHandler.markAsUpdated project_id TpdsUpdateSender.addDoc {project_id:project_id, path:path.fileSystem, doc_id:doc_id, project_name:project.name, rev:rev}, callback else callback() diff --git a/services/web/app/coffee/Features/Project/ProjectUpdateHandler.coffee b/services/web/app/coffee/Features/Project/ProjectUpdateHandler.coffee index ba3b3b6295..d89d7c7e89 100644 --- a/services/web/app/coffee/Features/Project/ProjectUpdateHandler.coffee +++ b/services/web/app/coffee/Features/Project/ProjectUpdateHandler.coffee @@ -2,30 +2,25 @@ Project = require('../../models/Project').Project logger = require('logger-sharelatex') module.exports = - markAsUpdated : (project_id, callback)-> + markAsUpdated : (project_id, user_id, timestamp, callback)-> conditions = {_id:project_id} - update = {lastUpdated:Date.now()} - Project.update conditions, update, {}, (err)-> - if callback? - callback() + update = { + lastUpdated: new Date(timestamp), + lastUpdatedBy: user_id + } + Project.update conditions, update, {}, callback markAsOpened : (project_id, callback)-> conditions = {_id:project_id} update = {lastOpened:Date.now()} - Project.update conditions, update, {}, (err)-> - if callback? - callback() + Project.update conditions, update, {}, callback markAsInactive: (project_id, callback)-> conditions = {_id:project_id} update = {active:false} - Project.update conditions, update, {}, (err)-> - if callback? - callback() + Project.update conditions, update, {}, callback markAsActive: (project_id, callback)-> conditions = {_id:project_id} update = {active:true} - Project.update conditions, update, {}, (err)-> - if callback? - callback() \ No newline at end of file + Project.update conditions, update, {}, callback diff --git a/services/web/app/coffee/models/Project.coffee b/services/web/app/coffee/models/Project.coffee index 00c2f1be52..f4b478d64e 100644 --- a/services/web/app/coffee/models/Project.coffee +++ b/services/web/app/coffee/models/Project.coffee @@ -19,6 +19,7 @@ DeletedFileSchema = new Schema ProjectSchema = new Schema name : {type:String, default:'new project'} lastUpdated : {type:Date, default: () -> new Date()} + lastUpdatedBy : {type:ObjectId, ref: 'User'} lastOpened : {type:Date} active : { type: Boolean, default: true } owner_ref : {type:ObjectId, ref:'User'} diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index b196c56870..2413632581 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -238,6 +238,7 @@ module.exports = class Router webRouter.post '/project/:project_id/doc/:doc_id/restore', AuthorizationMiddlewear.ensureUserCanWriteProjectContent, HistoryController.restoreDocFromDeletedDoc webRouter.post "/project/:project_id/restore_file", AuthorizationMiddlewear.ensureUserCanWriteProjectContent, HistoryController.restoreFileFromV2 privateApiRouter.post "/project/:Project_id/history/resync", AuthenticationController.httpAuth, HistoryController.resyncProjectHistory + privateApiRouter.post "/project/:project_id/last_updated", AuthenticationController.httpAuth, HistoryController.setLastUpdated webRouter.get "/project/:Project_id/labels", AuthorizationMiddlewear.ensureUserCanReadProject, HistoryController.selectHistoryApi, HistoryController.ensureProjectHistoryEnabled, HistoryController.getLabels webRouter.post "/project/:Project_id/labels", AuthorizationMiddlewear.ensureUserCanWriteProjectContent, HistoryController.selectHistoryApi, HistoryController.ensureProjectHistoryEnabled, HistoryController.createLabel diff --git a/services/web/test/acceptance/coffee/ProjectLastUpdatedTests.coffee b/services/web/test/acceptance/coffee/ProjectLastUpdatedTests.coffee new file mode 100644 index 0000000000..5798d0236c --- /dev/null +++ b/services/web/test/acceptance/coffee/ProjectLastUpdatedTests.coffee @@ -0,0 +1,42 @@ +expect = require("chai").expect +async = require("async") +User = require "./helpers/User" +request = require "./helpers/request" +settings = require "settings-sharelatex" +Project = require("../../../app/js/models/Project").Project + +markAsUpdated = (project_id, user_id, timestamp, callback) -> + request.post { + url: "/project/#{project_id}/last_updated" + json: { + user_id, + timestamp + } + auth: + user: settings.apis.web.user + pass: settings.apis.web.pass + sendImmediately: true + jar: false + }, callback + +describe "ProjectLastUpdated", -> + before (done) -> + @timeout(90000) + @owner = new User() + @timestamp = Date.now() + @user_id = "abcdef1234567890abcdef12" + async.series [ + (cb) => @owner.login cb + (cb) => @owner.createProject "private-project", (error, @project_id) => cb(error) + ], done + + describe "with user_id and timestamp", -> + it 'should update the project', (done) -> + markAsUpdated @project_id, @user_id, @timestamp, (error, response, body) => + return done(error) if error? + expect(response.statusCode).to.equal 200 + Project.findOne _id: @project_id, (error, project) => + return done(error) if error? + expect(project.lastUpdated.getTime()).to.equal @timestamp + expect(project.lastUpdatedBy.toString()).to.equal @user_id + done() diff --git a/services/web/test/unit/coffee/History/HistoryControllerTests.coffee b/services/web/test/unit/coffee/History/HistoryControllerTests.coffee index d5777f5490..4e29bbae90 100644 --- a/services/web/test/unit/coffee/History/HistoryControllerTests.coffee +++ b/services/web/test/unit/coffee/History/HistoryControllerTests.coffee @@ -23,6 +23,7 @@ describe "HistoryController", -> "../Project/ProjectDetailsHandler": @ProjectDetailsHandler = {} "../Project/ProjectEntityUpdateHandler": @ProjectEntityUpdateHandler = {} "./RestoreManager": @RestoreManager = {} + "../Project/ProjectUpdateHandler": @ProjectUpdateHandler = {} @settings.apis = trackchanges: enabled: false diff --git a/services/web/test/unit/coffee/Project/ProjectEntityUpdateHandlerTests.coffee b/services/web/test/unit/coffee/Project/ProjectEntityUpdateHandlerTests.coffee index 3de4546e6d..1b4739000f 100644 --- a/services/web/test/unit/coffee/Project/ProjectEntityUpdateHandlerTests.coffee +++ b/services/web/test/unit/coffee/Project/ProjectEntityUpdateHandlerTests.coffee @@ -190,11 +190,6 @@ describe 'ProjectEntityUpdateHandler', -> .calledWith(project_id, doc_id, @docLines, @version, @ranges) .should.equal true - it "should mark the project as updated", -> - @ProjectUpdater.markAsUpdated - .calledWith(project_id) - .should.equal true - it "should send the doc the to the TPDS", -> @TpdsUpdateSender.addDoc .calledWith({ diff --git a/services/web/test/unit/coffee/Project/ProjectUpdateHandlerTests.coffee b/services/web/test/unit/coffee/Project/ProjectUpdateHandlerTests.coffee index a68a9be1f1..da719c91f2 100644 --- a/services/web/test/unit/coffee/Project/ProjectUpdateHandlerTests.coffee +++ b/services/web/test/unit/coffee/Project/ProjectUpdateHandlerTests.coffee @@ -16,12 +16,15 @@ describe 'ProjectUpdateHandler', -> describe 'marking a project as recently updated', -> it 'should send an update to mongo', (done)-> project_id = "project_id" - @handler.markAsUpdated project_id, (err)=> - args = @ProjectModel.update.args[0] - args[0]._id.should.equal project_id - date = args[1].lastUpdated+"" - now = Date.now()+"" - date.substring(0,5).should.equal now.substring(0,5) + user_id = "mock_user_id" + timestamp = Date.now() + @handler.markAsUpdated project_id, user_id, timestamp, (err)=> + @ProjectModel.update.calledWith({ + _id: project_id, + }, { + lastUpdated: new Date(timestamp), + lastUpdatedBy: user_id + }).should.equal true done() describe "markAsOpened", ->