From 50df230846e1313ffeeb7a93117247a1dcb2cfd8 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Mon, 10 Jan 2022 10:23:05 +0000 Subject: [PATCH] [web] Upgrade Prettier to match version in monorepo root (#6231) GitOrigin-RevId: 02f97af1b9704782eee77a0b7dfc477ada23e34d --- services/web/app.js | 12 +- .../Authorization/AuthorizationManager.js | 21 +- .../Authorization/AuthorizationMiddleware.js | 33 +- .../src/Features/Captcha/CaptchaMiddleware.js | 3 +- .../Collaborators/CollaboratorsGetter.js | 55 +- .../Collaborators/CollaboratorsHandler.js | 12 +- .../src/Features/Compile/ClsiStateManager.js | 5 +- .../Features/Editor/EditorHttpController.js | 25 +- .../web/app/src/Features/Errors/Errors.js | 8 +- .../src/Features/Exports/ExportsHandler.js | 492 ++--- .../app/src/Features/Helpers/EmailHelper.js | 5 +- .../InactiveData/InactiveProjectManager.js | 25 +- .../Institutions/InstitutionsManager.js | 7 +- .../LinkedFiles/ProjectOutputFileAgent.js | 6 +- .../src/Features/Project/ProjectController.js | 24 +- .../Features/Project/ProjectDetailsHandler.js | 9 +- .../src/Features/Project/ProjectDuplicator.js | 11 +- .../Features/Project/ProjectEditorHandler.js | 5 +- .../ProjectEntityMongoUpdateHandler.js | 71 +- .../Project/ProjectEntityUpdateHandler.js | 7 +- .../Features/References/ReferencesHandler.js | 5 +- .../SplitTests/SplitTestMiddleware.js | 9 +- .../Features/SplitTests/SplitTestV2Handler.js | 8 +- .../Features/Subscription/FeaturesUpdater.js | 17 +- .../Subscription/LimitationsManager.js | 5 +- .../Features/Subscription/RecurlyWrapper.js | 15 +- .../Subscription/SubscriptionController.js | 57 +- .../Subscription/SubscriptionUpdater.js | 15 +- .../SubscriptionViewModelBuilder.js | 35 +- .../ThirdPartyDataStore/TpdsUpdateSender.js | 10 +- .../TokenAccess/TokenAccessController.js | 26 +- .../Features/Uploads/ProjectUploadManager.js | 21 +- .../src/Features/User/SAMLIdentityManager.js | 5 +- .../web/app/src/Features/User/UserGetter.js | 5 +- .../src/Features/User/UserSessionsManager.js | 25 +- .../UserMembershipController.js | 5 +- .../UserMembershipMiddleware.js | 9 +- .../web/app/src/infrastructure/Features.js | 15 +- .../app/src/infrastructure/Translations.js | 5 +- .../web/frontend/js/directives/onEnter.js | 16 +- .../components/clone-project-modal-content.js | 7 +- .../editor-navigation-toolbar-root.js | 5 +- .../components/file-tree-context-menu.js | 7 +- .../modes/file-tree-import-from-project.js | 6 +- .../file-tree-item/file-tree-item-name.js | 9 +- .../file-tree/components/file-tree-toolbar.js | 8 +- .../modals/file-tree-modal-create-folder.js | 9 +- .../controllers/file-tree-controller.js | 209 +-- .../hooks/file-tree-socket-listener.js | 8 +- .../components/detach-compile-button.js | 7 +- .../pdf-preview/components/pdf-js-viewer.js | 8 +- .../pdf-preview/components/pdf-logs-button.js | 9 +- .../components/pdf-synctex-controls.js | 9 +- .../pdf-preview/hooks/use-compile-triggers.js | 8 +- .../features/plans/group-plan-modal/index.js | 10 +- .../components/preview-logs-pane-entry.js | 12 +- .../preview/components/preview-pane.js | 10 +- .../components/edit-member.js | 6 +- .../components/select-collaborators.js | 10 +- .../components/share-project-modal.js | 7 +- .../js/ide/connection/ConnectionManager.js | 3 +- .../web/frontend/js/ide/editor/ShareJsDoc.js | 6 +- .../auto-complete/AutoCompleteManager.js | 10 +- .../spell-check/SpellCheckManager.js | 8 +- .../track-changes/TrackChangesAdapter.js | 24 +- .../track-changes/TrackChangesManager.js | 12 +- .../frontend/js/ide/history/HistoryManager.js | 13 +- .../js/ide/history/HistoryV2Manager.js | 23 +- .../HumanReadableLogsRules.js | 9 +- .../js/ide/log-parser/bib-log-parser.js | 27 +- .../js/ide/pdfng/directives/pdfViewer.js | 4 +- .../controllers/ReviewPanelController.js | 14 +- .../js/ide/review-panel/filters/notEmpty.js | 5 +- .../web/frontend/js/main/account-settings.js | 93 +- .../controllers/UserAffiliationsController.js | 30 +- .../js/main/project-list/project-list.js | 1604 +++++++++-------- .../js/shared/context/compile-context.js | 5 +- .../js/shared/context/layout-context.js | 5 +- .../js/shared/hooks/use-detach-action.js | 8 +- .../js/shared/hooks/use-detach-layout.js | 9 +- .../js/shared/hooks/use-detach-state.js | 8 +- .../create-file-modal-decorator.js | 31 +- .../20190912145032_create_users_indexes.js | 3 +- .../test/unit/src/LaunchpadControllerTests.js | 12 +- .../unit/src/UserActivateControllerTests.js | 4 +- services/web/package-lock.json | 18 +- services/web/package.json | 2 +- .../clear_institution_notifications.js | 18 +- .../web/scripts/count_files_in_projects.js | 5 +- .../delete-orphaned-docs.js | 4 +- .../count_project_history_categories.js | 3 +- ...conversion_if_created_after_fph_enabled.js | 3 +- .../sync-user-entitlements.js | 12 +- .../test/acceptance/src/ProjectInviteTests.js | 9 +- services/web/test/acceptance/src/TagsTests.js | 13 +- .../src/helpers/DeletedSubscription.js | 8 +- .../acceptance/src/helpers/Institution.js | 4 +- .../acceptance/src/helpers/Subscription.js | 8 +- .../test/acceptance/src/helpers/UserHelper.js | 5 +- services/web/test/frontend/bootstrap.js | 11 +- .../components/pdf-preview.test.js | 3 +- .../components/share-project-modal.test.js | 8 +- .../infrastructure/fetch-json.test.js | 3 +- .../spell-check/SpellCheckManagerTests.js | 11 +- .../ide/history/HistoryV2ManagerTests.js | 37 +- .../AuthenticationControllerTests.js | 24 +- .../AuthenticationManagerTests.js | 20 +- .../AuthorizationManagerTests.js | 196 +- .../AuthorizationMiddlewareTests.js | 4 +- .../BetaProgram/BetaProgramControllerTests.js | 7 +- .../Collaborators/CollaboratorsGetterTests.js | 87 +- .../CollaboratorsInviteControllerTests.js | 4 +- .../CollaboratorsInviteHandlerTests.js | 8 +- .../test/unit/src/Compile/ClsiManagerTests.js | 4 +- .../src/Documents/DocumentControllerTests.js | 3 +- .../ProjectDownloadsControllerTests.js | 4 +- .../unit/src/Editor/EditorControllerTests.js | 12 +- .../src/Editor/EditorHttpControllerTests.js | 8 +- .../src/Exports/ExportsControllerTests.js | 4 +- .../src/History/HistoryControllerTests.js | 3 +- .../unit/src/History/RestoreManagerTests.js | 3 +- .../Institutions/InstitutionsGetterTests.js | 27 +- .../Institutions/InstitutionsManagerTests.js | 28 +- .../unit/src/Metadata/MetaHandlerTests.js | 4 +- .../NotificationsControllerTests.js | 4 +- .../PasswordResetControllerTests.js | 9 +- .../PasswordResetHandlerTests.js | 14 +- .../src/Project/ProjectControllerTests.js | 4 +- .../unit/src/Project/ProjectDeleterTests.js | 12 +- .../src/Project/ProjectDetailsHandlerTests.js | 7 +- .../src/Project/ProjectDuplicatorTests.js | 8 +- .../src/Project/ProjectEntityHandlerTests.js | 4 +- .../ProjectEntityUpdateHandlerTests.js | 8 +- .../unit/src/Project/ProjectGetterTests.js | 4 +- .../src/Publishers/PublishersGetterTests.js | 28 +- .../src/References/ReferencesHandlerTests.js | 7 +- .../src/Spelling/SpellingControllerTests.js | 4 +- .../src/Subscription/FeaturesUpdaterTests.js | 12 +- .../Subscription/LimitationsManagerTests.js | 3 +- .../src/Subscription/RecurlyWrapperTests.js | 8 +- .../SubscriptionControllerTests.js | 3 +- .../SubscriptionGroupHandlerTests.js | 4 +- .../Subscription/SubscriptionHandlerTests.js | 12 +- .../src/Templates/TemplatesControllerTests.js | 7 +- .../TpdsProjectFlusherTests.js | 4 +- .../src/Uploads/ProjectUploadManagerTests.js | 8 +- .../User/ThirdPartyIdentityManagerTests.js | 14 +- .../test/unit/src/User/UserControllerTests.js | 4 +- .../test/unit/src/User/UserCreatorTests.js | 7 +- .../src/User/UserEmailsControllerTests.js | 17 +- .../unit/src/User/UserPagesControllerTests.js | 4 +- .../test/unit/src/User/UserUpdaterTests.js | 8 +- .../src/infrastructure/GeoIpLookupTest.js | 42 +- 153 files changed, 2151 insertions(+), 2232 deletions(-) diff --git a/services/web/app.js b/services/web/app.js index 16aa07b77c..5975e0b04f 100644 --- a/services/web/app.js +++ b/services/web/app.js @@ -15,10 +15,14 @@ const Settings = require('@overleaf/settings') const logger = require('@overleaf/logger') const PlansLocator = require('./app/src/Features/Subscription/PlansLocator') logger.initialize(process.env.METRICS_APP_NAME || 'web') -logger.logger.serializers.user = require('./app/src/infrastructure/LoggerSerializers').user -logger.logger.serializers.docs = require('./app/src/infrastructure/LoggerSerializers').docs -logger.logger.serializers.files = require('./app/src/infrastructure/LoggerSerializers').files -logger.logger.serializers.project = require('./app/src/infrastructure/LoggerSerializers').project +logger.logger.serializers.user = + require('./app/src/infrastructure/LoggerSerializers').user +logger.logger.serializers.docs = + require('./app/src/infrastructure/LoggerSerializers').docs +logger.logger.serializers.files = + require('./app/src/infrastructure/LoggerSerializers').files +logger.logger.serializers.project = + require('./app/src/infrastructure/LoggerSerializers').project if ((Settings.sentry != null ? Settings.sentry.dsn : undefined) != null) { logger.initializeErrorReporting(Settings.sentry.dsn) } diff --git a/services/web/app/src/Features/Authorization/AuthorizationManager.js b/services/web/app/src/Features/Authorization/AuthorizationManager.js index 796332b6ad..5e1037f3bb 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationManager.js +++ b/services/web/app/src/Features/Authorization/AuthorizationManager.js @@ -80,10 +80,11 @@ async function getPrivilegeLevelForProjectWithUser( token, opts = {} ) { - const privilegeLevel = await CollaboratorsGetter.promises.getMemberIdPrivilegeLevel( - userId, - projectId - ) + const privilegeLevel = + await CollaboratorsGetter.promises.getMemberIdPrivilegeLevel( + userId, + projectId + ) if (privilegeLevel && privilegeLevel !== PrivilegeLevels.NONE) { // The user has direct access return privilegeLevel @@ -140,13 +141,11 @@ async function getPrivilegeLevelForProjectWithToken(projectId, token) { // Anonymous users can have read-only access to token-based projects, // while read-write access must be logged in, // unless the `enableAnonymousReadAndWriteSharing` setting is enabled - const { - isValidReadAndWrite, - isValidReadOnly, - } = await TokenAccessHandler.promises.validateTokenForAnonymousAccess( - projectId, - token - ) + const { isValidReadAndWrite, isValidReadOnly } = + await TokenAccessHandler.promises.validateTokenForAnonymousAccess( + projectId, + token + ) if (isValidReadOnly) { // Grant anonymous user read-only access return PrivilegeLevels.READ_ONLY diff --git a/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js b/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js index 610ef4661d..9855b4c233 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js +++ b/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js @@ -29,11 +29,12 @@ async function blockRestrictedUserFromProject(req, res, next) { const projectId = _getProjectId(req) const userId = _getUserId(req) const token = TokenAccessHandler.getRequestToken(req, projectId) - const isRestrictedUser = await AuthorizationManager.promises.isRestrictedUserForProject( - userId, - projectId, - token - ) + const isRestrictedUser = + await AuthorizationManager.promises.isRestrictedUserForProject( + userId, + projectId, + token + ) if (isRestrictedUser) { return HttpErrorHandler.forbidden(req, res) } @@ -75,11 +76,12 @@ async function ensureUserCanWriteProjectSettings(req, res, next) { const otherParams = Object.keys(req.body).filter(x => x !== 'name') if (otherParams.length > 0) { - const canWrite = await AuthorizationManager.promises.canUserWriteProjectSettings( - userId, - projectId, - token - ) + const canWrite = + await AuthorizationManager.promises.canUserWriteProjectSettings( + userId, + projectId, + token + ) if (!canWrite) { return HttpErrorHandler.forbidden(req, res) } @@ -92,11 +94,12 @@ async function ensureUserCanWriteProjectContent(req, res, next) { const projectId = _getProjectId(req) const userId = _getUserId(req) const token = TokenAccessHandler.getRequestToken(req, projectId) - const canWrite = await AuthorizationManager.promises.canUserWriteProjectContent( - userId, - projectId, - token - ) + const canWrite = + await AuthorizationManager.promises.canUserWriteProjectContent( + userId, + projectId, + token + ) if (canWrite) { logger.log( { userId, projectId }, diff --git a/services/web/app/src/Features/Captcha/CaptchaMiddleware.js b/services/web/app/src/Features/Captcha/CaptchaMiddleware.js index d1b9fd6bd7..47f97e4214 100644 --- a/services/web/app/src/Features/Captcha/CaptchaMiddleware.js +++ b/services/web/app/src/Features/Captcha/CaptchaMiddleware.js @@ -50,8 +50,7 @@ module.exports = CaptchaMiddleware = { return res.status(400).send({ errorReason: 'cannot_verify_user_not_robot', message: { - text: - 'Sorry, we could not verify that you are not a robot. Please check that Google reCAPTCHA is not being blocked by an ad blocker or firewall.', + text: 'Sorry, we could not verify that you are not a robot. Please check that Google reCAPTCHA is not being blocked by an ad blocker or firewall.', }, }) } else { diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js b/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js index 3519045187..39077d28bf 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js @@ -132,42 +132,37 @@ async function isUserInvitedMemberOfProject(userId, projectId) { async function getProjectsUserIsMemberOf(userId, fields) { const limit = pLimit(2) - const [ - readAndWrite, - readOnly, - tokenReadAndWrite, - tokenReadOnly, - ] = await Promise.all([ - limit(() => Project.find({ collaberator_refs: userId }, fields).exec()), - limit(() => Project.find({ readOnly_refs: userId }, fields).exec()), - limit(() => - Project.find( - { - tokenAccessReadAndWrite_refs: userId, - publicAccesLevel: PublicAccessLevels.TOKEN_BASED, - }, - fields - ).exec() - ), - limit(() => - Project.find( - { - tokenAccessReadOnly_refs: userId, - publicAccesLevel: PublicAccessLevels.TOKEN_BASED, - }, - fields - ).exec() - ), - ]) + const [readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly] = + await Promise.all([ + limit(() => Project.find({ collaberator_refs: userId }, fields).exec()), + limit(() => Project.find({ readOnly_refs: userId }, fields).exec()), + limit(() => + Project.find( + { + tokenAccessReadAndWrite_refs: userId, + publicAccesLevel: PublicAccessLevels.TOKEN_BASED, + }, + fields + ).exec() + ), + limit(() => + Project.find( + { + tokenAccessReadOnly_refs: userId, + publicAccesLevel: PublicAccessLevels.TOKEN_BASED, + }, + fields + ).exec() + ), + ]) return { readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly } } async function getAllInvitedMembers(projectId) { try { const rawMembers = await getInvitedMembersWithPrivilegeLevels(projectId) - const { members } = ProjectEditorHandler.buildOwnerAndMembersViews( - rawMembers - ) + const { members } = + ProjectEditorHandler.buildOwnerAndMembersViews(rawMembers) return members } catch (err) { throw OError.tag(err, 'error getting members for project', { projectId }) diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js index 9dd3f1c9d9..d8d0d1b6e1 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js @@ -78,14 +78,10 @@ async function removeUserFromProject(projectId, userId) { } async function removeUserFromAllProjects(userId) { - const { - readAndWrite, - readOnly, - tokenReadAndWrite, - tokenReadOnly, - } = await CollaboratorsGetter.promises.getProjectsUserIsMemberOf(userId, { - _id: 1, - }) + const { readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly } = + await CollaboratorsGetter.promises.getProjectsUserIsMemberOf(userId, { + _id: 1, + }) const allProjects = readAndWrite .concat(readOnly) .concat(tokenReadAndWrite) diff --git a/services/web/app/src/Features/Compile/ClsiStateManager.js b/services/web/app/src/Features/Compile/ClsiStateManager.js index d1db73af86..a7e687f2ab 100644 --- a/services/web/app/src/Features/Compile/ClsiStateManager.js +++ b/services/web/app/src/Features/Compile/ClsiStateManager.js @@ -38,9 +38,8 @@ const buildState = s => module.exports = ClsiStateManager = { computeHash(project, options) { - const { docs, files } = ProjectEntityHandler.getAllEntitiesFromProject( - project - ) + const { docs, files } = + ProjectEntityHandler.getAllEntitiesFromProject(project) const fileList = Array.from(files || []).map( f => `${f.file._id}:${f.file.rev}:${f.file.created}:${f.path}` ) diff --git a/services/web/app/src/Features/Editor/EditorHttpController.js b/services/web/app/src/Features/Editor/EditorHttpController.js index 555b7b2233..ff91895bdf 100644 --- a/services/web/app/src/Features/Editor/EditorHttpController.js +++ b/services/web/app/src/Features/Editor/EditorHttpController.js @@ -60,11 +60,8 @@ async function joinProject(req, res, next) { userId = null } Metrics.inc('editor.join-project') - const { - project, - privilegeLevel, - isRestrictedUser, - } = await _buildJoinProjectView(req, projectId, userId) + const { project, privilegeLevel, isRestrictedUser } = + await _buildJoinProjectView(req, projectId, userId) if (!project) { return res.sendStatus(403) } @@ -116,15 +113,17 @@ async function _buildJoinProjectView(req, projectId, userId) { 'soft-failure when fetching deletedDocs from docstore' ) } - const members = await CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels( - projectId - ) + const members = + await CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels( + projectId + ) const token = TokenAccessHandler.getRequestToken(req, projectId) - const privilegeLevel = await AuthorizationManager.promises.getPrivilegeLevelForProject( - userId, - projectId, - token - ) + const privilegeLevel = + await AuthorizationManager.promises.getPrivilegeLevelForProject( + userId, + projectId, + token + ) if (privilegeLevel == null || privilegeLevel === PrivilegeLevels.NONE) { return { project: null, privilegeLevel: null, isRestrictedUser: false } } diff --git a/services/web/app/src/Features/Errors/Errors.js b/services/web/app/src/Features/Errors/Errors.js index a94153a917..7d3940ab31 100644 --- a/services/web/app/src/Features/Errors/Errors.js +++ b/services/web/app/src/Features/Errors/Errors.js @@ -99,12 +99,8 @@ class SAMLSessionDataMissing extends BackwardCompatibleError { ? arg.samlSession : {} this.tryAgain = true - const { - universityId, - universityName, - externalUserId, - institutionEmail, - } = samlSession + const { universityId, universityName, externalUserId, institutionEmail } = + samlSession if ( !universityId && diff --git a/services/web/app/src/Features/Exports/ExportsHandler.js b/services/web/app/src/Features/Exports/ExportsHandler.js index d456b7473c..28ff5061f3 100644 --- a/services/web/app/src/Features/Exports/ExportsHandler.js +++ b/services/web/app/src/Features/Exports/ExportsHandler.js @@ -27,261 +27,265 @@ let request = require('request') request = request.defaults() settings = require('@overleaf/settings') -module.exports = ExportsHandler = self = { - exportProject(export_params, callback) { - if (callback == null) { - callback = function () {} - } - return self._buildExport(export_params, function (err, export_data) { - if (err != null) { - return callback(err) - } - return self._requestExport(export_data, function (err, body) { - if (err != null) { - return callback(err) +module.exports = + ExportsHandler = + self = + { + exportProject(export_params, callback) { + if (callback == null) { + callback = function () {} } - export_data.v1_id = body.exportId - export_data.message = body.message - // TODO: possibly store the export data in Mongo - return callback(null, export_data) - }) - }) - }, - - _buildExport(export_params, callback) { - if (callback == null) { - callback = function () {} - } - const { - project_id, - user_id, - brand_variation_id, - title, - description, - author, - license, - show_source, - } = export_params - const jobs = { - project(cb) { - return ProjectGetter.getProject(project_id, cb) - }, - // TODO: when we update async, signature will change from (cb, results) to (results, cb) - rootDoc: [ - 'project', - (cb, results) => - ProjectRootDocManager.ensureRootDocumentIsValid( - project_id, - function (error) { - if (error != null) { - return callback(error) - } - return ProjectLocator.findRootDoc( - { project: results.project, project_id }, - cb - ) + return self._buildExport(export_params, function (err, export_data) { + if (err != null) { + return callback(err) + } + return self._requestExport(export_data, function (err, body) { + if (err != null) { + return callback(err) } - ), - ], - user(cb) { - return UserGetter.getUser( + export_data.v1_id = body.exportId + export_data.message = body.message + // TODO: possibly store the export data in Mongo + return callback(null, export_data) + }) + }) + }, + + _buildExport(export_params, callback) { + if (callback == null) { + callback = function () {} + } + const { + project_id, user_id, - { first_name: 1, last_name: 1, email: 1, overleaf: 1 }, - cb + brand_variation_id, + title, + description, + author, + license, + show_source, + } = export_params + const jobs = { + project(cb) { + return ProjectGetter.getProject(project_id, cb) + }, + // TODO: when we update async, signature will change from (cb, results) to (results, cb) + rootDoc: [ + 'project', + (cb, results) => + ProjectRootDocManager.ensureRootDocumentIsValid( + project_id, + function (error) { + if (error != null) { + return callback(error) + } + return ProjectLocator.findRootDoc( + { project: results.project, project_id }, + cb + ) + } + ), + ], + user(cb) { + return UserGetter.getUser( + user_id, + { first_name: 1, last_name: 1, email: 1, overleaf: 1 }, + cb + ) + }, + historyVersion(cb) { + return ProjectHistoryHandler.ensureHistoryExistsForProject( + project_id, + function (error) { + if (error != null) { + return callback(error) + } + return self._requestVersion(project_id, cb) + } + ) + }, + } + + return async.auto(jobs, function (err, results) { + if (err != null) { + OError.tag(err, 'error building project export', { + project_id, + user_id, + brand_variation_id, + }) + return callback(err) + } + + const { project, rootDoc, user, historyVersion } = results + if (!rootDoc || rootDoc[1] == null) { + err = new OError('cannot export project without root doc', { + project_id, + }) + return callback(err) + } + + if (export_params.first_name && export_params.last_name) { + user.first_name = export_params.first_name + user.last_name = export_params.last_name + } + + const export_data = { + project: { + id: project_id, + rootDocPath: + rootDoc[1] != null ? rootDoc[1].fileSystem : undefined, + historyId: __guard__( + project.overleaf != null ? project.overleaf.history : undefined, + x => x.id + ), + historyVersion, + v1ProjectId: + project.overleaf != null ? project.overleaf.id : undefined, + metadata: { + compiler: project.compiler, + imageName: project.imageName, + title, + description, + author, + license, + showSource: show_source, + }, + }, + user: { + id: user_id, + firstName: user.first_name, + lastName: user.last_name, + email: user.email, + orcidId: null, // until v2 gets ORCID + v1UserId: user.overleaf != null ? user.overleaf.id : undefined, + }, + destination: { + brandVariationId: brand_variation_id, + }, + options: { + callbackUrl: null, + }, // for now, until we want v1 to call us back + } + return callback(null, export_data) + }) + }, + + _requestExport(export_data, callback) { + if (callback == null) { + callback = function () {} + } + return request.post( + { + url: `${settings.apis.v1.url}/api/v1/sharelatex/exports`, + auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }, + json: export_data, + }, + function (err, res, body) { + if (err != null) { + OError.tag(err, 'error making request to v1 export', { + export: export_data, + }) + return callback(err) + } else if (res.statusCode >= 200 && res.statusCode < 300) { + return callback(null, body) + } else { + logger.warn( + { export: export_data }, + `v1 export returned failure; forwarding: ${body}` + ) + // pass the v1 error along for the publish modal to handle + const err = { forwardResponse: body } + return callback(err) + } + } ) }, - historyVersion(cb) { - return ProjectHistoryHandler.ensureHistoryExistsForProject( - project_id, - function (error) { - if (error != null) { - return callback(error) + + _requestVersion(project_id, callback) { + if (callback == null) { + callback = function () {} + } + return request.get( + { + url: `${settings.apis.project_history.url}/project/${project_id}/version`, + json: true, + }, + function (err, res, body) { + if (err != null) { + OError.tag(err, 'error making request to project history', { + project_id, + }) + return callback(err) + } else if (res.statusCode >= 200 && res.statusCode < 300) { + return callback(null, body.version) + } else { + err = new OError( + `project history version returned a failure status code: ${res.statusCode}`, + { project_id } + ) + return callback(err) + } + } + ) + }, + + fetchExport(export_id, callback) { + if (callback == null) { + callback = function () {} + } + return request.get( + { + url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}`, + auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }, + }, + function (err, res, body) { + if (err != null) { + OError.tag(err, 'error making request to v1 export', { + export: export_id, + }) + return callback(err) + } else if (res.statusCode >= 200 && res.statusCode < 300) { + return callback(null, body) + } else { + err = new OError( + `v1 export returned a failure status code: ${res.statusCode}`, + { export: export_id } + ) + return callback(err) + } + } + ) + }, + + fetchDownload(export_id, type, callback) { + if (callback == null) { + callback = function () {} + } + return request.get( + { + url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}/${type}_url`, + auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }, + }, + function (err, res, body) { + if (err != null) { + OError.tag(err, 'error making request to v1 export', { + export: export_id, + }) + return callback(err) + } else if (res.statusCode >= 200 && res.statusCode < 300) { + return callback(null, body) + } else { + err = new OError( + `v1 export returned a failure status code: ${res.statusCode}`, + { export: export_id } + ) + return callback(err) } - return self._requestVersion(project_id, cb) } ) }, } - return async.auto(jobs, function (err, results) { - if (err != null) { - OError.tag(err, 'error building project export', { - project_id, - user_id, - brand_variation_id, - }) - return callback(err) - } - - const { project, rootDoc, user, historyVersion } = results - if (!rootDoc || rootDoc[1] == null) { - err = new OError('cannot export project without root doc', { - project_id, - }) - return callback(err) - } - - if (export_params.first_name && export_params.last_name) { - user.first_name = export_params.first_name - user.last_name = export_params.last_name - } - - const export_data = { - project: { - id: project_id, - rootDocPath: rootDoc[1] != null ? rootDoc[1].fileSystem : undefined, - historyId: __guard__( - project.overleaf != null ? project.overleaf.history : undefined, - x => x.id - ), - historyVersion, - v1ProjectId: - project.overleaf != null ? project.overleaf.id : undefined, - metadata: { - compiler: project.compiler, - imageName: project.imageName, - title, - description, - author, - license, - showSource: show_source, - }, - }, - user: { - id: user_id, - firstName: user.first_name, - lastName: user.last_name, - email: user.email, - orcidId: null, // until v2 gets ORCID - v1UserId: user.overleaf != null ? user.overleaf.id : undefined, - }, - destination: { - brandVariationId: brand_variation_id, - }, - options: { - callbackUrl: null, - }, // for now, until we want v1 to call us back - } - return callback(null, export_data) - }) - }, - - _requestExport(export_data, callback) { - if (callback == null) { - callback = function () {} - } - return request.post( - { - url: `${settings.apis.v1.url}/api/v1/sharelatex/exports`, - auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }, - json: export_data, - }, - function (err, res, body) { - if (err != null) { - OError.tag(err, 'error making request to v1 export', { - export: export_data, - }) - return callback(err) - } else if (res.statusCode >= 200 && res.statusCode < 300) { - return callback(null, body) - } else { - logger.warn( - { export: export_data }, - `v1 export returned failure; forwarding: ${body}` - ) - // pass the v1 error along for the publish modal to handle - const err = { forwardResponse: body } - return callback(err) - } - } - ) - }, - - _requestVersion(project_id, callback) { - if (callback == null) { - callback = function () {} - } - return request.get( - { - url: `${settings.apis.project_history.url}/project/${project_id}/version`, - json: true, - }, - function (err, res, body) { - if (err != null) { - OError.tag(err, 'error making request to project history', { - project_id, - }) - return callback(err) - } else if (res.statusCode >= 200 && res.statusCode < 300) { - return callback(null, body.version) - } else { - err = new OError( - `project history version returned a failure status code: ${res.statusCode}`, - { project_id } - ) - return callback(err) - } - } - ) - }, - - fetchExport(export_id, callback) { - if (callback == null) { - callback = function () {} - } - return request.get( - { - url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}`, - auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }, - }, - function (err, res, body) { - if (err != null) { - OError.tag(err, 'error making request to v1 export', { - export: export_id, - }) - return callback(err) - } else if (res.statusCode >= 200 && res.statusCode < 300) { - return callback(null, body) - } else { - err = new OError( - `v1 export returned a failure status code: ${res.statusCode}`, - { export: export_id } - ) - return callback(err) - } - } - ) - }, - - fetchDownload(export_id, type, callback) { - if (callback == null) { - callback = function () {} - } - return request.get( - { - url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}/${type}_url`, - auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }, - }, - function (err, res, body) { - if (err != null) { - OError.tag(err, 'error making request to v1 export', { - export: export_id, - }) - return callback(err) - } else if (res.statusCode >= 200 && res.statusCode < 300) { - return callback(null, body) - } else { - err = new OError( - `v1 export returned a failure status code: ${res.statusCode}`, - { export: export_id } - ) - return callback(err) - } - } - ) - }, -} - function __guard__(value, transform) { return typeof value !== 'undefined' && value !== null ? transform(value) diff --git a/services/web/app/src/Features/Helpers/EmailHelper.js b/services/web/app/src/Features/Helpers/EmailHelper.js index 99f944739b..79d112f7a5 100644 --- a/services/web/app/src/Features/Helpers/EmailHelper.js +++ b/services/web/app/src/Features/Helpers/EmailHelper.js @@ -1,5 +1,6 @@ -// eslint-disable-next-line no-useless-escape -const EMAIL_REGEXP = /^([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ +const EMAIL_REGEXP = + // eslint-disable-next-line no-useless-escape + /^([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ function getDomain(email) { email = parseEmail(email) diff --git a/services/web/app/src/Features/InactiveData/InactiveProjectManager.js b/services/web/app/src/Features/InactiveData/InactiveProjectManager.js index 0495370260..afc808ca9f 100644 --- a/services/web/app/src/Features/InactiveData/InactiveProjectManager.js +++ b/services/web/app/src/Features/InactiveData/InactiveProjectManager.js @@ -78,16 +78,21 @@ module.exports = InactiveProjectManager = { if (err != null) { logger.err({ err }, 'could not get projects for deactivating') } - const jobs = _.map(projects, project => cb => - InactiveProjectManager.deactivateProject(project._id, function (err) { - if (err) { - logger.err( - { project_id: project._id, err: err }, - 'unable to deactivate project' - ) - } - cb() - }) + const jobs = _.map( + projects, + project => cb => + InactiveProjectManager.deactivateProject( + project._id, + function (err) { + if (err) { + logger.err( + { project_id: project._id, err: err }, + 'unable to deactivate project' + ) + } + cb() + } + ) ) logger.log( { numberOfProjects: projects && projects.length }, diff --git a/services/web/app/src/Features/Institutions/InstitutionsManager.js b/services/web/app/src/Features/Institutions/InstitutionsManager.js index 16c3de08b4..a5e89a29e5 100644 --- a/services/web/app/src/Features/Institutions/InstitutionsManager.js +++ b/services/web/app/src/Features/Institutions/InstitutionsManager.js @@ -125,11 +125,8 @@ async function checkInstitutionUsers(institutionId, emitNonProUserIds) { ) result.ssoUsers.current.entitled = entitled - const { - allSsoUsers, - allSsoUsersByIds, - currentNotEntitledCount, - } = await _getSsoUsers(institutionId, lapsedUserIds) + const { allSsoUsers, allSsoUsersByIds, currentNotEntitledCount } = + await _getSsoUsers(institutionId, lapsedUserIds) result.ssoUsers.total = allSsoUsers.length result.ssoUsers.current.notEntitled = currentNotEntitledCount diff --git a/services/web/app/src/Features/LinkedFiles/ProjectOutputFileAgent.js b/services/web/app/src/Features/LinkedFiles/ProjectOutputFileAgent.js index ec11c102f5..730328ea65 100644 --- a/services/web/app/src/Features/LinkedFiles/ProjectOutputFileAgent.js +++ b/services/web/app/src/Features/LinkedFiles/ProjectOutputFileAgent.js @@ -168,10 +168,8 @@ function _checkAuth(projectId, data, currentUserId, callback) { function _getFileStream(linkedFileData, userId, callback) { callback = _.once(callback) - const { - source_output_file_path: sourceOutputFilePath, - build_id: buildId, - } = linkedFileData + const { source_output_file_path: sourceOutputFilePath, build_id: buildId } = + linkedFileData LinkedFilesHandler.getSourceProject(linkedFileData, (err, project) => { if (err) { return callback(err) diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index de7ba65ac2..bedb40e138 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -357,9 +357,8 @@ const ProjectController = { if (err != null) { return next(err) } - const { docs, files } = ProjectEntityHandler.getAllEntitiesFromProject( - project - ) + const { docs, files } = + ProjectEntityHandler.getAllEntitiesFromProject(project) const entities = docs .concat(files) // Sort by path ascending @@ -553,9 +552,8 @@ const ProjectController = { delete req.session.saml } - const portalTemplates = ProjectController._buildPortalTemplatesList( - userAffiliations - ) + const portalTemplates = + ProjectController._buildPortalTemplatesList(userAffiliations) const projects = ProjectController._buildProjectList( results.projects, userId @@ -798,9 +796,8 @@ const ProjectController = { req, projectId ) - const allowedImageNames = ProjectHelper.getAllowedImagesForUser( - sessionUser - ) + const allowedImageNames = + ProjectHelper.getAllowedImagesForUser(sessionUser) AuthorizationManager.getPrivilegeLevelForProject( userId, @@ -1028,13 +1025,8 @@ const ProjectController = { _buildProjectList(allProjects, userId) { let project - const { - owned, - readAndWrite, - readOnly, - tokenReadAndWrite, - tokenReadOnly, - } = allProjects + const { owned, readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly } = + allProjects const projects = [] for (project of owned) { projects.push( diff --git a/services/web/app/src/Features/Project/ProjectDetailsHandler.js b/services/web/app/src/Features/Project/ProjectDetailsHandler.js index 90ef7548c1..4bc932bdba 100644 --- a/services/web/app/src/Features/Project/ProjectDetailsHandler.js +++ b/services/web/app/src/Features/Project/ProjectDetailsHandler.js @@ -144,10 +144,8 @@ async function validateProjectName(name) { // with a unique name. But that requires thinking through how we would handle incoming projects from // dropbox for example. async function generateUniqueName(userId, name, suffixes = []) { - const allUsersProjectNames = await ProjectGetter.promises.findAllUsersProjects( - userId, - { name: 1 } - ) + const allUsersProjectNames = + await ProjectGetter.promises.findAllUsersProjects(userId, { name: 1 }) // allUsersProjectNames is returned as a hash {owned: [name1, name2, ...], readOnly: [....]} // collect all of the names and flatten them into a single array const projectNameList = _.pluck( @@ -241,6 +239,7 @@ async function _generateTokens(project, callback) { tokens.readAndWritePrefix = numericPrefix } if (tokens.readOnly == null) { - tokens.readOnly = await TokenGenerator.promises.generateUniqueReadOnlyToken() + tokens.readOnly = + await TokenGenerator.promises.generateUniqueReadOnlyToken() } } diff --git a/services/web/app/src/Features/Project/ProjectDuplicator.js b/services/web/app/src/Features/Project/ProjectDuplicator.js index e06949f2ca..c10779f581 100644 --- a/services/web/app/src/Features/Project/ProjectDuplicator.js +++ b/services/web/app/src/Features/Project/ProjectDuplicator.js @@ -66,11 +66,12 @@ async function duplicate(owner, originalProjectId, newProjectName) { _copyDocs(originalEntries.docEntries, originalProject, newProject), _copyFiles(originalEntries.fileEntries, originalProject, newProject), ]) - const projectVersion = await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure( - newProject._id, - docEntries, - fileEntries - ) + const projectVersion = + await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure( + newProject._id, + docEntries, + fileEntries + ) // Silently ignore the rootDoc in case it's not valid per the new limits. if ( rootDocPath && diff --git a/services/web/app/src/Features/Project/ProjectEditorHandler.js b/services/web/app/src/Features/Project/ProjectEditorHandler.js index 649eba5983..81d6db6afb 100644 --- a/services/web/app/src/Features/Project/ProjectEditorHandler.js +++ b/services/web/app/src/Features/Project/ProjectEditorHandler.js @@ -62,9 +62,8 @@ module.exports = ProjectEditorHandler = { result.invites.forEach(invite => { delete invite.token }) - ;({ owner, ownerFeatures, members } = this.buildOwnerAndMembersViews( - members - )) + ;({ owner, ownerFeatures, members } = + this.buildOwnerAndMembersViews(members)) result.owner = owner result.members = members diff --git a/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.js b/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.js index 5aa7e4fd68..46b16ffdd9 100644 --- a/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.js +++ b/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.js @@ -257,21 +257,18 @@ async function mkdirp(projectId, path, options = {}) { for (const folderName of folders) { builtUpPath += `/${folderName}` try { - const { - element: foundFolder, - } = await ProjectLocator.promises.findElementByPath({ - project, - path: builtUpPath, - exactCaseMatch: options.exactCaseMatch, - }) + const { element: foundFolder } = + await ProjectLocator.promises.findElementByPath({ + project, + path: builtUpPath, + exactCaseMatch: options.exactCaseMatch, + }) lastFolder = foundFolder } catch (err) { // Folder couldn't be found. Create it. const parentFolderId = lastFolder && lastFolder._id - const { - folder: newFolder, - parentFolderId: newParentFolderId, - } = await addFolder(projectId, parentFolderId, folderName) + const { folder: newFolder, parentFolderId: newParentFolderId } = + await addFolder(projectId, parentFolderId, folderName) newFolder.parentFolder_id = newParentFolderId lastFolder = newFolder newFolders.push(newFolder) @@ -285,23 +282,19 @@ async function moveEntity(projectId, entityId, destFolderId, entityType) { projectId, { rootFolder: true, name: true, overleaf: true } ) - const { - element: entity, - path: entityPath, - } = await ProjectLocator.promises.findElement({ - project, - element_id: entityId, - type: entityType, - }) + const { element: entity, path: entityPath } = + await ProjectLocator.promises.findElement({ + project, + element_id: entityId, + type: entityType, + }) // Prevent top-level docs/files with reserved names (to match v1 behaviour) if (_blockedFilename(entityPath, entityType)) { throw new Errors.InvalidNameError('blocked element name') } await _checkValidMove(project, entityType, entity, entityPath, destFolderId) - const { - docs: oldDocs, - files: oldFiles, - } = ProjectEntityHandler.getAllEntitiesFromProject(project) + const { docs: oldDocs, files: oldFiles } = + ProjectEntityHandler.getAllEntitiesFromProject(project) // For safety, insert the entity in the destination // location first, and then remove the original. If // there is an error the entity may appear twice. This @@ -328,10 +321,8 @@ async function moveEntity(projectId, entityId, destFolderId, entityType) { entityPath.mongo, entityId ) - const { - docs: newDocs, - files: newFiles, - } = ProjectEntityHandler.getAllEntitiesFromProject(newProject) + const { docs: newDocs, files: newFiles } = + ProjectEntityHandler.getAllEntitiesFromProject(newProject) const startPath = entityPath.fileSystem const endPath = result.path.fileSystem const changes = { @@ -418,10 +409,8 @@ async function renameEntity( // check if the new name already exists in the current folder _checkValidElementName(parentFolder, newName) - const { - docs: oldDocs, - files: oldFiles, - } = ProjectEntityHandler.getAllEntitiesFromProject(project) + const { docs: oldDocs, files: oldFiles } = + ProjectEntityHandler.getAllEntitiesFromProject(project) // we need to increment the project version number for any structure change const newProject = await Project.findOneAndUpdate( @@ -430,10 +419,8 @@ async function renameEntity( { new: true } ).exec() - const { - docs: newDocs, - files: newFiles, - } = ProjectEntityHandler.getAllEntitiesFromProject(newProject) + const { docs: newDocs, files: newFiles } = + ProjectEntityHandler.getAllEntitiesFromProject(newProject) return { project, startPath, @@ -618,14 +605,12 @@ async function _checkValidMove( entityPath, destFolderId ) { - const { - element: destEntity, - path: destFolderPath, - } = await ProjectLocator.promises.findElement({ - project, - element_id: destFolderId, - type: 'folder', - }) + const { element: destEntity, path: destFolderPath } = + await ProjectLocator.promises.findElement({ + project, + element_id: destFolderId, + type: 'folder', + }) // check if there is already a doc/file/folder with the same name // in the destination folder _checkValidElementName(destEntity, entity.name) diff --git a/services/web/app/src/Features/Project/ProjectEntityUpdateHandler.js b/services/web/app/src/Features/Project/ProjectEntityUpdateHandler.js index 30b98a97bb..08d1580f4d 100644 --- a/services/web/app/src/Features/Project/ProjectEntityUpdateHandler.js +++ b/services/web/app/src/Features/Project/ProjectEntityUpdateHandler.js @@ -1349,11 +1349,8 @@ const ProjectEntityUpdateHandler = { return callback(error) } - let { - docs, - files, - folders, - } = ProjectEntityHandler.getAllEntitiesFromProject(project) + let { docs, files, folders } = + ProjectEntityHandler.getAllEntitiesFromProject(project) // _checkFileTree() must be passed the folders before docs and // files ProjectEntityUpdateHandler._checkFiletree( diff --git a/services/web/app/src/Features/References/ReferencesHandler.js b/services/web/app/src/Features/References/ReferencesHandler.js index 8f634317a2..f0ba20c5cd 100644 --- a/services/web/app/src/Features/References/ReferencesHandler.js +++ b/services/web/app/src/Features/References/ReferencesHandler.js @@ -166,8 +166,9 @@ module.exports = ReferencesHandler = { 'flushing docs to mongo before calling references service' ) return Async.series( - docIds.map(docId => cb => - DocumentUpdaterHandler.flushDocToMongo(projectId, docId, cb) + docIds.map( + docId => cb => + DocumentUpdaterHandler.flushDocToMongo(projectId, docId, cb) ), function (err) { // continue diff --git a/services/web/app/src/Features/SplitTests/SplitTestMiddleware.js b/services/web/app/src/Features/SplitTests/SplitTestMiddleware.js index 38ef4fcfde..8355dedd97 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestMiddleware.js +++ b/services/web/app/src/Features/SplitTests/SplitTestMiddleware.js @@ -41,10 +41,11 @@ async function _loadAssignmentInLocals(splitTest, session, locals) { if (cachedVariant) { LocalsHelper.setSplitTestVariant(locals, splitTest.name, cachedVariant) } else { - const assignment = await SplitTestV2Handler.promises.getAssignmentForSession( - session, - splitTest.name - ) + const assignment = + await SplitTestV2Handler.promises.getAssignmentForSession( + session, + splitTest.name + ) session.cachedSplitTestAssignments[cacheKey] = assignment.variant LocalsHelper.setSplitTestVariant( locals, diff --git a/services/web/app/src/Features/SplitTests/SplitTestV2Handler.js b/services/web/app/src/Features/SplitTests/SplitTestV2Handler.js index 4f3dd1bb42..d01fa38073 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestV2Handler.js +++ b/services/web/app/src/Features/SplitTests/SplitTestV2Handler.js @@ -138,12 +138,8 @@ async function _getAssignment( if (splitTest) { const currentVersion = splitTest.getCurrentVersion() if (currentVersion.active) { - const { - activeForUser, - selectedVariantName, - phase, - versionNumber, - } = await _getAssignmentMetadata(analyticsId, userId, splitTest) + const { activeForUser, selectedVariantName, phase, versionNumber } = + await _getAssignmentMetadata(analyticsId, userId, splitTest) if (activeForUser) { const assignmentConfig = { userId, diff --git a/services/web/app/src/Features/Subscription/FeaturesUpdater.js b/services/web/app/src/Features/Subscription/FeaturesUpdater.js index b1872a6294..fff97d76f9 100644 --- a/services/web/app/src/Features/Subscription/FeaturesUpdater.js +++ b/services/web/app/src/Features/Subscription/FeaturesUpdater.js @@ -48,10 +48,8 @@ async function refreshFeatures(userId, reason) { matchedFeatureSet ) - const { - features: newFeatures, - featuresChanged, - } = await UserFeaturesUpdater.promises.updateFeatures(userId, features) + const { features: newFeatures, featuresChanged } = + await UserFeaturesUpdater.promises.updateFeatures(userId, features) if (oldFeatures.dropbox === true && features.dropbox === false) { logger.log({ userId }, '[FeaturesUpdater] must unlink dropbox') const Modules = require('../../infrastructure/Modules') @@ -70,9 +68,8 @@ async function refreshFeatures(userId, reason) { async function computeFeatures(userId) { const individualFeatures = await _getIndividualFeatures(userId) const groupFeatureSets = await _getGroupFeatureSets(userId) - const institutionFeatures = await InstitutionsFeatures.promises.getInstitutionsFeatures( - userId - ) + const institutionFeatures = + await InstitutionsFeatures.promises.getInstitutionsFeatures(userId) const v1Features = await _getV1Features(userId) const bonusFeatures = await ReferalFeatures.promises.getBonusFeatures(userId) const featuresOverrides = await _getFeaturesOverrides(userId) @@ -144,10 +141,8 @@ async function _getFeaturesOverrides(userId) { async function _getV1Features(userId) { let planCode, v1Id try { - ;({ - planCode, - v1Id, - } = await V1SubscriptionManager.promises.getPlanCodeFromV1(userId)) + ;({ planCode, v1Id } = + await V1SubscriptionManager.promises.getPlanCodeFromV1(userId)) } catch (err) { if (err.name === 'NotFoundError') { return {} diff --git a/services/web/app/src/Features/Subscription/LimitationsManager.js b/services/web/app/src/Features/Subscription/LimitationsManager.js index 5405f9a6ad..91d4fa409d 100644 --- a/services/web/app/src/Features/Subscription/LimitationsManager.js +++ b/services/web/app/src/Features/Subscription/LimitationsManager.js @@ -197,9 +197,8 @@ const LimitationsManager = { return callback(new Error('no subscription found')) } - const limitReached = LimitationsManager.teamHasReachedMemberLimit( - subscription - ) + const limitReached = + LimitationsManager.teamHasReachedMemberLimit(subscription) callback(err, limitReached, subscription) } ) diff --git a/services/web/app/src/Features/Subscription/RecurlyWrapper.js b/services/web/app/src/Features/Subscription/RecurlyWrapper.js index 9133544581..f5f70334c8 100644 --- a/services/web/app/src/Features/Subscription/RecurlyWrapper.js +++ b/services/web/app/src/Features/Subscription/RecurlyWrapper.js @@ -283,9 +283,8 @@ const RecurlyWrapper = { account_code: user._id, }, } - const customFields = getCustomFieldsFromSubscriptionDetails( - subscriptionDetails - ) + const customFields = + getCustomFieldsFromSubscriptionDetails(subscriptionDetails) if (customFields) { data.custom_fields = customFields } @@ -395,9 +394,8 @@ const RecurlyWrapper = { data.account.billing_info.three_d_secure_action_result_token_id = recurlyTokenIds.threeDSecureActionResult } - const customFields = getCustomFieldsFromSubscriptionDetails( - subscriptionDetails - ) + const customFields = + getCustomFieldsFromSubscriptionDetails(subscriptionDetails) if (customFields) { data.custom_fields = customFields } @@ -525,9 +523,8 @@ const RecurlyWrapper = { recurlySubscription.account != null && recurlySubscription.account.url != null ) { - accountId = recurlySubscription.account.url.match( - /accounts\/(.*)/ - )[1] + accountId = + recurlySubscription.account.url.match(/accounts\/(.*)/)[1] } else { return callback( new Error("I don't understand the response from Recurly") diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.js b/services/web/app/src/Features/Subscription/SubscriptionController.js index ff58a5d4f8..a436207fc1 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.js +++ b/services/web/app/src/Features/Subscription/SubscriptionController.js @@ -30,11 +30,10 @@ const validGroupPlanModalOptions = { async function plansPage(req, res) { const plans = SubscriptionViewModelBuilder.buildPlansList() - const { - currencyCode: recommendedCurrency, - } = await GeoIpLookup.promises.getCurrencyCode( - (req.query ? req.query.ip : undefined) || req.ip - ) + const { currencyCode: recommendedCurrency } = + await GeoIpLookup.promises.getCurrencyCode( + (req.query ? req.query.ip : undefined) || req.ip + ) function getDefault(param, category, defaultValue) { const v = req.query && req.query[param] @@ -77,17 +76,17 @@ async function paymentPage(req, res) { if (!plan) { return HttpErrorHandler.unprocessableEntity(req, res, 'Plan not found') } - const hasSubscription = await LimitationsManager.promises.userHasV1OrV2Subscription( - user - ) + const hasSubscription = + await LimitationsManager.promises.userHasV1OrV2Subscription(user) if (hasSubscription) { res.redirect('/user/subscription?hasSubscription=true') } else { // LimitationsManager.userHasV2Subscription only checks Mongo. Double check with // Recurly as well at this point (we don't do this most places for speed). - const valid = await SubscriptionHandler.promises.validateNoSubscriptionInRecurly( - user._id - ) + const valid = + await SubscriptionHandler.promises.validateNoSubscriptionInRecurly( + user._id + ) if (!valid) { res.redirect('/user/subscription?hasSubscription=true') } else { @@ -98,12 +97,10 @@ async function paymentPage(req, res) { currency = queryCurrency } } - const { - currencyCode: recommendedCurrency, - countryCode, - } = await GeoIpLookup.promises.getCurrencyCode( - (req.query ? req.query.ip : undefined) || req.ip - ) + const { currencyCode: recommendedCurrency, countryCode } = + await GeoIpLookup.promises.getCurrencyCode( + (req.query ? req.query.ip : undefined) || req.ip + ) if (recommendedCurrency && currency == null) { currency = recommendedCurrency } @@ -127,9 +124,10 @@ async function paymentPage(req, res) { async function userSubscriptionPage(req, res) { const user = SessionManager.getSessionUser(req.session) - const results = await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( - user - ) + const results = + await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( + user + ) const { personalSubscription, memberGroupSubscriptions, @@ -139,9 +137,8 @@ async function userSubscriptionPage(req, res) { managedPublishers, v1SubscriptionStatus, } = results - const hasSubscription = await LimitationsManager.promises.userHasV1OrV2Subscription( - user - ) + const hasSubscription = + await LimitationsManager.promises.userHasV1OrV2Subscription(user) const fromPlansPage = req.query.hasSubscription const plans = SubscriptionViewModelBuilder.buildPlansList( personalSubscription ? personalSubscription.plan : undefined @@ -446,9 +443,8 @@ function processUpgradeToAnnualPlan(req, res, next) { async function extendTrial(req, res) { const user = SessionManager.getSessionUser(req.session) - const { - subscription, - } = await LimitationsManager.promises.userHasV2Subscription(user) + const { subscription } = + await LimitationsManager.promises.userHasV2Subscription(user) try { await SubscriptionHandler.promises.extendTrial(subscription, 14) @@ -485,10 +481,11 @@ async function refreshUserFeatures(req, res) { async function redirectToHostedPage(req, res) { const userId = SessionManager.getLoggedInUserId(req.session) const { pageType } = req.params - const url = await SubscriptionViewModelBuilder.promises.getRedirectToHostedPage( - userId, - pageType - ) + const url = + await SubscriptionViewModelBuilder.promises.getRedirectToHostedPage( + userId, + pageType + ) logger.warn({ userId, pageType }, 'redirecting to recurly hosted page') res.redirect(url) } diff --git a/services/web/app/src/Features/Subscription/SubscriptionUpdater.js b/services/web/app/src/Features/Subscription/SubscriptionUpdater.js index c658012b79..8aecc0a437 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionUpdater.js +++ b/services/web/app/src/Features/Subscription/SubscriptionUpdater.js @@ -79,9 +79,8 @@ async function removeUserFromGroup(subscriptionId, userId) { } async function removeUserFromAllGroups(userId) { - const subscriptions = await SubscriptionLocator.promises.getMemberSubscriptions( - userId - ) + const subscriptions = + await SubscriptionLocator.promises.getMemberSubscriptions(userId) if (subscriptions.length === 0) { return } @@ -114,9 +113,8 @@ async function deleteSubscription(subscription, deleterData) { } async function restoreSubscription(subscriptionId) { - const deletedSubscription = await SubscriptionLocator.promises.getDeletedSubscription( - subscriptionId - ) + const deletedSubscription = + await SubscriptionLocator.promises.getDeletedSubscription(subscriptionId) const subscription = deletedSubscription.subscription // 1. upsert subscription @@ -249,9 +247,8 @@ async function updateSubscriptionFromRecurly( async function _sendUserGroupPlanCodeUserProperty(userId) { try { - const subscriptions = await SubscriptionLocator.promises.getMemberSubscriptions( - userId - ) + const subscriptions = + await SubscriptionLocator.promises.getMemberSubscriptions(userId) let bestPlanCode = null let bestFeatures = {} for (const subscription of subscriptions) { diff --git a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js index fa90149151..b715ed7ca0 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js +++ b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js @@ -21,9 +21,8 @@ async function getRedirectToHostedPage(userId, pageType) { if (!['billing-details', 'account-management'].includes(pageType)) { throw new InvalidError('unexpected page type') } - const personalSubscription = await SubscriptionLocator.promises.getUsersSubscription( - userId - ) + const personalSubscription = + await SubscriptionLocator.promises.getUsersSubscription(userId) const recurlySubscriptionId = personalSubscription?.recurlySubscription_id if (!recurlySubscriptionId) { throw new NotFoundError('not a recurly subscription') @@ -253,23 +252,27 @@ function buildUsersSubscriptionViewModel(user, callback) { const pendingSubscriptionTax = personalSubscription.recurly.taxRate * recurlySubscription.pending_subscription.unit_amount_in_cents - personalSubscription.recurly.price = SubscriptionFormatters.formatPrice( - recurlySubscription.pending_subscription.unit_amount_in_cents + - pendingAddOnPrice + - pendingAddOnTax + - pendingSubscriptionTax, - recurlySubscription.currency - ) + personalSubscription.recurly.price = + SubscriptionFormatters.formatPrice( + recurlySubscription.pending_subscription.unit_amount_in_cents + + pendingAddOnPrice + + pendingAddOnTax + + pendingSubscriptionTax, + recurlySubscription.currency + ) const pendingTotalLicenses = (pendingPlan.membersLimit || 0) + pendingAdditionalLicenses - personalSubscription.recurly.pendingAdditionalLicenses = pendingAdditionalLicenses - personalSubscription.recurly.pendingTotalLicenses = pendingTotalLicenses + personalSubscription.recurly.pendingAdditionalLicenses = + pendingAdditionalLicenses + personalSubscription.recurly.pendingTotalLicenses = + pendingTotalLicenses personalSubscription.pendingPlan = pendingPlan } else { - personalSubscription.recurly.price = SubscriptionFormatters.formatPrice( - recurlySubscription.unit_amount_in_cents + addOnPrice + tax, - recurlySubscription.currency - ) + personalSubscription.recurly.price = + SubscriptionFormatters.formatPrice( + recurlySubscription.unit_amount_in_cents + addOnPrice + tax, + recurlySubscription.currency + ) } } diff --git a/services/web/app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js b/services/web/app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js index 69f7f7a2ea..9e3cc3a6ab 100644 --- a/services/web/app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js +++ b/services/web/app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js @@ -7,8 +7,8 @@ const path = require('path') const request = require('request-promise-native') const settings = require('@overleaf/settings') -const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter') - .promises +const CollaboratorsGetter = + require('../Collaborators/CollaboratorsGetter').promises const UserGetter = require('../User/UserGetter.js').promises const tpdsUrl = _.get(settings, ['apis', 'thirdPartyDataStore', 'url']) @@ -149,10 +149,8 @@ async function enqueue(group, method, job) { async function getProjectUsersIds(projectId) { // get list of all user ids with access to project. project owner // will always be the first entry in the list. - const [ - ownerUserId, - ...invitedUserIds - ] = await CollaboratorsGetter.getInvitedMemberIds(projectId) + const [ownerUserId, ...invitedUserIds] = + await CollaboratorsGetter.getInvitedMemberIds(projectId) // if there are no invited users, always return the owner if (!invitedUserIds.length) { return [ownerUserId] diff --git a/services/web/app/src/Features/TokenAccess/TokenAccessController.js b/services/web/app/src/Features/TokenAccess/TokenAccessController.js index e9b8031788..6ece78fdc2 100644 --- a/services/web/app/src/Features/TokenAccess/TokenAccessController.js +++ b/services/web/app/src/Features/TokenAccess/TokenAccessController.js @@ -25,11 +25,12 @@ async function _userAlreadyHasHigherPrivilege( if (!Object.values(TokenAccessHandler.TOKEN_TYPES).includes(tokenType)) { throw new Error('bad token type') } - const privilegeLevel = await AuthorizationManager.promises.getPrivilegeLevelForProject( - userId, - projectId, - token - ) + const privilegeLevel = + await AuthorizationManager.promises.getPrivilegeLevelForProject( + userId, + projectId, + token + ) return ( orderedPrivilegeLevels.indexOf(privilegeLevel) >= orderedPrivilegeLevels.indexOf(tokenType) @@ -84,9 +85,8 @@ async function tokenAccessPage(req, res, next) { } try { if (TokenAccessHandler.isReadOnlyToken(token)) { - const docPublishedInfo = await TokenAccessHandler.promises.getV1DocPublishedInfo( - token - ) + const docPublishedInfo = + await TokenAccessHandler.promises.getV1DocPublishedInfo(token) if (docPublishedInfo.allow === false) { return res.redirect(302, docPublishedInfo.published_path) } @@ -135,9 +135,8 @@ async function checkAndGetProjectOrResponseAction( const projectId = project._id const isAnonymousUser = !userId - const tokenAccessEnabled = TokenAccessHandler.tokenAccessEnabledForProject( - project - ) + const tokenAccessEnabled = + TokenAccessHandler.tokenAccessEnabledForProject(project) if (isAnonymousUser && tokenAccessEnabled) { if (tokenType === TokenAccessHandler.TOKEN_TYPES.READ_AND_WRITE) { if (TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED) { @@ -260,9 +259,8 @@ async function grantTokenAccessReadOnly(req, res, next) { return res.sendStatus(400) } const tokenType = TokenAccessHandler.TOKEN_TYPES.READ_ONLY - const docPublishedInfo = await TokenAccessHandler.promises.getV1DocPublishedInfo( - token - ) + const docPublishedInfo = + await TokenAccessHandler.promises.getV1DocPublishedInfo(token) if (docPublishedInfo.allow === false) { return res.json({ redirect: docPublishedInfo.published_path }) } diff --git a/services/web/app/src/Features/Uploads/ProjectUploadManager.js b/services/web/app/src/Features/Uploads/ProjectUploadManager.js index 47a75799b1..dd70e6a9ee 100644 --- a/services/web/app/src/Features/Uploads/ProjectUploadManager.js +++ b/services/web/app/src/Features/Uploads/ProjectUploadManager.js @@ -29,12 +29,10 @@ module.exports = { async function createProjectFromZipArchive(ownerId, defaultName, zipPath) { const contentsPath = await _extractZip(zipPath) - const { - path, - content, - } = await ProjectRootDocManager.promises.findRootDocFileFromDirectory( - contentsPath - ) + const { path, content } = + await ProjectRootDocManager.promises.findRootDocFileFromDirectory( + contentsPath + ) const projectName = DocumentHelper.getTitleFromTexContent(content || '') || defaultName @@ -131,11 +129,12 @@ async function _initializeProjectWithZipContents( project._id, importEntries ) - const projectVersion = await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure( - project._id, - docEntries, - fileEntries - ) + const projectVersion = + await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure( + project._id, + docEntries, + fileEntries + ) await _notifyDocumentUpdater(project, ownerId, { newFiles: fileEntries, newDocs: docEntries, diff --git a/services/web/app/src/Features/User/SAMLIdentityManager.js b/services/web/app/src/Features/User/SAMLIdentityManager.js index 581071be70..8659bf84a1 100644 --- a/services/web/app/src/Features/User/SAMLIdentityManager.js +++ b/services/web/app/src/Features/User/SAMLIdentityManager.js @@ -223,9 +223,8 @@ async function getUser(providerId, externalUserId) { } async function redundantSubscription(userId, providerId, providerName) { - const subscription = await SubscriptionLocator.promises.getUserIndividualSubscription( - userId - ) + const subscription = + await SubscriptionLocator.promises.getUserIndividualSubscription(userId) if (subscription) { await NotificationsBuilder.promises diff --git a/services/web/app/src/Features/User/UserGetter.js b/services/web/app/src/Features/User/UserGetter.js index 798aa7ba80..e54e84b9fa 100644 --- a/services/web/app/src/Features/User/UserGetter.js +++ b/services/web/app/src/Features/User/UserGetter.js @@ -264,9 +264,8 @@ const decorateFullEmails = ( ) } - emailData.emailHasInstitutionLicence = InstitutionsHelper.emailHasLicence( - emailData - ) + emailData.emailHasInstitutionLicence = + InstitutionsHelper.emailHasLicence(emailData) }) return emailsData diff --git a/services/web/app/src/Features/User/UserSessionsManager.js b/services/web/app/src/Features/User/UserSessionsManager.js index e8839204b8..43f355b8b1 100644 --- a/services/web/app/src/Features/User/UserSessionsManager.js +++ b/services/web/app/src/Features/User/UserSessionsManager.js @@ -217,19 +217,20 @@ const UserSessionsManager = { return callback(err) } Async.series( - sessionKeys.map(key => next => - rclient.get(key, function (err, val) { - if (err) { - return next(err) - } - if (!val) { - rclient.srem(sessionSetKey, key, function (err, result) { + sessionKeys.map( + key => next => + rclient.get(key, function (err, val) { + if (err) { return next(err) - }) - } else { - next() - } - }) + } + if (!val) { + rclient.srem(sessionSetKey, key, function (err, result) { + return next(err) + }) + } else { + next() + } + }) ), function (err, results) { callback(err) diff --git a/services/web/app/src/Features/UserMembership/UserMembershipController.js b/services/web/app/src/Features/UserMembership/UserMembershipController.js index 43ffef3f4c..c106783e46 100644 --- a/services/web/app/src/Features/UserMembership/UserMembershipController.js +++ b/services/web/app/src/Features/UserMembership/UserMembershipController.js @@ -31,9 +31,8 @@ module.exports = { if (error != null) { return next(error) } - const entityPrimaryKey = entity[ - entityConfig.fields.primaryKey - ].toString() + const entityPrimaryKey = + entity[entityConfig.fields.primaryKey].toString() if (entityConfig.fields.name) { entityName = entity[entityConfig.fields.name] } diff --git a/services/web/app/src/Features/UserMembership/UserMembershipMiddleware.js b/services/web/app/src/Features/UserMembership/UserMembershipMiddleware.js index 76f9e8285b..d84730b927 100644 --- a/services/web/app/src/Features/UserMembership/UserMembershipMiddleware.js +++ b/services/web/app/src/Features/UserMembership/UserMembershipMiddleware.js @@ -198,10 +198,11 @@ function fetchEntityConfig(entityName) { // fetch the entity with id and config, and set it in the request function fetchEntity() { return expressify(async (req, res, next) => { - const entity = await UserMembershipHandler.promises.getEntityWithoutAuthorizationCheck( - req.params.id, - req.entityConfig - ) + const entity = + await UserMembershipHandler.promises.getEntityWithoutAuthorizationCheck( + req.params.id, + req.entityConfig + ) req.entity = entity next() }) diff --git a/services/web/app/src/infrastructure/Features.js b/services/web/app/src/infrastructure/Features.js index 72c10472fe..badfd40655 100644 --- a/services/web/app/src/infrastructure/Features.js +++ b/services/web/app/src/infrastructure/Features.js @@ -1,19 +1,16 @@ const _ = require('lodash') const Settings = require('@overleaf/settings') -const publicRegistrationModuleAvailable = Settings.moduleImportSequence.includes( - 'public-registration' -) +const publicRegistrationModuleAvailable = + Settings.moduleImportSequence.includes('public-registration') const supportModuleAvailable = Settings.moduleImportSequence.includes('support') -const historyV1ModuleAvailable = Settings.moduleImportSequence.includes( - 'history-v1' -) +const historyV1ModuleAvailable = + Settings.moduleImportSequence.includes('history-v1') -const trackChangesModuleAvailable = Settings.moduleImportSequence.includes( - 'track-changes' -) +const trackChangesModuleAvailable = + Settings.moduleImportSequence.includes('track-changes') /** * @typedef {Object} Settings diff --git a/services/web/app/src/infrastructure/Translations.js b/services/web/app/src/infrastructure/Translations.js index af92ca5f08..81f6905d8e 100644 --- a/services/web/app/src/infrastructure/Translations.js +++ b/services/web/app/src/infrastructure/Translations.js @@ -77,9 +77,8 @@ function setLangBasedOnDomainMiddleware(req, res, next) { // offering to switch to the appropriate library const detectedLanguageCode = headerLangDetector.detect(req, res) if (req.language !== detectedLanguageCode) { - res.locals.suggestedLanguageSubdomainConfig = subdomainConfigs.get( - detectedLanguageCode - ) + res.locals.suggestedLanguageSubdomainConfig = + subdomainConfigs.get(detectedLanguageCode) } // Decorate req.i18n with translate function alias for backwards diff --git a/services/web/frontend/js/directives/onEnter.js b/services/web/frontend/js/directives/onEnter.js index 7c99867ffc..ce6a66159a 100644 --- a/services/web/frontend/js/directives/onEnter.js +++ b/services/web/frontend/js/directives/onEnter.js @@ -7,11 +7,13 @@ */ import App from '../base' -export default App.directive('onEnter', () => (scope, element, attrs) => - element.bind('keydown keypress', function (event) { - if (event.which === 13) { - scope.$apply(() => scope.$eval(attrs.onEnter, { event })) - return event.preventDefault() - } - }) +export default App.directive( + 'onEnter', + () => (scope, element, attrs) => + element.bind('keydown keypress', function (event) { + if (event.which === 13) { + scope.$apply(() => scope.$eval(attrs.onEnter, { event })) + return event.preventDefault() + } + }) ) diff --git a/services/web/frontend/js/features/clone-project-modal/components/clone-project-modal-content.js b/services/web/frontend/js/features/clone-project-modal/components/clone-project-modal-content.js index 585ec3f180..6b71689816 100644 --- a/services/web/frontend/js/features/clone-project-modal/components/clone-project-modal-content.js +++ b/services/web/frontend/js/features/clone-project-modal/components/clone-project-modal-content.js @@ -27,9 +27,10 @@ export default function CloneProjectModalContent({ ) // valid if the cloned project has a name - const valid = useMemo(() => clonedProjectName.trim().length > 0, [ - clonedProjectName, - ]) + const valid = useMemo( + () => clonedProjectName.trim().length > 0, + [clonedProjectName] + ) // form submission: clone the project if the name is valid const handleSubmit = event => { diff --git a/services/web/frontend/js/features/editor-navigation-toolbar/components/editor-navigation-toolbar-root.js b/services/web/frontend/js/features/editor-navigation-toolbar/components/editor-navigation-toolbar-root.js index 3b51cebd9a..6bba84ca07 100644 --- a/services/web/frontend/js/features/editor-navigation-toolbar/components/editor-navigation-toolbar-root.js +++ b/services/web/frontend/js/features/editor-navigation-toolbar/components/editor-navigation-toolbar-root.js @@ -69,9 +69,8 @@ const EditorNavigationToolbarRoot = React.memo( pdfLayout, } = useLayoutContext(layoutContextPropTypes) - const { markMessagesAsRead, unreadMessageCount } = useChatContext( - chatContextPropTypes - ) + const { markMessagesAsRead, unreadMessageCount } = + useChatContext(chatContextPropTypes) const toggleChatOpen = useCallback(() => { if (!chatIsOpen) { diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.js b/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.js index 2e2ec06093..da980730ab 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.js +++ b/services/web/frontend/js/features/file-tree/components/file-tree-context-menu.js @@ -7,11 +7,8 @@ import { useFileTreeMainContext } from '../contexts/file-tree-main' import FileTreeItemMenuItems from './file-tree-item/file-tree-item-menu-items' function FileTreeContextMenu() { - const { - hasWritePermissions, - contextMenuCoords, - setContextMenuCoords, - } = useFileTreeMainContext() + const { hasWritePermissions, contextMenuCoords, setContextMenuCoords } = + useFileTreeMainContext() if (!hasWritePermissions || !contextMenuCoords) return null diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-import-from-project.js b/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-import-from-project.js index f71d69f3e1..e251fee737 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-import-from-project.js +++ b/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-import-from-project.js @@ -16,10 +16,8 @@ import ErrorMessage from '../error-message' export default function FileTreeImportFromProject() { const { t } = useTranslation() - const { - hasLinkedProjectFileFeature, - hasLinkedProjectOutputFileFeature, - } = window.ExposedSettings + const { hasLinkedProjectFileFeature, hasLinkedProjectOutputFileFeature } = + window.ExposedSettings const canSwitchOutputFilesMode = hasLinkedProjectFileFeature && hasLinkedProjectOutputFileFeature diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-name.js b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-name.js index 65a3472964..aadb1e1174 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-name.js +++ b/services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-name.js @@ -9,13 +9,8 @@ import { useFileTreeMainContext } from '../../contexts/file-tree-main' function FileTreeItemName({ name, isSelected, setIsDraggable }) { const { hasWritePermissions } = useFileTreeMainContext() - const { - isRenaming, - startRenaming, - finishRenaming, - error, - cancel, - } = useFileTreeActionable() + const { isRenaming, startRenaming, finishRenaming, error, cancel } = + useFileTreeActionable() const isRenamingEntity = isRenaming && isSelected && !error diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-toolbar.js b/services/web/frontend/js/features/file-tree/components/file-tree-toolbar.js index 9e53483d7d..c2fe3ff235 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-toolbar.js +++ b/services/web/frontend/js/features/file-tree/components/file-tree-toolbar.js @@ -63,12 +63,8 @@ function FileTreeToolbarLeft() { function FileTreeToolbarRight() { const { t } = useTranslation() - const { - canRename, - canDelete, - startRenaming, - startDeleting, - } = useFileTreeActionable() + const { canRename, canDelete, startRenaming, startDeleting } = + useFileTreeActionable() if (!canRename && !canDelete) { return null diff --git a/services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.js b/services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.js index cdffa65950..054d7fb664 100644 --- a/services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.js +++ b/services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.js @@ -18,13 +18,8 @@ function FileTreeModalCreateFolder() { const [name, setName] = useState('') const [validName, setValidName] = useState(true) - const { - isCreatingFolder, - inFlight, - finishCreatingFolder, - cancel, - error, - } = useFileTreeActionable() + const { isCreatingFolder, inFlight, finishCreatingFolder, cancel, error } = + useFileTreeActionable() if (!isCreatingFolder) return null // the modal will not be rendered; return early diff --git a/services/web/frontend/js/features/file-tree/controllers/file-tree-controller.js b/services/web/frontend/js/features/file-tree/controllers/file-tree-controller.js index 76d54bf508..31d0d048e8 100644 --- a/services/web/frontend/js/features/file-tree/controllers/file-tree-controller.js +++ b/services/web/frontend/js/features/file-tree/controllers/file-tree-controller.js @@ -5,116 +5,119 @@ import { cloneDeep } from 'lodash' import FileTreeRoot from '../components/file-tree-root' import { rootContext } from '../../../shared/context/root-context' -App.controller('ReactFileTreeController', function ( - $scope, - $timeout, - ide - // eventTracking -) { - $scope.projectId = ide.project_id - $scope.rootFolder = null - $scope.rootDocId = null - $scope.hasWritePermissions = false - $scope.isConnected = true +App.controller( + 'ReactFileTreeController', + function ( + $scope, + $timeout, + ide + // eventTracking + ) { + $scope.projectId = ide.project_id + $scope.rootFolder = null + $scope.rootDocId = null + $scope.hasWritePermissions = false + $scope.isConnected = true - $scope.$on('project:joined', () => { - $scope.rootFolder = $scope.project.rootFolder - $scope.rootDocId = $scope.project.rootDoc_id - $scope.$emit('file-tree:initialized') - }) - - $scope.$watch('permissions.write', hasWritePermissions => { - $scope.hasWritePermissions = hasWritePermissions - }) - - $scope.$watch('editor.open_doc_id', openDocId => { - window.dispatchEvent( - new CustomEvent('editor.openDoc', { detail: openDocId }) - ) - }) - - // Set isConnected to true if: - // - connection state is 'ready', OR - // - connection state is 'waitingCountdown' and reconnection_countdown is null - // The added complexity is needed because in Firefox on page reload the - // connection state goes into 'waitingCountdown' before being hidden and we - // don't want to show a disconnect UI. - function updateIsConnected() { - const isReady = $scope.connection.state === 'ready' - const willStartCountdown = - $scope.connection.state === 'waitingCountdown' && - $scope.connection.reconnection_countdown === null - $scope.isConnected = isReady || willStartCountdown - } - - $scope.$watch('connection.state', updateIsConnected) - $scope.$watch('connection.reconnection_countdown', updateIsConnected) - - $scope.onInit = () => { - // HACK: resize the vertical pane on init after a 0ms timeout. We do not - // understand why this is necessary but without this the resized handle is - // stuck at the bottom. The vertical resize will soon be migrated to React - // so we accept to live with this hack for now. - $timeout(() => { - $scope.$emit('left-pane-resize-all') + $scope.$on('project:joined', () => { + $scope.rootFolder = $scope.project.rootFolder + $scope.rootDocId = $scope.project.rootDoc_id + $scope.$emit('file-tree:initialized') }) - } - $scope.onSelect = selectedEntities => { - if (selectedEntities.length === 1) { - const selectedEntity = selectedEntities[0] - const type = - selectedEntity.type === 'fileRef' ? 'file' : selectedEntity.type - $scope.$emit('entity:selected', { - ...selectedEntity.entity, - id: selectedEntity.entity._id, - type, - }) + $scope.$watch('permissions.write', hasWritePermissions => { + $scope.hasWritePermissions = hasWritePermissions + }) - // in the react implementation there is no such concept as "1 - // multi-selected entity" so here we pass a count of 0 - $scope.$emit('entities:multiSelected', { count: 0 }) - } else if (selectedEntities.length > 1) { - $scope.$emit('entities:multiSelected', { - count: selectedEntities.length, + $scope.$watch('editor.open_doc_id', openDocId => { + window.dispatchEvent( + new CustomEvent('editor.openDoc', { detail: openDocId }) + ) + }) + + // Set isConnected to true if: + // - connection state is 'ready', OR + // - connection state is 'waitingCountdown' and reconnection_countdown is null + // The added complexity is needed because in Firefox on page reload the + // connection state goes into 'waitingCountdown' before being hidden and we + // don't want to show a disconnect UI. + function updateIsConnected() { + const isReady = $scope.connection.state === 'ready' + const willStartCountdown = + $scope.connection.state === 'waitingCountdown' && + $scope.connection.reconnection_countdown === null + $scope.isConnected = isReady || willStartCountdown + } + + $scope.$watch('connection.state', updateIsConnected) + $scope.$watch('connection.reconnection_countdown', updateIsConnected) + + $scope.onInit = () => { + // HACK: resize the vertical pane on init after a 0ms timeout. We do not + // understand why this is necessary but without this the resized handle is + // stuck at the bottom. The vertical resize will soon be migrated to React + // so we accept to live with this hack for now. + $timeout(() => { + $scope.$emit('left-pane-resize-all') }) - } else { - $scope.$emit('entity:no-selection') + } + + $scope.onSelect = selectedEntities => { + if (selectedEntities.length === 1) { + const selectedEntity = selectedEntities[0] + const type = + selectedEntity.type === 'fileRef' ? 'file' : selectedEntity.type + $scope.$emit('entity:selected', { + ...selectedEntity.entity, + id: selectedEntity.entity._id, + type, + }) + + // in the react implementation there is no such concept as "1 + // multi-selected entity" so here we pass a count of 0 + $scope.$emit('entities:multiSelected', { count: 0 }) + } else if (selectedEntities.length > 1) { + $scope.$emit('entities:multiSelected', { + count: selectedEntities.length, + }) + } else { + $scope.$emit('entity:no-selection') + } + } + + $scope.userHasFeature = feature => ide.$scope.user.features[feature] + + $scope.$watch('permissions.write', hasWritePermissions => { + $scope.hasWritePermissions = hasWritePermissions + }) + + $scope.refProviders = ide.$scope.user.refProviders || {} + + ide.$scope.$watch( + 'user.refProviders', + refProviders => { + $scope.refProviders = cloneDeep(refProviders) + }, + true + ) + + $scope.setRefProviderEnabled = provider => { + ide.$scope.$applyAsync(() => { + ide.$scope.user.refProviders[provider] = true + }) + } + + $scope.setStartedFreeTrial = started => { + $scope.$applyAsync(() => { + $scope.startedFreeTrial = started + }) + } + + $scope.reindexReferences = () => { + ide.$scope.$emit('references:should-reindex', {}) } } - - $scope.userHasFeature = feature => ide.$scope.user.features[feature] - - $scope.$watch('permissions.write', hasWritePermissions => { - $scope.hasWritePermissions = hasWritePermissions - }) - - $scope.refProviders = ide.$scope.user.refProviders || {} - - ide.$scope.$watch( - 'user.refProviders', - refProviders => { - $scope.refProviders = cloneDeep(refProviders) - }, - true - ) - - $scope.setRefProviderEnabled = provider => { - ide.$scope.$applyAsync(() => { - ide.$scope.user.refProviders[provider] = true - }) - } - - $scope.setStartedFreeTrial = started => { - $scope.$applyAsync(() => { - $scope.startedFreeTrial = started - }) - } - - $scope.reindexReferences = () => { - ide.$scope.$emit('references:should-reindex', {}) - } -}) +) App.component( 'fileTreeRoot', diff --git a/services/web/frontend/js/features/file-tree/hooks/file-tree-socket-listener.js b/services/web/frontend/js/features/file-tree/hooks/file-tree-socket-listener.js index daf335cf4c..3a1e8731b8 100644 --- a/services/web/frontend/js/features/file-tree/hooks/file-tree-socket-listener.js +++ b/services/web/frontend/js/features/file-tree/hooks/file-tree-socket-listener.js @@ -19,12 +19,8 @@ export function useFileTreeSocketListener() { dispatchCreateFile, fileTreeData, } = useFileTreeMutable() - const { - selectedEntityIds, - selectedEntityParentIds, - select, - unselect, - } = useFileTreeSelectable() + const { selectedEntityIds, selectedEntityParentIds, select, unselect } = + useFileTreeSelectable() const socket = window._ide && window._ide.socket const selectEntityIfCreatedByUser = useCallback( diff --git a/services/web/frontend/js/features/pdf-preview/components/detach-compile-button.js b/services/web/frontend/js/features/pdf-preview/components/detach-compile-button.js index da13d7eb0d..0f0ece8e1d 100644 --- a/services/web/frontend/js/features/pdf-preview/components/detach-compile-button.js +++ b/services/web/frontend/js/features/pdf-preview/components/detach-compile-button.js @@ -16,9 +16,10 @@ export function DetachCompileButton() { 'detached' ) - const handleStartCompile = useCallback(() => startOrTriggerCompile(), [ - startOrTriggerCompile, - ]) + const handleStartCompile = useCallback( + () => startOrTriggerCompile(), + [startOrTriggerCompile] + ) return (
{ if (showLogs) { diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.js b/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.js index ed38d76349..287ef6bd31 100644 --- a/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.js +++ b/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.js @@ -103,13 +103,8 @@ function PdfSynctexControls() { const { detachRole } = useLayoutContext() - const { - clsiServerId, - pdfUrl, - pdfViewer, - position, - setHighlights, - } = useCompileContext() + const { clsiServerId, pdfUrl, pdfViewer, position, setHighlights } = + useCompileContext() const [cursorPosition, setCursorPosition] = useState(() => { const position = localStorage.getItem( diff --git a/services/web/frontend/js/features/pdf-preview/hooks/use-compile-triggers.js b/services/web/frontend/js/features/pdf-preview/hooks/use-compile-triggers.js index 6c1c1982e1..a4765e5e2b 100644 --- a/services/web/frontend/js/features/pdf-preview/hooks/use-compile-triggers.js +++ b/services/web/frontend/js/features/pdf-preview/hooks/use-compile-triggers.js @@ -10,12 +10,8 @@ const showPdfDetach = getMeta('ol-showPdfDetach') const debugPdfDetach = getMeta('ol-debugPdfDetach') export default function useCompileTriggers() { - const { - startCompile, - setChangedAt, - cleanupCompileResult, - setError, - } = useCompileContext() + const { startCompile, setChangedAt, cleanupCompileResult, setError } = + useCompileContext() const { role: detachRole } = useDetachContext() // recompile on key press diff --git a/services/web/frontend/js/features/plans/group-plan-modal/index.js b/services/web/frontend/js/features/plans/group-plan-modal/index.js index 7a6af7b635..282dad6947 100644 --- a/services/web/frontend/js/features/plans/group-plan-modal/index.js +++ b/services/web/frontend/js/features/plans/group-plan-modal/index.js @@ -4,8 +4,9 @@ import * as eventTracking from '../../../infrastructure/event-tracking' function getFormValues() { const modalEl = document.querySelector('[data-ol-group-plan-modal]') - const planCode = modalEl.querySelector('input[name="plan_code"]:checked') - .value + const planCode = modalEl.querySelector( + 'input[name="plan_code"]:checked' + ).value const size = modalEl.querySelector('#size').value const currency = modalEl.querySelector('#currency').value const usage = modalEl.querySelector('#usage').checked @@ -32,9 +33,8 @@ function updateGroupPlanView() { modalEl.querySelectorAll('[data-ol-group-plan-usage]').forEach(el => { el.hidden = el.getAttribute('data-ol-group-plan-usage') !== usage }) - modalEl.querySelector( - '[data-ol-group-plan-display-price]' - ).innerText = displayPrice + modalEl.querySelector('[data-ol-group-plan-display-price]').innerText = + displayPrice modalEl.querySelector( '[data-ol-group-plan-price-per-user]' ).innerText = `${currencySymbol}${perUserPrice} per user` diff --git a/services/web/frontend/js/features/preview/components/preview-logs-pane-entry.js b/services/web/frontend/js/features/preview/components/preview-logs-pane-entry.js index 8f0ae3831b..31e2b0d1fc 100644 --- a/services/web/frontend/js/features/preview/components/preview-logs-pane-entry.js +++ b/services/web/frontend/js/features/preview/components/preview-logs-pane-entry.js @@ -58,14 +58,10 @@ function PreviewLogEntryContent({ formattedContent, extraInfoURL, }) { - const { - isExpanded, - needsExpandCollapse, - expandableProps, - toggleProps, - } = useExpandCollapse({ - collapsedSize: 150, - }) + const { isExpanded, needsExpandCollapse, expandableProps, toggleProps } = + useExpandCollapse({ + collapsedSize: 150, + }) const buttonContainerClasses = classNames( 'log-entry-content-button-container', diff --git a/services/web/frontend/js/features/preview/components/preview-pane.js b/services/web/frontend/js/features/preview/components/preview-pane.js index 1268d11dee..3da427263d 100644 --- a/services/web/frontend/js/features/preview/components/preview-pane.js +++ b/services/web/frontend/js/features/preview/components/preview-pane.js @@ -30,12 +30,10 @@ function PreviewPane({ const [lastCompileTimestamp, setLastCompileTimestamp] = useState( compilerState.lastCompileTimestamp ) - const [seenLogsForCurrentCompile, setSeenLogsForCurrentCompile] = useState( - false - ) - const [dismissedFirstErrorPopUp, setDismissedFirstErrorPopUp] = useState( - false - ) + const [seenLogsForCurrentCompile, setSeenLogsForCurrentCompile] = + useState(false) + const [dismissedFirstErrorPopUp, setDismissedFirstErrorPopUp] = + useState(false) if (lastCompileTimestamp < compilerState.lastCompileTimestamp) { setLastCompileTimestamp(compilerState.lastCompileTimestamp) diff --git a/services/web/frontend/js/features/share-project-modal/components/edit-member.js b/services/web/frontend/js/features/share-project-modal/components/edit-member.js index 5c6af53bb3..6c72f08da8 100644 --- a/services/web/frontend/js/features/share-project-modal/components/edit-member.js +++ b/services/web/frontend/js/features/share-project-modal/components/edit-member.js @@ -18,10 +18,8 @@ import { useProjectContext } from '../../../shared/context/project-context' export default function EditMember({ member }) { const [privileges, setPrivileges] = useState(member.privileges) - const [ - confirmingOwnershipTransfer, - setConfirmingOwnershipTransfer, - ] = useState(false) + const [confirmingOwnershipTransfer, setConfirmingOwnershipTransfer] = + useState(false) // update the local state if the member's privileges change externally useEffect(() => { diff --git a/services/web/frontend/js/features/share-project-modal/components/select-collaborators.js b/services/web/frontend/js/features/share-project-modal/components/select-collaborators.js index 1eb12ce2db..5c3b717aa0 100644 --- a/services/web/frontend/js/features/share-project-modal/components/select-collaborators.js +++ b/services/web/frontend/js/features/share-project-modal/components/select-collaborators.js @@ -10,7 +10,8 @@ import Icon from '../../../shared/components/icon' // Unicode characters in these Unicode groups: // "General Punctuation — Spaces" // "General Punctuation — Format character" (including zero-width spaces) -const matchAllSpaces = /[\u061C\u2000-\u200F\u202A-\u202E\u2060\u2066-\u2069\u2028\u2029\u202F]/g +const matchAllSpaces = + /[\u061C\u2000-\u200F\u202A-\u202E\u2060\u2066-\u2069\u2028\u2029\u202F]/g export default function SelectCollaborators({ loading, @@ -28,9 +29,10 @@ export default function SelectCollaborators({ const [inputValue, setInputValue] = useState('') - const selectedEmails = useMemo(() => selectedItems.map(item => item.email), [ - selectedItems, - ]) + const selectedEmails = useMemo( + () => selectedItems.map(item => item.email), + [selectedItems] + ) const unselectedOptions = useMemo( () => options.filter(option => !selectedEmails.includes(option.email)), diff --git a/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js b/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js index b2c2a8d1a2..b474bc10bf 100644 --- a/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js +++ b/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js @@ -124,9 +124,10 @@ const ShareProjectModal = React.memo(function ShareProjectModal({ }, []) // merge the new data with the old project data - const updateProject = useCallback(data => Object.assign(project, data), [ - project, - ]) + const updateProject = useCallback( + data => Object.assign(project, data), + [project] + ) if (!project) { return null diff --git a/services/web/frontend/js/ide/connection/ConnectionManager.js b/services/web/frontend/js/ide/connection/ConnectionManager.js index db21c0a4dd..95b1c6ed31 100644 --- a/services/web/frontend/js/ide/connection/ConnectionManager.js +++ b/services/web/frontend/js/ide/connection/ConnectionManager.js @@ -426,7 +426,8 @@ Something went wrong connecting to your project. Please refresh if this continue this.joinProjectRetryInterval < this.JOIN_PROJECT_MAX_RETRY_INTERVAL ) { - this.joinProjectRetryInterval += this.JOIN_PROJECT_RETRY_INTERVAL + this.joinProjectRetryInterval += + this.JOIN_PROJECT_RETRY_INTERVAL } return } else { diff --git a/services/web/frontend/js/ide/editor/ShareJsDoc.js b/services/web/frontend/js/ide/editor/ShareJsDoc.js index 42526f3253..0842dd11c2 100644 --- a/services/web/frontend/js/ide/editor/ShareJsDoc.js +++ b/services/web/frontend/js/ide/editor/ShareJsDoc.js @@ -335,10 +335,8 @@ export default ShareJsDoc = (function () { // end-to-end check for edits -> acks, for this very ShareJsdoc // This will catch a broken connection and missing UX-blocker for the // user, allowing them to keep editing. - this._detachEditorWatchdogManager = this.EditorWatchdogManager.attachToEditor( - editorName, - editor - ) + this._detachEditorWatchdogManager = + this.EditorWatchdogManager.attachToEditor(editorName, editor) } _attachToEditor(editorName, editor, attachToShareJs) { diff --git a/services/web/frontend/js/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.js b/services/web/frontend/js/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.js index b508ee159c..d3c28768e4 100644 --- a/services/web/frontend/js/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.js +++ b/services/web/frontend/js/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.js @@ -329,9 +329,8 @@ class AutoCompleteManager { ) ) // Delete back to command start, as appropriate - const commandStartIndex = Helpers.getLastCommandFragmentIndex( - lineUpToCursor - ) + const commandStartIndex = + Helpers.getLastCommandFragmentIndex(lineUpToCursor) if (commandStartIndex !== -1) { leftRange.start.column = commandStartIndex } else { @@ -351,9 +350,8 @@ class AutoCompleteManager { ) if (lineBeyondCursor) { - const partialCommandMatch = lineBeyondCursor.match( - /^([a-zA-Z0-9]+)\{/ - ) + const partialCommandMatch = + lineBeyondCursor.match(/^([a-zA-Z0-9]+)\{/) if (partialCommandMatch) { // We've got a partial command after the cursor const commandTail = partialCommandMatch[1] diff --git a/services/web/frontend/js/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.js b/services/web/frontend/js/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.js index 9e59e17d10..4610cccd00 100644 --- a/services/web/frontend/js/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.js +++ b/services/web/frontend/js/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.js @@ -20,7 +20,8 @@ const BLACKLISTED_COMMAND_REGEX = new RegExp( ) // Regex generated from /\\?['\p{L}]+/g via https://mothereff.in/regexpu. // \p{L} matches unicode characters in the 'letter' category, but is not supported until ES6. -const WORD_REGEX = /\\?(?:['A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D])+/g +const WORD_REGEX = + /\\?(?:['A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D])+/g const DEBOUNCE_DELAY = 500 const IGNORED_MISSPELLINGS = [ @@ -175,9 +176,8 @@ class SpellCheckManager { openContextMenu(e) { const coords = this.adapter.getCoordsFromContextMenuEvent(e) const highlight = this.adapter.getHighlightFromCoords(coords) - const shouldPositionFromBottom = this.adapter.isContextMenuEventOnBottomHalf( - e - ) + const shouldPositionFromBottom = + this.adapter.isContextMenuEventOnBottomHalf(e) if (highlight) { this.adapter.preventContextMenuEventDefault(e) this.adapter.selectHighlightedWord(highlight) diff --git a/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesAdapter.js b/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesAdapter.js index c6cb1211ed..123381558e 100644 --- a/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesAdapter.js +++ b/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesAdapter.js @@ -89,10 +89,8 @@ class TrackChangesAdapter { if (this.changeIdToMarkerIdMap[change.id] == null) { return } - const { - background_marker_id, - callout_marker_id, - } = this.changeIdToMarkerIdMap[change.id] + const { background_marker_id, callout_marker_id } = + this.changeIdToMarkerIdMap[change.id] delete this.changeIdToMarkerIdMap[change.id] const session = this.editor.getSession() session.removeMarker(background_marker_id) @@ -103,10 +101,8 @@ class TrackChangesAdapter { if (this.changeIdToMarkerIdMap[change.id] == null) { return } - const { - background_marker_id, - callout_marker_id, - } = this.changeIdToMarkerIdMap[change.id] + const { background_marker_id, callout_marker_id } = + this.changeIdToMarkerIdMap[change.id] delete this.changeIdToMarkerIdMap[change.id] const session = this.editor.getSession() @@ -166,10 +162,8 @@ class TrackChangesAdapter { onCommentRemoved(comment) { if (this.changeIdToMarkerIdMap[comment.id] != null) { // Resolved comments may not have marker ids - const { - background_marker_id, - callout_marker_id, - } = this.changeIdToMarkerIdMap[comment.id] + const { background_marker_id, callout_marker_id } = + this.changeIdToMarkerIdMap[comment.id] delete this.changeIdToMarkerIdMap[comment.id] const session = this.editor.getSession() session.removeMarker(background_marker_id) @@ -183,10 +177,8 @@ class TrackChangesAdapter { } const session = this.editor.getSession() const markers = session.getMarkers() - const { - background_marker_id, - callout_marker_id, - } = this.changeIdToMarkerIdMap[change_id] + const { background_marker_id, callout_marker_id } = + this.changeIdToMarkerIdMap[change_id] if (background_marker_id != null && markers[background_marker_id] != null) { const background_marker = markers[background_marker_id] background_marker.range.start = start diff --git a/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.js b/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.js index b9333b716d..a51ee00bb0 100644 --- a/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.js +++ b/services/web/frontend/js/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.js @@ -496,10 +496,8 @@ class TrackChangesManager { for (const change of Array.from(this.rangesTracker.changes)) { if (this.adapter.changeIdToMarkerIdMap[change.id] != null) { ;({ op } = change) - ;({ - background_marker_id, - callout_marker_id, - } = this.adapter.changeIdToMarkerIdMap[change.id]) + ;({ background_marker_id, callout_marker_id } = + this.adapter.changeIdToMarkerIdMap[change.id]) start = this.adapter.shareJsOffsetToRowColumn(op.p) if (op.i != null) { end = this.adapter.shareJsOffsetToRowColumn(op.p + op.i.length) @@ -521,10 +519,8 @@ class TrackChangesManager { for (const comment of Array.from(this.rangesTracker.comments)) { if (this.adapter.changeIdToMarkerIdMap[comment.id] != null) { - ;({ - background_marker_id, - callout_marker_id, - } = this.adapter.changeIdToMarkerIdMap[comment.id]) + ;({ background_marker_id, callout_marker_id } = + this.adapter.changeIdToMarkerIdMap[comment.id]) start = this.adapter.shareJsOffsetToRowColumn(comment.op.p) end = this.adapter.shareJsOffsetToRowColumn( comment.op.p + comment.op.c.length diff --git a/services/web/frontend/js/ide/history/HistoryManager.js b/services/web/frontend/js/ide/history/HistoryManager.js index 5924bd02be..a281d0797d 100644 --- a/services/web/frontend/js/ide/history/HistoryManager.js +++ b/services/web/frontend/js/ide/history/HistoryManager.js @@ -130,12 +130,8 @@ export default HistoryManager = (function () { reloadDiff() { let { diff } = this.$scope.history const { updates, doc } = this.$scope.history.selection - const { - fromV, - toV, - start_ts, - end_ts, - } = this._calculateRangeFromSelection() + const { fromV, toV, start_ts, end_ts } = + this._calculateRangeFromSelection() if (doc == null) { return @@ -269,9 +265,8 @@ export default HistoryManager = (function () { if (updates == null) { updates = [] } - let previousUpdate = this.$scope.history.updates[ - this.$scope.history.updates.length - 1 - ] + let previousUpdate = + this.$scope.history.updates[this.$scope.history.updates.length - 1] for (const update of Array.from(updates)) { update.pathnames = [] // Used for display diff --git a/services/web/frontend/js/ide/history/HistoryV2Manager.js b/services/web/frontend/js/ide/history/HistoryV2Manager.js index 2aa84b5bb3..183fad7944 100644 --- a/services/web/frontend/js/ide/history/HistoryV2Manager.js +++ b/services/web/frontend/js/ide/history/HistoryV2Manager.js @@ -323,8 +323,8 @@ export default HistoryManager = (function () { selectFile(file) { if (file != null && file.pathname != null) { - this.$scope.history.selection.pathname = this._previouslySelectedPathname = - file.pathname + this.$scope.history.selection.pathname = + this._previouslySelectedPathname = file.pathname this.$scope.history.selection.file = file if (this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME) { this.loadFileAtPointInTime() @@ -659,13 +659,13 @@ export default HistoryManager = (function () { _loadLabels(labels, lastUpdateToV) { const sortedLabels = this._sortLabelsByVersionAndDate(labels) - const labelsWithoutPseudoLabel = this._deletePseudoCurrentStateLabelIfExistent( - sortedLabels - ) - const labelsWithPseudoLabelIfNeeded = this._addPseudoCurrentStateLabelIfNeeded( - labelsWithoutPseudoLabel, - lastUpdateToV - ) + const labelsWithoutPseudoLabel = + this._deletePseudoCurrentStateLabelIfExistent(sortedLabels) + const labelsWithPseudoLabelIfNeeded = + this._addPseudoCurrentStateLabelIfNeeded( + labelsWithoutPseudoLabel, + lastUpdateToV + ) return labelsWithPseudoLabelIfNeeded } @@ -902,9 +902,8 @@ export default HistoryManager = (function () { if (updates == null) { updates = [] } - let previousUpdate = this.$scope.history.updates[ - this.$scope.history.updates.length - 1 - ] + let previousUpdate = + this.$scope.history.updates[this.$scope.history.updates.length - 1] const dateTimeNow = new Date() const timestamp24hoursAgo = dateTimeNow.setDate(dateTimeNow.getDate() - 1) let cutOffIndex = null diff --git a/services/web/frontend/js/ide/human-readable-logs/HumanReadableLogsRules.js b/services/web/frontend/js/ide/human-readable-logs/HumanReadableLogsRules.js index 19f8e5d020..3f7202e2fc 100644 --- a/services/web/frontend/js/ide/human-readable-logs/HumanReadableLogsRules.js +++ b/services/web/frontend/js/ide/human-readable-logs/HumanReadableLogsRules.js @@ -500,7 +500,8 @@ const rules = [ ruleId: 'hint_mismatched_environment2', types: ['environment'], cascadesFrom: ['environment'], - regexToMatch: /Error: `\\end\{([^\}]+)\}' expected but found `\\end\{([^\}]+)\}'.*/, + regexToMatch: + /Error: `\\end\{([^\}]+)\}' expected but found `\\end\{([^\}]+)\}'.*/, newMessage: 'Error: environments do not match: \\begin{$1} ... \\end{$2}', humanReadableHintComponent: ( <> @@ -516,7 +517,8 @@ const rules = [ ruleId: 'hint_mismatched_environment3', types: ['environment'], cascadesFrom: ['environment'], - regexToMatch: /Warning: No matching \\end found for `\\begin\{([^\}]+)\}'.*/, + regexToMatch: + /Warning: No matching \\end found for `\\begin\{([^\}]+)\}'.*/, newMessage: 'Warning: No matching \\end found for \\begin{$1}', humanReadableHintComponent: ( <> @@ -532,7 +534,8 @@ const rules = [ ruleId: 'hint_mismatched_environment4', types: ['environment'], cascadesFrom: ['environment'], - regexToMatch: /Error: Found `\\end\{([^\}]+)\}' without corresponding \\begin.*/, + regexToMatch: + /Error: Found `\\end\{([^\}]+)\}' without corresponding \\begin.*/, newMessage: 'Error: found \\end{$1} without a corresponding \\begin{$1}', humanReadableHintComponent: ( <> diff --git a/services/web/frontend/js/ide/log-parser/bib-log-parser.js b/services/web/frontend/js/ide/log-parser/bib-log-parser.js index 9068d82fc2..916e855da1 100644 --- a/services/web/frontend/js/ide/log-parser/bib-log-parser.js +++ b/services/web/frontend/js/ide/log-parser/bib-log-parser.js @@ -3,9 +3,12 @@ const LINE_SPLITTER_REGEX = /^\[(\d+)].*>\s(INFO|WARN|ERROR)\s-\s(.*)$/ const MULTILINE_WARNING_REGEX = /^Warning--(.+)\n--line (\d+) of file (.+)$/m const SINGLELINE_WARNING_REGEX = /^Warning--(.+)$/m -const MULTILINE_ERROR_REGEX = /^(.*)---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this entry$/m -const BAD_CROSS_REFERENCE_REGEX = /^(A bad cross reference---entry ".+?"\nrefers to entry.+?, which doesn't exist)$/m -const MULTILINE_COMMAND_ERROR_REGEX = /^(.*)\n?---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this command$/m +const MULTILINE_ERROR_REGEX = + /^(.*)---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this entry$/m +const BAD_CROSS_REFERENCE_REGEX = + /^(A bad cross reference---entry ".+?"\nrefers to entry.+?, which doesn't exist)$/m +const MULTILINE_COMMAND_ERROR_REGEX = + /^(.*)\n?---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this command$/m // Errors hit in BST file have a slightly different format const BST_ERROR_REGEX = /^(.*?)\nwhile executing---line (\d+) of file (.*)/m @@ -103,13 +106,8 @@ export default class BibLogParser { [ MULTILINE_ERROR_REGEX, function (match) { - const [ - fullMatch, - firstMessage, - lineNumber, - fileName, - secondMessage, - ] = match + const [fullMatch, firstMessage, lineNumber, fileName, secondMessage] = + match return { file: fileName, level: 'error', @@ -135,13 +133,8 @@ export default class BibLogParser { [ MULTILINE_COMMAND_ERROR_REGEX, function (match) { - const [ - fullMatch, - firstMessage, - lineNumber, - fileName, - secondMessage, - ] = match + const [fullMatch, firstMessage, lineNumber, fileName, secondMessage] = + match return { file: fileName, level: 'error', diff --git a/services/web/frontend/js/ide/pdfng/directives/pdfViewer.js b/services/web/frontend/js/ide/pdfng/directives/pdfViewer.js index 1ec5ed3a9c..4a3e2faead 100644 --- a/services/web/frontend/js/ide/pdfng/directives/pdfViewer.js +++ b/services/web/frontend/js/ide/pdfng/directives/pdfViewer.js @@ -620,8 +620,8 @@ export default App.directive('pdfViewer', ($q, $timeout, pdfSpinner) => ({ if (selection.rangeCount === 0) { return false } - const selectionAncestorNode = selection.getRangeAt(0) - .commonAncestorContainer + const selectionAncestorNode = + selection.getRangeAt(0).commonAncestorContainer return ( element.find(selectionAncestorNode).length > 0 || element.is(selectionAncestorNode) diff --git a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js index 3d50f115f3..a12e0e0a4e 100644 --- a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js +++ b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js @@ -150,9 +150,8 @@ export default App.controller( $scope.$watch('project.members', function (members) { $scope.reviewPanel.formattedProjectMembers = {} if (($scope.project != null ? $scope.project.owner : undefined) != null) { - $scope.reviewPanel.formattedProjectMembers[ - $scope.project.owner._id - ] = formatUser($scope.project.owner) + $scope.reviewPanel.formattedProjectMembers[$scope.project.owner._id] = + formatUser($scope.project.owner) } if ( ($scope.project != null ? $scope.project.members : undefined) != null @@ -170,9 +169,8 @@ export default App.controller( ) } result.push( - ($scope.reviewPanel.formattedProjectMembers[ - member._id - ] = formatUser(member)) + ($scope.reviewPanel.formattedProjectMembers[member._id] = + formatUser(member)) ) } else { result.push(undefined) @@ -900,8 +898,8 @@ export default App.controller( $scope.toggleFullTCStateCollapse = function () { if ($scope.project.features.trackChanges) { - return ($scope.reviewPanel.fullTCStateCollapsed = !$scope.reviewPanel - .fullTCStateCollapsed) + return ($scope.reviewPanel.fullTCStateCollapsed = + !$scope.reviewPanel.fullTCStateCollapsed) } else { _sendAnalytics() return $scope.openTrackChangesUpgradeModal() diff --git a/services/web/frontend/js/ide/review-panel/filters/notEmpty.js b/services/web/frontend/js/ide/review-panel/filters/notEmpty.js index 747d630ce7..7924c07082 100644 --- a/services/web/frontend/js/ide/review-panel/filters/notEmpty.js +++ b/services/web/frontend/js/ide/review-panel/filters/notEmpty.js @@ -6,6 +6,7 @@ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import App from '../../../base' -export default App.filter('notEmpty', () => object => - !angular.equals({}, object) +export default App.filter( + 'notEmpty', + () => object => !angular.equals({}, object) ) diff --git a/services/web/frontend/js/main/account-settings.js b/services/web/frontend/js/main/account-settings.js index 127dc36587..dfe4c919df 100644 --- a/services/web/frontend/js/main/account-settings.js +++ b/services/web/frontend/js/main/account-settings.js @@ -1,52 +1,55 @@ import App from '../base' -App.controller('AccountSettingsController', function ( - $scope, - $http, - $modal, - // eslint-disable-next-line camelcase - eventTracking, - UserAffiliationsDataService -) { - $scope.subscribed = true +App.controller( + 'AccountSettingsController', + function ( + $scope, + $http, + $modal, + // eslint-disable-next-line camelcase + eventTracking, + UserAffiliationsDataService + ) { + $scope.subscribed = true - $scope.unsubscribe = function () { - $scope.unsubscribing = true - return $http({ - method: 'DELETE', - url: '/user/newsletter/unsubscribe', - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - .then(function () { - $scope.unsubscribing = false - $scope.subscribed = false - }) - .catch(() => ($scope.unsubscribing = true)) - } - - $scope.deleteAccount = function () { - $modal.open({ - templateUrl: 'deleteAccountModalTemplate', - controller: 'DeleteAccountModalController', - resolve: { - userDefaultEmail() { - return UserAffiliationsDataService.getUserDefaultEmail() - .then( - defaultEmailDetails => - (defaultEmailDetails != null - ? defaultEmailDetails.email - : undefined) || null - ) - .catch(() => null) + $scope.unsubscribe = function () { + $scope.unsubscribing = true + return $http({ + method: 'DELETE', + url: '/user/newsletter/unsubscribe', + headers: { + 'X-CSRF-Token': window.csrfToken, }, - }, - }) - } + }) + .then(function () { + $scope.unsubscribing = false + $scope.subscribed = false + }) + .catch(() => ($scope.unsubscribing = true)) + } - $scope.upgradeIntegration = service => - eventTracking.send('subscription-funnel', 'settings-page', service) -}) + $scope.deleteAccount = function () { + $modal.open({ + templateUrl: 'deleteAccountModalTemplate', + controller: 'DeleteAccountModalController', + resolve: { + userDefaultEmail() { + return UserAffiliationsDataService.getUserDefaultEmail() + .then( + defaultEmailDetails => + (defaultEmailDetails != null + ? defaultEmailDetails.email + : undefined) || null + ) + .catch(() => null) + }, + }, + }) + } + + $scope.upgradeIntegration = service => + eventTracking.send('subscription-funnel', 'settings-page', service) + } +) App.controller( 'DeleteAccountModalController', diff --git a/services/web/frontend/js/main/affiliations/controllers/UserAffiliationsController.js b/services/web/frontend/js/main/affiliations/controllers/UserAffiliationsController.js index 9c6f955b81..728bce7c0e 100644 --- a/services/web/frontend/js/main/affiliations/controllers/UserAffiliationsController.js +++ b/services/web/frontend/js/main/affiliations/controllers/UserAffiliationsController.js @@ -41,7 +41,8 @@ export default App.controller( const ONE_WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000 const LOCAL_AND_DOMAIN_REGEX = /([^@]+)@(.+)/ - const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\ ".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA -Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + const EMAIL_REGEX = + /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\ ".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA -Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const _matchLocalAndDomain = function (userEmailInput) { const match = userEmailInput @@ -84,9 +85,10 @@ export default App.controller( $scope.ui.isBlacklistedEmail = false $scope.ui.showManualUniversitySelectionUI = false if (userInputLocalAndDomain.domain) { - $scope.ui.isBlacklistedEmail = UserAffiliationsDataService.isDomainBlacklisted( - userInputLocalAndDomain.domain - ) + $scope.ui.isBlacklistedEmail = + UserAffiliationsDataService.isDomainBlacklisted( + userInputLocalAndDomain.domain + ) return UserAffiliationsDataService.getUniversityDomainFromPartialDomainInput( userInputLocalAndDomain.domain ) @@ -100,9 +102,8 @@ export default App.controller( ) { $scope.newAffiliation.university = universityDomain.university $scope.newAffiliation.department = universityDomain.department - $scope.newAffiliation.ssoAvailable = _ssoAvailableForDomain( - universityDomain - ) + $scope.newAffiliation.ssoAvailable = + _ssoAvailableForDomain(universityDomain) } else { _resetAffiliationSuggestion() } @@ -175,13 +176,14 @@ export default App.controller( ) } else { if ($scope.newAffiliation.university.isUserSuggested) { - addEmailPromise = UserAffiliationsDataService.addUserAffiliationWithUnknownUniversity( - $scope.newAffiliation.email, - $scope.newAffiliation.university.name, - $scope.newAffiliation.country.code, - $scope.newAffiliation.role, - $scope.newAffiliation.department - ) + addEmailPromise = + UserAffiliationsDataService.addUserAffiliationWithUnknownUniversity( + $scope.newAffiliation.email, + $scope.newAffiliation.university.name, + $scope.newAffiliation.country.code, + $scope.newAffiliation.role, + $scope.newAffiliation.department + ) } else { addEmailPromise = UserAffiliationsDataService.addUserAffiliation( $scope.newAffiliation.email, diff --git a/services/web/frontend/js/main/project-list/project-list.js b/services/web/frontend/js/main/project-list/project-list.js index 6489ef8255..a68008da5f 100644 --- a/services/web/frontend/js/main/project-list/project-list.js +++ b/services/web/frontend/js/main/project-list/project-list.js @@ -1,857 +1,865 @@ import _ from 'lodash' import App from '../../base' import './services/project-list' -App.controller('ProjectPageController', function ( - $scope, - $modal, - $window, - queuedHttp, - eventTracking, // eslint-disable-line camelcase - $timeout, - localStorage, - ProjectListService -) { - $scope.projects = window.data.projects - $scope.tags = window.data.tags - $scope.notifications = window.data.notifications - $scope.notificationsInstitution = window.data.notificationsInstitution - $scope.allSelected = false - $scope.selectedProjects = [] - $scope.filter = 'all' - $scope.predicate = 'lastUpdated' - $scope.nUntagged = 0 - $scope.reverse = true - $scope.searchText = { value: '' } - $scope.$watch('predicate', function (newValue) { - $scope.comparator = - newValue === 'ownerName' ? ownerNameComparator : defaultComparator - }) - - $scope.shouldShowSurveyLink = true - - if (localStorage('dismissed-2021-future-survey') === true) { - $scope.shouldShowSurveyLink = false - } - - $scope.dismissSurvey = () => { - localStorage('dismissed-2021-future-survey', true) - $scope.shouldShowSurveyLink = false - } - - $timeout(() => recalculateProjectListHeight(), 10) - - $scope.$watch( - () => - $scope.projects.filter( - project => - (project.tags == null || project.tags.length === 0) && - !project.archived && - !project.trashed - ).length, - newVal => ($scope.nUntagged = newVal) - ) - - function recalculateProjectListHeight() { - const $projListCard = $('.project-list-card') - if (!$projListCard || !$projListCard.offset()) return - - const topOffset = $projListCard.offset().top - const cardPadding = $projListCard.outerHeight() - $projListCard.height() - const bottomOffset = $('footer').outerHeight() - const height = $window.innerHeight - topOffset - bottomOffset - cardPadding - $scope.projectListHeight = height - } - - function defaultComparator(v1, v2) { - let result = 0 - const type1 = v1.type - const type2 = v2.type - - if ($scope.predicate === 'ownerName') { - return - } - - if (type1 === type2) { - let value1 = v1.value - let value2 = v2.value - - if (type1 === 'string') { - // Compare strings case-insensitively - value1 = value1.toLowerCase() - value2 = value2.toLowerCase() - } else if (type1 === 'object') { - // For basic objects, use the position of the object - // in the collection instead of the value - if (angular.isObject(value1)) value1 = v1.index - if (angular.isObject(value2)) value2 = v2.index - } - - if (value1 !== value2) { - result = value1 < value2 ? -1 : 1 - } - } else { - result = type1 < type2 ? -1 : 1 - } - - return result - } - - function ownerNameComparator(v1, v2) { - if ($scope.predicate !== 'ownerName') { - return - } - if (v1.value === 'You') { - if (v2.value === 'You') { - return v1.index < v2.index ? -1 : 1 - } else { - return 1 - } - } else if (v1.value === 'An Overleaf v1 User' || v1.value === 'None') { - if (v2.value === 'An Overleaf v1 User' || v2.value === 'None') { - return v1.index < v2.index ? -1 : 1 - } else { - return -1 - } - } else { - if (v2.value === 'You') { - return -1 - } else if (v2.value === 'An Overleaf v1 User' || v2.value === 'None') { - return 1 - } else { - return v1.value > v2.value ? -1 : 1 - } - } - } - - angular.element($window).bind('resize', function () { - recalculateProjectListHeight() - $scope.$apply() - }) - - $scope.$on('project-list:notifications-received', () => - $scope.$applyAsync(() => recalculateProjectListHeight()) - ) - - // Allow tags to be accessed on projects as well - const projectsById = {} - for (const project of $scope.projects) { - projectsById[project.id] = project - } - - $scope.getProjectById = id => projectsById[id] - - for (const tag of $scope.tags) { - for (const projectId of tag.project_ids || []) { - const project = projectsById[projectId] - if (project) { - if (!project.tags) { - project.tags = [] - } - project.tags.push(tag) - } - } - } - - $scope.changePredicate = function (newPredicate) { - if ($scope.predicate === newPredicate) { - $scope.reverse = !$scope.reverse - } - $scope.predicate = newPredicate - } - - $scope.getSortIconClass = function (column) { - if (column === $scope.predicate && $scope.reverse) { - return 'fa-caret-down' - } else if (column === $scope.predicate && !$scope.reverse) { - return 'fa-caret-up' - } else { - return '' - } - } - - $scope.searchProjects = function () { - eventTracking.send( - 'project-list-page-interaction', - 'project-search', - 'keydown' - ) - $scope.updateVisibleProjects() - } - - $scope.clearSearchText = function () { - $scope.searchText.value = '' +App.controller( + 'ProjectPageController', + function ( + $scope, + $modal, + $window, + queuedHttp, + eventTracking, // eslint-disable-line camelcase + $timeout, + localStorage, + ProjectListService + ) { + $scope.projects = window.data.projects + $scope.tags = window.data.tags + $scope.notifications = window.data.notifications + $scope.notificationsInstitution = window.data.notificationsInstitution + $scope.allSelected = false + $scope.selectedProjects = [] $scope.filter = 'all' - $scope.$emit('search:clear') - $scope.updateVisibleProjects() - } + $scope.predicate = 'lastUpdated' + $scope.nUntagged = 0 + $scope.reverse = true + $scope.searchText = { value: '' } + $scope.$watch('predicate', function (newValue) { + $scope.comparator = + newValue === 'ownerName' ? ownerNameComparator : defaultComparator + }) - $scope.setFilter = function (filter) { - $scope.filter = filter - $scope.updateVisibleProjects() - } + $scope.shouldShowSurveyLink = true - $scope.updateSelectedProjects = function () { - $scope.selectedProjects = $scope.projects.filter( - project => project.selected - ) - } + if (localStorage('dismissed-2021-future-survey') === true) { + $scope.shouldShowSurveyLink = false + } - $scope.getSelectedProjects = () => $scope.selectedProjects + $scope.dismissSurvey = () => { + localStorage('dismissed-2021-future-survey', true) + $scope.shouldShowSurveyLink = false + } - $scope.getSelectedProjectIds = () => - $scope.selectedProjects.map(project => project.id) + $timeout(() => recalculateProjectListHeight(), 10) - $scope.getFirstSelectedProject = () => $scope.selectedProjects[0] - - $scope.hasLeavableProjectsSelected = () => - _.some( - $scope.getSelectedProjects(), - project => project.accessLevel !== 'owner' && project.trashed + $scope.$watch( + () => + $scope.projects.filter( + project => + (project.tags == null || project.tags.length === 0) && + !project.archived && + !project.trashed + ).length, + newVal => ($scope.nUntagged = newVal) ) - $scope.hasDeletableProjectsSelected = () => - _.some( - $scope.getSelectedProjects(), - project => project.accessLevel === 'owner' && project.trashed + function recalculateProjectListHeight() { + const $projListCard = $('.project-list-card') + if (!$projListCard || !$projListCard.offset()) return + + const topOffset = $projListCard.offset().top + const cardPadding = $projListCard.outerHeight() - $projListCard.height() + const bottomOffset = $('footer').outerHeight() + const height = + $window.innerHeight - topOffset - bottomOffset - cardPadding + $scope.projectListHeight = height + } + + function defaultComparator(v1, v2) { + let result = 0 + const type1 = v1.type + const type2 = v2.type + + if ($scope.predicate === 'ownerName') { + return + } + + if (type1 === type2) { + let value1 = v1.value + let value2 = v2.value + + if (type1 === 'string') { + // Compare strings case-insensitively + value1 = value1.toLowerCase() + value2 = value2.toLowerCase() + } else if (type1 === 'object') { + // For basic objects, use the position of the object + // in the collection instead of the value + if (angular.isObject(value1)) value1 = v1.index + if (angular.isObject(value2)) value2 = v2.index + } + + if (value1 !== value2) { + result = value1 < value2 ? -1 : 1 + } + } else { + result = type1 < type2 ? -1 : 1 + } + + return result + } + + function ownerNameComparator(v1, v2) { + if ($scope.predicate !== 'ownerName') { + return + } + if (v1.value === 'You') { + if (v2.value === 'You') { + return v1.index < v2.index ? -1 : 1 + } else { + return 1 + } + } else if (v1.value === 'An Overleaf v1 User' || v1.value === 'None') { + if (v2.value === 'An Overleaf v1 User' || v2.value === 'None') { + return v1.index < v2.index ? -1 : 1 + } else { + return -1 + } + } else { + if (v2.value === 'You') { + return -1 + } else if (v2.value === 'An Overleaf v1 User' || v2.value === 'None') { + return 1 + } else { + return v1.value > v2.value ? -1 : 1 + } + } + } + + angular.element($window).bind('resize', function () { + recalculateProjectListHeight() + $scope.$apply() + }) + + $scope.$on('project-list:notifications-received', () => + $scope.$applyAsync(() => recalculateProjectListHeight()) ) - $scope.updateVisibleProjects = function () { - $scope.visibleProjects = [] - const selectedTag = $scope.getSelectedTag() + // Allow tags to be accessed on projects as well + const projectsById = {} for (const project of $scope.projects) { - let visible = true - // Only show if it matches any search text - if ($scope.searchText.value !== '') { + projectsById[project.id] = project + } + + $scope.getProjectById = id => projectsById[id] + + for (const tag of $scope.tags) { + for (const projectId of tag.project_ids || []) { + const project = projectsById[projectId] + if (project) { + if (!project.tags) { + project.tags = [] + } + project.tags.push(tag) + } + } + } + + $scope.changePredicate = function (newPredicate) { + if ($scope.predicate === newPredicate) { + $scope.reverse = !$scope.reverse + } + $scope.predicate = newPredicate + } + + $scope.getSortIconClass = function (column) { + if (column === $scope.predicate && $scope.reverse) { + return 'fa-caret-down' + } else if (column === $scope.predicate && !$scope.reverse) { + return 'fa-caret-up' + } else { + return '' + } + } + + $scope.searchProjects = function () { + eventTracking.send( + 'project-list-page-interaction', + 'project-search', + 'keydown' + ) + $scope.updateVisibleProjects() + } + + $scope.clearSearchText = function () { + $scope.searchText.value = '' + $scope.filter = 'all' + $scope.$emit('search:clear') + $scope.updateVisibleProjects() + } + + $scope.setFilter = function (filter) { + $scope.filter = filter + $scope.updateVisibleProjects() + } + + $scope.updateSelectedProjects = function () { + $scope.selectedProjects = $scope.projects.filter( + project => project.selected + ) + } + + $scope.getSelectedProjects = () => $scope.selectedProjects + + $scope.getSelectedProjectIds = () => + $scope.selectedProjects.map(project => project.id) + + $scope.getFirstSelectedProject = () => $scope.selectedProjects[0] + + $scope.hasLeavableProjectsSelected = () => + _.some( + $scope.getSelectedProjects(), + project => project.accessLevel !== 'owner' && project.trashed + ) + + $scope.hasDeletableProjectsSelected = () => + _.some( + $scope.getSelectedProjects(), + project => project.accessLevel === 'owner' && project.trashed + ) + + $scope.updateVisibleProjects = function () { + $scope.visibleProjects = [] + const selectedTag = $scope.getSelectedTag() + for (const project of $scope.projects) { + let visible = true + // Only show if it matches any search text + if ($scope.searchText.value !== '') { + if ( + project.name + .toLowerCase() + .indexOf($scope.searchText.value.toLowerCase()) === -1 + ) { + visible = false + } + } + // Only show if it matches the selected tag if ( - project.name - .toLowerCase() - .indexOf($scope.searchText.value.toLowerCase()) === -1 + $scope.filter === 'tag' && + selectedTag != null && + !selectedTag.project_ids.includes(project.id) ) { visible = false } - } - // Only show if it matches the selected tag - if ( - $scope.filter === 'tag' && - selectedTag != null && - !selectedTag.project_ids.includes(project.id) - ) { - visible = false - } - // Hide tagged projects if we only want to see the uncategorized ones - if ( - $scope.filter === 'untagged' && - (project.tags != null ? project.tags.length : undefined) > 0 - ) { - visible = false - } - - // Hide projects we own if we only want to see shared projects - if ($scope.filter === 'shared' && project.accessLevel === 'owner') { - visible = false - } - - // Hide projects we don't own if we only want to see owned projects - if ($scope.filter === 'owned' && project.accessLevel !== 'owner') { - visible = false - } - - if ($scope.filter === 'archived') { - // Only show archived projects - if (!project.archived) { + // Hide tagged projects if we only want to see the uncategorized ones + if ( + $scope.filter === 'untagged' && + (project.tags != null ? project.tags.length : undefined) > 0 + ) { visible = false } - } else { - // Only show non-archived projects - if (project.archived) { + + // Hide projects we own if we only want to see shared projects + if ($scope.filter === 'shared' && project.accessLevel === 'owner') { visible = false } + + // Hide projects we don't own if we only want to see owned projects + if ($scope.filter === 'owned' && project.accessLevel !== 'owner') { + visible = false + } + + if ($scope.filter === 'archived') { + // Only show archived projects + if (!project.archived) { + visible = false + } + } else { + // Only show non-archived projects + if (project.archived) { + visible = false + } + } + + if ($scope.filter === 'trashed') { + // Only show trashed projects + if (!project.trashed) { + visible = false + } + } else { + // Only show non-trashed projects + if (project.trashed) { + visible = false + } + } + + if (visible) { + $scope.visibleProjects.push(project) + } else { + // We don't want hidden selections + project.selected = false + } } - if ($scope.filter === 'trashed') { - // Only show trashed projects - if (!project.trashed) { - visible = false + localStorage( + 'project_list', + JSON.stringify({ + filter: $scope.filter, + selectedTagId: selectedTag != null ? selectedTag._id : undefined, + }) + ) + $scope.updateSelectedProjects() + } + + $scope.getSelectedTag = function () { + for (const tag of $scope.tags) { + if (tag.selected) { + return tag } - } else { - // Only show non-trashed projects - if (project.trashed) { - visible = false + } + return null + } + + $scope._removeProjectIdsFromTagArray = function (tag, removeProjectIds) { + // Remove project_id from tag.project_ids + const remainingProjectIds = [] + const removedProjectIds = [] + for (const projectId of tag.project_ids) { + if (!removeProjectIds.includes(projectId)) { + remainingProjectIds.push(projectId) + } else { + removedProjectIds.push(projectId) + } + } + tag.project_ids = remainingProjectIds + return removedProjectIds + } + + $scope._removeProjectFromList = function (project) { + const index = $scope.projects.indexOf(project) + if (index > -1) { + $scope.projects.splice(index, 1) + } + } + + $scope.removeSelectedProjectsFromTag = function (tag) { + tag.showWhenEmpty = true + + const selectedProjectIds = $scope.getSelectedProjectIds() + const selectedProjects = $scope.getSelectedProjects() + + const removedProjectIds = $scope._removeProjectIdsFromTagArray( + tag, + selectedProjectIds + ) + + // Remove tag from project.tags + for (const project of selectedProjects) { + if (!project.tags) { + project.tags = [] + } + const index = project.tags.indexOf(tag) + if (index > -1) { + project.tags.splice(index, 1) } } - if (visible) { - $scope.visibleProjects.push(project) - } else { - // We don't want hidden selections - project.selected = false + for (const projectId of removedProjectIds) { + queuedHttp({ + method: 'DELETE', + url: `/tag/${tag._id}/project/${projectId}`, + headers: { + 'X-CSRF-Token': window.csrfToken, + }, + }) } + + // If we're filtering by this tag then we need to remove + // the projects from view + $scope.updateVisibleProjects() } - localStorage( - 'project_list', - JSON.stringify({ - filter: $scope.filter, - selectedTagId: selectedTag != null ? selectedTag._id : undefined, - }) - ) - $scope.updateSelectedProjects() - } + $scope.removeProjectFromTag = function (project, tag) { + tag.showWhenEmpty = true - $scope.getSelectedTag = function () { - for (const tag of $scope.tags) { - if (tag.selected) { - return tag - } - } - return null - } - - $scope._removeProjectIdsFromTagArray = function (tag, removeProjectIds) { - // Remove project_id from tag.project_ids - const remainingProjectIds = [] - const removedProjectIds = [] - for (const projectId of tag.project_ids) { - if (!removeProjectIds.includes(projectId)) { - remainingProjectIds.push(projectId) - } else { - removedProjectIds.push(projectId) - } - } - tag.project_ids = remainingProjectIds - return removedProjectIds - } - - $scope._removeProjectFromList = function (project) { - const index = $scope.projects.indexOf(project) - if (index > -1) { - $scope.projects.splice(index, 1) - } - } - - $scope.removeSelectedProjectsFromTag = function (tag) { - tag.showWhenEmpty = true - - const selectedProjectIds = $scope.getSelectedProjectIds() - const selectedProjects = $scope.getSelectedProjects() - - const removedProjectIds = $scope._removeProjectIdsFromTagArray( - tag, - selectedProjectIds - ) - - // Remove tag from project.tags - for (const project of selectedProjects) { if (!project.tags) { project.tags = [] } const index = project.tags.indexOf(tag) + if (index > -1) { + $scope._removeProjectIdsFromTagArray(tag, [project.id]) project.tags.splice(index, 1) + queuedHttp({ + method: 'DELETE', + url: `/tag/${tag._id}/project/${project.id}`, + headers: { + 'X-CSRF-Token': window.csrfToken, + }, + }) + $scope.updateVisibleProjects() } } - for (const projectId of removedProjectIds) { - queuedHttp({ - method: 'DELETE', - url: `/tag/${tag._id}/project/${projectId}`, + $scope.addSelectedProjectsToTag = function (tag) { + const selectedProjects = $scope.getSelectedProjects() + eventTracking.send( + 'project-list-page-interaction', + 'project action', + 'addSelectedProjectsToTag' + ) + + // Add project_ids into tag.project_ids + const addedProjectIds = [] + for (const projectId of $scope.getSelectedProjectIds()) { + if (!tag.project_ids.includes(projectId)) { + tag.project_ids.push(projectId) + addedProjectIds.push(projectId) + } + } + + // Add tag into each project.tags + for (const project of selectedProjects) { + if (!project.tags) { + project.tags = [] + } + if (!project.tags.includes(tag)) { + project.tags.push(tag) + } + } + + for (const projectId of addedProjectIds) { + queuedHttp.post(`/tag/${tag._id}/project/${projectId}`, { + _csrf: window.csrfToken, + }) + } + } + + $scope.openNewTagModal = function (e) { + const modalInstance = $modal.open({ + templateUrl: 'newTagModalTemplate', + controller: 'NewTagModalController', + }) + + modalInstance.result.then(function (tag) { + const tagIsDuplicate = $scope.tags.find(function (existingTag) { + return tag.name === existingTag.name + }) + + if (!tagIsDuplicate) { + $scope.tags.push(tag) + $scope.addSelectedProjectsToTag(tag) + } + }) + } + + $scope.createProject = function (name, template) { + if (template == null) { + template = 'none' + } + return queuedHttp + .post('/project/new', { + _csrf: window.csrfToken, + projectName: name, + template, + }) + .then(function (response) { + const { data } = response + $scope.projects.push({ + name, + id: data.project_id, + accessLevel: 'owner', + owner: data.owner, + // TODO: Check access level if correct after adding it in + // to the rest of the app + }) + $scope.updateVisibleProjects() + }) + } + + $scope.openCreateProjectModal = function (template) { + if (template == null) { + template = 'none' + } + eventTracking.send( + 'project-list-page-interaction', + 'new-project', + template + ) + const modalInstance = $modal.open({ + templateUrl: 'newProjectModalTemplate', + controller: 'NewProjectModalController', + resolve: { + template() { + return template + }, + }, + scope: $scope, + }) + + modalInstance.result.then( + projectId => (window.location = `/project/${projectId}`) + ) + } + + $scope.renameProject = (project, newName) => + queuedHttp + .post(`/project/${project.id}/rename`, { + newProjectName: newName, + _csrf: window.csrfToken, + }) + .then(() => (project.name = newName)) + + $scope.openRenameProjectModal = function () { + const project = $scope.getFirstSelectedProject() + if (!project || project.accessLevel !== 'owner') { + return + } + eventTracking.send( + 'project-list-page-interaction', + 'project action', + 'Rename' + ) + $modal.open({ + templateUrl: 'renameProjectModalTemplate', + controller: 'RenameProjectModalController', + resolve: { + project() { + return project + }, + }, + scope: $scope, + }) + } + + $scope.cloneProject = function (project, cloneName) { + eventTracking.send( + 'project-list-page-interaction', + 'project action', + 'Clone' + ) + return queuedHttp + .post(`/project/${project.id}/clone`, { + _csrf: window.csrfToken, + projectName: cloneName, + }) + .then(function (response) { + const { data } = response + $scope.projects.push({ + name: data.name, + id: data.project_id, + accessLevel: 'owner', + owner: data.owner, + // TODO: Check access level if correct after adding it in + // to the rest of the app + }) + $scope.updateVisibleProjects() + }) + } + + $scope.openCloneProjectModal = function (project) { + if (!project) { + return + } + + $modal.open({ + templateUrl: 'cloneProjectModalTemplate', + controller: 'CloneProjectModalController', + resolve: { + project() { + return project + }, + }, + scope: $scope, + }) + } + + // Methods to create modals for archiving, trashing, leaving and deleting projects + const _createArchiveTrashLeaveOrDeleteProjectsModal = function ( + action, + projects + ) { + eventTracking.send( + 'project-list-page-interaction', + 'project action', + action + ) + return $modal.open({ + templateUrl: 'archiveTrashLeaveOrDeleteProjectsModalTemplate', + controller: 'ArchiveTrashLeaveOrDeleteProjectsModalController', + resolve: { + projects() { + return projects + }, + action() { + return action + }, + }, + }) + } + + $scope.createArchiveProjectsModal = function (projects) { + return _createArchiveTrashLeaveOrDeleteProjectsModal('archive', projects) + } + + $scope.createTrashProjectsModal = function (projects) { + return _createArchiveTrashLeaveOrDeleteProjectsModal('trash', projects) + } + + $scope.createLeaveProjectsModal = function (projects) { + return _createArchiveTrashLeaveOrDeleteProjectsModal('leave', projects) + } + + $scope.createDeleteProjectsModal = function (projects) { + return _createArchiveTrashLeaveOrDeleteProjectsModal('delete', projects) + } + + $scope.createLeaveOrDeleteProjectsModal = function (projects) { + return _createArchiveTrashLeaveOrDeleteProjectsModal( + 'leaveOrDelete', + projects + ) + } + + // + $scope.openArchiveProjectsModal = function () { + const modalInstance = $scope.createArchiveProjectsModal( + $scope.getSelectedProjects() + ) + modalInstance.result.then(() => $scope.archiveSelectedProjects()) + } + + $scope.openTrashProjectsModal = function () { + const modalInstance = $scope.createTrashProjectsModal( + $scope.getSelectedProjects() + ) + + modalInstance.result.then(() => $scope.trashSelectedProjects()) + } + + $scope.openLeaveProjectsModal = function () { + const modalInstance = $scope.createLeaveProjectsModal( + $scope.getSelectedProjects() + ) + modalInstance.result.then(() => $scope.leaveSelectedProjects()) + } + + $scope.openDeleteProjectsModal = function () { + const modalInstance = $scope.createDeleteProjectsModal( + $scope.getSelectedProjects() + ) + modalInstance.result.then(() => $scope.deleteSelectedProjects()) + } + + $scope.openLeaveOrDeleteProjectsModal = function () { + const modalInstance = $scope.createLeaveOrDeleteProjectsModal( + $scope.getSelectedProjects() + ) + modalInstance.result.then(() => $scope.leaveOrDeleteSelectedProjects()) + } + + // + $scope.archiveSelectedProjects = () => + $scope.archiveProjects($scope.getSelectedProjects()) + + $scope.unarchiveSelectedProjects = () => + $scope.unarchiveProjects($scope.getSelectedProjects()) + + $scope.trashSelectedProjects = () => + $scope.trashProjects($scope.getSelectedProjects()) + + $scope.untrashSelectedProjects = () => + $scope.untrashProjects($scope.getSelectedProjects()) + + $scope.leaveSelectedProjects = () => + $scope.leaveProjects($scope.getSelectedProjects()) + + $scope.deleteSelectedProjects = () => + $scope.deleteProjects($scope.getSelectedProjects()) + + $scope.leaveOrDeleteSelectedProjects = () => + $scope.leaveOrDeleteProjects($scope.getSelectedProjects()) + + // + $scope.archiveProjects = function (projects) { + for (const project of projects) { + project.archived = true + project.trashed = false + _archiveProject(project) + } + $scope.updateVisibleProjects() + } + + $scope.unarchiveProjects = function (projects) { + for (const project of projects) { + project.archived = false + _unarchiveProject(project) + } + $scope.updateVisibleProjects() + } + + $scope.trashProjects = function (projects) { + for (const project of projects) { + project.trashed = true + project.archived = false + _trashProject(project) + } + $scope.updateVisibleProjects() + } + + $scope.untrashProjects = function (projects) { + for (const project of projects) { + project.trashed = false + _untrashProject(project) + } + $scope.updateVisibleProjects() + } + + $scope.leaveProjects = function (projects) { + _deleteOrLeaveProjectsLocally(projects) + for (const project of projects) { + _leaveProject(project) + } + $scope.updateVisibleProjects() + } + + $scope.deleteProjects = function (projects) { + _deleteOrLeaveProjectsLocally(projects) + for (const project of projects) { + _deleteProject(project) + } + $scope.updateVisibleProjects() + } + + $scope.leaveOrDeleteProjects = function (projects) { + _deleteOrLeaveProjectsLocally(projects) + for (const project of projects) { + if (project.accessLevel === 'owner') { + _deleteProject(project) + } else { + _leaveProject(project) + } + } + $scope.updateVisibleProjects() + } + + // Actual interaction with the backend---we could move this into a service + const _archiveProject = function (project) { + return queuedHttp({ + method: 'POST', + url: `/project/${project.id}/archive`, headers: { 'X-CSRF-Token': window.csrfToken, }, }) } - // If we're filtering by this tag then we need to remove - // the projects from view - $scope.updateVisibleProjects() - } - - $scope.removeProjectFromTag = function (project, tag) { - tag.showWhenEmpty = true - - if (!project.tags) { - project.tags = [] - } - const index = project.tags.indexOf(tag) - - if (index > -1) { - $scope._removeProjectIdsFromTagArray(tag, [project.id]) - project.tags.splice(index, 1) - queuedHttp({ + const _unarchiveProject = function (project) { + return queuedHttp({ method: 'DELETE', - url: `/tag/${tag._id}/project/${project.id}`, + url: `/project/${project.id}/archive`, headers: { 'X-CSRF-Token': window.csrfToken, }, }) + } + + const _trashProject = function (project) { + return queuedHttp({ + method: 'POST', + url: `/project/${project.id}/trash`, + headers: { + 'X-CSRF-Token': window.csrfToken, + }, + }) + } + + const _untrashProject = function (project) { + return queuedHttp({ + method: 'DELETE', + url: `/project/${project.id}/trash`, + headers: { + 'X-CSRF-Token': window.csrfToken, + }, + }) + } + + const _leaveProject = function (project) { + return queuedHttp({ + method: 'POST', + url: `/project/${project.id}/leave`, + headers: { + 'X-CSRF-Token': window.csrfToken, + }, + }) + } + + const _deleteProject = function (project) { + return queuedHttp({ + method: 'DELETE', + url: `/project/${project.id}`, + headers: { + 'X-CSRF-Token': window.csrfToken, + }, + }) + } + + const _deleteOrLeaveProjectsLocally = function (projects) { + const projectIds = projects.map(p => p.id) + for (const tag of $scope.tags || []) { + $scope._removeProjectIdsFromTagArray(tag, projectIds) + } + for (const project of projects || []) { + $scope._removeProjectFromList(project) + } + } + + $scope.getValueForCurrentPredicate = function (project) { + if ($scope.predicate === 'ownerName') { + return ProjectListService.getOwnerName(project) + } else { + return project[$scope.predicate] + } + } + + $scope.openUploadProjectModal = function () { + $modal.open({ + templateUrl: 'uploadProjectModalTemplate', + controller: 'UploadProjectModalController', + }) + } + + $scope.downloadSelectedProjects = () => + $scope.downloadProjectsById($scope.getSelectedProjectIds()) + + $scope.downloadProjectsById = function (projectIds) { + let path + eventTracking.send( + 'project-list-page-interaction', + 'project action', + 'Download Zip' + ) + if (projectIds.length > 1) { + path = `/project/download/zip?project_ids=${projectIds.join(',')}` + } else { + path = `/project/${projectIds[0]}/download/zip` + } + return (window.location = path) + } + + const markTagAsSelected = id => { + for (const tag of $scope.tags) { + if (tag._id === id) { + tag.selected = true + } else { + tag.selected = false + } + } + } + + const storedUIOpts = JSON.parse(localStorage('project_list')) + + if (storedUIOpts && storedUIOpts.filter) { + if (storedUIOpts.filter === 'tag' && storedUIOpts.selectedTagId) { + markTagAsSelected(storedUIOpts.selectedTagId) + } + $scope.setFilter(storedUIOpts.filter) + } else { $scope.updateVisibleProjects() } } - - $scope.addSelectedProjectsToTag = function (tag) { - const selectedProjects = $scope.getSelectedProjects() - eventTracking.send( - 'project-list-page-interaction', - 'project action', - 'addSelectedProjectsToTag' - ) - - // Add project_ids into tag.project_ids - const addedProjectIds = [] - for (const projectId of $scope.getSelectedProjectIds()) { - if (!tag.project_ids.includes(projectId)) { - tag.project_ids.push(projectId) - addedProjectIds.push(projectId) - } - } - - // Add tag into each project.tags - for (const project of selectedProjects) { - if (!project.tags) { - project.tags = [] - } - if (!project.tags.includes(tag)) { - project.tags.push(tag) - } - } - - for (const projectId of addedProjectIds) { - queuedHttp.post(`/tag/${tag._id}/project/${projectId}`, { - _csrf: window.csrfToken, - }) - } - } - - $scope.openNewTagModal = function (e) { - const modalInstance = $modal.open({ - templateUrl: 'newTagModalTemplate', - controller: 'NewTagModalController', - }) - - modalInstance.result.then(function (tag) { - const tagIsDuplicate = $scope.tags.find(function (existingTag) { - return tag.name === existingTag.name - }) - - if (!tagIsDuplicate) { - $scope.tags.push(tag) - $scope.addSelectedProjectsToTag(tag) - } - }) - } - - $scope.createProject = function (name, template) { - if (template == null) { - template = 'none' - } - return queuedHttp - .post('/project/new', { - _csrf: window.csrfToken, - projectName: name, - template, - }) - .then(function (response) { - const { data } = response - $scope.projects.push({ - name, - id: data.project_id, - accessLevel: 'owner', - owner: data.owner, - // TODO: Check access level if correct after adding it in - // to the rest of the app - }) - $scope.updateVisibleProjects() - }) - } - - $scope.openCreateProjectModal = function (template) { - if (template == null) { - template = 'none' - } - eventTracking.send('project-list-page-interaction', 'new-project', template) - const modalInstance = $modal.open({ - templateUrl: 'newProjectModalTemplate', - controller: 'NewProjectModalController', - resolve: { - template() { - return template - }, - }, - scope: $scope, - }) - - modalInstance.result.then( - projectId => (window.location = `/project/${projectId}`) - ) - } - - $scope.renameProject = (project, newName) => - queuedHttp - .post(`/project/${project.id}/rename`, { - newProjectName: newName, - _csrf: window.csrfToken, - }) - .then(() => (project.name = newName)) - - $scope.openRenameProjectModal = function () { - const project = $scope.getFirstSelectedProject() - if (!project || project.accessLevel !== 'owner') { - return - } - eventTracking.send( - 'project-list-page-interaction', - 'project action', - 'Rename' - ) - $modal.open({ - templateUrl: 'renameProjectModalTemplate', - controller: 'RenameProjectModalController', - resolve: { - project() { - return project - }, - }, - scope: $scope, - }) - } - - $scope.cloneProject = function (project, cloneName) { - eventTracking.send( - 'project-list-page-interaction', - 'project action', - 'Clone' - ) - return queuedHttp - .post(`/project/${project.id}/clone`, { - _csrf: window.csrfToken, - projectName: cloneName, - }) - .then(function (response) { - const { data } = response - $scope.projects.push({ - name: data.name, - id: data.project_id, - accessLevel: 'owner', - owner: data.owner, - // TODO: Check access level if correct after adding it in - // to the rest of the app - }) - $scope.updateVisibleProjects() - }) - } - - $scope.openCloneProjectModal = function (project) { - if (!project) { - return - } - - $modal.open({ - templateUrl: 'cloneProjectModalTemplate', - controller: 'CloneProjectModalController', - resolve: { - project() { - return project - }, - }, - scope: $scope, - }) - } - - // Methods to create modals for archiving, trashing, leaving and deleting projects - const _createArchiveTrashLeaveOrDeleteProjectsModal = function ( - action, - projects - ) { - eventTracking.send( - 'project-list-page-interaction', - 'project action', - action - ) - return $modal.open({ - templateUrl: 'archiveTrashLeaveOrDeleteProjectsModalTemplate', - controller: 'ArchiveTrashLeaveOrDeleteProjectsModalController', - resolve: { - projects() { - return projects - }, - action() { - return action - }, - }, - }) - } - - $scope.createArchiveProjectsModal = function (projects) { - return _createArchiveTrashLeaveOrDeleteProjectsModal('archive', projects) - } - - $scope.createTrashProjectsModal = function (projects) { - return _createArchiveTrashLeaveOrDeleteProjectsModal('trash', projects) - } - - $scope.createLeaveProjectsModal = function (projects) { - return _createArchiveTrashLeaveOrDeleteProjectsModal('leave', projects) - } - - $scope.createDeleteProjectsModal = function (projects) { - return _createArchiveTrashLeaveOrDeleteProjectsModal('delete', projects) - } - - $scope.createLeaveOrDeleteProjectsModal = function (projects) { - return _createArchiveTrashLeaveOrDeleteProjectsModal( - 'leaveOrDelete', - projects - ) - } - - // - $scope.openArchiveProjectsModal = function () { - const modalInstance = $scope.createArchiveProjectsModal( - $scope.getSelectedProjects() - ) - modalInstance.result.then(() => $scope.archiveSelectedProjects()) - } - - $scope.openTrashProjectsModal = function () { - const modalInstance = $scope.createTrashProjectsModal( - $scope.getSelectedProjects() - ) - - modalInstance.result.then(() => $scope.trashSelectedProjects()) - } - - $scope.openLeaveProjectsModal = function () { - const modalInstance = $scope.createLeaveProjectsModal( - $scope.getSelectedProjects() - ) - modalInstance.result.then(() => $scope.leaveSelectedProjects()) - } - - $scope.openDeleteProjectsModal = function () { - const modalInstance = $scope.createDeleteProjectsModal( - $scope.getSelectedProjects() - ) - modalInstance.result.then(() => $scope.deleteSelectedProjects()) - } - - $scope.openLeaveOrDeleteProjectsModal = function () { - const modalInstance = $scope.createLeaveOrDeleteProjectsModal( - $scope.getSelectedProjects() - ) - modalInstance.result.then(() => $scope.leaveOrDeleteSelectedProjects()) - } - - // - $scope.archiveSelectedProjects = () => - $scope.archiveProjects($scope.getSelectedProjects()) - - $scope.unarchiveSelectedProjects = () => - $scope.unarchiveProjects($scope.getSelectedProjects()) - - $scope.trashSelectedProjects = () => - $scope.trashProjects($scope.getSelectedProjects()) - - $scope.untrashSelectedProjects = () => - $scope.untrashProjects($scope.getSelectedProjects()) - - $scope.leaveSelectedProjects = () => - $scope.leaveProjects($scope.getSelectedProjects()) - - $scope.deleteSelectedProjects = () => - $scope.deleteProjects($scope.getSelectedProjects()) - - $scope.leaveOrDeleteSelectedProjects = () => - $scope.leaveOrDeleteProjects($scope.getSelectedProjects()) - - // - $scope.archiveProjects = function (projects) { - for (const project of projects) { - project.archived = true - project.trashed = false - _archiveProject(project) - } - $scope.updateVisibleProjects() - } - - $scope.unarchiveProjects = function (projects) { - for (const project of projects) { - project.archived = false - _unarchiveProject(project) - } - $scope.updateVisibleProjects() - } - - $scope.trashProjects = function (projects) { - for (const project of projects) { - project.trashed = true - project.archived = false - _trashProject(project) - } - $scope.updateVisibleProjects() - } - - $scope.untrashProjects = function (projects) { - for (const project of projects) { - project.trashed = false - _untrashProject(project) - } - $scope.updateVisibleProjects() - } - - $scope.leaveProjects = function (projects) { - _deleteOrLeaveProjectsLocally(projects) - for (const project of projects) { - _leaveProject(project) - } - $scope.updateVisibleProjects() - } - - $scope.deleteProjects = function (projects) { - _deleteOrLeaveProjectsLocally(projects) - for (const project of projects) { - _deleteProject(project) - } - $scope.updateVisibleProjects() - } - - $scope.leaveOrDeleteProjects = function (projects) { - _deleteOrLeaveProjectsLocally(projects) - for (const project of projects) { - if (project.accessLevel === 'owner') { - _deleteProject(project) - } else { - _leaveProject(project) - } - } - $scope.updateVisibleProjects() - } - - // Actual interaction with the backend---we could move this into a service - const _archiveProject = function (project) { - return queuedHttp({ - method: 'POST', - url: `/project/${project.id}/archive`, - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - } - - const _unarchiveProject = function (project) { - return queuedHttp({ - method: 'DELETE', - url: `/project/${project.id}/archive`, - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - } - - const _trashProject = function (project) { - return queuedHttp({ - method: 'POST', - url: `/project/${project.id}/trash`, - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - } - - const _untrashProject = function (project) { - return queuedHttp({ - method: 'DELETE', - url: `/project/${project.id}/trash`, - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - } - - const _leaveProject = function (project) { - return queuedHttp({ - method: 'POST', - url: `/project/${project.id}/leave`, - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - } - - const _deleteProject = function (project) { - return queuedHttp({ - method: 'DELETE', - url: `/project/${project.id}`, - headers: { - 'X-CSRF-Token': window.csrfToken, - }, - }) - } - - const _deleteOrLeaveProjectsLocally = function (projects) { - const projectIds = projects.map(p => p.id) - for (const tag of $scope.tags || []) { - $scope._removeProjectIdsFromTagArray(tag, projectIds) - } - for (const project of projects || []) { - $scope._removeProjectFromList(project) - } - } - - $scope.getValueForCurrentPredicate = function (project) { - if ($scope.predicate === 'ownerName') { - return ProjectListService.getOwnerName(project) - } else { - return project[$scope.predicate] - } - } - - $scope.openUploadProjectModal = function () { - $modal.open({ - templateUrl: 'uploadProjectModalTemplate', - controller: 'UploadProjectModalController', - }) - } - - $scope.downloadSelectedProjects = () => - $scope.downloadProjectsById($scope.getSelectedProjectIds()) - - $scope.downloadProjectsById = function (projectIds) { - let path - eventTracking.send( - 'project-list-page-interaction', - 'project action', - 'Download Zip' - ) - if (projectIds.length > 1) { - path = `/project/download/zip?project_ids=${projectIds.join(',')}` - } else { - path = `/project/${projectIds[0]}/download/zip` - } - return (window.location = path) - } - - const markTagAsSelected = id => { - for (const tag of $scope.tags) { - if (tag._id === id) { - tag.selected = true - } else { - tag.selected = false - } - } - } - - const storedUIOpts = JSON.parse(localStorage('project_list')) - - if (storedUIOpts && storedUIOpts.filter) { - if (storedUIOpts.filter === 'tag' && storedUIOpts.selectedTagId) { - markTagAsSelected(storedUIOpts.selectedTagId) - } - $scope.setFilter(storedUIOpts.filter) - } else { - $scope.updateVisibleProjects() - } -}) +) App.controller( 'ProjectListItemController', diff --git a/services/web/frontend/js/shared/context/compile-context.js b/services/web/frontend/js/shared/context/compile-context.js index 8b805eaa9c..b78723c42e 100644 --- a/services/web/frontend/js/shared/context/compile-context.js +++ b/services/web/frontend/js/shared/context/compile-context.js @@ -87,9 +87,8 @@ export function CompileProvider({ children }) { const [pdfViewer] = useScopeValue('settings.pdfViewer') // the URL for downloading the PDF - const [pdfDownloadUrl, setPdfDownloadUrl] = useScopeValueSetterOnly( - 'pdf.downloadUrl' - ) + const [pdfDownloadUrl, setPdfDownloadUrl] = + useScopeValueSetterOnly('pdf.downloadUrl') // the URL for loading the PDF in the preview pane const [pdfUrl, setPdfUrl] = useScopeValueSetterOnly('pdf.url') diff --git a/services/web/frontend/js/shared/context/layout-context.js b/services/web/frontend/js/shared/context/layout-context.js index c075bd01f8..76aa29b59d 100644 --- a/services/web/frontend/js/shared/context/layout-context.js +++ b/services/web/frontend/js/shared/context/layout-context.js @@ -66,9 +66,8 @@ export function LayoutProvider({ children }) { const [chatIsOpen, setChatIsOpen] = useScopeValue('ui.chatOpen') // whether the review pane is open - const [reviewPanelOpen, setReviewPanelOpen] = useScopeValue( - 'ui.reviewPanelOpen' - ) + const [reviewPanelOpen, setReviewPanelOpen] = + useScopeValue('ui.reviewPanelOpen') // whether the menu pane is open const [leftMenuShown, setLeftMenuShown] = useScopeValue('ui.leftMenuShown') diff --git a/services/web/frontend/js/shared/hooks/use-detach-action.js b/services/web/frontend/js/shared/hooks/use-detach-action.js index 2c479304ef..e9376d85ab 100644 --- a/services/web/frontend/js/shared/hooks/use-detach-action.js +++ b/services/web/frontend/js/shared/hooks/use-detach-action.js @@ -10,12 +10,8 @@ export default function useDetachAction( senderRole, targetRole ) { - const { - role, - broadcastEvent, - addEventHandler, - deleteEventHandler, - } = useDetachContext() + const { role, broadcastEvent, addEventHandler, deleteEventHandler } = + useDetachContext() const eventName = `action-${actionName}` diff --git a/services/web/frontend/js/shared/hooks/use-detach-layout.js b/services/web/frontend/js/shared/hooks/use-detach-layout.js index 1b96c55a42..b864deb0b0 100644 --- a/services/web/frontend/js/shared/hooks/use-detach-layout.js +++ b/services/web/frontend/js/shared/hooks/use-detach-layout.js @@ -11,13 +11,8 @@ const LINKING_TIMEOUT = 60000 const RELINK_TIMEOUT = 10000 export default function useDetachLayout() { - const { - role, - setRole, - broadcastEvent, - addEventHandler, - deleteEventHandler, - } = useDetachContext() + const { role, setRole, broadcastEvent, addEventHandler, deleteEventHandler } = + useDetachContext() // isLinking: when the tab expects to be linked soon (e.g. on detach) const [isLinking, setIsLinking] = useState(false) diff --git a/services/web/frontend/js/shared/hooks/use-detach-state.js b/services/web/frontend/js/shared/hooks/use-detach-state.js index 924bf778bc..e8f9aeec54 100644 --- a/services/web/frontend/js/shared/hooks/use-detach-state.js +++ b/services/web/frontend/js/shared/hooks/use-detach-state.js @@ -12,12 +12,8 @@ export default function useDetachState( ) { const [value, setValue] = useState(defaultValue) - const { - role, - broadcastEvent, - addEventHandler, - deleteEventHandler, - } = useDetachContext() + const { role, broadcastEvent, addEventHandler, deleteEventHandler } = + useDetachContext() const eventName = `state-${key}` diff --git a/services/web/frontend/stories/modals/create-file/create-file-modal-decorator.js b/services/web/frontend/stories/modals/create-file/create-file-modal-decorator.js index aa2f27c819..811ffb836d 100644 --- a/services/web/frontend/stories/modals/create-file/create-file-modal-decorator.js +++ b/services/web/frontend/stories/modals/create-file/create-file-modal-decorator.js @@ -98,23 +98,22 @@ export const mockCreateFileModalFetch = fetchMock => return 204 }) -export const createFileModalDecorator = ( - contextProps = {}, - createMode = 'doc' +export const createFileModalDecorator = + (contextProps = {}, createMode = 'doc') => // eslint-disable-next-line react/display-name -) => Story => { - return ( - - - - - - - - - - ) -} + Story => { + return ( + + + + + + + + + + ) + } function OpenCreateFileModal({ children, createMode }) { const { startCreatingFile } = useFileTreeActionable() diff --git a/services/web/migrations/20190912145032_create_users_indexes.js b/services/web/migrations/20190912145032_create_users_indexes.js index 341022c612..b8b5c7e10b 100644 --- a/services/web/migrations/20190912145032_create_users_indexes.js +++ b/services/web/migrations/20190912145032_create_users_indexes.js @@ -48,8 +48,7 @@ const indexes = [ 'thirdPartyIdentifiers.externalUserId': 1, 'thirdPartyIdentifiers.providerId': 1, }, - name: - 'thirdPartyIdentifiers.externalUserId_1_thirdPartyIdentifiers.providerId_1', + name: 'thirdPartyIdentifiers.externalUserId_1_thirdPartyIdentifiers.providerId_1', sparse: true, }, { diff --git a/services/web/modules/launchpad/test/unit/src/LaunchpadControllerTests.js b/services/web/modules/launchpad/test/unit/src/LaunchpadControllerTests.js index 18aed24770..1f4e53dafc 100644 --- a/services/web/modules/launchpad/test/unit/src/LaunchpadControllerTests.js +++ b/services/web/modules/launchpad/test/unit/src/LaunchpadControllerTests.js @@ -33,12 +33,16 @@ describe('LaunchpadController', function () { requires: { '@overleaf/settings': (this.Settings = {}), '@overleaf/metrics': (this.Metrics = {}), - '../../../../app/src/Features/User/UserRegistrationHandler': (this.UserRegistrationHandler = {}), - '../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler = {}), + '../../../../app/src/Features/User/UserRegistrationHandler': + (this.UserRegistrationHandler = {}), + '../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler = + {}), '../../../../app/src/Features/User/UserGetter': (this.UserGetter = {}), '../../../../app/src/models/User': { User: this.User }, - '../../../../app/src/Features/Authentication/AuthenticationController': (this.AuthenticationController = {}), - '../../../../app/src/Features/Authentication/SessionManager': (this.SessionManager = {}), + '../../../../app/src/Features/Authentication/AuthenticationController': + (this.AuthenticationController = {}), + '../../../../app/src/Features/Authentication/SessionManager': + (this.SessionManager = {}), }, }) diff --git a/services/web/modules/user-activate/test/unit/src/UserActivateControllerTests.js b/services/web/modules/user-activate/test/unit/src/UserActivateControllerTests.js index 23d4b9cef5..bc68c9276b 100644 --- a/services/web/modules/user-activate/test/unit/src/UserActivateControllerTests.js +++ b/services/web/modules/user-activate/test/unit/src/UserActivateControllerTests.js @@ -21,8 +21,8 @@ describe('UserActivateController', function () { this.UserActivateController = SandboxedModule.require(MODULE_PATH, { requires: { '../../../../app/src/Features/User/UserGetter': this.UserGetter, - '../../../../app/src/Features/Errors/ErrorController': this - .ErrorController, + '../../../../app/src/Features/Errors/ErrorController': + this.ErrorController, }, }) this.req = { diff --git a/services/web/package-lock.json b/services/web/package-lock.json index 97bda4ce75..63b70e4051 100644 --- a/services/web/package-lock.json +++ b/services/web/package-lock.json @@ -7644,6 +7644,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", @@ -10606,6 +10612,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", @@ -31176,9 +31188,9 @@ "dev": true }, "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true }, "pretty-error": { diff --git a/services/web/package.json b/services/web/package.json index 35ba819426..a76ab80650 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -270,7 +270,7 @@ "optimize-css-assets-webpack-plugin": "^5.0.3", "pirates": "^4.0.1", "postcss-loader": "^3.0.0", - "prettier": "^2.2.1", + "prettier": "^2.5.1", "requirejs": "^2.3.6", "samlp": "^3.4.1", "sandboxed-module": "^2.0.4", diff --git a/services/web/scripts/clear_institution_notifications.js b/services/web/scripts/clear_institution_notifications.js index 052e3624a4..1627a5ed3d 100644 --- a/services/web/scripts/clear_institution_notifications.js +++ b/services/web/scripts/clear_institution_notifications.js @@ -9,10 +9,11 @@ async function main() { console.log('Deleting notifications of institution', institutionId) - const preview = await InstitutionsManager.promises.clearInstitutionNotifications( - institutionId, - true - ) + const preview = + await InstitutionsManager.promises.clearInstitutionNotifications( + institutionId, + true + ) console.log('--- Preview ---') console.log(JSON.stringify(preview, null, 4)) console.log('---------------') @@ -25,10 +26,11 @@ async function main() { console.log('Exit in the next 10s in case these numbers are off.') await sleep(10 * 1000) - const cleared = await InstitutionsManager.promises.clearInstitutionNotifications( - institutionId, - false - ) + const cleared = + await InstitutionsManager.promises.clearInstitutionNotifications( + institutionId, + false + ) console.log('--- Cleared ---') console.log(JSON.stringify(cleared, null, 4)) console.log('---------------') diff --git a/services/web/scripts/count_files_in_projects.js b/services/web/scripts/count_files_in_projects.js index b8f1c70efd..6d67640e4e 100644 --- a/services/web/scripts/count_files_in_projects.js +++ b/services/web/scripts/count_files_in_projects.js @@ -17,9 +17,8 @@ async function countFiles() { if (!project) { throw new Errors.NotFoundError('project not found') } - const { files, docs } = ProjectEntityHandler.getAllEntitiesFromProject( - project - ) + const { files, docs } = + ProjectEntityHandler.getAllEntitiesFromProject(project) console.error( projectId, files.length, diff --git a/services/web/scripts/delete-orphaned-docs/delete-orphaned-docs.js b/services/web/scripts/delete-orphaned-docs/delete-orphaned-docs.js index dd5d4f90cb..faf4a0089c 100644 --- a/services/web/scripts/delete-orphaned-docs/delete-orphaned-docs.js +++ b/services/web/scripts/delete-orphaned-docs/delete-orphaned-docs.js @@ -9,8 +9,8 @@ const { ObjectId, waitForDb, } = require('../../app/src/infrastructure/mongodb') -const DocstoreManager = require('../../app/src/Features/Docstore/DocstoreManager') - .promises +const DocstoreManager = + require('../../app/src/Features/Docstore/DocstoreManager').promises const argv = minimist(process.argv.slice(2)) const commit = argv.commit !== undefined diff --git a/services/web/scripts/history/count_project_history_categories.js b/services/web/scripts/history/count_project_history_categories.js index 490c45c8ed..62a456062f 100644 --- a/services/web/scripts/history/count_project_history_categories.js +++ b/services/web/scripts/history/count_project_history_categories.js @@ -30,7 +30,8 @@ const ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = '5a8d8a370000000000000000' const OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = new ObjectId( ID_WHEN_FULL_PROJECT_HISTORY_ENABLED ) -const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED = OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp() +const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED = + OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp() async function processBatch(_, projects) { await promiseMapWithLimit(WRITE_CONCURRENCY, projects, processProject) diff --git a/services/web/scripts/history/upgrade_v1_without_conversion_if_created_after_fph_enabled.js b/services/web/scripts/history/upgrade_v1_without_conversion_if_created_after_fph_enabled.js index 3b0064b469..35132fd77c 100644 --- a/services/web/scripts/history/upgrade_v1_without_conversion_if_created_after_fph_enabled.js +++ b/services/web/scripts/history/upgrade_v1_without_conversion_if_created_after_fph_enabled.js @@ -32,7 +32,8 @@ const ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = '5a8d8a370000000000000000' const OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = new ObjectId( ID_WHEN_FULL_PROJECT_HISTORY_ENABLED ) -const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED = OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp() +const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED = + OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp() // set a default BATCH_LAST_ID at our cutoff point if none set // we still check against this cut off point later, even if diff --git a/services/web/scripts/sync-user-entitlements/sync-user-entitlements.js b/services/web/scripts/sync-user-entitlements/sync-user-entitlements.js index 95f925f7ac..a40527e5e6 100644 --- a/services/web/scripts/sync-user-entitlements/sync-user-entitlements.js +++ b/services/web/scripts/sync-user-entitlements/sync-user-entitlements.js @@ -3,8 +3,8 @@ const fs = require('fs') const minimist = require('minimist') -const InstitutionsAPI = require('../../app/src/Features/Institutions/InstitutionsAPI') - .promises +const InstitutionsAPI = + require('../../app/src/Features/Institutions/InstitutionsAPI').promises const argv = minimist(process.argv.slice(2)) const commit = argv.commit !== undefined @@ -175,12 +175,8 @@ function loadCachedEntitlements(cachedEntitlementsFilename) { for (const cachedEntitlementLine of cachedEntitlementsData) { // this is safe because comma is not an allowed value for any column - const [ - userId, - email, - hasEntitlement, - providerId, - ] = cachedEntitlementLine.split(',') + const [userId, email, hasEntitlement, providerId] = + cachedEntitlementLine.split(',') let hasEntitlementBoolean if (ignoreNulls) { hasEntitlementBoolean = hasEntitlement === 't' diff --git a/services/web/test/acceptance/src/ProjectInviteTests.js b/services/web/test/acceptance/src/ProjectInviteTests.js index 95c6b425bb..9cbfd99b2c 100644 --- a/services/web/test/acceptance/src/ProjectInviteTests.js +++ b/services/web/test/acceptance/src/ProjectInviteTests.js @@ -563,10 +563,11 @@ describe('ProjectInviteTests', function () { throw err } this.secondInvite = invite - this.secondLink = CollaboratorsEmailHandler._buildInviteUrl( - this.fakeProject, - invite - ) + this.secondLink = + CollaboratorsEmailHandler._buildInviteUrl( + this.fakeProject, + invite + ) cb() } ) diff --git a/services/web/test/acceptance/src/TagsTests.js b/services/web/test/acceptance/src/TagsTests.js index 3a93cae926..d218567bf0 100644 --- a/services/web/test/acceptance/src/TagsTests.js +++ b/services/web/test/acceptance/src/TagsTests.js @@ -31,12 +31,13 @@ const _createTag = (user, name, callback) => { const _createTags = (user, tagNames, callback) => { const tags = [] async.series( - tagNames.map(tagName => cb => - _createTag(user, tagName, (err, response, body) => { - _expect200(err, response) - tags.push(body) - cb() - }) + tagNames.map( + tagName => cb => + _createTag(user, tagName, (err, response, body) => { + _expect200(err, response) + tags.push(body) + cb() + }) ), err => { callback(err, tags) diff --git a/services/web/test/acceptance/src/helpers/DeletedSubscription.js b/services/web/test/acceptance/src/helpers/DeletedSubscription.js index 8ea92de76d..9c73801cf5 100644 --- a/services/web/test/acceptance/src/helpers/DeletedSubscription.js +++ b/services/web/test/acceptance/src/helpers/DeletedSubscription.js @@ -1,10 +1,10 @@ const { expect } = require('chai') const MockSubscription = require('./Subscription') const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater') -const SubscriptionModel = require('../../../../app/src/models/Subscription') - .Subscription -const DeletedSubscriptionModel = require(`../../../../app/src/models/DeletedSubscription`) - .DeletedSubscription +const SubscriptionModel = + require('../../../../app/src/models/Subscription').Subscription +const DeletedSubscriptionModel = + require(`../../../../app/src/models/DeletedSubscription`).DeletedSubscription class DeletedSubscription { constructor(options = {}) { diff --git a/services/web/test/acceptance/src/helpers/Institution.js b/services/web/test/acceptance/src/helpers/Institution.js index a38f2d98c5..9b26e1f38e 100644 --- a/services/web/test/acceptance/src/helpers/Institution.js +++ b/services/web/test/acceptance/src/helpers/Institution.js @@ -1,6 +1,6 @@ const { ObjectId } = require('mongodb') -const InstitutionModel = require('../../../../app/src/models/Institution') - .Institution +const InstitutionModel = + require('../../../../app/src/models/Institution').Institution let count = parseInt(Math.random() * 999999) diff --git a/services/web/test/acceptance/src/helpers/Subscription.js b/services/web/test/acceptance/src/helpers/Subscription.js index 27793f811e..8c5c9bf3c2 100644 --- a/services/web/test/acceptance/src/helpers/Subscription.js +++ b/services/web/test/acceptance/src/helpers/Subscription.js @@ -1,10 +1,10 @@ const { db, ObjectId } = require('../../../../app/src/infrastructure/mongodb') const { expect } = require('chai') const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater') -const SubscriptionModel = require('../../../../app/src/models/Subscription') - .Subscription -const DeletedSubscriptionModel = require(`../../../../app/src/models/DeletedSubscription`) - .DeletedSubscription +const SubscriptionModel = + require('../../../../app/src/models/Subscription').Subscription +const DeletedSubscriptionModel = + require(`../../../../app/src/models/DeletedSubscription`).DeletedSubscription class Subscription { constructor(options = {}) { diff --git a/services/web/test/acceptance/src/helpers/UserHelper.js b/services/web/test/acceptance/src/helpers/UserHelper.js index 6fce8cc90d..401c504f8a 100644 --- a/services/web/test/acceptance/src/helpers/UserHelper.js +++ b/services/web/test/acceptance/src/helpers/UserHelper.js @@ -178,9 +178,8 @@ class UserHelper { // hash password and delete plaintext if set if (attributes.password) { - attributes.hashedPassword = await AuthenticationManager.promises.hashPassword( - attributes.password - ) + attributes.hashedPassword = + await AuthenticationManager.promises.hashPassword(attributes.password) delete attributes.password } diff --git a/services/web/test/frontend/bootstrap.js b/services/web/test/frontend/bootstrap.js index 52324a4027..8d159ff3c1 100644 --- a/services/web/test/frontend/bootstrap.js +++ b/services/web/test/frontend/bootstrap.js @@ -91,12 +91,17 @@ globalThis.requestAnimationFrame = global.requestAnimationFrame = globalThis.sessionStorage = global.sessionStorage = window.sessionStorage // add polyfill for ResizeObserver -globalThis.ResizeObserver = global.ResizeObserver = window.ResizeObserver = require('@juggle/resize-observer').ResizeObserver +globalThis.ResizeObserver = + global.ResizeObserver = + window.ResizeObserver = + require('@juggle/resize-observer').ResizeObserver // node-fetch doesn't accept relative URL's: https://github.com/node-fetch/node-fetch/blob/master/docs/v2-LIMITS.md#known-differences const fetch = require('node-fetch') -globalThis.fetch = global.fetch = window.fetch = (url, ...options) => - fetch(new URL(url, 'http://localhost'), ...options) +globalThis.fetch = + global.fetch = + window.fetch = + (url, ...options) => fetch(new URL(url, 'http://localhost'), ...options) // ignore CSS files const { addHook } = require('pirates') diff --git a/services/web/test/frontend/features/pdf-preview/components/pdf-preview.test.js b/services/web/test/frontend/features/pdf-preview/components/pdf-preview.test.js index f3e5e2b8db..0bd44ce02f 100644 --- a/services/web/test/frontend/features/pdf-preview/components/pdf-preview.test.js +++ b/services/web/test/frontend/features/pdf-preview/components/pdf-preview.test.js @@ -308,8 +308,7 @@ describe('', function () { 'This project was compiled very recently, so this compile has been skipped.', unavailable: 'Sorry, the compile server for your project was temporarily unavailable. Please try again in a few moments.', - foo: - 'Sorry, something went wrong and your project could not be compiled. Please try again in a few moments.', + foo: 'Sorry, something went wrong and your project could not be compiled. Please try again in a few moments.', } for (const [status, message] of Object.entries(compileErrorStatuses)) { diff --git a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js index 63b18d996d..4a8fc3929c 100644 --- a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js +++ b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js @@ -106,10 +106,10 @@ describe('', function () { { scope: { project } } ) - const [ - headerCloseButton, - footerCloseButton, - ] = await screen.findAllByRole('button', { name: 'Close' }) + const [headerCloseButton, footerCloseButton] = await screen.findAllByRole( + 'button', + { name: 'Close' } + ) fireEvent.click(headerCloseButton) fireEvent.click(footerCloseButton) diff --git a/services/web/test/frontend/infrastructure/fetch-json.test.js b/services/web/test/frontend/infrastructure/fetch-json.test.js index 6d29cffdaa..1d42c45344 100644 --- a/services/web/test/frontend/infrastructure/fetch-json.test.js +++ b/services/web/test/frontend/infrastructure/fetch-json.test.js @@ -120,8 +120,7 @@ describe('fetchJSON', function () { headers: { 'Content-Type': 'text/html', }, - body: - '

lorem ipsum

', + body: '

lorem ipsum

', }) const promise = getJSON('/test') diff --git a/services/web/test/karma/ide/editor/aceEditor/spell-check/SpellCheckManagerTests.js b/services/web/test/karma/ide/editor/aceEditor/spell-check/SpellCheckManagerTests.js index 56597bf9b4..9e17e04027 100644 --- a/services/web/test/karma/ide/editor/aceEditor/spell-check/SpellCheckManagerTests.js +++ b/services/web/test/karma/ide/editor/aceEditor/spell-check/SpellCheckManagerTests.js @@ -100,16 +100,7 @@ export default describe('SpellCheckManager', function () { this.timelord.tick(500) this.$httpBackend.flush() expect(this.adapter.getLinesByRows).to.have.been.calledWith([ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ]) }) }) diff --git a/services/web/test/karma/ide/history/HistoryV2ManagerTests.js b/services/web/test/karma/ide/history/HistoryV2ManagerTests.js index 84c5300604..f9e7c64c12 100644 --- a/services/web/test/karma/ide/history/HistoryV2ManagerTests.js +++ b/services/web/test/karma/ide/history/HistoryV2ManagerTests.js @@ -270,7 +270,8 @@ export default describe('HistoryV2Manager', function () { describe('with a previously selected file', function () { it('should prefer the previously selected file if it is available and has operations', function () { - this.historyManager._previouslySelectedPathname = this.mockedAddedFile.pathname + this.historyManager._previouslySelectedPathname = + this.mockedAddedFile.pathname this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( this.mockedAddedFile @@ -278,7 +279,8 @@ export default describe('HistoryV2Manager', function () { }) it('should prefer a file with ops if the previously selected file is available but has no operations', function () { - this.historyManager._previouslySelectedPathname = this.mockedReferencesFile.pathname + this.historyManager._previouslySelectedPathname = + this.mockedReferencesFile.pathname this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file.operation).to.exist }) @@ -335,9 +337,8 @@ export default describe('HistoryV2Manager', function () { this.mockedAddedFile ) this.$scope.history.selection.files.splice(indexOfAddedFile, 1) - const indexOfRenamedFile = this.$scope.history.selection.files.indexOf( - this.mockedRenamedFile - ) + const indexOfRenamedFile = + this.$scope.history.selection.files.indexOf(this.mockedRenamedFile) this.$scope.history.selection.files.splice(indexOfRenamedFile, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( @@ -392,9 +393,8 @@ export default describe('HistoryV2Manager', function () { this.mockedMainTex ) this.$scope.history.selection.files.splice(indexOfMainTex, 1) - const indexOfOtherTexFile = this.$scope.history.selection.files.indexOf( - this.mockedOtherTexFile - ) + const indexOfOtherTexFile = + this.$scope.history.selection.files.indexOf(this.mockedOtherTexFile) this.$scope.history.selection.files.splice(indexOfOtherTexFile, 1) this.historyManager.autoSelectFile() expect(this.$scope.history.selection.file).to.deep.equal( @@ -440,8 +440,10 @@ export default describe('HistoryV2Manager', function () { ], } this.sampleUpdateEditedFile = this.sampleUpdates[0].pathnames[0] - this.sampleUpdateAddedFile = this.sampleUpdates[0].project_ops[0].add.pathname - this.sampleUpdateRenamedFile = this.sampleUpdates[0].project_ops[1].rename.newPathname + this.sampleUpdateAddedFile = + this.sampleUpdates[0].project_ops[0].add.pathname + this.sampleUpdateRenamedFile = + this.sampleUpdates[0].project_ops[1].rename.newPathname this.$scope.history.updates = this.sampleUpdates this.$scope.history.selection.range = { fromV: this.sampleUpdates[0].toV, @@ -625,19 +627,18 @@ export default describe('HistoryV2Manager', function () { ] const lastUpdate = 5 - this.historyManager.$scope.history.labels = this.historyManager._loadLabels( - this.historyManager.$scope.history.labels, - lastUpdate - ) + this.historyManager.$scope.history.labels = + this.historyManager._loadLabels( + this.historyManager.$scope.history.labels, + lastUpdate + ) expect( this.historyManager.$scope.history.labels[0].isPseudoCurrentStateLabel ).to.equal(true) - this.historyManager.$scope.history.labels = this.historyManager._loadLabels( - [], - lastUpdate - ) + this.historyManager.$scope.history.labels = + this.historyManager._loadLabels([], lastUpdate) expect( this.historyManager.$scope.history.labels[0].isPseudoCurrentStateLabel ).to.equal(true) diff --git a/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js b/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js index 0f95ee0012..20526dd825 100644 --- a/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js +++ b/services/web/test/unit/src/Authentication/AuthenticationControllerTests.js @@ -58,7 +58,8 @@ describe('AuthenticationController', function () { identifyUser: sinon.stub(), getIdsFromSession: sinon.stub().returns({ userId: this.user._id }), }), - '../../infrastructure/SessionStoreManager': (this.SessionStoreManager = {}), + '../../infrastructure/SessionStoreManager': (this.SessionStoreManager = + {}), '@overleaf/settings': (this.Settings = { siteUrl: 'http://www.foo.bar', httpAuthUsers: this.httpAuthUsers, @@ -78,13 +79,14 @@ describe('AuthenticationController', function () { ipMatcherAffiliation: sinon.stub().returns({ create: sinon.stub() }), }), '../../models/User': { User: this.UserModel }, - '../../../../modules/oauth2-server/app/src/Oauth2Server': (this.Oauth2Server = { - Request: sinon.stub(), - Response: sinon.stub(), - server: { - authenticate: sinon.stub(), - }, - }), + '../../../../modules/oauth2-server/app/src/Oauth2Server': + (this.Oauth2Server = { + Request: sinon.stub(), + Response: sinon.stub(), + server: { + authenticate: sinon.stub(), + }, + }), '../Helpers/UrlHelper': (this.UrlHelper = { getSafeRedirectPath: sinon.stub(), }), @@ -413,7 +415,8 @@ describe('AuthenticationController', function () { describe('when the user is not logged in', function () { beforeEach(function () { this.req.session = {} - this.AuthenticationController._redirectToLoginOrRegisterPage = sinon.stub() + this.AuthenticationController._redirectToLoginOrRegisterPage = + sinon.stub() this.req.query = {} this.SessionManager.isUserLoggedIn = sinon.stub().returns(false) this.middleware(this.req, this.res, this.next) @@ -455,7 +458,8 @@ describe('AuthenticationController', function () { regenerate: sinon.stub().yields(), } this.req.user = this.user - this.AuthenticationController._redirectToLoginOrRegisterPage = sinon.stub() + this.AuthenticationController._redirectToLoginOrRegisterPage = + sinon.stub() this.req.query = {} this.SessionStoreManager.hasValidationToken = sinon .stub() diff --git a/services/web/test/unit/src/Authentication/AuthenticationManagerTests.js b/services/web/test/unit/src/Authentication/AuthenticationManagerTests.js index f825822e30..0fa27b829d 100644 --- a/services/web/test/unit/src/Authentication/AuthenticationManagerTests.js +++ b/services/web/test/unit/src/Authentication/AuthenticationManagerTests.js @@ -118,9 +118,8 @@ describe('AuthenticationManager', function () { 'testpassword', err => { expect(err).to.not.exist - const { - hashedPassword, - } = this.db.users.updateOne.lastCall.args[1].$set + const { hashedPassword } = + this.db.users.updateOne.lastCall.args[1].$set expect(hashedPassword).to.exist expect(hashedPassword.length).to.equal(60) expect(hashedPassword).to.match(/^\$2a\$04\$[a-zA-Z0-9/.]{53}$/) @@ -283,9 +282,8 @@ describe('AuthenticationManager', function () { describe('validateEmail', function () { describe('valid', function () { it('should return null', function () { - const result = this.AuthenticationManager.validateEmail( - 'foo@example.com' - ) + const result = + this.AuthenticationManager.validateEmail('foo@example.com') expect(result).to.equal(null) }) }) @@ -374,9 +372,8 @@ describe('AuthenticationManager', function () { }) it('should reject passwords that are too short', function () { - const result = this.AuthenticationManager.validatePassword( - '012345678' - ) + const result = + this.AuthenticationManager.validatePassword('012345678') expect(result).to.be.an.instanceOf( AuthenticationErrors.InvalidPasswordError @@ -392,9 +389,8 @@ describe('AuthenticationManager', function () { }) it('should reject passwords that are too long', function () { - const result = this.AuthenticationManager.validatePassword( - '0123456789abc' - ) + const result = + this.AuthenticationManager.validatePassword('0123456789abc') expect(result).to.be.an.instanceOf( AuthenticationErrors.InvalidPasswordError diff --git a/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js b/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js index 06e65c6207..e4849ea7ea 100644 --- a/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js +++ b/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js @@ -98,11 +98,12 @@ describe('AuthorizationManager', function () { this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel .withArgs(this.user._id, this.project._id) .resolves(PrivilegeLevels.READ_ONLY) - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it("should return the user's privilege level", function () { @@ -112,11 +113,12 @@ describe('AuthorizationManager', function () { describe('with a user id with no privilege level', function () { beforeEach(async function () { - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it('should return false', function () { @@ -127,11 +129,12 @@ describe('AuthorizationManager', function () { describe('with a user id who is an admin', function () { beforeEach(async function () { this.user.isAdmin = true - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it('should return the user as an owner', function () { @@ -142,11 +145,12 @@ describe('AuthorizationManager', function () { describe('with no user (anonymous)', function () { describe('when the token is not valid', function () { beforeEach(async function () { - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - null, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + null, + this.project._id, + this.token + ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { @@ -169,15 +173,17 @@ describe('AuthorizationManager', function () { describe('when the token is valid for read-and-write', function () { beforeEach(async function () { - this.TokenAccessHandler.promises.validateTokenForAnonymousAccess = sinon - .stub() - .withArgs(this.project._id, this.token) - .resolves({ isValidReadAndWrite: true, isValidReadOnly: false }) - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - null, - this.project._id, - this.token - ) + this.TokenAccessHandler.promises.validateTokenForAnonymousAccess = + sinon + .stub() + .withArgs(this.project._id, this.token) + .resolves({ isValidReadAndWrite: true, isValidReadOnly: false }) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + null, + this.project._id, + this.token + ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { @@ -200,15 +206,17 @@ describe('AuthorizationManager', function () { describe('when the token is valid for read-only', function () { beforeEach(async function () { - this.TokenAccessHandler.promises.validateTokenForAnonymousAccess = sinon - .stub() - .withArgs(this.project._id, this.token) - .resolves({ isValidReadAndWrite: false, isValidReadOnly: true }) - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - null, - this.project._id, - this.token - ) + this.TokenAccessHandler.promises.validateTokenForAnonymousAccess = + sinon + .stub() + .withArgs(this.project._id, this.token) + .resolves({ isValidReadAndWrite: false, isValidReadOnly: true }) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + null, + this.project._id, + this.token + ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { @@ -241,11 +249,12 @@ describe('AuthorizationManager', function () { this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel .withArgs(this.user._id, this.project._id) .resolves(PrivilegeLevels.READ_ONLY) - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it("should return the user's privilege level", function () { @@ -255,11 +264,12 @@ describe('AuthorizationManager', function () { describe('with a user id with no privilege level', function () { beforeEach(async function () { - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it('should return false', function () { @@ -270,11 +280,12 @@ describe('AuthorizationManager', function () { describe('with a user id who is an admin', function () { beforeEach(async function () { this.user.isAdmin = true - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it('should return the user as an owner', function () { @@ -284,11 +295,12 @@ describe('AuthorizationManager', function () { describe('with no user (anonymous)', function () { beforeEach(async function () { - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - null, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + null, + this.project._id, + this.token + ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { @@ -313,11 +325,12 @@ describe('AuthorizationManager', function () { this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel .withArgs(this.user._id, this.project._id) .resolves(PrivilegeLevels.READ_ONLY) - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it("should return the user's privilege level", function () { @@ -327,11 +340,12 @@ describe('AuthorizationManager', function () { describe('with a user id with no privilege level', function () { beforeEach(async function () { - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it('should return the public privilege level', function () { @@ -342,11 +356,12 @@ describe('AuthorizationManager', function () { describe('with a user id who is an admin', function () { beforeEach(async function () { this.user.isAdmin = true - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - this.user._id, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + this.user._id, + this.project._id, + this.token + ) }) it('should return the user as an owner', function () { @@ -356,11 +371,12 @@ describe('AuthorizationManager', function () { describe('with no user (anonymous)', function () { beforeEach(async function () { - this.result = await this.AuthorizationManager.promises.getPrivilegeLevelForProject( - null, - this.project._id, - this.token - ) + this.result = + await this.AuthorizationManager.promises.getPrivilegeLevelForProject( + null, + this.project._id, + this.token + ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { @@ -447,18 +463,20 @@ describe('AuthorizationManager', function () { }) it('should return true', async function () { - const isAdmin = await this.AuthorizationManager.promises.isUserSiteAdmin( - this.user._id - ) + const isAdmin = + await this.AuthorizationManager.promises.isUserSiteAdmin( + this.user._id + ) expect(isAdmin).to.equal(true) }) }) describe('when user is not admin', function () { it('should return false', async function () { - const isAdmin = await this.AuthorizationManager.promises.isUserSiteAdmin( - this.user._id - ) + const isAdmin = + await this.AuthorizationManager.promises.isUserSiteAdmin( + this.user._id + ) expect(isAdmin).to.equal(false) }) }) @@ -466,18 +484,16 @@ describe('AuthorizationManager', function () { describe('when user is not found', function () { it('should return false', async function () { const someOtherId = new ObjectId() - const isAdmin = await this.AuthorizationManager.promises.isUserSiteAdmin( - someOtherId - ) + const isAdmin = + await this.AuthorizationManager.promises.isUserSiteAdmin(someOtherId) expect(isAdmin).to.equal(false) }) }) describe('when no user is passed', function () { it('should return false', async function () { - const isAdmin = await this.AuthorizationManager.promises.isUserSiteAdmin( - null - ) + const isAdmin = + await this.AuthorizationManager.promises.isUserSiteAdmin(null) expect(isAdmin).to.equal(false) }) }) diff --git a/services/web/test/unit/src/Authorization/AuthorizationMiddlewareTests.js b/services/web/test/unit/src/Authorization/AuthorizationMiddlewareTests.js index 2bcfd51ac0..0509cf6bac 100644 --- a/services/web/test/unit/src/Authorization/AuthorizationMiddlewareTests.js +++ b/services/web/test/unit/src/Authorization/AuthorizationMiddlewareTests.js @@ -38,8 +38,8 @@ describe('AuthorizationMiddleware', function () { requires: { './AuthorizationManager': this.AuthorizationManager, '../Errors/HttpErrorHandler': this.HttpErrorHandler, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, '../Authentication/SessionManager': this.SessionManager, '../TokenAccess/TokenAccessHandler': this.TokenAccessHandler, }, diff --git a/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js b/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js index 8a785b2818..933d6d2200 100644 --- a/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js +++ b/services/web/test/unit/src/BetaProgram/BetaProgramControllerTests.js @@ -33,9 +33,10 @@ describe('BetaProgramController', function () { '@overleaf/settings': (this.settings = { languages: {}, }), - '../Authentication/AuthenticationController': (this.AuthenticationController = { - getLoggedInUserId: sinon.stub().returns(this.user._id), - }), + '../Authentication/AuthenticationController': + (this.AuthenticationController = { + getLoggedInUserId: sinon.stub().returns(this.user._id), + }), }, }) this.res = { diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js b/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js index bc0490141c..9857c9fde0 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js +++ b/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js @@ -64,9 +64,10 @@ describe('CollaboratorsGetter', function () { describe('getMemberIdsWithPrivilegeLevels', function () { describe('with project', function () { it('should return an array of member ids with their privilege levels', async function () { - const result = await this.CollaboratorsGetter.promises.getMemberIdsWithPrivilegeLevels( - this.project._id - ) + const result = + await this.CollaboratorsGetter.promises.getMemberIdsWithPrivilegeLevels( + this.project._id + ) expect(result).to.have.deep.members([ { id: this.ownerRef.toString(), @@ -141,9 +142,10 @@ describe('CollaboratorsGetter', function () { describe('getInvitedMemberIds', function () { it('should return the invited ids', async function () { - const memberIds = await this.CollaboratorsGetter.promises.getInvitedMemberIds( - this.project._id - ) + const memberIds = + await this.CollaboratorsGetter.promises.getInvitedMemberIds( + this.project._id + ) expect(memberIds).to.have.members([ this.ownerRef.toString(), this.readOnlyRef1.toString(), @@ -171,9 +173,10 @@ describe('CollaboratorsGetter', function () { }) it('should return an array of invited members with their privilege levels', async function () { - const result = await this.CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels( - this.project._id - ) + const result = + await this.CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels( + this.project._id + ) expect(result).to.have.deep.members([ { user: { _id: this.readOnlyRef1 }, privilegeLevel: 'readOnly' }, { user: { _id: this.readWriteRef2 }, privilegeLevel: 'readAndWrite' }, @@ -183,18 +186,20 @@ describe('CollaboratorsGetter', function () { describe('getMemberIdPrivilegeLevel', function () { it('should return the privilege level if it exists', async function () { - const level = await this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel( - this.readOnlyRef1, - this.project._id - ) + const level = + await this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel( + this.readOnlyRef1, + this.project._id + ) expect(level).to.equal('readOnly') }) it('should return false if the member has no privilege level', async function () { - const level = await this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel( - this.nonMemberRef, - this.project._id - ) + const level = + await this.CollaboratorsGetter.promises.getMemberIdPrivilegeLevel( + this.nonMemberRef, + this.project._id + ) expect(level).to.equal(false) }) }) @@ -202,18 +207,20 @@ describe('CollaboratorsGetter', function () { describe('isUserInvitedMemberOfProject', function () { describe('when user is a member of the project', function () { it('should return true and the privilegeLevel', async function () { - const isMember = await this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject( - this.readOnlyRef1 - ) + const isMember = + await this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject( + this.readOnlyRef1 + ) expect(isMember).to.equal(true) }) }) describe('when user is not a member of the project', function () { it('should return false', async function () { - const isMember = await this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject( - this.nonMemberRef - ) + const isMember = + await this.CollaboratorsGetter.promises.isUserInvitedMemberOfProject( + this.nonMemberRef + ) expect(isMember).to.equal(false) }) }) @@ -260,10 +267,11 @@ describe('CollaboratorsGetter', function () { }) it('should call the callback with the projects', async function () { - const projects = await this.CollaboratorsGetter.promises.getProjectsUserIsMemberOf( - this.userId, - this.fields - ) + const projects = + await this.CollaboratorsGetter.promises.getProjectsUserIsMemberOf( + this.userId, + this.fields + ) expect(projects).to.deep.equal({ readAndWrite: [ 'mock-read-write-project-1', @@ -311,9 +319,10 @@ describe('CollaboratorsGetter', function () { .withArgs(this.readWriteUser._id.toString()) .resolves(this.readWriteUser) this.ProjectEditorHandler.buildOwnerAndMembersViews.returns(this.views) - this.result = await this.CollaboratorsGetter.promises.getAllInvitedMembers( - this.project._id - ) + this.result = + await this.CollaboratorsGetter.promises.getAllInvitedMembers( + this.project._id + ) }) it('should produce a list of members', function () { @@ -332,19 +341,21 @@ describe('CollaboratorsGetter', function () { describe('userIsTokenMember', function () { it('should return true when the project is found', async function () { this.ProjectMock.expects('findOne').chain('exec').resolves(this.project) - const isMember = await this.CollaboratorsGetter.promises.userIsTokenMember( - this.userId, - this.project._id - ) + const isMember = + await this.CollaboratorsGetter.promises.userIsTokenMember( + this.userId, + this.project._id + ) expect(isMember).to.be.true }) it('should return false when the project is not found', async function () { this.ProjectMock.expects('findOne').chain('exec').resolves(null) - const isMember = await this.CollaboratorsGetter.promises.userIsTokenMember( - this.userId, - this.project._id - ) + const isMember = + await this.CollaboratorsGetter.promises.userIsTokenMember( + this.userId, + this.project._id + ) expect(isMember).to.be.false }) }) diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js b/services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js index 7f04d0ad03..7ff21a839f 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js @@ -52,8 +52,8 @@ describe('CollaboratorsInviteController', function () { emitToRoom: sinon.stub(), }), '../Analytics/AnalyticsManager': this.AnalyticsManger, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, '@overleaf/settings': (this.settings = {}), '../../infrastructure/RateLimiter': this.RateLimiter, }, diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandlerTests.js b/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandlerTests.js index 08eca22d94..53fbedf858 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandlerTests.js +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandlerTests.js @@ -62,7 +62,8 @@ describe('CollaboratorsInviteHandler', function () { }), '../User/UserGetter': (this.UserGetter = { getUser: sinon.stub() }), '../Project/ProjectGetter': (this.ProjectGetter = {}), - '../Notifications/NotificationsBuilder': (this.NotificationsBuilder = {}), + '../Notifications/NotificationsBuilder': (this.NotificationsBuilder = + {}), crypto: this.Crypto, }, }) @@ -368,9 +369,8 @@ describe('CollaboratorsInviteHandler', function () { describe('when _trySendInviteNotification produces an error', function () { beforeEach(function () { - return (this.CollaboratorsInviteHandler._trySendInviteNotification = sinon - .stub() - .callsArgWith(3, new Error('woops'))) + return (this.CollaboratorsInviteHandler._trySendInviteNotification = + sinon.stub().callsArgWith(3, new Error('woops'))) }) it('should produce an error', function (done) { diff --git a/services/web/test/unit/src/Compile/ClsiManagerTests.js b/services/web/test/unit/src/Compile/ClsiManagerTests.js index 656f2e7dfb..3d7531a4ac 100644 --- a/services/web/test/unit/src/Compile/ClsiManagerTests.js +++ b/services/web/test/unit/src/Compile/ClsiManagerTests.js @@ -54,8 +54,8 @@ describe('ClsiManager', function () { }, '../Project/ProjectEntityHandler': this.ProjectEntityHandler, '../Project/ProjectGetter': this.ProjectGetter, - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, './ClsiCookieManager': () => this.ClsiCookieManager, './ClsiStateManager': this.ClsiStateManager, request: this.request, diff --git a/services/web/test/unit/src/Documents/DocumentControllerTests.js b/services/web/test/unit/src/Documents/DocumentControllerTests.js index a1b5da1b42..44b01f8d4e 100644 --- a/services/web/test/unit/src/Documents/DocumentControllerTests.js +++ b/services/web/test/unit/src/Documents/DocumentControllerTests.js @@ -13,7 +13,8 @@ describe('DocumentController', function () { '../Project/ProjectGetter': (this.ProjectGetter = {}), '../Project/ProjectLocator': (this.ProjectLocator = {}), '../Project/ProjectEntityHandler': (this.ProjectEntityHandler = {}), - '../Project/ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {}), + '../Project/ProjectEntityUpdateHandler': + (this.ProjectEntityUpdateHandler = {}), }, }) this.res = new MockResponse() diff --git a/services/web/test/unit/src/Downloads/ProjectDownloadsControllerTests.js b/services/web/test/unit/src/Downloads/ProjectDownloadsControllerTests.js index 538c5bc7bd..4c9f0c3575 100644 --- a/services/web/test/unit/src/Downloads/ProjectDownloadsControllerTests.js +++ b/services/web/test/unit/src/Downloads/ProjectDownloadsControllerTests.js @@ -32,8 +32,8 @@ describe('ProjectDownloadsController', function () { './ProjectZipStreamManager': (this.ProjectZipStreamManager = {}), '../Project/ProjectGetter': (this.ProjectGetter = {}), '@overleaf/metrics': (this.metrics = {}), - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, }, } )) diff --git a/services/web/test/unit/src/Editor/EditorControllerTests.js b/services/web/test/unit/src/Editor/EditorControllerTests.js index 8dca636c2d..8ad80de8b3 100644 --- a/services/web/test/unit/src/Editor/EditorControllerTests.js +++ b/services/web/test/unit/src/Editor/EditorControllerTests.js @@ -47,7 +47,8 @@ describe('EditorController', function () { return (this.EditorController = SandboxedModule.require(modulePath, { requires: { - '../Project/ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {}), + '../Project/ProjectEntityUpdateHandler': + (this.ProjectEntityUpdateHandler = {}), '../Project/ProjectOptionsHandler': (this.ProjectOptionsHandler = { setCompiler: sinon.stub().yields(), setImageName: sinon.stub().yields(), @@ -59,10 +60,11 @@ describe('EditorController', function () { setPublicAccessLevel: sinon.stub().yields(), }), '../Project/ProjectDeleter': (this.ProjectDeleter = {}), - '../DocumentUpdater/DocumentUpdaterHandler': (this.DocumentUpdaterHandler = { - flushDocToMongo: sinon.stub().yields(), - setDocument: sinon.stub().yields(), - }), + '../DocumentUpdater/DocumentUpdaterHandler': + (this.DocumentUpdaterHandler = { + flushDocToMongo: sinon.stub().yields(), + setDocument: sinon.stub().yields(), + }), './EditorRealTimeController': (this.EditorRealTimeController = { emitToRoom: sinon.stub(), }), diff --git a/services/web/test/unit/src/Editor/EditorHttpControllerTests.js b/services/web/test/unit/src/Editor/EditorHttpControllerTests.js index 7e3dddc89e..3fc20fdf6c 100644 --- a/services/web/test/unit/src/Editor/EditorHttpControllerTests.js +++ b/services/web/test/unit/src/Editor/EditorHttpControllerTests.js @@ -138,13 +138,13 @@ describe('EditorHttpController', function () { '@overleaf/metrics': this.Metrics, '../Collaborators/CollaboratorsGetter': this.CollaboratorsGetter, '../Collaborators/CollaboratorsHandler': this.CollaboratorsHandler, - '../Collaborators/CollaboratorsInviteHandler': this - .CollaboratorsInviteHandler, + '../Collaborators/CollaboratorsInviteHandler': + this.CollaboratorsInviteHandler, '../TokenAccess/TokenAccessHandler': this.TokenAccessHandler, '../Authentication/SessionManager': this.SessionManager, '../../infrastructure/FileWriter': this.FileWriter, - '../Project/ProjectEntityUpdateHandler': this - .ProjectEntityUpdateHandler, + '../Project/ProjectEntityUpdateHandler': + this.ProjectEntityUpdateHandler, '../Docstore/DocstoreManager': this.DocstoreManager, '../Errors/HttpErrorHandler': this.HttpErrorHandler, }, diff --git a/services/web/test/unit/src/Exports/ExportsControllerTests.js b/services/web/test/unit/src/Exports/ExportsControllerTests.js index 66fdfabc9b..356eacf25e 100644 --- a/services/web/test/unit/src/Exports/ExportsControllerTests.js +++ b/services/web/test/unit/src/Exports/ExportsControllerTests.js @@ -65,8 +65,8 @@ describe('ExportsController', function () { return (this.controller = SandboxedModule.require(modulePath, { requires: { './ExportsHandler': this.handler, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, }, })) }) diff --git a/services/web/test/unit/src/History/HistoryControllerTests.js b/services/web/test/unit/src/History/HistoryControllerTests.js index 0ffc3f1fb6..65308617e9 100644 --- a/services/web/test/unit/src/History/HistoryControllerTests.js +++ b/services/web/test/unit/src/History/HistoryControllerTests.js @@ -30,7 +30,8 @@ describe('HistoryController', function () { '../Authentication/SessionManager': this.SessionManager, './HistoryManager': (this.HistoryManager = {}), '../Project/ProjectDetailsHandler': (this.ProjectDetailsHandler = {}), - '../Project/ProjectEntityUpdateHandler': (this.ProjectEntityUpdateHandler = {}), + '../Project/ProjectEntityUpdateHandler': + (this.ProjectEntityUpdateHandler = {}), '../User/UserGetter': (this.UserGetter = {}), './RestoreManager': (this.RestoreManager = {}), }, diff --git a/services/web/test/unit/src/History/RestoreManagerTests.js b/services/web/test/unit/src/History/RestoreManagerTests.js index 79516c6f10..0f8884fc81 100644 --- a/services/web/test/unit/src/History/RestoreManagerTests.js +++ b/services/web/test/unit/src/History/RestoreManagerTests.js @@ -29,7 +29,8 @@ describe('RestoreManager', function () { requires: { '@overleaf/settings': {}, '../../infrastructure/FileWriter': (this.FileWriter = {}), - '../Uploads/FileSystemImportManager': (this.FileSystemImportManager = {}), + '../Uploads/FileSystemImportManager': (this.FileSystemImportManager = + {}), '../Project/ProjectEntityHandler': (this.ProjectEntityHandler = {}), '../Editor/EditorController': (this.EditorController = {}), }, diff --git a/services/web/test/unit/src/Institutions/InstitutionsGetterTests.js b/services/web/test/unit/src/Institutions/InstitutionsGetterTests.js index 9972f290d1..14285a1c7d 100644 --- a/services/web/test/unit/src/Institutions/InstitutionsGetterTests.js +++ b/services/web/test/unit/src/Institutions/InstitutionsGetterTests.js @@ -17,8 +17,10 @@ describe('InstitutionsGetter', function () { this.InstitutionsGetter = SandboxedModule.require(modulePath, { requires: { '../User/UserGetter': this.UserGetter, - '../UserMembership/UserMembershipsHandler': (this.UserMembershipsHandler = {}), - '../UserMembership/UserMembershipEntityConfigs': (this.UserMembershipEntityConfigs = {}), + '../UserMembership/UserMembershipsHandler': + (this.UserMembershipsHandler = {}), + '../UserMembership/UserMembershipEntityConfigs': + (this.UserMembershipEntityConfigs = {}), }, }) @@ -94,17 +96,19 @@ describe('InstitutionsGetter', function () { describe('getCurrentInstitutionIds', function () { it('filters unconfirmed affiliations, those past reconfirmation, and returns only 1 result per institution', async function () { this.UserGetter.promises.getUserFullEmails.resolves(this.userEmails) - const institutions = await this.InstitutionsGetter.promises.getCurrentInstitutionIds( - this.userId - ) + const institutions = + await this.InstitutionsGetter.promises.getCurrentInstitutionIds( + this.userId + ) expect(institutions.length).to.equal(1) expect(institutions[0]).to.equal(456) }) it('handles empty response', async function () { this.UserGetter.promises.getUserFullEmails.resolves([]) - const institutions = await this.InstitutionsGetter.promises.getCurrentInstitutionIds( - this.userId - ) + const institutions = + await this.InstitutionsGetter.promises.getCurrentInstitutionIds( + this.userId + ) expect(institutions).to.deep.equal([]) }) it('handles errors', async function () { @@ -131,9 +135,10 @@ describe('InstitutionsGetter', function () { this.unconfirmedDomainLicensedAffiliation, this.unconfirmedEmailLicensedAffiliation, ]) - const institutions = await this.InstitutionsGetter.promises.getCurrentInstitutionsWithLicence( - this.userId - ) + const institutions = + await this.InstitutionsGetter.promises.getCurrentInstitutionsWithLicence( + this.userId + ) expect(institutions.map(institution => institution.id)).to.deep.equal([ this.licencedAffiliation.affiliation.institution.id, ]) diff --git a/services/web/test/unit/src/Institutions/InstitutionsManagerTests.js b/services/web/test/unit/src/Institutions/InstitutionsManagerTests.js index b8b1dc96d2..955465630e 100644 --- a/services/web/test/unit/src/Institutions/InstitutionsManagerTests.js +++ b/services/web/test/unit/src/Institutions/InstitutionsManagerTests.js @@ -96,12 +96,14 @@ describe('InstitutionsManager', function () { './InstitutionsAPI': { getInstitutionAffiliations: this.getInstitutionAffiliations, promises: { - getInstitutionAffiliations: (this.getInstitutionAffiliationsPromise = sinon - .stub() - .resolves(this.affiliations)), - getInstitutionAffiliationsCounts: (this.getInstitutionAffiliationsCounts = sinon - .stub() - .resolves(this.v1Counts)), + getInstitutionAffiliations: + (this.getInstitutionAffiliationsPromise = sinon + .stub() + .resolves(this.affiliations)), + getInstitutionAffiliationsCounts: + (this.getInstitutionAffiliationsCounts = sinon + .stub() + .resolves(this.v1Counts)), }, }, '../Subscription/FeaturesUpdater': { @@ -207,9 +209,10 @@ describe('InstitutionsManager', function () { it('returns entitled/not, sso/not, lapsed/current, and pro counts', async function () { if (Features.hasFeature('saas')) { this.isFeatureSetBetter.returns(true) - const usersSummary = await this.InstitutionsManager.promises.checkInstitutionUsers( - this.institutionId - ) + const usersSummary = + await this.InstitutionsManager.promises.checkInstitutionUsers( + this.institutionId + ) expect(usersSummary).to.deep.equal({ emailUsers: { total: 1, @@ -248,9 +251,10 @@ describe('InstitutionsManager', function () { if (Features.hasFeature('saas')) { this.isFeatureSetBetter.returns(true) this.v1Counts.with_confirmed_email = 100 - const usersSummary = await this.InstitutionsManager.promises.checkInstitutionUsers( - this.institutionId - ) + const usersSummary = + await this.InstitutionsManager.promises.checkInstitutionUsers( + this.institutionId + ) expect(usersSummary).to.deep.equal({ emailUsers: { total: 1, diff --git a/services/web/test/unit/src/Metadata/MetaHandlerTests.js b/services/web/test/unit/src/Metadata/MetaHandlerTests.js index 31a460e299..8b4408e579 100644 --- a/services/web/test/unit/src/Metadata/MetaHandlerTests.js +++ b/services/web/test/unit/src/Metadata/MetaHandlerTests.js @@ -54,8 +54,8 @@ describe('MetaHandler', function () { return (this.MetaHandler = SandboxedModule.require(modulePath, { requires: { '../Project/ProjectEntityHandler': this.ProjectEntityHandler, - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, './packageMapping': this.packageMapping, }, })) diff --git a/services/web/test/unit/src/Notifications/NotificationsControllerTests.js b/services/web/test/unit/src/Notifications/NotificationsControllerTests.js index 288b9aa19c..dd1104d698 100644 --- a/services/web/test/unit/src/Notifications/NotificationsControllerTests.js +++ b/services/web/test/unit/src/Notifications/NotificationsControllerTests.js @@ -33,8 +33,8 @@ describe('NotificationsController', function () { this.controller = SandboxedModule.require(modulePath, { requires: { './NotificationsHandler': this.handler, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, }, }) }) diff --git a/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js b/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js index 6d53110abf..b91d0e773e 100644 --- a/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js +++ b/services/web/test/unit/src/PasswordReset/PasswordResetControllerTests.js @@ -57,10 +57,11 @@ describe('PasswordResetController', function () { '../Authentication/AuthenticationManager': { validatePassword: sinon.stub().returns(null), }, - '../Authentication/AuthenticationController': (this.AuthenticationController = { - getLoggedInUserId: sinon.stub(), - finishLogin: sinon.stub(), - }), + '../Authentication/AuthenticationController': + (this.AuthenticationController = { + getLoggedInUserId: sinon.stub(), + finishLogin: sinon.stub(), + }), '../User/UserGetter': (this.UserGetter = { promises: { getUser: sinon.stub(), diff --git a/services/web/test/unit/src/PasswordReset/PasswordResetHandlerTests.js b/services/web/test/unit/src/PasswordReset/PasswordResetHandlerTests.js index b38708744d..86c5e96567 100644 --- a/services/web/test/unit/src/PasswordReset/PasswordResetHandlerTests.js +++ b/services/web/test/unit/src/PasswordReset/PasswordResetHandlerTests.js @@ -281,8 +281,8 @@ describe('PasswordResetHandler', function () { (error, result) => { const { reset, userId } = result expect(error).to.not.exist - const logCall = this.UserAuditLogHandler.promises.addEntry - .lastCall + const logCall = + this.UserAuditLogHandler.promises.addEntry.lastCall expect(logCall.args[0]).to.equal(this.user_id) expect(logCall.args[1]).to.equal('reset-password') expect(logCall.args[2]).to.equal(undefined) @@ -320,8 +320,8 @@ describe('PasswordResetHandler', function () { (error, result) => { const { reset, userId } = result expect(error).to.not.exist - const logCall = this.UserAuditLogHandler.promises.addEntry - .lastCall + const logCall = + this.UserAuditLogHandler.promises.addEntry.lastCall expect(logCall.args[0]).to.equal(this.user_id) expect(logCall.args[1]).to.equal('reset-password') expect(logCall.args[2]).to.equal(this.user_id) @@ -337,10 +337,8 @@ describe('PasswordResetHandler', function () { describe('errors', function () { describe('via UserAuditLogHandler', function () { beforeEach(function () { - this.PasswordResetHandler.promises.getUserForPasswordResetToken = sinon - .stub() - .withArgs(this.token) - .resolves(this.user) + this.PasswordResetHandler.promises.getUserForPasswordResetToken = + sinon.stub().withArgs(this.token).resolves(this.user) this.UserAuditLogHandler.promises.addEntry.rejects( new Error('oops') ) diff --git a/services/web/test/unit/src/Project/ProjectControllerTests.js b/services/web/test/unit/src/Project/ProjectControllerTests.js index cacd39511c..412bb8cb0a 100644 --- a/services/web/test/unit/src/Project/ProjectControllerTests.js +++ b/services/web/test/unit/src/Project/ProjectControllerTests.js @@ -184,8 +184,8 @@ describe('ProjectController', function () { '../Subscription/FeaturesUpdater': this.FeaturesUpdater, '../Notifications/NotificationsBuilder': this.NotificationBuilder, '../User/UserGetter': this.UserGetter, - '../BrandVariations/BrandVariationsHandler': this - .BrandVariationsHandler, + '../BrandVariations/BrandVariationsHandler': + this.BrandVariationsHandler, '../ThirdPartyDataStore/TpdsProjectFlusher': this.TpdsProjectFlusher, '../../models/Project': {}, '../Analytics/AnalyticsManager': { recordEventForUser: () => {} }, diff --git a/services/web/test/unit/src/Project/ProjectDeleterTests.js b/services/web/test/unit/src/Project/ProjectDeleterTests.js index 1ea1bb7680..2ba5361eb4 100644 --- a/services/web/test/unit/src/Project/ProjectDeleterTests.js +++ b/services/web/test/unit/src/Project/ProjectDeleterTests.js @@ -143,8 +143,8 @@ describe('ProjectDeleter', function () { '../../models/Project': { Project: Project }, './ProjectHelper': this.ProjectHelper, '../../models/DeletedProject': { DeletedProject: DeletedProject }, - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, '../Tags/TagsHandler': this.TagsHandler, '../FileStore/FileStoreHandler': this.FileStoreHandler, '../ThirdPartyDataStore/TpdsUpdateSender': this.TpdsUpdateSender, @@ -267,10 +267,10 @@ describe('ProjectDeleter', function () { deletedProjectOwnerId: this.project.owner_ref, deletedProjectCollaboratorIds: this.project.collaberator_refs, deletedProjectReadOnlyIds: this.project.readOnly_refs, - deletedProjectReadWriteTokenAccessIds: this.project - .tokenAccessReadAndWrite_refs, - deletedProjectReadOnlyTokenAccessIds: this.project - .tokenAccessReadOnly_refs, + deletedProjectReadWriteTokenAccessIds: + this.project.tokenAccessReadAndWrite_refs, + deletedProjectReadOnlyTokenAccessIds: + this.project.tokenAccessReadOnly_refs, deletedProjectReadWriteToken: this.project.tokens.readAndWrite, deletedProjectReadOnlyToken: this.project.tokens.readOnly, deletedProjectOverleafId: this.project.overleaf.id, diff --git a/services/web/test/unit/src/Project/ProjectDetailsHandlerTests.js b/services/web/test/unit/src/Project/ProjectDetailsHandlerTests.js index dd71d7ce65..a03bb9d6a9 100644 --- a/services/web/test/unit/src/Project/ProjectDetailsHandlerTests.js +++ b/services/web/test/unit/src/Project/ProjectDetailsHandlerTests.js @@ -121,9 +121,10 @@ describe('ProjectDetailsHandler', function () { it('should make a call to mongo just for the description', async function () { this.ProjectGetter.promises.getProject.resolves() await this.handler.promises.getProjectDescription(this.project._id) - expect( - this.ProjectGetter.promises.getProject - ).to.have.been.calledWith(this.project._id, { description: true }) + expect(this.ProjectGetter.promises.getProject).to.have.been.calledWith( + this.project._id, + { description: true } + ) }) it('should return what the mongo call returns', async function () { diff --git a/services/web/test/unit/src/Project/ProjectDuplicatorTests.js b/services/web/test/unit/src/Project/ProjectDuplicatorTests.js index 8968a4554b..0c286bdfc2 100644 --- a/services/web/test/unit/src/Project/ProjectDuplicatorTests.js +++ b/services/web/test/unit/src/Project/ProjectDuplicatorTests.js @@ -204,13 +204,13 @@ describe('ProjectDuplicator', function () { '../../models/Doc': { Doc: this.Doc }, '../../models/File': { File: this.File }, '../Docstore/DocstoreManager': this.DocstoreManager, - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, '../FileStore/FileStoreHandler': this.FileStoreHandler, './ProjectCreationHandler': this.ProjectCreationHandler, './ProjectDeleter': this.ProjectDeleter, - './ProjectEntityMongoUpdateHandler': this - .ProjectEntityMongoUpdateHandler, + './ProjectEntityMongoUpdateHandler': + this.ProjectEntityMongoUpdateHandler, './ProjectEntityUpdateHandler': this.ProjectEntityUpdateHandler, './ProjectGetter': this.ProjectGetter, './ProjectLocator': this.ProjectLocator, diff --git a/services/web/test/unit/src/Project/ProjectEntityHandlerTests.js b/services/web/test/unit/src/Project/ProjectEntityHandlerTests.js index fe24120e16..f6023682a7 100644 --- a/services/web/test/unit/src/Project/ProjectEntityHandlerTests.js +++ b/services/web/test/unit/src/Project/ProjectEntityHandlerTests.js @@ -32,8 +32,8 @@ describe('ProjectEntityHandler', function () { this.ProjectEntityHandler = SandboxedModule.require(modulePath, { requires: { '../Docstore/DocstoreManager': (this.DocstoreManager = {}), - '../../Features/DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../../Features/DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, '../../models/Project': { Project: this.ProjectModel, }, diff --git a/services/web/test/unit/src/Project/ProjectEntityUpdateHandlerTests.js b/services/web/test/unit/src/Project/ProjectEntityUpdateHandlerTests.js index 8536f62c3a..ee2175e523 100644 --- a/services/web/test/unit/src/Project/ProjectEntityUpdateHandlerTests.js +++ b/services/web/test/unit/src/Project/ProjectEntityUpdateHandlerTests.js @@ -154,8 +154,8 @@ describe('ProjectEntityUpdateHandler', function () { fs: this.fs, '../../models/Doc': { Doc: this.DocModel }, '../Docstore/DocstoreManager': this.DocstoreManager, - '../../Features/DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../../Features/DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, '../../models/File': { File: this.FileModel }, '../FileStore/FileStoreHandler': this.FileStoreHandler, '../../infrastructure/LockManager': this.LockManager, @@ -164,8 +164,8 @@ describe('ProjectEntityUpdateHandler', function () { './ProjectLocator': this.ProjectLocator, './ProjectUpdateHandler': this.ProjectUpdater, './ProjectEntityHandler': this.ProjectEntityHandler, - './ProjectEntityMongoUpdateHandler': this - .ProjectEntityMongoUpdateHandler, + './ProjectEntityMongoUpdateHandler': + this.ProjectEntityMongoUpdateHandler, '../ThirdPartyDataStore/TpdsUpdateSender': this.TpdsUpdateSender, '../Editor/EditorRealTimeController': this.EditorRealTimeController, '../../infrastructure/FileWriter': this.FileWriter, diff --git a/services/web/test/unit/src/Project/ProjectGetterTests.js b/services/web/test/unit/src/Project/ProjectGetterTests.js index 6f459bf8e4..3b835c3f7a 100644 --- a/services/web/test/unit/src/Project/ProjectGetterTests.js +++ b/services/web/test/unit/src/Project/ProjectGetterTests.js @@ -55,8 +55,8 @@ describe('ProjectGetter', function () { }, '../Collaborators/CollaboratorsGetter': this.CollaboratorsGetter, '../../infrastructure/LockManager': this.LockManager, - './ProjectEntityMongoUpdateHandler': this - .ProjectEntityMongoUpdateHandler, + './ProjectEntityMongoUpdateHandler': + this.ProjectEntityMongoUpdateHandler, }, }) }) diff --git a/services/web/test/unit/src/Publishers/PublishersGetterTests.js b/services/web/test/unit/src/Publishers/PublishersGetterTests.js index b003b23bf6..7103e4ddf2 100644 --- a/services/web/test/unit/src/Publishers/PublishersGetterTests.js +++ b/services/web/test/unit/src/Publishers/PublishersGetterTests.js @@ -30,20 +30,22 @@ describe('PublishersGetter', function () { this.PublishersGetter = SandboxedModule.require(modulePath, { requires: { '../User/UserGetter': this.UserGetter, - '../UserMembership/UserMembershipsHandler': (this.UserMembershipsHandler = { - getEntitiesByUser: sinon - .stub() - .callsArgWith(2, null, [this.publisher]), - }), - '../UserMembership/UserMembershipEntityConfigs': (this.UserMembershipEntityConfigs = { - publisher: { - modelName: 'Publisher', - canCreate: true, - fields: { - primaryKey: 'slug', + '../UserMembership/UserMembershipsHandler': + (this.UserMembershipsHandler = { + getEntitiesByUser: sinon + .stub() + .callsArgWith(2, null, [this.publisher]), + }), + '../UserMembership/UserMembershipEntityConfigs': + (this.UserMembershipEntityConfigs = { + publisher: { + modelName: 'Publisher', + canCreate: true, + fields: { + primaryKey: 'slug', + }, }, - }, - }), + }), }, }) diff --git a/services/web/test/unit/src/References/ReferencesHandlerTests.js b/services/web/test/unit/src/References/ReferencesHandlerTests.js index b0fa942aee..272ef49336 100644 --- a/services/web/test/unit/src/References/ReferencesHandlerTests.js +++ b/services/web/test/unit/src/References/ReferencesHandlerTests.js @@ -64,9 +64,10 @@ describe('ReferencesHandler', function () { '../User/UserGetter': (this.UserGetter = { getUser: sinon.stub(), }), - '../DocumentUpdater/DocumentUpdaterHandler': (this.DocumentUpdaterHandler = { - flushDocToMongo: sinon.stub().callsArgWith(2, null), - }), + '../DocumentUpdater/DocumentUpdaterHandler': + (this.DocumentUpdaterHandler = { + flushDocToMongo: sinon.stub().callsArgWith(2, null), + }), '../../infrastructure/Features': (this.Features = { hasFeature: sinon.stub().returns(true), }), diff --git a/services/web/test/unit/src/Spelling/SpellingControllerTests.js b/services/web/test/unit/src/Spelling/SpellingControllerTests.js index c4b72fff3f..ae450280ff 100644 --- a/services/web/test/unit/src/Spelling/SpellingControllerTests.js +++ b/services/web/test/unit/src/Spelling/SpellingControllerTests.js @@ -36,8 +36,8 @@ describe('SpellingController', function () { ], apis: { spelling: { host: SPELLING_HOST, url: SPELLING_URL } }, }, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, }, }) this.req = { diff --git a/services/web/test/unit/src/Subscription/FeaturesUpdaterTests.js b/services/web/test/unit/src/Subscription/FeaturesUpdaterTests.js index 1e6e6c32f9..12675055ae 100644 --- a/services/web/test/unit/src/Subscription/FeaturesUpdaterTests.js +++ b/services/web/test/unit/src/Subscription/FeaturesUpdaterTests.js @@ -127,13 +127,11 @@ describe('FeaturesUpdater', function () { describe('refreshFeatures', function () { it('should return features and featuresChanged', async function () { - const { - features, - featuresChanged, - } = await this.FeaturesUpdater.promises.refreshFeatures( - this.user._id, - 'test' - ) + const { features, featuresChanged } = + await this.FeaturesUpdater.promises.refreshFeatures( + this.user._id, + 'test' + ) expect(features).to.exist expect(featuresChanged).to.exist }) diff --git a/services/web/test/unit/src/Subscription/LimitationsManagerTests.js b/services/web/test/unit/src/Subscription/LimitationsManagerTests.js index f70af9b305..a8934e6899 100644 --- a/services/web/test/unit/src/Subscription/LimitationsManagerTests.js +++ b/services/web/test/unit/src/Subscription/LimitationsManagerTests.js @@ -41,7 +41,8 @@ describe('LimitationsManager', function () { './SubscriptionLocator': this.SubscriptionLocator, '@overleaf/settings': (this.Settings = {}), '../Collaborators/CollaboratorsGetter': (this.CollaboratorsGetter = {}), - '../Collaborators/CollaboratorsInviteHandler': (this.CollaboratorsInviteHandler = {}), + '../Collaborators/CollaboratorsInviteHandler': + (this.CollaboratorsInviteHandler = {}), './V1SubscriptionManager': (this.V1SubscriptionManager = {}), }, }) diff --git a/services/web/test/unit/src/Subscription/RecurlyWrapperTests.js b/services/web/test/unit/src/Subscription/RecurlyWrapperTests.js index fdc9d77dc5..81e2c7e080 100644 --- a/services/web/test/unit/src/Subscription/RecurlyWrapperTests.js +++ b/services/web/test/unit/src/Subscription/RecurlyWrapperTests.js @@ -141,16 +141,14 @@ describe('RecurlyWrapper', function () { } tk.freeze(Date.now()) // freeze the time for these tests - return (this.RecurlyWrapper = RecurlyWrapper = SandboxedModule.require( - modulePath, - { + return (this.RecurlyWrapper = RecurlyWrapper = + SandboxedModule.require(modulePath, { requires: { '@overleaf/settings': this.settings, request: sinon.stub(), './Errors': SubscriptionErrors, }, - } - )) + })) }) afterEach(function () { diff --git a/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js b/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js index 09273f83fe..170afae8de 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js +++ b/services/web/test/unit/src/Subscription/SubscriptionControllerTests.js @@ -467,7 +467,8 @@ describe('SubscriptionController', function () { threeDSecureActionResult: '5678', } this.req.body.recurly_token_id = this.recurlyTokenIds.billing - this.req.body.recurly_three_d_secure_action_result_token_id = this.recurlyTokenIds.threeDSecureActionResult + this.req.body.recurly_three_d_secure_action_result_token_id = + this.recurlyTokenIds.threeDSecureActionResult this.req.body.subscriptionDetails = this.subscriptionDetails this.LimitationsManager.userHasV1OrV2Subscription.yields(null, false) return this.SubscriptionController.createSubscription(this.req, this.res) diff --git a/services/web/test/unit/src/Subscription/SubscriptionGroupHandlerTests.js b/services/web/test/unit/src/Subscription/SubscriptionGroupHandlerTests.js index 22b6951c53..6b8a88df8a 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionGroupHandlerTests.js +++ b/services/web/test/unit/src/Subscription/SubscriptionGroupHandlerTests.js @@ -99,8 +99,8 @@ describe('SubscriptionGroupHandler', function () { '../Email/EmailHandler': this.EmailHandler, '@overleaf/settings': this.settings, '../Notifications/NotificationsBuilder': this.NotificationsBuilder, - '../UserMembership/UserMembershipViewModel': this - .UserMembershipViewModel, + '../UserMembership/UserMembershipViewModel': + this.UserMembershipViewModel, }, })) }) diff --git a/services/web/test/unit/src/Subscription/SubscriptionHandlerTests.js b/services/web/test/unit/src/Subscription/SubscriptionHandlerTests.js index c2f9448c18..e5281969ec 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionHandlerTests.js +++ b/services/web/test/unit/src/Subscription/SubscriptionHandlerTests.js @@ -202,8 +202,8 @@ describe('SubscriptionHandler', function () { expect( this.RecurlyClient.changeSubscriptionByUuid ).to.have.been.calledWith(this.subscription.recurlySubscription_id) - const updateOptions = this.RecurlyClient.changeSubscriptionByUuid - .args[0][1] + const updateOptions = + this.RecurlyClient.changeSubscriptionByUuid.args[0][1] updateOptions.planCode.should.equal(this.plan_code) }) } @@ -252,8 +252,8 @@ describe('SubscriptionHandler', function () { shouldSyncSubscription() it('should update with timeframe ' + timeframe, function () { - const updateOptions = this.RecurlyClient.changeSubscriptionByUuid - .args[0][1] + const updateOptions = + this.RecurlyClient.changeSubscriptionByUuid.args[0][1] updateOptions.timeframe.should.equal(timeframe) }) } @@ -364,8 +364,8 @@ describe('SubscriptionHandler', function () { expect(this.RecurlyClient.changeSubscriptionByUuid).to.be.calledWith( this.subscription.recurlySubscription_id ) - const updateOptions = this.RecurlyClient.changeSubscriptionByUuid - .args[0][1] + const updateOptions = + this.RecurlyClient.changeSubscriptionByUuid.args[0][1] updateOptions.planCode.should.equal(this.plan_code) }) }) diff --git a/services/web/test/unit/src/Templates/TemplatesControllerTests.js b/services/web/test/unit/src/Templates/TemplatesControllerTests.js index dd43000941..af9d927ed9 100644 --- a/services/web/test/unit/src/Templates/TemplatesControllerTests.js +++ b/services/web/test/unit/src/Templates/TemplatesControllerTests.js @@ -24,9 +24,10 @@ describe('TemplatesController', function () { this.TemplatesController = SandboxedModule.require(modulePath, { requires: { '../Project/ProjectHelper': ProjectHelper, - '../Authentication/AuthenticationController': (this.AuthenticationController = { - getLoggedInUserId: sinon.stub().returns(this.user_id), - }), + '../Authentication/AuthenticationController': + (this.AuthenticationController = { + getLoggedInUserId: sinon.stub().returns(this.user_id), + }), './TemplatesManager': (this.TemplatesManager = { createProjectFromV1Template: sinon.stub(), }), diff --git a/services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js b/services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js index bcdec7f9ff..1d00d14cac 100644 --- a/services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js +++ b/services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js @@ -47,8 +47,8 @@ describe('TpdsProjectFlusher', function () { this.TpdsProjectFlusher = SandboxedModule.require(MODULE_PATH, { requires: { - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, '../Project/ProjectGetter': this.ProjectGetter, '../Project/ProjectEntityHandler': this.ProjectEntityHandler, '../../models/Project': { Project }, diff --git a/services/web/test/unit/src/Uploads/ProjectUploadManagerTests.js b/services/web/test/unit/src/Uploads/ProjectUploadManagerTests.js index 125236937c..233095fd44 100644 --- a/services/web/test/unit/src/Uploads/ProjectUploadManagerTests.js +++ b/services/web/test/unit/src/Uploads/ProjectUploadManagerTests.js @@ -151,13 +151,13 @@ describe('ProjectUploadManager', function () { '../../models/Doc': { Doc: this.Doc }, '../Docstore/DocstoreManager': this.DocstoreManager, '../Documents/DocumentHelper': this.DocumentHelper, - '../DocumentUpdater/DocumentUpdaterHandler': this - .DocumentUpdaterHandler, + '../DocumentUpdater/DocumentUpdaterHandler': + this.DocumentUpdaterHandler, '../FileStore/FileStoreHandler': this.FileStoreHandler, './FileSystemImportManager': this.FileSystemImportManager, '../Project/ProjectCreationHandler': this.ProjectCreationHandler, - '../Project/ProjectEntityMongoUpdateHandler': this - .ProjectEntityMongoUpdateHandler, + '../Project/ProjectEntityMongoUpdateHandler': + this.ProjectEntityMongoUpdateHandler, '../Project/ProjectRootDocManager': this.ProjectRootDocManager, '../Project/ProjectDetailsHandler': this.ProjectDetailsHandler, '../Project/ProjectDeleter': this.ProjectDeleter, diff --git a/services/web/test/unit/src/User/ThirdPartyIdentityManagerTests.js b/services/web/test/unit/src/User/ThirdPartyIdentityManagerTests.js index 54e3e3ecb6..3667a7cb93 100644 --- a/services/web/test/unit/src/User/ThirdPartyIdentityManagerTests.js +++ b/services/web/test/unit/src/User/ThirdPartyIdentityManagerTests.js @@ -16,12 +16,14 @@ describe('ThirdPartyIdentityManager', function () { this.auditLog = { initiatorId: this.userId, ipAddress: '0:0:0:0' } this.ThirdPartyIdentityManager = SandboxedModule.require(modulePath, { requires: { - '../../../../app/src/Features/User/UserAuditLogHandler': (this.UserAuditLogHandler = { - addEntry: sinon.stub().yields(), - }), - '../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler = { - sendEmail: sinon.stub().yields(), - }), + '../../../../app/src/Features/User/UserAuditLogHandler': + (this.UserAuditLogHandler = { + addEntry: sinon.stub().yields(), + }), + '../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler = + { + sendEmail: sinon.stub().yields(), + }), '../../../../app/src/models/User': { User: (this.User = { findOneAndUpdate: sinon.stub().yields(undefined, this.user), diff --git a/services/web/test/unit/src/User/UserControllerTests.js b/services/web/test/unit/src/User/UserControllerTests.js index 77cf549500..8440e6c4e4 100644 --- a/services/web/test/unit/src/User/UserControllerTests.js +++ b/services/web/test/unit/src/User/UserControllerTests.js @@ -105,8 +105,8 @@ describe('UserController', function () { }, '../Newsletter/NewsletterManager': this.NewsLetterManager, './UserRegistrationHandler': this.UserRegistrationHandler, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, '../Authentication/SessionManager': this.SessionManager, '../Authentication/AuthenticationManager': this.AuthenticationManager, '../../infrastructure/Features': (this.Features = { diff --git a/services/web/test/unit/src/User/UserCreatorTests.js b/services/web/test/unit/src/User/UserCreatorTests.js index b1c0b8c874..cc447bc358 100644 --- a/services/web/test/unit/src/User/UserCreatorTests.js +++ b/services/web/test/unit/src/User/UserCreatorTests.js @@ -48,9 +48,10 @@ describe('UserCreator', function () { './UserOnboardingEmailManager': (this.UserOnboardingEmailManager = { scheduleOnboardingEmail: sinon.stub(), }), - './UserPostRegistrationAnalyticsManager': (this.UserPostRegistrationAnalyticsManager = { - schedulePostRegistrationAnalytics: sinon.stub(), - }), + './UserPostRegistrationAnalyticsManager': + (this.UserPostRegistrationAnalyticsManager = { + schedulePostRegistrationAnalytics: sinon.stub(), + }), }, }) diff --git a/services/web/test/unit/src/User/UserEmailsControllerTests.js b/services/web/test/unit/src/User/UserEmailsControllerTests.js index da948cf004..303ce150ba 100644 --- a/services/web/test/unit/src/User/UserEmailsControllerTests.js +++ b/services/web/test/unit/src/User/UserEmailsControllerTests.js @@ -62,12 +62,13 @@ describe('UserEmailsController', function () { }, }), '../Helpers/EmailHelper': this.EmailHelper, - './UserEmailsConfirmationHandler': (this.UserEmailsConfirmationHandler = { - sendReconfirmationEmail: sinon.stub(), - promises: { - sendConfirmationEmail: sinon.stub().resolves(), - }, - }), + './UserEmailsConfirmationHandler': (this.UserEmailsConfirmationHandler = + { + sendReconfirmationEmail: sinon.stub(), + promises: { + sendConfirmationEmail: sinon.stub().resolves(), + }, + }), '../Institutions/InstitutionsAPI': this.InstitutionsAPI, '../Errors/HttpErrorHandler': this.HttpErrorHandler, }, @@ -132,8 +133,8 @@ describe('UserEmailsController', function () { this.newEmail ) - const affiliationOptions = this.UserUpdater.promises.addEmailAddress - .lastCall.args[2] + const affiliationOptions = + this.UserUpdater.promises.addEmailAddress.lastCall.args[2] Object.keys(affiliationOptions).length.should.equal(3) affiliationOptions.university.should.equal(this.req.body.university) affiliationOptions.department.should.equal(this.req.body.department) diff --git a/services/web/test/unit/src/User/UserPagesControllerTests.js b/services/web/test/unit/src/User/UserPagesControllerTests.js index 279aea69ff..deef5bc2ca 100644 --- a/services/web/test/unit/src/User/UserPagesControllerTests.js +++ b/services/web/test/unit/src/User/UserPagesControllerTests.js @@ -63,8 +63,8 @@ describe('UserPagesController', function () { './UserGetter': this.UserGetter, './UserSessionsManager': this.UserSessionsManager, '../Errors/ErrorController': this.ErrorController, - '../Authentication/AuthenticationController': this - .AuthenticationController, + '../Authentication/AuthenticationController': + this.AuthenticationController, '../Authentication/SessionManager': this.SessionManager, request: (this.request = sinon.stub()), }, diff --git a/services/web/test/unit/src/User/UserUpdaterTests.js b/services/web/test/unit/src/User/UserUpdaterTests.js index f8489fb975..c5f0128bdd 100644 --- a/services/web/test/unit/src/User/UserUpdaterTests.js +++ b/services/web/test/unit/src/User/UserUpdaterTests.js @@ -670,11 +670,11 @@ describe('UserUpdater', function () { error => { expect(error).to.not.exist this.EmailHandler.promises.sendEmail.callCount.should.equal(2) - const toOldEmailAlert = this.EmailHandler.promises.sendEmail - .firstCall + const toOldEmailAlert = + this.EmailHandler.promises.sendEmail.firstCall expect(toOldEmailAlert.args[0]).to.equal('securityAlert') - const toNewEmailAlert = this.EmailHandler.promises.sendEmail - .lastCall + const toNewEmailAlert = + this.EmailHandler.promises.sendEmail.lastCall expect(toOldEmailAlert.args[1].to).to.equal(this.stubbedUser.email) expect(toNewEmailAlert.args[0]).to.equal('securityAlert') expect(toNewEmailAlert.args[1].to).to.equal(this.newEmail) diff --git a/services/web/test/unit/src/infrastructure/GeoIpLookupTest.js b/services/web/test/unit/src/infrastructure/GeoIpLookupTest.js index 2e2b6f392a..8fafd64b4b 100644 --- a/services/web/test/unit/src/infrastructure/GeoIpLookupTest.js +++ b/services/web/test/unit/src/infrastructure/GeoIpLookupTest.js @@ -227,10 +227,8 @@ describe('GeoIpLookup', function () { describe('async', function () { it('should return GBP for GB country', async function () { this.request.get.callsArgWith(1, null, null, this.stubbedResponse) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('GBP') countryCode.should.equal('GB') }) @@ -238,10 +236,8 @@ describe('GeoIpLookup', function () { it('should return GBP for gb country', async function () { this.stubbedResponse.country_code = 'gb' this.request.get.callsArgWith(1, null, null, this.stubbedResponse) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('GBP') countryCode.should.equal('GB') }) @@ -249,10 +245,8 @@ describe('GeoIpLookup', function () { it('should return USD for US', async function () { this.stubbedResponse.country_code = 'US' this.request.get.callsArgWith(1, null, null, this.stubbedResponse) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('USD') countryCode.should.equal('US') }) @@ -260,30 +254,24 @@ describe('GeoIpLookup', function () { it('should return EUR for DE', async function () { this.stubbedResponse.country_code = 'DE' this.request.get.callsArgWith(1, null, null, this.stubbedResponse) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('EUR') countryCode.should.equal('DE') }) it('should default to USD if there is an error', async function () { this.request.get.callsArgWith(1, null, null, { error: true }) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('USD') expect(countryCode).to.be.undefined }) it('should default to USD if there are no details', async function () { this.request.get.callsArgWith(1, null, null, {}) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('USD') expect(countryCode).to.be.undefined }) @@ -291,10 +279,8 @@ describe('GeoIpLookup', function () { it('should default to USD if there is no match for their country', async function () { this.stubbedResponse.country_code = 'Non existant' this.request.get.callsArgWith(1, null, null, this.stubbedResponse) - const { - currencyCode, - countryCode, - } = await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) + const { currencyCode, countryCode } = + await this.GeoIpLookup.promises.getCurrencyCode(this.ipAddress) currencyCode.should.equal('USD') countryCode.should.equal('NON EXISTANT') })