devcontainer_setup.mjs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // @ts-check
  2. import Settings from '@overleaf/settings'
  3. import { waitForDb, db, ObjectId } from '../app/src/infrastructure/mongodb.mjs'
  4. import GracefulShutdown from '../app/src/infrastructure/GracefulShutdown.mjs'
  5. import UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.mjs'
  6. import { Subscription } from '../app/src/models/Subscription.mjs'
  7. import minimist from 'minimist'
  8. import {
  9. createProjectWithOldHistoryId,
  10. provisionSplitTests,
  11. } from './e2e_test_setup.mjs'
  12. import { Project } from '../app/src/models/Project.mjs'
  13. import OError from '@overleaf/o-error'
  14. const { email: USER_EMAIL, password: PASSWORD } = minimist(
  15. process.argv.slice(2),
  16. { string: ['email', 'password'] }
  17. )
  18. /**
  19. * @param {string} email
  20. * @param {Object} opts
  21. * @param {boolean?} opts.isAdmin
  22. * @param {boolean?} opts.forceProfessional
  23. * @return {Promise<string>}
  24. */
  25. async function createUser(
  26. email,
  27. opts = { isAdmin: false, forceProfessional: false }
  28. ) {
  29. const { isAdmin = false, forceProfessional = false } = opts
  30. /** @type {import('mongodb-legacy').ObjectId} */
  31. let userId
  32. try {
  33. const user = await UserRegistrationHandler.promises.registerNewUser({
  34. email,
  35. password: PASSWORD,
  36. })
  37. userId = user._id
  38. } catch (err) {
  39. if (
  40. err instanceof OError &&
  41. err.message.includes('EmailAlreadyRegistered') &&
  42. err.info &&
  43. 'userId' in err.info &&
  44. err.info.userId instanceof ObjectId
  45. ) {
  46. userId = err.info.userId
  47. } else {
  48. throw err
  49. }
  50. }
  51. /** @type {string[]} */
  52. let adminRoles = []
  53. if (isAdmin) {
  54. adminRoles = ['engineering']
  55. }
  56. await db.users.updateOne(
  57. { _id: userId },
  58. {
  59. $set: {
  60. // Set admin flag.
  61. isAdmin,
  62. adminRoles,
  63. // disable AI features, does not work with custom GH Code Spaces domain.
  64. 'aiFeatures.enabled': false,
  65. // Override features.
  66. ...(forceProfessional
  67. ? {
  68. features: Settings.features.professional,
  69. featuresOverrides: [{ features: Settings.features.professional }],
  70. }
  71. : {}),
  72. },
  73. }
  74. )
  75. return userId.toString()
  76. }
  77. async function provisionUsers() {
  78. await Promise.all([
  79. createUser(USER_EMAIL, { isAdmin: true, forceProfessional: true }),
  80. createUser('admin@overleaf.com', {
  81. isAdmin: true,
  82. forceProfessional: true,
  83. }),
  84. createUser('free@overleaf.com'),
  85. createUser('premium@overleaf.com').then(async userId => {
  86. const subscription = new Subscription({
  87. admin_id: userId,
  88. member_ids: [userId],
  89. manager_ids: [userId],
  90. planCode: 'professional',
  91. customAccount: true,
  92. })
  93. try {
  94. await subscription.save()
  95. } catch (err) {
  96. if (!isAlreadyExistsErr(err)) throw err // ignore already exists error
  97. }
  98. }),
  99. createUser('group-owner@overleaf.com').then(async userId => {
  100. const memberId = await createUser('group-member@overleaf.com')
  101. const subscription = new Subscription({
  102. admin_id: userId,
  103. member_ids: [memberId],
  104. manager_ids: [userId],
  105. groupPlan: true,
  106. planCode: 'group_professional_10_enterprise',
  107. membersLimit: 10,
  108. teamName: 'Test Team',
  109. customAccount: true,
  110. })
  111. try {
  112. await subscription.save()
  113. } catch (err) {
  114. if (!isAlreadyExistsErr(err)) throw err // ignore already exists error
  115. }
  116. }),
  117. createUser('with-old-history@overleaf.com', {
  118. isAdmin: true,
  119. forceProfessional: true,
  120. }).then(async userId => {
  121. const projectName = 'old history id (Uses v1 postgres storage)'
  122. const ownedProjects = await Project.find(
  123. { owner_ref: userId },
  124. { name: true }
  125. ).exec()
  126. for (const project of ownedProjects) {
  127. if (project.name === projectName) return
  128. }
  129. await createProjectWithOldHistoryId(userId, projectName)
  130. }),
  131. ])
  132. }
  133. /**
  134. * @param {unknown} err
  135. * @return {boolean}
  136. */
  137. function isAlreadyExistsErr(err) {
  138. return err instanceof Error && 'code' in err && err.code === 11000
  139. }
  140. async function main() {
  141. if (process.env.NODE_ENV !== 'development') {
  142. throw new Error('only available in dev-env')
  143. }
  144. await waitForDb()
  145. await Promise.all([provisionUsers(), provisionSplitTests(true)])
  146. }
  147. if (import.meta.main) {
  148. await main()
  149. await GracefulShutdown.gracefulShutdown()
  150. }