mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-25 10:10:08 +02:00
Merge pull request #28584 from overleaf/ac-some-web-esm-migration-5
[web] Convert some Features files to ES modules (part 5) GitOrigin-RevId: 0cad67f9afe0095e2b066bf2f4d3717c00540dab
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
const logger = require('@overleaf/logger')
|
||||
const OError = require('@overleaf/o-error')
|
||||
const AnalyticsRegistrationSourceHelper = require('./AnalyticsRegistrationSourceHelper')
|
||||
const SessionManager = require('../../Features/Authentication/SessionManager')
|
||||
import logger from '@overleaf/logger'
|
||||
import OError from '@overleaf/o-error'
|
||||
import AnalyticsRegistrationSourceHelper from './AnalyticsRegistrationSourceHelper.js'
|
||||
import SessionManager from '../../Features/Authentication/SessionManager.js'
|
||||
|
||||
function setSource(medium, source) {
|
||||
return function (req, res, next) {
|
||||
@@ -51,7 +51,7 @@ function setInbound() {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
setSource,
|
||||
clearSource,
|
||||
setInbound,
|
||||
@@ -2,7 +2,7 @@ import AuthenticationController from './../Authentication/AuthenticationControll
|
||||
import AnalyticsController from './AnalyticsController.mjs'
|
||||
import AnalyticsProxy from './AnalyticsProxy.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
|
||||
const rateLimiters = {
|
||||
recordEvent: new RateLimiter('analytics-record-event', {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-check
|
||||
import { ForbiddenError, UserNotFoundError } from '../Errors/Errors.js'
|
||||
import PermissionsManager from './PermissionsManager.js'
|
||||
import PermissionsManager from './PermissionsManager.mjs'
|
||||
import Modules from '../../infrastructure/Modules.js'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
import Features from '../../infrastructure/Features.js'
|
||||
@@ -9,7 +9,7 @@ import Features from '../../infrastructure/Features.js'
|
||||
* @typedef {(import('express').Request)} Request
|
||||
* @typedef {(import('express').Response)} Response
|
||||
* @typedef {(import('express').NextFunction)} NextFunction
|
||||
* @typedef {import('./PermissionsManager').Capability} Capability
|
||||
* @typedef {import('./PermissionsManager.mjs').Capability} Capability
|
||||
*/
|
||||
|
||||
const {
|
||||
|
||||
@@ -41,9 +41,12 @@
|
||||
* }
|
||||
*/
|
||||
|
||||
const { callbackify } = require('util')
|
||||
const { ForbiddenError } = require('../Errors/Errors')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
import { callbackify } from 'node:util'
|
||||
|
||||
import Errors from '../Errors/Errors.js'
|
||||
import Modules from '../../infrastructure/Modules.js'
|
||||
|
||||
const { ForbiddenError } = Errors
|
||||
|
||||
/**
|
||||
* @typedef {(import('../../../../types/capabilities').Capability)} Capability
|
||||
@@ -466,7 +469,7 @@ async function checkUserListPermissions(userList, capabilities) {
|
||||
return true
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
validatePolicies,
|
||||
registerCapability,
|
||||
registerPolicy,
|
||||
@@ -3,9 +3,9 @@ import AuthenticationController from '../Authentication/AuthenticationController
|
||||
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
|
||||
import CollaboratorsInviteController from './CollaboratorsInviteController.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
import CaptchaMiddleware from '../Captcha/CaptchaMiddleware.mjs'
|
||||
import AnalyticsRegistrationSourceMiddleware from '../Analytics/AnalyticsRegistrationSourceMiddleware.js'
|
||||
import AnalyticsRegistrationSourceMiddleware from '../Analytics/AnalyticsRegistrationSourceMiddleware.mjs'
|
||||
|
||||
const rateLimiters = {
|
||||
inviteToProjectByProjectId: new RateLimiter(
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
const { callbackify } = require('util')
|
||||
const { callbackifyMultiResult } = require('@overleaf/promise-utils')
|
||||
const {
|
||||
import { callbackify } from 'node:util'
|
||||
import { callbackifyMultiResult } from '@overleaf/promise-utils'
|
||||
import {
|
||||
fetchString,
|
||||
fetchStringWithResponse,
|
||||
fetchStream,
|
||||
RequestFailedError,
|
||||
} = require('@overleaf/fetch-utils')
|
||||
const Settings = require('@overleaf/settings')
|
||||
const ProjectGetter = require('../Project/ProjectGetter')
|
||||
const ProjectEntityHandler = require('../Project/ProjectEntityHandler')
|
||||
const logger = require('@overleaf/logger')
|
||||
const OError = require('@overleaf/o-error')
|
||||
const { Cookie } = require('tough-cookie')
|
||||
const ClsiCookieManager = require('./ClsiCookieManager')(
|
||||
} from '@overleaf/fetch-utils'
|
||||
import Settings from '@overleaf/settings'
|
||||
import ProjectGetter from '../Project/ProjectGetter.js'
|
||||
import ProjectEntityHandler from '../Project/ProjectEntityHandler.js'
|
||||
import logger from '@overleaf/logger'
|
||||
import OError from '@overleaf/o-error'
|
||||
import { Cookie } from 'tough-cookie'
|
||||
import ClsiCookieManagerFactory from './ClsiCookieManager.js'
|
||||
import ClsiStateManager from './ClsiStateManager.js'
|
||||
import _ from 'lodash'
|
||||
import ClsiFormatChecker from './ClsiFormatChecker.js'
|
||||
import DocumentUpdaterHandler from '../DocumentUpdater/DocumentUpdaterHandler.js'
|
||||
import Metrics from '@overleaf/metrics'
|
||||
import Errors from '../Errors/Errors.js'
|
||||
import ClsiCacheHandler from './ClsiCacheHandler.js'
|
||||
import HistoryManager from '../History/HistoryManager.js'
|
||||
import SplitTestHandler from '../SplitTests/SplitTestHandler.js'
|
||||
import AnalyticsManager from '../Analytics/AnalyticsManager.js'
|
||||
|
||||
const ClsiCookieManager = ClsiCookieManagerFactory(
|
||||
Settings.apis.clsi?.backendGroupName
|
||||
)
|
||||
const NewBackendCloudClsiCookieManager = require('./ClsiCookieManager')(
|
||||
const NewBackendCloudClsiCookieManager = ClsiCookieManagerFactory(
|
||||
Settings.apis.clsi_new?.backendGroupName
|
||||
)
|
||||
const ClsiStateManager = require('./ClsiStateManager')
|
||||
const _ = require('lodash')
|
||||
const ClsiFormatChecker = require('./ClsiFormatChecker')
|
||||
const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
|
||||
const Metrics = require('@overleaf/metrics')
|
||||
const Errors = require('../Errors/Errors')
|
||||
const ClsiCacheHandler = require('./ClsiCacheHandler')
|
||||
const { getFilestoreBlobURL } = require('../History/HistoryManager')
|
||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||
const AnalyticsManager = require('../Analytics/AnalyticsManager')
|
||||
|
||||
const VALID_COMPILERS = ['pdflatex', 'latex', 'xelatex', 'lualatex']
|
||||
const OUTPUT_FILE_TIMEOUT_MS = 60000
|
||||
@@ -843,7 +845,7 @@ function _finaliseRequest(projectId, options, project, docs, files) {
|
||||
path = path.replace(/^\//, '') // Remove leading /
|
||||
resources.push({
|
||||
path,
|
||||
url: getFilestoreBlobURL(historyId, file.hash),
|
||||
url: HistoryManager.getFilestoreBlobURL(historyId, file.hash),
|
||||
modified: file.created?.getTime(),
|
||||
})
|
||||
}
|
||||
@@ -975,7 +977,7 @@ function _getClsiServerIdFromResponse(response) {
|
||||
return null
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
sendRequest: callbackifyMultiResult(sendRequest, [
|
||||
'status',
|
||||
'outputFiles',
|
||||
@@ -5,7 +5,7 @@ import OError from '@overleaf/o-error'
|
||||
import Metrics from '@overleaf/metrics'
|
||||
import ProjectGetter from '../Project/ProjectGetter.js'
|
||||
import CompileManager from './CompileManager.mjs'
|
||||
import ClsiManager from './ClsiManager.js'
|
||||
import ClsiManager from './ClsiManager.mjs'
|
||||
import logger from '@overleaf/logger'
|
||||
import Settings from '@overleaf/settings'
|
||||
import Errors from '../Errors/Errors.js'
|
||||
|
||||
@@ -4,7 +4,7 @@ import RedisWrapper from '../../infrastructure/RedisWrapper.js'
|
||||
import ProjectGetter from '../Project/ProjectGetter.js'
|
||||
import ProjectRootDocManager from '../Project/ProjectRootDocManager.js'
|
||||
import UserGetter from '../User/UserGetter.js'
|
||||
import ClsiManager from './ClsiManager.js'
|
||||
import ClsiManager from './ClsiManager.mjs'
|
||||
import Metrics from '@overleaf/metrics'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import UserAnalyticsIdCache from '../Analytics/UserAnalyticsIdCache.js'
|
||||
|
||||
@@ -2,7 +2,7 @@ import EditorHttpController from './EditorHttpController.mjs'
|
||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
|
||||
const rateLimiters = {
|
||||
addDocToProject: new RateLimiter('add-doc-to-project', {
|
||||
|
||||
@@ -4,7 +4,7 @@ import Settings from '@overleaf/settings'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
import HistoryController from './HistoryController.mjs'
|
||||
|
||||
const rateLimiters = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
|
||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
import LinkedFilesController from './LinkedFilesController.mjs'
|
||||
|
||||
const rateLimiters = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import AuthorizationManager from '../Authorization/AuthorizationManager.js'
|
||||
import CompileManager from '../Compile/CompileManager.mjs'
|
||||
import ClsiManager from '../Compile/ClsiManager.js'
|
||||
import ClsiManager from '../Compile/ClsiManager.mjs'
|
||||
import ProjectFileAgent from './ProjectFileAgent.mjs'
|
||||
import _ from 'lodash'
|
||||
import LinkedFilesErrors from './LinkedFilesErrors.mjs'
|
||||
|
||||
@@ -5,7 +5,7 @@ import OneTimeTokenHandler from '../Security/OneTimeTokenHandler.js'
|
||||
import EmailHandler from '../Email/EmailHandler.js'
|
||||
import AuthenticationManager from '../Authentication/AuthenticationManager.js'
|
||||
import { callbackify, promisify } from 'node:util'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.mjs'
|
||||
|
||||
const assertUserPermissions = PermissionsManager.promises.assertUserPermissions
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import PasswordResetController from './PasswordResetController.mjs'
|
||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||
import CaptchaMiddleware from '../../Features/Captcha/CaptchaMiddleware.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
|
||||
const rateLimiter = new RateLimiter('password_reset_rate_limit', {
|
||||
points: 6,
|
||||
|
||||
@@ -14,7 +14,7 @@ import TagsHandler from '../Tags/TagsHandler.js'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
import logger from '@overleaf/logger'
|
||||
import Features from '../../infrastructure/Features.js'
|
||||
import SubscriptionViewModelBuilder from '../Subscription/SubscriptionViewModelBuilder.js'
|
||||
import SubscriptionViewModelBuilder from '../Subscription/SubscriptionViewModelBuilder.mjs'
|
||||
import NotificationsHandler from '../Notifications/NotificationsHandler.js'
|
||||
import Modules from '../../infrastructure/Modules.js'
|
||||
import { OError, V1ConnectionError } from '../Errors/Errors.js'
|
||||
@@ -27,7 +27,7 @@ import SplitTestHandler from '../SplitTests/SplitTestHandler.js'
|
||||
import SplitTestSessionHandler from '../SplitTests/SplitTestSessionHandler.js'
|
||||
import TutorialHandler from '../Tutorial/TutorialHandler.mjs'
|
||||
import SubscriptionHelper from '../Subscription/SubscriptionHelper.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.mjs'
|
||||
import AnalyticsManager from '../Analytics/AnalyticsManager.js'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const logger = require('@overleaf/logger')
|
||||
const SessionManager = require('../Authentication/SessionManager')
|
||||
const LoginRateLimiter = require('./LoginRateLimiter')
|
||||
const settings = require('@overleaf/settings')
|
||||
import logger from '@overleaf/logger'
|
||||
import SessionManager from '../Authentication/SessionManager.js'
|
||||
import LoginRateLimiter from './LoginRateLimiter.js'
|
||||
import settings from '@overleaf/settings'
|
||||
|
||||
/**
|
||||
* Return a rate limiting middleware
|
||||
@@ -88,4 +88,4 @@ const RateLimiterMiddleware = {
|
||||
loginRateLimitEmail,
|
||||
}
|
||||
|
||||
module.exports = RateLimiterMiddleware
|
||||
export default RateLimiterMiddleware
|
||||
@@ -1,9 +1,9 @@
|
||||
// @ts-check
|
||||
import mongodb from '../../infrastructure/mongodb.js'
|
||||
import { callbackify } from 'node:util'
|
||||
import Settings from '@overleaf/settings'
|
||||
import Errors from '../Errors/Errors.js'
|
||||
|
||||
const { db } = require('../../infrastructure/mongodb')
|
||||
const { callbackify } = require('util')
|
||||
const Settings = require('@overleaf/settings')
|
||||
const { InvalidError } = require('../Errors/Errors')
|
||||
const { db } = mongodb
|
||||
|
||||
const LearnedWordsManager = {
|
||||
/**
|
||||
@@ -15,7 +15,7 @@ const LearnedWordsManager = {
|
||||
|
||||
const wordSize = Buffer.from(word).length
|
||||
if (wordsSize + wordSize > Settings.maxDictionarySize) {
|
||||
throw new InvalidError('Max dictionary size reached')
|
||||
throw new Errors.InvalidError('Max dictionary size reached')
|
||||
}
|
||||
|
||||
return await db.spellingPreferences.updateOne(
|
||||
@@ -86,7 +86,7 @@ const LearnedWordsManager = {
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
learnWord: callbackify(LearnedWordsManager.learnWord),
|
||||
unlearnWord: callbackify(LearnedWordsManager.unlearnWord),
|
||||
getLearnedWords: callbackify(LearnedWordsManager.getLearnedWords),
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-check
|
||||
|
||||
import SessionManager from '../Authentication/SessionManager.js'
|
||||
import LearnedWordsManager from './LearnedWordsManager.js'
|
||||
import LearnedWordsManager from './LearnedWordsManager.mjs'
|
||||
import { z, validateReq } from '../../infrastructure/Validation.js'
|
||||
|
||||
const learnSchema = z.object({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import OError from '@overleaf/o-error'
|
||||
import Metrics from '@overleaf/metrics'
|
||||
import { promisifyAll } from '@overleaf/promise-utils'
|
||||
import LearnedWordsManager from './LearnedWordsManager.js'
|
||||
import LearnedWordsManager from './LearnedWordsManager.mjs'
|
||||
|
||||
const SpellingHandler = {
|
||||
getUserDictionary(userId, callback) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||
const AnalyticsManager = require('../Analytics/AnalyticsManager')
|
||||
const SubscriptionEmailHandler = require('./SubscriptionEmailHandler')
|
||||
const { AI_ADD_ON_CODE } = require('./AiHelper')
|
||||
const { ObjectId } = require('mongodb-legacy')
|
||||
import SplitTestHandler from '../SplitTests/SplitTestHandler.js'
|
||||
import AnalyticsManager from '../Analytics/AnalyticsManager.js'
|
||||
import SubscriptionEmailHandler from './SubscriptionEmailHandler.js'
|
||||
import { AI_ADD_ON_CODE } from './AiHelper.js'
|
||||
import mongodb from 'mongodb-legacy'
|
||||
|
||||
const { ObjectId } = mongodb
|
||||
|
||||
const INVOICE_SUBSCRIPTION_LIMIT = 10
|
||||
|
||||
@@ -389,6 +391,6 @@ function _getSubscriptionData(eventData) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
sendRecurlyAnalyticsEvent,
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
import SessionManager from '../Authentication/SessionManager.js'
|
||||
import SubscriptionHandler from './SubscriptionHandler.js'
|
||||
import SubscriptionHelper from './SubscriptionHelper.js'
|
||||
import SubscriptionViewModelBuilder from './SubscriptionViewModelBuilder.js'
|
||||
import SubscriptionViewModelBuilder from './SubscriptionViewModelBuilder.mjs'
|
||||
import LimitationsManager from './LimitationsManager.js'
|
||||
import RecurlyWrapper from './RecurlyWrapper.js'
|
||||
import Settings from '@overleaf/settings'
|
||||
@@ -13,7 +13,7 @@ import FeaturesUpdater from './FeaturesUpdater.js'
|
||||
import GroupPlansData from './GroupPlansData.js'
|
||||
import V1SubscriptionManager from './V1SubscriptionManager.js'
|
||||
import AnalyticsManager from '../Analytics/AnalyticsManager.js'
|
||||
import RecurlyEventHandler from './RecurlyEventHandler.js'
|
||||
import RecurlyEventHandler from './RecurlyEventHandler.mjs'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
import OError from '@overleaf/o-error'
|
||||
import Errors from './Errors.js'
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
import PlansLocator from './PlansLocator.js'
|
||||
import { User } from '../../models/User.js'
|
||||
import UserGetter from '../User/UserGetter.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.mjs'
|
||||
import { sanitizeSessionUserForFrontEnd } from '../../infrastructure/FrontEndUser.js'
|
||||
import { z, validateReq } from '../../infrastructure/Validation.js'
|
||||
import { IndeterminateInvoiceError } from '../Errors/Errors.js'
|
||||
|
||||
@@ -4,7 +4,7 @@ import SubscriptionController from './SubscriptionController.mjs'
|
||||
import SubscriptionGroupController from './SubscriptionGroupController.mjs'
|
||||
import TeamInvitesController from './TeamInvitesController.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
import Settings from '@overleaf/settings'
|
||||
|
||||
const teamInviteRateLimiter = new RateLimiter('team-invite', {
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
// ts-check
|
||||
const Settings = require('@overleaf/settings')
|
||||
const PlansLocator = require('./PlansLocator')
|
||||
const { isStandaloneAiAddOnPlanCode } = require('./AiHelper')
|
||||
const { MEMBERS_LIMIT_ADD_ON_CODE } = require('./PaymentProviderEntities')
|
||||
const SubscriptionFormatters = require('./SubscriptionFormatters')
|
||||
const SubscriptionLocator = require('./SubscriptionLocator')
|
||||
const InstitutionsGetter = require('../Institutions/InstitutionsGetter')
|
||||
const InstitutionsManager = require('../Institutions/InstitutionsManager')
|
||||
const PublishersGetter = require('../Publishers/PublishersGetter')
|
||||
const sanitizeHtml = require('sanitize-html')
|
||||
const _ = require('lodash')
|
||||
const async = require('async')
|
||||
const SubscriptionHelper = require('./SubscriptionHelper')
|
||||
const { callbackify } = require('@overleaf/promise-utils')
|
||||
const { V1ConnectionError } = require('../Errors/Errors')
|
||||
const FeaturesHelper = require('./FeaturesHelper')
|
||||
const { formatCurrency } = require('../../util/currency')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||
import Settings from '@overleaf/settings'
|
||||
|
||||
import PlansLocator from './PlansLocator.js'
|
||||
import { isStandaloneAiAddOnPlanCode } from './AiHelper.js'
|
||||
import { MEMBERS_LIMIT_ADD_ON_CODE } from './PaymentProviderEntities.js'
|
||||
import SubscriptionFormatters from './SubscriptionFormatters.js'
|
||||
import SubscriptionLocator from './SubscriptionLocator.js'
|
||||
import InstitutionsGetter from '../Institutions/InstitutionsGetter.js'
|
||||
import InstitutionsManager from '../Institutions/InstitutionsManager.js'
|
||||
import PublishersGetter from '../Publishers/PublishersGetter.js'
|
||||
import sanitizeHtml from 'sanitize-html'
|
||||
import _ from 'lodash'
|
||||
import async from 'async'
|
||||
import SubscriptionHelper from './SubscriptionHelper.js'
|
||||
import { callbackify } from '@overleaf/promise-utils'
|
||||
import { V1ConnectionError } from '../Errors/Errors.js'
|
||||
import FeaturesHelper from './FeaturesHelper.js'
|
||||
import { formatCurrency } from '../../util/currency.js'
|
||||
import Modules from '../../infrastructure/Modules.js'
|
||||
import SplitTestHandler from '../SplitTests/SplitTestHandler.js'
|
||||
|
||||
/**
|
||||
* @import { Subscription } from "../../../../types/project/dashboard/subscription"
|
||||
@@ -629,7 +630,7 @@ function buildPlansListForSubscriptionDash(currentPlan, isInTrial) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
buildUsersSubscriptionViewModel: callbackify(buildUsersSubscriptionViewModel),
|
||||
buildPlansList,
|
||||
buildPlansListForSubscriptionDash,
|
||||
@@ -10,7 +10,7 @@ import EmailHelper from '../Helpers/EmailHelper.js'
|
||||
import UserGetter from '../User/UserGetter.js'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
import HttpErrorHandler from '../Errors/HttpErrorHandler.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.js'
|
||||
import PermissionsManager from '../Authorization/PermissionsManager.mjs'
|
||||
import EmailHandler from '../Email/EmailHandler.js'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import Modules from '../../infrastructure/Modules.js'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const path = require('path')
|
||||
const SessionManager = require('../Authentication/SessionManager')
|
||||
const TemplatesManager = require('./TemplatesManager')
|
||||
const ProjectHelper = require('../Project/ProjectHelper')
|
||||
const logger = require('@overleaf/logger')
|
||||
const { expressify } = require('@overleaf/promise-utils')
|
||||
import path from 'node:path'
|
||||
import SessionManager from '../Authentication/SessionManager.js'
|
||||
import TemplatesManager from './TemplatesManager.js'
|
||||
import ProjectHelper from '../Project/ProjectHelper.js'
|
||||
import logger from '@overleaf/logger'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
|
||||
const TemplatesController = {
|
||||
async getV1Template(req, res) {
|
||||
@@ -27,7 +27,7 @@ const TemplatesController = {
|
||||
}
|
||||
res.render(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
import.meta.dirname,
|
||||
'../../../views/project/editor/new_from_template'
|
||||
),
|
||||
data
|
||||
@@ -54,7 +54,7 @@ const TemplatesController = {
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
getV1Template: expressify(TemplatesController.getV1Template),
|
||||
createProjectFromV1Template: expressify(
|
||||
TemplatesController.createProjectFromV1Template
|
||||
@@ -8,10 +8,11 @@
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const settings = require('@overleaf/settings')
|
||||
const logger = require('@overleaf/logger')
|
||||
import settings from '@overleaf/settings'
|
||||
|
||||
module.exports = {
|
||||
import logger from '@overleaf/logger'
|
||||
|
||||
export default {
|
||||
saveTemplateDataInSession(req, res, next) {
|
||||
if (req.query.templateName) {
|
||||
req.session.templateData = req.query
|
||||
@@ -1,9 +1,9 @@
|
||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||
import TemplatesController from './TemplatesController.js'
|
||||
import TemplatesMiddleware from './TemplatesMiddleware.js'
|
||||
import TemplatesController from './TemplatesController.mjs'
|
||||
import TemplatesMiddleware from './TemplatesMiddleware.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import AnalyticsRegistrationSourceMiddleware from '../Analytics/AnalyticsRegistrationSourceMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
import AnalyticsRegistrationSourceMiddleware from '../Analytics/AnalyticsRegistrationSourceMiddleware.mjs'
|
||||
|
||||
const rateLimiter = new RateLimiter('create-project-from-template', {
|
||||
points: 20,
|
||||
|
||||
@@ -2,7 +2,7 @@ import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mj
|
||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||
import ProjectUploadController from './ProjectUploadController.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
import Settings from '@overleaf/settings'
|
||||
|
||||
const rateLimiters = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import UserMembershipController from './UserMembershipController.mjs'
|
||||
import SubscriptionGroupController from '../Subscription/SubscriptionGroupController.mjs'
|
||||
import TeamInvitesController from '../Subscription/TeamInvitesController.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
|
||||
|
||||
const rateLimiters = {
|
||||
createTeamInvite: new RateLimiter('create-team-invite', {
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
openProjectRateLimiter,
|
||||
overleafLoginRateLimiter,
|
||||
} from './infrastructure/RateLimiter.js'
|
||||
import RateLimiterMiddleware from './Features/Security/RateLimiterMiddleware.js'
|
||||
import RateLimiterMiddleware from './Features/Security/RateLimiterMiddleware.mjs'
|
||||
import InactiveProjectController from './Features/InactiveData/InactiveProjectController.mjs'
|
||||
import ContactRouter from './Features/Contacts/ContactRouter.mjs'
|
||||
import ReferencesController from './Features/References/ReferencesController.mjs'
|
||||
@@ -55,7 +55,7 @@ import LinkedFilesRouter from './Features/LinkedFiles/LinkedFilesRouter.mjs'
|
||||
import TemplatesRouter from './Features/Templates/TemplatesRouter.mjs'
|
||||
import UserMembershipRouter from './Features/UserMembership/UserMembershipRouter.mjs'
|
||||
import SystemMessageController from './Features/SystemMessages/SystemMessageController.mjs'
|
||||
import AnalyticsRegistrationSourceMiddleware from './Features/Analytics/AnalyticsRegistrationSourceMiddleware.js'
|
||||
import AnalyticsRegistrationSourceMiddleware from './Features/Analytics/AnalyticsRegistrationSourceMiddleware.mjs'
|
||||
import AnalyticsUTMTrackingMiddleware from './Features/Analytics/AnalyticsUTMTrackingMiddleware.mjs'
|
||||
import CaptchaMiddleware from './Features/Captcha/CaptchaMiddleware.mjs'
|
||||
import UnsupportedBrowserMiddleware from './infrastructure/UnsupportedBrowserMiddleware.js'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { db, ObjectId } from '../../../../app/src/infrastructure/mongodb.js'
|
||||
import { expect } from 'chai'
|
||||
import { callbackifyClass } from '@overleaf/promise-utils'
|
||||
import SubscriptionUpdater from '../../../../app/src/Features/Subscription/SubscriptionUpdater.js'
|
||||
import PermissionsManager from '../../../../app/src/Features/Authorization/PermissionsManager.js'
|
||||
import PermissionsManager from '../../../../app/src/Features/Authorization/PermissionsManager.mjs'
|
||||
import SSOConfigManager from '../../../../modules/group-settings/app/src/sso/SSOConfigManager.mjs'
|
||||
import { Subscription as SubscriptionModel } from '../../../../app/src/models/Subscription.js'
|
||||
import { DeletedSubscription as DeletedSubscriptionModel } from '../../../../app/src/models/DeletedSubscription.js'
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
const sinon = require('sinon')
|
||||
const { expect } = require('chai')
|
||||
import { vi, expect } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Authorization/PermissionsManager.js'
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { ForbiddenError } = require('../../../../app/src/Features/Errors/Errors')
|
||||
'../../../../app/src/Features/Authorization/PermissionsManager.mjs'
|
||||
|
||||
describe('PermissionsManager', function () {
|
||||
beforeEach(function () {
|
||||
this.PermissionsManager = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'../../infrastructure/Modules': (this.Modules = {
|
||||
promises: {
|
||||
hooks: {
|
||||
fire: (this.hooksFire = sinon.stub().resolves([[]])),
|
||||
},
|
||||
beforeEach(async function (ctx) {
|
||||
vi.doMock('../../../../app/src/infrastructure/Modules', () => ({
|
||||
default: (ctx.Modules = {
|
||||
promises: {
|
||||
hooks: {
|
||||
fire: (ctx.hooksFire = sinon.stub().resolves([[]])),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability1', {
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
ctx.PermissionsManager = (await import(modulePath)).default
|
||||
ctx.PermissionsManager.registerCapability('capability1', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability2', {
|
||||
ctx.PermissionsManager.registerCapability('capability2', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability3', {
|
||||
ctx.PermissionsManager.registerCapability('capability3', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability4', {
|
||||
ctx.PermissionsManager.registerCapability('capability4', {
|
||||
default: false,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('openPolicy', {
|
||||
ctx.PermissionsManager.registerPolicy('openPolicy', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('restrictivePolicy', {
|
||||
ctx.PermissionsManager.registerPolicy('restrictivePolicy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
this.openPolicyResponseSet = [
|
||||
ctx.openPolicyResponseSet = [
|
||||
[
|
||||
{
|
||||
managedUsersEnabled: true,
|
||||
@@ -50,7 +49,7 @@ describe('PermissionsManager', function () {
|
||||
},
|
||||
],
|
||||
]
|
||||
this.restrictivePolicyResponseSet = [
|
||||
ctx.restrictivePolicyResponseSet = [
|
||||
[
|
||||
{
|
||||
managedUsersEnabled: true,
|
||||
@@ -65,40 +64,40 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
|
||||
describe('validatePolicies', function () {
|
||||
it('accepts empty object', function () {
|
||||
expect(() => this.PermissionsManager.validatePolicies({})).not.to.throw
|
||||
it('accepts empty object', function (ctx) {
|
||||
expect(() => ctx.PermissionsManager.validatePolicies({})).not.to.throw
|
||||
})
|
||||
|
||||
it('accepts object with registered policies', function () {
|
||||
it('accepts object with registered policies', function (ctx) {
|
||||
expect(() =>
|
||||
this.PermissionsManager.validatePolicies({
|
||||
ctx.PermissionsManager.validatePolicies({
|
||||
openPolicy: true,
|
||||
restrictivePolicy: false,
|
||||
})
|
||||
).not.to.throw
|
||||
})
|
||||
|
||||
it('accepts object with policies containing non-boolean values', function () {
|
||||
it('accepts object with policies containing non-boolean values', function (ctx) {
|
||||
expect(() =>
|
||||
this.PermissionsManager.validatePolicies({
|
||||
ctx.PermissionsManager.validatePolicies({
|
||||
openPolicy: 1,
|
||||
})
|
||||
).to.throw('policy value must be a boolean: openPolicy = 1')
|
||||
expect(() =>
|
||||
this.PermissionsManager.validatePolicies({
|
||||
ctx.PermissionsManager.validatePolicies({
|
||||
openPolicy: undefined,
|
||||
})
|
||||
).to.throw('policy value must be a boolean: openPolicy = undefined')
|
||||
expect(() =>
|
||||
this.PermissionsManager.validatePolicies({
|
||||
ctx.PermissionsManager.validatePolicies({
|
||||
openPolicy: null,
|
||||
})
|
||||
).to.throw('policy value must be a boolean: openPolicy = null')
|
||||
})
|
||||
|
||||
it('throws error on object with policies that are not registered', function () {
|
||||
it('throws error on object with policies that are not registered', function (ctx) {
|
||||
expect(() =>
|
||||
this.PermissionsManager.validatePolicies({
|
||||
ctx.PermissionsManager.validatePolicies({
|
||||
openPolicy: true,
|
||||
unregisteredPolicy: false,
|
||||
})
|
||||
@@ -108,20 +107,20 @@ describe('PermissionsManager', function () {
|
||||
|
||||
describe('hasPermission', function () {
|
||||
describe('when no policies apply to the user', function () {
|
||||
it('should return true if default permission is true', function () {
|
||||
it('should return true if default permission is true', function (ctx) {
|
||||
const groupPolicy = {}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if the default permission is false', function () {
|
||||
it('should return false if the default permission is false', function (ctx) {
|
||||
const groupPolicy = {}
|
||||
const capability = 'capability4'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
@@ -130,8 +129,8 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
|
||||
describe('when a policy applies to the user', function () {
|
||||
it('should return true if the user has the capability after the policy is applied', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
it('should return true if the user has the capability after the policy is applied', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
@@ -139,15 +138,15 @@ describe('PermissionsManager', function () {
|
||||
policy: true,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if the user does not have the capability after the policy is applied', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
it('should return false if the user does not have the capability after the policy is applied', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
@@ -155,15 +154,15 @@ describe('PermissionsManager', function () {
|
||||
policy: true,
|
||||
}
|
||||
const capability = 'capability2'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
|
||||
it('should return the default permission if the policy does not apply to the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
it('should return the default permission if the policy does not apply to the capability', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
@@ -172,7 +171,7 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
{
|
||||
const capability = 'capability3'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
@@ -180,7 +179,7 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
{
|
||||
const capability = 'capability4'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
@@ -188,8 +187,8 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
})
|
||||
|
||||
it('should return the default permission if the policy is not enforced', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
it('should return the default permission if the policy is not enforced', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
@@ -197,12 +196,12 @@ describe('PermissionsManager', function () {
|
||||
policy: false,
|
||||
}
|
||||
const capability1 = 'capability1'
|
||||
const result1 = this.PermissionsManager.hasPermission(
|
||||
const result1 = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability1
|
||||
)
|
||||
const capability2 = 'capability2'
|
||||
const result2 = this.PermissionsManager.hasPermission(
|
||||
const result2 = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability2
|
||||
)
|
||||
@@ -212,13 +211,13 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
|
||||
describe('when multiple policies apply to the user', function () {
|
||||
it('should return true if all policies allow the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
it('should return true if all policies allow the capability', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
ctx.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
@@ -227,20 +226,20 @@ describe('PermissionsManager', function () {
|
||||
policy2: true,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if any policy denies the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
it('should return false if any policy denies the capability', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
ctx.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
@@ -249,20 +248,20 @@ describe('PermissionsManager', function () {
|
||||
policy2: true,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
|
||||
it('should return the default permssion when the applicable policy is not enforced', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
it('should return the default permssion when the applicable policy is not enforced', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
ctx.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
@@ -271,15 +270,15 @@ describe('PermissionsManager', function () {
|
||||
policy2: false,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return the default permission if the policies do not restrict to the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
it('should return the default permission if the policies do not restrict to the capability', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
@@ -288,7 +287,7 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
{
|
||||
const capability = 'capability3'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
@@ -296,7 +295,7 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
{
|
||||
const capability = 'capability4'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
const result = ctx.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
@@ -307,17 +306,17 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
|
||||
describe('getUserCapabilities', function () {
|
||||
it('should return the default capabilities when no group policy is provided', function () {
|
||||
it('should return the default capabilities when no group policy is provided', function (ctx) {
|
||||
const groupPolicy = {}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
ctx.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(
|
||||
new Set(['capability1', 'capability2', 'capability3'])
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a reduced capability set when a group policy is provided', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
it('should return a reduced capability set when a group policy is provided', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
@@ -325,18 +324,18 @@ describe('PermissionsManager', function () {
|
||||
policy: true,
|
||||
}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
ctx.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(
|
||||
new Set(['capability1', 'capability3'])
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a reduced capability set when multiple group policies are provided', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
it('should return a reduced capability set when multiple group policies are provided', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
ctx.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
@@ -346,20 +345,20 @@ describe('PermissionsManager', function () {
|
||||
policy2: true,
|
||||
}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
ctx.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(new Set(['capability3']))
|
||||
})
|
||||
|
||||
it('should return an empty capability set when group policies remove all permissions', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
it('should return an empty capability set when group policies remove all permissions', function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
ctx.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('policy3', {
|
||||
ctx.PermissionsManager.registerPolicy('policy3', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
capability3: false,
|
||||
@@ -370,14 +369,14 @@ describe('PermissionsManager', function () {
|
||||
policy3: true,
|
||||
}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
ctx.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(new Set())
|
||||
})
|
||||
})
|
||||
|
||||
describe('getUserValidationStatus', function () {
|
||||
it('should return the status for the policy when the user conforms', async function () {
|
||||
this.PermissionsManager.registerPolicy(
|
||||
it('should return the status for the policy when the user conforms', async function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy(
|
||||
'policy',
|
||||
{},
|
||||
{
|
||||
@@ -392,7 +391,7 @@ describe('PermissionsManager', function () {
|
||||
const user = { prop: 'allowed' }
|
||||
const subscription = { prop: 'managed' }
|
||||
const result =
|
||||
await this.PermissionsManager.promises.getUserValidationStatus({
|
||||
await ctx.PermissionsManager.promises.getUserValidationStatus({
|
||||
user,
|
||||
groupPolicy,
|
||||
subscription,
|
||||
@@ -400,8 +399,8 @@ describe('PermissionsManager', function () {
|
||||
expect(result).to.deep.equal(new Map([['policy', true]]))
|
||||
})
|
||||
|
||||
it('should return the status for the policy when the user does not conform', async function () {
|
||||
this.PermissionsManager.registerPolicy(
|
||||
it('should return the status for the policy when the user does not conform', async function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy(
|
||||
'policy',
|
||||
{},
|
||||
{
|
||||
@@ -416,15 +415,15 @@ describe('PermissionsManager', function () {
|
||||
const user = { prop: 'not allowed' }
|
||||
const subscription = { prop: 'managed' }
|
||||
const result =
|
||||
await this.PermissionsManager.promises.getUserValidationStatus({
|
||||
await ctx.PermissionsManager.promises.getUserValidationStatus({
|
||||
user,
|
||||
groupPolicy,
|
||||
subscription,
|
||||
})
|
||||
expect(result).to.deep.equal(new Map([['policy', false]]))
|
||||
})
|
||||
it('should return the status for multiple policies according to whether the user conforms', async function () {
|
||||
this.PermissionsManager.registerPolicy(
|
||||
it('should return the status for multiple policies according to whether the user conforms', async function (ctx) {
|
||||
ctx.PermissionsManager.registerPolicy(
|
||||
'policy1',
|
||||
{},
|
||||
{
|
||||
@@ -433,7 +432,7 @@ describe('PermissionsManager', function () {
|
||||
},
|
||||
}
|
||||
)
|
||||
this.PermissionsManager.registerPolicy(
|
||||
ctx.PermissionsManager.registerPolicy(
|
||||
'policy2',
|
||||
{},
|
||||
{
|
||||
@@ -442,7 +441,7 @@ describe('PermissionsManager', function () {
|
||||
},
|
||||
}
|
||||
)
|
||||
this.PermissionsManager.registerPolicy(
|
||||
ctx.PermissionsManager.registerPolicy(
|
||||
'policy3',
|
||||
{},
|
||||
{
|
||||
@@ -460,7 +459,7 @@ describe('PermissionsManager', function () {
|
||||
const user = { prop: 'allowed' }
|
||||
const subscription = { prop: 'managed' }
|
||||
const result =
|
||||
await this.PermissionsManager.promises.getUserValidationStatus({
|
||||
await ctx.PermissionsManager.promises.getUserValidationStatus({
|
||||
user,
|
||||
groupPolicy,
|
||||
subscription,
|
||||
@@ -475,20 +474,20 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
describe('assertUserPermissions', function () {
|
||||
describe('allowed', function () {
|
||||
it('should not error when managedUsersEnabled is not enabled for user', async function () {
|
||||
it('should not error when managedUsersEnabled is not enabled for user', async function (ctx) {
|
||||
const result =
|
||||
await this.PermissionsManager.promises.assertUserPermissions(
|
||||
await ctx.PermissionsManager.promises.assertUserPermissions(
|
||||
{ _id: 'user123' },
|
||||
['add-secondary-email']
|
||||
)
|
||||
expect(result).to.be.undefined
|
||||
})
|
||||
|
||||
it('should not error when default capability is true', async function () {
|
||||
this.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
it('should not error when default capability is true', async function (ctx) {
|
||||
ctx.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
default: true,
|
||||
})
|
||||
this.hooksFire.resolves([
|
||||
ctx.hooksFire.resolves([
|
||||
[
|
||||
{
|
||||
managedUsersEnabled: true,
|
||||
@@ -497,21 +496,21 @@ describe('PermissionsManager', function () {
|
||||
],
|
||||
])
|
||||
const result =
|
||||
await this.PermissionsManager.promises.assertUserPermissions(
|
||||
await ctx.PermissionsManager.promises.assertUserPermissions(
|
||||
{ _id: 'user123' },
|
||||
['some-policy-to-check']
|
||||
)
|
||||
expect(result).to.be.undefined
|
||||
})
|
||||
|
||||
it('should not error when default permission is false but user has permission', async function () {
|
||||
this.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
it('should not error when default permission is false but user has permission', async function (ctx) {
|
||||
ctx.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
default: false,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('userCanDoSomePolicy', {
|
||||
ctx.PermissionsManager.registerPolicy('userCanDoSomePolicy', {
|
||||
'some-policy-to-check': true,
|
||||
})
|
||||
this.hooksFire.resolves([
|
||||
ctx.hooksFire.resolves([
|
||||
[
|
||||
{
|
||||
managedUsersEnabled: true,
|
||||
@@ -522,7 +521,7 @@ describe('PermissionsManager', function () {
|
||||
],
|
||||
])
|
||||
const result =
|
||||
await this.PermissionsManager.promises.assertUserPermissions(
|
||||
await ctx.PermissionsManager.promises.assertUserPermissions(
|
||||
{ _id: 'user123' },
|
||||
['some-policy-to-check']
|
||||
)
|
||||
@@ -531,21 +530,21 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
|
||||
describe('not allowed', function () {
|
||||
it('should return error when managedUsersEnabled is enabled for user but there is no group policy', async function () {
|
||||
this.hooksFire.resolves([[{ managedUsersEnabled: true }]])
|
||||
it('should return error when managedUsersEnabled is enabled for user but there is no group policy', async function (ctx) {
|
||||
ctx.hooksFire.resolves([[{ managedUsersEnabled: true }]])
|
||||
await expect(
|
||||
this.PermissionsManager.promises.assertUserPermissions(
|
||||
ctx.PermissionsManager.promises.assertUserPermissions(
|
||||
{ _id: 'user123' },
|
||||
['add-secondary-email']
|
||||
)
|
||||
).to.be.rejectedWith(Error, 'unknown capability: add-secondary-email')
|
||||
})
|
||||
|
||||
it('should return error when default permission is false', async function () {
|
||||
this.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
it('should return error when default permission is false', async function (ctx) {
|
||||
ctx.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
default: false,
|
||||
})
|
||||
this.hooksFire.resolves([
|
||||
ctx.hooksFire.resolves([
|
||||
[
|
||||
{
|
||||
managedUsersEnabled: true,
|
||||
@@ -554,21 +553,23 @@ describe('PermissionsManager', function () {
|
||||
],
|
||||
])
|
||||
await expect(
|
||||
this.PermissionsManager.promises.assertUserPermissions(
|
||||
ctx.PermissionsManager.promises.assertUserPermissions(
|
||||
{ _id: 'user123' },
|
||||
['some-policy-to-check']
|
||||
)
|
||||
).to.be.rejectedWith(ForbiddenError)
|
||||
).to.be.rejectedWith(
|
||||
'user does not have one or more permissions within some-policy-to-check'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return error when default permission is true but user does not have permission', async function () {
|
||||
this.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
it('should return error when default permission is true but user does not have permission', async function (ctx) {
|
||||
ctx.PermissionsManager.registerCapability('some-policy-to-check', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('userCannotDoSomePolicy', {
|
||||
ctx.PermissionsManager.registerPolicy('userCannotDoSomePolicy', {
|
||||
'some-policy-to-check': false,
|
||||
})
|
||||
this.hooksFire.resolves([
|
||||
ctx.hooksFire.resolves([
|
||||
[
|
||||
{
|
||||
managedUsersEnabled: true,
|
||||
@@ -577,33 +578,35 @@ describe('PermissionsManager', function () {
|
||||
],
|
||||
])
|
||||
await expect(
|
||||
this.PermissionsManager.promises.assertUserPermissions(
|
||||
ctx.PermissionsManager.promises.assertUserPermissions(
|
||||
{ _id: 'user123' },
|
||||
['some-policy-to-check']
|
||||
)
|
||||
).to.be.rejectedWith(ForbiddenError)
|
||||
).to.be.rejectedWith(
|
||||
'user does not have one or more permissions within some-policy-to-check'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('registerAllowedProperty', function () {
|
||||
it('allows us to register a property', async function () {
|
||||
this.PermissionsManager.registerAllowedProperty('metadata1')
|
||||
const result = await this.PermissionsManager.getAllowedProperties()
|
||||
it('allows us to register a property', async function (ctx) {
|
||||
ctx.PermissionsManager.registerAllowedProperty('metadata1')
|
||||
const result = await ctx.PermissionsManager.getAllowedProperties()
|
||||
expect(result).to.deep.equal(new Set(['metadata1']))
|
||||
})
|
||||
|
||||
// used if multiple modules would require the same prop, since we dont know which will load first, both must register
|
||||
it('should handle multiple registrations of the same property', async function () {
|
||||
this.PermissionsManager.registerAllowedProperty('metadata1')
|
||||
this.PermissionsManager.registerAllowedProperty('metadata1')
|
||||
const result = await this.PermissionsManager.getAllowedProperties()
|
||||
it('should handle multiple registrations of the same property', async function (ctx) {
|
||||
ctx.PermissionsManager.registerAllowedProperty('metadata1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('metadata1')
|
||||
const result = await ctx.PermissionsManager.getAllowedProperties()
|
||||
expect(result).to.deep.equal(new Set(['metadata1']))
|
||||
})
|
||||
})
|
||||
|
||||
describe('combineAllowedProperties', function () {
|
||||
it('should handle multiple occurences of the same property, preserving the first occurence', async function () {
|
||||
it('should handle multiple occurences of the same property, preserving the first occurence', async function (ctx) {
|
||||
const policy1 = {
|
||||
groupPolicy: {
|
||||
policy: false,
|
||||
@@ -618,17 +621,17 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
|
||||
const results = [policy1, policy2]
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
|
||||
const combinedProps =
|
||||
this.PermissionsManager.combineAllowedProperties(results)
|
||||
ctx.PermissionsManager.combineAllowedProperties(results)
|
||||
|
||||
expect(combinedProps).to.deep.equal({
|
||||
prop1: 'some other value here',
|
||||
})
|
||||
})
|
||||
|
||||
it('should add registered properties to the set', async function () {
|
||||
it('should add registered properties to the set', async function (ctx) {
|
||||
const policy = {
|
||||
groupPolicy: {
|
||||
policy: false,
|
||||
@@ -645,11 +648,11 @@ describe('PermissionsManager', function () {
|
||||
}
|
||||
|
||||
const results = [policy, policy2]
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
this.PermissionsManager.registerAllowedProperty('prop2')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop2')
|
||||
|
||||
const combinedProps =
|
||||
this.PermissionsManager.combineAllowedProperties(results)
|
||||
ctx.PermissionsManager.combineAllowedProperties(results)
|
||||
|
||||
expect(combinedProps).to.deep.equal({
|
||||
prop1: 'some value here',
|
||||
@@ -657,7 +660,7 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should not add unregistered properties to the req object', async function () {
|
||||
it('should not add unregistered properties to the req object', async function (ctx) {
|
||||
const policy = {
|
||||
groupPolicy: {
|
||||
policy: false,
|
||||
@@ -671,36 +674,36 @@ describe('PermissionsManager', function () {
|
||||
},
|
||||
prop2: 'some value here',
|
||||
}
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
|
||||
const results = [policy, policy2]
|
||||
|
||||
const combinedProps =
|
||||
this.PermissionsManager.combineAllowedProperties(results)
|
||||
ctx.PermissionsManager.combineAllowedProperties(results)
|
||||
|
||||
expect(combinedProps).to.deep.equal({ prop1: 'some value here' })
|
||||
})
|
||||
|
||||
it('should handle an empty array', async function () {
|
||||
it('should handle an empty array', async function (ctx) {
|
||||
const results = []
|
||||
|
||||
const combinedProps =
|
||||
this.PermissionsManager.combineAllowedProperties(results)
|
||||
ctx.PermissionsManager.combineAllowedProperties(results)
|
||||
|
||||
expect(combinedProps).to.deep.equal({})
|
||||
})
|
||||
})
|
||||
|
||||
describe('combineGroupPolicies', function () {
|
||||
it('should return an empty object when an empty array is passed', async function () {
|
||||
it('should return an empty object when an empty array is passed', async function (ctx) {
|
||||
const results = []
|
||||
|
||||
const combinedPolicy =
|
||||
this.PermissionsManager.combineGroupPolicies(results)
|
||||
ctx.PermissionsManager.combineGroupPolicies(results)
|
||||
expect(combinedPolicy).to.deep.equal({})
|
||||
})
|
||||
|
||||
it('should combine multiple group policies into a single policy object', async function () {
|
||||
it('should combine multiple group policies into a single policy object', async function (ctx) {
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
}
|
||||
@@ -709,12 +712,12 @@ describe('PermissionsManager', function () {
|
||||
policy2: false,
|
||||
policy3: true,
|
||||
}
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
|
||||
const results = [groupPolicy, groupPolicy2]
|
||||
|
||||
const combinedPolicy =
|
||||
this.PermissionsManager.combineGroupPolicies(results)
|
||||
ctx.PermissionsManager.combineGroupPolicies(results)
|
||||
|
||||
expect(combinedPolicy).to.deep.equal({
|
||||
policy1: true,
|
||||
@@ -722,7 +725,7 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle duplicate enforced policies across different group policies', async function () {
|
||||
it('should handle duplicate enforced policies across different group policies', async function (ctx) {
|
||||
const groupPolicy = {
|
||||
policy1: false,
|
||||
policy2: true,
|
||||
@@ -732,12 +735,12 @@ describe('PermissionsManager', function () {
|
||||
policy2: true,
|
||||
policy3: true,
|
||||
}
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
|
||||
const results = [groupPolicy, groupPolicy2]
|
||||
|
||||
const combinedPolicy =
|
||||
this.PermissionsManager.combineGroupPolicies(results)
|
||||
ctx.PermissionsManager.combineGroupPolicies(results)
|
||||
|
||||
expect(combinedPolicy).to.deep.equal({
|
||||
policy2: true,
|
||||
@@ -745,7 +748,7 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle group policies with no enforced policies', async function () {
|
||||
it('should handle group policies with no enforced policies', async function (ctx) {
|
||||
const groupPolicy = {
|
||||
policy1: false,
|
||||
policy2: false,
|
||||
@@ -755,17 +758,17 @@ describe('PermissionsManager', function () {
|
||||
policy2: false,
|
||||
policy3: true,
|
||||
}
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
|
||||
const results = [groupPolicy, groupPolicy2]
|
||||
|
||||
const combinedPolicy =
|
||||
this.PermissionsManager.combineGroupPolicies(results)
|
||||
ctx.PermissionsManager.combineGroupPolicies(results)
|
||||
|
||||
expect(combinedPolicy).to.deep.equal({ policy3: true })
|
||||
})
|
||||
|
||||
it('should choose the stricter option between two policy values', async function () {
|
||||
it('should choose the stricter option between two policy values', async function (ctx) {
|
||||
const groupPolicy = {
|
||||
policy1: false,
|
||||
policy2: true,
|
||||
@@ -777,12 +780,12 @@ describe('PermissionsManager', function () {
|
||||
policy3: true,
|
||||
policy4: false,
|
||||
}
|
||||
this.PermissionsManager.registerAllowedProperty('prop1')
|
||||
ctx.PermissionsManager.registerAllowedProperty('prop1')
|
||||
|
||||
const results = [groupPolicy, groupPolicy2]
|
||||
|
||||
const combinedPolicy =
|
||||
this.PermissionsManager.combineGroupPolicies(results)
|
||||
ctx.PermissionsManager.combineGroupPolicies(results)
|
||||
|
||||
expect(combinedPolicy).to.deep.equal({
|
||||
policy2: true,
|
||||
@@ -793,30 +796,30 @@ describe('PermissionsManager', function () {
|
||||
})
|
||||
|
||||
describe('checkUserListPermissions', function () {
|
||||
it('should return true when all users have permissions required', async function () {
|
||||
it('should return true when all users have permissions required', async function (ctx) {
|
||||
const userList = ['user1', 'user2', 'user3']
|
||||
const capabilities = ['capability1', 'capability2']
|
||||
this.hooksFire.onCall(0).resolves(this.openPolicyResponseSet)
|
||||
this.hooksFire.onCall(1).resolves(this.openPolicyResponseSet)
|
||||
this.hooksFire.onCall(2).resolves(this.openPolicyResponseSet)
|
||||
ctx.hooksFire.onCall(0).resolves(ctx.openPolicyResponseSet)
|
||||
ctx.hooksFire.onCall(1).resolves(ctx.openPolicyResponseSet)
|
||||
ctx.hooksFire.onCall(2).resolves(ctx.openPolicyResponseSet)
|
||||
|
||||
const usersHavePermission =
|
||||
await this.PermissionsManager.promises.checkUserListPermissions(
|
||||
await ctx.PermissionsManager.promises.checkUserListPermissions(
|
||||
userList,
|
||||
capabilities
|
||||
)
|
||||
expect(usersHavePermission).to.equal(true)
|
||||
})
|
||||
|
||||
it('should return false if any user does not have permission', async function () {
|
||||
it('should return false if any user does not have permission', async function (ctx) {
|
||||
const userList = ['user1', 'user2', 'user3']
|
||||
const capabilities = ['capability1', 'capability2']
|
||||
this.hooksFire.onCall(0).resolves(this.openPolicyResponseSet)
|
||||
this.hooksFire.onCall(1).resolves(this.restrictivePolicyResponseSet)
|
||||
this.hooksFire.onCall(2).resolves(this.openPolicyResponseSet)
|
||||
ctx.hooksFire.onCall(0).resolves(ctx.openPolicyResponseSet)
|
||||
ctx.hooksFire.onCall(1).resolves(ctx.restrictivePolicyResponseSet)
|
||||
ctx.hooksFire.onCall(2).resolves(ctx.openPolicyResponseSet)
|
||||
|
||||
const usersHavePermission =
|
||||
await this.PermissionsManager.promises.checkUserListPermissions(
|
||||
await ctx.PermissionsManager.promises.checkUserListPermissions(
|
||||
userList,
|
||||
capabilities
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
import { vi } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Security/RateLimiterMiddleware.mjs'
|
||||
|
||||
describe('RateLimiterMiddleware', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.SessionManager = {
|
||||
getLoggedInUserId: () => ctx.req.session?.user?._id,
|
||||
}
|
||||
|
||||
vi.doMock('@overleaf/settings', () => ({
|
||||
default: (ctx.settings = {}),
|
||||
}))
|
||||
|
||||
vi.doMock('../../../../app/src/Features/Security/LoginRateLimiter', () => ({
|
||||
default: {},
|
||||
}))
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Authentication/SessionManager',
|
||||
() => ({
|
||||
default: ctx.SessionManager,
|
||||
})
|
||||
)
|
||||
|
||||
ctx.RateLimiterMiddleware = (await import(modulePath)).default
|
||||
ctx.req = { params: {} }
|
||||
ctx.res = {
|
||||
status: sinon.stub(),
|
||||
write: sinon.stub(),
|
||||
end: sinon.stub(),
|
||||
}
|
||||
ctx.next = sinon.stub()
|
||||
})
|
||||
|
||||
describe('rateLimit', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.projectId = 'project-id'
|
||||
ctx.docId = 'doc-id'
|
||||
ctx.rateLimiter = {
|
||||
consume: sinon.stub().resolves({ remainingPoints: 2 }),
|
||||
}
|
||||
ctx.middleware = ctx.RateLimiterMiddleware.rateLimit(ctx.rateLimiter, {
|
||||
params: ['projectId', 'docId'],
|
||||
})
|
||||
ctx.req.params = { projectId: ctx.projectId, docId: ctx.docId }
|
||||
})
|
||||
|
||||
describe('when there is no session', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
await new Promise(resolve => {
|
||||
ctx.req.ip = ctx.ip = '1.2.3.4'
|
||||
ctx.middleware(ctx.req, ctx.res, () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should call the rate limiter with the ip address', function (ctx) {
|
||||
ctx.rateLimiter.consume.should.have.been.calledWith(
|
||||
`${ctx.projectId}:${ctx.docId}:${ctx.ip}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when smoke test user', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
await new Promise(resolve => {
|
||||
ctx.userId = 'smoke-test-user-id'
|
||||
ctx.req.session = {
|
||||
user: { _id: ctx.userId },
|
||||
}
|
||||
ctx.settings.smokeTest = { userId: ctx.userId }
|
||||
ctx.middleware(ctx.req, ctx.res, () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should not call the rate limiter', function (ctx) {
|
||||
ctx.rateLimiter.consume.should.not.have.been.called
|
||||
})
|
||||
})
|
||||
|
||||
describe('when under the rate limit with logged in user', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
await new Promise(resolve => {
|
||||
ctx.userId = 'user-id'
|
||||
ctx.req.session = {
|
||||
user: { _id: ctx.userId },
|
||||
}
|
||||
ctx.middleware(ctx.req, ctx.res, () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should call the rate limiter backend with the userId', function (ctx) {
|
||||
ctx.rateLimiter.consume.should.have.been.calledWith(
|
||||
`${ctx.projectId}:${ctx.docId}:${ctx.userId}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when under the rate limit with anonymous user', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
await new Promise(resolve => {
|
||||
ctx.req.ip = '1.2.3.4'
|
||||
ctx.middleware(ctx.req, ctx.res, () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should call the rate limiter backend with the ip address', function (ctx) {
|
||||
ctx.rateLimiter.consume.should.have.been.calledWith(
|
||||
`${ctx.projectId}:${ctx.docId}:${ctx.req.ip}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when over the rate limit', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
await new Promise(resolve => {
|
||||
ctx.userId = 'user-id'
|
||||
ctx.req.session = {
|
||||
user: { _id: ctx.userId },
|
||||
}
|
||||
ctx.res.end.callsFake(() => {
|
||||
resolve()
|
||||
})
|
||||
ctx.rateLimiter.consume.rejects({ remainingPoints: 0 })
|
||||
ctx.middleware(ctx.req, ctx.res, ctx.next)
|
||||
})
|
||||
})
|
||||
|
||||
it('should return a 429', function (ctx) {
|
||||
ctx.res.status.should.have.been.calledWith(429)
|
||||
})
|
||||
|
||||
it('should not continue', function (ctx) {
|
||||
ctx.next.should.not.have.been.called
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,129 +0,0 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = require('path').join(
|
||||
__dirname,
|
||||
'../../../../app/src/Features/Security/RateLimiterMiddleware'
|
||||
)
|
||||
|
||||
describe('RateLimiterMiddleware', function () {
|
||||
beforeEach(function () {
|
||||
this.SessionManager = {
|
||||
getLoggedInUserId: () => this.req.session?.user?._id,
|
||||
}
|
||||
this.RateLimiterMiddleware = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'@overleaf/settings': (this.settings = {}),
|
||||
'./LoginRateLimiter': {},
|
||||
'../Authentication/SessionManager': this.SessionManager,
|
||||
},
|
||||
})
|
||||
this.req = { params: {} }
|
||||
this.res = {
|
||||
status: sinon.stub(),
|
||||
write: sinon.stub(),
|
||||
end: sinon.stub(),
|
||||
}
|
||||
this.next = sinon.stub()
|
||||
})
|
||||
|
||||
describe('rateLimit', function () {
|
||||
beforeEach(function () {
|
||||
this.projectId = 'project-id'
|
||||
this.docId = 'doc-id'
|
||||
this.rateLimiter = {
|
||||
consume: sinon.stub().resolves({ remainingPoints: 2 }),
|
||||
}
|
||||
this.middleware = this.RateLimiterMiddleware.rateLimit(this.rateLimiter, {
|
||||
params: ['projectId', 'docId'],
|
||||
})
|
||||
this.req.params = { projectId: this.projectId, docId: this.docId }
|
||||
})
|
||||
|
||||
describe('when there is no session', function () {
|
||||
beforeEach(function (done) {
|
||||
this.req.ip = this.ip = '1.2.3.4'
|
||||
this.middleware(this.req, this.res, () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should call the rate limiter with the ip address', function () {
|
||||
this.rateLimiter.consume.should.have.been.calledWith(
|
||||
`${this.projectId}:${this.docId}:${this.ip}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when smoke test user', function () {
|
||||
beforeEach(function (done) {
|
||||
this.userId = 'smoke-test-user-id'
|
||||
this.req.session = {
|
||||
user: { _id: this.userId },
|
||||
}
|
||||
this.settings.smokeTest = { userId: this.userId }
|
||||
this.middleware(this.req, this.res, () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not call the rate limiter', function () {
|
||||
this.rateLimiter.consume.should.not.have.been.called
|
||||
})
|
||||
})
|
||||
|
||||
describe('when under the rate limit with logged in user', function () {
|
||||
beforeEach(function (done) {
|
||||
this.userId = 'user-id'
|
||||
this.req.session = {
|
||||
user: { _id: this.userId },
|
||||
}
|
||||
this.middleware(this.req, this.res, () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should call the rate limiter backend with the userId', function () {
|
||||
this.rateLimiter.consume.should.have.been.calledWith(
|
||||
`${this.projectId}:${this.docId}:${this.userId}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when under the rate limit with anonymous user', function () {
|
||||
beforeEach(function (done) {
|
||||
this.req.ip = '1.2.3.4'
|
||||
this.middleware(this.req, this.res, () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should call the rate limiter backend with the ip address', function () {
|
||||
this.rateLimiter.consume.should.have.been.calledWith(
|
||||
`${this.projectId}:${this.docId}:${this.req.ip}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when over the rate limit', function () {
|
||||
beforeEach(function (done) {
|
||||
this.userId = 'user-id'
|
||||
this.req.session = {
|
||||
user: { _id: this.userId },
|
||||
}
|
||||
this.res.end.callsFake(() => {
|
||||
done()
|
||||
})
|
||||
this.rateLimiter.consume.rejects({ remainingPoints: 0 })
|
||||
this.middleware(this.req, this.res, this.next)
|
||||
})
|
||||
|
||||
it('should return a 429', function () {
|
||||
this.res.status.should.have.been.calledWith(429)
|
||||
})
|
||||
|
||||
it('should not continue', function () {
|
||||
this.next.should.not.have.been.called
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
142
services/web/test/unit/src/Spelling/LearnedWordsManager.test.mjs
Normal file
142
services/web/test/unit/src/Spelling/LearnedWordsManager.test.mjs
Normal file
@@ -0,0 +1,142 @@
|
||||
import { vi, expect } from 'vitest'
|
||||
import Errors from '../../../../app/src/Features/Errors/Errors.js'
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Spelling/LearnedWordsManager.mjs'
|
||||
|
||||
vi.mock('../../../../app/src/Features/Errors/Errors.js', () =>
|
||||
vi.importActual('../../../../app/src/Features/Errors/Errors.js')
|
||||
)
|
||||
|
||||
describe('LearnedWordsManager', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.token = 'a6b3cd919ge'
|
||||
ctx.db = {
|
||||
spellingPreferences: {
|
||||
updateOne: vi.fn(),
|
||||
findOne: vi.fn().mockResolvedValue(['pear']),
|
||||
},
|
||||
}
|
||||
|
||||
vi.doMock('../../../../app/src/infrastructure/mongodb.js', () => ({
|
||||
default: { db: ctx.db },
|
||||
}))
|
||||
|
||||
vi.doMock('@overleaf/metrics', () => ({
|
||||
default: {
|
||||
inc: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.doMock('@overleaf/settings', () => ({
|
||||
default: {
|
||||
maxDictionarySize: 20,
|
||||
},
|
||||
}))
|
||||
ctx.LearnedWordsManager = (await import(modulePath)).default
|
||||
})
|
||||
|
||||
describe('learnWord', function () {
|
||||
describe('under size limit', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.word = 'instanton'
|
||||
await ctx.LearnedWordsManager.promises.learnWord(ctx.token, ctx.word)
|
||||
})
|
||||
|
||||
it('should insert the word in the word list in the database', function (ctx) {
|
||||
expect(ctx.db.spellingPreferences.updateOne).toHaveBeenCalledWith(
|
||||
{
|
||||
token: ctx.token,
|
||||
},
|
||||
{
|
||||
$addToSet: { learnedWords: ctx.word },
|
||||
},
|
||||
{
|
||||
upsert: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('over size limit', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.word = 'superlongwordthatwillgobeyondthelimit'
|
||||
})
|
||||
|
||||
it('should throw an error and not insert the word in the word list in the database', async function (ctx) {
|
||||
await expect(
|
||||
ctx.LearnedWordsManager.promises.learnWord(ctx.token, ctx.word)
|
||||
).to.be.rejectedWith(Errors.InvalidError)
|
||||
expect(ctx.db.spellingPreferences.updateOne).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('unlearnWord', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.word = 'instanton'
|
||||
await ctx.LearnedWordsManager.promises.unlearnWord(ctx.token, ctx.word)
|
||||
})
|
||||
|
||||
it('should remove the word from the word list in the database', function (ctx) {
|
||||
expect(ctx.db.spellingPreferences.updateOne).toHaveBeenCalledWith(
|
||||
{
|
||||
token: ctx.token,
|
||||
},
|
||||
{
|
||||
$pull: { learnedWords: ctx.word },
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getLearnedWords', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.wordList = ['apples', 'bananas', 'pears']
|
||||
ctx.wordListWithDuplicates = ctx.wordList.slice()
|
||||
ctx.wordListWithDuplicates.push('bananas')
|
||||
ctx.db.spellingPreferences.findOne = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ learnedWords: ctx.wordListWithDuplicates })
|
||||
ctx.learnedWords = await ctx.LearnedWordsManager.promises.getLearnedWords(
|
||||
ctx.token
|
||||
)
|
||||
})
|
||||
|
||||
it('should get the word list for the given user', function (ctx) {
|
||||
expect(ctx.db.spellingPreferences.findOne).toHaveBeenCalledWith({
|
||||
token: ctx.token,
|
||||
})
|
||||
})
|
||||
|
||||
it('should return the word list without duplicates', function (ctx) {
|
||||
expect(ctx.learnedWords).to.deep.equal(ctx.wordList)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getLearnedWordsSize', function () {
|
||||
it('should return the word list size in the callback', async function (ctx) {
|
||||
ctx.db.spellingPreferences.findOne = conditions => {
|
||||
return Promise.resolve({
|
||||
learnedWords: ['apples', 'bananas', 'pears', 'bananas'],
|
||||
})
|
||||
}
|
||||
const learnedWordsSize =
|
||||
await ctx.LearnedWordsManager.promises.getLearnedWordsSize(ctx.token)
|
||||
expect(learnedWordsSize).to.equal(38)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteUsersLearnedWords', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.db.spellingPreferences.deleteOne = vi.fn()
|
||||
})
|
||||
|
||||
it('should get the word list for the given user', async function (ctx) {
|
||||
await ctx.LearnedWordsManager.promises.deleteUsersLearnedWords(ctx.token)
|
||||
expect(ctx.db.spellingPreferences.deleteOne).toHaveBeenCalledWith({
|
||||
token: ctx.token,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,141 +0,0 @@
|
||||
const sinon = require('sinon')
|
||||
const { expect } = require('chai')
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const modulePath = require('path').join(
|
||||
__dirname,
|
||||
'/../../../../app/src/Features/Spelling/LearnedWordsManager'
|
||||
)
|
||||
const { InvalidError } = require('../../../../app/src/Features/Errors/Errors')
|
||||
|
||||
describe('LearnedWordsManager', function () {
|
||||
beforeEach(function () {
|
||||
this.token = 'a6b3cd919ge'
|
||||
this.db = {
|
||||
spellingPreferences: {
|
||||
updateOne: sinon.stub().resolves(),
|
||||
findOne: sinon.stub().resolves(['pear']),
|
||||
},
|
||||
}
|
||||
this.LearnedWordsManager = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'../../infrastructure/mongodb': { db: this.db },
|
||||
'@overleaf/metrics': {
|
||||
inc: sinon.stub(),
|
||||
},
|
||||
'@overleaf/settings': {
|
||||
maxDictionarySize: 20,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
describe('learnWord', function () {
|
||||
describe('under size limit', function () {
|
||||
beforeEach(async function () {
|
||||
this.word = 'instanton'
|
||||
await this.LearnedWordsManager.promises.learnWord(this.token, this.word)
|
||||
})
|
||||
|
||||
it('should insert the word in the word list in the database', function () {
|
||||
expect(
|
||||
this.db.spellingPreferences.updateOne.calledWith(
|
||||
{
|
||||
token: this.token,
|
||||
},
|
||||
{
|
||||
$addToSet: { learnedWords: this.word },
|
||||
},
|
||||
{
|
||||
upsert: true,
|
||||
}
|
||||
)
|
||||
).to.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('over size limit', function () {
|
||||
beforeEach(function () {
|
||||
this.word = 'superlongwordthatwillgobeyondthelimit'
|
||||
})
|
||||
|
||||
it('should throw an error and not insert the word in the word list in the database', async function () {
|
||||
await expect(
|
||||
this.LearnedWordsManager.promises.learnWord(this.token, this.word)
|
||||
).to.be.rejectedWith(InvalidError)
|
||||
expect(this.db.spellingPreferences.updateOne.notCalled).to.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('unlearnWord', function () {
|
||||
beforeEach(async function () {
|
||||
this.word = 'instanton'
|
||||
await this.LearnedWordsManager.promises.unlearnWord(this.token, this.word)
|
||||
})
|
||||
|
||||
it('should remove the word from the word list in the database', function () {
|
||||
expect(
|
||||
this.db.spellingPreferences.updateOne.calledWith(
|
||||
{
|
||||
token: this.token,
|
||||
},
|
||||
{
|
||||
$pull: { learnedWords: this.word },
|
||||
}
|
||||
)
|
||||
).to.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getLearnedWords', function () {
|
||||
beforeEach(async function () {
|
||||
this.wordList = ['apples', 'bananas', 'pears']
|
||||
this.wordListWithDuplicates = this.wordList.slice()
|
||||
this.wordListWithDuplicates.push('bananas')
|
||||
this.db.spellingPreferences.findOne = conditions => {
|
||||
return Promise.resolve({ learnedWords: this.wordListWithDuplicates })
|
||||
}
|
||||
sinon.spy(this.db.spellingPreferences, 'findOne')
|
||||
this.learnedWords =
|
||||
await this.LearnedWordsManager.promises.getLearnedWords(this.token)
|
||||
})
|
||||
|
||||
it('should get the word list for the given user', function () {
|
||||
expect(
|
||||
this.db.spellingPreferences.findOne.calledWith({ token: this.token })
|
||||
).to.equal(true)
|
||||
})
|
||||
|
||||
it('should return the word list without duplicates', function () {
|
||||
expect(this.learnedWords).to.deep.equal(this.wordList)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getLearnedWordsSize', function () {
|
||||
it('should return the word list size in the callback', async function () {
|
||||
this.db.spellingPreferences.findOne = conditions => {
|
||||
return Promise.resolve({
|
||||
learnedWords: ['apples', 'bananas', 'pears', 'bananas'],
|
||||
})
|
||||
}
|
||||
const learnedWordsSize =
|
||||
await this.LearnedWordsManager.promises.getLearnedWordsSize(this.token)
|
||||
expect(learnedWordsSize).to.equal(38)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteUsersLearnedWords', function () {
|
||||
beforeEach(function () {
|
||||
this.db.spellingPreferences.deleteOne = sinon.stub().resolves()
|
||||
})
|
||||
|
||||
it('should get the word list for the given user', async function () {
|
||||
await this.LearnedWordsManager.promises.deleteUsersLearnedWords(
|
||||
this.token
|
||||
)
|
||||
expect(
|
||||
this.db.spellingPreferences.deleteOne.calledWith({ token: this.token })
|
||||
).to.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,16 +1,19 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { ObjectId } = require('mongodb-legacy')
|
||||
const sinon = require('sinon')
|
||||
import { vi } from 'vitest'
|
||||
import mongodb from 'mongodb-legacy'
|
||||
import sinon from 'sinon'
|
||||
|
||||
const { ObjectId } = mongodb
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Subscription/RecurlyEventHandler'
|
||||
'../../../../app/src/Features/Subscription/RecurlyEventHandler.mjs'
|
||||
|
||||
describe('RecurlyEventHandler', function () {
|
||||
beforeEach(function () {
|
||||
this.userId = '123abc234bcd456cde567def'
|
||||
this.planCode = 'collaborator-annual'
|
||||
this.eventData = {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.userId = '123abc234bcd456cde567def'
|
||||
ctx.planCode = 'collaborator-annual'
|
||||
ctx.eventData = {
|
||||
account: {
|
||||
account_code: this.userId,
|
||||
account_code: ctx.userId,
|
||||
},
|
||||
subscription: {
|
||||
uuid: '8435ad98c1ce45da99b07f6a6a2e780f',
|
||||
@@ -26,17 +29,33 @@ describe('RecurlyEventHandler', function () {
|
||||
},
|
||||
}
|
||||
|
||||
this.RecurlyEventHandler = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'mongodb-legacy': { ObjectId },
|
||||
'./SubscriptionEmailHandler': (this.SubscriptionEmailHandler = {
|
||||
vi.doMock('mongodb-legacy', () => ({
|
||||
default: { ObjectId },
|
||||
}))
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Subscription/SubscriptionEmailHandler',
|
||||
() => ({
|
||||
default: (ctx.SubscriptionEmailHandler = {
|
||||
sendTrialOnboardingEmail: sinon.stub(),
|
||||
}),
|
||||
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Analytics/AnalyticsManager',
|
||||
() => ({
|
||||
default: (ctx.AnalyticsManager = {
|
||||
recordEventForUserInBackground: sinon.stub(),
|
||||
setUserPropertyForUserInBackground: sinon.stub(),
|
||||
}),
|
||||
'../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/SplitTests/SplitTestHandler',
|
||||
() => ({
|
||||
default: (ctx.SplitTestHandler = {
|
||||
promises: {
|
||||
getAssignmentForUser: sinon.stub().resolves({
|
||||
variant: 'default',
|
||||
@@ -44,340 +63,342 @@ describe('RecurlyEventHandler', function () {
|
||||
hasUserBeenAssignedToVariant: sinon.stub().resolves(false),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
ctx.RecurlyEventHandler = (await import(modulePath)).default
|
||||
})
|
||||
|
||||
it('with new_subscription_notification - free trial', async function () {
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with new_subscription_notification - free trial', async function (ctx) {
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'new_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-started',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-plan-code',
|
||||
this.planCode
|
||||
ctx.planCode
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'active'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('with new_subscription_notification - free trial with customerio integration enabled', async function () {
|
||||
this.SplitTestHandler.promises.hasUserBeenAssignedToVariant.resolves(true)
|
||||
it('with new_subscription_notification - free trial with customerio integration enabled', async function (ctx) {
|
||||
ctx.SplitTestHandler.promises.hasUserBeenAssignedToVariant.resolves(true)
|
||||
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'new_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-started',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': true,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-plan-code',
|
||||
this.planCode
|
||||
ctx.planCode
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'active'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('sends free trial onboarding email if user starting a trial', async function () {
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('sends free trial onboarding email if user starting a trial', async function (ctx) {
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'new_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
|
||||
sinon.assert.called(this.SubscriptionEmailHandler.sendTrialOnboardingEmail)
|
||||
sinon.assert.called(ctx.SubscriptionEmailHandler.sendTrialOnboardingEmail)
|
||||
})
|
||||
|
||||
it('with new_subscription_notification - no free trial', async function () {
|
||||
this.eventData.subscription.current_period_started_at = new Date(
|
||||
it('with new_subscription_notification - no free trial', async function (ctx) {
|
||||
ctx.eventData.subscription.current_period_started_at = new Date(
|
||||
'2021-02-10 12:34:56'
|
||||
)
|
||||
this.eventData.subscription.current_period_ends_at = new Date(
|
||||
ctx.eventData.subscription.current_period_ends_at = new Date(
|
||||
'2021-02-17 12:34:56'
|
||||
)
|
||||
this.eventData.subscription.quantity = 3
|
||||
ctx.eventData.subscription.quantity = 3
|
||||
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'new_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-started',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 3,
|
||||
is_trial: false,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'active'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
false
|
||||
)
|
||||
})
|
||||
|
||||
it('with updated_subscription_notification', async function () {
|
||||
this.planCode = 'new-plan-code'
|
||||
this.eventData.subscription.plan.plan_code = this.planCode
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with updated_subscription_notification', async function (ctx) {
|
||||
ctx.planCode = 'new-plan-code'
|
||||
ctx.eventData.subscription.plan.plan_code = ctx.planCode
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'updated_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-updated',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-plan-code',
|
||||
this.planCode
|
||||
ctx.planCode
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'active'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('with updated_subscription_notification with customerio integration enabled', async function () {
|
||||
this.SplitTestHandler.promises.hasUserBeenAssignedToVariant.resolves(true)
|
||||
this.planCode = 'new-plan-code'
|
||||
this.eventData.subscription.plan.plan_code = this.planCode
|
||||
it('with updated_subscription_notification with customerio integration enabled', async function (ctx) {
|
||||
ctx.SplitTestHandler.promises.hasUserBeenAssignedToVariant.resolves(true)
|
||||
ctx.planCode = 'new-plan-code'
|
||||
ctx.eventData.subscription.plan.plan_code = ctx.planCode
|
||||
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'updated_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-updated',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': true,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-plan-code',
|
||||
this.planCode
|
||||
ctx.planCode
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'active'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('with canceled_subscription_notification', async function () {
|
||||
this.eventData.subscription.state = 'cancelled'
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with canceled_subscription_notification', async function (ctx) {
|
||||
ctx.eventData.subscription.state = 'cancelled'
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'canceled_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-cancelled',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'cancelled'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('with expired_subscription_notification', async function () {
|
||||
this.eventData.subscription.state = 'expired'
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with expired_subscription_notification', async function (ctx) {
|
||||
ctx.eventData.subscription.state = 'expired'
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'expired_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-expired',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-plan-code',
|
||||
this.planCode
|
||||
ctx.planCode
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-state',
|
||||
'expired'
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-is-trial',
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('with renewed_subscription_notification', async function () {
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with renewed_subscription_notification', async function (ctx) {
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'renewed_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-renewed',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
is_trial: true,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('with reactivated_account_notification', async function () {
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with reactivated_account_notification', async function (ctx) {
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'reactivated_account_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-reactivated',
|
||||
{
|
||||
plan_code: this.planCode,
|
||||
plan_code: ctx.planCode,
|
||||
quantity: 1,
|
||||
has_ai_add_on: false,
|
||||
subscriptionId: this.eventData.subscription.uuid,
|
||||
subscriptionId: ctx.eventData.subscription.uuid,
|
||||
payment_provider: 'recurly',
|
||||
'customerio-integration': false,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('with paid_charge_invoice_notification', async function () {
|
||||
it('with paid_charge_invoice_notification', async function (ctx) {
|
||||
const invoice = {
|
||||
invoice_number: 1234,
|
||||
currency: 'USD',
|
||||
@@ -390,18 +411,18 @@ describe('RecurlyEventHandler', function () {
|
||||
collection_method: 'automatic',
|
||||
subscription_ids: ['abcd1234', 'defa3214'],
|
||||
}
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'paid_charge_invoice_notification',
|
||||
{
|
||||
account: {
|
||||
account_code: this.userId,
|
||||
account_code: ctx.userId,
|
||||
},
|
||||
invoice,
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-invoice-collected',
|
||||
{
|
||||
invoiceNumber: invoice.invoice_number,
|
||||
@@ -417,12 +438,12 @@ describe('RecurlyEventHandler', function () {
|
||||
)
|
||||
})
|
||||
|
||||
it('with paid_charge_invoice_notification and total_in_cents 0', async function () {
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with paid_charge_invoice_notification and total_in_cents 0', async function (ctx) {
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'paid_charge_invoice_notification',
|
||||
{
|
||||
account: {
|
||||
account_code: this.userId,
|
||||
account_code: ctx.userId,
|
||||
},
|
||||
invoice: {
|
||||
state: 'paid',
|
||||
@@ -430,15 +451,15 @@ describe('RecurlyEventHandler', function () {
|
||||
},
|
||||
}
|
||||
)
|
||||
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
|
||||
sinon.assert.notCalled(ctx.AnalyticsManager.recordEventForUserInBackground)
|
||||
})
|
||||
|
||||
it('with closed_invoice_notification', async function () {
|
||||
await this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with closed_invoice_notification', async function (ctx) {
|
||||
await ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'closed_invoice_notification',
|
||||
{
|
||||
account: {
|
||||
account_code: this.userId,
|
||||
account_code: ctx.userId,
|
||||
},
|
||||
invoice: {
|
||||
state: 'collected',
|
||||
@@ -447,18 +468,18 @@ describe('RecurlyEventHandler', function () {
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUserInBackground,
|
||||
this.userId,
|
||||
ctx.AnalyticsManager.recordEventForUserInBackground,
|
||||
ctx.userId,
|
||||
'subscription-invoice-collected'
|
||||
)
|
||||
})
|
||||
|
||||
it('with closed_invoice_notification and total_in_cents 0', function () {
|
||||
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
it('with closed_invoice_notification and total_in_cents 0', function (ctx) {
|
||||
ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'closed_invoice_notification',
|
||||
{
|
||||
account: {
|
||||
account_code: this.userId,
|
||||
account_code: ctx.userId,
|
||||
},
|
||||
invoice: {
|
||||
state: 'collected',
|
||||
@@ -466,25 +487,25 @@ describe('RecurlyEventHandler', function () {
|
||||
},
|
||||
}
|
||||
)
|
||||
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
|
||||
sinon.assert.notCalled(ctx.AnalyticsManager.recordEventForUserInBackground)
|
||||
})
|
||||
|
||||
it('nothing is called with invalid account code', function () {
|
||||
this.eventData.account.account_code = 'foo_bar'
|
||||
it('nothing is called with invalid account code', function (ctx) {
|
||||
ctx.eventData.account.account_code = 'foo_bar'
|
||||
|
||||
this.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
ctx.RecurlyEventHandler.sendRecurlyAnalyticsEvent(
|
||||
'new_subscription_notification',
|
||||
this.eventData
|
||||
ctx.eventData
|
||||
)
|
||||
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUserInBackground)
|
||||
sinon.assert.notCalled(ctx.AnalyticsManager.recordEventForUserInBackground)
|
||||
sinon.assert.notCalled(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground
|
||||
)
|
||||
sinon.assert.notCalled(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground
|
||||
)
|
||||
sinon.assert.notCalled(
|
||||
this.AnalyticsManager.setUserPropertyForUserInBackground
|
||||
ctx.AnalyticsManager.setUserPropertyForUserInBackground
|
||||
)
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
import { vi, expect } from 'vitest'
|
||||
import sinon from 'sinon'
|
||||
import ProjectHelper from '../../../../app/src/Features/Project/ProjectHelper.js'
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Templates/TemplatesController.mjs'
|
||||
|
||||
describe('TemplatesController', function () {
|
||||
beforeEach(async function (ctx) {
|
||||
ctx.user_id = 'user-id'
|
||||
|
||||
vi.doMock('../../../../app/src/Features/Project/ProjectHelper', () => ({
|
||||
default: ProjectHelper,
|
||||
}))
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Authentication/AuthenticationController',
|
||||
() => ({
|
||||
default: (ctx.AuthenticationController = {
|
||||
getLoggedInUserId: sinon.stub().returns(ctx.user_id),
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Templates/TemplatesManager',
|
||||
() => ({
|
||||
default: (ctx.TemplatesManager = {
|
||||
promises: { createProjectFromV1Template: sinon.stub() },
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/SplitTests/SplitTestHandler',
|
||||
() => ({
|
||||
default: (ctx.SplitTestHandler = {
|
||||
promises: {
|
||||
getAssignment: sinon.stub().resolves({ variant: 'default' }),
|
||||
},
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
ctx.TemplatesController = (await import(modulePath)).default
|
||||
ctx.next = sinon.stub()
|
||||
ctx.req = {
|
||||
body: {
|
||||
brandVariationId: 'brand-variation-id',
|
||||
compiler: 'compiler',
|
||||
mainFile: 'main-file',
|
||||
templateId: 'template-id',
|
||||
templateName: 'template-name',
|
||||
templateVersionId: 'template-version-id',
|
||||
},
|
||||
session: {
|
||||
templateData: 'template-data',
|
||||
user: {
|
||||
_id: ctx.user_id,
|
||||
},
|
||||
},
|
||||
}
|
||||
return (ctx.res = { redirect: sinon.stub() })
|
||||
})
|
||||
|
||||
describe('createProjectFromV1Template', function () {
|
||||
describe('on success', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.project = { _id: 'project-id' }
|
||||
ctx.TemplatesManager.promises.createProjectFromV1Template.resolves(
|
||||
ctx.project
|
||||
)
|
||||
return ctx.TemplatesController.createProjectFromV1Template(
|
||||
ctx.req,
|
||||
ctx.res,
|
||||
ctx.next
|
||||
)
|
||||
})
|
||||
|
||||
it('should call TemplatesManager', function (ctx) {
|
||||
return ctx.TemplatesManager.promises.createProjectFromV1Template.should.have.been.calledWithMatch(
|
||||
'brand-variation-id',
|
||||
'compiler',
|
||||
'main-file',
|
||||
'template-id',
|
||||
'template-name',
|
||||
'template-version-id',
|
||||
'user-id'
|
||||
)
|
||||
})
|
||||
|
||||
it('should redirect to project', function (ctx) {
|
||||
return ctx.res.redirect.should.have.been.calledWith(
|
||||
'/project/project-id'
|
||||
)
|
||||
})
|
||||
|
||||
it('should delete session', function (ctx) {
|
||||
return expect(ctx.req.session.templateData).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
describe('on error', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.TemplatesManager.promises.createProjectFromV1Template.rejects(
|
||||
'error'
|
||||
)
|
||||
return ctx.TemplatesController.createProjectFromV1Template(
|
||||
ctx.req,
|
||||
ctx.res,
|
||||
ctx.next
|
||||
)
|
||||
})
|
||||
|
||||
it('should call next with error', function (ctx) {
|
||||
return ctx.next.should.have.been.calledWithMatch(
|
||||
sinon.match.instanceOf(Error)
|
||||
)
|
||||
})
|
||||
|
||||
it('should not redirect', function (ctx) {
|
||||
return ctx.res.redirect.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,108 +0,0 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { expect } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const ProjectHelper = require('../../../../app/src/Features/Project/ProjectHelper')
|
||||
|
||||
const modulePath = '../../../../app/src/Features/Templates/TemplatesController'
|
||||
|
||||
describe('TemplatesController', function () {
|
||||
beforeEach(function () {
|
||||
this.user_id = 'user-id'
|
||||
this.TemplatesController = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'../Project/ProjectHelper': ProjectHelper,
|
||||
'../Authentication/AuthenticationController':
|
||||
(this.AuthenticationController = {
|
||||
getLoggedInUserId: sinon.stub().returns(this.user_id),
|
||||
}),
|
||||
'./TemplatesManager': (this.TemplatesManager = {
|
||||
promises: { createProjectFromV1Template: sinon.stub() },
|
||||
}),
|
||||
'../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
|
||||
promises: {
|
||||
getAssignment: sinon.stub().resolves({ variant: 'default' }),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
this.next = sinon.stub()
|
||||
this.req = {
|
||||
body: {
|
||||
brandVariationId: 'brand-variation-id',
|
||||
compiler: 'compiler',
|
||||
mainFile: 'main-file',
|
||||
templateId: 'template-id',
|
||||
templateName: 'template-name',
|
||||
templateVersionId: 'template-version-id',
|
||||
},
|
||||
session: {
|
||||
templateData: 'template-data',
|
||||
user: {
|
||||
_id: this.user_id,
|
||||
},
|
||||
},
|
||||
}
|
||||
return (this.res = { redirect: sinon.stub() })
|
||||
})
|
||||
|
||||
describe('createProjectFromV1Template', function () {
|
||||
describe('on success', function () {
|
||||
beforeEach(function () {
|
||||
this.project = { _id: 'project-id' }
|
||||
this.TemplatesManager.promises.createProjectFromV1Template.resolves(
|
||||
this.project
|
||||
)
|
||||
return this.TemplatesController.createProjectFromV1Template(
|
||||
this.req,
|
||||
this.res,
|
||||
this.next
|
||||
)
|
||||
})
|
||||
|
||||
it('should call TemplatesManager', function () {
|
||||
return this.TemplatesManager.promises.createProjectFromV1Template.should.have.been.calledWithMatch(
|
||||
'brand-variation-id',
|
||||
'compiler',
|
||||
'main-file',
|
||||
'template-id',
|
||||
'template-name',
|
||||
'template-version-id',
|
||||
'user-id'
|
||||
)
|
||||
})
|
||||
|
||||
it('should redirect to project', function () {
|
||||
return this.res.redirect.should.have.been.calledWith(
|
||||
'/project/project-id'
|
||||
)
|
||||
})
|
||||
|
||||
it('should delete session', function () {
|
||||
return expect(this.req.session.templateData).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
describe('on error', function () {
|
||||
beforeEach(function () {
|
||||
this.TemplatesManager.promises.createProjectFromV1Template.rejects(
|
||||
'error'
|
||||
)
|
||||
return this.TemplatesController.createProjectFromV1Template(
|
||||
this.req,
|
||||
this.res,
|
||||
this.next
|
||||
)
|
||||
})
|
||||
|
||||
it('should call next with error', function () {
|
||||
return this.next.should.have.been.calledWithMatch(
|
||||
sinon.match.instanceOf(Error)
|
||||
)
|
||||
})
|
||||
|
||||
it('should not redirect', function () {
|
||||
return this.res.redirect.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user