|
@@ -1,13 +1,16 @@
|
|
|
-import { promiseMapWithLimit } from '@overleaf/promise-utils'
|
|
|
|
|
|
|
+// @ts-check
|
|
|
import Settings from '@overleaf/settings'
|
|
import Settings from '@overleaf/settings'
|
|
|
-import { waitForDb, db } from '../app/src/infrastructure/mongodb.mjs'
|
|
|
|
|
|
|
+import { waitForDb, db, ObjectId } from '../app/src/infrastructure/mongodb.mjs'
|
|
|
import GracefulShutdown from '../app/src/infrastructure/GracefulShutdown.mjs'
|
|
import GracefulShutdown from '../app/src/infrastructure/GracefulShutdown.mjs'
|
|
|
import UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.mjs'
|
|
import UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.mjs'
|
|
|
|
|
+import { Subscription } from '../app/src/models/Subscription.mjs'
|
|
|
import minimist from 'minimist'
|
|
import minimist from 'minimist'
|
|
|
import {
|
|
import {
|
|
|
createProjectWithOldHistoryId,
|
|
createProjectWithOldHistoryId,
|
|
|
provisionSplitTests,
|
|
provisionSplitTests,
|
|
|
} from './e2e_test_setup.mjs'
|
|
} from './e2e_test_setup.mjs'
|
|
|
|
|
+import { Project } from '../app/src/models/Project.mjs'
|
|
|
|
|
+import OError from '@overleaf/o-error'
|
|
|
|
|
|
|
|
const { email: USER_EMAIL, password: PASSWORD } = minimist(
|
|
const { email: USER_EMAIL, password: PASSWORD } = minimist(
|
|
|
process.argv.slice(2),
|
|
process.argv.slice(2),
|
|
@@ -16,9 +19,17 @@ const { email: USER_EMAIL, password: PASSWORD } = minimist(
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* @param {string} email
|
|
* @param {string} email
|
|
|
|
|
+ * @param {Object} opts
|
|
|
|
|
+ * @param {boolean?} opts.isAdmin
|
|
|
|
|
+ * @param {boolean?} opts.forceProfessional
|
|
|
* @return {Promise<string>}
|
|
* @return {Promise<string>}
|
|
|
*/
|
|
*/
|
|
|
-async function createUser(email) {
|
|
|
|
|
|
|
+async function createUser(
|
|
|
|
|
+ email,
|
|
|
|
|
+ opts = { isAdmin: false, forceProfessional: false }
|
|
|
|
|
+) {
|
|
|
|
|
+ const { isAdmin = false, forceProfessional = false } = opts
|
|
|
|
|
+ /** @type {import('mongodb-legacy').ObjectId} */
|
|
|
let userId
|
|
let userId
|
|
|
try {
|
|
try {
|
|
|
const user = await UserRegistrationHandler.promises.registerNewUser({
|
|
const user = await UserRegistrationHandler.promises.registerNewUser({
|
|
@@ -27,16 +38,19 @@ async function createUser(email) {
|
|
|
})
|
|
})
|
|
|
userId = user._id
|
|
userId = user._id
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
- if (err.message.includes('EmailAlreadyRegistered')) {
|
|
|
|
|
|
|
+ if (
|
|
|
|
|
+ err instanceof OError &&
|
|
|
|
|
+ err.message.includes('EmailAlreadyRegistered') &&
|
|
|
|
|
+ err.info &&
|
|
|
|
|
+ 'userId' in err.info &&
|
|
|
|
|
+ err.info.userId instanceof ObjectId
|
|
|
|
|
+ ) {
|
|
|
userId = err.info.userId
|
|
userId = err.info.userId
|
|
|
} else {
|
|
} else {
|
|
|
throw err
|
|
throw err
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- const features = email.startsWith('free')
|
|
|
|
|
- ? Settings.defaultFeatures
|
|
|
|
|
- : Settings.features.professional
|
|
|
|
|
- const isAdmin = email === USER_EMAIL || email === 'admin@overleaf.com'
|
|
|
|
|
|
|
+ /** @type {string[]} */
|
|
|
let adminRoles = []
|
|
let adminRoles = []
|
|
|
if (isAdmin) {
|
|
if (isAdmin) {
|
|
|
adminRoles = ['engineering']
|
|
adminRoles = ['engineering']
|
|
@@ -48,34 +62,84 @@ async function createUser(email) {
|
|
|
// Set admin flag.
|
|
// Set admin flag.
|
|
|
isAdmin,
|
|
isAdmin,
|
|
|
adminRoles,
|
|
adminRoles,
|
|
|
- // Override features.
|
|
|
|
|
- features,
|
|
|
|
|
- featuresOverrides: [{ features }],
|
|
|
|
|
// disable AI features, does not work with custom GH Code Spaces domain.
|
|
// disable AI features, does not work with custom GH Code Spaces domain.
|
|
|
'aiFeatures.enabled': false,
|
|
'aiFeatures.enabled': false,
|
|
|
|
|
+ // Override features.
|
|
|
|
|
+ ...(forceProfessional
|
|
|
|
|
+ ? {
|
|
|
|
|
+ features: Settings.features.professional,
|
|
|
|
|
+ featuresOverrides: [{ features: Settings.features.professional }],
|
|
|
|
|
+ }
|
|
|
|
|
+ : {}),
|
|
|
},
|
|
},
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
return userId.toString()
|
|
return userId.toString()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * @param {string} email
|
|
|
|
|
- * @return {Promise<void>}
|
|
|
|
|
- */
|
|
|
|
|
-async function provisionUser(email) {
|
|
|
|
|
- const userId = await createUser(email)
|
|
|
|
|
- await createProjectWithOldHistoryId(userId)
|
|
|
|
|
|
|
+async function provisionUsers() {
|
|
|
|
|
+ await Promise.all([
|
|
|
|
|
+ createUser(USER_EMAIL, { isAdmin: true, forceProfessional: true }),
|
|
|
|
|
+ createUser('admin@overleaf.com', {
|
|
|
|
|
+ isAdmin: true,
|
|
|
|
|
+ forceProfessional: true,
|
|
|
|
|
+ }),
|
|
|
|
|
+ createUser('free@overleaf.com'),
|
|
|
|
|
+ createUser('premium@overleaf.com').then(async userId => {
|
|
|
|
|
+ const subscription = new Subscription({
|
|
|
|
|
+ admin_id: userId,
|
|
|
|
|
+ member_ids: [userId],
|
|
|
|
|
+ manager_ids: [userId],
|
|
|
|
|
+ planCode: 'professional',
|
|
|
|
|
+ customAccount: true,
|
|
|
|
|
+ })
|
|
|
|
|
+ try {
|
|
|
|
|
+ await subscription.save()
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ if (!isAlreadyExistsErr(err)) throw err // ignore already exists error
|
|
|
|
|
+ }
|
|
|
|
|
+ }),
|
|
|
|
|
+ createUser('group-owner@overleaf.com').then(async userId => {
|
|
|
|
|
+ const memberId = await createUser('group-member@overleaf.com')
|
|
|
|
|
+ const subscription = new Subscription({
|
|
|
|
|
+ admin_id: userId,
|
|
|
|
|
+ member_ids: [memberId],
|
|
|
|
|
+ manager_ids: [userId],
|
|
|
|
|
+ groupPlan: true,
|
|
|
|
|
+ planCode: 'group_professional_10_enterprise',
|
|
|
|
|
+ membersLimit: 10,
|
|
|
|
|
+ teamName: 'Test Team',
|
|
|
|
|
+ customAccount: true,
|
|
|
|
|
+ })
|
|
|
|
|
+ try {
|
|
|
|
|
+ await subscription.save()
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ if (!isAlreadyExistsErr(err)) throw err // ignore already exists error
|
|
|
|
|
+ }
|
|
|
|
|
+ }),
|
|
|
|
|
+ createUser('with-old-history@overleaf.com', {
|
|
|
|
|
+ isAdmin: true,
|
|
|
|
|
+ forceProfessional: true,
|
|
|
|
|
+ }).then(async userId => {
|
|
|
|
|
+ const projectName = 'old history id (Uses v1 postgres storage)'
|
|
|
|
|
+ const ownedProjects = await Project.find(
|
|
|
|
|
+ { owner_ref: userId },
|
|
|
|
|
+ { name: true }
|
|
|
|
|
+ ).exec()
|
|
|
|
|
+ for (const project of ownedProjects) {
|
|
|
|
|
+ if (project.name === projectName) return
|
|
|
|
|
+ }
|
|
|
|
|
+ await createProjectWithOldHistoryId(userId, projectName)
|
|
|
|
|
+ }),
|
|
|
|
|
+ ])
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-async function provisionUsers() {
|
|
|
|
|
- const emails = [
|
|
|
|
|
- USER_EMAIL,
|
|
|
|
|
- 'admin@overleaf.com',
|
|
|
|
|
- 'free@overleaf.com',
|
|
|
|
|
- 'premium@overleaf.com',
|
|
|
|
|
- ]
|
|
|
|
|
- await promiseMapWithLimit(5, emails, provisionUser)
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @param {unknown} err
|
|
|
|
|
+ * @return {boolean}
|
|
|
|
|
+ */
|
|
|
|
|
+function isAlreadyExistsErr(err) {
|
|
|
|
|
+ return err instanceof Error && 'code' in err && err.code === 11000
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function main() {
|
|
async function main() {
|
|
@@ -83,7 +147,7 @@ async function main() {
|
|
|
throw new Error('only available in dev-env')
|
|
throw new Error('only available in dev-env')
|
|
|
}
|
|
}
|
|
|
await waitForDb()
|
|
await waitForDb()
|
|
|
- await Promise.all([provisionUsers(), provisionSplitTests()])
|
|
|
|
|
|
|
+ await Promise.all([provisionUsers(), provisionSplitTests(true)])
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (import.meta.main) {
|
|
if (import.meta.main) {
|