From 829595777cbfc22e976ad965d1fa45163b0a3c64 Mon Sep 17 00:00:00 2001 From: Nate Stemen Date: Tue, 24 Oct 2017 16:35:28 +0100 Subject: [PATCH 01/58] change regex to match single backslash and command fragment --- .../aceEditor/auto-complete/AutoCompleteManager.coffee | 1 + .../editor/directives/aceEditor/auto-complete/Helpers.coffee | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee index 24a524b4b6..7ee46206d5 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee @@ -229,6 +229,7 @@ define [ 99999 ) ) + if lineBeyondCursor if partialCommandMatch = lineBeyondCursor.match(/^([a-z0-9]+)\{/) # We've got a partial command after the cursor diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee index 7beb41debd..c3d5ef56ba 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee @@ -17,8 +17,8 @@ define [ # \includegraphics[width=\textwidth]{.. # should not match the \textwidth. blankArguments = lineUpToCursor.replace /\[([^\]]*)\]/g, (args) -> - Array(args.length+1).join('.') - if m = blankArguments.match(/(\\[^\\]+)$/) + Array(args.length + 1).join('.') + if m = blankArguments.match(/(\\[^\\]*)$/) return m.index else return -1 From e8731bc2768e5f43e0219d66405ff3dd19a84584 Mon Sep 17 00:00:00 2001 From: Nate Stemen Date: Fri, 20 Oct 2017 11:07:56 +0100 Subject: [PATCH 02/58] allow for capital letters in command name --- .../aceEditor/auto-complete/AutoCompleteManager.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee index 24a524b4b6..6f2e5fbec9 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee @@ -149,7 +149,7 @@ define [ lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\" lastTwoChars = lineUpToCursor.slice(-2) # Don't offer autocomplete on double-backslash, backslash-colon, etc - if lastTwoChars.match(/^\\[^a-z]$/) + if lastTwoChars.match(/^\\[^a-zA-Z]$/) @editor?.completer?.detach?() return if commandName in ['begin', 'end'] @@ -230,7 +230,7 @@ define [ ) ) if lineBeyondCursor - if partialCommandMatch = lineBeyondCursor.match(/^([a-z0-9]+)\{/) + if partialCommandMatch = lineBeyondCursor.match(/^([a-zA-Z0-9]+)\{/) # We've got a partial command after the cursor commandTail = partialCommandMatch[1] # remove rest of the partial command, right of cursor From dc6110db8d2b269307f425d53908c6e09dbcbaee Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 16 Nov 2017 11:32:08 +0000 Subject: [PATCH 03/58] put ace in readonly mode when changing session if the session fails to attach successfully (e.g due to an exception in the changeSession event handler) the editor will be left in a state where the user will not be able to enter any text. This should at least cause them to reload the editor. --- .../web/public/coffee/ide/editor/directives/aceEditor.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 577a3a0e75..12d3cc7b5b 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -356,6 +356,7 @@ define [ session.setOption("useWorker", scope.syntaxValidation); # now attach session to editor + editor.setReadOnly(true) editor.setSession(session) doc = session.getDocument() @@ -364,6 +365,7 @@ define [ editor.initing = true sharejs_doc.attachToAce(editor) editor.initing = false + editor.setReadOnly(false) resetScrollMargins() From bd09ef81f24969f5eba978b950086b19ba616276 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 16 Nov 2017 15:41:16 +0000 Subject: [PATCH 04/58] added comments --- .../web/public/coffee/ide/editor/directives/aceEditor.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 12d3cc7b5b..79aad26221 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -356,7 +356,7 @@ define [ session.setOption("useWorker", scope.syntaxValidation); # now attach session to editor - editor.setReadOnly(true) + editor.setReadOnly(true) # set to readonly until document change handlers are attached editor.setSession(session) doc = session.getDocument() @@ -365,7 +365,8 @@ define [ editor.initing = true sharejs_doc.attachToAce(editor) editor.initing = false - editor.setReadOnly(false) + # now ready to edit document + editor.setReadOnly(scope.readOnly) # respect the readOnly setting, normally false resetScrollMargins() From 154943ba68f4ac17bae91db5b269352c7ddd0e50 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 17 Nov 2017 16:38:44 +0000 Subject: [PATCH 05/58] Don't check for linting errors if code check is disabled There are a couple of reasons for this: 1. Some linting errors are returned from the server after a compile is run, replacing client-side linting errors. If code check is disabled this does not happen, and therefore linting errors persist until the next compile. This makes it appear as though autocompile is not running 2. It is likely that if code check is disabled, the user is deliberately ignoring linting errors and therefore the linting check is pointless --- .../public/coffee/ide/pdf/controllers/PdfController.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index e2bb51a0fd..17afd8bbcb 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -85,7 +85,11 @@ define [ isTimeNonMonotonic = timeSinceLastCompile < 0 if isTimeNonMonotonic || timeSinceLastCompile >= AUTO_COMPILE_TIMEOUT - if (!ide.$scope.hasLintingError) + # If user has code check disabled, it is likely because they have + # linting errors that they are ignoring. Therefore it doesn't make sense + # to block auto compiles. It also causes problems where server-provided + # linting errors aren't cleared after typing + if (ide.$scope.settings.syntaxValidation and !ide.$scope.hasLintingError) $scope.recompile(isAutoCompileOnChange: true) else # Extend remainder of timeout From ca0982a909c388385c3a11e01c9404b9fa873c10 Mon Sep 17 00:00:00 2001 From: James Allen Date: Fri, 17 Nov 2017 17:16:12 +0000 Subject: [PATCH 06/58] Enable the external auth switches when OL OAuth in use --- services/web/app/coffee/infrastructure/ExpressLocals.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/infrastructure/ExpressLocals.coffee b/services/web/app/coffee/infrastructure/ExpressLocals.coffee index 0b30d11cc5..1f22b2d2c3 100644 --- a/services/web/app/coffee/infrastructure/ExpressLocals.coffee +++ b/services/web/app/coffee/infrastructure/ExpressLocals.coffee @@ -89,7 +89,7 @@ module.exports = (app, webRouter, privateApiRouter, publicApiRouter)-> webRouter.use (req, res, next)-> req.externalAuthenticationSystemUsed = res.locals.externalAuthenticationSystemUsed = -> - Settings.ldap? or Settings.saml? + Settings.ldap? or Settings.saml? or Settings.overleaf?.oauth? next() webRouter.use (req, res, next)-> From 311ebf89c44b27bcae33afeeeb6af7d511ba54fa Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 20 Nov 2017 10:10:23 +0000 Subject: [PATCH 07/58] Refactor to always use req.externalAuthenticationSystemUsed --- services/web/app/coffee/Features/User/UserController.coffee | 3 +-- .../test/UnitTests/coffee/User/UserControllerTests.coffee | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/services/web/app/coffee/Features/User/UserController.coffee b/services/web/app/coffee/Features/User/UserController.coffee index d64883b23b..7dc82c1a7b 100644 --- a/services/web/app/coffee/Features/User/UserController.coffee +++ b/services/web/app/coffee/Features/User/UserController.coffee @@ -51,7 +51,6 @@ module.exports = UserController = updateUserSettings : (req, res)-> user_id = AuthenticationController.getLoggedInUserId(req) - usingExternalAuth = settings.ldap? or settings.saml? logger.log user_id: user_id, "updating account settings" User.findById user_id, (err, user)-> if err? or !user? @@ -84,7 +83,7 @@ module.exports = UserController = user.ace.syntaxValidation = req.body.syntaxValidation user.save (err)-> newEmail = req.body.email?.trim().toLowerCase() - if !newEmail? or newEmail == user.email or usingExternalAuth + if !newEmail? or newEmail == user.email or req.externalAuthenticationSystemUsed() # end here, don't update email AuthenticationController.setInSessionUser(req, {first_name: user.first_name, last_name: user.last_name}) return res.sendStatus 200 diff --git a/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee b/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee index a71fe4bb91..c358f35b22 100644 --- a/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee @@ -187,6 +187,7 @@ describe "UserController", -> describe "updateUserSettings", -> beforeEach -> @newEmail = "hello@world.com" + @req.externalAuthenticationSystemUsed = sinon.stub().returns(false) it "should call save", (done)-> @req.body = {} @@ -280,10 +281,7 @@ describe "UserController", -> beforeEach -> @UserUpdater.changeEmailAddress.callsArgWith(2) @newEmail = 'someone23@example.com' - @settings.ldap = {active: true} - - afterEach -> - delete @settings.ldap + @req.externalAuthenticationSystemUsed = sinon.stub().returns(true) it 'should not set a new email', (done) -> @req.body.email = @newEmail From f6bbf7fe3f03b9ba7738b2b57e9602ab893fe3fb Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 25 Oct 2017 09:13:17 +0100 Subject: [PATCH 08/58] wip --- .../Features/Project/OlProjectGetter.coffee | 18 ++++++++++++++++++ .../Features/Project/ProjectController.coffee | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 services/web/app/coffee/Features/Project/OlProjectGetter.coffee diff --git a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee b/services/web/app/coffee/Features/Project/OlProjectGetter.coffee new file mode 100644 index 0000000000..06eb1be0be --- /dev/null +++ b/services/web/app/coffee/Features/Project/OlProjectGetter.coffee @@ -0,0 +1,18 @@ +request = require 'request' +settings = require 'settings-sharelatex' +Errors = require '../Errors/Errors' + +makeRequest = (opts, callback) -> + if settings.apis?.olProjects?.url? + urlPath = opts.url + opts.url = "#{settings.apis.olProjects.url}#{urlPath}" + request opts, callback + else + callback(new Errors.ServiceNotConfiguredError('OL Projects service not configured')) + +module.exports = OlProjectGetter = + findAllUsersProjects: (userId, callback = (error, projects) ->) -> + opts = + method: 'GET' + url: '/api/v0/current_user' + json: true \ No newline at end of file diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index ff20664c43..a586dddb94 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -1,5 +1,6 @@ async = require("async") logger = require("logger-sharelatex") +Settings = require('settings-sharelatex') projectDeleter = require("./ProjectDeleter") projectDuplicator = require("./ProjectDuplicator") projectCreationHandler = require("./ProjectCreationHandler") @@ -148,6 +149,11 @@ module.exports = ProjectController = NotificationsHandler.getUserNotifications user_id, cb projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb + olProjects: (cb) -> + console.log('OOOOOOOOOOOOOOOOOOOOOOO') + if Settings.brandPrefix == "ol-" + OlProjectGetter.findAllUsersProjects user_id, cb + cb() hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb user: (cb) -> From fa0559f8d76a0273f7a15927dd3029c37ebf94c3 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 09:42:12 +0000 Subject: [PATCH 09/58] Fetch OL projects using OAuth --- .../coffee/Features/Project/OlProjectGetter.coffee | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee b/services/web/app/coffee/Features/Project/OlProjectGetter.coffee index 06eb1be0be..3f47c0dac4 100644 --- a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee +++ b/services/web/app/coffee/Features/Project/OlProjectGetter.coffee @@ -1,6 +1,8 @@ request = require 'request' settings = require 'settings-sharelatex' +logger = require 'logger-sharelatex' Errors = require '../Errors/Errors' +oAuthRequest = require '../../../../modules/overleaf-integration-web-module/app/coffee/oauth/OAuthRequest' makeRequest = (opts, callback) -> if settings.apis?.olProjects?.url? @@ -12,7 +14,11 @@ makeRequest = (opts, callback) -> module.exports = OlProjectGetter = findAllUsersProjects: (userId, callback = (error, projects) ->) -> - opts = + oAuthRequest userId, { + url: "#{settings.overleaf.host}/api/v1/sharelatex/docs" method: 'GET' - url: '/api/v0/current_user' - json: true \ No newline at end of file + json: true + }, (error, docs) -> + return callback(error) if error? + logger.log {userId, docs}, "got projects from OL" + callback(null, docs) \ No newline at end of file From 8c66342a0419a9577544e1e68d724ef08e4318a3 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 09:42:44 +0000 Subject: [PATCH 10/58] Pull in OL projects and process for view --- .../Features/Project/ProjectController.coffee | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index a586dddb94..c8126b10bd 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -18,6 +18,7 @@ fs = require "fs" InactiveProjectManager = require("../InactiveData/InactiveProjectManager") ProjectUpdateHandler = require("./ProjectUpdateHandler") ProjectGetter = require("./ProjectGetter") +OlProjectGetter = require("./OlProjectGetter") PrivilegeLevels = require("../Authorization/PrivilegeLevels") AuthenticationController = require("../Authentication/AuthenticationController") PackageVersions = require("../../infrastructure/PackageVersions") @@ -150,10 +151,10 @@ module.exports = ProjectController = projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb olProjects: (cb) -> - console.log('OOOOOOOOOOOOOOOOOOOOOOO') if Settings.brandPrefix == "ol-" OlProjectGetter.findAllUsersProjects user_id, cb - cb() + else + cb() hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb user: (cb) -> @@ -167,7 +168,7 @@ module.exports = ProjectController = notifications = require("underscore").map results.notifications, (notification)-> notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts) return notification - projects = ProjectController._buildProjectList results.projects + projects = ProjectController._buildProjectList results.projects, results.olProjects.projects user = results.user ProjectController._injectProjectOwners projects, (error, projects) -> return next(error) if error? @@ -396,7 +397,7 @@ module.exports = ProjectController = showLinkSharingOnboarding: showLinkSharingOnboarding timer.done() - _buildProjectList: (allProjects)-> + _buildProjectList: (allProjects, olProjects = [])-> {owned, readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly} = allProjects projects = [] for project in owned @@ -406,6 +407,8 @@ module.exports = ProjectController = projects.push ProjectController._buildProjectViewModel(project, "readWrite", Sources.INVITE) for project in readOnly projects.push ProjectController._buildProjectViewModel(project, "readOnly", Sources.INVITE) + for project in olProjects + projects.push ProjectController._buildOlProjectViwModel(project) # Token-access # Only add these projects if they're not already present, this gives us cascading access # from 'owner' => 'token-read-only' @@ -433,6 +436,18 @@ module.exports = ProjectController = } return model + _buildOlProjectViewModel: (project) -> + { + id: project.id + name: project.title + lastUpdated: project.updated_at +# publicAccessLevel: +# accessLevel: + archived: project.archived +# owner_ref: + isOLProject: true + } + _injectProjectOwners: (projects, callback = (error, projects) ->) -> users = {} for project in projects From d072fabb25618d693b2dcaac02167dec62e15701 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 11:26:54 +0000 Subject: [PATCH 11/58] Fix non-beta throwing error because it's expecting OL projects --- .../web/app/coffee/Features/Project/ProjectController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index c8126b10bd..fca884f371 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -168,7 +168,7 @@ module.exports = ProjectController = notifications = require("underscore").map results.notifications, (notification)-> notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts) return notification - projects = ProjectController._buildProjectList results.projects, results.olProjects.projects + projects = ProjectController._buildProjectList results.projects, results.olProjects?.projects user = results.user ProjectController._injectProjectOwners projects, (error, projects) -> return next(error) if error? From 532a26c68f5175e79dad496da14ca690ee12aecc Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 11:27:24 +0000 Subject: [PATCH 12/58] Extract out project list item to template and add OL-specific template --- services/web/app/views/project/list/item.pug | 40 +++++++++++++++ .../web/app/views/project/list/ol-item.pug | 11 ++++ .../app/views/project/list/project-list.pug | 50 ++++--------------- 3 files changed, 60 insertions(+), 41 deletions(-) create mode 100644 services/web/app/views/project/list/item.pug create mode 100644 services/web/app/views/project/list/ol-item.pug diff --git a/services/web/app/views/project/list/item.pug b/services/web/app/views/project/list/item.pug new file mode 100644 index 0000000000..f246ad34d4 --- /dev/null +++ b/services/web/app/views/project/list/item.pug @@ -0,0 +1,40 @@ +.col-xs-6 + input.select-item( + select-individual, + type="checkbox", + ng-model="project.selected" + stop-propagation="click" + aria-label=translate('select_project') + " '{{ project.name }}'" + ) + span + a.projectName( + ng-href="{{projectLink(project)}}" + stop-propagation="click" + ) {{project.name}} + span( + ng-controller="TagListController" + ) + .tag-label( + ng-repeat='tag in project.tags' + stop-propagation="click" + ) + a.label.label-default.tag-label-name( + href, + ng-click="selectTag(tag)" + ) {{tag.name}} + a.label.label-default.tag-label-remove( + href + ng-click="removeProjectFromTag(project, tag)" + ) × + +.col-xs-2 + span.owner {{ownerName()}} + span(ng-if="isLinkSharingProject(project)") + |   + i.fa.fa-link.small( + tooltip=translate("link_sharing") + tooltip-placement="right" + tooltip-append-to-body="true" + ) +.col-xs-4 + span.last-modified {{project.lastUpdated | formatDate}} \ No newline at end of file diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug new file mode 100644 index 0000000000..be76749706 --- /dev/null +++ b/services/web/app/views/project/list/ol-item.pug @@ -0,0 +1,11 @@ +.col-xs-6 + span + a.projectName( + href="/project/{{project.id}}" + stop-propagation="click" + ) {{project.name}} + +.col-xs-2 + span.owner +.col-xs-4 + span.last-modified \ No newline at end of file diff --git a/services/web/app/views/project/list/project-list.pug b/services/web/app/views/project/list/project-list.pug index aba8ed08be..66103ea3fa 100644 --- a/services/web/app/views/project/list/project-list.pug +++ b/services/web/app/views/project/list/project-list.pug @@ -142,47 +142,15 @@ ng-repeat="project in visibleProjects | orderBy:predicate:reverse", ng-controller="ProjectListItemController" ) - .row(select-row) - .col-xs-6 - input.select-item( - select-individual, - type="checkbox", - ng-model="project.selected" - stop-propagation="click" - aria-label=translate('select_project') + " '{{ project.name }}'" - ) - span - a.projectName( - ng-href="{{projectLink(project)}}" - stop-propagation="click" - ) {{project.name}} - span( - ng-controller="TagListController" - ) - .tag-label( - ng-repeat='tag in project.tags' - stop-propagation="click" - ) - a.label.label-default.tag-label-name( - href, - ng-click="selectTag(tag)" - ) {{tag.name}} - a.label.label-default.tag-label-remove( - href - ng-click="removeProjectFromTag(project, tag)" - ) × - - .col-xs-2 - span.owner {{ownerName()}} - span(ng-if="isLinkSharingProject(project)") - |   - i.fa.fa-link.small( - tooltip=translate("link_sharing") - tooltip-placement="right" - tooltip-append-to-body="true" - ) - .col-xs-4 - span.last-modified {{project.lastUpdated | formatDate}} + .row( + ng-if="!project.isOLProject" + select-row + ) + include ./item + .row( + ng-if="project.isOLProject" + ) + include ./ol-item li( ng-if="visibleProjects.length == 0", ng-cloak From fe90ef047f456c72b33542f18fbdbbc9e1611766 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 11:39:39 +0000 Subject: [PATCH 13/58] Temp OL label --- services/web/app/views/project/list/ol-item.pug | 5 ++--- services/web/public/stylesheets/app/project-list.less | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug index be76749706..a43d681b1f 100644 --- a/services/web/app/views/project/list/ol-item.pug +++ b/services/web/app/views/project/list/ol-item.pug @@ -1,11 +1,10 @@ -.col-xs-6 +.col-xs-8 + span.label.label-default.ol-label OL span a.projectName( href="/project/{{project.id}}" stop-propagation="click" ) {{project.name}} -.col-xs-2 - span.owner .col-xs-4 span.last-modified \ No newline at end of file diff --git a/services/web/public/stylesheets/app/project-list.less b/services/web/public/stylesheets/app/project-list.less index 1568915296..cde6596303 100644 --- a/services/web/public/stylesheets/app/project-list.less +++ b/services/web/public/stylesheets/app/project-list.less @@ -366,6 +366,12 @@ ul.project-list { border-top-left-radius: 0; border-bottom-left-radius: 0; } + + .ol-label { + margin-right: 9px; + margin-left: 5px; + padding: 2px 3px 1px; + } } i.tablesort { padding-left: 8px; From 9eff01fcc536589177b8f268e08cc6e2766ad236 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 11:52:07 +0000 Subject: [PATCH 14/58] Explcitly depend on moment --- services/web/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/services/web/package.json b/services/web/package.json index e831d929e1..b4dd29395d 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -40,6 +40,7 @@ "metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.7.1", "mimelib": "0.2.14", "mocha": "1.17.1", + "moment": "^2.18.1", "mongojs": "2.4.0", "mongoose": "4.11.4", "multer": "^0.1.8", From fc6da2e2e4a2166ad8cbfce3c3d916af8b2891bc Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 12:27:09 +0000 Subject: [PATCH 15/58] Parse & display OL project last updated --- .../web/app/coffee/Features/Project/ProjectController.coffee | 3 ++- services/web/app/views/project/list/ol-item.pug | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index fca884f371..67d6a8014a 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -1,4 +1,5 @@ async = require("async") +moment = require('moment') logger = require("logger-sharelatex") Settings = require('settings-sharelatex') projectDeleter = require("./ProjectDeleter") @@ -440,7 +441,7 @@ module.exports = ProjectController = { id: project.id name: project.title - lastUpdated: project.updated_at + lastUpdated: moment.unix(project.updated_at) # publicAccessLevel: # accessLevel: archived: project.archived diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug index a43d681b1f..c0bf873ce7 100644 --- a/services/web/app/views/project/list/ol-item.pug +++ b/services/web/app/views/project/list/ol-item.pug @@ -7,4 +7,4 @@ ) {{project.name}} .col-xs-4 - span.last-modified \ No newline at end of file + span.last-modified {{project.lastUpdated | formatDate}} \ No newline at end of file From 3c8dd6c42185b678eb678cad23407e340bdafad5 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 12:27:19 +0000 Subject: [PATCH 16/58] Link to OL project --- services/web/app/views/project/list/ol-item.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug index c0bf873ce7..39741af6aa 100644 --- a/services/web/app/views/project/list/ol-item.pug +++ b/services/web/app/views/project/list/ol-item.pug @@ -2,7 +2,7 @@ span.label.label-default.ol-label OL span a.projectName( - href="/project/{{project.id}}" + href=settings.overleaf.host + "/{{project.id}}" stop-propagation="click" ) {{project.name}} From 20c756ec9a09c2524072a0a4f030cce6c69c4b77 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 14:28:35 +0000 Subject: [PATCH 17/58] Switch to v1 wording --- services/web/app/views/project/list/ol-item.pug | 2 +- services/web/public/stylesheets/app/project-list.less | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug index 39741af6aa..a5f21e7387 100644 --- a/services/web/app/views/project/list/ol-item.pug +++ b/services/web/app/views/project/list/ol-item.pug @@ -1,5 +1,5 @@ .col-xs-8 - span.label.label-default.ol-label OL + span.label.label-default.ol-label V1 span a.projectName( href=settings.overleaf.host + "/{{project.id}}" diff --git a/services/web/public/stylesheets/app/project-list.less b/services/web/public/stylesheets/app/project-list.less index cde6596303..88442147f2 100644 --- a/services/web/public/stylesheets/app/project-list.less +++ b/services/web/public/stylesheets/app/project-list.less @@ -368,7 +368,7 @@ ul.project-list { } .ol-label { - margin-right: 9px; + margin-right: 11px; margin-left: 5px; padding: 2px 3px 1px; } From dfe17d63ba89c7f4ea786d18f1a2375934eab2c2 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 14:29:20 +0000 Subject: [PATCH 18/58] Projects removed also treated as archived --- .../web/app/coffee/Features/Project/ProjectController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 67d6a8014a..78c84f5681 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -444,7 +444,7 @@ module.exports = ProjectController = lastUpdated: moment.unix(project.updated_at) # publicAccessLevel: # accessLevel: - archived: project.archived + archived: project.removed || project.archived # owner_ref: isOLProject: true } From 3f422dc48c93af9fad1733da8417c643e7493904 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 15:07:59 +0000 Subject: [PATCH 19/58] Clean up OL view model --- .../web/app/coffee/Features/Project/ProjectController.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 78c84f5681..9b281617c8 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -442,10 +442,8 @@ module.exports = ProjectController = id: project.id name: project.title lastUpdated: moment.unix(project.updated_at) -# publicAccessLevel: -# accessLevel: + accessLevel: "readOnly", archived: project.removed || project.archived -# owner_ref: isOLProject: true } From 37c7a95fde550827b960745d890c1e4caad518ff Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 15:30:14 +0000 Subject: [PATCH 20/58] Hide V1 projects from shared filter --- .../web/public/coffee/main/project-list/project-list.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/web/public/coffee/main/project-list/project-list.coffee b/services/web/public/coffee/main/project-list/project-list.coffee index 8c39df060f..63e669308c 100644 --- a/services/web/public/coffee/main/project-list/project-list.coffee +++ b/services/web/public/coffee/main/project-list/project-list.coffee @@ -116,6 +116,10 @@ define [ if $scope.filter == "shared" and project.accessLevel == "owner" visible = false + # Hide projects from V1 if we only want to see shared projects + if $scope.filter == "shared" and project.isOLProject + visible = false + # Hide projects we don't own if we only want to see owned projects if $scope.filter == "owned" and project.accessLevel != "owner" visible = false From 7910f2109fd30887a345c69bfbab2138c1f759f0 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 15:32:54 +0000 Subject: [PATCH 21/58] Switch to V1 wording --- .../web/app/coffee/Features/Project/ProjectController.coffee | 3 ++- services/web/app/views/project/list/ol-item.pug | 2 +- services/web/app/views/project/list/project-list.pug | 4 ++-- .../web/public/coffee/main/project-list/project-list.coffee | 2 +- services/web/public/stylesheets/app/project-list.less | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 9b281617c8..ac28dcdf4c 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -434,6 +434,7 @@ module.exports = ProjectController = archived: !!project.archived owner_ref: project.owner_ref tokens: project.tokens + isV1Project: false } return model @@ -444,7 +445,7 @@ module.exports = ProjectController = lastUpdated: moment.unix(project.updated_at) accessLevel: "readOnly", archived: project.removed || project.archived - isOLProject: true + isV1Project: true } _injectProjectOwners: (projects, callback = (error, projects) ->) -> diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug index a5f21e7387..49a6dd01f2 100644 --- a/services/web/app/views/project/list/ol-item.pug +++ b/services/web/app/views/project/list/ol-item.pug @@ -1,5 +1,5 @@ .col-xs-8 - span.label.label-default.ol-label V1 + span.label.label-default.v1-label V1 span a.projectName( href=settings.overleaf.host + "/{{project.id}}" diff --git a/services/web/app/views/project/list/project-list.pug b/services/web/app/views/project/list/project-list.pug index 66103ea3fa..260cc387f0 100644 --- a/services/web/app/views/project/list/project-list.pug +++ b/services/web/app/views/project/list/project-list.pug @@ -143,12 +143,12 @@ ng-controller="ProjectListItemController" ) .row( - ng-if="!project.isOLProject" + ng-if="!project.isV1Project" select-row ) include ./item .row( - ng-if="project.isOLProject" + ng-if="project.isV1Project" ) include ./ol-item li( diff --git a/services/web/public/coffee/main/project-list/project-list.coffee b/services/web/public/coffee/main/project-list/project-list.coffee index 63e669308c..335f46c62d 100644 --- a/services/web/public/coffee/main/project-list/project-list.coffee +++ b/services/web/public/coffee/main/project-list/project-list.coffee @@ -117,7 +117,7 @@ define [ visible = false # Hide projects from V1 if we only want to see shared projects - if $scope.filter == "shared" and project.isOLProject + if $scope.filter == "shared" and project.isV1Project visible = false # Hide projects we don't own if we only want to see owned projects diff --git a/services/web/public/stylesheets/app/project-list.less b/services/web/public/stylesheets/app/project-list.less index 88442147f2..d3745854c3 100644 --- a/services/web/public/stylesheets/app/project-list.less +++ b/services/web/public/stylesheets/app/project-list.less @@ -367,7 +367,7 @@ ul.project-list { border-bottom-left-radius: 0; } - .ol-label { + .v1-label { margin-right: 11px; margin-left: 5px; padding: 2px 3px 1px; From 5ee52408e57b10d2f0899f0287f1952fe9b6abef Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 16:16:25 +0000 Subject: [PATCH 22/58] Inject v1 flag into view model --- .../web/app/coffee/Features/Project/ProjectController.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index ac28dcdf4c..e441ce6ca1 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -144,6 +144,7 @@ module.exports = ProjectController = timer = new metrics.Timer("project-list") user_id = AuthenticationController.getLoggedInUserId(req) currentUser = AuthenticationController.getSessionUser(req) + isV1 = Settings.brandPrefix == "ol-" async.parallel { tags: (cb)-> TagsHandler.getAllTags user_id, cb @@ -152,7 +153,7 @@ module.exports = ProjectController = projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb olProjects: (cb) -> - if Settings.brandPrefix == "ol-" + if isV1 OlProjectGetter.findAllUsersProjects user_id, cb else cb() @@ -181,6 +182,7 @@ module.exports = ProjectController = notifications: notifications or [] user: user hasSubscription: results.hasSubscription[0] + isV1: isV1 } if Settings?.algolia?.app_id? and Settings?.algolia?.read_only_api_key? From c1b3cc3a69ad8537ad5f929267e573c0a72b9468 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 30 Oct 2017 16:16:39 +0000 Subject: [PATCH 23/58] Add v1 filter --- services/web/app/views/project/list/side-bar.pug | 3 +++ .../web/public/coffee/main/project-list/project-list.coffee | 3 +++ 2 files changed, 6 insertions(+) diff --git a/services/web/app/views/project/list/side-bar.pug b/services/web/app/views/project/list/side-bar.pug index fe053f0019..33be0f5378 100644 --- a/services/web/app/views/project/list/side-bar.pug +++ b/services/web/app/views/project/list/side-bar.pug @@ -45,6 +45,9 @@ a(href) #{translate("shared_with_you")} li(ng-class="{active: (filter == 'archived')}", ng-click="filterProjects('archived')") a(href) #{translate("deleted_projects")} + if isV1 + li(ng-class="{active: (filter == 'v1')}", ng-click="filterProjects('v1')") + a(href) #{translate("v1_projects")} li.separator h2 #{translate("folders")} li.tag( diff --git a/services/web/public/coffee/main/project-list/project-list.coffee b/services/web/public/coffee/main/project-list/project-list.coffee index 335f46c62d..1d81504c74 100644 --- a/services/web/public/coffee/main/project-list/project-list.coffee +++ b/services/web/public/coffee/main/project-list/project-list.coffee @@ -133,6 +133,9 @@ define [ if project.archived visible = false + if $scope.filter == "v1" and !project.isV1Project + visible = false + if visible $scope.visibleProjects.push project else From 020e8ab8c488661a0c24bce87b9df42d7875aa98 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 31 Oct 2017 09:38:55 +0000 Subject: [PATCH 24/58] Change wording to v1 --- .../web/app/coffee/Features/Project/ProjectController.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index e441ce6ca1..f8c0676938 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -152,7 +152,7 @@ module.exports = ProjectController = NotificationsHandler.getUserNotifications user_id, cb projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb - olProjects: (cb) -> + v1Projects: (cb) -> if isV1 OlProjectGetter.findAllUsersProjects user_id, cb else @@ -170,7 +170,7 @@ module.exports = ProjectController = notifications = require("underscore").map results.notifications, (notification)-> notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts) return notification - projects = ProjectController._buildProjectList results.projects, results.olProjects?.projects + projects = ProjectController._buildProjectList results.projects, results.v1Projects?.projects user = results.user ProjectController._injectProjectOwners projects, (error, projects) -> return next(error) if error? From ec64d1fab9dd744afb0dba6c9ccd6c398d12e53a Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 31 Oct 2017 12:37:18 +0000 Subject: [PATCH 25/58] Combine tags with v1 tags --- .../web/app/coffee/Features/Project/ProjectController.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index f8c0676938..2aeddd1ab6 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -166,7 +166,8 @@ module.exports = ProjectController = logger.err err:err, "error getting data for project list page" return next(err) logger.log results:results, user_id:user_id, "rendering project list" - tags = results.tags[0] + v1Tags = results.v1Projects?.tags or [] + tags = results.tags[0].concat(v1Tags) notifications = require("underscore").map results.notifications, (notification)-> notification.html = req.i18n.translate(notification.templateKey, notification.messageOpts) return notification From 35883b6b27b57f5851118acf2fcf8e593dc93e59 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 31 Oct 2017 14:09:54 +0000 Subject: [PATCH 26/58] Extract V1 badge styles to file --- services/web/app/views/project/list/ol-item.pug | 2 +- services/web/public/stylesheets/_style_includes.less | 1 + services/web/public/stylesheets/app/project-list.less | 7 +++---- services/web/public/stylesheets/app/v1-badge.less | 9 +++++++++ 4 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 services/web/public/stylesheets/app/v1-badge.less diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/ol-item.pug index 49a6dd01f2..67648b9c7b 100644 --- a/services/web/app/views/project/list/ol-item.pug +++ b/services/web/app/views/project/list/ol-item.pug @@ -1,5 +1,5 @@ .col-xs-8 - span.label.label-default.v1-label V1 + span.v1-badge span a.projectName( href=settings.overleaf.host + "/{{project.id}}" diff --git a/services/web/public/stylesheets/_style_includes.less b/services/web/public/stylesheets/_style_includes.less index a5c7589ef0..54539a4cb4 100644 --- a/services/web/public/stylesheets/_style_includes.less +++ b/services/web/public/stylesheets/_style_includes.less @@ -78,6 +78,7 @@ @import "app/invite.less"; @import "app/review-features-page.less"; @import "app/error-pages.less"; +@import "app/v1-badge.less"; @import "../js/libs/pdfListView/TextLayer.css"; @import "../js/libs/pdfListView/AnnotationsLayer.css"; diff --git a/services/web/public/stylesheets/app/project-list.less b/services/web/public/stylesheets/app/project-list.less index d3745854c3..1ca170ff89 100644 --- a/services/web/public/stylesheets/app/project-list.less +++ b/services/web/public/stylesheets/app/project-list.less @@ -367,10 +367,9 @@ ul.project-list { border-bottom-left-radius: 0; } - .v1-label { - margin-right: 11px; - margin-left: 5px; - padding: 2px 3px 1px; + .v1-badge { + margin-right: 9px; + margin-left: 7px; } } i.tablesort { diff --git a/services/web/public/stylesheets/app/v1-badge.less b/services/web/public/stylesheets/app/v1-badge.less new file mode 100644 index 0000000000..0c64ee9e6b --- /dev/null +++ b/services/web/public/stylesheets/app/v1-badge.less @@ -0,0 +1,9 @@ +.v1-badge { + &:extend(.label); + &:extend(.label-default); + padding: 2px 3px 1px; + margin: 0 4px; + &:before { + content: "V1"; + } +} \ No newline at end of file From d43863d438fc87f9dd83197d0ec13879de2f7fa1 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 31 Oct 2017 14:10:40 +0000 Subject: [PATCH 27/58] Add V1 badge to tags from V1 --- services/web/app/views/project/list/side-bar.pug | 1 + 1 file changed, 1 insertion(+) diff --git a/services/web/app/views/project/list/side-bar.pug b/services/web/app/views/project/list/side-bar.pug index 33be0f5378..4888cfdc70 100644 --- a/services/web/app/views/project/list/side-bar.pug +++ b/services/web/app/views/project/list/side-bar.pug @@ -65,6 +65,7 @@ ) span.name {{tag.name}} span.subdued ({{tag.project_ids.length}}) + span.v1-badge(ng-if="tag.isV1", ng-cloak) span.dropdown.tag-menu(dropdown) a.dropdown-toggle( href="#", From bb8f80c1e4a2a5a2830eee45428f2e3277336915 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 31 Oct 2017 14:28:42 +0000 Subject: [PATCH 28/58] Tweak v1 badge styles --- services/web/public/stylesheets/app/v1-badge.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/web/public/stylesheets/app/v1-badge.less b/services/web/public/stylesheets/app/v1-badge.less index 0c64ee9e6b..c2ca96ec73 100644 --- a/services/web/public/stylesheets/app/v1-badge.less +++ b/services/web/public/stylesheets/app/v1-badge.less @@ -1,8 +1,9 @@ .v1-badge { &:extend(.label); &:extend(.label-default); + vertical-align: 11%; padding: 2px 3px 1px; - margin: 0 4px; + margin: 0 6px; &:before { content: "V1"; } From 87352610225949792dd400d5f0fefd1694886c94 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 1 Nov 2017 14:01:06 +0000 Subject: [PATCH 29/58] Extract V1 projects fetch to integration module OlProjectGetter now just detects if integration module is loaded and proxies to integration module. If module not loaded, it just bails --- .../Features/Project/OlProjectGetter.coffee | 36 +++++++++---------- .../Features/Project/ProjectController.coffee | 5 +-- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee b/services/web/app/coffee/Features/Project/OlProjectGetter.coffee index 3f47c0dac4..ab3187a636 100644 --- a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee +++ b/services/web/app/coffee/Features/Project/OlProjectGetter.coffee @@ -1,24 +1,22 @@ -request = require 'request' -settings = require 'settings-sharelatex' +fs = require 'fs' +path = require 'path' logger = require 'logger-sharelatex' -Errors = require '../Errors/Errors' -oAuthRequest = require '../../../../modules/overleaf-integration-web-module/app/coffee/oauth/OAuthRequest' -makeRequest = (opts, callback) -> - if settings.apis?.olProjects?.url? - urlPath = opts.url - opts.url = "#{settings.apis.olProjects.url}#{urlPath}" - request opts, callback - else - callback(new Errors.ServiceNotConfiguredError('OL Projects service not configured')) +INTEGRATION_MODULE_PATH = path.resolve(__dirname, '../../../../modules/overleaf-integration-web-module') module.exports = OlProjectGetter = + integrationModuleExists: (callback = (error, stats) ->) -> + fs.stat INTEGRATION_MODULE_PATH, (error, stats) -> + if error? or !stats.isDirectory() + return callback(false) + return callback(true) + findAllUsersProjects: (userId, callback = (error, projects) ->) -> - oAuthRequest userId, { - url: "#{settings.overleaf.host}/api/v1/sharelatex/docs" - method: 'GET' - json: true - }, (error, docs) -> - return callback(error) if error? - logger.log {userId, docs}, "got projects from OL" - callback(null, docs) \ No newline at end of file + OlProjectGetter.integrationModuleExists (exists) -> + if exists + logger.log {exists}, "integration module does exist, loading V1 projects" + V1ProjectListGetter = require(path.join(INTEGRATION_MODULE_PATH, 'app/coffee/ProjectList/ProjectListGetter')) + V1ProjectListGetter.findAllUsersProjects(userId, callback) + else + logger.log {exists}, "integration modules doesn't exists, not loading V1 projects" + return callback() diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 2aeddd1ab6..e067d7f9e7 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -153,10 +153,7 @@ module.exports = ProjectController = projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb v1Projects: (cb) -> - if isV1 - OlProjectGetter.findAllUsersProjects user_id, cb - else - cb() + OlProjectGetter.findAllUsersProjects user_id, cb hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb user: (cb) -> From 8df31590a9087b875bfd9d28b4dd9591fe546fcd Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 1 Nov 2017 14:10:12 +0000 Subject: [PATCH 30/58] Switch V1 naming instead of OL --- .../coffee/Features/Project/ProjectController.coffee | 12 ++++++------ ...OlProjectGetter.coffee => V1ProjectGetter.coffee} | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) rename services/web/app/coffee/Features/Project/{OlProjectGetter.coffee => V1ProjectGetter.coffee} (90%) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index e067d7f9e7..3b2099f923 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -19,7 +19,7 @@ fs = require "fs" InactiveProjectManager = require("../InactiveData/InactiveProjectManager") ProjectUpdateHandler = require("./ProjectUpdateHandler") ProjectGetter = require("./ProjectGetter") -OlProjectGetter = require("./OlProjectGetter") +V1ProjectGetter = require("./V1ProjectGetter") PrivilegeLevels = require("../Authorization/PrivilegeLevels") AuthenticationController = require("../Authentication/AuthenticationController") PackageVersions = require("../../infrastructure/PackageVersions") @@ -153,7 +153,7 @@ module.exports = ProjectController = projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb v1Projects: (cb) -> - OlProjectGetter.findAllUsersProjects user_id, cb + V1ProjectGetter.findAllUsersProjects user_id, cb hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb user: (cb) -> @@ -398,7 +398,7 @@ module.exports = ProjectController = showLinkSharingOnboarding: showLinkSharingOnboarding timer.done() - _buildProjectList: (allProjects, olProjects = [])-> + _buildProjectList: (allProjects, v1Projects = [])-> {owned, readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly} = allProjects projects = [] for project in owned @@ -408,8 +408,8 @@ module.exports = ProjectController = projects.push ProjectController._buildProjectViewModel(project, "readWrite", Sources.INVITE) for project in readOnly projects.push ProjectController._buildProjectViewModel(project, "readOnly", Sources.INVITE) - for project in olProjects - projects.push ProjectController._buildOlProjectViwModel(project) + for project in v1Projects + projects.push ProjectController._buildV1ProjectViewModel(project) # Token-access # Only add these projects if they're not already present, this gives us cascading access # from 'owner' => 'token-read-only' @@ -438,7 +438,7 @@ module.exports = ProjectController = } return model - _buildOlProjectViewModel: (project) -> + _buildV1ProjectViewModel: (project) -> { id: project.id name: project.title diff --git a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee similarity index 90% rename from services/web/app/coffee/Features/Project/OlProjectGetter.coffee rename to services/web/app/coffee/Features/Project/V1ProjectGetter.coffee index ab3187a636..ca957e2804 100644 --- a/services/web/app/coffee/Features/Project/OlProjectGetter.coffee +++ b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee @@ -4,7 +4,7 @@ logger = require 'logger-sharelatex' INTEGRATION_MODULE_PATH = path.resolve(__dirname, '../../../../modules/overleaf-integration-web-module') -module.exports = OlProjectGetter = +module.exports = V1ProjectGetter = integrationModuleExists: (callback = (error, stats) ->) -> fs.stat INTEGRATION_MODULE_PATH, (error, stats) -> if error? or !stats.isDirectory() @@ -12,7 +12,7 @@ module.exports = OlProjectGetter = return callback(true) findAllUsersProjects: (userId, callback = (error, projects) ->) -> - OlProjectGetter.integrationModuleExists (exists) -> + V1ProjectGetter.integrationModuleExists (exists) -> if exists logger.log {exists}, "integration module does exist, loading V1 projects" V1ProjectListGetter = require(path.join(INTEGRATION_MODULE_PATH, 'app/coffee/ProjectList/ProjectListGetter')) From 072448280838f04bfbabd3f5cde0663628bda040 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 1 Nov 2017 14:12:44 +0000 Subject: [PATCH 31/58] Don't use brand prefix setting to mark v1 --- .../web/app/coffee/Features/Project/ProjectController.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 3b2099f923..944ac04a2e 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -144,7 +144,6 @@ module.exports = ProjectController = timer = new metrics.Timer("project-list") user_id = AuthenticationController.getLoggedInUserId(req) currentUser = AuthenticationController.getSessionUser(req) - isV1 = Settings.brandPrefix == "ol-" async.parallel { tags: (cb)-> TagsHandler.getAllTags user_id, cb @@ -180,7 +179,7 @@ module.exports = ProjectController = notifications: notifications or [] user: user hasSubscription: results.hasSubscription[0] - isV1: isV1 + isV1: results.v1Projects? } if Settings?.algolia?.app_id? and Settings?.algolia?.read_only_api_key? From 9bf74f29bdee44c8fe880197d28bd8c60153df98 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 1 Nov 2017 14:13:50 +0000 Subject: [PATCH 32/58] Improve naming --- .../web/app/coffee/Features/Project/ProjectController.coffee | 2 +- services/web/app/views/project/list/side-bar.pug | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 944ac04a2e..5b5668ec31 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -179,7 +179,7 @@ module.exports = ProjectController = notifications: notifications or [] user: user hasSubscription: results.hasSubscription[0] - isV1: results.v1Projects? + isShowingV1Projects: results.v1Projects? } if Settings?.algolia?.app_id? and Settings?.algolia?.read_only_api_key? diff --git a/services/web/app/views/project/list/side-bar.pug b/services/web/app/views/project/list/side-bar.pug index 4888cfdc70..69bfecd50a 100644 --- a/services/web/app/views/project/list/side-bar.pug +++ b/services/web/app/views/project/list/side-bar.pug @@ -45,7 +45,7 @@ a(href) #{translate("shared_with_you")} li(ng-class="{active: (filter == 'archived')}", ng-click="filterProjects('archived')") a(href) #{translate("deleted_projects")} - if isV1 + if isShowingV1Projects li(ng-class="{active: (filter == 'v1')}", ng-click="filterProjects('v1')") a(href) #{translate("v1_projects")} li.separator @@ -65,7 +65,7 @@ ) span.name {{tag.name}} span.subdued ({{tag.project_ids.length}}) - span.v1-badge(ng-if="tag.isV1", ng-cloak) + span.v1-badge(ng-if="tag.isShowingV1Projects", ng-cloak) span.dropdown.tag-menu(dropdown) a.dropdown-toggle( href="#", From fff6873e1072c4bfd0d3cb0afa5642ed96d6ae6b Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 10:18:01 +0000 Subject: [PATCH 33/58] Add tests for getting V1 projects --- .../Project/ProjectControllerTests.coffee | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 498090f790..7cd43f0174 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -54,6 +54,8 @@ describe "ProjectController", -> @ProjectGetter = findAllUsersProjects: sinon.stub() getProject: sinon.stub() + @V1ProjectGetter = + findAllUsersProjects: sinon.stub() @AuthenticationController = getLoggedInUser: sinon.stub().callsArgWith(1, null, @user) getLoggedInUserId: sinon.stub().returns(@user._id) @@ -89,6 +91,7 @@ describe "ProjectController", -> "./ProjectUpdateHandler":@ProjectUpdateHandler "../ReferencesSearch/ReferencesSearchHandler": @ReferencesSearchHandler "./ProjectGetter": @ProjectGetter + './V1ProjectGetter': @V1ProjectGetter '../Authentication/AuthenticationController': @AuthenticationController "../Analytics/AnalyticsManager": @AnalyticsManager "../TokenAccess/TokenAccessHandler": @TokenAccessHandler @@ -263,6 +266,7 @@ describe "ProjectController", -> @TagsHandler.getAllTags.callsArgWith(1, null, @tags, {}) @NotificationsHandler.getUserNotifications = sinon.stub().callsArgWith(1, null, @notifications, {}) @ProjectGetter.findAllUsersProjects.callsArgWith(2, null, @allProjects) + @V1ProjectGetter.findAllUsersProjects.callsArg(1) # Without integration module cb returns without args it "should render the project/list page", (done)-> @res.render = (pageName, opts)=> @@ -278,7 +282,7 @@ describe "ProjectController", -> it "should send the projects", (done)-> @res.render = (pageName, opts)=> - opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length + @tokenReadAndWrite.length + @tokenReadOnly.length) + opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length) done() @ProjectController.projectListPage @req, @res @@ -295,6 +299,36 @@ describe "ProjectController", -> done() @ProjectController.projectListPage @req, @res + describe 'with overleaf-integration-web-module', -> + beforeEach -> + @V1Response = + projects: [ + { id: '123mockV1Id', title: 'mock title', updated_at: 1509616411, removed: false, archived: false } + { id: '456mockV1Id', title: 'mock title 2', updated_at: 1509616411, removed: true, archived: false } + ], + tags: [ + { name: 'mock tag', project_ids: ['123mockV1Id'] } + ] + @V1ProjectGetter.findAllUsersProjects.callsArgWith(1, null, @V1Response) + + it 'should include V1 projects', (done) -> + @res.render = (pageName, opts) => + opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length + @V1Response.projects.length) + done() + @ProjectController.projectListPage @req, @res + + it 'should include V1 tags', (done) -> + @res.render = (pageName, opts) => + opts.tags.length.should.equal (@tags.length + @V1Response.tags.length) + done() + @ProjectController.projectListPage @req, @res + + it 'should have isShowingV1Projects flag', (done) -> + @res.render = (pageName, opts) => + opts.isShowingV1Projects.should.equal true + done() + @ProjectController.projectListPage @req, @res + describe "projectListPage with duplicate projects", -> beforeEach -> From 24166af90e54c73b9e70b7948847cef6315a4a96 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 11:59:05 +0000 Subject: [PATCH 34/58] Add tests for V1ProjectGetter --- .../Project/V1ProjectGetterTests.coffee | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee diff --git a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee new file mode 100644 index 0000000000..e2851eecdb --- /dev/null +++ b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee @@ -0,0 +1,47 @@ +sinon = require('sinon') +should = require('chai').should() +SandboxedModule = require('sandboxed-module') + +modulePath = '../../../../app/js/Features/Project/V1ProjectGetter.js' + +describe 'V1ProjectGetter', -> + beforeEach -> + @fs = + stat: sinon.stub() + @path = + resolve: sinon.stub().returns('path/to/integration/module') + join: sinon.stub().returns('path/to/file/in/integration/module') + @IntegrationProjectListGetter = + findAllUsersProjects: sinon.stub() + @V1ProjectGetter = SandboxedModule.require modulePath, requires: + 'fs': @fs + 'path': @path + 'logger-sharelatex': log: -> + 'path/to/file/in/integration/module': @IntegrationProjectListGetter + @userId = 123 + @callback = sinon.stub() + + describe 'without overleaf-integration-web-module', -> + beforeEach -> + # Mock not finding integration module + @fs.stat.yields({ code: 'mock-ENOENT-error' }) + # Call method + @V1ProjectGetter.findAllUsersProjects @userId, @callback + + it 'should call the callback with no arguments', -> + @callback.calledWith().should.equal true + + describe 'with overleaf-integration-web-module', -> + beforeEach -> + # Mock finding integration module + @fs.stat.yields(null, isDirectory: sinon.stub().returns(true)) + # Mock integration module response + @IntegrationProjectListGetter.findAllUsersProjects.yields(null, @response = { + projects: [{ id: '123mockV1Id', title: 'mock title' }] + tags: [{ name: 'mock tag', project_ids: ['123mockV1Id'] }] + }) + # Call method + @V1ProjectGetter.findAllUsersProjects @userId, @callback + + it 'should call the callback with all the projects and tags', -> + @callback.calledWith(null, @response).should.equal true From 9a96f070d56bbb862e9199a8c8346e3583f6656b Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 12:09:47 +0000 Subject: [PATCH 35/58] Add assertions for correctly mapping V1 properties --- .../UnitTests/coffee/Project/ProjectControllerTests.coffee | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 7cd43f0174..2392c4476b 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -314,6 +314,13 @@ describe "ProjectController", -> it 'should include V1 projects', (done) -> @res.render = (pageName, opts) => opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length + @V1Response.projects.length) + opts.projects.forEach (p) -> + # Check properties correctly mapped from V1 + expect(p).to.have.property 'id' + expect(p).to.have.property 'name' + expect(p).to.have.property 'lastUpdated' + expect(p).to.have.property 'accessLevel' + expect(p).to.have.property 'archived' done() @ProjectController.projectListPage @req, @res From 56634bdb49873550fa3e4f2c9b5e6d7bc25022f7 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 12:16:11 +0000 Subject: [PATCH 36/58] Add assertions for tag properties --- .../UnitTests/coffee/Project/ProjectControllerTests.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 2392c4476b..b53d36cd6f 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -327,6 +327,9 @@ describe "ProjectController", -> it 'should include V1 tags', (done) -> @res.render = (pageName, opts) => opts.tags.length.should.equal (@tags.length + @V1Response.tags.length) + opts.tags.forEach (t) -> + expect(t).to.have.property 'name' + expect(t).to.have.property 'project_ids' done() @ProjectController.projectListPage @req, @res From 08fd092f7c72d17c7a7a88560253666d5e0d183e Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 12:24:26 +0000 Subject: [PATCH 37/58] Rename v1 list item template for consistency --- services/web/app/views/project/list/project-list.pug | 2 +- .../web/app/views/project/list/{ol-item.pug => v1-item.pug} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename services/web/app/views/project/list/{ol-item.pug => v1-item.pug} (100%) diff --git a/services/web/app/views/project/list/project-list.pug b/services/web/app/views/project/list/project-list.pug index 260cc387f0..806e2d97e8 100644 --- a/services/web/app/views/project/list/project-list.pug +++ b/services/web/app/views/project/list/project-list.pug @@ -150,7 +150,7 @@ .row( ng-if="project.isV1Project" ) - include ./ol-item + include ./v1-item li( ng-if="visibleProjects.length == 0", ng-cloak diff --git a/services/web/app/views/project/list/ol-item.pug b/services/web/app/views/project/list/v1-item.pug similarity index 100% rename from services/web/app/views/project/list/ol-item.pug rename to services/web/app/views/project/list/v1-item.pug From 4b25525e9d5341d4fd47e151d727d4e7fe0dcd25 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 12:24:42 +0000 Subject: [PATCH 38/58] Add aria labels to V1 badges --- services/web/app/views/project/list/side-bar.pug | 6 +++++- services/web/app/views/project/list/v1-item.pug | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/project/list/side-bar.pug b/services/web/app/views/project/list/side-bar.pug index 69bfecd50a..1cb41d6119 100644 --- a/services/web/app/views/project/list/side-bar.pug +++ b/services/web/app/views/project/list/side-bar.pug @@ -65,7 +65,11 @@ ) span.name {{tag.name}} span.subdued ({{tag.project_ids.length}}) - span.v1-badge(ng-if="tag.isShowingV1Projects", ng-cloak) + span.v1-badge( + ng-if="tag.isShowingV1Projects", + ng-cloak, + aria-label=translate("v1_badge") + ) span.dropdown.tag-menu(dropdown) a.dropdown-toggle( href="#", diff --git a/services/web/app/views/project/list/v1-item.pug b/services/web/app/views/project/list/v1-item.pug index 67648b9c7b..5631788aeb 100644 --- a/services/web/app/views/project/list/v1-item.pug +++ b/services/web/app/views/project/list/v1-item.pug @@ -1,5 +1,5 @@ .col-xs-8 - span.v1-badge + span.v1-badge(aria-label=translate("v1_badge")) span a.projectName( href=settings.overleaf.host + "/{{project.id}}" From 4b2e22c257b7866f9d2ee588122951e3390050fc Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 2 Nov 2017 12:34:28 +0000 Subject: [PATCH 39/58] Remove duplicate dependency --- .../web/app/coffee/Features/Project/ProjectController.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 5b5668ec31..30d403b189 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -1,7 +1,6 @@ async = require("async") moment = require('moment') logger = require("logger-sharelatex") -Settings = require('settings-sharelatex') projectDeleter = require("./ProjectDeleter") projectDuplicator = require("./ProjectDuplicator") projectCreationHandler = require("./ProjectCreationHandler") From 3bc48a7a05bfa0cc57d45bd2ba086d56089a1031 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 3 Nov 2017 09:30:58 +0000 Subject: [PATCH 40/58] Switch to date builtin instead of moment --- .../web/app/coffee/Features/Project/ProjectController.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 30d403b189..877a0ae634 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -1,5 +1,4 @@ async = require("async") -moment = require('moment') logger = require("logger-sharelatex") projectDeleter = require("./ProjectDeleter") projectDuplicator = require("./ProjectDuplicator") @@ -440,7 +439,7 @@ module.exports = ProjectController = { id: project.id name: project.title - lastUpdated: moment.unix(project.updated_at) + lastUpdated: new Date(project.updated_at * 1000) # Convert from epoch accessLevel: "readOnly", archived: project.removed || project.archived isV1Project: true From e32406a4c4eb011121da736afbfb9b29858b6d6b Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 3 Nov 2017 10:16:03 +0000 Subject: [PATCH 41/58] Dynamically monkey patch impl to check integration once instead of each request --- .../Features/Project/V1ProjectGetter.coffee | 29 +++++++++---------- .../Project/V1ProjectGetterTests.coffee | 27 ++++++++++------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee index ca957e2804..26efa45312 100644 --- a/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee +++ b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee @@ -4,19 +4,18 @@ logger = require 'logger-sharelatex' INTEGRATION_MODULE_PATH = path.resolve(__dirname, '../../../../modules/overleaf-integration-web-module') -module.exports = V1ProjectGetter = - integrationModuleExists: (callback = (error, stats) ->) -> - fs.stat INTEGRATION_MODULE_PATH, (error, stats) -> - if error? or !stats.isDirectory() - return callback(false) - return callback(true) - +V1ProjectGetter = + # Default implementation is a no-op findAllUsersProjects: (userId, callback = (error, projects) ->) -> - V1ProjectGetter.integrationModuleExists (exists) -> - if exists - logger.log {exists}, "integration module does exist, loading V1 projects" - V1ProjectListGetter = require(path.join(INTEGRATION_MODULE_PATH, 'app/coffee/ProjectList/ProjectListGetter')) - V1ProjectListGetter.findAllUsersProjects(userId, callback) - else - logger.log {exists}, "integration modules doesn't exists, not loading V1 projects" - return callback() + logger.log {}, "integration modules doesn't exist, not loading V1 projects" + return callback() + +fs.stat INTEGRATION_MODULE_PATH, (error, stats) -> + return if error? or !stats.isDirectory() + logger.log {isDirectory: stats.isDirectory}, "integration module does exist, loading V1 projects" + # Monkey patch impl to actually fetch projects + V1ProjectGetter.findAllUsersProjects = (userId, callback = (error, projects) ->) -> + IntegrationProjectListGetter = require(path.join(INTEGRATION_MODULE_PATH, 'app/coffee/ProjectList/ProjectListGetter')) + IntegrationProjectListGetter.findAllUsersProjects(userId, callback) + +module.exports = V1ProjectGetter \ No newline at end of file diff --git a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee index e2851eecdb..a7d2e9f326 100644 --- a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee @@ -6,25 +6,24 @@ modulePath = '../../../../app/js/Features/Project/V1ProjectGetter.js' describe 'V1ProjectGetter', -> beforeEach -> - @fs = - stat: sinon.stub() @path = resolve: sinon.stub().returns('path/to/integration/module') join: sinon.stub().returns('path/to/file/in/integration/module') @IntegrationProjectListGetter = findAllUsersProjects: sinon.stub() - @V1ProjectGetter = SandboxedModule.require modulePath, requires: - 'fs': @fs - 'path': @path - 'logger-sharelatex': log: -> - 'path/to/file/in/integration/module': @IntegrationProjectListGetter @userId = 123 @callback = sinon.stub() describe 'without overleaf-integration-web-module', -> beforeEach -> - # Mock not finding integration module - @fs.stat.yields({ code: 'mock-ENOENT-error' }) + @fs = + stat: sinon.stub().yields({code: 'mock-ENOENT-error'}) + @V1ProjectGetter = SandboxedModule.require modulePath, requires: + # Mock not finding integration module + 'fs': @fs + 'path': @path + 'logger-sharelatex': log: -> + 'path/to/file/in/integration/module': @IntegrationProjectListGetter # Call method @V1ProjectGetter.findAllUsersProjects @userId, @callback @@ -33,8 +32,14 @@ describe 'V1ProjectGetter', -> describe 'with overleaf-integration-web-module', -> beforeEach -> - # Mock finding integration module - @fs.stat.yields(null, isDirectory: sinon.stub().returns(true)) + @fs = + stat: sinon.stub().yields(null, isDirectory: sinon.stub().returns(true)) + @V1ProjectGetter = SandboxedModule.require modulePath, requires: + # Mock finding integration module + 'fs': @fs + 'path': @path + 'logger-sharelatex': log: -> + 'path/to/file/in/integration/module': @IntegrationProjectListGetter # Mock integration module response @IntegrationProjectListGetter.findAllUsersProjects.yields(null, @response = { projects: [{ id: '123mockV1Id', title: 'mock title' }] From 6822a0d838b65b79904abd678d2aea75e2862091 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 3 Nov 2017 10:17:55 +0000 Subject: [PATCH 42/58] Add assertions for integration module call --- .../test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee index a7d2e9f326..c97574550b 100644 --- a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee @@ -29,6 +29,7 @@ describe 'V1ProjectGetter', -> it 'should call the callback with no arguments', -> @callback.calledWith().should.equal true + @IntegrationProjectListGetter.findAllUsersProjects.called.should.equal false describe 'with overleaf-integration-web-module', -> beforeEach -> @@ -50,3 +51,4 @@ describe 'V1ProjectGetter', -> it 'should call the callback with all the projects and tags', -> @callback.calledWith(null, @response).should.equal true + @IntegrationProjectListGetter.findAllUsersProjects.called.should.equal true From c629f27db9e012b64f38fd638873a32d20aa5279 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 3 Nov 2017 10:20:48 +0000 Subject: [PATCH 43/58] Remove unneeded moment dep --- services/web/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/services/web/package.json b/services/web/package.json index b4dd29395d..e831d929e1 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -40,7 +40,6 @@ "metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.7.1", "mimelib": "0.2.14", "mocha": "1.17.1", - "moment": "^2.18.1", "mongojs": "2.4.0", "mongoose": "4.11.4", "multer": "^0.1.8", From d5cfd34bb72445fedede938fd9ae9964e01bb87d Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 3 Nov 2017 10:23:29 +0000 Subject: [PATCH 44/58] Log something useful --- services/web/app/coffee/Features/Project/V1ProjectGetter.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee index 26efa45312..b304429b2f 100644 --- a/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee +++ b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee @@ -12,7 +12,7 @@ V1ProjectGetter = fs.stat INTEGRATION_MODULE_PATH, (error, stats) -> return if error? or !stats.isDirectory() - logger.log {isDirectory: stats.isDirectory}, "integration module does exist, loading V1 projects" + logger.log {isDirectory: stats.isDirectory()}, "integration module does exist, loading V1 projects" # Monkey patch impl to actually fetch projects V1ProjectGetter.findAllUsersProjects = (userId, callback = (error, projects) ->) -> IntegrationProjectListGetter = require(path.join(INTEGRATION_MODULE_PATH, 'app/coffee/ProjectList/ProjectListGetter')) From d9c19ccdc4a28d8e095bac1c85fd0b3f9df39192 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Fri, 3 Nov 2017 10:30:48 +0000 Subject: [PATCH 45/58] Fix V1 tags not showing badge correctly --- services/web/app/views/project/list/side-bar.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/views/project/list/side-bar.pug b/services/web/app/views/project/list/side-bar.pug index 1cb41d6119..9fceb4cc86 100644 --- a/services/web/app/views/project/list/side-bar.pug +++ b/services/web/app/views/project/list/side-bar.pug @@ -66,7 +66,7 @@ span.name {{tag.name}} span.subdued ({{tag.project_ids.length}}) span.v1-badge( - ng-if="tag.isShowingV1Projects", + ng-if="tag.isV1", ng-cloak, aria-label=translate("v1_badge") ) From 47942816ae186be574ce186c3de4ba03ea25e908 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 14 Nov 2017 11:38:06 +0000 Subject: [PATCH 46/58] Include token based --- .../coffee/Project/ProjectControllerTests.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index b53d36cd6f..14b7fa3c99 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -282,7 +282,7 @@ describe "ProjectController", -> it "should send the projects", (done)-> @res.render = (pageName, opts)=> - opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length) + opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length + @tokenReadAndWrite.length + @tokenReadOnly.length) done() @ProjectController.projectListPage @req, @res @@ -313,7 +313,14 @@ describe "ProjectController", -> it 'should include V1 projects', (done) -> @res.render = (pageName, opts) => - opts.projects.length.should.equal (@projects.length + @collabertions.length + @readOnly.length + @V1Response.projects.length) + opts.projects.length.should.equal ( + @projects.length + + @collabertions.length + + @readOnly.length + + @tokenReadAndWrite.length + + @tokenReadOnly.length + + @V1Response.projects.length + ) opts.projects.forEach (p) -> # Check properties correctly mapped from V1 expect(p).to.have.property 'id' From 3eaf6c5d8e9991d56481076cd87bb23928af4985 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Tue, 14 Nov 2017 11:38:46 +0000 Subject: [PATCH 47/58] Stub V1 project getter --- .../test/UnitTests/coffee/Project/ProjectControllerTests.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 14b7fa3c99..2111abc085 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -389,6 +389,7 @@ describe "ProjectController", -> @TagsHandler.getAllTags.callsArgWith(1, null, @tags, {}) @NotificationsHandler.getUserNotifications = sinon.stub().callsArgWith(1, null, @notifications, {}) @ProjectGetter.findAllUsersProjects.callsArgWith(2, null, @allProjects) + @V1ProjectGetter.findAllUsersProjects.callsArg(1) # Without integration module cb returns without args it "should render the project/list page", (done)-> @res.render = (pageName, opts)=> From 621977c47c7fc860a263cb17e9c19bf178b42c6b Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 15 Nov 2017 15:54:47 +0000 Subject: [PATCH 48/58] Replace call to V1ProjectGetter with Module hook --- .../Features/Project/ProjectController.coffee | 5 +++-- .../coffee/Project/ProjectControllerTests.coffee | 15 ++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 877a0ae634..be3236747a 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -17,7 +17,6 @@ fs = require "fs" InactiveProjectManager = require("../InactiveData/InactiveProjectManager") ProjectUpdateHandler = require("./ProjectUpdateHandler") ProjectGetter = require("./ProjectGetter") -V1ProjectGetter = require("./V1ProjectGetter") PrivilegeLevels = require("../Authorization/PrivilegeLevels") AuthenticationController = require("../Authentication/AuthenticationController") PackageVersions = require("../../infrastructure/PackageVersions") @@ -25,6 +24,7 @@ AnalyticsManager = require "../Analytics/AnalyticsManager" Sources = require "../Authorization/Sources" TokenAccessHandler = require '../TokenAccess/TokenAccessHandler' CollaboratorsHandler = require '../Collaborators/CollaboratorsHandler' +Modules = require '../../infrastructure/Modules' crypto = require 'crypto' module.exports = ProjectController = @@ -150,7 +150,8 @@ module.exports = ProjectController = projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb v1Projects: (cb) -> - V1ProjectGetter.findAllUsersProjects user_id, cb + Modules.hooks.fire "findAllUsersProjects", user_id, (error, projects = []) -> + cb error, projects[0] # hooks.fire returns an array of results, only need first hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb user: (cb) -> diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 2111abc085..4236ffa37f 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -54,8 +54,6 @@ describe "ProjectController", -> @ProjectGetter = findAllUsersProjects: sinon.stub() getProject: sinon.stub() - @V1ProjectGetter = - findAllUsersProjects: sinon.stub() @AuthenticationController = getLoggedInUser: sinon.stub().callsArgWith(1, null, @user) getLoggedInUserId: sinon.stub().returns(@user._id) @@ -68,6 +66,9 @@ describe "ProjectController", -> protectTokens: sinon.stub() @CollaboratorsHandler = userIsTokenMember: sinon.stub().callsArgWith(2, null, false) + @Modules = + hooks: + fire: sinon.stub() @ProjectController = SandboxedModule.require modulePath, requires: "settings-sharelatex":@settings "logger-sharelatex": @@ -91,11 +92,11 @@ describe "ProjectController", -> "./ProjectUpdateHandler":@ProjectUpdateHandler "../ReferencesSearch/ReferencesSearchHandler": @ReferencesSearchHandler "./ProjectGetter": @ProjectGetter - './V1ProjectGetter': @V1ProjectGetter '../Authentication/AuthenticationController': @AuthenticationController "../Analytics/AnalyticsManager": @AnalyticsManager "../TokenAccess/TokenAccessHandler": @TokenAccessHandler "../Collaborators/CollaboratorsHandler": @CollaboratorsHandler + "../../infrastructure/Modules": @Modules @projectName = "£12321jkj9ujkljds" @req = @@ -266,7 +267,7 @@ describe "ProjectController", -> @TagsHandler.getAllTags.callsArgWith(1, null, @tags, {}) @NotificationsHandler.getUserNotifications = sinon.stub().callsArgWith(1, null, @notifications, {}) @ProjectGetter.findAllUsersProjects.callsArgWith(2, null, @allProjects) - @V1ProjectGetter.findAllUsersProjects.callsArg(1) # Without integration module cb returns without args + @Modules.hooks.fire.yields(undefined) # Without integration module hook, cb returns undefined it "should render the project/list page", (done)-> @res.render = (pageName, opts)=> @@ -299,7 +300,7 @@ describe "ProjectController", -> done() @ProjectController.projectListPage @req, @res - describe 'with overleaf-integration-web-module', -> + describe 'with overleaf-integration-web-module hook', -> beforeEach -> @V1Response = projects: [ @@ -309,7 +310,7 @@ describe "ProjectController", -> tags: [ { name: 'mock tag', project_ids: ['123mockV1Id'] } ] - @V1ProjectGetter.findAllUsersProjects.callsArgWith(1, null, @V1Response) + @Modules.hooks.fire.withArgs('findAllUsersProjects', @user._id).yields(null, [@V1Response]) # Need to wrap response in array, as multiple hooks could fire it 'should include V1 projects', (done) -> @res.render = (pageName, opts) => @@ -389,7 +390,7 @@ describe "ProjectController", -> @TagsHandler.getAllTags.callsArgWith(1, null, @tags, {}) @NotificationsHandler.getUserNotifications = sinon.stub().callsArgWith(1, null, @notifications, {}) @ProjectGetter.findAllUsersProjects.callsArgWith(2, null, @allProjects) - @V1ProjectGetter.findAllUsersProjects.callsArg(1) # Without integration module cb returns without args + @Modules.hooks.fire.withArgs('findAllUsersProjects', @user._id).yields(undefined) # Without integration module hook, cb returns undefined it "should render the project/list page", (done)-> @res.render = (pageName, opts)=> From 119be26989b6c188fa4982798dd627511ce33dff Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 15 Nov 2017 15:59:13 +0000 Subject: [PATCH 49/58] Remove unnecessary project getter Had bad assumption about whether ol-integration module would be available in filesystem, now replaced with Module hook --- .../Features/Project/V1ProjectGetter.coffee | 21 -------- .../Project/V1ProjectGetterTests.coffee | 54 ------------------- 2 files changed, 75 deletions(-) delete mode 100644 services/web/app/coffee/Features/Project/V1ProjectGetter.coffee delete mode 100644 services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee diff --git a/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee b/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee deleted file mode 100644 index b304429b2f..0000000000 --- a/services/web/app/coffee/Features/Project/V1ProjectGetter.coffee +++ /dev/null @@ -1,21 +0,0 @@ -fs = require 'fs' -path = require 'path' -logger = require 'logger-sharelatex' - -INTEGRATION_MODULE_PATH = path.resolve(__dirname, '../../../../modules/overleaf-integration-web-module') - -V1ProjectGetter = - # Default implementation is a no-op - findAllUsersProjects: (userId, callback = (error, projects) ->) -> - logger.log {}, "integration modules doesn't exist, not loading V1 projects" - return callback() - -fs.stat INTEGRATION_MODULE_PATH, (error, stats) -> - return if error? or !stats.isDirectory() - logger.log {isDirectory: stats.isDirectory()}, "integration module does exist, loading V1 projects" - # Monkey patch impl to actually fetch projects - V1ProjectGetter.findAllUsersProjects = (userId, callback = (error, projects) ->) -> - IntegrationProjectListGetter = require(path.join(INTEGRATION_MODULE_PATH, 'app/coffee/ProjectList/ProjectListGetter')) - IntegrationProjectListGetter.findAllUsersProjects(userId, callback) - -module.exports = V1ProjectGetter \ No newline at end of file diff --git a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee b/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee deleted file mode 100644 index c97574550b..0000000000 --- a/services/web/test/UnitTests/coffee/Project/V1ProjectGetterTests.coffee +++ /dev/null @@ -1,54 +0,0 @@ -sinon = require('sinon') -should = require('chai').should() -SandboxedModule = require('sandboxed-module') - -modulePath = '../../../../app/js/Features/Project/V1ProjectGetter.js' - -describe 'V1ProjectGetter', -> - beforeEach -> - @path = - resolve: sinon.stub().returns('path/to/integration/module') - join: sinon.stub().returns('path/to/file/in/integration/module') - @IntegrationProjectListGetter = - findAllUsersProjects: sinon.stub() - @userId = 123 - @callback = sinon.stub() - - describe 'without overleaf-integration-web-module', -> - beforeEach -> - @fs = - stat: sinon.stub().yields({code: 'mock-ENOENT-error'}) - @V1ProjectGetter = SandboxedModule.require modulePath, requires: - # Mock not finding integration module - 'fs': @fs - 'path': @path - 'logger-sharelatex': log: -> - 'path/to/file/in/integration/module': @IntegrationProjectListGetter - # Call method - @V1ProjectGetter.findAllUsersProjects @userId, @callback - - it 'should call the callback with no arguments', -> - @callback.calledWith().should.equal true - @IntegrationProjectListGetter.findAllUsersProjects.called.should.equal false - - describe 'with overleaf-integration-web-module', -> - beforeEach -> - @fs = - stat: sinon.stub().yields(null, isDirectory: sinon.stub().returns(true)) - @V1ProjectGetter = SandboxedModule.require modulePath, requires: - # Mock finding integration module - 'fs': @fs - 'path': @path - 'logger-sharelatex': log: -> - 'path/to/file/in/integration/module': @IntegrationProjectListGetter - # Mock integration module response - @IntegrationProjectListGetter.findAllUsersProjects.yields(null, @response = { - projects: [{ id: '123mockV1Id', title: 'mock title' }] - tags: [{ name: 'mock tag', project_ids: ['123mockV1Id'] }] - }) - # Call method - @V1ProjectGetter.findAllUsersProjects @userId, @callback - - it 'should call the callback with all the projects and tags', -> - @callback.calledWith(null, @response).should.equal true - @IntegrationProjectListGetter.findAllUsersProjects.called.should.equal true From 24ceaffd3a2f4efae435c84cea5c242c0516a27b Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 15 Nov 2017 16:28:41 +0000 Subject: [PATCH 50/58] Rename hook for clarity --- .../app/coffee/Features/Project/ProjectController.coffee | 2 +- .../UnitTests/coffee/Project/ProjectControllerTests.coffee | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index be3236747a..a4d8ab0274 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -150,7 +150,7 @@ module.exports = ProjectController = projects: (cb)-> ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb v1Projects: (cb) -> - Modules.hooks.fire "findAllUsersProjects", user_id, (error, projects = []) -> + Modules.hooks.fire "findAllV1Projects", user_id, (error, projects = []) -> cb error, projects[0] # hooks.fire returns an array of results, only need first hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 4236ffa37f..35176acd4b 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -267,7 +267,7 @@ describe "ProjectController", -> @TagsHandler.getAllTags.callsArgWith(1, null, @tags, {}) @NotificationsHandler.getUserNotifications = sinon.stub().callsArgWith(1, null, @notifications, {}) @ProjectGetter.findAllUsersProjects.callsArgWith(2, null, @allProjects) - @Modules.hooks.fire.yields(undefined) # Without integration module hook, cb returns undefined + @Modules.hooks.fire.withArgs('findAllV1Projects', @user._id).yields(undefined) # Without integration module hook, cb returns undefined it "should render the project/list page", (done)-> @res.render = (pageName, opts)=> @@ -310,7 +310,7 @@ describe "ProjectController", -> tags: [ { name: 'mock tag', project_ids: ['123mockV1Id'] } ] - @Modules.hooks.fire.withArgs('findAllUsersProjects', @user._id).yields(null, [@V1Response]) # Need to wrap response in array, as multiple hooks could fire + @Modules.hooks.fire.withArgs('findAllV1Projects', @user._id).yields(null, [@V1Response]) # Need to wrap response in array, as multiple hooks could fire it 'should include V1 projects', (done) -> @res.render = (pageName, opts) => @@ -390,7 +390,7 @@ describe "ProjectController", -> @TagsHandler.getAllTags.callsArgWith(1, null, @tags, {}) @NotificationsHandler.getUserNotifications = sinon.stub().callsArgWith(1, null, @notifications, {}) @ProjectGetter.findAllUsersProjects.callsArgWith(2, null, @allProjects) - @Modules.hooks.fire.withArgs('findAllUsersProjects', @user._id).yields(undefined) # Without integration module hook, cb returns undefined + @Modules.hooks.fire.withArgs('findAllV1Projects', @user._id).yields(undefined) # Without integration module hook, cb returns undefined it "should render the project/list page", (done)-> @res.render = (pageName, opts)=> From f3583b17021daeb65f19e197932c351b3edd8cc0 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 15 Nov 2017 17:19:37 +0000 Subject: [PATCH 51/58] Show warning message if V1 connection fails --- .../web/app/coffee/Features/Project/ProjectController.coffee | 5 ++++- services/web/app/views/project/list/project-list.pug | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index a4d8ab0274..bbff14d2a1 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -151,7 +151,9 @@ module.exports = ProjectController = ProjectGetter.findAllUsersProjects user_id, 'name lastUpdated publicAccesLevel archived owner_ref tokens', cb v1Projects: (cb) -> Modules.hooks.fire "findAllV1Projects", user_id, (error, projects = []) -> - cb error, projects[0] # hooks.fire returns an array of results, only need first + if error? and error.message == 'No V1 connection' + return cb(null, projects: [], tags: [], noConnection: true) + return cb(error, projects[0]) # hooks.fire returns an array of results, only need first hasSubscription: (cb)-> LimitationsManager.userHasSubscriptionOrIsGroupMember currentUser, cb user: (cb) -> @@ -179,6 +181,7 @@ module.exports = ProjectController = user: user hasSubscription: results.hasSubscription[0] isShowingV1Projects: results.v1Projects? + noV1Connection: results.v1Projects?.noConnection } if Settings?.algolia?.app_id? and Settings?.algolia?.read_only_api_key? diff --git a/services/web/app/views/project/list/project-list.pug b/services/web/app/views/project/list/project-list.pug index 806e2d97e8..0db4f49400 100644 --- a/services/web/app/views/project/list/project-list.pug +++ b/services/web/app/views/project/list/project-list.pug @@ -114,6 +114,10 @@ ) #{translate("delete_forever")} .row.row-spaced + if noV1Connection + .col-xs-12 + .alert.alert-warning No V1 Connection + .col-xs-12 .card.card-thin.project-list-card ul.list-unstyled.project-list.structured-list( From a63e40f03f658514706878b8ff10947dcdacb827 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Thu, 16 Nov 2017 17:11:39 +0000 Subject: [PATCH 52/58] Adjust vertical padding on V1 badge --- services/web/public/stylesheets/app/v1-badge.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/public/stylesheets/app/v1-badge.less b/services/web/public/stylesheets/app/v1-badge.less index c2ca96ec73..ced9d04c81 100644 --- a/services/web/public/stylesheets/app/v1-badge.less +++ b/services/web/public/stylesheets/app/v1-badge.less @@ -2,7 +2,7 @@ &:extend(.label); &:extend(.label-default); vertical-align: 11%; - padding: 2px 3px 1px; + padding: 1px 3px; margin: 0 6px; &:before { content: "V1"; From 029e3b155738ca07925b752a1c22eea0729a13b8 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 20 Nov 2017 12:25:09 +0000 Subject: [PATCH 53/58] fix the cancellation of spelling requests --- .../ide/editor/directives/aceEditor.coffee | 4 ++-- .../spell-check/SpellCheckManager.coffee | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 577a3a0e75..2b805ef996 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -35,7 +35,7 @@ define [ url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}" return url - App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics, preamble, $http) -> + App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics, preamble, $http, $q) -> monkeyPatchSearch($rootScope, $compile) return { @@ -97,7 +97,7 @@ define [ if scope.spellCheck # only enable spellcheck when explicitly required spellCheckCache = $cacheFactory("spellCheck-#{scope.name}", {capacity: 1000}) - spellCheckManager = new SpellCheckManager(scope, editor, element, spellCheckCache, $http) + spellCheckManager = new SpellCheckManager(scope, editor, element, spellCheckCache, $http, $q) undoManager = new UndoManager(scope, editor, element) highlightsManager = new HighlightsManager(scope, editor, element) cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee index 5d420a29b4..acbd636531 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee @@ -5,9 +5,9 @@ define [ Range = ace.require("ace/range").Range class SpellCheckManager - constructor: (@$scope, @editor, @element, @cache, @$http) -> + constructor: (@$scope, @editor, @element, @cache, @$http, @$q) -> $(document.body).append @element.find(".spell-check-menu") - + @inProgressRequest = null @updatedLines = [] @highlightedWordManager = new HighlightedWordManager(@editor) @@ -23,8 +23,8 @@ define [ @editor.on "changeSession", (e) => @highlightedWordManager.reset() - # if @inProgressRequest? - # @inProgressRequest.abort() + if @inProgressRequest? + @inProgressRequest.abort() if @$scope.spellCheckEnabled and @$scope.spellCheckLanguage and @$scope.spellCheckLanguage != "" @runSpellCheckSoon(200) @@ -235,11 +235,18 @@ define [ apiRequest: (endpoint, data, callback = (error, result) ->)-> data.token = window.user.id data._csrf = window.csrfToken - @$http.post("/spelling" + endpoint, data) + # use angular timeout option to cancel request if doc is changed + requestHandler = @$q.defer() + options = {timeout: requestHandler.promise} + httpRequest = @$http.post("/spelling" + endpoint, data, options) .then (response) => callback(null, response.data) .catch (response) => callback(new Error('api failure')) + # provide a method to cancel the request + abortRequest = () -> + requestHandler.resolve() + return { abort: abortRequest } blacklistedCommandRegex: /// \\ # initial backslash From 5bb46a930a3775bb3c2a7be9534764f27b69098a Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Mon, 20 Nov 2017 15:55:00 +0000 Subject: [PATCH 54/58] Check presence of overleaf settings --- services/web/app/views/project/list/v1-item.pug | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/web/app/views/project/list/v1-item.pug b/services/web/app/views/project/list/v1-item.pug index 5631788aeb..3a5e86e791 100644 --- a/services/web/app/views/project/list/v1-item.pug +++ b/services/web/app/views/project/list/v1-item.pug @@ -1,10 +1,11 @@ .col-xs-8 span.v1-badge(aria-label=translate("v1_badge")) span - a.projectName( - href=settings.overleaf.host + "/{{project.id}}" - stop-propagation="click" - ) {{project.name}} + if settings.overleaf && settings.overleaf.host + a.projectName( + href=settings.overleaf.host + "/{{project.id}}" + stop-propagation="click" + ) {{project.name}} .col-xs-4 span.last-modified {{project.lastUpdated | formatDate}} \ No newline at end of file From 7187f5ed675a8d3d1e1820a52f98e7272e12a9f6 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 21 Nov 2017 10:43:24 +0000 Subject: [PATCH 55/58] use /login for smoke tests not register 1) A user needs an OL access token to load the beta - https://github.com/sharelatex/overleaf-integration-web-module/blob/5001dc48f15ca557bab8689f50b6ac28f30db66a/app/coffee/OAuth/OAuthRequest.coffee#L8 2) If a user has an OL access token they can not use the register endpoint on ShareLaTeX. https://github.com/sharelatex/web-sharelatex-modules/blob/master/public-registration/app/coffee/PublicRegistrationController.coffee#L72 --- services/web/test/smoke/coffee/SmokeTests.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/web/test/smoke/coffee/SmokeTests.coffee b/services/web/test/smoke/coffee/SmokeTests.coffee index 0e6f7d6244..a6ac06cb5a 100644 --- a/services/web/test/smoke/coffee/SmokeTests.coffee +++ b/services/web/test/smoke/coffee/SmokeTests.coffee @@ -33,9 +33,9 @@ describe "Opening", -> return done(err) logger.log "smoke test: clearing rate limit " require("../../../app/js/infrastructure/RateLimiter.js").clearRateLimit "open-project", "#{Settings.smokeTest.projectId}:#{Settings.smokeTest.userId}", -> - logger.log "smoke test: hitting /register" + logger.log "smoke test: hitting /login" command = """ - curl -H "X-Forwarded-Proto: https" -c #{cookeFilePath} #{buildUrl('register')} + curl -H "X-Forwarded-Proto: https" -c #{cookeFilePath} #{buildUrl('login')} """ child.exec command, (err, stdout, stderr)-> if err? then done(err) @@ -47,9 +47,9 @@ describe "Opening", -> logger.log "smoke test: converting cookie file 1" convertCookieFile (err) -> return done(err) if err? - logger.log "smoke test: hitting /register with csrf" + logger.log "smoke test: hitting /login with csrf" command = """ - curl -c #{cookeFilePath} -H "Content-Type: application/json" -H "X-Forwarded-Proto: https" -d '{"_csrf":"#{csrf}", "email":"#{Settings.smokeTest.user}", "password":"#{Settings.smokeTest.password}"}' #{buildUrl('register')} + curl -c #{cookeFilePath} -H "Content-Type: application/json" -H "X-Forwarded-Proto: https" -d '{"_csrf":"#{csrf}", "email":"#{Settings.smokeTest.user}", "password":"#{Settings.smokeTest.password}"}' #{buildUrl('login')} """ child.exec command, (err) -> return done(err) if err? From b7dca80294267964a7408b3ac4ecd2b9c5a72bdd Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 21 Nov 2017 12:17:53 +0000 Subject: [PATCH 56/58] use /dev/csrf for smoke tests --- services/web/test/smoke/coffee/SmokeTests.coffee | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/services/web/test/smoke/coffee/SmokeTests.coffee b/services/web/test/smoke/coffee/SmokeTests.coffee index a6ac06cb5a..e710acddec 100644 --- a/services/web/test/smoke/coffee/SmokeTests.coffee +++ b/services/web/test/smoke/coffee/SmokeTests.coffee @@ -33,17 +33,13 @@ describe "Opening", -> return done(err) logger.log "smoke test: clearing rate limit " require("../../../app/js/infrastructure/RateLimiter.js").clearRateLimit "open-project", "#{Settings.smokeTest.projectId}:#{Settings.smokeTest.userId}", -> - logger.log "smoke test: hitting /login" + logger.log "smoke test: hitting dev/csrf" command = """ - curl -H "X-Forwarded-Proto: https" -c #{cookeFilePath} #{buildUrl('login')} + curl -H "X-Forwarded-Proto: https" -c #{cookeFilePath} #{buildUrl('dev/csrf')} """ child.exec command, (err, stdout, stderr)-> if err? then done(err) - csrfMatches = stdout.match("") - if !csrfMatches? - logger.err stdout:stdout, "smoke test: does not have csrf token" - return done("smoke test: does not have csrf token") - csrf = csrfMatches[1] + csrf = stdout logger.log "smoke test: converting cookie file 1" convertCookieFile (err) -> return done(err) if err? From c11ea59dc17c2836078f539c06f961c9a2e4aec3 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Wed, 22 Nov 2017 09:50:08 +0000 Subject: [PATCH 57/58] Increase link-sharing rollout to 100% --- .../web/app/coffee/Features/Project/ProjectController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index bbff14d2a1..90ac6f09aa 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -342,7 +342,7 @@ module.exports = ProjectController = enableTokenAccessUI = ProjectController._isInPercentageRollout( 'linksharing', project.owner_ref, - 40 + 100 ) showLinkSharingOnboarding = enableTokenAccessUI && results.couldShowLinkSharingOnboarding AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, token, (error, privilegeLevel)-> From ba04875ddce35fe92433a5fc9a13f80818b0850d Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 22 Nov 2017 10:54:46 +0000 Subject: [PATCH 58/58] Increase autocompile rollout to 10% --- .../web/app/coffee/Features/Project/ProjectController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 90ac6f09aa..174413b248 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -289,7 +289,7 @@ module.exports = ProjectController = # Extract data from user's ObjectId timestamp = parseInt(user_id.toString().substring(0, 8), 16) - rolloutPercentage = 5 # Percentage of users to roll out to + rolloutPercentage = 10 # Percentage of users to roll out to if !ProjectController._isInPercentageRollout('autocompile', user_id, rolloutPercentage) # Don't show if user is not part of roll out return cb(null, { enabled: false, showOnboarding: false })