mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-02 05:41:33 +02:00
[github] code spaces: tweaks from initial feedback (#32834)
* [github] code spaces: add more standard users with a common password * [github] code spaces: automatically share dev-env with Overleaf org * [github] code spaces: merge split tests rather than replacing them * [github] code spaces: ts-check the setup script in web GitOrigin-RevId: 1a86ac7e0304d47e68290352f58a0e193eed1d77
This commit is contained in:
@@ -39,6 +39,10 @@ const UserRegistrationHandler = {
|
||||
return user
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Object} userDetails
|
||||
* @return {Promise<{ _id: import('mongodb-legacy').ObjectId }>}
|
||||
*/
|
||||
async registerNewUser(userDetails) {
|
||||
const requestIsValid =
|
||||
UserRegistrationHandler._registrationRequestIsValid(userDetails)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { promiseMapWithLimit } from '@overleaf/promise-utils'
|
||||
// @ts-check
|
||||
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 UserRegistrationHandler from '../app/src/Features/User/UserRegistrationHandler.mjs'
|
||||
import { Subscription } from '../app/src/models/Subscription.mjs'
|
||||
import minimist from 'minimist'
|
||||
import {
|
||||
createProjectWithOldHistoryId,
|
||||
provisionSplitTests,
|
||||
} 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(
|
||||
process.argv.slice(2),
|
||||
@@ -16,9 +19,17 @@ const { email: USER_EMAIL, password: PASSWORD } = minimist(
|
||||
|
||||
/**
|
||||
* @param {string} email
|
||||
* @param {Object} opts
|
||||
* @param {boolean?} opts.isAdmin
|
||||
* @param {boolean?} opts.forceProfessional
|
||||
* @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
|
||||
try {
|
||||
const user = await UserRegistrationHandler.promises.registerNewUser({
|
||||
@@ -27,16 +38,19 @@ async function createUser(email) {
|
||||
})
|
||||
userId = user._id
|
||||
} 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
|
||||
} else {
|
||||
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 = []
|
||||
if (isAdmin) {
|
||||
adminRoles = ['engineering']
|
||||
@@ -48,34 +62,84 @@ async function createUser(email) {
|
||||
// Set admin flag.
|
||||
isAdmin,
|
||||
adminRoles,
|
||||
// Override features.
|
||||
features,
|
||||
featuresOverrides: [{ features }],
|
||||
// disable AI features, does not work with custom GH Code Spaces domain.
|
||||
'aiFeatures.enabled': false,
|
||||
// Override features.
|
||||
...(forceProfessional
|
||||
? {
|
||||
features: Settings.features.professional,
|
||||
featuresOverrides: [{ features: Settings.features.professional }],
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
)
|
||||
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() {
|
||||
@@ -83,7 +147,7 @@ async function main() {
|
||||
throw new Error('only available in dev-env')
|
||||
}
|
||||
await waitForDb()
|
||||
await Promise.all([provisionUsers(), provisionSplitTests()])
|
||||
await Promise.all([provisionUsers(), provisionSplitTests(true)])
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
|
||||
@@ -85,8 +85,10 @@ async function deleteUser(email) {
|
||||
await UserDeleter.promises.expireDeletedUser(user._id)
|
||||
}
|
||||
|
||||
export async function createProjectWithOldHistoryId(userId) {
|
||||
const projectName = 'old history id'
|
||||
export async function createProjectWithOldHistoryId(
|
||||
userId,
|
||||
projectName = 'old history id'
|
||||
) {
|
||||
const historyId = parseInt(
|
||||
await HistoryManager.promises.initializeProject(),
|
||||
10
|
||||
@@ -137,7 +139,7 @@ async function purgeNewUsers() {
|
||||
)
|
||||
}
|
||||
|
||||
export async function provisionSplitTests() {
|
||||
export async function provisionSplitTests(merge = false) {
|
||||
const backup = Path.join(
|
||||
MONOREPO,
|
||||
'backup',
|
||||
@@ -181,7 +183,11 @@ export async function provisionSplitTests() {
|
||||
],
|
||||
})
|
||||
console.log(`> Importing ${SPLIT_TESTS.length} split-tests from production.`)
|
||||
await SplitTestManager.replaceSplitTests(SPLIT_TESTS)
|
||||
if (merge) {
|
||||
await SplitTestManager.mergeSplitTests(SPLIT_TESTS, false)
|
||||
} else {
|
||||
await SplitTestManager.replaceSplitTests(SPLIT_TESTS)
|
||||
}
|
||||
}
|
||||
|
||||
async function checkNoTableScan() {
|
||||
|
||||
Reference in New Issue
Block a user