From beb6f6d484bdf932527a46bce1f3d5a15b318467 Mon Sep 17 00:00:00 2001 From: Andrew Rumble Date: Thu, 20 Nov 2025 09:06:38 +0000 Subject: [PATCH] Merge pull request #29597 from overleaf/ar-last-features-esm-conversion [web] last features esm conversion GitOrigin-RevId: a35ab995bf654f1cdfe0e0062d8806761ecccf2d --- services/web/.eslintrc.js | 2 + .../Analytics/AnalyticsController.mjs | 2 +- .../Features/Analytics/AnalyticsManager.mjs | 2 +- .../AuthenticationController.mjs | 4 +- ...tionErrors.js => AuthenticationErrors.mjs} | 22 +-- .../Authentication/AuthenticationManager.mjs | 2 +- .../Authorization/AuthorizationManager.mjs | 4 +- .../Authorization/PermissionsController.mjs | 2 +- ...PrivilegeLevels.js => PrivilegeLevels.mjs} | 2 +- .../BrandVariationsHandler.mjs | 2 +- .../Collaborators/CollaboratorsController.mjs | 4 +- .../Collaborators/CollaboratorsGetter.mjs | 2 +- .../Collaborators/CollaboratorsHandler.mjs | 2 +- .../CollaboratorsInviteController.mjs | 2 +- .../CollaboratorsInviteGetter.mjs | 2 +- .../CollaboratorsInviteHandler.mjs | 2 +- .../OwnershipTransferHandler.mjs | 2 +- .../src/Features/Compile/ClsiCacheHandler.mjs | 2 +- .../src/Features/Compile/ClsiCacheManager.mjs | 2 +- .../Features/Compile/CompileController.mjs | 2 +- .../Features/Editor/EditorHttpController.mjs | 2 +- .../{NoCTAEmailBody.js => NoCTAEmailBody.mjs} | 4 +- .../Bodies/{cta-email.js => cta-email.mjs} | 4 +- .../app/src/Features/Email/EmailBuilder.mjs | 8 +- .../app/src/Features/Email/EmailHandler.mjs | 2 +- ...essageHelper.js => EmailMessageHelper.mjs} | 4 +- ...ayout.js => BaseWithHeaderEmailLayout.mjs} | 6 +- .../Features/Helpers/{Mongo.js => Mongo.mjs} | 10 +- .../Features/History/HistoryController.mjs | 2 +- .../Features/Project/ProjectController.mjs | 6 +- .../Project/ProjectCreationHandler.mjs | 2 +- .../Project/ProjectDetailsHandler.mjs | 2 +- .../src/Features/Project/ProjectGetter.mjs | 4 +- .../Project/ProjectListController.mjs | 4 +- ...ginRateLimiter.js => LoginRateLimiter.mjs} | 8 +- .../Security/RateLimiterMiddleware.mjs | 2 +- .../Features/SplitTests/SplitTestHandler.mjs | 2 +- .../Features/StaticPages/HomeController.mjs | 2 +- .../{AiHelper.js => AiHelper.mjs} | 12 +- .../Subscription/{Errors.js => Errors.mjs} | 35 ++-- .../Features/Subscription/FeaturesUpdater.mjs | 4 +- .../{GroupPlansData.js => GroupPlansData.mjs} | 10 +- .../Subscription/LimitationsManager.mjs | 2 +- .../Subscription/PaymentProviderEntities.mjs | 4 +- .../Features/Subscription/RecurlyClient.mjs | 4 +- .../Subscription/RecurlyEventHandler.mjs | 2 +- .../Features/Subscription/RecurlyWrapper.mjs | 2 +- .../Subscription/SubscriptionController.mjs | 6 +- .../Subscription/SubscriptionEmailBuilder.mjs | 2 +- .../SubscriptionGroupController.mjs | 2 +- .../Subscription/SubscriptionGroupHandler.mjs | 4 +- .../Subscription/SubscriptionHelper.mjs | 4 +- .../Subscription/SubscriptionLocator.mjs | 4 +- .../Subscription/SubscriptionUpdater.mjs | 2 +- .../SubscriptionViewModelBuilder.mjs | 2 +- .../TokenAccess/TokenAccessController.mjs | 2 +- .../TokenAccess/TokenAccessHandler.mjs | 6 +- .../{TokenGenerator.js => TokenGenerator.mjs} | 10 +- .../{ArchiveErrors.js => ArchiveErrors.mjs} | 10 +- .../src/Features/Uploads/ArchiveManager.mjs | 2 +- .../Uploads/ProjectUploadController.mjs | 2 +- .../app/src/Features/User/UserController.mjs | 2 +- .../web/app/src/Features/User/UserCreator.mjs | 2 +- .../Features/User/UserEmailsController.mjs | 2 +- .../web/app/src/Features/User/UserGetter.mjs | 5 +- .../User/UserOnboardingEmailManager.mjs | 2 +- .../src/Features/User/UserPagesController.mjs | 2 +- .../UserPostRegistrationAnalyticsManager.mjs | 2 +- .../web/app/src/Features/User/UserUpdater.mjs | 6 +- .../UserMembershipViewModel.mjs | 4 +- .../src/Features/V1/{V1Api.js => V1Api.mjs} | 11 +- .../web/app/src/Features/V1/V1Handler.mjs | 2 +- .../app/src/infrastructure/ExpressLocals.mjs | 2 +- .../{Features.js => Features.mjs} | 6 +- .../app/src/infrastructure/QueueWorkers.mjs | 4 +- .../infrastructure/{Queues.js => Queues.mjs} | 10 +- .../web/app/src/infrastructure/Server.mjs | 2 +- .../src/infrastructure/SiteAdminHandler.mjs | 2 +- services/web/app/src/models/User.mjs | 2 +- services/web/app/src/router.mjs | 2 +- .../backfill_mixpanel_user_properties.mjs | 3 +- .../regenerate_duplicate_referral_ids.mjs | 2 +- .../acceptance/src/ActiveUsersMetricTests.mjs | 2 +- .../acceptance/src/AddSecondaryEmailTests.mjs | 2 +- .../acceptance/src/AuthorizationTests.mjs | 2 +- .../web/test/acceptance/src/DeletionTests.mjs | 2 +- services/web/test/acceptance/src/Init.mjs | 2 +- .../web/test/acceptance/src/MongoHelper.mjs | 7 +- .../acceptance/src/PrimaryEmailCheckTests.mjs | 2 +- .../test/acceptance/src/ProjectCRUDTests.mjs | 2 +- .../acceptance/src/ProjectInviteTests.mjs | 2 +- .../test/acceptance/src/RegistrationTests.mjs | 2 +- .../web/test/acceptance/src/SettingsTests.mjs | 2 +- .../test/acceptance/src/UserHelperTests.mjs | 2 +- .../smoke/src/steps/001_clearRateLimits.mjs | 2 +- services/web/test/unit/bootstrap.js | 5 +- .../Analytics/AnalyticsController.test.mjs | 6 +- .../src/Analytics/AnalyticsManager.test.mjs | 10 +- .../AnalyticsUTMTrackingMiddleware.test.mjs | 8 +- .../src/Analytics/EmailChangeHelpers.test.mjs | 4 +- .../AuthenticationController.test.mjs | 10 +- .../AuthenticationManager.test.mjs | 2 +- .../AuthorizationManager.test.mjs | 2 +- .../BetaProgramController.test.mjs | 8 +- .../unit/src/Chat/ChatApiHandler.test.mjs | 2 +- .../CollaboratorsController.test.mjs | 8 +- .../CollaboratorsGetter.test.mjs | 2 +- .../CollaboratorsHandler.test.mjs | 2 +- .../CollaboratorsInviteController.test.mjs | 117 +++++++------- .../CollaboratorsInviteGetter.test.mjs | 2 +- .../CollaboratorsInviteHandler.test.mjs | 2 +- .../OwnershipTransferHandler.test.mjs | 2 +- .../unit/src/Compile/ClsiManager.test.mjs | 2 +- .../src/Compile/CompileController.test.mjs | 24 +-- .../src/Contact/ContactController.test.mjs | 6 +- .../DocumentUpdaterHandler.test.mjs | 2 +- .../ProjectZipStreamManager.test.mjs | 2 +- .../src/Editor/EditorHttpController.test.mjs | 24 +-- .../Editor/EditorRealTimeController.test.mjs | 2 +- .../test/unit/src/Email/EmailBuilder.test.mjs | 10 +- .../test/unit/src/Email/EmailHandler.test.mjs | 2 +- .../src/Email/EmailMessageHelper.test.mjs | 28 ++++ .../unit/src/Email/EmailMessageHelperTests.js | 35 ---- .../test/unit/src/Email/EmailSender.test.mjs | 2 +- .../src/History/HistoryController.test.mjs | 2 +- .../src/Institutions/InstitutionsAPI.test.mjs | 2 +- .../Institutions/InstitutionsManager.test.mjs | 4 +- .../src/Project/ProjectController.test.mjs | 2 +- .../Project/ProjectListController.test.mjs | 2 + .../src/Security/LoginRateLimiter.test.mjs | 77 +++++++++ .../src/Security/LoginRateLimiterTests.js | 80 --------- .../src/SplitTests/SplitTestHandler.test.mjs | 2 +- .../SplitTestSessionHandler.test.mjs | 2 +- .../src/Subscription/FeaturesUpdater.test.mjs | 2 +- .../PaymentProviderEntities.test.mjs | 4 +- .../src/Subscription/RecurlyWrapper.test.mjs | 2 +- .../SubscriptionController.test.mjs | 4 +- .../V1SusbcriptionManager.test.mjs | 2 +- .../TpdsUpdateSender.test.mjs | 2 +- .../ThirdPartyDataStore/UpdateMerger.test.mjs | 2 +- .../TokenAccessController.test.mjs | 2 +- .../TokenAccess/TokenAccessHandler.test.mjs | 4 +- .../unit/src/Uploads/ArchiveManager.test.mjs | 4 +- .../Uploads/ProjectUploadController.test.mjs | 2 +- .../test/unit/src/User/UserGetter.test.mjs | 13 +- .../src/User/UserPagesController.test.mjs | 2 +- .../src/User/UserRegistrationHandler.test.mjs | 2 +- .../test/unit/src/User/UserUpdater.test.mjs | 9 +- .../UserMembershipViewModel.test.mjs | 9 +- .../unit/src/helpers/MockResponseVitest.mjs | 2 +- .../unit/src/infrastructure/Features.test.mjs | 151 +++++++++++++++++ .../unit/src/infrastructure/FeaturesTests.js | 152 ------------------ .../src/infrastructure/GeoIpLookup.test.mjs | 2 +- 153 files changed, 632 insertions(+), 623 deletions(-) rename services/web/app/src/Features/Authentication/{AuthenticationErrors.js => AuthenticationErrors.mjs} (67%) rename services/web/app/src/Features/Authorization/{PrivilegeLevels.js => PrivilegeLevels.mjs} (86%) rename services/web/app/src/Features/Email/Bodies/{NoCTAEmailBody.js => NoCTAEmailBody.mjs} (97%) rename services/web/app/src/Features/Email/Bodies/{cta-email.js => cta-email.mjs} (98%) rename services/web/app/src/Features/Email/{EmailMessageHelper.js => EmailMessageHelper.mjs} (89%) rename services/web/app/src/Features/Email/Layouts/{BaseWithHeaderEmailLayout.js => BaseWithHeaderEmailLayout.mjs} (99%) rename services/web/app/src/Features/Helpers/{Mongo.js => Mongo.mjs} (86%) rename services/web/app/src/Features/Security/{LoginRateLimiter.js => LoginRateLimiter.mjs} (78%) rename services/web/app/src/Features/Subscription/{AiHelper.js => AiHelper.mjs} (78%) rename services/web/app/src/Features/Subscription/{Errors.js => Errors.mjs} (57%) rename services/web/app/src/Features/Subscription/{GroupPlansData.js => GroupPlansData.mjs} (92%) rename services/web/app/src/Features/TokenGenerator/{TokenGenerator.js => TokenGenerator.mjs} (92%) rename services/web/app/src/Features/Uploads/{ArchiveErrors.js => ArchiveErrors.mjs} (59%) rename services/web/app/src/Features/V1/{V1Api.js => V1Api.mjs} (93%) rename services/web/app/src/infrastructure/{Features.js => Features.mjs} (96%) rename services/web/app/src/infrastructure/{Queues.js => Queues.mjs} (93%) create mode 100644 services/web/test/unit/src/Email/EmailMessageHelper.test.mjs delete mode 100644 services/web/test/unit/src/Email/EmailMessageHelperTests.js create mode 100644 services/web/test/unit/src/Security/LoginRateLimiter.test.mjs delete mode 100644 services/web/test/unit/src/Security/LoginRateLimiterTests.js create mode 100644 services/web/test/unit/src/infrastructure/Features.test.mjs delete mode 100644 services/web/test/unit/src/infrastructure/FeaturesTests.js diff --git a/services/web/.eslintrc.js b/services/web/.eslintrc.js index 8056ffd48b..f8602a5b92 100644 --- a/services/web/.eslintrc.js +++ b/services/web/.eslintrc.js @@ -137,6 +137,8 @@ module.exports = { 'app.mjs', 'scripts/**/*.mjs', 'migrations/**/*.mjs', + 'test/acceptance/src/**/*.mjs', + 'test/unit/src/**/*.mjs', ], excludedFiles: [ // migration template file diff --git a/services/web/app/src/Features/Analytics/AnalyticsController.mjs b/services/web/app/src/Features/Analytics/AnalyticsController.mjs index 2c9305dd50..76b5452e58 100644 --- a/services/web/app/src/Features/Analytics/AnalyticsController.mjs +++ b/services/web/app/src/Features/Analytics/AnalyticsController.mjs @@ -2,7 +2,7 @@ import metrics from '@overleaf/metrics' import AnalyticsManager from './AnalyticsManager.mjs' import SessionManager from '../Authentication/SessionManager.mjs' import GeoIpLookup from '../../infrastructure/GeoIpLookup.mjs' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import { expressify } from '@overleaf/promise-utils' import AccountMappingHelper from './AccountMappingHelper.mjs' diff --git a/services/web/app/src/Features/Analytics/AnalyticsManager.mjs b/services/web/app/src/Features/Analytics/AnalyticsManager.mjs index 272cf68497..014934905c 100644 --- a/services/web/app/src/Features/Analytics/AnalyticsManager.mjs +++ b/services/web/app/src/Features/Analytics/AnalyticsManager.mjs @@ -2,7 +2,7 @@ import SessionManager from '../Authentication/SessionManager.mjs' import UserAnalyticsIdCache from './UserAnalyticsIdCache.mjs' import Settings from '@overleaf/settings' import Metrics from '../../infrastructure/Metrics.js' -import Queues from '../../infrastructure/Queues.js' +import Queues from '../../infrastructure/Queues.mjs' import crypto, { createHash } from 'node:crypto' import _ from 'lodash' import { expressify } from '@overleaf/promise-utils' diff --git a/services/web/app/src/Features/Authentication/AuthenticationController.mjs b/services/web/app/src/Features/Authentication/AuthenticationController.mjs index f698c2fd3e..7f6187dfc2 100644 --- a/services/web/app/src/Features/Authentication/AuthenticationController.mjs +++ b/services/web/app/src/Features/Authentication/AuthenticationController.mjs @@ -1,7 +1,7 @@ import AuthenticationManager from './AuthenticationManager.mjs' import SessionManager from './SessionManager.mjs' import OError from '@overleaf/o-error' -import LoginRateLimiter from '../Security/LoginRateLimiter.js' +import LoginRateLimiter from '../Security/LoginRateLimiter.mjs' import UserUpdater from '../User/UserUpdater.mjs' import Metrics from '@overleaf/metrics' import logger from '@overleaf/logger' @@ -23,7 +23,7 @@ import { acceptsJson } from '../../infrastructure/RequestContentTypeDetection.js import AdminAuthorizationHelper from '../Helpers/AdminAuthorizationHelper.mjs' import Modules from '../../infrastructure/Modules.js' import { expressify, promisify } from '@overleaf/promise-utils' -import { handleAuthenticateErrors } from './AuthenticationErrors.js' +import { handleAuthenticateErrors } from './AuthenticationErrors.mjs' import EmailHelper from '../Helpers/EmailHelper.mjs' const { hasAdminAccess } = AdminAuthorizationHelper diff --git a/services/web/app/src/Features/Authentication/AuthenticationErrors.js b/services/web/app/src/Features/Authentication/AuthenticationErrors.mjs similarity index 67% rename from services/web/app/src/Features/Authentication/AuthenticationErrors.js rename to services/web/app/src/Features/Authentication/AuthenticationErrors.mjs index c5dc8bac33..dc1d0cbd8d 100644 --- a/services/web/app/src/Features/Authentication/AuthenticationErrors.js +++ b/services/web/app/src/Features/Authentication/AuthenticationErrors.mjs @@ -1,15 +1,15 @@ -const Metrics = require('@overleaf/metrics') -const OError = require('@overleaf/o-error') -const Settings = require('@overleaf/settings') -const Errors = require('../Errors/Errors') +import Metrics from '@overleaf/metrics' +import OError from '@overleaf/o-error' +import Settings from '@overleaf/settings' +import Errors from '../Errors/Errors.js' -class InvalidEmailError extends Errors.BackwardCompatibleError {} -class InvalidPasswordError extends Errors.BackwardCompatibleError {} -class ParallelLoginError extends Errors.BackwardCompatibleError {} -class PasswordMustBeDifferentError extends Errors.BackwardCompatibleError {} -class PasswordReusedError extends Errors.BackwardCompatibleError {} +export class InvalidEmailError extends Errors.BackwardCompatibleError {} +export class InvalidPasswordError extends Errors.BackwardCompatibleError {} +export class ParallelLoginError extends Errors.BackwardCompatibleError {} +export class PasswordMustBeDifferentError extends Errors.BackwardCompatibleError {} +export class PasswordReusedError extends Errors.BackwardCompatibleError {} -function handleAuthenticateErrors(error, req) { +export function handleAuthenticateErrors(error, req) { if (error.message === 'password is too long') { Metrics.inc('login_failure_reason', 1, { status: 'password_is_too_long', @@ -48,7 +48,7 @@ function handleAuthenticateErrors(error, req) { throw error } -module.exports = { +export default { InvalidEmailError, InvalidPasswordError, ParallelLoginError, diff --git a/services/web/app/src/Features/Authentication/AuthenticationManager.mjs b/services/web/app/src/Features/Authentication/AuthenticationManager.mjs index 0d45c4eaa8..ab24e0e41e 100644 --- a/services/web/app/src/Features/Authentication/AuthenticationManager.mjs +++ b/services/web/app/src/Features/Authentication/AuthenticationManager.mjs @@ -10,7 +10,7 @@ import { ParallelLoginError, PasswordMustBeDifferentError, PasswordReusedError, -} from './AuthenticationErrors.js' +} from './AuthenticationErrors.mjs' import { callbackify, callbackifyMultiResult } from '@overleaf/promise-utils' import HaveIBeenPwned from './HaveIBeenPwned.mjs' diff --git a/services/web/app/src/Features/Authorization/AuthorizationManager.mjs b/services/web/app/src/Features/Authorization/AuthorizationManager.mjs index 7a9be587b9..dd9c19ce30 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationManager.mjs +++ b/services/web/app/src/Features/Authorization/AuthorizationManager.mjs @@ -1,11 +1,11 @@ import { callbackify } from 'node:util' import mongodb from 'mongodb-legacy' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import CollaboratorsGetter from '../Collaborators/CollaboratorsGetter.mjs' import CollaboratorsHandler from '../Collaborators/CollaboratorsHandler.mjs' import ProjectGetter from '../Project/ProjectGetter.mjs' import { User } from '../../models/User.mjs' -import PrivilegeLevels from './PrivilegeLevels.js' +import PrivilegeLevels from './PrivilegeLevels.mjs' import TokenAccessHandler from '../TokenAccess/TokenAccessHandler.mjs' import PublicAccessLevels from './PublicAccessLevels.mjs' import Errors from '../Errors/Errors.js' diff --git a/services/web/app/src/Features/Authorization/PermissionsController.mjs b/services/web/app/src/Features/Authorization/PermissionsController.mjs index 25b9702547..9dd6bf6300 100644 --- a/services/web/app/src/Features/Authorization/PermissionsController.mjs +++ b/services/web/app/src/Features/Authorization/PermissionsController.mjs @@ -3,7 +3,7 @@ import { ForbiddenError, UserNotFoundError } from '../Errors/Errors.js' import PermissionsManager from './PermissionsManager.mjs' import Modules from '../../infrastructure/Modules.js' import { expressify } from '@overleaf/promise-utils' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' /** * @typedef {(import('express').Request)} Request diff --git a/services/web/app/src/Features/Authorization/PrivilegeLevels.js b/services/web/app/src/Features/Authorization/PrivilegeLevels.mjs similarity index 86% rename from services/web/app/src/Features/Authorization/PrivilegeLevels.js rename to services/web/app/src/Features/Authorization/PrivilegeLevels.mjs index e78669954c..fcf42488bc 100644 --- a/services/web/app/src/Features/Authorization/PrivilegeLevels.js +++ b/services/web/app/src/Features/Authorization/PrivilegeLevels.mjs @@ -9,4 +9,4 @@ const PrivilegeLevels = { OWNER: 'owner', } -module.exports = PrivilegeLevels +export default PrivilegeLevels diff --git a/services/web/app/src/Features/BrandVariations/BrandVariationsHandler.mjs b/services/web/app/src/Features/BrandVariations/BrandVariationsHandler.mjs index f66c573f2e..ba6c19777d 100644 --- a/services/web/app/src/Features/BrandVariations/BrandVariationsHandler.mjs +++ b/services/web/app/src/Features/BrandVariations/BrandVariationsHandler.mjs @@ -2,7 +2,7 @@ import OError from '@overleaf/o-error' import { URL } from 'node:url' import settings from '@overleaf/settings' import logger from '@overleaf/logger' -import V1Api from '../V1/V1Api.js' +import V1Api from '../V1/V1Api.mjs' import sanitizeHtml from 'sanitize-html' import { promisify } from '@overleaf/promise-utils' diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsController.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsController.mjs index d1769c9203..b70553218e 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsController.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsController.mjs @@ -14,9 +14,9 @@ import AdminAuthorizationHelper from '../Helpers/AdminAuthorizationHelper.mjs' import TokenAccessHandler from '../TokenAccess/TokenAccessHandler.mjs' import ProjectAuditLogHandler from '../Project/ProjectAuditLogHandler.mjs' import LimitationsManager from '../Subscription/LimitationsManager.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import { z, zz, validateReq } from '../../infrastructure/Validation.js' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' const { hasAdminAccess } = AdminAuthorizationHelper const ObjectId = mongodb.ObjectId diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsGetter.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsGetter.mjs index b75a06f955..ec77e51c22 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsGetter.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsGetter.mjs @@ -11,7 +11,7 @@ import PublicAccessLevels from '../Authorization/PublicAccessLevels.mjs' import Errors from '../Errors/Errors.js' import ProjectEditorHandler from '../Project/ProjectEditorHandler.mjs' import Sources from '../Authorization/Sources.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' const { ObjectId } = mongodb diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs index ab7f366315..a25837f57e 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs @@ -4,7 +4,7 @@ import { Project } from '../../models/Project.mjs' import ProjectGetter from '../Project/ProjectGetter.mjs' import logger from '@overleaf/logger' import ContactManager from '../Contacts/ContactManager.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import TpdsProjectFlusher from '../ThirdPartyDataStore/TpdsProjectFlusher.mjs' import CollaboratorsGetter from './CollaboratorsGetter.mjs' import Errors from '../Errors/Errors.js' diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs index 75d280701e..aca557934a 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs @@ -16,7 +16,7 @@ import { expressify } from '@overleaf/promise-utils' import ProjectAuditLogHandler from '../Project/ProjectAuditLogHandler.mjs' import Errors from '../Errors/Errors.js' import AuthenticationController from '../Authentication/AuthenticationController.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' // This rate limiter allows a different number of requests depending on the // number of callaborators a user is allowed. This is implemented by providing diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs index 8ce4651e49..e7903c900f 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteGetter.mjs @@ -1,6 +1,6 @@ import logger from '@overleaf/logger' import { ProjectInvite } from '../../models/ProjectInvite.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import CollaboratorsInviteHelper from './CollaboratorsInviteHelper.mjs' async function getAllInvites(projectId) { diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.mjs index 4c956dc102..d6f745b556 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteHandler.mjs @@ -8,7 +8,7 @@ import CollaboratorsInviteHelper from './CollaboratorsInviteHelper.mjs' import UserGetter from '../User/UserGetter.mjs' import ProjectGetter from '../Project/ProjectGetter.mjs' import NotificationsBuilder from '../Notifications/NotificationsBuilder.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import LimitationsManager from '../Subscription/LimitationsManager.mjs' import ProjectAuditLogHandler from '../Project/ProjectAuditLogHandler.mjs' import _ from 'lodash' diff --git a/services/web/app/src/Features/Collaborators/OwnershipTransferHandler.mjs b/services/web/app/src/Features/Collaborators/OwnershipTransferHandler.mjs index 093f6893c8..a0b9bfa054 100644 --- a/services/web/app/src/Features/Collaborators/OwnershipTransferHandler.mjs +++ b/services/web/app/src/Features/Collaborators/OwnershipTransferHandler.mjs @@ -5,7 +5,7 @@ import UserGetter from '../User/UserGetter.mjs' import CollaboratorsHandler from './CollaboratorsHandler.mjs' import EmailHandler from '../Email/EmailHandler.mjs' import Errors from '../Errors/Errors.js' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import TpdsProjectFlusher from '../ThirdPartyDataStore/TpdsProjectFlusher.mjs' import ProjectAuditLogHandler from '../Project/ProjectAuditLogHandler.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' diff --git a/services/web/app/src/Features/Compile/ClsiCacheHandler.mjs b/services/web/app/src/Features/Compile/ClsiCacheHandler.mjs index fd30724768..6c5f20c0d2 100644 --- a/services/web/app/src/Features/Compile/ClsiCacheHandler.mjs +++ b/services/web/app/src/Features/Compile/ClsiCacheHandler.mjs @@ -8,7 +8,7 @@ import logger from '@overleaf/logger' import Settings from '@overleaf/settings' import OError from '@overleaf/o-error' import { NotFoundError, InvalidNameError } from '../Errors/Errors.js' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' const TIMEOUT = 4_000 diff --git a/services/web/app/src/Features/Compile/ClsiCacheManager.mjs b/services/web/app/src/Features/Compile/ClsiCacheManager.mjs index 0cec56cdfb..d61645fef7 100644 --- a/services/web/app/src/Features/Compile/ClsiCacheManager.mjs +++ b/services/web/app/src/Features/Compile/ClsiCacheManager.mjs @@ -7,7 +7,7 @@ import UserGetter from '../User/UserGetter.mjs' import Settings from '@overleaf/settings' import { fetchJson, RequestFailedError } from '@overleaf/fetch-utils' import Metrics from '@overleaf/metrics' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' /** * Get the most recent build and metadata diff --git a/services/web/app/src/Features/Compile/CompileController.mjs b/services/web/app/src/Features/Compile/CompileController.mjs index 8e6382c2ec..f1a3a6e8fc 100644 --- a/services/web/app/src/Features/Compile/CompileController.mjs +++ b/services/web/app/src/Features/Compile/CompileController.mjs @@ -21,7 +21,7 @@ import { fetchStreamWithResponse, RequestFailedError, } from '@overleaf/fetch-utils' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' const { z, zz, validateReq } = Validation const ClsiCookieManager = ClsiCookieManagerFactory( diff --git a/services/web/app/src/Features/Editor/EditorHttpController.mjs b/services/web/app/src/Features/Editor/EditorHttpController.mjs index 2c79bf3131..9fe2550e4e 100644 --- a/services/web/app/src/Features/Editor/EditorHttpController.mjs +++ b/services/web/app/src/Features/Editor/EditorHttpController.mjs @@ -5,7 +5,7 @@ import AuthorizationManager from '../Authorization/AuthorizationManager.mjs' import ProjectEditorHandler from '../Project/ProjectEditorHandler.mjs' import Metrics from '@overleaf/metrics' import CollaboratorsInviteGetter from '../Collaborators/CollaboratorsInviteGetter.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import SessionManager from '../Authentication/SessionManager.mjs' import Errors from '../Errors/Errors.js' import { expressify } from '@overleaf/promise-utils' diff --git a/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.js b/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs similarity index 97% rename from services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.js rename to services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs index fb68ecc7f9..a078cad8e6 100644 --- a/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.js +++ b/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs @@ -1,6 +1,6 @@ -const _ = require('lodash') +import _ from 'lodash' -module.exports = _.template(`\ +export default _.template(`\ diff --git a/services/web/app/src/Features/Email/Bodies/cta-email.js b/services/web/app/src/Features/Email/Bodies/cta-email.mjs similarity index 98% rename from services/web/app/src/Features/Email/Bodies/cta-email.js rename to services/web/app/src/Features/Email/Bodies/cta-email.mjs index 346793cdb1..6d49620a7d 100644 --- a/services/web/app/src/Features/Email/Bodies/cta-email.js +++ b/services/web/app/src/Features/Email/Bodies/cta-email.mjs @@ -1,6 +1,6 @@ -const _ = require('lodash') +import _ from 'lodash' -module.exports = _.template(`\ +export default _.template(`\
diff --git a/services/web/app/src/Features/Email/EmailBuilder.mjs b/services/web/app/src/Features/Email/EmailBuilder.mjs index 294a180a0d..c78e878528 100644 --- a/services/web/app/src/Features/Email/EmailBuilder.mjs +++ b/services/web/app/src/Features/Email/EmailBuilder.mjs @@ -1,12 +1,12 @@ import _ from 'lodash' import settings from '@overleaf/settings' import moment from 'moment' -import EmailMessageHelper from './EmailMessageHelper.js' +import EmailMessageHelper from './EmailMessageHelper.mjs' import StringHelper from '../Helpers/StringHelper.mjs' -import BaseWithHeaderEmailLayout from './Layouts/BaseWithHeaderEmailLayout.js' +import BaseWithHeaderEmailLayout from './Layouts/BaseWithHeaderEmailLayout.mjs' import SpamSafe from './SpamSafe.mjs' -import ctaEmailBody from './Bodies/cta-email.js' -import NoCTAEmailBody from './Bodies/NoCTAEmailBody.js' +import ctaEmailBody from './Bodies/cta-email.mjs' +import NoCTAEmailBody from './Bodies/NoCTAEmailBody.mjs' function _emailBodyPlainText(content, opts, ctaEmail) { let emailBody = `${content.greeting(opts, true)}` diff --git a/services/web/app/src/Features/Email/EmailHandler.mjs b/services/web/app/src/Features/Email/EmailHandler.mjs index ae52acdb82..85a94d5439 100644 --- a/services/web/app/src/Features/Email/EmailHandler.mjs +++ b/services/web/app/src/Features/Email/EmailHandler.mjs @@ -3,7 +3,7 @@ import Settings from '@overleaf/settings' import logger from '@overleaf/logger' import EmailBuilder from './EmailBuilder.mjs' import EmailSender from './EmailSender.mjs' -import Queues from '../../infrastructure/Queues.js' +import Queues from '../../infrastructure/Queues.mjs' const EMAIL_SETTINGS = Settings.email || {} diff --git a/services/web/app/src/Features/Email/EmailMessageHelper.js b/services/web/app/src/Features/Email/EmailMessageHelper.mjs similarity index 89% rename from services/web/app/src/Features/Email/EmailMessageHelper.js rename to services/web/app/src/Features/Email/EmailMessageHelper.mjs index d8fcc7d120..fe240478ab 100644 --- a/services/web/app/src/Features/Email/EmailMessageHelper.js +++ b/services/web/app/src/Features/Email/EmailMessageHelper.mjs @@ -1,4 +1,4 @@ -const sanitizeHtml = require('sanitize-html') +import sanitizeHtml from 'sanitize-html' const sanitizeOptions = { html: { allowedTags: ['a', 'span', 'b', 'br', 'i'], @@ -22,7 +22,7 @@ function displayLink(text, url, isPlainText) { return isPlainText ? `${text} (${url})` : `${text}` } -module.exports = { +export default { cleanHTML, displayLink, } diff --git a/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.js b/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs similarity index 99% rename from services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.js rename to services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs index 11546e74c0..33c298d09b 100644 --- a/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.js +++ b/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs @@ -1,7 +1,7 @@ -const _ = require('lodash') -const settings = require('@overleaf/settings') +import _ from 'lodash' +import settings from '@overleaf/settings' -module.exports = _.template(`\ +export default _.template(`\ diff --git a/services/web/app/src/Features/Helpers/Mongo.js b/services/web/app/src/Features/Helpers/Mongo.mjs similarity index 86% rename from services/web/app/src/Features/Helpers/Mongo.js rename to services/web/app/src/Features/Helpers/Mongo.mjs index 3ec083a1f5..aecf3b5260 100644 --- a/services/web/app/src/Features/Helpers/Mongo.js +++ b/services/web/app/src/Features/Helpers/Mongo.mjs @@ -1,6 +1,8 @@ -const OError = require('@overleaf/o-error') -const { ObjectId } = require('mongodb-legacy') -const { ObjectId: MongooseObjectId } = require('mongoose').mongo +import OError from '@overleaf/o-error' +import mongodb from 'mongodb-legacy' +import { ObjectId as MongooseObjectId } from 'mongoose' + +const { ObjectId } = mongodb function _getObjectIdInstance(id) { if (typeof id === 'string') { @@ -47,7 +49,7 @@ function isObjectIdInstance(id) { return id instanceof ObjectId || id instanceof MongooseObjectId } -module.exports = { +export default { isObjectIdInstance, normalizeQuery, normalizeMultiQuery, diff --git a/services/web/app/src/Features/History/HistoryController.mjs b/services/web/app/src/Features/History/HistoryController.mjs index 0961936356..d78ab0cb1a 100644 --- a/services/web/app/src/Features/History/HistoryController.mjs +++ b/services/web/app/src/Features/History/HistoryController.mjs @@ -24,7 +24,7 @@ import ProjectDetailsHandler from '../Project/ProjectDetailsHandler.mjs' import ProjectEntityUpdateHandler from '../Project/ProjectEntityUpdateHandler.mjs' import RestoreManager from './RestoreManager.mjs' import { prepareZipAttachment } from '../../infrastructure/Response.js' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import { z, zz, validateReq } from '../../infrastructure/Validation.js' // Number of seconds after which the browser should send a request to revalidate diff --git a/services/web/app/src/Features/Project/ProjectController.mjs b/services/web/app/src/Features/Project/ProjectController.mjs index ec4005025b..c869eca186 100644 --- a/services/web/app/src/Features/Project/ProjectController.mjs +++ b/services/web/app/src/Features/Project/ProjectController.mjs @@ -21,14 +21,14 @@ import AuthorizationManager from '../Authorization/AuthorizationManager.mjs' import InactiveProjectManager from '../InactiveData/InactiveProjectManager.mjs' import ProjectUpdateHandler from './ProjectUpdateHandler.mjs' import ProjectGetter from './ProjectGetter.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import SessionManager from '../Authentication/SessionManager.mjs' import Sources from '../Authorization/Sources.mjs' import TokenAccessHandler from '../TokenAccess/TokenAccessHandler.mjs' import CollaboratorsGetter from '../Collaborators/CollaboratorsGetter.mjs' import ProjectEntityHandler from './ProjectEntityHandler.mjs' import TpdsProjectFlusher from '../ThirdPartyDataStore/TpdsProjectFlusher.mjs' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import BrandVariationsHandler from '../BrandVariations/BrandVariationsHandler.mjs' import UserController from '../User/UserController.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' @@ -47,7 +47,7 @@ import UserUpdater from '../User/UserUpdater.mjs' import Modules from '../../infrastructure/Modules.js' import { z, zz, validateReq } from '../../infrastructure/Validation.js' import UserGetter from '../User/UserGetter.mjs' -import { isStandaloneAiAddOnPlanCode } from '../Subscription/AiHelper.js' +import { isStandaloneAiAddOnPlanCode } from '../Subscription/AiHelper.mjs' import SubscriptionController from '../Subscription/SubscriptionController.mjs' import { formatCurrency } from '../../util/currency.js' import UserSettingsHelper from './UserSettingsHelper.mjs' diff --git a/services/web/app/src/Features/Project/ProjectCreationHandler.mjs b/services/web/app/src/Features/Project/ProjectCreationHandler.mjs index 03ad4437a2..55df89bcc2 100644 --- a/services/web/app/src/Features/Project/ProjectCreationHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectCreationHandler.mjs @@ -2,7 +2,7 @@ import OError from '@overleaf/o-error' import metrics from '@overleaf/metrics' import Settings from '@overleaf/settings' import mongodb from 'mongodb-legacy' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import { Project } from '../../models/Project.mjs' import { Folder } from '../../models/Folder.mjs' import ProjectEntityUpdateHandler from './ProjectEntityUpdateHandler.mjs' diff --git a/services/web/app/src/Features/Project/ProjectDetailsHandler.mjs b/services/web/app/src/Features/Project/ProjectDetailsHandler.mjs index a2116ecdf3..7ef920c087 100644 --- a/services/web/app/src/Features/Project/ProjectDetailsHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectDetailsHandler.mjs @@ -6,7 +6,7 @@ import logger from '@overleaf/logger' import TpdsUpdateSender from '../ThirdPartyDataStore/TpdsUpdateSender.mjs' import PublicAccessLevels from '../Authorization/PublicAccessLevels.mjs' import Errors from '../Errors/Errors.js' -import TokenGenerator from '../TokenGenerator/TokenGenerator.js' +import TokenGenerator from '../TokenGenerator/TokenGenerator.mjs' import ProjectHelper from './ProjectHelper.mjs' import settings from '@overleaf/settings' import { callbackify } from 'node:util' diff --git a/services/web/app/src/Features/Project/ProjectGetter.mjs b/services/web/app/src/Features/Project/ProjectGetter.mjs index 2aafb73892..77069a7d72 100644 --- a/services/web/app/src/Features/Project/ProjectGetter.mjs +++ b/services/web/app/src/Features/Project/ProjectGetter.mjs @@ -1,5 +1,5 @@ import { db } from '../../infrastructure/mongodb.js' -import { normalizeQuery } from '../Helpers/Mongo.js' +import Mongo from '../Helpers/Mongo.mjs' import OError from '@overleaf/o-error' import { Project } from '../../models/Project.mjs' import LockManager from '../../infrastructure/LockManager.js' @@ -8,6 +8,8 @@ import { callbackifyAll } from '@overleaf/promise-utils' import ProjectEntityMongoUpdateHandler from './ProjectEntityMongoUpdateHandler.mjs' import CollaboratorsGetter from '../Collaborators/CollaboratorsGetter.mjs' +const { normalizeQuery } = Mongo + const ProjectGetter = { EXCLUDE_DEPTH: 8, diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index dfb165f535..2acbb85c66 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -6,7 +6,7 @@ import Metrics from '@overleaf/metrics' import Settings from '@overleaf/settings' import ProjectHelper from './ProjectHelper.mjs' import ProjectGetter from './ProjectGetter.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import SessionManager from '../Authentication/SessionManager.mjs' import Sources from '../Authorization/Sources.mjs' import UserGetter from '../User/UserGetter.mjs' @@ -14,7 +14,7 @@ import SurveyHandler from '../Survey/SurveyHandler.mjs' import TagsHandler from '../Tags/TagsHandler.mjs' import { expressify } from '@overleaf/promise-utils' import logger from '@overleaf/logger' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import SubscriptionViewModelBuilder from '../Subscription/SubscriptionViewModelBuilder.mjs' import NotificationsHandler from '../Notifications/NotificationsHandler.mjs' import Modules from '../../infrastructure/Modules.js' diff --git a/services/web/app/src/Features/Security/LoginRateLimiter.js b/services/web/app/src/Features/Security/LoginRateLimiter.mjs similarity index 78% rename from services/web/app/src/Features/Security/LoginRateLimiter.js rename to services/web/app/src/Features/Security/LoginRateLimiter.mjs index bab5193632..f85f9be5f7 100644 --- a/services/web/app/src/Features/Security/LoginRateLimiter.js +++ b/services/web/app/src/Features/Security/LoginRateLimiter.mjs @@ -1,6 +1,6 @@ -const { RateLimiter } = require('../../infrastructure/RateLimiter') -const { callbackify } = require('@overleaf/promise-utils') -const Settings = require('@overleaf/settings') +import { RateLimiter } from '../../infrastructure/RateLimiter.js' +import { callbackify } from '@overleaf/promise-utils' +import Settings from '@overleaf/settings' const rateLimiterLoginEmail = new RateLimiter( 'login', @@ -38,4 +38,4 @@ LoginRateLimiter.promises = { recordSuccessfulLogin, } -module.exports = LoginRateLimiter +export default LoginRateLimiter diff --git a/services/web/app/src/Features/Security/RateLimiterMiddleware.mjs b/services/web/app/src/Features/Security/RateLimiterMiddleware.mjs index c3b4de8bae..8119d6f74a 100644 --- a/services/web/app/src/Features/Security/RateLimiterMiddleware.mjs +++ b/services/web/app/src/Features/Security/RateLimiterMiddleware.mjs @@ -1,6 +1,6 @@ import logger from '@overleaf/logger' import SessionManager from '../Authentication/SessionManager.mjs' -import LoginRateLimiter from './LoginRateLimiter.js' +import LoginRateLimiter from './LoginRateLimiter.mjs' import settings from '@overleaf/settings' /** diff --git a/services/web/app/src/Features/SplitTests/SplitTestHandler.mjs b/services/web/app/src/Features/SplitTests/SplitTestHandler.mjs index 36501f2be4..1a9a296c83 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestHandler.mjs +++ b/services/web/app/src/Features/SplitTests/SplitTestHandler.mjs @@ -8,7 +8,7 @@ import { callbackify } from 'node:util' import SplitTestCache from './SplitTestCache.mjs' import { SplitTest } from '../../models/SplitTest.mjs' import UserAnalyticsIdCache from '../Analytics/UserAnalyticsIdCache.mjs' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import SplitTestUtils from './SplitTestUtils.mjs' import Settings from '@overleaf/settings' import SessionManager from '../Authentication/SessionManager.mjs' diff --git a/services/web/app/src/Features/StaticPages/HomeController.mjs b/services/web/app/src/Features/StaticPages/HomeController.mjs index 740e1eb240..bd82075ae5 100644 --- a/services/web/app/src/Features/StaticPages/HomeController.mjs +++ b/services/web/app/src/Features/StaticPages/HomeController.mjs @@ -1,4 +1,4 @@ -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' import Path from 'node:path' import fs from 'node:fs' diff --git a/services/web/app/src/Features/Subscription/AiHelper.js b/services/web/app/src/Features/Subscription/AiHelper.mjs similarity index 78% rename from services/web/app/src/Features/Subscription/AiHelper.js rename to services/web/app/src/Features/Subscription/AiHelper.mjs index d6b0e06644..37a1a2e4a7 100644 --- a/services/web/app/src/Features/Subscription/AiHelper.js +++ b/services/web/app/src/Features/Subscription/AiHelper.mjs @@ -2,9 +2,9 @@ // Initially, this functions lived in PaymentProviderEntities.js, // but it was moved to this file to prevent circular dependency issue -const AI_ASSIST_STANDALONE_MONTHLY_PLAN_CODE = 'assistant' -const AI_ASSIST_STANDALONE_ANNUAL_PLAN_CODE = 'assistant-annual' -const AI_ADD_ON_CODE = 'assistant' +export const AI_ASSIST_STANDALONE_MONTHLY_PLAN_CODE = 'assistant' +export const AI_ASSIST_STANDALONE_ANNUAL_PLAN_CODE = 'assistant-annual' +export const AI_ADD_ON_CODE = 'assistant' /** * Returns whether the given plan code is a standalone AI plan @@ -12,7 +12,7 @@ const AI_ADD_ON_CODE = 'assistant' * @param {string | null | undefined} planCode * @return {boolean} */ -function isStandaloneAiAddOnPlanCode(planCode) { +export function isStandaloneAiAddOnPlanCode(planCode) { return ( planCode === AI_ASSIST_STANDALONE_MONTHLY_PLAN_CODE || planCode === AI_ASSIST_STANDALONE_ANNUAL_PLAN_CODE @@ -28,7 +28,7 @@ function isStandaloneAiAddOnPlanCode(planCode) { * * @return {boolean} */ -function subscriptionChangeIsAiAssistUpgrade(subscriptionChange) { +export function subscriptionChangeIsAiAssistUpgrade(subscriptionChange) { return Boolean( isStandaloneAiAddOnPlanCode(subscriptionChange.nextPlanCode) || subscriptionChange.nextAddOns?.some( @@ -37,7 +37,7 @@ function subscriptionChangeIsAiAssistUpgrade(subscriptionChange) { ) } -module.exports = { +export default { AI_ADD_ON_CODE, AI_ASSIST_STANDALONE_MONTHLY_PLAN_CODE, AI_ASSIST_STANDALONE_ANNUAL_PLAN_CODE, diff --git a/services/web/app/src/Features/Subscription/Errors.js b/services/web/app/src/Features/Subscription/Errors.mjs similarity index 57% rename from services/web/app/src/Features/Subscription/Errors.js rename to services/web/app/src/Features/Subscription/Errors.mjs index 8d4498290a..546f5822e5 100644 --- a/services/web/app/src/Features/Subscription/Errors.js +++ b/services/web/app/src/Features/Subscription/Errors.mjs @@ -1,9 +1,10 @@ // @ts-check -const Errors = require('../Errors/Errors') -const OError = require('@overleaf/o-error') +import Errors from '../Errors/Errors.js' -class RecurlyTransactionError extends Errors.BackwardCompatibleError { +import OError from '@overleaf/o-error' + +export class RecurlyTransactionError extends Errors.BackwardCompatibleError { constructor(options) { super({ message: 'Unknown transaction error', @@ -12,27 +13,27 @@ class RecurlyTransactionError extends Errors.BackwardCompatibleError { } } -class DuplicateAddOnError extends OError {} +export class DuplicateAddOnError extends OError {} -class AddOnNotPresentError extends OError {} +export class AddOnNotPresentError extends OError {} -class MissingBillingInfoError extends OError {} +export class MissingBillingInfoError extends OError {} -class ManuallyCollectedError extends OError {} +export class ManuallyCollectedError extends OError {} -class PendingChangeError extends OError {} +export class PendingChangeError extends OError {} -class InactiveError extends OError {} +export class InactiveError extends OError {} -class SubtotalLimitExceededError extends OError {} +export class SubtotalLimitExceededError extends OError {} -class HasPastDueInvoiceError extends OError {} +export class HasPastDueInvoiceError extends OError {} -class HasNoAdditionalLicenseWhenManuallyCollectedError extends OError {} +export class HasNoAdditionalLicenseWhenManuallyCollectedError extends OError {} -class InvalidTaxIdError extends OError {} +export class InvalidTaxIdError extends OError {} -class StripeClientIdempotencyKeyInUseError extends OError { +export class StripeClientIdempotencyKeyInUseError extends OError { constructor() { super('Stripe idempotency key was already in use') } @@ -43,7 +44,7 @@ class StripeClientIdempotencyKeyInUseError extends OError { * @property {string} PaymentActionRequiredInfo.clientSecret * @property {string} PaymentActionRequiredInfo.publicKey */ -class PaymentActionRequiredError extends OError { +export class PaymentActionRequiredError extends OError { /** * @param {PaymentActionRequiredInfo} info */ @@ -58,7 +59,7 @@ class PaymentActionRequiredError extends OError { * @property {string} PaymentFailedInfo.reason * @property {string} PaymentFailedInfo.adviceCode */ -class PaymentFailedError extends OError { +export class PaymentFailedError extends OError { /** * @param {PaymentFailedInfo} info */ @@ -67,7 +68,7 @@ class PaymentFailedError extends OError { } } -module.exports = { +export default { RecurlyTransactionError, DuplicateAddOnError, AddOnNotPresentError, diff --git a/services/web/app/src/Features/Subscription/FeaturesUpdater.mjs b/services/web/app/src/Features/Subscription/FeaturesUpdater.mjs index 9b318ba5d2..1304c5b35c 100644 --- a/services/web/app/src/Features/Subscription/FeaturesUpdater.mjs +++ b/services/web/app/src/Features/Subscription/FeaturesUpdater.mjs @@ -13,9 +13,9 @@ import V1SubscriptionManager from './V1SubscriptionManager.mjs' import InstitutionsFeatures from '../Institutions/InstitutionsFeatures.mjs' import UserGetter from '../User/UserGetter.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' -import Queues from '../../infrastructure/Queues.js' +import Queues from '../../infrastructure/Queues.mjs' import Modules from '../../infrastructure/Modules.js' -import { AI_ADD_ON_CODE } from './AiHelper.js' +import { AI_ADD_ON_CODE } from './AiHelper.mjs' /** * Enqueue a job for refreshing features for the given user diff --git a/services/web/app/src/Features/Subscription/GroupPlansData.js b/services/web/app/src/Features/Subscription/GroupPlansData.mjs similarity index 92% rename from services/web/app/src/Features/Subscription/GroupPlansData.js rename to services/web/app/src/Features/Subscription/GroupPlansData.mjs index 5f765056be..5fa0041773 100644 --- a/services/web/app/src/Features/Subscription/GroupPlansData.js +++ b/services/web/app/src/Features/Subscription/GroupPlansData.mjs @@ -1,6 +1,6 @@ -const Settings = require('@overleaf/settings') -const fs = require('fs') -const Path = require('path') +import Settings from '@overleaf/settings' +import fs from 'node:fs' +import Path from 'node:path' // The groups.json file encodes the various group plan options we provide, and // is used in the app the render the appropriate dialog in the plans page, and @@ -12,7 +12,7 @@ const Path = require('path') // fetch pricing data and generate a groups.json using the current Recurly // prices const data = fs.readFileSync( - Path.join(__dirname, '/../../../templates/plans/groups.json') + Path.join(import.meta.dirname, '/../../../templates/plans/groups.json') ) const groups = JSON.parse(data.toString()) @@ -63,4 +63,4 @@ for (const [usage, planData] of Object.entries(groups)) { } } -module.exports = groups +export default groups diff --git a/services/web/app/src/Features/Subscription/LimitationsManager.mjs b/services/web/app/src/Features/Subscription/LimitationsManager.mjs index 81296d72b8..bd33ee4234 100644 --- a/services/web/app/src/Features/Subscription/LimitationsManager.mjs +++ b/services/web/app/src/Features/Subscription/LimitationsManager.mjs @@ -8,7 +8,7 @@ import SubscriptionLocator from './SubscriptionLocator.mjs' import Settings from '@overleaf/settings' import CollaboratorsGetter from '../Collaborators/CollaboratorsGetter.mjs' import CollaboratorsInvitesGetter from '../Collaborators/CollaboratorsInviteGetter.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import { callbackify, callbackifyMultiResult } from '@overleaf/promise-utils' async function allowedNumberOfCollaboratorsInProject(projectId) { diff --git a/services/web/app/src/Features/Subscription/PaymentProviderEntities.mjs b/services/web/app/src/Features/Subscription/PaymentProviderEntities.mjs index caeab041c1..2858f593fc 100644 --- a/services/web/app/src/Features/Subscription/PaymentProviderEntities.mjs +++ b/services/web/app/src/Features/Subscription/PaymentProviderEntities.mjs @@ -18,10 +18,10 @@ import OError from '@overleaf/o-error' -import { DuplicateAddOnError, AddOnNotPresentError } from './Errors.js' +import { DuplicateAddOnError, AddOnNotPresentError } from './Errors.mjs' import PlansLocator from './PlansLocator.mjs' import SubscriptionHelper from './SubscriptionHelper.mjs' -import { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } from './AiHelper.js' +import { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } from './AiHelper.mjs' export const MEMBERS_LIMIT_ADD_ON_CODE = 'additional-license' export class PaymentProviderSubscription { diff --git a/services/web/app/src/Features/Subscription/RecurlyClient.mjs b/services/web/app/src/Features/Subscription/RecurlyClient.mjs index d983fcfa8c..cfd4c9443a 100644 --- a/services/web/app/src/Features/Subscription/RecurlyClient.mjs +++ b/services/web/app/src/Features/Subscription/RecurlyClient.mjs @@ -22,9 +22,9 @@ import { import { MissingBillingInfoError, SubtotalLimitExceededError, -} from './Errors.js' +} from './Errors.mjs' import RecurlyMetrics from './RecurlyMetrics.mjs' -import { isStandaloneAiAddOnPlanCode, AI_ADD_ON_CODE } from './AiHelper.js' +import { isStandaloneAiAddOnPlanCode, AI_ADD_ON_CODE } from './AiHelper.mjs' /** * @import { PaymentProviderSubscriptionChangeRequest } from './PaymentProviderEntities.mjs' diff --git a/services/web/app/src/Features/Subscription/RecurlyEventHandler.mjs b/services/web/app/src/Features/Subscription/RecurlyEventHandler.mjs index ac718fbc4e..403456fc61 100644 --- a/services/web/app/src/Features/Subscription/RecurlyEventHandler.mjs +++ b/services/web/app/src/Features/Subscription/RecurlyEventHandler.mjs @@ -1,7 +1,7 @@ import SplitTestHandler from '../SplitTests/SplitTestHandler.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' import SubscriptionEmailHandler from './SubscriptionEmailHandler.mjs' -import { AI_ADD_ON_CODE } from './AiHelper.js' +import { AI_ADD_ON_CODE } from './AiHelper.mjs' import mongodb from 'mongodb-legacy' const { ObjectId } = mongodb diff --git a/services/web/app/src/Features/Subscription/RecurlyWrapper.mjs b/services/web/app/src/Features/Subscription/RecurlyWrapper.mjs index e44d930411..e644953d31 100644 --- a/services/web/app/src/Features/Subscription/RecurlyWrapper.mjs +++ b/services/web/app/src/Features/Subscription/RecurlyWrapper.mjs @@ -7,7 +7,7 @@ import Settings from '@overleaf/settings' import xml2js from 'xml2js' import logger from '@overleaf/logger' import Errors from '../Errors/Errors.js' -import SubscriptionErrors from './Errors.js' +import SubscriptionErrors from './Errors.mjs' import { callbackify } from '@overleaf/promise-utils' import RecurlyMetrics from './RecurlyMetrics.mjs' diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.mjs b/services/web/app/src/Features/Subscription/SubscriptionController.mjs index 0108a9e348..e85c7fd351 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionController.mjs @@ -10,13 +10,13 @@ import Settings from '@overleaf/settings' import logger from '@overleaf/logger' import GeoIpLookup from '../../infrastructure/GeoIpLookup.mjs' import FeaturesUpdater from './FeaturesUpdater.mjs' -import GroupPlansData from './GroupPlansData.js' +import GroupPlansData from './GroupPlansData.mjs' import V1SubscriptionManager from './V1SubscriptionManager.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' import RecurlyEventHandler from './RecurlyEventHandler.mjs' import { expressify } from '@overleaf/promise-utils' import OError from '@overleaf/o-error' -import Errors from './Errors.js' +import Errors from './Errors.mjs' import SplitTestHandler from '../SplitTests/SplitTestHandler.mjs' import AuthorizationManager from '../Authorization/AuthorizationManager.mjs' import Modules from '../../infrastructure/Modules.js' @@ -26,7 +26,7 @@ import RecurlyClient from './RecurlyClient.mjs' import { AI_ADD_ON_CODE, subscriptionChangeIsAiAssistUpgrade, -} from './AiHelper.js' +} from './AiHelper.mjs' import PlansLocator from './PlansLocator.mjs' import { User } from '../../models/User.mjs' import UserGetter from '../User/UserGetter.mjs' diff --git a/services/web/app/src/Features/Subscription/SubscriptionEmailBuilder.mjs b/services/web/app/src/Features/Subscription/SubscriptionEmailBuilder.mjs index 9e7552d207..c24bb6779c 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionEmailBuilder.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionEmailBuilder.mjs @@ -1,5 +1,5 @@ import EmailBuilder from '../Email/EmailBuilder.mjs' -import EmailMessageHelper from '../Email/EmailMessageHelper.js' +import EmailMessageHelper from '../Email/EmailMessageHelper.mjs' import settings from '@overleaf/settings' EmailBuilder.templates.trialOnboarding = EmailBuilder.NoCTAEmailTemplate({ diff --git a/services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs b/services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs index f9fe532391..746274c161 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionGroupController.mjs @@ -20,7 +20,7 @@ import { HasPastDueInvoiceError, HasNoAdditionalLicenseWhenManuallyCollectedError, PaymentActionRequiredError, -} from './Errors.js' +} from './Errors.mjs' const MAX_NUMBER_OF_USERS = 20 const MAX_NUMBER_OF_PO_NUMBER_CHARACTERS = 50 diff --git a/services/web/app/src/Features/Subscription/SubscriptionGroupHandler.mjs b/services/web/app/src/Features/Subscription/SubscriptionGroupHandler.mjs index 3a14f74cc0..facdf16a13 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionGroupHandler.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionGroupHandler.mjs @@ -9,7 +9,7 @@ import { Subscription } from '../../models/Subscription.mjs' import { User } from '../../models/User.mjs' import PlansLocator from './PlansLocator.mjs' import TeamInvitesHandler from './TeamInvitesHandler.mjs' -import GroupPlansData from './GroupPlansData.js' +import GroupPlansData from './GroupPlansData.mjs' import Modules from '../../infrastructure/Modules.js' import PaymentProviderEntities from './PaymentProviderEntities.mjs' import { @@ -18,7 +18,7 @@ import { InactiveError, HasPastDueInvoiceError, HasNoAdditionalLicenseWhenManuallyCollectedError, -} from './Errors.js' +} from './Errors.mjs' import EmailHelper from '../Helpers/EmailHelper.mjs' import { InvalidEmailError } from '../Errors/Errors.js' diff --git a/services/web/app/src/Features/Subscription/SubscriptionHelper.mjs b/services/web/app/src/Features/Subscription/SubscriptionHelper.mjs index 0a84b28520..ca67df6e15 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionHelper.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionHelper.mjs @@ -2,8 +2,8 @@ import Settings from '@overleaf/settings' import { formatCurrency } from '../../util/currency.js' -import GroupPlansData from './GroupPlansData.js' -import { isStandaloneAiAddOnPlanCode } from './AiHelper.js' +import GroupPlansData from './GroupPlansData.mjs' +import { isStandaloneAiAddOnPlanCode } from './AiHelper.mjs' import { Subscription } from '../../models/Subscription.mjs' const MILLISECONDS = 1_000 diff --git a/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs b/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs index 3ded2be604..1417b1be1a 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs @@ -8,8 +8,8 @@ import { Subscription } from '../../models/Subscription.mjs' import SubscriptionHelper from './SubscriptionHelper.mjs' import { DeletedSubscription } from '../../models/DeletedSubscription.mjs' import logger from '@overleaf/logger' -import { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } from './AiHelper.js' -import './GroupPlansData.js' // make sure dynamic group plans are loaded +import { AI_ADD_ON_CODE, isStandaloneAiAddOnPlanCode } from './AiHelper.mjs' +import './GroupPlansData.mjs' // make sure dynamic group plans are loaded const SubscriptionLocator = { async getUsersSubscription(userOrId) { diff --git a/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs b/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs index 6936a55634..f0a0ef7ec2 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionUpdater.mjs @@ -8,7 +8,7 @@ import FeaturesHelper from './FeaturesHelper.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' import { DeletedSubscription } from '../../models/DeletedSubscription.mjs' import logger from '@overleaf/logger' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import UserAuditLogHandler from '../User/UserAuditLogHandler.mjs' import UserUpdater from '../User/UserUpdater.mjs' import AccountMappingHelper from '../Analytics/AccountMappingHelper.mjs' diff --git a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs index b4e67c67e8..b573a4fad3 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.mjs @@ -2,7 +2,7 @@ import Settings from '@overleaf/settings' import PlansLocator from './PlansLocator.mjs' -import { isStandaloneAiAddOnPlanCode } from './AiHelper.js' +import { isStandaloneAiAddOnPlanCode } from './AiHelper.mjs' import PaymentProviderEntities from './PaymentProviderEntities.mjs' import SubscriptionFormatters from './SubscriptionFormatters.mjs' import SubscriptionLocator from './SubscriptionLocator.mjs' diff --git a/services/web/app/src/Features/TokenAccess/TokenAccessController.mjs b/services/web/app/src/Features/TokenAccess/TokenAccessController.mjs index 608b567f3d..16d627e128 100644 --- a/services/web/app/src/Features/TokenAccess/TokenAccessController.mjs +++ b/services/web/app/src/Features/TokenAccess/TokenAccessController.mjs @@ -6,7 +6,7 @@ import logger from '@overleaf/logger' import OError from '@overleaf/o-error' import { expressify } from '@overleaf/promise-utils' import AuthorizationManager from '../Authorization/AuthorizationManager.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import ProjectAuditLogHandler from '../Project/ProjectAuditLogHandler.mjs' import CollaboratorsInviteHandler from '../Collaborators/CollaboratorsInviteHandler.mjs' import CollaboratorsHandler from '../Collaborators/CollaboratorsHandler.mjs' diff --git a/services/web/app/src/Features/TokenAccess/TokenAccessHandler.mjs b/services/web/app/src/Features/TokenAccess/TokenAccessHandler.mjs index 88d643707f..5d0c004dfc 100644 --- a/services/web/app/src/Features/TokenAccess/TokenAccessHandler.mjs +++ b/services/web/app/src/Features/TokenAccess/TokenAccessHandler.mjs @@ -1,15 +1,15 @@ import { Project } from '../../models/Project.mjs' import PublicAccessLevels from '../Authorization/PublicAccessLevels.mjs' -import PrivilegeLevels from '../Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import mongodb from 'mongodb-legacy' import Metrics from '@overleaf/metrics' import Settings from '@overleaf/settings' import logger from '@overleaf/logger' -import V1Api from '../V1/V1Api.js' +import V1Api from '../V1/V1Api.mjs' import crypto from 'node:crypto' import { callbackifyAll } from '@overleaf/promise-utils' import Analytics from '../Analytics/AnalyticsManager.mjs' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' const { ObjectId } = mongodb diff --git a/services/web/app/src/Features/TokenGenerator/TokenGenerator.js b/services/web/app/src/Features/TokenGenerator/TokenGenerator.mjs similarity index 92% rename from services/web/app/src/Features/TokenGenerator/TokenGenerator.js rename to services/web/app/src/Features/TokenGenerator/TokenGenerator.mjs index e3a321028b..4a07feb1b6 100644 --- a/services/web/app/src/Features/TokenGenerator/TokenGenerator.js +++ b/services/web/app/src/Features/TokenGenerator/TokenGenerator.mjs @@ -1,7 +1,7 @@ -const crypto = require('crypto') -const V1Api = require('../V1/V1Api') -const Features = require('../../infrastructure/Features') -const { callbackify } = require('util') +import crypto from 'node:crypto' +import V1Api from '../V1/V1Api.mjs' +import Features from '../../infrastructure/Features.mjs' +import { callbackify } from 'node:util' // (From Overleaf `random_token.rb`) // Letters (not numbers! see generate_token) used in tokens. They're all @@ -94,4 +94,4 @@ const TokenGenerator = { TokenGenerator.promises = { generateUniqueReadOnlyToken, } -module.exports = TokenGenerator +export default TokenGenerator diff --git a/services/web/app/src/Features/Uploads/ArchiveErrors.js b/services/web/app/src/Features/Uploads/ArchiveErrors.mjs similarity index 59% rename from services/web/app/src/Features/Uploads/ArchiveErrors.js rename to services/web/app/src/Features/Uploads/ArchiveErrors.mjs index d78941ecce..38a6c31e41 100644 --- a/services/web/app/src/Features/Uploads/ArchiveErrors.js +++ b/services/web/app/src/Features/Uploads/ArchiveErrors.mjs @@ -1,6 +1,6 @@ -const Errors = require('../Errors/Errors') +import Errors from '../Errors/Errors.js' -class InvalidZipFileError extends Errors.BackwardCompatibleError { +export class InvalidZipFileError extends Errors.BackwardCompatibleError { constructor(options) { super({ message: 'invalid_zip_file', @@ -9,7 +9,7 @@ class InvalidZipFileError extends Errors.BackwardCompatibleError { } } -class EmptyZipFileError extends InvalidZipFileError { +export class EmptyZipFileError extends InvalidZipFileError { constructor(options) { super({ message: 'empty_zip_file', @@ -18,7 +18,7 @@ class EmptyZipFileError extends InvalidZipFileError { } } -class ZipContentsTooLargeError extends InvalidZipFileError { +export class ZipContentsTooLargeError extends InvalidZipFileError { constructor(options) { super({ message: 'zip_contents_too_large', @@ -27,7 +27,7 @@ class ZipContentsTooLargeError extends InvalidZipFileError { } } -module.exports = { +export default { InvalidZipFileError, EmptyZipFileError, ZipContentsTooLargeError, diff --git a/services/web/app/src/Features/Uploads/ArchiveManager.mjs b/services/web/app/src/Features/Uploads/ArchiveManager.mjs index 6c3c470c85..24eac59f8b 100644 --- a/services/web/app/src/Features/Uploads/ArchiveManager.mjs +++ b/services/web/app/src/Features/Uploads/ArchiveManager.mjs @@ -24,7 +24,7 @@ import { InvalidZipFileError, EmptyZipFileError, ZipContentsTooLargeError, -} from './ArchiveErrors.js' +} from './ArchiveErrors.mjs' import _ from 'lodash' import { promisifyAll } from '@overleaf/promise-utils' diff --git a/services/web/app/src/Features/Uploads/ProjectUploadController.mjs b/services/web/app/src/Features/Uploads/ProjectUploadController.mjs index e88b9944d5..61bf91b16b 100644 --- a/services/web/app/src/Features/Uploads/ProjectUploadController.mjs +++ b/services/web/app/src/Features/Uploads/ProjectUploadController.mjs @@ -8,7 +8,7 @@ import SessionManager from '../Authentication/SessionManager.mjs' import EditorController from '../Editor/EditorController.mjs' import ProjectLocator from '../Project/ProjectLocator.mjs' import Settings from '@overleaf/settings' -import { InvalidZipFileError } from './ArchiveErrors.js' +import { InvalidZipFileError } from './ArchiveErrors.mjs' import multer from 'multer' import lodash from 'lodash' import { expressify } from '@overleaf/promise-utils' diff --git a/services/web/app/src/Features/User/UserController.mjs b/services/web/app/src/Features/User/UserController.mjs index 9a21c494d1..88b09691d7 100644 --- a/services/web/app/src/Features/User/UserController.mjs +++ b/services/web/app/src/Features/User/UserController.mjs @@ -7,7 +7,7 @@ import logger from '@overleaf/logger' import metrics from '@overleaf/metrics' import AuthenticationManager from '../Authentication/AuthenticationManager.mjs' import SessionManager from '../Authentication/SessionManager.mjs' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import { z, validateReq } from '../../infrastructure/Validation.js' import UserAuditLogHandler from './UserAuditLogHandler.mjs' import UserSessionsManager from './UserSessionsManager.mjs' diff --git a/services/web/app/src/Features/User/UserCreator.mjs b/services/web/app/src/Features/User/UserCreator.mjs index 08ed98b455..d6e5aa8f57 100644 --- a/services/web/app/src/Features/User/UserCreator.mjs +++ b/services/web/app/src/Features/User/UserCreator.mjs @@ -1,7 +1,7 @@ import logger from '@overleaf/logger' import util from 'node:util' import { AffiliationError } from '../Errors/Errors.js' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import { User } from '../../models/User.mjs' import UserDeleter from './UserDeleter.mjs' import UserGetter from './UserGetter.mjs' diff --git a/services/web/app/src/Features/User/UserEmailsController.mjs b/services/web/app/src/Features/User/UserEmailsController.mjs index 0a30410740..008bc62030 100644 --- a/services/web/app/src/Features/User/UserEmailsController.mjs +++ b/services/web/app/src/Features/User/UserEmailsController.mjs @@ -17,7 +17,7 @@ import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' import UserPrimaryEmailCheckHandler from '../User/UserPrimaryEmailCheckHandler.mjs' import UserAuditLogHandler from './UserAuditLogHandler.mjs' import { RateLimiter } from '../../infrastructure/RateLimiter.js' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import tsscmp from 'tsscmp' import Modules from '../../infrastructure/Modules.js' diff --git a/services/web/app/src/Features/User/UserGetter.mjs b/services/web/app/src/Features/User/UserGetter.mjs index c8bce40136..c2459c35dc 100644 --- a/services/web/app/src/Features/User/UserGetter.mjs +++ b/services/web/app/src/Features/User/UserGetter.mjs @@ -5,13 +5,14 @@ import settings from '@overleaf/settings' import InstitutionsAPI from '../Institutions/InstitutionsAPI.mjs' import InstitutionsHelper from '../Institutions/InstitutionsHelper.mjs' import Errors from '../Errors/Errors.js' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import { User } from '../../models/User.mjs' -import { normalizeQuery, normalizeMultiQuery } from '../Helpers/Mongo.js' +import Mongo from '../Helpers/Mongo.mjs' import Modules from '../../infrastructure/Modules.js' import FeaturesHelper from '../Subscription/FeaturesHelper.mjs' import AsyncLocalStorage from '../../infrastructure/AsyncLocalStorage.js' +const { normalizeQuery, normalizeMultiQuery } = Mongo const InstitutionsAPIPromises = InstitutionsAPI.promises function _lastDayToReconfirm(emailData, institutionData) { diff --git a/services/web/app/src/Features/User/UserOnboardingEmailManager.mjs b/services/web/app/src/Features/User/UserOnboardingEmailManager.mjs index b29bbd2d96..fd10cf13d8 100644 --- a/services/web/app/src/Features/User/UserOnboardingEmailManager.mjs +++ b/services/web/app/src/Features/User/UserOnboardingEmailManager.mjs @@ -1,4 +1,4 @@ -import Queues from '../../infrastructure/Queues.js' +import Queues from '../../infrastructure/Queues.mjs' import EmailHandler from '../Email/EmailHandler.mjs' import UserUpdater from './UserUpdater.mjs' import UserGetter from './UserGetter.mjs' diff --git a/services/web/app/src/Features/User/UserPagesController.mjs b/services/web/app/src/Features/User/UserPagesController.mjs index d2e669a733..42d7167b9d 100644 --- a/services/web/app/src/Features/User/UserPagesController.mjs +++ b/services/web/app/src/Features/User/UserPagesController.mjs @@ -9,7 +9,7 @@ import NewsletterManager from '../Newsletter/NewsletterManager.mjs' import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs' import _ from 'lodash' import { expressify } from '@overleaf/promise-utils' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import Modules from '../../infrastructure/Modules.js' async function settingsPage(req, res) { diff --git a/services/web/app/src/Features/User/UserPostRegistrationAnalyticsManager.mjs b/services/web/app/src/Features/User/UserPostRegistrationAnalyticsManager.mjs index a21b929bd2..a1c55f9fe2 100644 --- a/services/web/app/src/Features/User/UserPostRegistrationAnalyticsManager.mjs +++ b/services/web/app/src/Features/User/UserPostRegistrationAnalyticsManager.mjs @@ -1,4 +1,4 @@ -import Queues from '../../infrastructure/Queues.js' +import Queues from '../../infrastructure/Queues.mjs' import UserGetter from './UserGetter.mjs' import InstitutionsAPI from '../Institutions/InstitutionsAPI.mjs' import AnalyticsManager from '../Analytics/AnalyticsManager.mjs' diff --git a/services/web/app/src/Features/User/UserUpdater.mjs b/services/web/app/src/Features/User/UserUpdater.mjs index f45b0456d2..4f4cdf2ba7 100644 --- a/services/web/app/src/Features/User/UserUpdater.mjs +++ b/services/web/app/src/Features/User/UserUpdater.mjs @@ -1,11 +1,11 @@ import logger from '@overleaf/logger' import OError from '@overleaf/o-error' import { db } from '../../infrastructure/mongodb.js' -import { normalizeQuery } from '../Helpers/Mongo.js' +import Mongo from '../Helpers/Mongo.mjs' import { callbackify } from 'node:util' import UserGetter from './UserGetter.mjs' import InstitutionsAPI from '../Institutions/InstitutionsAPI.mjs' -import Features from '../../infrastructure/Features.js' +import Features from '../../infrastructure/Features.mjs' import FeaturesUpdater from '../Subscription/FeaturesUpdater.mjs' import EmailHandler from '../Email/EmailHandler.mjs' import EmailHelper from '../Helpers/EmailHelper.mjs' @@ -22,6 +22,8 @@ import UserSessionsManager from './UserSessionsManager.mjs' import ThirdPartyIdentityManager from './ThirdPartyIdentityManager.mjs' import AsyncLocalStorage from '../../infrastructure/AsyncLocalStorage.js' +const { normalizeQuery } = Mongo + async function _sendSecurityAlertPrimaryEmailChanged( userId, oldEmail, diff --git a/services/web/app/src/Features/UserMembership/UserMembershipViewModel.mjs b/services/web/app/src/Features/UserMembership/UserMembershipViewModel.mjs index 5a34288ce1..c317940263 100644 --- a/services/web/app/src/Features/UserMembership/UserMembershipViewModel.mjs +++ b/services/web/app/src/Features/UserMembership/UserMembershipViewModel.mjs @@ -1,5 +1,7 @@ import UserGetter from '../User/UserGetter.mjs' -import { isObjectIdInstance } from '../Helpers/Mongo.js' +import Mongo from '../Helpers/Mongo.mjs' + +const { isObjectIdInstance } = Mongo const UserMembershipViewModel = { build(userOrEmail) { diff --git a/services/web/app/src/Features/V1/V1Api.js b/services/web/app/src/Features/V1/V1Api.mjs similarity index 93% rename from services/web/app/src/Features/V1/V1Api.js rename to services/web/app/src/Features/V1/V1Api.mjs index ce15891a76..a81719b3c3 100644 --- a/services/web/app/src/Features/V1/V1Api.js +++ b/services/web/app/src/Features/V1/V1Api.mjs @@ -7,10 +7,11 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const request = require('request') -const settings = require('@overleaf/settings') -const Errors = require('../Errors/Errors') -const { promisifyAll } = require('@overleaf/promise-utils') +import request from 'request' + +import settings from '@overleaf/settings' +import Errors from '../Errors/Errors.js' +import { promisifyAll } from '@overleaf/promise-utils' // TODO: check what happens when these settings aren't defined const DEFAULT_V1_PARAMS = { @@ -103,4 +104,4 @@ V1Api.promises = promisifyAll(V1Api, { oauthRequest: ['response', 'body'], }, }) -module.exports = V1Api +export default V1Api diff --git a/services/web/app/src/Features/V1/V1Handler.mjs b/services/web/app/src/Features/V1/V1Handler.mjs index 7c5f2d39ca..28aa86f3c0 100644 --- a/services/web/app/src/Features/V1/V1Handler.mjs +++ b/services/web/app/src/Features/V1/V1Handler.mjs @@ -11,7 +11,7 @@ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import OError from '@overleaf/o-error' -import V1Api from './V1Api.js' +import V1Api from './V1Api.mjs' import logger from '@overleaf/logger' let V1Handler diff --git a/services/web/app/src/infrastructure/ExpressLocals.mjs b/services/web/app/src/infrastructure/ExpressLocals.mjs index 05281be6e2..b7c32faed4 100644 --- a/services/web/app/src/infrastructure/ExpressLocals.mjs +++ b/services/web/app/src/infrastructure/ExpressLocals.mjs @@ -6,7 +6,7 @@ import Path from 'node:path' import moment from 'moment' import { fetchJson } from '@overleaf/fetch-utils' import contentDisposition from 'content-disposition' -import Features from './Features.js' +import Features from './Features.mjs' import SessionManager from '../Features/Authentication/SessionManager.mjs' import PackageVersions from './PackageVersions.js' import Modules from './Modules.js' diff --git a/services/web/app/src/infrastructure/Features.js b/services/web/app/src/infrastructure/Features.mjs similarity index 96% rename from services/web/app/src/infrastructure/Features.js rename to services/web/app/src/infrastructure/Features.mjs index c93d1f6702..b6b9961962 100644 --- a/services/web/app/src/infrastructure/Features.js +++ b/services/web/app/src/infrastructure/Features.mjs @@ -1,5 +1,5 @@ -const _ = require('lodash') -const Settings = require('@overleaf/settings') +import _ from 'lodash' +import Settings from '@overleaf/settings' const supportModuleAvailable = Settings.moduleImportSequence.includes('support') @@ -98,4 +98,4 @@ const Features = { }, } -module.exports = Features +export default Features diff --git a/services/web/app/src/infrastructure/QueueWorkers.mjs b/services/web/app/src/infrastructure/QueueWorkers.mjs index 134913a9df..77540e3d0f 100644 --- a/services/web/app/src/infrastructure/QueueWorkers.mjs +++ b/services/web/app/src/infrastructure/QueueWorkers.mjs @@ -1,5 +1,5 @@ -import Features from './Features.js' -import Queues from './Queues.js' +import Features from './Features.mjs' +import Queues from './Queues.mjs' import UserOnboardingEmailManager from '../Features/User/UserOnboardingEmailManager.mjs' import UserPostRegistrationAnalyticsManager from '../Features/User/UserPostRegistrationAnalyticsManager.mjs' import FeaturesUpdater from '../Features/Subscription/FeaturesUpdater.mjs' diff --git a/services/web/app/src/infrastructure/Queues.js b/services/web/app/src/infrastructure/Queues.mjs similarity index 93% rename from services/web/app/src/infrastructure/Queues.js rename to services/web/app/src/infrastructure/Queues.mjs index 973e52420c..a5555a30c8 100644 --- a/services/web/app/src/infrastructure/Queues.js +++ b/services/web/app/src/infrastructure/Queues.mjs @@ -1,7 +1,7 @@ -const Queue = require('bull') -const Settings = require('@overleaf/settings') -const Features = require('../infrastructure/Features') -const { addConnectionDrainer } = require('./GracefulShutdown') +import Queue from 'bull' +import Settings from '@overleaf/settings' +import Features from '../infrastructure/Features.mjs' +import { addConnectionDrainer } from './GracefulShutdown.js' // Bull will keep a fixed number of the most recently completed jobs. This is // useful to inspect recently completed jobs. The bull prometheus exporter also @@ -127,7 +127,7 @@ async function createScheduledJob(queueName, { name, data, options }, delay) { ) } -module.exports = { +export default { getQueue, createScheduledJob, } diff --git a/services/web/app/src/infrastructure/Server.mjs b/services/web/app/src/infrastructure/Server.mjs index c95b3dabff..52044bf79a 100644 --- a/services/web/app/src/infrastructure/Server.mjs +++ b/services/web/app/src/infrastructure/Server.mjs @@ -23,7 +23,7 @@ import ReferalConnect from '../Features/Referal/ReferalConnect.mjs' import RedirectManager from './RedirectManager.mjs' import translations from './Translations.mjs' import Views from './Views.js' -import Features from './Features.js' +import Features from './Features.mjs' import ErrorController from '../Features/Errors/ErrorController.mjs' import HttpErrorHandler from '../Features/Errors/HttpErrorHandler.mjs' import UserSessionsManager from '../Features/User/UserSessionsManager.mjs' diff --git a/services/web/app/src/infrastructure/SiteAdminHandler.mjs b/services/web/app/src/infrastructure/SiteAdminHandler.mjs index 27cc1d9e39..f9368f485f 100644 --- a/services/web/app/src/infrastructure/SiteAdminHandler.mjs +++ b/services/web/app/src/infrastructure/SiteAdminHandler.mjs @@ -7,7 +7,7 @@ import { addRequiredCleanupHandlerBeforeDrainingConnections, } from './GracefulShutdown.js' -import Features from './Features.js' +import Features from './Features.mjs' import UserHandler from '../Features/User/UserHandler.mjs' import metrics from '@overleaf/metrics' diff --git a/services/web/app/src/models/User.mjs b/services/web/app/src/models/User.mjs index 5739474106..7ae68ca21f 100644 --- a/services/web/app/src/models/User.mjs +++ b/services/web/app/src/models/User.mjs @@ -1,6 +1,6 @@ import Settings from '@overleaf/settings' import mongoose from '../infrastructure/Mongoose.js' -import TokenGenerator from '../Features/TokenGenerator/TokenGenerator.js' +import TokenGenerator from '../Features/TokenGenerator/TokenGenerator.mjs' const { Schema } = mongoose const { ObjectId } = Schema diff --git a/services/web/app/src/router.mjs b/services/web/app/src/router.mjs index 52c215ef13..d4af39c7e6 100644 --- a/services/web/app/src/router.mjs +++ b/services/web/app/src/router.mjs @@ -1,6 +1,6 @@ import AdminController from './Features/ServerAdmin/AdminController.mjs' import ErrorController from './Features/Errors/ErrorController.mjs' -import Features from './infrastructure/Features.js' +import Features from './infrastructure/Features.mjs' import ProjectController from './Features/Project/ProjectController.mjs' import ProjectApiController from './Features/Project/ProjectApiController.mjs' import ProjectListController from './Features/Project/ProjectListController.mjs' diff --git a/services/web/scripts/backfill_mixpanel_user_properties.mjs b/services/web/scripts/backfill_mixpanel_user_properties.mjs index 6e3dabd4c2..ab7259fb45 100644 --- a/services/web/scripts/backfill_mixpanel_user_properties.mjs +++ b/services/web/scripts/backfill_mixpanel_user_properties.mjs @@ -2,12 +2,13 @@ import '../app/src/models/User.mjs' import { batchedUpdateWithResultHandling } from '@overleaf/mongo-utils/batchedUpdate.js' import { promiseMapWithLimit } from '@overleaf/promise-utils' -import { getQueue } from '../app/src/infrastructure/Queues.js' +import Queues from '../app/src/infrastructure/Queues.mjs' import SubscriptionLocator from '../app/src/Features/Subscription/SubscriptionLocator.mjs' import PlansLocator from '../app/src/Features/Subscription/PlansLocator.mjs' import FeaturesHelper from '../app/src/Features/Subscription/FeaturesHelper.mjs' import { db } from '../app/src/infrastructure/mongodb.js' +const { getQueue } = Queues const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY || '10', 10) const mixpanelSinkQueue = getQueue('analytics-mixpanel-sink') diff --git a/services/web/scripts/regenerate_duplicate_referral_ids.mjs b/services/web/scripts/regenerate_duplicate_referral_ids.mjs index 499823a08f..84f3a7f61e 100644 --- a/services/web/scripts/regenerate_duplicate_referral_ids.mjs +++ b/services/web/scripts/regenerate_duplicate_referral_ids.mjs @@ -3,7 +3,7 @@ import { READ_PREFERENCE_SECONDARY, } from '../app/src/infrastructure/mongodb.js' import { promiseMapWithLimit } from '@overleaf/promise-utils' -import TokenGenerator from '../app/src/Features/TokenGenerator/TokenGenerator.js' +import TokenGenerator from '../app/src/Features/TokenGenerator/TokenGenerator.mjs' import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js' const VERBOSE_LOGGING = process.env.VERBOSE_LOGGING === 'true' diff --git a/services/web/test/acceptance/src/ActiveUsersMetricTests.mjs b/services/web/test/acceptance/src/ActiveUsersMetricTests.mjs index 8fbb661148..a7ca912ef2 100644 --- a/services/web/test/acceptance/src/ActiveUsersMetricTests.mjs +++ b/services/web/test/acceptance/src/ActiveUsersMetricTests.mjs @@ -1,6 +1,6 @@ import { promisify } from 'node:util' import { expect } from 'chai' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import MetricsHelper from './helpers/metrics.mjs' import UserHelper from './helpers/User.mjs' const sleep = promisify(setTimeout) diff --git a/services/web/test/acceptance/src/AddSecondaryEmailTests.mjs b/services/web/test/acceptance/src/AddSecondaryEmailTests.mjs index c153416fe6..d56d7e877e 100644 --- a/services/web/test/acceptance/src/AddSecondaryEmailTests.mjs +++ b/services/web/test/acceptance/src/AddSecondaryEmailTests.mjs @@ -3,7 +3,7 @@ import UserHelper from './helpers/User.mjs' import logger from '@overleaf/logger' import sinon from 'sinon' import { db } from '../../../app/src/infrastructure/mongodb.js' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' const User = UserHelper.promises diff --git a/services/web/test/acceptance/src/AuthorizationTests.mjs b/services/web/test/acceptance/src/AuthorizationTests.mjs index 63001af6f8..dce54f438b 100644 --- a/services/web/test/acceptance/src/AuthorizationTests.mjs +++ b/services/web/test/acceptance/src/AuthorizationTests.mjs @@ -2,7 +2,7 @@ import { expect } from 'chai' import UserHelper from './helpers/User.mjs' import request from './helpers/request.js' import settings from '@overleaf/settings' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import expectErrorResponse from './helpers/expectErrorResponse.mjs' import { promisify } from '@overleaf/promise-utils' diff --git a/services/web/test/acceptance/src/DeletionTests.mjs b/services/web/test/acceptance/src/DeletionTests.mjs index d7a1ff8896..39d1ba053d 100644 --- a/services/web/test/acceptance/src/DeletionTests.mjs +++ b/services/web/test/acceptance/src/DeletionTests.mjs @@ -7,7 +7,7 @@ import async from 'async' import { expect } from 'chai' import settings from '@overleaf/settings' import { db, ObjectId } from '../../../app/src/infrastructure/mongodb.js' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import MockDocstoreApiClass from './mocks/MockDocstoreApi.mjs' import MockChatApiClass from './mocks/MockChatApi.mjs' import MockGitBridgeApiClass from './mocks/MockGitBridgeApi.mjs' diff --git a/services/web/test/acceptance/src/Init.mjs b/services/web/test/acceptance/src/Init.mjs index c491ba3636..2179e27aeb 100644 --- a/services/web/test/acceptance/src/Init.mjs +++ b/services/web/test/acceptance/src/Init.mjs @@ -1,5 +1,5 @@ import './helpers/InitApp.mjs' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import MockAnalyticsApi from './mocks/MockAnalyticsApi.mjs' import MockChatApi from './mocks/MockChatApi.mjs' diff --git a/services/web/test/acceptance/src/MongoHelper.mjs b/services/web/test/acceptance/src/MongoHelper.mjs index dc7ddbeab6..1821477bdf 100644 --- a/services/web/test/acceptance/src/MongoHelper.mjs +++ b/services/web/test/acceptance/src/MongoHelper.mjs @@ -3,12 +3,11 @@ import mongodb from 'mongodb-legacy' import mongoose from 'mongoose' import { User as UserModel } from '../../../app/src/models/User.mjs' import { db } from '../../../app/src/infrastructure/mongodb.js' -import { - normalizeQuery, - normalizeMultiQuery, -} from '../../../app/src/Features/Helpers/Mongo.js' +import MongoHelpers from '../../../app/src/Features/Helpers/Mongo.mjs' import UserHelper from './helpers/User.mjs' +const { normalizeQuery, normalizeMultiQuery } = MongoHelpers + const User = UserHelper.promises const NativeObjectId = mongodb.ObjectId diff --git a/services/web/test/acceptance/src/PrimaryEmailCheckTests.mjs b/services/web/test/acceptance/src/PrimaryEmailCheckTests.mjs index bc85f96a5d..16fcdf5ebb 100644 --- a/services/web/test/acceptance/src/PrimaryEmailCheckTests.mjs +++ b/services/web/test/acceptance/src/PrimaryEmailCheckTests.mjs @@ -1,7 +1,7 @@ import UserHelper from './helpers/UserHelper.mjs' import Settings from '@overleaf/settings' import { expect } from 'chai' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import MockV1ApiClass from './mocks/MockV1Api.mjs' import SubscriptionHelper from './helpers/Subscription.mjs' diff --git a/services/web/test/acceptance/src/ProjectCRUDTests.mjs b/services/web/test/acceptance/src/ProjectCRUDTests.mjs index 2c6d638e9f..12d4e3e0c7 100644 --- a/services/web/test/acceptance/src/ProjectCRUDTests.mjs +++ b/services/web/test/acceptance/src/ProjectCRUDTests.mjs @@ -4,7 +4,7 @@ import { Project } from '../../../app/src/models/Project.mjs' import mongodb from 'mongodb-legacy' import cheerio from 'cheerio' import { Subscription } from '../../../app/src/models/Subscription.mjs' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' const ObjectId = mongodb.ObjectId diff --git a/services/web/test/acceptance/src/ProjectInviteTests.mjs b/services/web/test/acceptance/src/ProjectInviteTests.mjs index 0debf26169..525a1bbc82 100644 --- a/services/web/test/acceptance/src/ProjectInviteTests.mjs +++ b/services/web/test/acceptance/src/ProjectInviteTests.mjs @@ -4,7 +4,7 @@ import User from './helpers/User.mjs' import settings from '@overleaf/settings' import CollaboratorsEmailHandler from '../../../app/src/Features/Collaborators/CollaboratorsEmailHandler.mjs' import CollaboratorsInviteHelper from '../../../app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import sinon from 'sinon' let generateTokenSpy diff --git a/services/web/test/acceptance/src/RegistrationTests.mjs b/services/web/test/acceptance/src/RegistrationTests.mjs index f062d3d314..c5fd66def7 100644 --- a/services/web/test/acceptance/src/RegistrationTests.mjs +++ b/services/web/test/acceptance/src/RegistrationTests.mjs @@ -3,7 +3,7 @@ import async from 'async' import metrics from './helpers/metrics.mjs' import User from './helpers/User.mjs' import redis from './helpers/redis.mjs' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' const UserPromises = User.promises diff --git a/services/web/test/acceptance/src/SettingsTests.mjs b/services/web/test/acceptance/src/SettingsTests.mjs index 52378f1044..fc8bfa34f4 100644 --- a/services/web/test/acceptance/src/SettingsTests.mjs +++ b/services/web/test/acceptance/src/SettingsTests.mjs @@ -12,7 +12,7 @@ import { expect } from 'chai' import async from 'async' import User from './helpers/User.mjs' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' describe('SettingsPage', function () { beforeEach(function (done) { diff --git a/services/web/test/acceptance/src/UserHelperTests.mjs b/services/web/test/acceptance/src/UserHelperTests.mjs index ab229133b6..b48af2ef81 100644 --- a/services/web/test/acceptance/src/UserHelperTests.mjs +++ b/services/web/test/acceptance/src/UserHelperTests.mjs @@ -1,6 +1,6 @@ import AuthenticationManager from '../../../app/src/Features/Authentication/AuthenticationManager.mjs' import UserHelper from './helpers/UserHelper.mjs' -import Features from '../../../app/src/infrastructure/Features.js' +import Features from '../../../app/src/infrastructure/Features.mjs' import { expect } from 'chai' describe('UserHelper', function () { diff --git a/services/web/test/smoke/src/steps/001_clearRateLimits.mjs b/services/web/test/smoke/src/steps/001_clearRateLimits.mjs index 45e59f2b8c..953c3fca62 100644 --- a/services/web/test/smoke/src/steps/001_clearRateLimits.mjs +++ b/services/web/test/smoke/src/steps/001_clearRateLimits.mjs @@ -3,7 +3,7 @@ import { overleafLoginRateLimiter, openProjectRateLimiter, } from '../../../../app/src/infrastructure/RateLimiter.js' -import LoginRateLimiter from '../../../../app/src/Features/Security/LoginRateLimiter.js' +import LoginRateLimiter from '../../../../app/src/Features/Security/LoginRateLimiter.mjs' async function clearLoginRateLimit() { await LoginRateLimiter.promises.recordSuccessfulLogin(Settings.smokeTest.user) diff --git a/services/web/test/unit/bootstrap.js b/services/web/test/unit/bootstrap.js index 00bcc3e958..82a1b04072 100644 --- a/services/web/test/unit/bootstrap.js +++ b/services/web/test/unit/bootstrap.js @@ -66,10 +66,7 @@ function getSandboxedModuleRequires() { '@overleaf/logger': globalStubs.logger, } - const internalModules = [ - '../../app/src/Features/Errors/Errors', - '../../app/src/Features/Helpers/Mongo', - ] + const internalModules = ['../../app/src/Features/Errors/Errors'] const externalLibs = [ 'async', 'bull', diff --git a/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs b/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs index c31900112b..be86f3bd04 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs +++ b/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs @@ -1,6 +1,6 @@ import { vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponseVitest.mjs' const modulePath = new URL( '../../../../app/src/Features/Analytics/AnalyticsController.mjs', import.meta.url @@ -33,7 +33,7 @@ describe('AnalyticsController', function () { }) ) - vi.doMock('../../../../app/src/infrastructure/Features.js', () => ({ + vi.doMock('../../../../app/src/infrastructure/Features.mjs', () => ({ default: ctx.Features, })) @@ -47,7 +47,7 @@ describe('AnalyticsController', function () { ctx.controller = (await import(modulePath)).default - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) }) describe('updateEditingSession', function () { diff --git a/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs b/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs index 86b95b60c2..82c5d741c6 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs +++ b/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs @@ -1,8 +1,8 @@ import { vi, assert } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' import mongodb from 'mongodb-legacy' const { ObjectId } = mongodb @@ -395,9 +395,9 @@ describe('AnalyticsManager', function () { })) ctx.AnalyticsManager = (await import(MODULE_PATH)).default - ctx.req = new MockRequest() + ctx.req = new MockRequest(vi) ctx.req.session = {} - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.next = () => {} }) diff --git a/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs b/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs index eeed2f2850..dcad6a08cd 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs +++ b/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs @@ -1,7 +1,7 @@ import { assert, vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' const MODULE_PATH = new URL( '../../../../app/src/Features/Analytics/AnalyticsUTMTrackingMiddleware', @@ -13,8 +13,8 @@ describe('AnalyticsUTMTrackingMiddleware', function () { ctx.analyticsId = 'ecdb935a-52f3-4f91-aebc-7a70d2ffbb55' ctx.userId = '61795fcb013504bb7b663092' - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub().returns() ctx.req.session = { user: { diff --git a/services/web/test/unit/src/Analytics/EmailChangeHelpers.test.mjs b/services/web/test/unit/src/Analytics/EmailChangeHelpers.test.mjs index 8fb9371e05..bf414139ae 100644 --- a/services/web/test/unit/src/Analytics/EmailChangeHelpers.test.mjs +++ b/services/web/test/unit/src/Analytics/EmailChangeHelpers.test.mjs @@ -29,7 +29,9 @@ describe('EmailChangeHelper', function () { ) EmailChangeHelpers = ( - await import('../../../../app/src/Features/Analytics/EmailChangeHelper') + await import( + '../../../../app/src/Features/Analytics/EmailChangeHelper.mjs' + ) ).default }) diff --git a/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs b/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs index 72f1e7ab33..17273d723f 100644 --- a/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs +++ b/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs @@ -1,10 +1,10 @@ import { beforeEach, describe, it, vi, expect } from 'vitest' import sinon from 'sinon' import tk from 'timekeeper' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' import mongodb from 'mongodb-legacy' -import AuthenticationErrors from '../../../../app/src/Features/Authentication/AuthenticationErrors.js' +import AuthenticationErrors from '../../../../app/src/Features/Authentication/AuthenticationErrors.mjs' const modulePath = '../../../../app/src/Features/Authentication/AuthenticationController.mjs' @@ -64,8 +64,8 @@ describe('AuthenticationController', function () { }, } ctx.password = 'banana' - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.callback = sinon.stub() ctx.next = sinon.stub() ctx.req.session.analyticsId = 'abc-123' diff --git a/services/web/test/unit/src/Authentication/AuthenticationManager.test.mjs b/services/web/test/unit/src/Authentication/AuthenticationManager.test.mjs index 2a85092530..c56112835b 100644 --- a/services/web/test/unit/src/Authentication/AuthenticationManager.test.mjs +++ b/services/web/test/unit/src/Authentication/AuthenticationManager.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import AuthenticationErrors from '../../../../app/src/Features/Authentication/AuthenticationErrors.js' +import AuthenticationErrors from '../../../../app/src/Features/Authentication/AuthenticationErrors.mjs' import tk from 'timekeeper' import bcrypt from 'bcrypt' diff --git a/services/web/test/unit/src/Authorization/AuthorizationManager.test.mjs b/services/web/test/unit/src/Authorization/AuthorizationManager.test.mjs index 9b80678e30..8a5d7bde43 100644 --- a/services/web/test/unit/src/Authorization/AuthorizationManager.test.mjs +++ b/services/web/test/unit/src/Authorization/AuthorizationManager.test.mjs @@ -1,7 +1,7 @@ import { beforeEach, describe, it, vi, expect } from 'vitest' import sinon from 'sinon' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.mjs' import PublicAccessLevels from '../../../../app/src/Features/Authorization/PublicAccessLevels.mjs' import mongodb from 'mongodb-legacy' const modulePath = diff --git a/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs b/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs index b1fc8cf2fa..a80a24e3c9 100644 --- a/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs +++ b/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs @@ -1,7 +1,7 @@ import { expect, vi } from 'vitest' import path from 'node:path' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponseVitest.mjs' import { fileURLToPath } from 'node:url' const __dirname = fileURLToPath(new URL('.', import.meta.url)) @@ -74,7 +74,7 @@ describe('BetaProgramController', function () { ) ctx.BetaProgramController = (await import(modulePath)).default - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() }) @@ -122,7 +122,7 @@ describe('BetaProgramController', function () { it("should not redirect to '/beta/participate'", function (ctx) { ctx.BetaProgramController.optIn(ctx.req, ctx.res, ctx.next) - ctx.res.redirect.callCount.should.equal(0) + expect(ctx.res.redirect).not.toHaveBeenCalled() }) it('should produce an error', async function (ctx) { @@ -248,7 +248,7 @@ describe('BetaProgramController', function () { it('should not render the opt-in page', function (ctx) { ctx.BetaProgramController.optInPage(ctx.req, ctx.res, ctx.next) - ctx.res.render.callCount.should.equal(0) + expect(ctx.res.render).not.toHaveBeenCalled() }) it('should produce an error', async function (ctx) { diff --git a/services/web/test/unit/src/Chat/ChatApiHandler.test.mjs b/services/web/test/unit/src/Chat/ChatApiHandler.test.mjs index a204c64dd7..83cc9d23b9 100644 --- a/services/web/test/unit/src/Chat/ChatApiHandler.test.mjs +++ b/services/web/test/unit/src/Chat/ChatApiHandler.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import { RequestFailedError } from '@overleaf/fetch-utils' diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs index 471092252a..922673f436 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs @@ -2,8 +2,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' const ObjectId = mongodb.ObjectId @@ -16,8 +16,8 @@ vi.mock('../../../../app/src/Features/Errors/Errors.js', () => describe('CollaboratorsController', function () { beforeEach(async function (ctx) { - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.user = { _id: new ObjectId() } ctx.projectId = new ObjectId() diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsGetter.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsGetter.test.mjs index cd6506c7d4..9d304f421d 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsGetter.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsGetter.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import Path from 'path' +import Path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import { Project } from '../../../../app/src/models/Project.mjs' diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsHandler.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsHandler.test.mjs index fa4e4bc2b2..f9e571449b 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsHandler.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsHandler.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import Errors from '../../../../app/src/Features/Errors/Errors.js' import { Project } from '../../../../app/src/models/Project.mjs' diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs index 2aaf02dbb5..7cfa9c71c2 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs @@ -1,7 +1,7 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' import _ from 'lodash' @@ -214,8 +214,8 @@ describe('CollaboratorsInviteController', function () { ctx.CollaboratorsInviteController = (await import(MODULE_PATH)).default - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.next = sinon.stub() }) @@ -248,8 +248,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce a list of invite objects', function (ctx) { - ctx.res.json.callCount.should.equal(1) - ctx.res.json.calledWith({ invites: ctx.fakeInvites }).should.equal(true) + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json).toHaveBeenCalledWith({ invites: ctx.fakeInvites }) }) it('should have called CollaboratorsInviteHandler.getAllInvites', function (ctx) { @@ -312,8 +312,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce json response', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json.firstCall.args[0]).to.deep.equal({ + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json.mock.calls[0][0]).to.deep.equal({ invite: ctx.inviteReducedData, }) }) @@ -397,8 +397,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce json response without an invite', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json.firstCall.args[0]).to.deep.equal({ + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json.mock.calls[0][0]).to.deep.equal({ invite: null, }) }) @@ -442,8 +442,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce json response', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json.firstCall.args[0]).to.deep.equal({ + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json.mock.calls[0][0]).to.deep.equal({ invite: ctx.inviteReducedData, }) }) @@ -577,8 +577,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce json response with no invite, and an error property', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json.firstCall.args[0]).to.deep.equal({ + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json.mock.calls[0][0]).to.deep.equal({ invite: null, error: 'cannot_invite_non_user', }) @@ -656,8 +656,8 @@ describe('CollaboratorsInviteController', function () { }) it('should reject action, return json response with error code', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json.firstCall.args[0]).to.deep.equal({ + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json.mock.calls[0][0]).to.deep.equal({ invite: null, error: 'cannot_invite_self', }) @@ -702,7 +702,7 @@ describe('CollaboratorsInviteController', function () { }) it('should send a 429 response', function (ctx) { - ctx.res.sendStatus.calledWith(429).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(429) }) it('should not call inviteToProject', function (ctx) { @@ -760,8 +760,11 @@ describe('CollaboratorsInviteController', function () { }) it('should render the view template', function (ctx) { - ctx.res.render.callCount.should.equal(1) - ctx.res.render.calledWith('project/invite/show').should.equal(true) + expect(ctx.res.render).toHaveBeenCalledTimes(1) + expect(ctx.res.render).toHaveBeenCalledWith( + 'project/invite/show', + expect.anything() + ) }) it('should not call next', function (ctx) { @@ -826,32 +829,29 @@ describe('CollaboratorsInviteController', function () { }) it('should redirect to the register page', function (ctx) { - expect(ctx.res.render).to.not.have.been.called - expect(ctx.res.redirect).to.have.been.calledOnce - expect(ctx.res.redirect).to.have.been.calledWith('/register') + expect(ctx.res.render).not.toHaveBeenCalled() + expect(ctx.res.redirect).toHaveBeenCalledTimes(1) + expect(ctx.res.redirect).toHaveBeenCalledWith('/register') }) }) describe('when user is already a member of the project', function () { beforeEach(async function (ctx) { - await new Promise(resolve => { - ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.resolves( - true - ) - ctx.res.callback = () => resolve() - ctx.CollaboratorsInviteController.viewInvite( - ctx.req, - ctx.res, - ctx.next - ) - }) + ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.resolves( + true + ) + await ctx.CollaboratorsInviteController.viewInvite( + ctx.req, + ctx.res, + ctx.next + ) }) it('should redirect to the project page', function (ctx) { - ctx.res.redirect.callCount.should.equal(1) - ctx.res.redirect - .calledWith(`/project/${ctx.projectId}`) - .should.equal(true) + expect(ctx.res.redirect).toHaveBeenCalledTimes(1) + expect(ctx.res.redirect).toHaveBeenCalledWith( + `/project/${ctx.projectId}` + ) }) it('should not call next with an error', function (ctx) { @@ -987,8 +987,11 @@ describe('CollaboratorsInviteController', function () { }) it('should render the not-valid view template', function (ctx) { - ctx.res.render.callCount.should.equal(1) - ctx.res.render.calledWith('project/invite/not-valid').should.equal(true) + expect(ctx.res.render).toHaveBeenCalledTimes(1) + expect(ctx.res.render).toHaveBeenCalledWith( + 'project/invite/not-valid', + expect.anything() + ) }) it('should not call next', function (ctx) { @@ -1081,8 +1084,11 @@ describe('CollaboratorsInviteController', function () { }) it('should render the not-valid view template', function (ctx) { - ctx.res.render.callCount.should.equal(1) - ctx.res.render.calledWith('project/invite/not-valid').should.equal(true) + expect(ctx.res.render).toHaveBeenCalledTimes(1) + expect(ctx.res.render).toHaveBeenCalledWith( + 'project/invite/not-valid', + expect.anything() + ) }) it('should not call next', function (ctx) { @@ -1175,8 +1181,11 @@ describe('CollaboratorsInviteController', function () { }) it('should render the not-valid view template', function (ctx) { - ctx.res.render.callCount.should.equal(1) - ctx.res.render.calledWith('project/invite/not-valid').should.equal(true) + expect(ctx.res.render).toHaveBeenCalledTimes(1) + expect(ctx.res.render).toHaveBeenCalledWith( + 'project/invite/not-valid', + expect.anything() + ) }) it('should not call next', function (ctx) { @@ -1236,8 +1245,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce a 201 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.calledWith(201).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(201) }) it('should have called generateNewInvite', function (ctx) { @@ -1296,8 +1305,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce a 404 response when invite is null', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.should.have.been.calledWith(404) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(404) }) }) }) @@ -1318,7 +1327,7 @@ describe('CollaboratorsInviteController', function () { }) it('should not produce a 201 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(0) + expect(ctx.res.sendStatus).not.toHaveBeenCalled() }) it('should call next with the error', function (ctx) { @@ -1355,8 +1364,8 @@ describe('CollaboratorsInviteController', function () { }) it('should produce a 204 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.should.have.been.calledWith(204) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(204) }) it('should have called revokeInvite', function (ctx) { @@ -1402,7 +1411,7 @@ describe('CollaboratorsInviteController', function () { }) it('should not produce a 201 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(0) + expect(ctx.res.sendStatus).not.toHaveBeenCalled() }) it('should call next with the error', function (ctx) { @@ -1439,8 +1448,8 @@ describe('CollaboratorsInviteController', function () { }) it('should redirect to project page', function (ctx) { - ctx.res.redirect.should.have.been.calledOnce - ctx.res.redirect.should.have.been.calledWith( + expect(ctx.res.redirect).toHaveBeenCalledTimes(1) + expect(ctx.res.redirect).toHaveBeenCalledWith( `/project/${ctx.projectId}` ) }) @@ -1511,7 +1520,7 @@ describe('CollaboratorsInviteController', function () { }) it('should not redirect to project page', function (ctx) { - ctx.res.redirect.callCount.should.equal(0) + expect(ctx.res.redirect).not.toHaveBeenCalled() }) it('should call next with the error', function (ctx) { diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteGetter.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsInviteGetter.test.mjs index 742516757a..16dd78c08f 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteGetter.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteGetter.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import Crypto from 'crypto' +import Crypto from 'node:crypto' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandler.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandler.test.mjs index 41e5e3eba5..47c7c4eefe 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandler.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteHandler.test.mjs @@ -1,7 +1,7 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import Crypto from 'crypto' +import Crypto from 'node:crypto' const ObjectId = mongodb.ObjectId diff --git a/services/web/test/unit/src/Collaborators/OwnershipTransferHandler.test.mjs b/services/web/test/unit/src/Collaborators/OwnershipTransferHandler.test.mjs index 35e48e2e15..4cf14afcd1 100644 --- a/services/web/test/unit/src/Collaborators/OwnershipTransferHandler.test.mjs +++ b/services/web/test/unit/src/Collaborators/OwnershipTransferHandler.test.mjs @@ -1,6 +1,6 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.mjs' import Errors from '../../../../app/src/Features/Errors/Errors.js' import mongodb from 'mongodb-legacy' diff --git a/services/web/test/unit/src/Compile/ClsiManager.test.mjs b/services/web/test/unit/src/Compile/ClsiManager.test.mjs index e539747a5e..dc679c27ef 100644 --- a/services/web/test/unit/src/Compile/ClsiManager.test.mjs +++ b/services/web/test/unit/src/Compile/ClsiManager.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import { setTimeout } from 'timers/promises' +import { setTimeout } from 'node:timers/promises' import sinon from 'sinon' import tk from 'timekeeper' import { RequestFailedError } from '@overleaf/fetch-utils' diff --git a/services/web/test/unit/src/Compile/CompileController.test.mjs b/services/web/test/unit/src/Compile/CompileController.test.mjs index ef2c22951f..d715d3e600 100644 --- a/services/web/test/unit/src/Compile/CompileController.test.mjs +++ b/services/web/test/unit/src/Compile/CompileController.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' import { Headers } from 'node-fetch' import { ReadableString } from '@overleaf/stream-utils' import { RequestFailedError } from '@overleaf/fetch-utils' @@ -53,6 +53,8 @@ describe('CompileController', function () { clsiCookie: { key: 'cookie-key', }, + moduleImportSequence: [], + overleaf: {}, } ctx.ClsiCookieManager = { promises: { @@ -168,9 +170,9 @@ describe('CompileController', function () { ctx.projectId = 'abc123def456abc123def456' ctx.build_id = '18fbe9e7564-30dcb2f71250c690' ctx.next = sinon.stub() - ctx.req = new MockRequest() - ctx.res = new MockResponse() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) + ctx.res = new MockResponse(vi) }) describe('compile', function () { @@ -288,7 +290,7 @@ describe('CompileController', function () { }) it('should do the compile without the auto compile flag', function (ctx) { - ctx.CompileManager.promises.compile.should.have.been.calledWith( + expect(ctx.CompileManager.promises.compile).to.have.been.calledWith( ctx.projectId, ctx.user_id, { @@ -409,7 +411,7 @@ describe('CompileController', function () { it('should set the content-type of the response to application/json', async function (ctx) { await ctx.CompileController.compileSubmission(ctx.req, ctx.res, ctx.next) - ctx.res.contentType.calledWith('application/json').should.equal(true) + expect(ctx.res.contentType).toBeCalledWith('application/json') }) it('should send a successful response reporting the status and files', async function (ctx) { @@ -497,11 +499,11 @@ describe('CompileController', function () { }) it('should set the content-type of the response to application/pdf', function (ctx) { - ctx.res.contentType.calledWith('application/pdf').should.equal(true) + expect(ctx.res.contentType).toBeCalledWith('application/pdf') }) it('should set the content-disposition header with a safe version of the project name', function (ctx) { - ctx.res.setContentDisposition.should.be.calledWith('inline', { + expect(ctx.res.setContentDisposition).toBeCalledWith('inline', { filename: 'test_namè__1.pdf', }) }) @@ -556,7 +558,7 @@ describe('CompileController', function () { it('should return 500', async function (ctx) { await ctx.CompileController.downloadPdf(ctx.req, ctx.res, ctx.next) // should it be 429 instead? - ctx.res.sendStatus.calledWith(500).should.equal(true) + expect(ctx.res.sendStatus).toBeCalledWith(500) ctx.CompileController._proxyToClsi.should.not.have.been.called }) }) @@ -567,7 +569,7 @@ describe('CompileController', function () { }) it('should return 500', async function (ctx) { await ctx.CompileController.downloadPdf(ctx.req, ctx.res, ctx.next) - ctx.res.sendStatus.calledWith(500).should.equal(true) + expect(ctx.res.sendStatus).toBeCalledWith(500) ctx.CompileController._proxyToClsi.should.not.have.been.called }) }) diff --git a/services/web/test/unit/src/Contact/ContactController.test.mjs b/services/web/test/unit/src/Contact/ContactController.test.mjs index 06dd5b768a..3f85cf1c88 100644 --- a/services/web/test/unit/src/Contact/ContactController.test.mjs +++ b/services/web/test/unit/src/Contact/ContactController.test.mjs @@ -1,6 +1,6 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponseVitest.mjs' const modulePath = '../../../../app/src/Features/Contacts/ContactController.mjs' describe('ContactController', function () { @@ -33,7 +33,7 @@ describe('ContactController', function () { ctx.ContactController = (await import(modulePath)).default ctx.req = {} - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) }) describe('getContacts', function () { @@ -130,7 +130,7 @@ describe('ContactController', function () { it('should return a formatted list of contacts in contact list order, without holding accounts', async function (ctx) { await new Promise((resolve, reject) => { ctx.res.callback = () => { - ctx.res.json.args[0][0].contacts.should.deep.equal([ + ctx.res.json.mock.calls[0][0].contacts.should.deep.equal([ { id: 'contact-1', email: 'joe@example.com', diff --git a/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterHandler.test.mjs b/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterHandler.test.mjs index 6246b948ab..6afaa0b8bf 100644 --- a/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterHandler.test.mjs +++ b/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterHandler.test.mjs @@ -1,6 +1,6 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import path from 'path' +import path from 'node:path' import mongodb from 'mongodb-legacy' import nock from 'nock' diff --git a/services/web/test/unit/src/Downloads/ProjectZipStreamManager.test.mjs b/services/web/test/unit/src/Downloads/ProjectZipStreamManager.test.mjs index ab38897fb7..61f8a4ab77 100644 --- a/services/web/test/unit/src/Downloads/ProjectZipStreamManager.test.mjs +++ b/services/web/test/unit/src/Downloads/ProjectZipStreamManager.test.mjs @@ -10,7 +10,7 @@ import { vi } from 'vitest' * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import sinon from 'sinon' -import { EventEmitter } from 'events' +import { EventEmitter } from 'node:events' const modulePath = '../../../../app/src/Features/Downloads/ProjectZipStreamManager.mjs' diff --git a/services/web/test/unit/src/Editor/EditorHttpController.test.mjs b/services/web/test/unit/src/Editor/EditorHttpController.test.mjs index eb225a84a4..730d9c811a 100644 --- a/services/web/test/unit/src/Editor/EditorHttpController.test.mjs +++ b/services/web/test/unit/src/Editor/EditorHttpController.test.mjs @@ -2,8 +2,8 @@ import { beforeEach, describe, it, vi, expect } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockResponse from '../helpers/MockResponseVitest.mjs' const { ObjectId } = mongodb @@ -52,8 +52,8 @@ describe('EditorHttpController', function () { ctx.source = 'editor' ctx.parentFolderId = 'mock-folder-id' - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.token = null ctx.docLines = ['hello', 'overleaf'] @@ -302,7 +302,7 @@ describe('EditorHttpController', function () { }) it('should return the project and privilege level', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ project: ctx.projectView, privilegeLevel: 'owner', isRestrictedUser: false, @@ -359,7 +359,7 @@ describe('EditorHttpController', function () { }) it('should mark the user as restricted, and hide details of owner', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ project: ctx.reducedProjectView, privilegeLevel: 'readOnly', isRestrictedUser: true, @@ -415,7 +415,7 @@ describe('EditorHttpController', function () { }) it('should mark the user as restricted', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ project: ctx.reducedProjectView, privilegeLevel: 'readOnly', isRestrictedUser: true, @@ -449,7 +449,7 @@ describe('EditorHttpController', function () { }) it('should mark the user as being a token-access member', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ project: ctx.projectView, privilegeLevel: 'readAndWrite', isRestrictedUser: false, @@ -505,7 +505,7 @@ describe('EditorHttpController', function () { }) it('should send the doc back as JSON', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith(ctx.doc) + expect(ctx.res.json).toHaveBeenCalledWith(ctx.doc) }) }) @@ -528,7 +528,7 @@ describe('EditorHttpController', function () { await new Promise(resolve => { ctx.res.callback = () => { expect(ctx.res.body).to.equal('"project_has_too_many_files_limit"') - expect(ctx.res.status).to.have.been.calledWith(400) + expect(ctx.res.status).toHaveBeenCalledWith(400) resolve() } ctx.EditorHttpController.addDoc(ctx.req, ctx.res) @@ -565,7 +565,7 @@ describe('EditorHttpController', function () { }) it('should send the folder back as JSON', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith(ctx.folder) + expect(ctx.res.json).toHaveBeenCalledWith(ctx.folder) }) }) @@ -646,7 +646,7 @@ describe('EditorHttpController', function () { }) it('should send back a success response', function (ctx) { - expect(ctx.res.sendStatus).to.have.been.calledWith(204) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(204) }) }) describe('with long name', function () { diff --git a/services/web/test/unit/src/Editor/EditorRealTimeController.test.mjs b/services/web/test/unit/src/Editor/EditorRealTimeController.test.mjs index 79bcd269a7..f6862eb3ac 100644 --- a/services/web/test/unit/src/Editor/EditorRealTimeController.test.mjs +++ b/services/web/test/unit/src/Editor/EditorRealTimeController.test.mjs @@ -1,5 +1,5 @@ import { vi } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' const modulePath = path.join( import.meta.dirname, diff --git a/services/web/test/unit/src/Email/EmailBuilder.test.mjs b/services/web/test/unit/src/Email/EmailBuilder.test.mjs index f47a4c0cee..d9970c4d4d 100644 --- a/services/web/test/unit/src/Email/EmailBuilder.test.mjs +++ b/services/web/test/unit/src/Email/EmailBuilder.test.mjs @@ -1,11 +1,11 @@ import { vi, expect } from 'vitest' import cheerio from 'cheerio' -import path from 'path' +import path from 'node:path' -import EmailMessageHelper from '../../../../app/src/Features/Email/EmailMessageHelper.js' -import ctaEmailBody from '../../../../app/src/Features/Email/Bodies/cta-email.js' -import NoCTAEmailBody from '../../../../app/src/Features/Email/Bodies/NoCTAEmailBody.js' -import BaseWithHeaderEmailLayout from '../../../../app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.js' +import EmailMessageHelper from '../../../../app/src/Features/Email/EmailMessageHelper.mjs' +import ctaEmailBody from '../../../../app/src/Features/Email/Bodies/cta-email.mjs' +import NoCTAEmailBody from '../../../../app/src/Features/Email/Bodies/NoCTAEmailBody.mjs' +import BaseWithHeaderEmailLayout from '../../../../app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs' const MODULE_PATH = path.join( import.meta.dirname, diff --git a/services/web/test/unit/src/Email/EmailHandler.test.mjs b/services/web/test/unit/src/Email/EmailHandler.test.mjs index c61f181e33..3d189efb3f 100644 --- a/services/web/test/unit/src/Email/EmailHandler.test.mjs +++ b/services/web/test/unit/src/Email/EmailHandler.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' const MODULE_PATH = path.join( diff --git a/services/web/test/unit/src/Email/EmailMessageHelper.test.mjs b/services/web/test/unit/src/Email/EmailMessageHelper.test.mjs new file mode 100644 index 0000000000..2b1a11f03a --- /dev/null +++ b/services/web/test/unit/src/Email/EmailMessageHelper.test.mjs @@ -0,0 +1,28 @@ +import path from 'node:path' +import { expect } from 'vitest' + +const MODULE_PATH = path.join( + import.meta.dirname, + '../../../../app/src/Features/Email/EmailMessageHelper' +) + +describe('EmailMessageHelper', function () { + beforeEach(async function (ctx) { + ctx.EmailMessageHelper = (await import(MODULE_PATH)).default + }) + describe('cleanHTML', function () { + beforeEach(function (ctx) { + ctx.text = 'a message' + ctx.span = `${ctx.text}` + ctx.fullMessage = `${ctx.span}
` + }) + it('should remove HTML for plainText version', function (ctx) { + const processed = ctx.EmailMessageHelper.cleanHTML(ctx.fullMessage, true) + expect(processed).to.equal(ctx.text) + }) + it('should keep HTML for HTML version but remove tags not allowed', function (ctx) { + const processed = ctx.EmailMessageHelper.cleanHTML(ctx.fullMessage, false) + expect(processed).to.equal(ctx.span) + }) + }) +}) diff --git a/services/web/test/unit/src/Email/EmailMessageHelperTests.js b/services/web/test/unit/src/Email/EmailMessageHelperTests.js deleted file mode 100644 index 563c51acf6..0000000000 --- a/services/web/test/unit/src/Email/EmailMessageHelperTests.js +++ /dev/null @@ -1,35 +0,0 @@ -const SandboxedModule = require('sandboxed-module') -const path = require('path') -const { expect } = require('chai') - -const MODULE_PATH = path.join( - __dirname, - '../../../../app/src/Features/Email/EmailMessageHelper' -) - -describe('EmailMessageHelper', function () { - beforeEach(function () { - this.EmailMessageHelper = SandboxedModule.require(MODULE_PATH, {}) - }) - describe('cleanHTML', function () { - beforeEach(function () { - this.text = 'a message' - this.span = `${this.text}` - this.fullMessage = `${this.span}
` - }) - it('should remove HTML for plainText version', function () { - const processed = this.EmailMessageHelper.cleanHTML( - this.fullMessage, - true - ) - expect(processed).to.equal(this.text) - }) - it('should keep HTML for HTML version but remove tags not allowed', function () { - const processed = this.EmailMessageHelper.cleanHTML( - this.fullMessage, - false - ) - expect(processed).to.equal(this.span) - }) - }) -}) diff --git a/services/web/test/unit/src/Email/EmailSender.test.mjs b/services/web/test/unit/src/Email/EmailSender.test.mjs index e8ab70163f..81cd742d9b 100644 --- a/services/web/test/unit/src/Email/EmailSender.test.mjs +++ b/services/web/test/unit/src/Email/EmailSender.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' const MODULE_PATH = path.join( diff --git a/services/web/test/unit/src/History/HistoryController.test.mjs b/services/web/test/unit/src/History/HistoryController.test.mjs index ce826d1c0a..4a06a1cf59 100644 --- a/services/web/test/unit/src/History/HistoryController.test.mjs +++ b/services/web/test/unit/src/History/HistoryController.test.mjs @@ -118,7 +118,7 @@ describe('HistoryController', function () { }) ) - vi.doMock('../../../../app/src/infrastructure/Features.js', () => ({ + vi.doMock('../../../../app/src/infrastructure/Features.mjs', () => ({ default: (ctx.Features = sinon.stub().withArgs('saas').returns(true)), })) diff --git a/services/web/test/unit/src/Institutions/InstitutionsAPI.test.mjs b/services/web/test/unit/src/Institutions/InstitutionsAPI.test.mjs index 34c56eba2a..f4b3921c92 100644 --- a/services/web/test/unit/src/Institutions/InstitutionsAPI.test.mjs +++ b/services/web/test/unit/src/Institutions/InstitutionsAPI.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' diff --git a/services/web/test/unit/src/Institutions/InstitutionsManager.test.mjs b/services/web/test/unit/src/Institutions/InstitutionsManager.test.mjs index 77a0dea3f1..ab877012f1 100644 --- a/services/web/test/unit/src/Institutions/InstitutionsManager.test.mjs +++ b/services/web/test/unit/src/Institutions/InstitutionsManager.test.mjs @@ -1,8 +1,8 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import Features from '../../../../app/src/infrastructure/Features.js' +import Features from '../../../../app/src/infrastructure/Features.mjs' const modulePath = path.join( import.meta.dirname, '../../../../app/src/Features/Institutions/InstitutionsManager' diff --git a/services/web/test/unit/src/Project/ProjectController.test.mjs b/services/web/test/unit/src/Project/ProjectController.test.mjs index 8d66b039e3..4382654ce9 100644 --- a/services/web/test/unit/src/Project/ProjectController.test.mjs +++ b/services/web/test/unit/src/Project/ProjectController.test.mjs @@ -1,6 +1,6 @@ import { beforeEach, describe, it, vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/Project/ProjectListController.test.mjs b/services/web/test/unit/src/Project/ProjectListController.test.mjs index 28307bd9e9..8c05193e90 100644 --- a/services/web/test/unit/src/Project/ProjectListController.test.mjs +++ b/services/web/test/unit/src/Project/ProjectListController.test.mjs @@ -2,6 +2,7 @@ import { beforeEach, describe, it, expect, vi } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' +import Settings from '@overleaf/settings' const ObjectId = mongodb.ObjectId @@ -64,6 +65,7 @@ describe('ProjectListController', function () { }, ] ctx.settings = { + ...Settings, siteUrl: 'https://overleaf.com', } ctx.onboardingDataCollection = { diff --git a/services/web/test/unit/src/Security/LoginRateLimiter.test.mjs b/services/web/test/unit/src/Security/LoginRateLimiter.test.mjs new file mode 100644 index 0000000000..69d052ca90 --- /dev/null +++ b/services/web/test/unit/src/Security/LoginRateLimiter.test.mjs @@ -0,0 +1,77 @@ +import { vi, expect } from 'vitest' +import sinon from 'sinon' +const modulePath = '../../../../app/src/Features/Security/LoginRateLimiter' + +describe('LoginRateLimiter', function () { + beforeEach(async function (ctx) { + ctx.email = 'bob@bob.com' + ctx.rateLimiter = { + consume: sinon.stub().resolves(), + delete: sinon.stub().resolves(), + } + ctx.RateLimiter = { + RateLimiter: sinon.stub().withArgs('login').returns(ctx.rateLimiter), + } + + vi.doMock( + '../../../../app/src/infrastructure/RateLimiter', + () => ctx.RateLimiter + ) + + ctx.LoginRateLimiter = (await import(modulePath)).default + }) + + describe('processLoginRequest', function () { + it('should consume points', async function (ctx) { + await ctx.LoginRateLimiter.promises.processLoginRequest(ctx.email) + expect(ctx.rateLimiter.consume).to.have.been.calledWith(ctx.email) + }) + + describe('when login is allowed', function () { + it('should call pass allow=true', async function (ctx) { + const allow = await ctx.LoginRateLimiter.promises.processLoginRequest( + ctx.email + ) + expect(allow).to.equal(true) + }) + }) + + describe('when login is blocked', function () { + beforeEach(function (ctx) { + ctx.rateLimiter.consume.rejects({ remainingPoints: 0 }) + }) + + it('should call pass allow=false', async function (ctx) { + const allow = await ctx.LoginRateLimiter.promises.processLoginRequest( + ctx.email + ) + expect(allow).to.equal(false) + }) + }) + + describe('when consume produces an error', function () { + beforeEach(function (ctx) { + ctx.rateLimiter.consume.rejects(new Error('woops')) + }) + + it('should produce an error', async function (ctx) { + let error + + try { + await ctx.LoginRateLimiter.promises.processLoginRequest(ctx.email) + } catch (err) { + error = err + } + + expect(error).to.exist + }) + }) + }) + + describe('recordSuccessfulLogin', function () { + it('should clear the rate limit', async function (ctx) { + await ctx.LoginRateLimiter.promises.recordSuccessfulLogin(ctx.email) + expect(ctx.rateLimiter.delete).to.have.been.calledWith(ctx.email) + }) + }) +}) diff --git a/services/web/test/unit/src/Security/LoginRateLimiterTests.js b/services/web/test/unit/src/Security/LoginRateLimiterTests.js deleted file mode 100644 index 6dadaad8c2..0000000000 --- a/services/web/test/unit/src/Security/LoginRateLimiterTests.js +++ /dev/null @@ -1,80 +0,0 @@ -const SandboxedModule = require('sandboxed-module') -const sinon = require('sinon') -const { expect } = require('chai') -const modulePath = require('path').join( - __dirname, - '../../../../app/src/Features/Security/LoginRateLimiter' -) - -describe('LoginRateLimiter', function () { - beforeEach(function () { - this.email = 'bob@bob.com' - this.rateLimiter = { - consume: sinon.stub().resolves(), - delete: sinon.stub().resolves(), - } - this.RateLimiter = { - RateLimiter: sinon.stub().withArgs('login').returns(this.rateLimiter), - } - - this.LoginRateLimiter = SandboxedModule.require(modulePath, { - requires: { - '../../infrastructure/RateLimiter': this.RateLimiter, - }, - }) - }) - - describe('processLoginRequest', function () { - it('should consume points', async function () { - await this.LoginRateLimiter.promises.processLoginRequest(this.email) - expect(this.rateLimiter.consume).to.have.been.calledWith(this.email) - }) - - describe('when login is allowed', function () { - it('should call pass allow=true', async function () { - const allow = await this.LoginRateLimiter.promises.processLoginRequest( - this.email - ) - expect(allow).to.equal(true) - }) - }) - - describe('when login is blocked', function () { - beforeEach(function () { - this.rateLimiter.consume.rejects({ remainingPoints: 0 }) - }) - - it('should call pass allow=false', async function () { - const allow = await this.LoginRateLimiter.promises.processLoginRequest( - this.email - ) - expect(allow).to.equal(false) - }) - }) - - describe('when consume produces an error', function () { - beforeEach(function () { - this.rateLimiter.consume.rejects(new Error('woops')) - }) - - it('should produce an error', async function () { - let error - - try { - await this.LoginRateLimiter.promises.processLoginRequest(this.email) - } catch (err) { - error = err - } - - expect(error).to.exist - }) - }) - }) - - describe('recordSuccessfulLogin', function () { - it('should clear the rate limit', async function () { - await this.LoginRateLimiter.promises.recordSuccessfulLogin(this.email) - expect(this.rateLimiter.delete).to.have.been.calledWith(this.email) - }) - }) -}) diff --git a/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs b/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs index f3103679a2..a4c9dc61df 100644 --- a/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs +++ b/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs @@ -1,5 +1,5 @@ import { vi, assert, expect } from 'vitest' -import Path from 'path' +import Path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import MockRequest from '../helpers/MockRequest.js' diff --git a/services/web/test/unit/src/SplitTests/SplitTestSessionHandler.test.mjs b/services/web/test/unit/src/SplitTests/SplitTestSessionHandler.test.mjs index 33793ec1f6..a29bf22b22 100644 --- a/services/web/test/unit/src/SplitTests/SplitTestSessionHandler.test.mjs +++ b/services/web/test/unit/src/SplitTests/SplitTestSessionHandler.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import Path from 'path' +import Path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' diff --git a/services/web/test/unit/src/Subscription/FeaturesUpdater.test.mjs b/services/web/test/unit/src/Subscription/FeaturesUpdater.test.mjs index d34419f1bf..515b44ef70 100644 --- a/services/web/test/unit/src/Subscription/FeaturesUpdater.test.mjs +++ b/services/web/test/unit/src/Subscription/FeaturesUpdater.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.js' +import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.mjs' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/Subscription/PaymentProviderEntities.test.mjs b/services/web/test/unit/src/Subscription/PaymentProviderEntities.test.mjs index 8b60574599..404426e764 100644 --- a/services/web/test/unit/src/Subscription/PaymentProviderEntities.test.mjs +++ b/services/web/test/unit/src/Subscription/PaymentProviderEntities.test.mjs @@ -1,9 +1,9 @@ import { vi, expect } from 'vitest' -import Errors from '../../../../app/src/Features/Subscription/Errors.js' +import Errors from '../../../../app/src/Features/Subscription/Errors.mjs' import PaymentProviderEntities from '../../../../app/src/Features/Subscription/PaymentProviderEntities.mjs' -import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.js' +import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.mjs' import SubscriptionHelper from '../../../../app/src/Features/Subscription/SubscriptionHelper.mjs' const { diff --git a/services/web/test/unit/src/Subscription/RecurlyWrapper.test.mjs b/services/web/test/unit/src/Subscription/RecurlyWrapper.test.mjs index 32f86ad9ad..6c91a361de 100644 --- a/services/web/test/unit/src/Subscription/RecurlyWrapper.test.mjs +++ b/services/web/test/unit/src/Subscription/RecurlyWrapper.test.mjs @@ -2,7 +2,7 @@ import { vi, assert, expect } from 'vitest' import sinon from 'sinon' import tk from 'timekeeper' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import SubscriptionErrors from '../../../../app/src/Features/Subscription/Errors.js' +import SubscriptionErrors from '../../../../app/src/Features/Subscription/Errors.mjs' import { RequestFailedError } from '@overleaf/fetch-utils' const modulePath = '../../../../app/src/Features/Subscription/RecurlyWrapper' diff --git a/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs b/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs index 1d4e6ec607..98bc3d84fe 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs +++ b/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs @@ -2,9 +2,9 @@ import { vi, assert, expect } from 'vitest' import sinon from 'sinon' import MockRequest from '../helpers/MockRequest.js' import MockResponse from '../helpers/MockResponse.js' -import SubscriptionErrors from '../../../../app/src/Features/Subscription/Errors.js' +import SubscriptionErrors from '../../../../app/src/Features/Subscription/Errors.mjs' import SubscriptionHelper from '../../../../app/src/Features/Subscription/SubscriptionHelper.mjs' -import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.js' +import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.mjs' const modulePath = '../../../../app/src/Features/Subscription/SubscriptionController.mjs' diff --git a/services/web/test/unit/src/Subscription/V1SusbcriptionManager.test.mjs b/services/web/test/unit/src/Subscription/V1SusbcriptionManager.test.mjs index 7c2e1f821c..c0aeace3b5 100644 --- a/services/web/test/unit/src/Subscription/V1SusbcriptionManager.test.mjs +++ b/services/web/test/unit/src/Subscription/V1SusbcriptionManager.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' const modulePath = path.join( import.meta.dirname, diff --git a/services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSender.test.mjs b/services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSender.test.mjs index 5537a4dc24..3ad0e6a176 100644 --- a/services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSender.test.mjs +++ b/services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSender.test.mjs @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import mongodb from 'mongodb-legacy' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/ThirdPartyDataStore/UpdateMerger.test.mjs b/services/web/test/unit/src/ThirdPartyDataStore/UpdateMerger.test.mjs index d4290dce5d..58bc5f974d 100644 --- a/services/web/test/unit/src/ThirdPartyDataStore/UpdateMerger.test.mjs +++ b/services/web/test/unit/src/ThirdPartyDataStore/UpdateMerger.test.mjs @@ -1,6 +1,6 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import { Writable } from 'stream' +import { Writable } from 'node:stream' import mongodb from 'mongodb-legacy' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs b/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs index 117a6b0b14..9fd93ac294 100644 --- a/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs +++ b/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs @@ -3,7 +3,7 @@ import sinon from 'sinon' import mongodb from 'mongodb-legacy' import MockRequest from '../helpers/MockRequest.js' import MockResponse from '../helpers/MockResponse.js' -import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.mjs' import UrlHelper from '../../../../app/src/Features/Helpers/UrlHelper.mjs' const { getSafeRedirectPath } = UrlHelper diff --git a/services/web/test/unit/src/TokenAccess/TokenAccessHandler.test.mjs b/services/web/test/unit/src/TokenAccess/TokenAccessHandler.test.mjs index ffb8127725..0519bcb4bf 100644 --- a/services/web/test/unit/src/TokenAccess/TokenAccessHandler.test.mjs +++ b/services/web/test/unit/src/TokenAccess/TokenAccessHandler.test.mjs @@ -1,8 +1,8 @@ import { vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.js' +import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.mjs' const modulePath = path.join( import.meta.dirname, diff --git a/services/web/test/unit/src/Uploads/ArchiveManager.test.mjs b/services/web/test/unit/src/Uploads/ArchiveManager.test.mjs index b3aa7abc5d..4ab5e14b4f 100644 --- a/services/web/test/unit/src/Uploads/ArchiveManager.test.mjs +++ b/services/web/test/unit/src/Uploads/ArchiveManager.test.mjs @@ -8,8 +8,8 @@ import { vi, expect } from 'vitest' * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import sinon from 'sinon' -import ArchiveErrors from '../../../../app/src/Features/Uploads/ArchiveErrors.js' -import events from 'events' +import ArchiveErrors from '../../../../app/src/Features/Uploads/ArchiveErrors.mjs' +import events from 'node:events' vi.mock('../../../../app/src/Features/Uploads/ArchiveErrors.js', () => vi.importActual('../../../../app/src/Features/Uploads/ArchiveErrors.js') diff --git a/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs b/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs index b36d596da2..a5b5ed410e 100644 --- a/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs +++ b/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs @@ -9,7 +9,7 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' import MockRequest from '../helpers/MockRequest.js' import MockResponse from '../helpers/MockResponse.js' -import ArchiveErrors from '../../../../app/src/Features/Uploads/ArchiveErrors.js' +import ArchiveErrors from '../../../../app/src/Features/Uploads/ArchiveErrors.mjs' const modulePath = '../../../../app/src/Features/Uploads/ProjectUploadController.mjs' diff --git a/services/web/test/unit/src/User/UserGetter.test.mjs b/services/web/test/unit/src/User/UserGetter.test.mjs index 71c711f320..8299dac405 100644 --- a/services/web/test/unit/src/User/UserGetter.test.mjs +++ b/services/web/test/unit/src/User/UserGetter.test.mjs @@ -1,18 +1,16 @@ import { vi, expect } from 'vitest' import mongodb from 'mongodb-legacy' -import assert from 'assert' +import assert from 'node:assert' import moment from 'moment' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import { - normalizeQuery, - normalizeMultiQuery, -} from '../../../../app/src/Features/Helpers/Mongo.js' +import MongoHelpers from '../../../../app/src/Features/Helpers/Mongo.mjs' const modulePath = path.join( import.meta.dirname, '../../../../app/src/Features/User/UserGetter' ) +const { normalizeQuery, normalizeMultiQuery } = MongoHelpers vi.mock('../../../../app/src/Features/Errors/Errors.js', () => vi.importActual('../../../../app/src/Features/Errors/Errors.js') @@ -60,8 +58,7 @@ describe('UserGetter', function () { } vi.doMock('../../../../app/src/Features/Helpers/Mongo', () => ({ - normalizeQuery, - normalizeMultiQuery, + default: { normalizeQuery, normalizeMultiQuery }, })) vi.doMock('../../../../app/src/infrastructure/mongodb', () => ctx.Mongo) diff --git a/services/web/test/unit/src/User/UserPagesController.test.mjs b/services/web/test/unit/src/User/UserPagesController.test.mjs index 0a05cbfb3c..5a5d301e55 100644 --- a/services/web/test/unit/src/User/UserPagesController.test.mjs +++ b/services/web/test/unit/src/User/UserPagesController.test.mjs @@ -1,5 +1,5 @@ import { expect, vi } from 'vitest' -import assert from 'assert' +import assert from 'node:assert' import sinon from 'sinon' import MockResponse from '../helpers/MockResponse.js' import MockRequest from '../helpers/MockRequest.js' diff --git a/services/web/test/unit/src/User/UserRegistrationHandler.test.mjs b/services/web/test/unit/src/User/UserRegistrationHandler.test.mjs index ce1f478fbf..733e12a121 100644 --- a/services/web/test/unit/src/User/UserRegistrationHandler.test.mjs +++ b/services/web/test/unit/src/User/UserRegistrationHandler.test.mjs @@ -1,5 +1,5 @@ import { vi, expect } from 'vitest' -import assert from 'assert' +import assert from 'node:assert' import sinon from 'sinon' import EmailHelper from '../../../../app/src/Features/Helpers/EmailHelper.mjs' diff --git a/services/web/test/unit/src/User/UserUpdater.test.mjs b/services/web/test/unit/src/User/UserUpdater.test.mjs index fd0b68779e..be53b84435 100644 --- a/services/web/test/unit/src/User/UserUpdater.test.mjs +++ b/services/web/test/unit/src/User/UserUpdater.test.mjs @@ -1,12 +1,13 @@ import { vi, expect } from 'vitest' -import { setTimeout } from 'timers/promises' -import path from 'path' +import { setTimeout } from 'node:timers/promises' +import path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import tk from 'timekeeper' -import { normalizeQuery } from '../../../../app/src/Features/Helpers/Mongo.js' +import MongoHelpers from '../../../../app/src/Features/Helpers/Mongo.mjs' import Errors from '../../../../app/src/Features/Errors/Errors.js' +const { normalizeQuery } = MongoHelpers const { ObjectId } = mongodb const MODULE_PATH = path.join( @@ -126,7 +127,7 @@ describe('UserUpdater', function () { } vi.doMock('../../../../app/src/Features/Helpers/Mongo', () => ({ - normalizeQuery, + default: { normalizeQuery }, })) vi.doMock('../../../../app/src/infrastructure/mongodb', () => ctx.mongodb) diff --git a/services/web/test/unit/src/UserMembership/UserMembershipViewModel.test.mjs b/services/web/test/unit/src/UserMembership/UserMembershipViewModel.test.mjs index 590008d454..04b160f522 100644 --- a/services/web/test/unit/src/UserMembership/UserMembershipViewModel.test.mjs +++ b/services/web/test/unit/src/UserMembership/UserMembershipViewModel.test.mjs @@ -1,14 +1,12 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import { - isObjectIdInstance, - normalizeQuery, -} from '../../../../app/src/Features/Helpers/Mongo.js' +import MongoHelpers from '../../../../app/src/Features/Helpers/Mongo.mjs' const assertCalledWith = sinon.assert.calledWith const assertNotCalled = sinon.assert.notCalled +const { isObjectIdInstance, normalizeQuery } = MongoHelpers const { ObjectId } = mongodb const modulePath = @@ -23,8 +21,7 @@ describe('UserMembershipViewModel', function () { })) vi.doMock('../../../../app/src/Features/Helpers/Mongo', () => ({ - isObjectIdInstance, - normalizeQuery, + default: { isObjectIdInstance, normalizeQuery }, })) vi.doMock('../../../../app/src/Features/User/UserGetter', () => ({ diff --git a/services/web/test/unit/src/helpers/MockResponseVitest.mjs b/services/web/test/unit/src/helpers/MockResponseVitest.mjs index cc82ced870..a2401ef465 100644 --- a/services/web/test/unit/src/helpers/MockResponseVitest.mjs +++ b/services/web/test/unit/src/helpers/MockResponseVitest.mjs @@ -1,4 +1,4 @@ -import Path from 'path' +import Path from 'node:path' import contentDisposition from 'content-disposition' class MockResponse { diff --git a/services/web/test/unit/src/infrastructure/Features.test.mjs b/services/web/test/unit/src/infrastructure/Features.test.mjs new file mode 100644 index 0000000000..0e01b23433 --- /dev/null +++ b/services/web/test/unit/src/infrastructure/Features.test.mjs @@ -0,0 +1,151 @@ +import { vi, expect } from 'vitest' +const modulePath = '../../../../app/src/infrastructure/Features.mjs' + +describe('Features', function () { + beforeEach(async function (ctx) { + vi.doMock('@overleaf/settings', () => ({ + default: (ctx.settings = { + moduleImportSequence: [], + enabledLinkedFileTypes: [], + }), + })) + + ctx.Features = (await import(modulePath)).default + }) + describe('externalAuthenticationSystemUsed', function () { + describe('without any settings', function () { + it('should return false', function (ctx) { + expect(ctx.Features.externalAuthenticationSystemUsed()).to.be.false + }) + }) + describe('with ldap setting', function () { + beforeEach(function (ctx) { + ctx.settings.ldap = { enable: true } + }) + it('should return true', function (ctx) { + expect(ctx.Features.externalAuthenticationSystemUsed()).to.be.true + }) + }) + describe('with saml setting', function () { + beforeEach(function (ctx) { + ctx.settings.saml = { enable: true } + }) + it('should return true', function (ctx) { + expect(ctx.Features.externalAuthenticationSystemUsed()).to.be.true + }) + }) + describe('with oauth setting', function () { + beforeEach(function (ctx) { + ctx.settings.overleaf = { oauth: true } + }) + it('should return true', function (ctx) { + expect(ctx.Features.externalAuthenticationSystemUsed()).to.be.true + }) + }) + }) + + describe('hasFeature', function () { + describe('without any settings', function () { + it('should return true', function (ctx) { + expect(ctx.Features.hasFeature('registration-page')).to.be.true + }) + it('should return false', function (ctx) { + expect(ctx.Features.hasFeature('registration')).to.be.false + expect(ctx.Features.hasFeature('affiliations')).to.be.false + expect(ctx.Features.hasFeature('analytics')).to.be.false + expect(ctx.Features.hasFeature('git-bridge')).to.be.false + expect(ctx.Features.hasFeature('github-sync')).to.be.false + expect(ctx.Features.hasFeature('homepage')).to.be.false + expect(ctx.Features.hasFeature('link-url')).to.be.false + expect(ctx.Features.hasFeature('oauth')).to.be.false + expect(ctx.Features.hasFeature('saas')).to.be.false + expect(ctx.Features.hasFeature('references')).to.be.false + expect(ctx.Features.hasFeature('saml')).to.be.false + expect(ctx.Features.hasFeature('templates-server-pro')).to.be.false + }) + }) + describe('with settings', function () { + describe('empty overleaf object', function () { + beforeEach(function (ctx) { + ctx.settings.overleaf = {} + ctx.settings.apis = {} + }) + it('should return true', function (ctx) { + expect(ctx.Features.hasFeature('saas')).to.be.true + expect(ctx.Features.hasFeature('registration')).to.be.true + }) + it('should return false', function (ctx) { + expect(ctx.Features.hasFeature('affiliations')).to.be.false + expect(ctx.Features.hasFeature('analytics')).to.be.false + expect(ctx.Features.hasFeature('git-bridge')).to.be.false + expect(ctx.Features.hasFeature('github-sync')).to.be.false + expect(ctx.Features.hasFeature('homepage')).to.be.false + expect(ctx.Features.hasFeature('link-url')).to.be.false + expect(ctx.Features.hasFeature('oauth')).to.be.false + expect(ctx.Features.hasFeature('references')).to.be.false + expect(ctx.Features.hasFeature('saml')).to.be.false + expect(ctx.Features.hasFeature('templates-server-pro')).to.be.false + }) + describe('with APIs', function () { + beforeEach(function (ctx) { + ctx.settings.apis = { + linkedUrlProxy: { + url: 'https://www.overleaf.com', + }, + references: { + url: 'https://www.overleaf.com', + }, + v1: { + url: 'https://www.overleaf.com', + }, + } + }) + it('should return true', function (ctx) { + expect(ctx.Features.hasFeature('affiliations')).to.be.true + expect(ctx.Features.hasFeature('analytics')).to.be.true + expect(ctx.Features.hasFeature('saas')).to.be.true + expect(ctx.Features.hasFeature('references')).to.be.true + expect(ctx.Features.hasFeature('registration')).to.be.true + }) + it('should return false', function (ctx) { + expect(ctx.Features.hasFeature('link-url')).to.be.false + expect(ctx.Features.hasFeature('git-bridge')).to.be.false + expect(ctx.Features.hasFeature('github-sync')).to.be.false + expect(ctx.Features.hasFeature('homepage')).to.be.false + expect(ctx.Features.hasFeature('oauth')).to.be.false + expect(ctx.Features.hasFeature('saml')).to.be.false + expect(ctx.Features.hasFeature('templates-server-pro')).to.be.false + }) + describe('with all other settings flags', function () { + beforeEach(function (ctx) { + ctx.settings.enableHomepage = true + ctx.settings.enableGitBridge = true + ctx.settings.enableGithubSync = true + ctx.settings.enableSaml = true + ctx.settings.oauth = true + ctx.settings.enabledLinkedFileTypes = ['url', 'project_file'] + }) + it('should return true or return value', function (ctx) { + expect(ctx.Features.hasFeature('link-url')).to.be.true + expect(ctx.Features.hasFeature('affiliations')).to.be.true + expect(ctx.Features.hasFeature('analytics')).to.be.true + expect(ctx.Features.hasFeature('github-sync')).to.be.true + expect(ctx.Features.hasFeature('git-bridge')).to.be.true + expect(ctx.Features.hasFeature('homepage')).to.be.true + expect(ctx.Features.hasFeature('link-url')).to.be.true + expect(ctx.Features.hasFeature('oauth')).to.be.true + expect(ctx.Features.hasFeature('saas')).to.be.true + expect(ctx.Features.hasFeature('references')).to.be.true + expect(ctx.Features.hasFeature('registration')).to.be.true + expect(ctx.Features.hasFeature('saml')).to.be.true + }) + it('should return false', function (ctx) { + expect(ctx.Features.hasFeature('templates-server-pro')).to.be + .false + }) + }) + }) + }) + }) + }) +}) diff --git a/services/web/test/unit/src/infrastructure/FeaturesTests.js b/services/web/test/unit/src/infrastructure/FeaturesTests.js deleted file mode 100644 index dcdf1e4e62..0000000000 --- a/services/web/test/unit/src/infrastructure/FeaturesTests.js +++ /dev/null @@ -1,152 +0,0 @@ -const { expect } = require('chai') -const modulePath = '../../../../app/src/infrastructure/Features.js' -const SandboxedModule = require('sandboxed-module') - -describe('Features', function () { - beforeEach(function () { - this.Features = SandboxedModule.require(modulePath, { - requires: { - '@overleaf/settings': (this.settings = { - moduleImportSequence: [], - enabledLinkedFileTypes: [], - }), - }, - }) - }) - describe('externalAuthenticationSystemUsed', function () { - describe('without any settings', function () { - it('should return false', function () { - expect(this.Features.externalAuthenticationSystemUsed()).to.be.false - }) - }) - describe('with ldap setting', function () { - beforeEach(function () { - this.settings.ldap = { enable: true } - }) - it('should return true', function () { - expect(this.Features.externalAuthenticationSystemUsed()).to.be.true - }) - }) - describe('with saml setting', function () { - beforeEach(function () { - this.settings.saml = { enable: true } - }) - it('should return true', function () { - expect(this.Features.externalAuthenticationSystemUsed()).to.be.true - }) - }) - describe('with oauth setting', function () { - beforeEach(function () { - this.settings.overleaf = { oauth: true } - }) - it('should return true', function () { - expect(this.Features.externalAuthenticationSystemUsed()).to.be.true - }) - }) - }) - - describe('hasFeature', function () { - describe('without any settings', function () { - it('should return true', function () { - expect(this.Features.hasFeature('registration-page')).to.be.true - }) - it('should return false', function () { - expect(this.Features.hasFeature('registration')).to.be.false - expect(this.Features.hasFeature('affiliations')).to.be.false - expect(this.Features.hasFeature('analytics')).to.be.false - expect(this.Features.hasFeature('git-bridge')).to.be.false - expect(this.Features.hasFeature('github-sync')).to.be.false - expect(this.Features.hasFeature('homepage')).to.be.false - expect(this.Features.hasFeature('link-url')).to.be.false - expect(this.Features.hasFeature('oauth')).to.be.false - expect(this.Features.hasFeature('saas')).to.be.false - expect(this.Features.hasFeature('references')).to.be.false - expect(this.Features.hasFeature('saml')).to.be.false - expect(this.Features.hasFeature('templates-server-pro')).to.be.false - }) - }) - describe('with settings', function () { - describe('empty overleaf object', function () { - beforeEach(function () { - this.settings.overleaf = {} - this.settings.apis = {} - }) - it('should return true', function () { - expect(this.Features.hasFeature('saas')).to.be.true - expect(this.Features.hasFeature('registration')).to.be.true - }) - it('should return false', function () { - expect(this.Features.hasFeature('affiliations')).to.be.false - expect(this.Features.hasFeature('analytics')).to.be.false - expect(this.Features.hasFeature('git-bridge')).to.be.false - expect(this.Features.hasFeature('github-sync')).to.be.false - expect(this.Features.hasFeature('homepage')).to.be.false - expect(this.Features.hasFeature('link-url')).to.be.false - expect(this.Features.hasFeature('oauth')).to.be.false - expect(this.Features.hasFeature('references')).to.be.false - expect(this.Features.hasFeature('saml')).to.be.false - expect(this.Features.hasFeature('templates-server-pro')).to.be.false - }) - describe('with APIs', function () { - beforeEach(function () { - this.settings.apis = { - linkedUrlProxy: { - url: 'https://www.overleaf.com', - }, - references: { - url: 'https://www.overleaf.com', - }, - v1: { - url: 'https://www.overleaf.com', - }, - } - }) - it('should return true', function () { - expect(this.Features.hasFeature('affiliations')).to.be.true - expect(this.Features.hasFeature('analytics')).to.be.true - expect(this.Features.hasFeature('saas')).to.be.true - expect(this.Features.hasFeature('references')).to.be.true - expect(this.Features.hasFeature('registration')).to.be.true - }) - it('should return false', function () { - expect(this.Features.hasFeature('link-url')).to.be.false - expect(this.Features.hasFeature('git-bridge')).to.be.false - expect(this.Features.hasFeature('github-sync')).to.be.false - expect(this.Features.hasFeature('homepage')).to.be.false - expect(this.Features.hasFeature('oauth')).to.be.false - expect(this.Features.hasFeature('saml')).to.be.false - expect(this.Features.hasFeature('templates-server-pro')).to.be.false - }) - describe('with all other settings flags', function () { - beforeEach(function () { - this.settings.enableHomepage = true - this.settings.enableGitBridge = true - this.settings.enableGithubSync = true - this.settings.enableSaml = true - this.settings.oauth = true - this.settings.enabledLinkedFileTypes = ['url', 'project_file'] - }) - it('should return true or return value', function () { - expect(this.Features.hasFeature('link-url')).to.be.true - expect(this.Features.hasFeature('affiliations')).to.be.true - expect(this.Features.hasFeature('analytics')).to.be.true - expect(this.Features.hasFeature('github-sync')).to.be.true - expect(this.Features.hasFeature('git-bridge')).to.be.true - expect(this.Features.hasFeature('homepage')).to.be.true - expect(this.Features.hasFeature('link-url')).to.be.true - expect(this.Features.hasFeature('oauth')).to.be.true - expect(this.Features.hasFeature('saas')).to.be.true - expect(this.Features.hasFeature('references')).to.be.true - expect(this.Features.hasFeature('registration')).to.be.true - expect(this.Features.hasFeature('saml')).to.be.true - }) - it('should return false', function () { - expect(this.Features.hasFeature('templates-server-pro')).to.be - .false - }) - }) - }) - }) - }) - }) -}) diff --git a/services/web/test/unit/src/infrastructure/GeoIpLookup.test.mjs b/services/web/test/unit/src/infrastructure/GeoIpLookup.test.mjs index 794e5c706c..858025be2d 100644 --- a/services/web/test/unit/src/infrastructure/GeoIpLookup.test.mjs +++ b/services/web/test/unit/src/infrastructure/GeoIpLookup.test.mjs @@ -1,5 +1,5 @@ import { assert, describe, beforeEach, it, vi, expect } from 'vitest' -import path from 'path' +import path from 'node:path' import sinon from 'sinon' const modulePath = path.join(