| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999 |
- /* eslint-disable
- camelcase,
- handle-callback-err,
- max-len,
- no-path-concat,
- no-unused-vars,
- */
- // TODO: This file was created by bulk-decaffeinate.
- // Fix any style issues and re-enable lint.
- /*
- * decaffeinate suggestions:
- * DS101: Remove unnecessary use of Array.from
- * DS102: Remove unnecessary code created because of implicit returns
- * DS103: Rewrite code to no longer use __guard__
- * DS205: Consider reworking code to avoid use of IIFEs
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
- let generateThemeList, ProjectController
- const async = require('async')
- const logger = require('logger-sharelatex')
- const projectDeleter = require('./ProjectDeleter')
- const projectDuplicator = require('./ProjectDuplicator')
- const projectCreationHandler = require('./ProjectCreationHandler')
- const editorController = require('../Editor/EditorController')
- const ProjectHelper = require('./ProjectHelper')
- const metrics = require('metrics-sharelatex')
- const { User } = require('../../models/User')
- const TagsHandler = require('../Tags/TagsHandler')
- const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
- const NotificationsHandler = require('../Notifications/NotificationsHandler')
- const LimitationsManager = require('../Subscription/LimitationsManager')
- const underscore = require('underscore')
- const Settings = require('settings-sharelatex')
- const AuthorizationManager = require('../Authorization/AuthorizationManager')
- const fs = require('fs')
- const InactiveProjectManager = require('../InactiveData/InactiveProjectManager')
- const ProjectUpdateHandler = require('./ProjectUpdateHandler')
- const ProjectGetter = require('./ProjectGetter')
- const PrivilegeLevels = require('../Authorization/PrivilegeLevels')
- const AuthenticationController = require('../Authentication/AuthenticationController')
- const PackageVersions = require('../../infrastructure/PackageVersions')
- const AnalyticsManager = require('../Analytics/AnalyticsManager')
- const Sources = require('../Authorization/Sources')
- const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
- const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler')
- const Modules = require('../../infrastructure/Modules')
- const ProjectEntityHandler = require('./ProjectEntityHandler')
- const UserGetter = require('../User/UserGetter')
- const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
- const crypto = require('crypto')
- const { V1ConnectionError } = require('../Errors/Errors')
- const Features = require('../../infrastructure/Features')
- const BrandVariationsHandler = require('../BrandVariations/BrandVariationsHandler')
- const { getUserAffiliations } = require('../Institutions/InstitutionsAPI')
- const V1Handler = require('../V1/V1Handler')
- module.exports = ProjectController = {
- _isInPercentageRollout(rolloutName, objectId, percentage) {
- if (Settings.bypassPercentageRollouts === true) {
- return true
- }
- const data = `${rolloutName}:${objectId.toString()}`
- const md5hash = crypto
- .createHash('md5')
- .update(data)
- .digest('hex')
- const counter = parseInt(md5hash.slice(26, 32), 16)
- return counter % 100 < percentage
- },
- updateProjectSettings(req, res, next) {
- const project_id = req.params.Project_id
- const jobs = []
- if (req.body.compiler != null) {
- jobs.push(callback =>
- editorController.setCompiler(project_id, req.body.compiler, callback)
- )
- }
- if (req.body.imageName != null) {
- jobs.push(callback =>
- editorController.setImageName(project_id, req.body.imageName, callback)
- )
- }
- if (req.body.name != null) {
- jobs.push(callback =>
- editorController.renameProject(project_id, req.body.name, callback)
- )
- }
- if (req.body.spellCheckLanguage != null) {
- jobs.push(callback =>
- editorController.setSpellCheckLanguage(
- project_id,
- req.body.spellCheckLanguage,
- callback
- )
- )
- }
- if (req.body.rootDocId != null) {
- jobs.push(callback =>
- editorController.setRootDoc(project_id, req.body.rootDocId, callback)
- )
- }
- return async.series(jobs, function(error) {
- if (error != null) {
- return next(error)
- }
- return res.sendStatus(204)
- })
- },
- updateProjectAdminSettings(req, res, next) {
- const project_id = req.params.Project_id
- const jobs = []
- if (req.body.publicAccessLevel != null) {
- jobs.push(callback =>
- editorController.setPublicAccessLevel(
- project_id,
- req.body.publicAccessLevel,
- callback
- )
- )
- }
- return async.series(jobs, function(error) {
- if (error != null) {
- return next(error)
- }
- return res.sendStatus(204)
- })
- },
- deleteProject(req, res) {
- const project_id = req.params.Project_id
- const forever = (req.query != null ? req.query.forever : undefined) != null
- logger.log({ project_id, forever }, 'received request to archive project')
- const user = AuthenticationController.getSessionUser(req)
- const cb = function(err) {
- if (err != null) {
- return res.sendStatus(500)
- } else {
- return res.sendStatus(200)
- }
- }
- if (forever) {
- return projectDeleter.deleteProject(
- project_id,
- { deleterUser: user, ipAddress: req.ip },
- cb
- )
- } else {
- return projectDeleter.archiveProject(project_id, cb)
- }
- },
- expireDeletedProjectsAfterDuration(req, res) {
- logger.log(
- 'received request to look for old deleted projects and expire them'
- )
- projectDeleter.expireDeletedProjectsAfterDuration(function(err) {
- if (err != null) {
- return res.sendStatus(500)
- } else {
- return res.sendStatus(200)
- }
- })
- },
- expireDeletedProject(req, res, next) {
- const { projectId } = req.params
- logger.log('received request to expire deleted project', { projectId })
- projectDeleter.expireDeletedProject(projectId, function(err) {
- if (err != null) {
- return next(err)
- } else {
- return res.sendStatus(200)
- }
- })
- },
- restoreProject(req, res) {
- const project_id = req.params.Project_id
- logger.log({ project_id }, 'received request to restore project')
- return projectDeleter.restoreProject(project_id, function(err) {
- if (err != null) {
- return res.sendStatus(500)
- } else {
- return res.sendStatus(200)
- }
- })
- },
- cloneProject(req, res, next) {
- res.setTimeout(5 * 60 * 1000) // allow extra time for the copy to complete
- metrics.inc('cloned-project')
- const project_id = req.params.Project_id
- const { projectName } = req.body
- logger.log({ project_id, projectName }, 'cloning project')
- if (!AuthenticationController.isUserLoggedIn(req)) {
- return res.send({ redir: '/register' })
- }
- const currentUser = AuthenticationController.getSessionUser(req)
- return projectDuplicator.duplicate(
- currentUser,
- project_id,
- projectName,
- function(err, project) {
- if (err != null) {
- logger.warn(
- { err, project_id, user_id: currentUser._id },
- 'error cloning project'
- )
- return next(err)
- }
- return res.send({
- name: project.name,
- project_id: project._id,
- owner_ref: project.owner_ref
- })
- }
- )
- },
- newProject(req, res, next) {
- const user_id = AuthenticationController.getLoggedInUserId(req)
- const projectName =
- req.body.projectName != null ? req.body.projectName.trim() : undefined
- const { template } = req.body
- logger.log(
- { user: user_id, projectType: template, name: projectName },
- 'creating project'
- )
- return async.waterfall(
- [
- function(cb) {
- if (template === 'example') {
- return projectCreationHandler.createExampleProject(
- user_id,
- projectName,
- cb
- )
- } else {
- return projectCreationHandler.createBasicProject(
- user_id,
- projectName,
- cb
- )
- }
- }
- ],
- function(err, project) {
- if (err != null) {
- return next(err)
- }
- logger.log(
- { project, user: user_id, name: projectName, templateType: template },
- 'created project'
- )
- return res.send({ project_id: project._id })
- }
- )
- },
- renameProject(req, res, next) {
- const project_id = req.params.Project_id
- const newName = req.body.newProjectName
- return editorController.renameProject(project_id, newName, function(err) {
- if (err != null) {
- return next(err)
- }
- return res.sendStatus(200)
- })
- },
- userProjectsJson(req, res, next) {
- const user_id = AuthenticationController.getLoggedInUserId(req)
- return ProjectGetter.findAllUsersProjects(
- user_id,
- 'name lastUpdated publicAccesLevel archived trashed owner_ref tokens',
- function(err, projects) {
- if (err != null) {
- return next(err)
- }
- projects = ProjectController._buildProjectList(projects, user_id)
- .filter(p => !ProjectHelper.isArchivedOrTrashed(p, user_id))
- .filter(p => !p.isV1Project)
- .map(p => ({ _id: p.id, name: p.name, accessLevel: p.accessLevel }))
- return res.json({ projects })
- }
- )
- },
- projectEntitiesJson(req, res, next) {
- const user_id = AuthenticationController.getLoggedInUserId(req)
- const project_id = req.params.Project_id
- return ProjectGetter.getProject(project_id, function(err, project) {
- if (err != null) {
- return next(err)
- }
- return ProjectEntityHandler.getAllEntitiesFromProject(project, function(
- err,
- docs,
- files
- ) {
- if (err != null) {
- return next(err)
- }
- const entities = docs
- .concat(files)
- .sort((a, b) => a.path > b.path) // Sort by path ascending
- .map(e => ({
- path: e.path,
- type: e.doc != null ? 'doc' : 'file'
- }))
- return res.json({ project_id, entities })
- })
- })
- },
- projectListPage(req, res, next) {
- const timer = new metrics.Timer('project-list')
- const user_id = AuthenticationController.getLoggedInUserId(req)
- const currentUser = AuthenticationController.getSessionUser(req)
- return async.parallel(
- {
- tags(cb) {
- return TagsHandler.getAllTags(user_id, cb)
- },
- notifications(cb) {
- return NotificationsHandler.getUserNotifications(user_id, cb)
- },
- projects(cb) {
- return ProjectGetter.findAllUsersProjects(
- user_id,
- 'name lastUpdated lastUpdatedBy publicAccesLevel archived owner_ref tokens',
- cb
- )
- },
- v1Projects(cb) {
- if (!Features.hasFeature('overleaf-integration')) {
- return cb(null, null)
- }
- return Modules.hooks.fire('findAllV1Projects', user_id, function(
- error,
- projects
- ) {
- if (projects == null) {
- projects = []
- }
- if (error != null && error instanceof V1ConnectionError) {
- return cb(null, { projects: [], tags: [], noConnection: true })
- }
- return cb(error, projects[0])
- })
- }, // hooks.fire returns an array of results, only need first
- hasSubscription(cb) {
- return LimitationsManager.hasPaidSubscription(currentUser, function(
- error,
- hasPaidSubscription
- ) {
- if (error != null && error instanceof V1ConnectionError) {
- return cb(null, true)
- }
- return cb(error, hasPaidSubscription)
- })
- },
- user(cb) {
- return User.findById(
- user_id,
- 'featureSwitches overleaf awareOfV2 features',
- cb
- )
- },
- userAffiliations(cb) {
- if (!Features.hasFeature('affiliations')) {
- return cb(null, null)
- }
- return getUserAffiliations(user_id, cb)
- }
- },
- function(err, results) {
- if (err != null) {
- logger.warn({ err }, 'error getting data for project list page')
- return next(err)
- }
- const v1Tags =
- (results.v1Projects != null ? results.v1Projects.tags : undefined) ||
- []
- const tags = results.tags.concat(v1Tags)
- const notifications = require('underscore').map(
- results.notifications,
- function(notification) {
- notification.html = req.i18n.translate(
- notification.templateKey,
- notification.messageOpts
- )
- return notification
- }
- )
- const portalTemplates = ProjectController._buildPortalTemplatesList(
- results.userAffiliations
- )
- const projects = ProjectController._buildProjectList(
- results.projects,
- user_id,
- results.v1Projects != null ? results.v1Projects.projects : undefined
- )
- const { user } = results
- const { userAffiliations } = results
- const warnings = ProjectController._buildWarningsList(
- results.v1Projects
- )
- // in v2 add notifications for matching university IPs
- if (Settings.overleaf != null) {
- UserGetter.getUser(user_id, { lastLoginIp: 1 }, function(
- error,
- user
- ) {
- if (req.ip !== user.lastLoginIp) {
- return NotificationsBuilder.ipMatcherAffiliation(user._id).create(
- req.ip
- )
- }
- })
- }
- return ProjectController._injectProjectUsers(projects, function(
- error,
- projects
- ) {
- if (error != null) {
- return next(error)
- }
- const viewModel = {
- title: 'your_projects',
- priority_title: true,
- projects,
- tags,
- notifications: notifications || [],
- portalTemplates,
- user,
- userAffiliations,
- hasSubscription: results.hasSubscription,
- isShowingV1Projects: results.v1Projects != null,
- warnings,
- zipFileSizeLimit: Settings.maxUploadSize
- }
- if (
- Settings.algolia &&
- Settings.algolia.app_id &&
- Settings.algolia.read_only_api_key
- ) {
- viewModel.showUserDetailsArea = true
- viewModel.algolia_api_key = Settings.algolia.read_only_api_key
- viewModel.algolia_app_id = Settings.algolia.app_id
- } else {
- viewModel.showUserDetailsArea = false
- }
- const paidUser =
- (user.features != null ? user.features.github : undefined) &&
- (user.features != null ? user.features.dropbox : undefined) // use a heuristic for paid account
- const freeUserProportion = 0.1
- const sampleFreeUser =
- parseInt(user._id.toString().slice(-2), 16) <
- freeUserProportion * 255
- const showFrontWidget = paidUser || sampleFreeUser
- logger.log(
- { paidUser, sampleFreeUser, showFrontWidget },
- 'deciding whether to show front widget'
- )
- if (showFrontWidget) {
- viewModel.frontChatWidgetRoomId =
- Settings.overleaf != null
- ? Settings.overleaf.front_chat_widget_room_id
- : undefined
- }
- res.render('project/list', viewModel)
- return timer.done()
- })
- }
- )
- },
- loadEditor(req, res, next) {
- let anonymous, user_id
- const timer = new metrics.Timer('load-editor')
- if (!Settings.editorIsOpen) {
- return res.render('general/closed', { title: 'updating_site' })
- }
- if (AuthenticationController.isUserLoggedIn(req)) {
- user_id = AuthenticationController.getLoggedInUserId(req)
- anonymous = false
- } else {
- anonymous = true
- user_id = null
- }
- const project_id = req.params.Project_id
- logger.log({ project_id, anonymous, user_id }, 'loading editor')
- // record failures to load the custom websocket
- if ((req.query != null ? req.query.ws : undefined) === 'fallback') {
- metrics.inc('load-editor-ws-fallback')
- }
- return async.auto(
- {
- project(cb) {
- return ProjectGetter.getProject(
- project_id,
- {
- name: 1,
- lastUpdated: 1,
- track_changes: 1,
- owner_ref: 1,
- brandVariationId: 1,
- overleaf: 1,
- tokens: 1
- },
- function(err, project) {
- if (err != null) {
- return cb(err)
- }
- if (
- (project.overleaf != null ? project.overleaf.id : undefined) ==
- null ||
- (project.tokens != null
- ? project.tokens.readAndWrite
- : undefined) == null ||
- Settings.projectImportingCheckMaxCreateDelta == null
- ) {
- return cb(null, project)
- }
- const createDelta =
- (new Date().getTime() -
- new Date(project._id.getTimestamp()).getTime()) /
- 1000
- if (
- !(createDelta < Settings.projectImportingCheckMaxCreateDelta)
- ) {
- return cb(null, project)
- }
- return V1Handler.getDocExported(
- project.tokens.readAndWrite,
- function(err, doc_exported) {
- if (err != null) {
- return next(err)
- }
- project.exporting = doc_exported.exporting
- return cb(null, project)
- }
- )
- }
- )
- },
- user(cb) {
- if (user_id == null) {
- return cb(null, defaultSettingsForAnonymousUser(user_id))
- } else {
- return User.findById(user_id, function(err, user) {
- logger.log({ project_id, user_id }, 'got user')
- return cb(err, user)
- })
- }
- },
- subscription(cb) {
- if (user_id == null) {
- return cb()
- }
- return SubscriptionLocator.getUsersSubscription(user_id, cb)
- },
- activate(cb) {
- return InactiveProjectManager.reactivateProjectIfRequired(
- project_id,
- cb
- )
- },
- markAsOpened(cb) {
- // don't need to wait for this to complete
- ProjectUpdateHandler.markAsOpened(project_id, function() {})
- return cb()
- },
- isTokenMember(cb) {
- cb = underscore.once(cb)
- if (user_id == null) {
- return cb()
- }
- return CollaboratorsHandler.userIsTokenMember(user_id, project_id, cb)
- },
- brandVariation: [
- 'project',
- function(cb, results) {
- if (
- (results.project != null
- ? results.project.brandVariationId
- : undefined) == null
- ) {
- return cb()
- }
- return BrandVariationsHandler.getBrandVariationById(
- results.project.brandVariationId,
- (error, brandVariationDetails) => cb(error, brandVariationDetails)
- )
- }
- ]
- },
- function(err, results) {
- if (err != null) {
- logger.warn({ err }, 'error getting details for project page')
- return next(err)
- }
- const { project } = results
- const { user } = results
- const { subscription } = results
- const { brandVariation } = results
- const daysSinceLastUpdated =
- (new Date() - project.lastUpdated) / 86400000
- logger.log(
- { project_id, daysSinceLastUpdated },
- 'got db results for loading editor'
- )
- const token = TokenAccessHandler.getRequestToken(req, project_id)
- const { isTokenMember } = results
- return AuthorizationManager.getPrivilegeLevelForProject(
- user_id,
- project_id,
- token,
- function(error, privilegeLevel) {
- let allowedFreeTrial
- if (error != null) {
- return next(error)
- }
- if (
- privilegeLevel == null ||
- privilegeLevel === PrivilegeLevels.NONE
- ) {
- return res.sendStatus(401)
- }
- if (project.exporting) {
- res.render('project/importing', { bodyClasses: ['editor'] })
- return
- }
- if (
- subscription != null &&
- subscription.freeTrial != null &&
- subscription.freeTrial.expiresAt != null
- ) {
- allowedFreeTrial = !!subscription.freeTrial.allowed || true
- }
- logger.log({ project_id }, 'rendering editor page')
- res.render('project/editor', {
- title: project.name,
- priority_title: true,
- bodyClasses: ['editor'],
- project_id: project._id,
- user: {
- id: user_id,
- email: user.email,
- first_name: user.first_name,
- last_name: user.last_name,
- referal_id: user.referal_id,
- signUpDate: user.signUpDate,
- subscription: {
- freeTrial: { allowed: allowedFreeTrial }
- },
- featureSwitches: user.featureSwitches,
- features: user.features,
- refProviders: user.refProviders,
- betaProgram: user.betaProgram,
- isAdmin: user.isAdmin
- },
- userSettings: {
- mode: user.ace.mode,
- editorTheme: user.ace.theme,
- fontSize: user.ace.fontSize,
- autoComplete: user.ace.autoComplete,
- autoPairDelimiters: user.ace.autoPairDelimiters,
- pdfViewer: user.ace.pdfViewer,
- syntaxValidation: user.ace.syntaxValidation,
- fontFamily: user.ace.fontFamily,
- lineHeight: user.ace.lineHeight,
- overallTheme: user.ace.overallTheme
- },
- trackChangesState: project.track_changes,
- privilegeLevel,
- chatUrl: Settings.apis.chat.url,
- anonymous,
- anonymousAccessToken: req._anonymousAccessToken,
- isTokenMember,
- isRestrictedTokenMember:
- isTokenMember === true && privilegeLevel === 'readOnly',
- languages: Settings.languages,
- editorThemes: THEME_LIST,
- maxDocLength: Settings.max_doc_length,
- useV2History: !!__guard__(
- project.overleaf != null ? project.overleaf.history : undefined,
- x => x.display
- ),
- showTestControls:
- (req.query != null ? req.query.tc : undefined) === 'true' ||
- user.isAdmin,
- brandVariation,
- allowedImageNames: Settings.allowedImageNames || [],
- gitBridgePublicBaseUrl: Settings.gitBridgePublicBaseUrl
- })
- return timer.done()
- }
- )
- }
- )
- },
- _buildProjectList(allProjects, userId, v1Projects) {
- let project
- if (v1Projects == null) {
- v1Projects = []
- }
- const {
- owned,
- readAndWrite,
- readOnly,
- tokenReadAndWrite,
- tokenReadOnly
- } = allProjects
- const projects = []
- for (project of Array.from(owned)) {
- projects.push(
- ProjectController._buildProjectViewModel(
- project,
- 'owner',
- Sources.OWNER,
- userId
- )
- )
- }
- // Invite-access
- for (project of Array.from(readAndWrite)) {
- projects.push(
- ProjectController._buildProjectViewModel(
- project,
- 'readWrite',
- Sources.INVITE,
- userId
- )
- )
- }
- for (project of Array.from(readOnly)) {
- projects.push(
- ProjectController._buildProjectViewModel(
- project,
- 'readOnly',
- Sources.INVITE,
- userId
- )
- )
- }
- for (project of Array.from(v1Projects)) {
- projects.push(ProjectController._buildV1ProjectViewModel(project))
- }
- // Token-access
- // Only add these projects if they're not already present, this gives us cascading access
- // from 'owner' => 'token-read-only'
- for (project of Array.from(tokenReadAndWrite)) {
- if (
- projects.filter(p => p.id.toString() === project._id.toString())
- .length === 0
- ) {
- projects.push(
- ProjectController._buildProjectViewModel(
- project,
- 'readAndWrite',
- Sources.TOKEN,
- userId
- )
- )
- }
- }
- for (project of Array.from(tokenReadOnly)) {
- if (
- projects.filter(p => p.id.toString() === project._id.toString())
- .length === 0
- ) {
- projects.push(
- ProjectController._buildProjectViewModel(
- project,
- 'readOnly',
- Sources.TOKEN,
- userId
- )
- )
- }
- }
- return projects
- },
- _buildProjectViewModel(project, accessLevel, source, userId) {
- TokenAccessHandler.protectTokens(project, accessLevel)
- const model = {
- id: project._id,
- name: project.name,
- lastUpdated: project.lastUpdated,
- lastUpdatedBy: project.lastUpdatedBy,
- publicAccessLevel: project.publicAccesLevel,
- accessLevel,
- source,
- archived: ProjectHelper.isArchived(project, userId),
- owner_ref: project.owner_ref,
- tokens: project.tokens,
- isV1Project: false
- }
- if (accessLevel === PrivilegeLevels.READ_ONLY && source === Sources.TOKEN) {
- model.owner_ref = null
- model.lastUpdatedBy = null
- }
- return model
- },
- _buildV1ProjectViewModel(project) {
- const projectViewModel = {
- id: project.id,
- name: project.title,
- lastUpdated: new Date(project.updated_at * 1000), // Convert from epoch
- archived: project.removed || project.archived,
- isV1Project: true
- }
- if (
- (project.owner != null && project.owner.user_is_owner) ||
- (project.creator != null && project.creator.user_is_creator)
- ) {
- projectViewModel.accessLevel = 'owner'
- } else {
- projectViewModel.accessLevel = 'readOnly'
- }
- if (project.owner != null) {
- projectViewModel.owner = {
- first_name: project.owner.name
- }
- } else if (project.creator != null) {
- projectViewModel.owner = {
- first_name: project.creator.name
- }
- }
- return projectViewModel
- },
- _injectProjectUsers(projects, callback) {
- let project
- if (callback == null) {
- callback = function(error, projects) {}
- }
- const users = {}
- for (project of Array.from(projects)) {
- if (project.owner_ref != null) {
- users[project.owner_ref.toString()] = true
- }
- if (project.lastUpdatedBy != null) {
- users[project.lastUpdatedBy.toString()] = true
- }
- }
- const jobs = []
- for (let user_id in users) {
- const _ = users[user_id]
- ;(user_id =>
- jobs.push(callback =>
- UserGetter.getUserOrUserStubById(
- user_id,
- { first_name: 1, last_name: 1, email: 1 },
- function(error, user) {
- if (error != null) {
- return callback(error)
- }
- users[user_id] = user
- return callback()
- }
- )
- ))(user_id)
- }
- return async.series(jobs, function(error) {
- for (project of Array.from(projects)) {
- if (project.owner_ref != null) {
- project.owner = users[project.owner_ref.toString()]
- }
- if (project.lastUpdatedBy != null) {
- project.lastUpdatedBy =
- users[project.lastUpdatedBy.toString()] || null
- }
- }
- return callback(null, projects)
- })
- },
- _buildWarningsList(v1ProjectData) {
- if (v1ProjectData == null) {
- v1ProjectData = {}
- }
- const warnings = []
- if (v1ProjectData.noConnection && Settings.overleaf) {
- warnings.push('No V1 Connection')
- }
- if (v1ProjectData.hasHiddenV1Projects) {
- warnings.push(
- "Looks like you've got a lot of V1 projects! Some of them may be hidden on V2. To view them all, use the V1 dashboard."
- )
- }
- return warnings
- },
- _buildPortalTemplatesList(affiliations) {
- if (affiliations == null) {
- affiliations = []
- }
- const portalTemplates = []
- for (let aff of Array.from(affiliations)) {
- if (
- aff.portal &&
- aff.portal.slug &&
- aff.portal.templates_count &&
- aff.portal.templates_count > 0
- ) {
- const portalPath = aff.institution.isUniversity ? '/edu/' : '/org/'
- portalTemplates.push({
- name: aff.institution.name,
- url: Settings.siteUrl + portalPath + aff.portal.slug
- })
- }
- }
- return portalTemplates
- }
- }
- var defaultSettingsForAnonymousUser = user_id => ({
- id: user_id,
- ace: {
- mode: 'none',
- theme: 'textmate',
- fontSize: '12',
- autoComplete: true,
- spellCheckLanguage: '',
- pdfViewer: '',
- syntaxValidation: true
- },
- subscription: {
- freeTrial: {
- allowed: true
- }
- },
- featureSwitches: {
- github: false
- }
- })
- var THEME_LIST = []
- ;(generateThemeList = function() {
- const files = fs.readdirSync(
- __dirname + '/../../../../public/js/' + PackageVersions.lib('ace')
- )
- return (() => {
- const result = []
- for (let file of Array.from(files)) {
- if (file.slice(-2) === 'js' && /^theme-/.test(file)) {
- const cleanName = file.slice(0, -3).slice(6)
- result.push(THEME_LIST.push(cleanName))
- } else {
- result.push(undefined)
- }
- }
- return result
- })()
- })()
- function __guard__(value, transform) {
- return typeof value !== 'undefined' && value !== null
- ? transform(value)
- : undefined
- }
|