[web] Upgrade Prettier to match version in monorepo root (#6231)

GitOrigin-RevId: 02f97af1b9704782eee77a0b7dfc477ada23e34d
This commit is contained in:
Alf Eaton
2022-01-10 10:23:05 +00:00
committed by Copybot
parent f3f0be5c56
commit 50df230846
153 changed files with 2151 additions and 2232 deletions
+8 -4
View File
@@ -15,10 +15,14 @@ const Settings = require('@overleaf/settings')
const logger = require('@overleaf/logger')
const PlansLocator = require('./app/src/Features/Subscription/PlansLocator')
logger.initialize(process.env.METRICS_APP_NAME || 'web')
logger.logger.serializers.user = require('./app/src/infrastructure/LoggerSerializers').user
logger.logger.serializers.docs = require('./app/src/infrastructure/LoggerSerializers').docs
logger.logger.serializers.files = require('./app/src/infrastructure/LoggerSerializers').files
logger.logger.serializers.project = require('./app/src/infrastructure/LoggerSerializers').project
logger.logger.serializers.user =
require('./app/src/infrastructure/LoggerSerializers').user
logger.logger.serializers.docs =
require('./app/src/infrastructure/LoggerSerializers').docs
logger.logger.serializers.files =
require('./app/src/infrastructure/LoggerSerializers').files
logger.logger.serializers.project =
require('./app/src/infrastructure/LoggerSerializers').project
if ((Settings.sentry != null ? Settings.sentry.dsn : undefined) != null) {
logger.initializeErrorReporting(Settings.sentry.dsn)
}
@@ -80,10 +80,11 @@ async function getPrivilegeLevelForProjectWithUser(
token,
opts = {}
) {
const privilegeLevel = await CollaboratorsGetter.promises.getMemberIdPrivilegeLevel(
userId,
projectId
)
const privilegeLevel =
await CollaboratorsGetter.promises.getMemberIdPrivilegeLevel(
userId,
projectId
)
if (privilegeLevel && privilegeLevel !== PrivilegeLevels.NONE) {
// The user has direct access
return privilegeLevel
@@ -140,13 +141,11 @@ async function getPrivilegeLevelForProjectWithToken(projectId, token) {
// Anonymous users can have read-only access to token-based projects,
// while read-write access must be logged in,
// unless the `enableAnonymousReadAndWriteSharing` setting is enabled
const {
isValidReadAndWrite,
isValidReadOnly,
} = await TokenAccessHandler.promises.validateTokenForAnonymousAccess(
projectId,
token
)
const { isValidReadAndWrite, isValidReadOnly } =
await TokenAccessHandler.promises.validateTokenForAnonymousAccess(
projectId,
token
)
if (isValidReadOnly) {
// Grant anonymous user read-only access
return PrivilegeLevels.READ_ONLY
@@ -29,11 +29,12 @@ async function blockRestrictedUserFromProject(req, res, next) {
const projectId = _getProjectId(req)
const userId = _getUserId(req)
const token = TokenAccessHandler.getRequestToken(req, projectId)
const isRestrictedUser = await AuthorizationManager.promises.isRestrictedUserForProject(
userId,
projectId,
token
)
const isRestrictedUser =
await AuthorizationManager.promises.isRestrictedUserForProject(
userId,
projectId,
token
)
if (isRestrictedUser) {
return HttpErrorHandler.forbidden(req, res)
}
@@ -75,11 +76,12 @@ async function ensureUserCanWriteProjectSettings(req, res, next) {
const otherParams = Object.keys(req.body).filter(x => x !== 'name')
if (otherParams.length > 0) {
const canWrite = await AuthorizationManager.promises.canUserWriteProjectSettings(
userId,
projectId,
token
)
const canWrite =
await AuthorizationManager.promises.canUserWriteProjectSettings(
userId,
projectId,
token
)
if (!canWrite) {
return HttpErrorHandler.forbidden(req, res)
}
@@ -92,11 +94,12 @@ async function ensureUserCanWriteProjectContent(req, res, next) {
const projectId = _getProjectId(req)
const userId = _getUserId(req)
const token = TokenAccessHandler.getRequestToken(req, projectId)
const canWrite = await AuthorizationManager.promises.canUserWriteProjectContent(
userId,
projectId,
token
)
const canWrite =
await AuthorizationManager.promises.canUserWriteProjectContent(
userId,
projectId,
token
)
if (canWrite) {
logger.log(
{ userId, projectId },
@@ -50,8 +50,7 @@ module.exports = CaptchaMiddleware = {
return res.status(400).send({
errorReason: 'cannot_verify_user_not_robot',
message: {
text:
'Sorry, we could not verify that you are not a robot. Please check that Google reCAPTCHA is not being blocked by an ad blocker or firewall.',
text: 'Sorry, we could not verify that you are not a robot. Please check that Google reCAPTCHA is not being blocked by an ad blocker or firewall.',
},
})
} else {
@@ -132,42 +132,37 @@ async function isUserInvitedMemberOfProject(userId, projectId) {
async function getProjectsUserIsMemberOf(userId, fields) {
const limit = pLimit(2)
const [
readAndWrite,
readOnly,
tokenReadAndWrite,
tokenReadOnly,
] = await Promise.all([
limit(() => Project.find({ collaberator_refs: userId }, fields).exec()),
limit(() => Project.find({ readOnly_refs: userId }, fields).exec()),
limit(() =>
Project.find(
{
tokenAccessReadAndWrite_refs: userId,
publicAccesLevel: PublicAccessLevels.TOKEN_BASED,
},
fields
).exec()
),
limit(() =>
Project.find(
{
tokenAccessReadOnly_refs: userId,
publicAccesLevel: PublicAccessLevels.TOKEN_BASED,
},
fields
).exec()
),
])
const [readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly] =
await Promise.all([
limit(() => Project.find({ collaberator_refs: userId }, fields).exec()),
limit(() => Project.find({ readOnly_refs: userId }, fields).exec()),
limit(() =>
Project.find(
{
tokenAccessReadAndWrite_refs: userId,
publicAccesLevel: PublicAccessLevels.TOKEN_BASED,
},
fields
).exec()
),
limit(() =>
Project.find(
{
tokenAccessReadOnly_refs: userId,
publicAccesLevel: PublicAccessLevels.TOKEN_BASED,
},
fields
).exec()
),
])
return { readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly }
}
async function getAllInvitedMembers(projectId) {
try {
const rawMembers = await getInvitedMembersWithPrivilegeLevels(projectId)
const { members } = ProjectEditorHandler.buildOwnerAndMembersViews(
rawMembers
)
const { members } =
ProjectEditorHandler.buildOwnerAndMembersViews(rawMembers)
return members
} catch (err) {
throw OError.tag(err, 'error getting members for project', { projectId })
@@ -78,14 +78,10 @@ async function removeUserFromProject(projectId, userId) {
}
async function removeUserFromAllProjects(userId) {
const {
readAndWrite,
readOnly,
tokenReadAndWrite,
tokenReadOnly,
} = await CollaboratorsGetter.promises.getProjectsUserIsMemberOf(userId, {
_id: 1,
})
const { readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly } =
await CollaboratorsGetter.promises.getProjectsUserIsMemberOf(userId, {
_id: 1,
})
const allProjects = readAndWrite
.concat(readOnly)
.concat(tokenReadAndWrite)
@@ -38,9 +38,8 @@ const buildState = s =>
module.exports = ClsiStateManager = {
computeHash(project, options) {
const { docs, files } = ProjectEntityHandler.getAllEntitiesFromProject(
project
)
const { docs, files } =
ProjectEntityHandler.getAllEntitiesFromProject(project)
const fileList = Array.from(files || []).map(
f => `${f.file._id}:${f.file.rev}:${f.file.created}:${f.path}`
)
@@ -60,11 +60,8 @@ async function joinProject(req, res, next) {
userId = null
}
Metrics.inc('editor.join-project')
const {
project,
privilegeLevel,
isRestrictedUser,
} = await _buildJoinProjectView(req, projectId, userId)
const { project, privilegeLevel, isRestrictedUser } =
await _buildJoinProjectView(req, projectId, userId)
if (!project) {
return res.sendStatus(403)
}
@@ -116,15 +113,17 @@ async function _buildJoinProjectView(req, projectId, userId) {
'soft-failure when fetching deletedDocs from docstore'
)
}
const members = await CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels(
projectId
)
const members =
await CollaboratorsGetter.promises.getInvitedMembersWithPrivilegeLevels(
projectId
)
const token = TokenAccessHandler.getRequestToken(req, projectId)
const privilegeLevel = await AuthorizationManager.promises.getPrivilegeLevelForProject(
userId,
projectId,
token
)
const privilegeLevel =
await AuthorizationManager.promises.getPrivilegeLevelForProject(
userId,
projectId,
token
)
if (privilegeLevel == null || privilegeLevel === PrivilegeLevels.NONE) {
return { project: null, privilegeLevel: null, isRestrictedUser: false }
}
@@ -99,12 +99,8 @@ class SAMLSessionDataMissing extends BackwardCompatibleError {
? arg.samlSession
: {}
this.tryAgain = true
const {
universityId,
universityName,
externalUserId,
institutionEmail,
} = samlSession
const { universityId, universityName, externalUserId, institutionEmail } =
samlSession
if (
!universityId &&
@@ -27,261 +27,265 @@ let request = require('request')
request = request.defaults()
settings = require('@overleaf/settings')
module.exports = ExportsHandler = self = {
exportProject(export_params, callback) {
if (callback == null) {
callback = function () {}
}
return self._buildExport(export_params, function (err, export_data) {
if (err != null) {
return callback(err)
}
return self._requestExport(export_data, function (err, body) {
if (err != null) {
return callback(err)
module.exports =
ExportsHandler =
self =
{
exportProject(export_params, callback) {
if (callback == null) {
callback = function () {}
}
export_data.v1_id = body.exportId
export_data.message = body.message
// TODO: possibly store the export data in Mongo
return callback(null, export_data)
})
})
},
_buildExport(export_params, callback) {
if (callback == null) {
callback = function () {}
}
const {
project_id,
user_id,
brand_variation_id,
title,
description,
author,
license,
show_source,
} = export_params
const jobs = {
project(cb) {
return ProjectGetter.getProject(project_id, cb)
},
// TODO: when we update async, signature will change from (cb, results) to (results, cb)
rootDoc: [
'project',
(cb, results) =>
ProjectRootDocManager.ensureRootDocumentIsValid(
project_id,
function (error) {
if (error != null) {
return callback(error)
}
return ProjectLocator.findRootDoc(
{ project: results.project, project_id },
cb
)
return self._buildExport(export_params, function (err, export_data) {
if (err != null) {
return callback(err)
}
return self._requestExport(export_data, function (err, body) {
if (err != null) {
return callback(err)
}
),
],
user(cb) {
return UserGetter.getUser(
export_data.v1_id = body.exportId
export_data.message = body.message
// TODO: possibly store the export data in Mongo
return callback(null, export_data)
})
})
},
_buildExport(export_params, callback) {
if (callback == null) {
callback = function () {}
}
const {
project_id,
user_id,
{ first_name: 1, last_name: 1, email: 1, overleaf: 1 },
cb
brand_variation_id,
title,
description,
author,
license,
show_source,
} = export_params
const jobs = {
project(cb) {
return ProjectGetter.getProject(project_id, cb)
},
// TODO: when we update async, signature will change from (cb, results) to (results, cb)
rootDoc: [
'project',
(cb, results) =>
ProjectRootDocManager.ensureRootDocumentIsValid(
project_id,
function (error) {
if (error != null) {
return callback(error)
}
return ProjectLocator.findRootDoc(
{ project: results.project, project_id },
cb
)
}
),
],
user(cb) {
return UserGetter.getUser(
user_id,
{ first_name: 1, last_name: 1, email: 1, overleaf: 1 },
cb
)
},
historyVersion(cb) {
return ProjectHistoryHandler.ensureHistoryExistsForProject(
project_id,
function (error) {
if (error != null) {
return callback(error)
}
return self._requestVersion(project_id, cb)
}
)
},
}
return async.auto(jobs, function (err, results) {
if (err != null) {
OError.tag(err, 'error building project export', {
project_id,
user_id,
brand_variation_id,
})
return callback(err)
}
const { project, rootDoc, user, historyVersion } = results
if (!rootDoc || rootDoc[1] == null) {
err = new OError('cannot export project without root doc', {
project_id,
})
return callback(err)
}
if (export_params.first_name && export_params.last_name) {
user.first_name = export_params.first_name
user.last_name = export_params.last_name
}
const export_data = {
project: {
id: project_id,
rootDocPath:
rootDoc[1] != null ? rootDoc[1].fileSystem : undefined,
historyId: __guard__(
project.overleaf != null ? project.overleaf.history : undefined,
x => x.id
),
historyVersion,
v1ProjectId:
project.overleaf != null ? project.overleaf.id : undefined,
metadata: {
compiler: project.compiler,
imageName: project.imageName,
title,
description,
author,
license,
showSource: show_source,
},
},
user: {
id: user_id,
firstName: user.first_name,
lastName: user.last_name,
email: user.email,
orcidId: null, // until v2 gets ORCID
v1UserId: user.overleaf != null ? user.overleaf.id : undefined,
},
destination: {
brandVariationId: brand_variation_id,
},
options: {
callbackUrl: null,
}, // for now, until we want v1 to call us back
}
return callback(null, export_data)
})
},
_requestExport(export_data, callback) {
if (callback == null) {
callback = function () {}
}
return request.post(
{
url: `${settings.apis.v1.url}/api/v1/sharelatex/exports`,
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass },
json: export_data,
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to v1 export', {
export: export_data,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body)
} else {
logger.warn(
{ export: export_data },
`v1 export returned failure; forwarding: ${body}`
)
// pass the v1 error along for the publish modal to handle
const err = { forwardResponse: body }
return callback(err)
}
}
)
},
historyVersion(cb) {
return ProjectHistoryHandler.ensureHistoryExistsForProject(
project_id,
function (error) {
if (error != null) {
return callback(error)
_requestVersion(project_id, callback) {
if (callback == null) {
callback = function () {}
}
return request.get(
{
url: `${settings.apis.project_history.url}/project/${project_id}/version`,
json: true,
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to project history', {
project_id,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body.version)
} else {
err = new OError(
`project history version returned a failure status code: ${res.statusCode}`,
{ project_id }
)
return callback(err)
}
}
)
},
fetchExport(export_id, callback) {
if (callback == null) {
callback = function () {}
}
return request.get(
{
url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}`,
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass },
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to v1 export', {
export: export_id,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body)
} else {
err = new OError(
`v1 export returned a failure status code: ${res.statusCode}`,
{ export: export_id }
)
return callback(err)
}
}
)
},
fetchDownload(export_id, type, callback) {
if (callback == null) {
callback = function () {}
}
return request.get(
{
url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}/${type}_url`,
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass },
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to v1 export', {
export: export_id,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body)
} else {
err = new OError(
`v1 export returned a failure status code: ${res.statusCode}`,
{ export: export_id }
)
return callback(err)
}
return self._requestVersion(project_id, cb)
}
)
},
}
return async.auto(jobs, function (err, results) {
if (err != null) {
OError.tag(err, 'error building project export', {
project_id,
user_id,
brand_variation_id,
})
return callback(err)
}
const { project, rootDoc, user, historyVersion } = results
if (!rootDoc || rootDoc[1] == null) {
err = new OError('cannot export project without root doc', {
project_id,
})
return callback(err)
}
if (export_params.first_name && export_params.last_name) {
user.first_name = export_params.first_name
user.last_name = export_params.last_name
}
const export_data = {
project: {
id: project_id,
rootDocPath: rootDoc[1] != null ? rootDoc[1].fileSystem : undefined,
historyId: __guard__(
project.overleaf != null ? project.overleaf.history : undefined,
x => x.id
),
historyVersion,
v1ProjectId:
project.overleaf != null ? project.overleaf.id : undefined,
metadata: {
compiler: project.compiler,
imageName: project.imageName,
title,
description,
author,
license,
showSource: show_source,
},
},
user: {
id: user_id,
firstName: user.first_name,
lastName: user.last_name,
email: user.email,
orcidId: null, // until v2 gets ORCID
v1UserId: user.overleaf != null ? user.overleaf.id : undefined,
},
destination: {
brandVariationId: brand_variation_id,
},
options: {
callbackUrl: null,
}, // for now, until we want v1 to call us back
}
return callback(null, export_data)
})
},
_requestExport(export_data, callback) {
if (callback == null) {
callback = function () {}
}
return request.post(
{
url: `${settings.apis.v1.url}/api/v1/sharelatex/exports`,
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass },
json: export_data,
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to v1 export', {
export: export_data,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body)
} else {
logger.warn(
{ export: export_data },
`v1 export returned failure; forwarding: ${body}`
)
// pass the v1 error along for the publish modal to handle
const err = { forwardResponse: body }
return callback(err)
}
}
)
},
_requestVersion(project_id, callback) {
if (callback == null) {
callback = function () {}
}
return request.get(
{
url: `${settings.apis.project_history.url}/project/${project_id}/version`,
json: true,
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to project history', {
project_id,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body.version)
} else {
err = new OError(
`project history version returned a failure status code: ${res.statusCode}`,
{ project_id }
)
return callback(err)
}
}
)
},
fetchExport(export_id, callback) {
if (callback == null) {
callback = function () {}
}
return request.get(
{
url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}`,
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass },
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to v1 export', {
export: export_id,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body)
} else {
err = new OError(
`v1 export returned a failure status code: ${res.statusCode}`,
{ export: export_id }
)
return callback(err)
}
}
)
},
fetchDownload(export_id, type, callback) {
if (callback == null) {
callback = function () {}
}
return request.get(
{
url: `${settings.apis.v1.url}/api/v1/sharelatex/exports/${export_id}/${type}_url`,
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass },
},
function (err, res, body) {
if (err != null) {
OError.tag(err, 'error making request to v1 export', {
export: export_id,
})
return callback(err)
} else if (res.statusCode >= 200 && res.statusCode < 300) {
return callback(null, body)
} else {
err = new OError(
`v1 export returned a failure status code: ${res.statusCode}`,
{ export: export_id }
)
return callback(err)
}
}
)
},
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
@@ -1,5 +1,6 @@
// eslint-disable-next-line no-useless-escape
const EMAIL_REGEXP = /^([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
const EMAIL_REGEXP =
// eslint-disable-next-line no-useless-escape
/^([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
function getDomain(email) {
email = parseEmail(email)
@@ -78,16 +78,21 @@ module.exports = InactiveProjectManager = {
if (err != null) {
logger.err({ err }, 'could not get projects for deactivating')
}
const jobs = _.map(projects, project => cb =>
InactiveProjectManager.deactivateProject(project._id, function (err) {
if (err) {
logger.err(
{ project_id: project._id, err: err },
'unable to deactivate project'
)
}
cb()
})
const jobs = _.map(
projects,
project => cb =>
InactiveProjectManager.deactivateProject(
project._id,
function (err) {
if (err) {
logger.err(
{ project_id: project._id, err: err },
'unable to deactivate project'
)
}
cb()
}
)
)
logger.log(
{ numberOfProjects: projects && projects.length },
@@ -125,11 +125,8 @@ async function checkInstitutionUsers(institutionId, emitNonProUserIds) {
)
result.ssoUsers.current.entitled = entitled
const {
allSsoUsers,
allSsoUsersByIds,
currentNotEntitledCount,
} = await _getSsoUsers(institutionId, lapsedUserIds)
const { allSsoUsers, allSsoUsersByIds, currentNotEntitledCount } =
await _getSsoUsers(institutionId, lapsedUserIds)
result.ssoUsers.total = allSsoUsers.length
result.ssoUsers.current.notEntitled = currentNotEntitledCount
@@ -168,10 +168,8 @@ function _checkAuth(projectId, data, currentUserId, callback) {
function _getFileStream(linkedFileData, userId, callback) {
callback = _.once(callback)
const {
source_output_file_path: sourceOutputFilePath,
build_id: buildId,
} = linkedFileData
const { source_output_file_path: sourceOutputFilePath, build_id: buildId } =
linkedFileData
LinkedFilesHandler.getSourceProject(linkedFileData, (err, project) => {
if (err) {
return callback(err)
@@ -357,9 +357,8 @@ const ProjectController = {
if (err != null) {
return next(err)
}
const { docs, files } = ProjectEntityHandler.getAllEntitiesFromProject(
project
)
const { docs, files } =
ProjectEntityHandler.getAllEntitiesFromProject(project)
const entities = docs
.concat(files)
// Sort by path ascending
@@ -553,9 +552,8 @@ const ProjectController = {
delete req.session.saml
}
const portalTemplates = ProjectController._buildPortalTemplatesList(
userAffiliations
)
const portalTemplates =
ProjectController._buildPortalTemplatesList(userAffiliations)
const projects = ProjectController._buildProjectList(
results.projects,
userId
@@ -798,9 +796,8 @@ const ProjectController = {
req,
projectId
)
const allowedImageNames = ProjectHelper.getAllowedImagesForUser(
sessionUser
)
const allowedImageNames =
ProjectHelper.getAllowedImagesForUser(sessionUser)
AuthorizationManager.getPrivilegeLevelForProject(
userId,
@@ -1028,13 +1025,8 @@ const ProjectController = {
_buildProjectList(allProjects, userId) {
let project
const {
owned,
readAndWrite,
readOnly,
tokenReadAndWrite,
tokenReadOnly,
} = allProjects
const { owned, readAndWrite, readOnly, tokenReadAndWrite, tokenReadOnly } =
allProjects
const projects = []
for (project of owned) {
projects.push(
@@ -144,10 +144,8 @@ async function validateProjectName(name) {
// with a unique name. But that requires thinking through how we would handle incoming projects from
// dropbox for example.
async function generateUniqueName(userId, name, suffixes = []) {
const allUsersProjectNames = await ProjectGetter.promises.findAllUsersProjects(
userId,
{ name: 1 }
)
const allUsersProjectNames =
await ProjectGetter.promises.findAllUsersProjects(userId, { name: 1 })
// allUsersProjectNames is returned as a hash {owned: [name1, name2, ...], readOnly: [....]}
// collect all of the names and flatten them into a single array
const projectNameList = _.pluck(
@@ -241,6 +239,7 @@ async function _generateTokens(project, callback) {
tokens.readAndWritePrefix = numericPrefix
}
if (tokens.readOnly == null) {
tokens.readOnly = await TokenGenerator.promises.generateUniqueReadOnlyToken()
tokens.readOnly =
await TokenGenerator.promises.generateUniqueReadOnlyToken()
}
}
@@ -66,11 +66,12 @@ async function duplicate(owner, originalProjectId, newProjectName) {
_copyDocs(originalEntries.docEntries, originalProject, newProject),
_copyFiles(originalEntries.fileEntries, originalProject, newProject),
])
const projectVersion = await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure(
newProject._id,
docEntries,
fileEntries
)
const projectVersion =
await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure(
newProject._id,
docEntries,
fileEntries
)
// Silently ignore the rootDoc in case it's not valid per the new limits.
if (
rootDocPath &&
@@ -62,9 +62,8 @@ module.exports = ProjectEditorHandler = {
result.invites.forEach(invite => {
delete invite.token
})
;({ owner, ownerFeatures, members } = this.buildOwnerAndMembersViews(
members
))
;({ owner, ownerFeatures, members } =
this.buildOwnerAndMembersViews(members))
result.owner = owner
result.members = members
@@ -257,21 +257,18 @@ async function mkdirp(projectId, path, options = {}) {
for (const folderName of folders) {
builtUpPath += `/${folderName}`
try {
const {
element: foundFolder,
} = await ProjectLocator.promises.findElementByPath({
project,
path: builtUpPath,
exactCaseMatch: options.exactCaseMatch,
})
const { element: foundFolder } =
await ProjectLocator.promises.findElementByPath({
project,
path: builtUpPath,
exactCaseMatch: options.exactCaseMatch,
})
lastFolder = foundFolder
} catch (err) {
// Folder couldn't be found. Create it.
const parentFolderId = lastFolder && lastFolder._id
const {
folder: newFolder,
parentFolderId: newParentFolderId,
} = await addFolder(projectId, parentFolderId, folderName)
const { folder: newFolder, parentFolderId: newParentFolderId } =
await addFolder(projectId, parentFolderId, folderName)
newFolder.parentFolder_id = newParentFolderId
lastFolder = newFolder
newFolders.push(newFolder)
@@ -285,23 +282,19 @@ async function moveEntity(projectId, entityId, destFolderId, entityType) {
projectId,
{ rootFolder: true, name: true, overleaf: true }
)
const {
element: entity,
path: entityPath,
} = await ProjectLocator.promises.findElement({
project,
element_id: entityId,
type: entityType,
})
const { element: entity, path: entityPath } =
await ProjectLocator.promises.findElement({
project,
element_id: entityId,
type: entityType,
})
// Prevent top-level docs/files with reserved names (to match v1 behaviour)
if (_blockedFilename(entityPath, entityType)) {
throw new Errors.InvalidNameError('blocked element name')
}
await _checkValidMove(project, entityType, entity, entityPath, destFolderId)
const {
docs: oldDocs,
files: oldFiles,
} = ProjectEntityHandler.getAllEntitiesFromProject(project)
const { docs: oldDocs, files: oldFiles } =
ProjectEntityHandler.getAllEntitiesFromProject(project)
// For safety, insert the entity in the destination
// location first, and then remove the original. If
// there is an error the entity may appear twice. This
@@ -328,10 +321,8 @@ async function moveEntity(projectId, entityId, destFolderId, entityType) {
entityPath.mongo,
entityId
)
const {
docs: newDocs,
files: newFiles,
} = ProjectEntityHandler.getAllEntitiesFromProject(newProject)
const { docs: newDocs, files: newFiles } =
ProjectEntityHandler.getAllEntitiesFromProject(newProject)
const startPath = entityPath.fileSystem
const endPath = result.path.fileSystem
const changes = {
@@ -418,10 +409,8 @@ async function renameEntity(
// check if the new name already exists in the current folder
_checkValidElementName(parentFolder, newName)
const {
docs: oldDocs,
files: oldFiles,
} = ProjectEntityHandler.getAllEntitiesFromProject(project)
const { docs: oldDocs, files: oldFiles } =
ProjectEntityHandler.getAllEntitiesFromProject(project)
// we need to increment the project version number for any structure change
const newProject = await Project.findOneAndUpdate(
@@ -430,10 +419,8 @@ async function renameEntity(
{ new: true }
).exec()
const {
docs: newDocs,
files: newFiles,
} = ProjectEntityHandler.getAllEntitiesFromProject(newProject)
const { docs: newDocs, files: newFiles } =
ProjectEntityHandler.getAllEntitiesFromProject(newProject)
return {
project,
startPath,
@@ -618,14 +605,12 @@ async function _checkValidMove(
entityPath,
destFolderId
) {
const {
element: destEntity,
path: destFolderPath,
} = await ProjectLocator.promises.findElement({
project,
element_id: destFolderId,
type: 'folder',
})
const { element: destEntity, path: destFolderPath } =
await ProjectLocator.promises.findElement({
project,
element_id: destFolderId,
type: 'folder',
})
// check if there is already a doc/file/folder with the same name
// in the destination folder
_checkValidElementName(destEntity, entity.name)
@@ -1349,11 +1349,8 @@ const ProjectEntityUpdateHandler = {
return callback(error)
}
let {
docs,
files,
folders,
} = ProjectEntityHandler.getAllEntitiesFromProject(project)
let { docs, files, folders } =
ProjectEntityHandler.getAllEntitiesFromProject(project)
// _checkFileTree() must be passed the folders before docs and
// files
ProjectEntityUpdateHandler._checkFiletree(
@@ -166,8 +166,9 @@ module.exports = ReferencesHandler = {
'flushing docs to mongo before calling references service'
)
return Async.series(
docIds.map(docId => cb =>
DocumentUpdaterHandler.flushDocToMongo(projectId, docId, cb)
docIds.map(
docId => cb =>
DocumentUpdaterHandler.flushDocToMongo(projectId, docId, cb)
),
function (err) {
// continue
@@ -41,10 +41,11 @@ async function _loadAssignmentInLocals(splitTest, session, locals) {
if (cachedVariant) {
LocalsHelper.setSplitTestVariant(locals, splitTest.name, cachedVariant)
} else {
const assignment = await SplitTestV2Handler.promises.getAssignmentForSession(
session,
splitTest.name
)
const assignment =
await SplitTestV2Handler.promises.getAssignmentForSession(
session,
splitTest.name
)
session.cachedSplitTestAssignments[cacheKey] = assignment.variant
LocalsHelper.setSplitTestVariant(
locals,
@@ -138,12 +138,8 @@ async function _getAssignment(
if (splitTest) {
const currentVersion = splitTest.getCurrentVersion()
if (currentVersion.active) {
const {
activeForUser,
selectedVariantName,
phase,
versionNumber,
} = await _getAssignmentMetadata(analyticsId, userId, splitTest)
const { activeForUser, selectedVariantName, phase, versionNumber } =
await _getAssignmentMetadata(analyticsId, userId, splitTest)
if (activeForUser) {
const assignmentConfig = {
userId,
@@ -48,10 +48,8 @@ async function refreshFeatures(userId, reason) {
matchedFeatureSet
)
const {
features: newFeatures,
featuresChanged,
} = await UserFeaturesUpdater.promises.updateFeatures(userId, features)
const { features: newFeatures, featuresChanged } =
await UserFeaturesUpdater.promises.updateFeatures(userId, features)
if (oldFeatures.dropbox === true && features.dropbox === false) {
logger.log({ userId }, '[FeaturesUpdater] must unlink dropbox')
const Modules = require('../../infrastructure/Modules')
@@ -70,9 +68,8 @@ async function refreshFeatures(userId, reason) {
async function computeFeatures(userId) {
const individualFeatures = await _getIndividualFeatures(userId)
const groupFeatureSets = await _getGroupFeatureSets(userId)
const institutionFeatures = await InstitutionsFeatures.promises.getInstitutionsFeatures(
userId
)
const institutionFeatures =
await InstitutionsFeatures.promises.getInstitutionsFeatures(userId)
const v1Features = await _getV1Features(userId)
const bonusFeatures = await ReferalFeatures.promises.getBonusFeatures(userId)
const featuresOverrides = await _getFeaturesOverrides(userId)
@@ -144,10 +141,8 @@ async function _getFeaturesOverrides(userId) {
async function _getV1Features(userId) {
let planCode, v1Id
try {
;({
planCode,
v1Id,
} = await V1SubscriptionManager.promises.getPlanCodeFromV1(userId))
;({ planCode, v1Id } =
await V1SubscriptionManager.promises.getPlanCodeFromV1(userId))
} catch (err) {
if (err.name === 'NotFoundError') {
return {}
@@ -197,9 +197,8 @@ const LimitationsManager = {
return callback(new Error('no subscription found'))
}
const limitReached = LimitationsManager.teamHasReachedMemberLimit(
subscription
)
const limitReached =
LimitationsManager.teamHasReachedMemberLimit(subscription)
callback(err, limitReached, subscription)
}
)
@@ -283,9 +283,8 @@ const RecurlyWrapper = {
account_code: user._id,
},
}
const customFields = getCustomFieldsFromSubscriptionDetails(
subscriptionDetails
)
const customFields =
getCustomFieldsFromSubscriptionDetails(subscriptionDetails)
if (customFields) {
data.custom_fields = customFields
}
@@ -395,9 +394,8 @@ const RecurlyWrapper = {
data.account.billing_info.three_d_secure_action_result_token_id =
recurlyTokenIds.threeDSecureActionResult
}
const customFields = getCustomFieldsFromSubscriptionDetails(
subscriptionDetails
)
const customFields =
getCustomFieldsFromSubscriptionDetails(subscriptionDetails)
if (customFields) {
data.custom_fields = customFields
}
@@ -525,9 +523,8 @@ const RecurlyWrapper = {
recurlySubscription.account != null &&
recurlySubscription.account.url != null
) {
accountId = recurlySubscription.account.url.match(
/accounts\/(.*)/
)[1]
accountId =
recurlySubscription.account.url.match(/accounts\/(.*)/)[1]
} else {
return callback(
new Error("I don't understand the response from Recurly")
@@ -30,11 +30,10 @@ const validGroupPlanModalOptions = {
async function plansPage(req, res) {
const plans = SubscriptionViewModelBuilder.buildPlansList()
const {
currencyCode: recommendedCurrency,
} = await GeoIpLookup.promises.getCurrencyCode(
(req.query ? req.query.ip : undefined) || req.ip
)
const { currencyCode: recommendedCurrency } =
await GeoIpLookup.promises.getCurrencyCode(
(req.query ? req.query.ip : undefined) || req.ip
)
function getDefault(param, category, defaultValue) {
const v = req.query && req.query[param]
@@ -77,17 +76,17 @@ async function paymentPage(req, res) {
if (!plan) {
return HttpErrorHandler.unprocessableEntity(req, res, 'Plan not found')
}
const hasSubscription = await LimitationsManager.promises.userHasV1OrV2Subscription(
user
)
const hasSubscription =
await LimitationsManager.promises.userHasV1OrV2Subscription(user)
if (hasSubscription) {
res.redirect('/user/subscription?hasSubscription=true')
} else {
// LimitationsManager.userHasV2Subscription only checks Mongo. Double check with
// Recurly as well at this point (we don't do this most places for speed).
const valid = await SubscriptionHandler.promises.validateNoSubscriptionInRecurly(
user._id
)
const valid =
await SubscriptionHandler.promises.validateNoSubscriptionInRecurly(
user._id
)
if (!valid) {
res.redirect('/user/subscription?hasSubscription=true')
} else {
@@ -98,12 +97,10 @@ async function paymentPage(req, res) {
currency = queryCurrency
}
}
const {
currencyCode: recommendedCurrency,
countryCode,
} = await GeoIpLookup.promises.getCurrencyCode(
(req.query ? req.query.ip : undefined) || req.ip
)
const { currencyCode: recommendedCurrency, countryCode } =
await GeoIpLookup.promises.getCurrencyCode(
(req.query ? req.query.ip : undefined) || req.ip
)
if (recommendedCurrency && currency == null) {
currency = recommendedCurrency
}
@@ -127,9 +124,10 @@ async function paymentPage(req, res) {
async function userSubscriptionPage(req, res) {
const user = SessionManager.getSessionUser(req.session)
const results = await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
user
)
const results =
await SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
user
)
const {
personalSubscription,
memberGroupSubscriptions,
@@ -139,9 +137,8 @@ async function userSubscriptionPage(req, res) {
managedPublishers,
v1SubscriptionStatus,
} = results
const hasSubscription = await LimitationsManager.promises.userHasV1OrV2Subscription(
user
)
const hasSubscription =
await LimitationsManager.promises.userHasV1OrV2Subscription(user)
const fromPlansPage = req.query.hasSubscription
const plans = SubscriptionViewModelBuilder.buildPlansList(
personalSubscription ? personalSubscription.plan : undefined
@@ -446,9 +443,8 @@ function processUpgradeToAnnualPlan(req, res, next) {
async function extendTrial(req, res) {
const user = SessionManager.getSessionUser(req.session)
const {
subscription,
} = await LimitationsManager.promises.userHasV2Subscription(user)
const { subscription } =
await LimitationsManager.promises.userHasV2Subscription(user)
try {
await SubscriptionHandler.promises.extendTrial(subscription, 14)
@@ -485,10 +481,11 @@ async function refreshUserFeatures(req, res) {
async function redirectToHostedPage(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session)
const { pageType } = req.params
const url = await SubscriptionViewModelBuilder.promises.getRedirectToHostedPage(
userId,
pageType
)
const url =
await SubscriptionViewModelBuilder.promises.getRedirectToHostedPage(
userId,
pageType
)
logger.warn({ userId, pageType }, 'redirecting to recurly hosted page')
res.redirect(url)
}
@@ -79,9 +79,8 @@ async function removeUserFromGroup(subscriptionId, userId) {
}
async function removeUserFromAllGroups(userId) {
const subscriptions = await SubscriptionLocator.promises.getMemberSubscriptions(
userId
)
const subscriptions =
await SubscriptionLocator.promises.getMemberSubscriptions(userId)
if (subscriptions.length === 0) {
return
}
@@ -114,9 +113,8 @@ async function deleteSubscription(subscription, deleterData) {
}
async function restoreSubscription(subscriptionId) {
const deletedSubscription = await SubscriptionLocator.promises.getDeletedSubscription(
subscriptionId
)
const deletedSubscription =
await SubscriptionLocator.promises.getDeletedSubscription(subscriptionId)
const subscription = deletedSubscription.subscription
// 1. upsert subscription
@@ -249,9 +247,8 @@ async function updateSubscriptionFromRecurly(
async function _sendUserGroupPlanCodeUserProperty(userId) {
try {
const subscriptions = await SubscriptionLocator.promises.getMemberSubscriptions(
userId
)
const subscriptions =
await SubscriptionLocator.promises.getMemberSubscriptions(userId)
let bestPlanCode = null
let bestFeatures = {}
for (const subscription of subscriptions) {
@@ -21,9 +21,8 @@ async function getRedirectToHostedPage(userId, pageType) {
if (!['billing-details', 'account-management'].includes(pageType)) {
throw new InvalidError('unexpected page type')
}
const personalSubscription = await SubscriptionLocator.promises.getUsersSubscription(
userId
)
const personalSubscription =
await SubscriptionLocator.promises.getUsersSubscription(userId)
const recurlySubscriptionId = personalSubscription?.recurlySubscription_id
if (!recurlySubscriptionId) {
throw new NotFoundError('not a recurly subscription')
@@ -253,23 +252,27 @@ function buildUsersSubscriptionViewModel(user, callback) {
const pendingSubscriptionTax =
personalSubscription.recurly.taxRate *
recurlySubscription.pending_subscription.unit_amount_in_cents
personalSubscription.recurly.price = SubscriptionFormatters.formatPrice(
recurlySubscription.pending_subscription.unit_amount_in_cents +
pendingAddOnPrice +
pendingAddOnTax +
pendingSubscriptionTax,
recurlySubscription.currency
)
personalSubscription.recurly.price =
SubscriptionFormatters.formatPrice(
recurlySubscription.pending_subscription.unit_amount_in_cents +
pendingAddOnPrice +
pendingAddOnTax +
pendingSubscriptionTax,
recurlySubscription.currency
)
const pendingTotalLicenses =
(pendingPlan.membersLimit || 0) + pendingAdditionalLicenses
personalSubscription.recurly.pendingAdditionalLicenses = pendingAdditionalLicenses
personalSubscription.recurly.pendingTotalLicenses = pendingTotalLicenses
personalSubscription.recurly.pendingAdditionalLicenses =
pendingAdditionalLicenses
personalSubscription.recurly.pendingTotalLicenses =
pendingTotalLicenses
personalSubscription.pendingPlan = pendingPlan
} else {
personalSubscription.recurly.price = SubscriptionFormatters.formatPrice(
recurlySubscription.unit_amount_in_cents + addOnPrice + tax,
recurlySubscription.currency
)
personalSubscription.recurly.price =
SubscriptionFormatters.formatPrice(
recurlySubscription.unit_amount_in_cents + addOnPrice + tax,
recurlySubscription.currency
)
}
}
@@ -7,8 +7,8 @@ const path = require('path')
const request = require('request-promise-native')
const settings = require('@overleaf/settings')
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
.promises
const CollaboratorsGetter =
require('../Collaborators/CollaboratorsGetter').promises
const UserGetter = require('../User/UserGetter.js').promises
const tpdsUrl = _.get(settings, ['apis', 'thirdPartyDataStore', 'url'])
@@ -149,10 +149,8 @@ async function enqueue(group, method, job) {
async function getProjectUsersIds(projectId) {
// get list of all user ids with access to project. project owner
// will always be the first entry in the list.
const [
ownerUserId,
...invitedUserIds
] = await CollaboratorsGetter.getInvitedMemberIds(projectId)
const [ownerUserId, ...invitedUserIds] =
await CollaboratorsGetter.getInvitedMemberIds(projectId)
// if there are no invited users, always return the owner
if (!invitedUserIds.length) {
return [ownerUserId]
@@ -25,11 +25,12 @@ async function _userAlreadyHasHigherPrivilege(
if (!Object.values(TokenAccessHandler.TOKEN_TYPES).includes(tokenType)) {
throw new Error('bad token type')
}
const privilegeLevel = await AuthorizationManager.promises.getPrivilegeLevelForProject(
userId,
projectId,
token
)
const privilegeLevel =
await AuthorizationManager.promises.getPrivilegeLevelForProject(
userId,
projectId,
token
)
return (
orderedPrivilegeLevels.indexOf(privilegeLevel) >=
orderedPrivilegeLevels.indexOf(tokenType)
@@ -84,9 +85,8 @@ async function tokenAccessPage(req, res, next) {
}
try {
if (TokenAccessHandler.isReadOnlyToken(token)) {
const docPublishedInfo = await TokenAccessHandler.promises.getV1DocPublishedInfo(
token
)
const docPublishedInfo =
await TokenAccessHandler.promises.getV1DocPublishedInfo(token)
if (docPublishedInfo.allow === false) {
return res.redirect(302, docPublishedInfo.published_path)
}
@@ -135,9 +135,8 @@ async function checkAndGetProjectOrResponseAction(
const projectId = project._id
const isAnonymousUser = !userId
const tokenAccessEnabled = TokenAccessHandler.tokenAccessEnabledForProject(
project
)
const tokenAccessEnabled =
TokenAccessHandler.tokenAccessEnabledForProject(project)
if (isAnonymousUser && tokenAccessEnabled) {
if (tokenType === TokenAccessHandler.TOKEN_TYPES.READ_AND_WRITE) {
if (TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED) {
@@ -260,9 +259,8 @@ async function grantTokenAccessReadOnly(req, res, next) {
return res.sendStatus(400)
}
const tokenType = TokenAccessHandler.TOKEN_TYPES.READ_ONLY
const docPublishedInfo = await TokenAccessHandler.promises.getV1DocPublishedInfo(
token
)
const docPublishedInfo =
await TokenAccessHandler.promises.getV1DocPublishedInfo(token)
if (docPublishedInfo.allow === false) {
return res.json({ redirect: docPublishedInfo.published_path })
}
@@ -29,12 +29,10 @@ module.exports = {
async function createProjectFromZipArchive(ownerId, defaultName, zipPath) {
const contentsPath = await _extractZip(zipPath)
const {
path,
content,
} = await ProjectRootDocManager.promises.findRootDocFileFromDirectory(
contentsPath
)
const { path, content } =
await ProjectRootDocManager.promises.findRootDocFileFromDirectory(
contentsPath
)
const projectName =
DocumentHelper.getTitleFromTexContent(content || '') || defaultName
@@ -131,11 +129,12 @@ async function _initializeProjectWithZipContents(
project._id,
importEntries
)
const projectVersion = await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure(
project._id,
docEntries,
fileEntries
)
const projectVersion =
await ProjectEntityMongoUpdateHandler.promises.createNewFolderStructure(
project._id,
docEntries,
fileEntries
)
await _notifyDocumentUpdater(project, ownerId, {
newFiles: fileEntries,
newDocs: docEntries,
@@ -223,9 +223,8 @@ async function getUser(providerId, externalUserId) {
}
async function redundantSubscription(userId, providerId, providerName) {
const subscription = await SubscriptionLocator.promises.getUserIndividualSubscription(
userId
)
const subscription =
await SubscriptionLocator.promises.getUserIndividualSubscription(userId)
if (subscription) {
await NotificationsBuilder.promises
@@ -264,9 +264,8 @@ const decorateFullEmails = (
)
}
emailData.emailHasInstitutionLicence = InstitutionsHelper.emailHasLicence(
emailData
)
emailData.emailHasInstitutionLicence =
InstitutionsHelper.emailHasLicence(emailData)
})
return emailsData
@@ -217,19 +217,20 @@ const UserSessionsManager = {
return callback(err)
}
Async.series(
sessionKeys.map(key => next =>
rclient.get(key, function (err, val) {
if (err) {
return next(err)
}
if (!val) {
rclient.srem(sessionSetKey, key, function (err, result) {
sessionKeys.map(
key => next =>
rclient.get(key, function (err, val) {
if (err) {
return next(err)
})
} else {
next()
}
})
}
if (!val) {
rclient.srem(sessionSetKey, key, function (err, result) {
return next(err)
})
} else {
next()
}
})
),
function (err, results) {
callback(err)
@@ -31,9 +31,8 @@ module.exports = {
if (error != null) {
return next(error)
}
const entityPrimaryKey = entity[
entityConfig.fields.primaryKey
].toString()
const entityPrimaryKey =
entity[entityConfig.fields.primaryKey].toString()
if (entityConfig.fields.name) {
entityName = entity[entityConfig.fields.name]
}
@@ -198,10 +198,11 @@ function fetchEntityConfig(entityName) {
// fetch the entity with id and config, and set it in the request
function fetchEntity() {
return expressify(async (req, res, next) => {
const entity = await UserMembershipHandler.promises.getEntityWithoutAuthorizationCheck(
req.params.id,
req.entityConfig
)
const entity =
await UserMembershipHandler.promises.getEntityWithoutAuthorizationCheck(
req.params.id,
req.entityConfig
)
req.entity = entity
next()
})
@@ -1,19 +1,16 @@
const _ = require('lodash')
const Settings = require('@overleaf/settings')
const publicRegistrationModuleAvailable = Settings.moduleImportSequence.includes(
'public-registration'
)
const publicRegistrationModuleAvailable =
Settings.moduleImportSequence.includes('public-registration')
const supportModuleAvailable = Settings.moduleImportSequence.includes('support')
const historyV1ModuleAvailable = Settings.moduleImportSequence.includes(
'history-v1'
)
const historyV1ModuleAvailable =
Settings.moduleImportSequence.includes('history-v1')
const trackChangesModuleAvailable = Settings.moduleImportSequence.includes(
'track-changes'
)
const trackChangesModuleAvailable =
Settings.moduleImportSequence.includes('track-changes')
/**
* @typedef {Object} Settings
@@ -77,9 +77,8 @@ function setLangBasedOnDomainMiddleware(req, res, next) {
// offering to switch to the appropriate library
const detectedLanguageCode = headerLangDetector.detect(req, res)
if (req.language !== detectedLanguageCode) {
res.locals.suggestedLanguageSubdomainConfig = subdomainConfigs.get(
detectedLanguageCode
)
res.locals.suggestedLanguageSubdomainConfig =
subdomainConfigs.get(detectedLanguageCode)
}
// Decorate req.i18n with translate function alias for backwards
@@ -7,11 +7,13 @@
*/
import App from '../base'
export default App.directive('onEnter', () => (scope, element, attrs) =>
element.bind('keydown keypress', function (event) {
if (event.which === 13) {
scope.$apply(() => scope.$eval(attrs.onEnter, { event }))
return event.preventDefault()
}
})
export default App.directive(
'onEnter',
() => (scope, element, attrs) =>
element.bind('keydown keypress', function (event) {
if (event.which === 13) {
scope.$apply(() => scope.$eval(attrs.onEnter, { event }))
return event.preventDefault()
}
})
)
@@ -27,9 +27,10 @@ export default function CloneProjectModalContent({
)
// valid if the cloned project has a name
const valid = useMemo(() => clonedProjectName.trim().length > 0, [
clonedProjectName,
])
const valid = useMemo(
() => clonedProjectName.trim().length > 0,
[clonedProjectName]
)
// form submission: clone the project if the name is valid
const handleSubmit = event => {
@@ -69,9 +69,8 @@ const EditorNavigationToolbarRoot = React.memo(
pdfLayout,
} = useLayoutContext(layoutContextPropTypes)
const { markMessagesAsRead, unreadMessageCount } = useChatContext(
chatContextPropTypes
)
const { markMessagesAsRead, unreadMessageCount } =
useChatContext(chatContextPropTypes)
const toggleChatOpen = useCallback(() => {
if (!chatIsOpen) {
@@ -7,11 +7,8 @@ import { useFileTreeMainContext } from '../contexts/file-tree-main'
import FileTreeItemMenuItems from './file-tree-item/file-tree-item-menu-items'
function FileTreeContextMenu() {
const {
hasWritePermissions,
contextMenuCoords,
setContextMenuCoords,
} = useFileTreeMainContext()
const { hasWritePermissions, contextMenuCoords, setContextMenuCoords } =
useFileTreeMainContext()
if (!hasWritePermissions || !contextMenuCoords) return null
@@ -16,10 +16,8 @@ import ErrorMessage from '../error-message'
export default function FileTreeImportFromProject() {
const { t } = useTranslation()
const {
hasLinkedProjectFileFeature,
hasLinkedProjectOutputFileFeature,
} = window.ExposedSettings
const { hasLinkedProjectFileFeature, hasLinkedProjectOutputFileFeature } =
window.ExposedSettings
const canSwitchOutputFilesMode =
hasLinkedProjectFileFeature && hasLinkedProjectOutputFileFeature
@@ -9,13 +9,8 @@ import { useFileTreeMainContext } from '../../contexts/file-tree-main'
function FileTreeItemName({ name, isSelected, setIsDraggable }) {
const { hasWritePermissions } = useFileTreeMainContext()
const {
isRenaming,
startRenaming,
finishRenaming,
error,
cancel,
} = useFileTreeActionable()
const { isRenaming, startRenaming, finishRenaming, error, cancel } =
useFileTreeActionable()
const isRenamingEntity = isRenaming && isSelected && !error
@@ -63,12 +63,8 @@ function FileTreeToolbarLeft() {
function FileTreeToolbarRight() {
const { t } = useTranslation()
const {
canRename,
canDelete,
startRenaming,
startDeleting,
} = useFileTreeActionable()
const { canRename, canDelete, startRenaming, startDeleting } =
useFileTreeActionable()
if (!canRename && !canDelete) {
return null
@@ -18,13 +18,8 @@ function FileTreeModalCreateFolder() {
const [name, setName] = useState('')
const [validName, setValidName] = useState(true)
const {
isCreatingFolder,
inFlight,
finishCreatingFolder,
cancel,
error,
} = useFileTreeActionable()
const { isCreatingFolder, inFlight, finishCreatingFolder, cancel, error } =
useFileTreeActionable()
if (!isCreatingFolder) return null // the modal will not be rendered; return early
@@ -5,116 +5,119 @@ import { cloneDeep } from 'lodash'
import FileTreeRoot from '../components/file-tree-root'
import { rootContext } from '../../../shared/context/root-context'
App.controller('ReactFileTreeController', function (
$scope,
$timeout,
ide
// eventTracking
) {
$scope.projectId = ide.project_id
$scope.rootFolder = null
$scope.rootDocId = null
$scope.hasWritePermissions = false
$scope.isConnected = true
App.controller(
'ReactFileTreeController',
function (
$scope,
$timeout,
ide
// eventTracking
) {
$scope.projectId = ide.project_id
$scope.rootFolder = null
$scope.rootDocId = null
$scope.hasWritePermissions = false
$scope.isConnected = true
$scope.$on('project:joined', () => {
$scope.rootFolder = $scope.project.rootFolder
$scope.rootDocId = $scope.project.rootDoc_id
$scope.$emit('file-tree:initialized')
})
$scope.$watch('permissions.write', hasWritePermissions => {
$scope.hasWritePermissions = hasWritePermissions
})
$scope.$watch('editor.open_doc_id', openDocId => {
window.dispatchEvent(
new CustomEvent('editor.openDoc', { detail: openDocId })
)
})
// Set isConnected to true if:
// - connection state is 'ready', OR
// - connection state is 'waitingCountdown' and reconnection_countdown is null
// The added complexity is needed because in Firefox on page reload the
// connection state goes into 'waitingCountdown' before being hidden and we
// don't want to show a disconnect UI.
function updateIsConnected() {
const isReady = $scope.connection.state === 'ready'
const willStartCountdown =
$scope.connection.state === 'waitingCountdown' &&
$scope.connection.reconnection_countdown === null
$scope.isConnected = isReady || willStartCountdown
}
$scope.$watch('connection.state', updateIsConnected)
$scope.$watch('connection.reconnection_countdown', updateIsConnected)
$scope.onInit = () => {
// HACK: resize the vertical pane on init after a 0ms timeout. We do not
// understand why this is necessary but without this the resized handle is
// stuck at the bottom. The vertical resize will soon be migrated to React
// so we accept to live with this hack for now.
$timeout(() => {
$scope.$emit('left-pane-resize-all')
$scope.$on('project:joined', () => {
$scope.rootFolder = $scope.project.rootFolder
$scope.rootDocId = $scope.project.rootDoc_id
$scope.$emit('file-tree:initialized')
})
}
$scope.onSelect = selectedEntities => {
if (selectedEntities.length === 1) {
const selectedEntity = selectedEntities[0]
const type =
selectedEntity.type === 'fileRef' ? 'file' : selectedEntity.type
$scope.$emit('entity:selected', {
...selectedEntity.entity,
id: selectedEntity.entity._id,
type,
})
$scope.$watch('permissions.write', hasWritePermissions => {
$scope.hasWritePermissions = hasWritePermissions
})
// in the react implementation there is no such concept as "1
// multi-selected entity" so here we pass a count of 0
$scope.$emit('entities:multiSelected', { count: 0 })
} else if (selectedEntities.length > 1) {
$scope.$emit('entities:multiSelected', {
count: selectedEntities.length,
$scope.$watch('editor.open_doc_id', openDocId => {
window.dispatchEvent(
new CustomEvent('editor.openDoc', { detail: openDocId })
)
})
// Set isConnected to true if:
// - connection state is 'ready', OR
// - connection state is 'waitingCountdown' and reconnection_countdown is null
// The added complexity is needed because in Firefox on page reload the
// connection state goes into 'waitingCountdown' before being hidden and we
// don't want to show a disconnect UI.
function updateIsConnected() {
const isReady = $scope.connection.state === 'ready'
const willStartCountdown =
$scope.connection.state === 'waitingCountdown' &&
$scope.connection.reconnection_countdown === null
$scope.isConnected = isReady || willStartCountdown
}
$scope.$watch('connection.state', updateIsConnected)
$scope.$watch('connection.reconnection_countdown', updateIsConnected)
$scope.onInit = () => {
// HACK: resize the vertical pane on init after a 0ms timeout. We do not
// understand why this is necessary but without this the resized handle is
// stuck at the bottom. The vertical resize will soon be migrated to React
// so we accept to live with this hack for now.
$timeout(() => {
$scope.$emit('left-pane-resize-all')
})
} else {
$scope.$emit('entity:no-selection')
}
$scope.onSelect = selectedEntities => {
if (selectedEntities.length === 1) {
const selectedEntity = selectedEntities[0]
const type =
selectedEntity.type === 'fileRef' ? 'file' : selectedEntity.type
$scope.$emit('entity:selected', {
...selectedEntity.entity,
id: selectedEntity.entity._id,
type,
})
// in the react implementation there is no such concept as "1
// multi-selected entity" so here we pass a count of 0
$scope.$emit('entities:multiSelected', { count: 0 })
} else if (selectedEntities.length > 1) {
$scope.$emit('entities:multiSelected', {
count: selectedEntities.length,
})
} else {
$scope.$emit('entity:no-selection')
}
}
$scope.userHasFeature = feature => ide.$scope.user.features[feature]
$scope.$watch('permissions.write', hasWritePermissions => {
$scope.hasWritePermissions = hasWritePermissions
})
$scope.refProviders = ide.$scope.user.refProviders || {}
ide.$scope.$watch(
'user.refProviders',
refProviders => {
$scope.refProviders = cloneDeep(refProviders)
},
true
)
$scope.setRefProviderEnabled = provider => {
ide.$scope.$applyAsync(() => {
ide.$scope.user.refProviders[provider] = true
})
}
$scope.setStartedFreeTrial = started => {
$scope.$applyAsync(() => {
$scope.startedFreeTrial = started
})
}
$scope.reindexReferences = () => {
ide.$scope.$emit('references:should-reindex', {})
}
}
$scope.userHasFeature = feature => ide.$scope.user.features[feature]
$scope.$watch('permissions.write', hasWritePermissions => {
$scope.hasWritePermissions = hasWritePermissions
})
$scope.refProviders = ide.$scope.user.refProviders || {}
ide.$scope.$watch(
'user.refProviders',
refProviders => {
$scope.refProviders = cloneDeep(refProviders)
},
true
)
$scope.setRefProviderEnabled = provider => {
ide.$scope.$applyAsync(() => {
ide.$scope.user.refProviders[provider] = true
})
}
$scope.setStartedFreeTrial = started => {
$scope.$applyAsync(() => {
$scope.startedFreeTrial = started
})
}
$scope.reindexReferences = () => {
ide.$scope.$emit('references:should-reindex', {})
}
})
)
App.component(
'fileTreeRoot',
@@ -19,12 +19,8 @@ export function useFileTreeSocketListener() {
dispatchCreateFile,
fileTreeData,
} = useFileTreeMutable()
const {
selectedEntityIds,
selectedEntityParentIds,
select,
unselect,
} = useFileTreeSelectable()
const { selectedEntityIds, selectedEntityParentIds, select, unselect } =
useFileTreeSelectable()
const socket = window._ide && window._ide.socket
const selectEntityIfCreatedByUser = useCallback(
@@ -16,9 +16,10 @@ export function DetachCompileButton() {
'detached'
)
const handleStartCompile = useCallback(() => startOrTriggerCompile(), [
startOrTriggerCompile,
])
const handleStartCompile = useCallback(
() => startOrTriggerCompile(),
[startOrTriggerCompile]
)
return (
<div
@@ -14,12 +14,8 @@ import getMeta from '../../../utils/meta'
function PdfJsViewer({ url }) {
const { _id: projectId } = useProjectContext()
const {
setError,
firstRenderDone,
highlights,
setPosition,
} = useCompileContext()
const { setError, firstRenderDone, highlights, setPosition } =
useCompileContext()
const [timePDFFetched, setTimePDFFetched] = useState()
// state values persisted in localStorage to restore on load
@@ -5,13 +5,8 @@ import { sendMBOnce } from '../../../infrastructure/event-tracking'
import { useCompileContext } from '../../../shared/context/compile-context'
function PdfLogsButton() {
const {
codeCheckFailed,
error,
logEntries,
showLogs,
setShowLogs,
} = useCompileContext()
const { codeCheckFailed, error, logEntries, showLogs, setShowLogs } =
useCompileContext()
const buttonStyle = useMemo(() => {
if (showLogs) {
@@ -103,13 +103,8 @@ function PdfSynctexControls() {
const { detachRole } = useLayoutContext()
const {
clsiServerId,
pdfUrl,
pdfViewer,
position,
setHighlights,
} = useCompileContext()
const { clsiServerId, pdfUrl, pdfViewer, position, setHighlights } =
useCompileContext()
const [cursorPosition, setCursorPosition] = useState(() => {
const position = localStorage.getItem(
@@ -10,12 +10,8 @@ const showPdfDetach = getMeta('ol-showPdfDetach')
const debugPdfDetach = getMeta('ol-debugPdfDetach')
export default function useCompileTriggers() {
const {
startCompile,
setChangedAt,
cleanupCompileResult,
setError,
} = useCompileContext()
const { startCompile, setChangedAt, cleanupCompileResult, setError } =
useCompileContext()
const { role: detachRole } = useDetachContext()
// recompile on key press
@@ -4,8 +4,9 @@ import * as eventTracking from '../../../infrastructure/event-tracking'
function getFormValues() {
const modalEl = document.querySelector('[data-ol-group-plan-modal]')
const planCode = modalEl.querySelector('input[name="plan_code"]:checked')
.value
const planCode = modalEl.querySelector(
'input[name="plan_code"]:checked'
).value
const size = modalEl.querySelector('#size').value
const currency = modalEl.querySelector('#currency').value
const usage = modalEl.querySelector('#usage').checked
@@ -32,9 +33,8 @@ function updateGroupPlanView() {
modalEl.querySelectorAll('[data-ol-group-plan-usage]').forEach(el => {
el.hidden = el.getAttribute('data-ol-group-plan-usage') !== usage
})
modalEl.querySelector(
'[data-ol-group-plan-display-price]'
).innerText = displayPrice
modalEl.querySelector('[data-ol-group-plan-display-price]').innerText =
displayPrice
modalEl.querySelector(
'[data-ol-group-plan-price-per-user]'
).innerText = `${currencySymbol}${perUserPrice} per user`
@@ -58,14 +58,10 @@ function PreviewLogEntryContent({
formattedContent,
extraInfoURL,
}) {
const {
isExpanded,
needsExpandCollapse,
expandableProps,
toggleProps,
} = useExpandCollapse({
collapsedSize: 150,
})
const { isExpanded, needsExpandCollapse, expandableProps, toggleProps } =
useExpandCollapse({
collapsedSize: 150,
})
const buttonContainerClasses = classNames(
'log-entry-content-button-container',
@@ -30,12 +30,10 @@ function PreviewPane({
const [lastCompileTimestamp, setLastCompileTimestamp] = useState(
compilerState.lastCompileTimestamp
)
const [seenLogsForCurrentCompile, setSeenLogsForCurrentCompile] = useState(
false
)
const [dismissedFirstErrorPopUp, setDismissedFirstErrorPopUp] = useState(
false
)
const [seenLogsForCurrentCompile, setSeenLogsForCurrentCompile] =
useState(false)
const [dismissedFirstErrorPopUp, setDismissedFirstErrorPopUp] =
useState(false)
if (lastCompileTimestamp < compilerState.lastCompileTimestamp) {
setLastCompileTimestamp(compilerState.lastCompileTimestamp)
@@ -18,10 +18,8 @@ import { useProjectContext } from '../../../shared/context/project-context'
export default function EditMember({ member }) {
const [privileges, setPrivileges] = useState(member.privileges)
const [
confirmingOwnershipTransfer,
setConfirmingOwnershipTransfer,
] = useState(false)
const [confirmingOwnershipTransfer, setConfirmingOwnershipTransfer] =
useState(false)
// update the local state if the member's privileges change externally
useEffect(() => {
@@ -10,7 +10,8 @@ import Icon from '../../../shared/components/icon'
// Unicode characters in these Unicode groups:
// "General Punctuation — Spaces"
// "General Punctuation — Format character" (including zero-width spaces)
const matchAllSpaces = /[\u061C\u2000-\u200F\u202A-\u202E\u2060\u2066-\u2069\u2028\u2029\u202F]/g
const matchAllSpaces =
/[\u061C\u2000-\u200F\u202A-\u202E\u2060\u2066-\u2069\u2028\u2029\u202F]/g
export default function SelectCollaborators({
loading,
@@ -28,9 +29,10 @@ export default function SelectCollaborators({
const [inputValue, setInputValue] = useState('')
const selectedEmails = useMemo(() => selectedItems.map(item => item.email), [
selectedItems,
])
const selectedEmails = useMemo(
() => selectedItems.map(item => item.email),
[selectedItems]
)
const unselectedOptions = useMemo(
() => options.filter(option => !selectedEmails.includes(option.email)),
@@ -124,9 +124,10 @@ const ShareProjectModal = React.memo(function ShareProjectModal({
}, [])
// merge the new data with the old project data
const updateProject = useCallback(data => Object.assign(project, data), [
project,
])
const updateProject = useCallback(
data => Object.assign(project, data),
[project]
)
if (!project) {
return null
@@ -426,7 +426,8 @@ Something went wrong connecting to your project. Please refresh if this continue
this.joinProjectRetryInterval <
this.JOIN_PROJECT_MAX_RETRY_INTERVAL
) {
this.joinProjectRetryInterval += this.JOIN_PROJECT_RETRY_INTERVAL
this.joinProjectRetryInterval +=
this.JOIN_PROJECT_RETRY_INTERVAL
}
return
} else {
@@ -335,10 +335,8 @@ export default ShareJsDoc = (function () {
// end-to-end check for edits -> acks, for this very ShareJsdoc
// This will catch a broken connection and missing UX-blocker for the
// user, allowing them to keep editing.
this._detachEditorWatchdogManager = this.EditorWatchdogManager.attachToEditor(
editorName,
editor
)
this._detachEditorWatchdogManager =
this.EditorWatchdogManager.attachToEditor(editorName, editor)
}
_attachToEditor(editorName, editor, attachToShareJs) {
@@ -329,9 +329,8 @@ class AutoCompleteManager {
)
)
// Delete back to command start, as appropriate
const commandStartIndex = Helpers.getLastCommandFragmentIndex(
lineUpToCursor
)
const commandStartIndex =
Helpers.getLastCommandFragmentIndex(lineUpToCursor)
if (commandStartIndex !== -1) {
leftRange.start.column = commandStartIndex
} else {
@@ -351,9 +350,8 @@ class AutoCompleteManager {
)
if (lineBeyondCursor) {
const partialCommandMatch = lineBeyondCursor.match(
/^([a-zA-Z0-9]+)\{/
)
const partialCommandMatch =
lineBeyondCursor.match(/^([a-zA-Z0-9]+)\{/)
if (partialCommandMatch) {
// We've got a partial command after the cursor
const commandTail = partialCommandMatch[1]
File diff suppressed because one or more lines are too long
@@ -89,10 +89,8 @@ class TrackChangesAdapter {
if (this.changeIdToMarkerIdMap[change.id] == null) {
return
}
const {
background_marker_id,
callout_marker_id,
} = this.changeIdToMarkerIdMap[change.id]
const { background_marker_id, callout_marker_id } =
this.changeIdToMarkerIdMap[change.id]
delete this.changeIdToMarkerIdMap[change.id]
const session = this.editor.getSession()
session.removeMarker(background_marker_id)
@@ -103,10 +101,8 @@ class TrackChangesAdapter {
if (this.changeIdToMarkerIdMap[change.id] == null) {
return
}
const {
background_marker_id,
callout_marker_id,
} = this.changeIdToMarkerIdMap[change.id]
const { background_marker_id, callout_marker_id } =
this.changeIdToMarkerIdMap[change.id]
delete this.changeIdToMarkerIdMap[change.id]
const session = this.editor.getSession()
@@ -166,10 +162,8 @@ class TrackChangesAdapter {
onCommentRemoved(comment) {
if (this.changeIdToMarkerIdMap[comment.id] != null) {
// Resolved comments may not have marker ids
const {
background_marker_id,
callout_marker_id,
} = this.changeIdToMarkerIdMap[comment.id]
const { background_marker_id, callout_marker_id } =
this.changeIdToMarkerIdMap[comment.id]
delete this.changeIdToMarkerIdMap[comment.id]
const session = this.editor.getSession()
session.removeMarker(background_marker_id)
@@ -183,10 +177,8 @@ class TrackChangesAdapter {
}
const session = this.editor.getSession()
const markers = session.getMarkers()
const {
background_marker_id,
callout_marker_id,
} = this.changeIdToMarkerIdMap[change_id]
const { background_marker_id, callout_marker_id } =
this.changeIdToMarkerIdMap[change_id]
if (background_marker_id != null && markers[background_marker_id] != null) {
const background_marker = markers[background_marker_id]
background_marker.range.start = start
@@ -496,10 +496,8 @@ class TrackChangesManager {
for (const change of Array.from(this.rangesTracker.changes)) {
if (this.adapter.changeIdToMarkerIdMap[change.id] != null) {
;({ op } = change)
;({
background_marker_id,
callout_marker_id,
} = this.adapter.changeIdToMarkerIdMap[change.id])
;({ background_marker_id, callout_marker_id } =
this.adapter.changeIdToMarkerIdMap[change.id])
start = this.adapter.shareJsOffsetToRowColumn(op.p)
if (op.i != null) {
end = this.adapter.shareJsOffsetToRowColumn(op.p + op.i.length)
@@ -521,10 +519,8 @@ class TrackChangesManager {
for (const comment of Array.from(this.rangesTracker.comments)) {
if (this.adapter.changeIdToMarkerIdMap[comment.id] != null) {
;({
background_marker_id,
callout_marker_id,
} = this.adapter.changeIdToMarkerIdMap[comment.id])
;({ background_marker_id, callout_marker_id } =
this.adapter.changeIdToMarkerIdMap[comment.id])
start = this.adapter.shareJsOffsetToRowColumn(comment.op.p)
end = this.adapter.shareJsOffsetToRowColumn(
comment.op.p + comment.op.c.length
@@ -130,12 +130,8 @@ export default HistoryManager = (function () {
reloadDiff() {
let { diff } = this.$scope.history
const { updates, doc } = this.$scope.history.selection
const {
fromV,
toV,
start_ts,
end_ts,
} = this._calculateRangeFromSelection()
const { fromV, toV, start_ts, end_ts } =
this._calculateRangeFromSelection()
if (doc == null) {
return
@@ -269,9 +265,8 @@ export default HistoryManager = (function () {
if (updates == null) {
updates = []
}
let previousUpdate = this.$scope.history.updates[
this.$scope.history.updates.length - 1
]
let previousUpdate =
this.$scope.history.updates[this.$scope.history.updates.length - 1]
for (const update of Array.from(updates)) {
update.pathnames = [] // Used for display
@@ -323,8 +323,8 @@ export default HistoryManager = (function () {
selectFile(file) {
if (file != null && file.pathname != null) {
this.$scope.history.selection.pathname = this._previouslySelectedPathname =
file.pathname
this.$scope.history.selection.pathname =
this._previouslySelectedPathname = file.pathname
this.$scope.history.selection.file = file
if (this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME) {
this.loadFileAtPointInTime()
@@ -659,13 +659,13 @@ export default HistoryManager = (function () {
_loadLabels(labels, lastUpdateToV) {
const sortedLabels = this._sortLabelsByVersionAndDate(labels)
const labelsWithoutPseudoLabel = this._deletePseudoCurrentStateLabelIfExistent(
sortedLabels
)
const labelsWithPseudoLabelIfNeeded = this._addPseudoCurrentStateLabelIfNeeded(
labelsWithoutPseudoLabel,
lastUpdateToV
)
const labelsWithoutPseudoLabel =
this._deletePseudoCurrentStateLabelIfExistent(sortedLabels)
const labelsWithPseudoLabelIfNeeded =
this._addPseudoCurrentStateLabelIfNeeded(
labelsWithoutPseudoLabel,
lastUpdateToV
)
return labelsWithPseudoLabelIfNeeded
}
@@ -902,9 +902,8 @@ export default HistoryManager = (function () {
if (updates == null) {
updates = []
}
let previousUpdate = this.$scope.history.updates[
this.$scope.history.updates.length - 1
]
let previousUpdate =
this.$scope.history.updates[this.$scope.history.updates.length - 1]
const dateTimeNow = new Date()
const timestamp24hoursAgo = dateTimeNow.setDate(dateTimeNow.getDate() - 1)
let cutOffIndex = null
@@ -500,7 +500,8 @@ const rules = [
ruleId: 'hint_mismatched_environment2',
types: ['environment'],
cascadesFrom: ['environment'],
regexToMatch: /Error: `\\end\{([^\}]+)\}' expected but found `\\end\{([^\}]+)\}'.*/,
regexToMatch:
/Error: `\\end\{([^\}]+)\}' expected but found `\\end\{([^\}]+)\}'.*/,
newMessage: 'Error: environments do not match: \\begin{$1} ... \\end{$2}',
humanReadableHintComponent: (
<>
@@ -516,7 +517,8 @@ const rules = [
ruleId: 'hint_mismatched_environment3',
types: ['environment'],
cascadesFrom: ['environment'],
regexToMatch: /Warning: No matching \\end found for `\\begin\{([^\}]+)\}'.*/,
regexToMatch:
/Warning: No matching \\end found for `\\begin\{([^\}]+)\}'.*/,
newMessage: 'Warning: No matching \\end found for \\begin{$1}',
humanReadableHintComponent: (
<>
@@ -532,7 +534,8 @@ const rules = [
ruleId: 'hint_mismatched_environment4',
types: ['environment'],
cascadesFrom: ['environment'],
regexToMatch: /Error: Found `\\end\{([^\}]+)\}' without corresponding \\begin.*/,
regexToMatch:
/Error: Found `\\end\{([^\}]+)\}' without corresponding \\begin.*/,
newMessage: 'Error: found \\end{$1} without a corresponding \\begin{$1}',
humanReadableHintComponent: (
<>
@@ -3,9 +3,12 @@ const LINE_SPLITTER_REGEX = /^\[(\d+)].*>\s(INFO|WARN|ERROR)\s-\s(.*)$/
const MULTILINE_WARNING_REGEX = /^Warning--(.+)\n--line (\d+) of file (.+)$/m
const SINGLELINE_WARNING_REGEX = /^Warning--(.+)$/m
const MULTILINE_ERROR_REGEX = /^(.*)---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this entry$/m
const BAD_CROSS_REFERENCE_REGEX = /^(A bad cross reference---entry ".+?"\nrefers to entry.+?, which doesn't exist)$/m
const MULTILINE_COMMAND_ERROR_REGEX = /^(.*)\n?---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this command$/m
const MULTILINE_ERROR_REGEX =
/^(.*)---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this entry$/m
const BAD_CROSS_REFERENCE_REGEX =
/^(A bad cross reference---entry ".+?"\nrefers to entry.+?, which doesn't exist)$/m
const MULTILINE_COMMAND_ERROR_REGEX =
/^(.*)\n?---line (\d+) of file (.*)\n([^]+?)\nI'm skipping whatever remains of this command$/m
// Errors hit in BST file have a slightly different format
const BST_ERROR_REGEX = /^(.*?)\nwhile executing---line (\d+) of file (.*)/m
@@ -103,13 +106,8 @@ export default class BibLogParser {
[
MULTILINE_ERROR_REGEX,
function (match) {
const [
fullMatch,
firstMessage,
lineNumber,
fileName,
secondMessage,
] = match
const [fullMatch, firstMessage, lineNumber, fileName, secondMessage] =
match
return {
file: fileName,
level: 'error',
@@ -135,13 +133,8 @@ export default class BibLogParser {
[
MULTILINE_COMMAND_ERROR_REGEX,
function (match) {
const [
fullMatch,
firstMessage,
lineNumber,
fileName,
secondMessage,
] = match
const [fullMatch, firstMessage, lineNumber, fileName, secondMessage] =
match
return {
file: fileName,
level: 'error',
@@ -620,8 +620,8 @@ export default App.directive('pdfViewer', ($q, $timeout, pdfSpinner) => ({
if (selection.rangeCount === 0) {
return false
}
const selectionAncestorNode = selection.getRangeAt(0)
.commonAncestorContainer
const selectionAncestorNode =
selection.getRangeAt(0).commonAncestorContainer
return (
element.find(selectionAncestorNode).length > 0 ||
element.is(selectionAncestorNode)
@@ -150,9 +150,8 @@ export default App.controller(
$scope.$watch('project.members', function (members) {
$scope.reviewPanel.formattedProjectMembers = {}
if (($scope.project != null ? $scope.project.owner : undefined) != null) {
$scope.reviewPanel.formattedProjectMembers[
$scope.project.owner._id
] = formatUser($scope.project.owner)
$scope.reviewPanel.formattedProjectMembers[$scope.project.owner._id] =
formatUser($scope.project.owner)
}
if (
($scope.project != null ? $scope.project.members : undefined) != null
@@ -170,9 +169,8 @@ export default App.controller(
)
}
result.push(
($scope.reviewPanel.formattedProjectMembers[
member._id
] = formatUser(member))
($scope.reviewPanel.formattedProjectMembers[member._id] =
formatUser(member))
)
} else {
result.push(undefined)
@@ -900,8 +898,8 @@ export default App.controller(
$scope.toggleFullTCStateCollapse = function () {
if ($scope.project.features.trackChanges) {
return ($scope.reviewPanel.fullTCStateCollapsed = !$scope.reviewPanel
.fullTCStateCollapsed)
return ($scope.reviewPanel.fullTCStateCollapsed =
!$scope.reviewPanel.fullTCStateCollapsed)
} else {
_sendAnalytics()
return $scope.openTrackChangesUpgradeModal()
@@ -6,6 +6,7 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
import App from '../../../base'
export default App.filter('notEmpty', () => object =>
!angular.equals({}, object)
export default App.filter(
'notEmpty',
() => object => !angular.equals({}, object)
)
@@ -1,52 +1,55 @@
import App from '../base'
App.controller('AccountSettingsController', function (
$scope,
$http,
$modal,
// eslint-disable-next-line camelcase
eventTracking,
UserAffiliationsDataService
) {
$scope.subscribed = true
App.controller(
'AccountSettingsController',
function (
$scope,
$http,
$modal,
// eslint-disable-next-line camelcase
eventTracking,
UserAffiliationsDataService
) {
$scope.subscribed = true
$scope.unsubscribe = function () {
$scope.unsubscribing = true
return $http({
method: 'DELETE',
url: '/user/newsletter/unsubscribe',
headers: {
'X-CSRF-Token': window.csrfToken,
},
})
.then(function () {
$scope.unsubscribing = false
$scope.subscribed = false
})
.catch(() => ($scope.unsubscribing = true))
}
$scope.deleteAccount = function () {
$modal.open({
templateUrl: 'deleteAccountModalTemplate',
controller: 'DeleteAccountModalController',
resolve: {
userDefaultEmail() {
return UserAffiliationsDataService.getUserDefaultEmail()
.then(
defaultEmailDetails =>
(defaultEmailDetails != null
? defaultEmailDetails.email
: undefined) || null
)
.catch(() => null)
$scope.unsubscribe = function () {
$scope.unsubscribing = true
return $http({
method: 'DELETE',
url: '/user/newsletter/unsubscribe',
headers: {
'X-CSRF-Token': window.csrfToken,
},
},
})
}
})
.then(function () {
$scope.unsubscribing = false
$scope.subscribed = false
})
.catch(() => ($scope.unsubscribing = true))
}
$scope.upgradeIntegration = service =>
eventTracking.send('subscription-funnel', 'settings-page', service)
})
$scope.deleteAccount = function () {
$modal.open({
templateUrl: 'deleteAccountModalTemplate',
controller: 'DeleteAccountModalController',
resolve: {
userDefaultEmail() {
return UserAffiliationsDataService.getUserDefaultEmail()
.then(
defaultEmailDetails =>
(defaultEmailDetails != null
? defaultEmailDetails.email
: undefined) || null
)
.catch(() => null)
},
},
})
}
$scope.upgradeIntegration = service =>
eventTracking.send('subscription-funnel', 'settings-page', service)
}
)
App.controller(
'DeleteAccountModalController',
@@ -41,7 +41,8 @@ export default App.controller(
const ONE_WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000
const LOCAL_AND_DOMAIN_REGEX = /([^@]+)@(.+)/
const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\ ".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA -Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
const EMAIL_REGEX =
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\ ".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA -Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
const _matchLocalAndDomain = function (userEmailInput) {
const match = userEmailInput
@@ -84,9 +85,10 @@ export default App.controller(
$scope.ui.isBlacklistedEmail = false
$scope.ui.showManualUniversitySelectionUI = false
if (userInputLocalAndDomain.domain) {
$scope.ui.isBlacklistedEmail = UserAffiliationsDataService.isDomainBlacklisted(
userInputLocalAndDomain.domain
)
$scope.ui.isBlacklistedEmail =
UserAffiliationsDataService.isDomainBlacklisted(
userInputLocalAndDomain.domain
)
return UserAffiliationsDataService.getUniversityDomainFromPartialDomainInput(
userInputLocalAndDomain.domain
)
@@ -100,9 +102,8 @@ export default App.controller(
) {
$scope.newAffiliation.university = universityDomain.university
$scope.newAffiliation.department = universityDomain.department
$scope.newAffiliation.ssoAvailable = _ssoAvailableForDomain(
universityDomain
)
$scope.newAffiliation.ssoAvailable =
_ssoAvailableForDomain(universityDomain)
} else {
_resetAffiliationSuggestion()
}
@@ -175,13 +176,14 @@ export default App.controller(
)
} else {
if ($scope.newAffiliation.university.isUserSuggested) {
addEmailPromise = UserAffiliationsDataService.addUserAffiliationWithUnknownUniversity(
$scope.newAffiliation.email,
$scope.newAffiliation.university.name,
$scope.newAffiliation.country.code,
$scope.newAffiliation.role,
$scope.newAffiliation.department
)
addEmailPromise =
UserAffiliationsDataService.addUserAffiliationWithUnknownUniversity(
$scope.newAffiliation.email,
$scope.newAffiliation.university.name,
$scope.newAffiliation.country.code,
$scope.newAffiliation.role,
$scope.newAffiliation.department
)
} else {
addEmailPromise = UserAffiliationsDataService.addUserAffiliation(
$scope.newAffiliation.email,
File diff suppressed because it is too large Load Diff
@@ -87,9 +87,8 @@ export function CompileProvider({ children }) {
const [pdfViewer] = useScopeValue('settings.pdfViewer')
// the URL for downloading the PDF
const [pdfDownloadUrl, setPdfDownloadUrl] = useScopeValueSetterOnly(
'pdf.downloadUrl'
)
const [pdfDownloadUrl, setPdfDownloadUrl] =
useScopeValueSetterOnly('pdf.downloadUrl')
// the URL for loading the PDF in the preview pane
const [pdfUrl, setPdfUrl] = useScopeValueSetterOnly('pdf.url')
@@ -66,9 +66,8 @@ export function LayoutProvider({ children }) {
const [chatIsOpen, setChatIsOpen] = useScopeValue('ui.chatOpen')
// whether the review pane is open
const [reviewPanelOpen, setReviewPanelOpen] = useScopeValue(
'ui.reviewPanelOpen'
)
const [reviewPanelOpen, setReviewPanelOpen] =
useScopeValue('ui.reviewPanelOpen')
// whether the menu pane is open
const [leftMenuShown, setLeftMenuShown] = useScopeValue('ui.leftMenuShown')
@@ -10,12 +10,8 @@ export default function useDetachAction(
senderRole,
targetRole
) {
const {
role,
broadcastEvent,
addEventHandler,
deleteEventHandler,
} = useDetachContext()
const { role, broadcastEvent, addEventHandler, deleteEventHandler } =
useDetachContext()
const eventName = `action-${actionName}`
@@ -11,13 +11,8 @@ const LINKING_TIMEOUT = 60000
const RELINK_TIMEOUT = 10000
export default function useDetachLayout() {
const {
role,
setRole,
broadcastEvent,
addEventHandler,
deleteEventHandler,
} = useDetachContext()
const { role, setRole, broadcastEvent, addEventHandler, deleteEventHandler } =
useDetachContext()
// isLinking: when the tab expects to be linked soon (e.g. on detach)
const [isLinking, setIsLinking] = useState(false)
@@ -12,12 +12,8 @@ export default function useDetachState(
) {
const [value, setValue] = useState(defaultValue)
const {
role,
broadcastEvent,
addEventHandler,
deleteEventHandler,
} = useDetachContext()
const { role, broadcastEvent, addEventHandler, deleteEventHandler } =
useDetachContext()
const eventName = `state-${key}`
@@ -98,23 +98,22 @@ export const mockCreateFileModalFetch = fetchMock =>
return 204
})
export const createFileModalDecorator = (
contextProps = {},
createMode = 'doc'
export const createFileModalDecorator =
(contextProps = {}, createMode = 'doc') =>
// eslint-disable-next-line react/display-name
) => Story => {
return (
<FileTreeContext {...defaultContextProps} {...contextProps}>
<FileTreeCreateNameProvider>
<FileTreeCreateFormProvider>
<OpenCreateFileModal createMode={createMode}>
<Story />
</OpenCreateFileModal>
</FileTreeCreateFormProvider>
</FileTreeCreateNameProvider>
</FileTreeContext>
)
}
Story => {
return (
<FileTreeContext {...defaultContextProps} {...contextProps}>
<FileTreeCreateNameProvider>
<FileTreeCreateFormProvider>
<OpenCreateFileModal createMode={createMode}>
<Story />
</OpenCreateFileModal>
</FileTreeCreateFormProvider>
</FileTreeCreateNameProvider>
</FileTreeContext>
)
}
function OpenCreateFileModal({ children, createMode }) {
const { startCreatingFile } = useFileTreeActionable()
@@ -48,8 +48,7 @@ const indexes = [
'thirdPartyIdentifiers.externalUserId': 1,
'thirdPartyIdentifiers.providerId': 1,
},
name:
'thirdPartyIdentifiers.externalUserId_1_thirdPartyIdentifiers.providerId_1',
name: 'thirdPartyIdentifiers.externalUserId_1_thirdPartyIdentifiers.providerId_1',
sparse: true,
},
{
@@ -33,12 +33,16 @@ describe('LaunchpadController', function () {
requires: {
'@overleaf/settings': (this.Settings = {}),
'@overleaf/metrics': (this.Metrics = {}),
'../../../../app/src/Features/User/UserRegistrationHandler': (this.UserRegistrationHandler = {}),
'../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler = {}),
'../../../../app/src/Features/User/UserRegistrationHandler':
(this.UserRegistrationHandler = {}),
'../../../../app/src/Features/Email/EmailHandler': (this.EmailHandler =
{}),
'../../../../app/src/Features/User/UserGetter': (this.UserGetter = {}),
'../../../../app/src/models/User': { User: this.User },
'../../../../app/src/Features/Authentication/AuthenticationController': (this.AuthenticationController = {}),
'../../../../app/src/Features/Authentication/SessionManager': (this.SessionManager = {}),
'../../../../app/src/Features/Authentication/AuthenticationController':
(this.AuthenticationController = {}),
'../../../../app/src/Features/Authentication/SessionManager':
(this.SessionManager = {}),
},
})
@@ -21,8 +21,8 @@ describe('UserActivateController', function () {
this.UserActivateController = SandboxedModule.require(MODULE_PATH, {
requires: {
'../../../../app/src/Features/User/UserGetter': this.UserGetter,
'../../../../app/src/Features/Errors/ErrorController': this
.ErrorController,
'../../../../app/src/Features/Errors/ErrorController':
this.ErrorController,
},
})
this.req = {
+15 -3
View File
@@ -7644,6 +7644,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"prettier": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
"dev": true
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
@@ -10606,6 +10612,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"prettier": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
"dev": true
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
@@ -31176,9 +31188,9 @@
"dev": true
},
"prettier": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true
},
"pretty-error": {
+1 -1
View File
@@ -270,7 +270,7 @@
"optimize-css-assets-webpack-plugin": "^5.0.3",
"pirates": "^4.0.1",
"postcss-loader": "^3.0.0",
"prettier": "^2.2.1",
"prettier": "^2.5.1",
"requirejs": "^2.3.6",
"samlp": "^3.4.1",
"sandboxed-module": "^2.0.4",
@@ -9,10 +9,11 @@ async function main() {
console.log('Deleting notifications of institution', institutionId)
const preview = await InstitutionsManager.promises.clearInstitutionNotifications(
institutionId,
true
)
const preview =
await InstitutionsManager.promises.clearInstitutionNotifications(
institutionId,
true
)
console.log('--- Preview ---')
console.log(JSON.stringify(preview, null, 4))
console.log('---------------')
@@ -25,10 +26,11 @@ async function main() {
console.log('Exit in the next 10s in case these numbers are off.')
await sleep(10 * 1000)
const cleared = await InstitutionsManager.promises.clearInstitutionNotifications(
institutionId,
false
)
const cleared =
await InstitutionsManager.promises.clearInstitutionNotifications(
institutionId,
false
)
console.log('--- Cleared ---')
console.log(JSON.stringify(cleared, null, 4))
console.log('---------------')
@@ -17,9 +17,8 @@ async function countFiles() {
if (!project) {
throw new Errors.NotFoundError('project not found')
}
const { files, docs } = ProjectEntityHandler.getAllEntitiesFromProject(
project
)
const { files, docs } =
ProjectEntityHandler.getAllEntitiesFromProject(project)
console.error(
projectId,
files.length,
@@ -9,8 +9,8 @@ const {
ObjectId,
waitForDb,
} = require('../../app/src/infrastructure/mongodb')
const DocstoreManager = require('../../app/src/Features/Docstore/DocstoreManager')
.promises
const DocstoreManager =
require('../../app/src/Features/Docstore/DocstoreManager').promises
const argv = minimist(process.argv.slice(2))
const commit = argv.commit !== undefined
@@ -30,7 +30,8 @@ const ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = '5a8d8a370000000000000000'
const OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = new ObjectId(
ID_WHEN_FULL_PROJECT_HISTORY_ENABLED
)
const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED = OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp()
const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED =
OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp()
async function processBatch(_, projects) {
await promiseMapWithLimit(WRITE_CONCURRENCY, projects, processProject)
@@ -32,7 +32,8 @@ const ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = '5a8d8a370000000000000000'
const OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED = new ObjectId(
ID_WHEN_FULL_PROJECT_HISTORY_ENABLED
)
const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED = OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp()
const DATETIME_WHEN_FULL_PROJECT_HISTORY_ENABLED =
OBJECT_ID_WHEN_FULL_PROJECT_HISTORY_ENABLED.getTimestamp()
// set a default BATCH_LAST_ID at our cutoff point if none set
// we still check against this cut off point later, even if
@@ -3,8 +3,8 @@
const fs = require('fs')
const minimist = require('minimist')
const InstitutionsAPI = require('../../app/src/Features/Institutions/InstitutionsAPI')
.promises
const InstitutionsAPI =
require('../../app/src/Features/Institutions/InstitutionsAPI').promises
const argv = minimist(process.argv.slice(2))
const commit = argv.commit !== undefined
@@ -175,12 +175,8 @@ function loadCachedEntitlements(cachedEntitlementsFilename) {
for (const cachedEntitlementLine of cachedEntitlementsData) {
// this is safe because comma is not an allowed value for any column
const [
userId,
email,
hasEntitlement,
providerId,
] = cachedEntitlementLine.split(',')
const [userId, email, hasEntitlement, providerId] =
cachedEntitlementLine.split(',')
let hasEntitlementBoolean
if (ignoreNulls) {
hasEntitlementBoolean = hasEntitlement === 't'
@@ -563,10 +563,11 @@ describe('ProjectInviteTests', function () {
throw err
}
this.secondInvite = invite
this.secondLink = CollaboratorsEmailHandler._buildInviteUrl(
this.fakeProject,
invite
)
this.secondLink =
CollaboratorsEmailHandler._buildInviteUrl(
this.fakeProject,
invite
)
cb()
}
)
@@ -31,12 +31,13 @@ const _createTag = (user, name, callback) => {
const _createTags = (user, tagNames, callback) => {
const tags = []
async.series(
tagNames.map(tagName => cb =>
_createTag(user, tagName, (err, response, body) => {
_expect200(err, response)
tags.push(body)
cb()
})
tagNames.map(
tagName => cb =>
_createTag(user, tagName, (err, response, body) => {
_expect200(err, response)
tags.push(body)
cb()
})
),
err => {
callback(err, tags)
@@ -1,10 +1,10 @@
const { expect } = require('chai')
const MockSubscription = require('./Subscription')
const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater')
const SubscriptionModel = require('../../../../app/src/models/Subscription')
.Subscription
const DeletedSubscriptionModel = require(`../../../../app/src/models/DeletedSubscription`)
.DeletedSubscription
const SubscriptionModel =
require('../../../../app/src/models/Subscription').Subscription
const DeletedSubscriptionModel =
require(`../../../../app/src/models/DeletedSubscription`).DeletedSubscription
class DeletedSubscription {
constructor(options = {}) {
@@ -1,6 +1,6 @@
const { ObjectId } = require('mongodb')
const InstitutionModel = require('../../../../app/src/models/Institution')
.Institution
const InstitutionModel =
require('../../../../app/src/models/Institution').Institution
let count = parseInt(Math.random() * 999999)
@@ -1,10 +1,10 @@
const { db, ObjectId } = require('../../../../app/src/infrastructure/mongodb')
const { expect } = require('chai')
const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater')
const SubscriptionModel = require('../../../../app/src/models/Subscription')
.Subscription
const DeletedSubscriptionModel = require(`../../../../app/src/models/DeletedSubscription`)
.DeletedSubscription
const SubscriptionModel =
require('../../../../app/src/models/Subscription').Subscription
const DeletedSubscriptionModel =
require(`../../../../app/src/models/DeletedSubscription`).DeletedSubscription
class Subscription {
constructor(options = {}) {
@@ -178,9 +178,8 @@ class UserHelper {
// hash password and delete plaintext if set
if (attributes.password) {
attributes.hashedPassword = await AuthenticationManager.promises.hashPassword(
attributes.password
)
attributes.hashedPassword =
await AuthenticationManager.promises.hashPassword(attributes.password)
delete attributes.password
}
+8 -3
View File
@@ -91,12 +91,17 @@ globalThis.requestAnimationFrame = global.requestAnimationFrame =
globalThis.sessionStorage = global.sessionStorage = window.sessionStorage
// add polyfill for ResizeObserver
globalThis.ResizeObserver = global.ResizeObserver = window.ResizeObserver = require('@juggle/resize-observer').ResizeObserver
globalThis.ResizeObserver =
global.ResizeObserver =
window.ResizeObserver =
require('@juggle/resize-observer').ResizeObserver
// node-fetch doesn't accept relative URL's: https://github.com/node-fetch/node-fetch/blob/master/docs/v2-LIMITS.md#known-differences
const fetch = require('node-fetch')
globalThis.fetch = global.fetch = window.fetch = (url, ...options) =>
fetch(new URL(url, 'http://localhost'), ...options)
globalThis.fetch =
global.fetch =
window.fetch =
(url, ...options) => fetch(new URL(url, 'http://localhost'), ...options)
// ignore CSS files
const { addHook } = require('pirates')

Some files were not shown because too many files have changed in this diff Show More