mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-14 20:40:17 -05:00
Merge pull request #11869 from overleaf/em-upgrade-mongoose-web
Upgrade Mongoose and the Mongo driver in web GitOrigin-RevId: 2cad1aabe57eae424a9e4c68b2e0062f0e78ffaf
This commit is contained in:
parent
076bc9b39c
commit
65976cb363
43 changed files with 660 additions and 474 deletions
205
package-lock.json
generated
205
package-lock.json
generated
|
@ -34519,8 +34519,8 @@
|
|||
"minimist": "^1.2.7",
|
||||
"mmmagic": "^0.5.3",
|
||||
"moment": "^2.29.4",
|
||||
"mongodb": "~3.6.0",
|
||||
"mongoose": "^5.13.11",
|
||||
"mongodb": "^4.13.0",
|
||||
"mongoose": "^6.9.1",
|
||||
"multer": "overleaf/multer#e1df247fbf8e7590520d20ae3601eaef9f3d2e9e",
|
||||
"nocache": "^2.1.0",
|
||||
"nock": "^13.1.3",
|
||||
|
@ -34910,6 +34910,40 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/bson": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
|
||||
"integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==",
|
||||
"dependencies": {
|
||||
"buffer": "^5.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/bson/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
|
@ -35934,6 +35968,14 @@
|
|||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/kareem": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
|
||||
"integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/karma-webpack": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-5.0.0.tgz",
|
||||
|
@ -36094,41 +36136,60 @@
|
|||
}
|
||||
},
|
||||
"services/web/node_modules/mongodb": {
|
||||
"version": "3.6.12",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.12.tgz",
|
||||
"integrity": "sha512-ErHpF4P4disEIQB8Nns2twIMVXcvmlwjpKqfVnyB/hhd/L5We48LfoBYjBjuUSiSqL6ffmcygPTgjvpy2LETRQ==",
|
||||
"version": "4.13.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.13.0.tgz",
|
||||
"integrity": "sha512-+taZ/bV8d1pYuHL4U+gSwkhmDrwkWbH1l4aah4YpmpscMwgFBkufIKxgP/G7m87/NUuQzc2Z75ZTI7ZOyqZLbw==",
|
||||
"dependencies": {
|
||||
"bl": "^2.2.1",
|
||||
"bson": "^1.1.4",
|
||||
"denque": "^1.4.1",
|
||||
"optional-require": "^1.0.3",
|
||||
"safe-buffer": "^5.1.2"
|
||||
"bson": "^4.7.0",
|
||||
"mongodb-connection-string-url": "^2.5.4",
|
||||
"socks": "^2.7.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
"node": ">=12.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"saslprep": "^1.0.0"
|
||||
"@aws-sdk/credential-providers": "^3.186.0",
|
||||
"saslprep": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/mongoose": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.9.1.tgz",
|
||||
"integrity": "sha512-hOz1ZWV0w6WEVLrj89Wpk7PXDYtDDF6k7/NX79lY5iKqeFtZsceBXW8xW59YFNcW5O3cH32hQ8IbDlhgyBsDMA==",
|
||||
"dependencies": {
|
||||
"bson": "^4.7.0",
|
||||
"kareem": "2.5.1",
|
||||
"mongodb": "4.13.0",
|
||||
"mpath": "0.9.0",
|
||||
"mquery": "4.0.3",
|
||||
"ms": "2.1.3",
|
||||
"sift": "16.0.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"aws4": {
|
||||
"optional": true
|
||||
},
|
||||
"bson-ext": {
|
||||
"optional": true
|
||||
},
|
||||
"kerberos": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-client-encryption": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-extjson": {
|
||||
"optional": true
|
||||
},
|
||||
"snappy": {
|
||||
"optional": true
|
||||
}
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mongoose"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/mpath": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/mquery": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz",
|
||||
"integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==",
|
||||
"dependencies": {
|
||||
"debug": "4.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/multer": {
|
||||
|
@ -36814,6 +36875,11 @@
|
|||
"stack-trace": "0.0.10"
|
||||
}
|
||||
},
|
||||
"services/web/node_modules/sift": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz",
|
||||
"integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="
|
||||
},
|
||||
"services/web/node_modules/sinon": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz",
|
||||
|
@ -43734,8 +43800,8 @@
|
|||
"mocha-each": "^2.0.1",
|
||||
"mock-fs": "^5.1.2",
|
||||
"moment": "^2.29.4",
|
||||
"mongodb": "~3.6.0",
|
||||
"mongoose": "^5.13.11",
|
||||
"mongodb": "^4.13.0",
|
||||
"mongoose": "^6.9.1",
|
||||
"multer": "overleaf/multer#e1df247fbf8e7590520d20ae3601eaef9f3d2e9e",
|
||||
"nocache": "^2.1.0",
|
||||
"nock": "^13.1.1",
|
||||
|
@ -43993,6 +44059,25 @@
|
|||
"integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==",
|
||||
"dev": true
|
||||
},
|
||||
"bson": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
|
||||
"integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==",
|
||||
"requires": {
|
||||
"buffer": "^5.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
|
@ -44710,6 +44795,11 @@
|
|||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"kareem": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
|
||||
"integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA=="
|
||||
},
|
||||
"karma-webpack": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-5.0.0.tgz",
|
||||
|
@ -44829,16 +44919,42 @@
|
|||
}
|
||||
},
|
||||
"mongodb": {
|
||||
"version": "3.6.12",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.12.tgz",
|
||||
"integrity": "sha512-ErHpF4P4disEIQB8Nns2twIMVXcvmlwjpKqfVnyB/hhd/L5We48LfoBYjBjuUSiSqL6ffmcygPTgjvpy2LETRQ==",
|
||||
"version": "4.13.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.13.0.tgz",
|
||||
"integrity": "sha512-+taZ/bV8d1pYuHL4U+gSwkhmDrwkWbH1l4aah4YpmpscMwgFBkufIKxgP/G7m87/NUuQzc2Z75ZTI7ZOyqZLbw==",
|
||||
"requires": {
|
||||
"bl": "^2.2.1",
|
||||
"bson": "^1.1.4",
|
||||
"denque": "^1.4.1",
|
||||
"optional-require": "^1.0.3",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"saslprep": "^1.0.0"
|
||||
"@aws-sdk/credential-providers": "^3.186.0",
|
||||
"bson": "^4.7.0",
|
||||
"mongodb-connection-string-url": "^2.5.4",
|
||||
"saslprep": "^1.0.3",
|
||||
"socks": "^2.7.1"
|
||||
}
|
||||
},
|
||||
"mongoose": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.9.1.tgz",
|
||||
"integrity": "sha512-hOz1ZWV0w6WEVLrj89Wpk7PXDYtDDF6k7/NX79lY5iKqeFtZsceBXW8xW59YFNcW5O3cH32hQ8IbDlhgyBsDMA==",
|
||||
"requires": {
|
||||
"bson": "^4.7.0",
|
||||
"kareem": "2.5.1",
|
||||
"mongodb": "4.13.0",
|
||||
"mpath": "0.9.0",
|
||||
"mquery": "4.0.3",
|
||||
"ms": "2.1.3",
|
||||
"sift": "16.0.1"
|
||||
}
|
||||
},
|
||||
"mpath": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew=="
|
||||
},
|
||||
"mquery": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz",
|
||||
"integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==",
|
||||
"requires": {
|
||||
"debug": "4.x"
|
||||
}
|
||||
},
|
||||
"multer": {
|
||||
|
@ -45289,6 +45405,11 @@
|
|||
"stack-trace": "0.0.10"
|
||||
}
|
||||
},
|
||||
"sift": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz",
|
||||
"integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="
|
||||
},
|
||||
"sinon": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz",
|
||||
|
|
|
@ -109,7 +109,7 @@ const AuthenticationManager = {
|
|||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
if (result.nModified !== 1) {
|
||||
if (result.modifiedCount !== 1) {
|
||||
return callback(new ParallelLoginError())
|
||||
}
|
||||
if (!match) {
|
||||
|
|
|
@ -234,7 +234,7 @@ async function setCollaboratorPrivilegeLevel(
|
|||
}
|
||||
}
|
||||
const mongoResponse = await Project.updateOne(query, update).exec()
|
||||
if (mongoResponse.n === 0) {
|
||||
if (mongoResponse.matchedCount === 0) {
|
||||
throw new Errors.NotFoundError('project or collaborator not found')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ const ProjectHistoryHandler = {
|
|||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
if (result.n === 0) {
|
||||
if (result.matchedCount === 0) {
|
||||
return callback(new Error('history exists'))
|
||||
}
|
||||
callback()
|
||||
|
@ -57,7 +57,7 @@ const ProjectHistoryHandler = {
|
|||
return callback(err)
|
||||
}
|
||||
// return an error if overleaf.history.id wasn't present
|
||||
if (result.n === 0) {
|
||||
if (result.matchedCount === 0) {
|
||||
return callback(new Error('history not upgraded'))
|
||||
}
|
||||
callback()
|
||||
|
@ -76,7 +76,7 @@ const ProjectHistoryHandler = {
|
|||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
if (result.n === 0) {
|
||||
if (result.matchedCount === 0) {
|
||||
return callback(new Error('history not downgraded'))
|
||||
}
|
||||
callback()
|
||||
|
@ -94,7 +94,7 @@ const ProjectHistoryHandler = {
|
|||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
if (result.n === 0) {
|
||||
if (result.matchedCount === 0) {
|
||||
return callback(new Error('migration flag not set'))
|
||||
}
|
||||
callback()
|
||||
|
|
|
@ -12,20 +12,14 @@ if (
|
|||
)
|
||||
}
|
||||
|
||||
mongoose.set('autoIndex', false)
|
||||
mongoose.set('strictQuery', false)
|
||||
|
||||
const connectionPromise = mongoose.connect(
|
||||
Settings.mongo.url,
|
||||
Object.assign(
|
||||
{
|
||||
// mongoose specific config
|
||||
config: { autoIndex: false },
|
||||
// mongoose defaults to false, native driver defaults to true
|
||||
useNewUrlParser: true,
|
||||
// use the equivalent `findOneAndUpdate` methods of the native driver
|
||||
useFindAndModify: false,
|
||||
},
|
||||
Settings.mongo.options
|
||||
)
|
||||
Settings.mongo.options
|
||||
)
|
||||
|
||||
addConnectionDrainer('mongoose', async () => {
|
||||
await connectionPromise
|
||||
await mongoose.disconnect()
|
||||
|
|
|
@ -14,7 +14,7 @@ const DeletedFileSchema = new Schema(
|
|||
},
|
||||
deletedAt: { type: Date },
|
||||
},
|
||||
{ collection: 'deletedFiles' }
|
||||
{ collection: 'deletedFiles', minimize: false }
|
||||
)
|
||||
|
||||
exports.DeletedFile = mongoose.model('DeletedFile', DeletedFileSchema)
|
||||
|
|
|
@ -26,7 +26,7 @@ const DeletedProjectSchema = new Schema(
|
|||
deleterData: DeleterDataSchema,
|
||||
project: ProjectSchema,
|
||||
},
|
||||
{ collection: 'deletedProjects' }
|
||||
{ collection: 'deletedProjects', minimize: false }
|
||||
)
|
||||
|
||||
exports.DeletedProject = mongoose.model('DeletedProject', DeletedProjectSchema)
|
||||
|
|
|
@ -23,7 +23,7 @@ const DeletedSubscriptionSchema = new Schema(
|
|||
deleterData: DeleterDataSchema,
|
||||
subscription: SubscriptionSchema,
|
||||
},
|
||||
{ collection: 'deletedSubscriptions' }
|
||||
{ collection: 'deletedSubscriptions', minimize: false }
|
||||
)
|
||||
|
||||
exports.DeletedSubscription = mongoose.model(
|
||||
|
|
|
@ -23,7 +23,7 @@ const DeletedUserSchema = new Schema(
|
|||
deleterData: DeleterDataSchema,
|
||||
user: UserSchema,
|
||||
},
|
||||
{ collection: 'deletedUsers' }
|
||||
{ collection: 'deletedUsers', minimize: false }
|
||||
)
|
||||
|
||||
exports.DeletedUser = mongoose.model('DeletedUser', DeletedUserSchema)
|
||||
|
|
|
@ -2,9 +2,12 @@ const mongoose = require('../infrastructure/Mongoose')
|
|||
|
||||
const { Schema } = mongoose
|
||||
|
||||
const DocSchema = new Schema({
|
||||
name: { type: String, default: 'new doc' },
|
||||
})
|
||||
const DocSchema = new Schema(
|
||||
{
|
||||
name: { type: String, default: 'new doc' },
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.Doc = mongoose.model('Doc', DocSchema)
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ const DocSnapshotSchema = new Schema(
|
|||
ranges: Schema.Types.Mixed,
|
||||
ts: Date,
|
||||
},
|
||||
{ collection: 'docSnapshots' }
|
||||
{ collection: 'docSnapshots', minimize: false }
|
||||
)
|
||||
|
||||
exports.DocSnapshot = mongoose.model('DocSnapshot', DocSnapshotSchema)
|
||||
|
|
|
@ -2,20 +2,23 @@ const mongoose = require('../infrastructure/Mongoose')
|
|||
const { Schema } = mongoose
|
||||
const { ObjectId } = Schema
|
||||
|
||||
const FeedbackSchema = new Schema({
|
||||
userId: {
|
||||
type: ObjectId,
|
||||
ref: 'User',
|
||||
},
|
||||
source: String,
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
const FeedbackSchema = new Schema(
|
||||
{
|
||||
userId: {
|
||||
type: ObjectId,
|
||||
ref: 'User',
|
||||
},
|
||||
source: String,
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
data: {},
|
||||
})
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.Feedback = mongoose.model('Feedback', FeedbackSchema)
|
||||
exports.FeedbackSchema = FeedbackSchema
|
||||
|
|
|
@ -2,23 +2,26 @@ const mongoose = require('../infrastructure/Mongoose')
|
|||
|
||||
const { Schema } = mongoose
|
||||
|
||||
const FileSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
created: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
const FileSchema = new Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
created: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
rev: { type: Number, default: 0 },
|
||||
linkedFileData: { type: Schema.Types.Mixed },
|
||||
hash: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
rev: { type: Number, default: 0 },
|
||||
linkedFileData: { type: Schema.Types.Mixed },
|
||||
hash: {
|
||||
type: String,
|
||||
},
|
||||
})
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.File = mongoose.model('File', FileSchema)
|
||||
exports.FileSchema = FileSchema
|
||||
|
|
|
@ -4,9 +4,12 @@ const { FileSchema } = require('./File')
|
|||
|
||||
const { Schema } = mongoose
|
||||
|
||||
const FolderSchema = new Schema({
|
||||
name: { type: String, default: 'new folder' },
|
||||
})
|
||||
const FolderSchema = new Schema(
|
||||
{
|
||||
name: { type: String, default: 'new folder' },
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
FolderSchema.add({
|
||||
docs: [DocSchema],
|
||||
|
|
|
@ -5,14 +5,17 @@ const settings = require('@overleaf/settings')
|
|||
const logger = require('@overleaf/logger')
|
||||
const request = require('request')
|
||||
|
||||
const InstitutionSchema = new Schema({
|
||||
v1Id: { type: Number, required: true },
|
||||
managerIds: [{ type: ObjectId, ref: 'User' }],
|
||||
metricsEmail: {
|
||||
optedOutUserIds: [{ type: ObjectId, ref: 'User' }],
|
||||
lastSent: { type: Date },
|
||||
const InstitutionSchema = new Schema(
|
||||
{
|
||||
v1Id: { type: Number, required: true },
|
||||
managerIds: [{ type: ObjectId, ref: 'User' }],
|
||||
metricsEmail: {
|
||||
optedOutUserIds: [{ type: ObjectId, ref: 'User' }],
|
||||
lastSent: { type: Date },
|
||||
},
|
||||
},
|
||||
})
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
// fetch institution's data from v1 API. Errors are ignored
|
||||
InstitutionSchema.method('fetchV1Data', function (callback) {
|
||||
|
|
|
@ -15,6 +15,7 @@ const OauthAccessTokenSchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'oauthAccessTokens',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ const OauthApplicationSchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'oauthApplications',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ const OauthAuthorizationCodeSchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'oauthAuthorizationCodes',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -24,92 +24,95 @@ const DeletedFileSchema = new Schema({
|
|||
deletedAt: { type: Date },
|
||||
})
|
||||
|
||||
const ProjectSchema = new Schema({
|
||||
name: { type: String, default: 'new project' },
|
||||
lastUpdated: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
lastUpdatedBy: { type: ObjectId, ref: 'User' },
|
||||
lastOpened: { type: Date },
|
||||
active: { type: Boolean, default: true },
|
||||
owner_ref: { type: ObjectId, ref: 'User' },
|
||||
collaberator_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
readOnly_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
rootDoc_id: { type: ObjectId },
|
||||
rootFolder: [FolderSchema],
|
||||
version: { type: Number }, // incremented for every change in the project structure (folders and filenames)
|
||||
publicAccesLevel: { type: String, default: 'private' },
|
||||
compiler: { type: String, default: 'pdflatex' },
|
||||
spellCheckLanguage: { type: String, default: 'en' },
|
||||
deletedByExternalDataSource: { type: Boolean, default: false },
|
||||
description: { type: String, default: '' },
|
||||
archived: { type: Schema.Types.Mixed },
|
||||
trashed: [{ type: ObjectId, ref: 'User' }],
|
||||
deletedDocs: [DeletedDocSchema],
|
||||
deletedFiles: [DeletedFileSchema],
|
||||
imageName: { type: String },
|
||||
brandVariationId: { type: String },
|
||||
track_changes: { type: Object },
|
||||
tokens: {
|
||||
readOnly: {
|
||||
type: String,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: { 'tokens.readOnly': { $exists: true } },
|
||||
const ProjectSchema = new Schema(
|
||||
{
|
||||
name: { type: String, default: 'new project' },
|
||||
lastUpdated: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
readAndWrite: {
|
||||
type: String,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: { 'tokens.readAndWrite': { $exists: true } },
|
||||
lastUpdatedBy: { type: ObjectId, ref: 'User' },
|
||||
lastOpened: { type: Date },
|
||||
active: { type: Boolean, default: true },
|
||||
owner_ref: { type: ObjectId, ref: 'User' },
|
||||
collaberator_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
readOnly_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
rootDoc_id: { type: ObjectId },
|
||||
rootFolder: [FolderSchema],
|
||||
version: { type: Number }, // incremented for every change in the project structure (folders and filenames)
|
||||
publicAccesLevel: { type: String, default: 'private' },
|
||||
compiler: { type: String, default: 'pdflatex' },
|
||||
spellCheckLanguage: { type: String, default: 'en' },
|
||||
deletedByExternalDataSource: { type: Boolean, default: false },
|
||||
description: { type: String, default: '' },
|
||||
archived: { type: Schema.Types.Mixed },
|
||||
trashed: [{ type: ObjectId, ref: 'User' }],
|
||||
deletedDocs: [DeletedDocSchema],
|
||||
deletedFiles: [DeletedFileSchema],
|
||||
imageName: { type: String },
|
||||
brandVariationId: { type: String },
|
||||
track_changes: { type: Object },
|
||||
tokens: {
|
||||
readOnly: {
|
||||
type: String,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: { 'tokens.readOnly': { $exists: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
readAndWritePrefix: {
|
||||
type: String,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: {
|
||||
'tokens.readAndWritePrefix': { $exists: true },
|
||||
readAndWrite: {
|
||||
type: String,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: { 'tokens.readAndWrite': { $exists: true } },
|
||||
},
|
||||
},
|
||||
readAndWritePrefix: {
|
||||
type: String,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: {
|
||||
'tokens.readAndWritePrefix': { $exists: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tokenAccessReadOnly_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
tokenAccessReadAndWrite_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
fromV1TemplateId: { type: Number },
|
||||
fromV1TemplateVersionId: { type: Number },
|
||||
overleaf: {
|
||||
id: { type: Number },
|
||||
imported_at_ver_id: { type: Number },
|
||||
token: { type: String },
|
||||
read_token: { type: String },
|
||||
history: {
|
||||
id: { type: Schema.Types.Mixed },
|
||||
display: { type: Boolean },
|
||||
upgradedAt: { type: Date },
|
||||
allowDowngrade: { type: Boolean },
|
||||
zipFileArchivedInProject: { type: Boolean },
|
||||
},
|
||||
},
|
||||
collabratecUsers: [
|
||||
{
|
||||
user_id: { type: ObjectId, ref: 'User' },
|
||||
collabratec_document_id: { type: String },
|
||||
collabratec_privategroup_id: { type: String },
|
||||
added_at: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
tokenAccessReadOnly_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
tokenAccessReadAndWrite_refs: [{ type: ObjectId, ref: 'User' }],
|
||||
fromV1TemplateId: { type: Number },
|
||||
fromV1TemplateVersionId: { type: Number },
|
||||
overleaf: {
|
||||
id: { type: Number },
|
||||
imported_at_ver_id: { type: Number },
|
||||
token: { type: String },
|
||||
read_token: { type: String },
|
||||
history: {
|
||||
id: { type: Schema.Types.Mixed },
|
||||
display: { type: Boolean },
|
||||
upgradedAt: { type: Date },
|
||||
allowDowngrade: { type: Boolean },
|
||||
zipFileArchivedInProject: { type: Boolean },
|
||||
},
|
||||
},
|
||||
],
|
||||
deferredTpdsFlushCounter: { type: Number },
|
||||
})
|
||||
collabratecUsers: [
|
||||
{
|
||||
user_id: { type: ObjectId, ref: 'User' },
|
||||
collabratec_document_id: { type: String },
|
||||
collabratec_privategroup_id: { type: String },
|
||||
added_at: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
deferredTpdsFlushCounter: { type: Number },
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
ProjectSchema.statics.getProject = function (projectOrId, fields, callback) {
|
||||
if (projectOrId._id != null) {
|
||||
|
|
|
@ -11,6 +11,7 @@ const ProjectAuditLogEntrySchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'projectAuditLogEntries',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const ProjectHistoryFailureSchema = new Schema(
|
|||
resyncAttempts: Number,
|
||||
requestCount: Number,
|
||||
},
|
||||
{ collection: 'projectHistoryFailures' }
|
||||
{ collection: 'projectHistoryFailures', minimize: false }
|
||||
)
|
||||
|
||||
exports.ProjectHistoryFailure = mongoose.model(
|
||||
|
|
|
@ -27,6 +27,7 @@ const ProjectInviteSchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'projectInvites',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -5,10 +5,13 @@ const settings = require('@overleaf/settings')
|
|||
const logger = require('@overleaf/logger')
|
||||
const request = require('request')
|
||||
|
||||
const PublisherSchema = new Schema({
|
||||
slug: { type: String, required: true },
|
||||
managerIds: [{ type: ObjectId, ref: 'User' }],
|
||||
})
|
||||
const PublisherSchema = new Schema(
|
||||
{
|
||||
slug: { type: String, required: true },
|
||||
managerIds: [{ type: ObjectId, ref: 'User' }],
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
// fetch publisher's (brand on v1) data from v1 API. Errors are ignored
|
||||
PublisherSchema.method('fetchV1Data', function (callback) {
|
||||
|
|
|
@ -8,6 +8,7 @@ const SamlCacheSchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'samlCache',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ const SamlLogSchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'samlLogs',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -96,59 +96,62 @@ const VersionSchema = new Schema(
|
|||
{ _id: false }
|
||||
)
|
||||
|
||||
const SplitTestSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
minLength: MIN_NAME_LENGTH,
|
||||
maxlength: MAX_NAME_LENGTH,
|
||||
required: true,
|
||||
unique: true,
|
||||
validate: {
|
||||
validator: function (input) {
|
||||
return input !== null && NAME_REGEX.test(input)
|
||||
const SplitTestSchema = new Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
minLength: MIN_NAME_LENGTH,
|
||||
maxlength: MAX_NAME_LENGTH,
|
||||
required: true,
|
||||
unique: true,
|
||||
validate: {
|
||||
validator: function (input) {
|
||||
return input !== null && NAME_REGEX.test(input)
|
||||
},
|
||||
message: `invalid, must match: ${NAME_REGEX}`,
|
||||
},
|
||||
message: `invalid, must match: ${NAME_REGEX}`,
|
||||
},
|
||||
versions: [VersionSchema],
|
||||
forbidReleasePhase: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
expectedEndDate: {
|
||||
type: Date,
|
||||
required: false,
|
||||
},
|
||||
ticketUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
reportsUrls: {
|
||||
type: [String],
|
||||
required: false,
|
||||
default: [],
|
||||
},
|
||||
winningVariant: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
archived: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
archivedAt: {
|
||||
type: Date,
|
||||
required: false,
|
||||
},
|
||||
badgeInfo: {
|
||||
type: BadgeInfoSchema,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
versions: [VersionSchema],
|
||||
forbidReleasePhase: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
expectedEndDate: {
|
||||
type: Date,
|
||||
required: false,
|
||||
},
|
||||
ticketUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
reportsUrls: {
|
||||
type: [String],
|
||||
required: false,
|
||||
default: [],
|
||||
},
|
||||
winningVariant: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
archived: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
archivedAt: {
|
||||
type: Date,
|
||||
required: false,
|
||||
},
|
||||
badgeInfo: {
|
||||
type: BadgeInfoSchema,
|
||||
required: false,
|
||||
},
|
||||
})
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
module.exports = {
|
||||
SplitTest: mongoose.model('SplitTest', SplitTestSchema),
|
||||
|
|
|
@ -4,52 +4,55 @@ const { TeamInviteSchema } = require('./TeamInvite')
|
|||
const { Schema } = mongoose
|
||||
const { ObjectId } = Schema
|
||||
|
||||
const SubscriptionSchema = new Schema({
|
||||
admin_id: {
|
||||
type: ObjectId,
|
||||
ref: 'User',
|
||||
index: { unique: true, dropDups: true },
|
||||
},
|
||||
manager_ids: {
|
||||
type: [ObjectId],
|
||||
ref: 'User',
|
||||
required: true,
|
||||
validate: function (managers) {
|
||||
// require at least one manager
|
||||
return !!managers.length
|
||||
const SubscriptionSchema = new Schema(
|
||||
{
|
||||
admin_id: {
|
||||
type: ObjectId,
|
||||
ref: 'User',
|
||||
index: { unique: true, dropDups: true },
|
||||
},
|
||||
},
|
||||
member_ids: [{ type: ObjectId, ref: 'User' }],
|
||||
invited_emails: [String],
|
||||
teamInvites: [TeamInviteSchema],
|
||||
recurlySubscription_id: String,
|
||||
teamName: { type: String },
|
||||
teamNotice: { type: String },
|
||||
planCode: { type: String },
|
||||
groupPlan: { type: Boolean, default: false },
|
||||
membersLimit: { type: Number, default: 0 },
|
||||
customAccount: Boolean,
|
||||
overleaf: {
|
||||
id: {
|
||||
type: Number,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: { 'overleaf.id': { $exists: true } },
|
||||
manager_ids: {
|
||||
type: [ObjectId],
|
||||
ref: 'User',
|
||||
required: true,
|
||||
validate: function (managers) {
|
||||
// require at least one manager
|
||||
return !!managers.length
|
||||
},
|
||||
},
|
||||
member_ids: [{ type: ObjectId, ref: 'User' }],
|
||||
invited_emails: [String],
|
||||
teamInvites: [TeamInviteSchema],
|
||||
recurlySubscription_id: String,
|
||||
teamName: { type: String },
|
||||
teamNotice: { type: String },
|
||||
planCode: { type: String },
|
||||
groupPlan: { type: Boolean, default: false },
|
||||
membersLimit: { type: Number, default: 0 },
|
||||
customAccount: Boolean,
|
||||
overleaf: {
|
||||
id: {
|
||||
type: Number,
|
||||
index: {
|
||||
unique: true,
|
||||
partialFilterExpression: { 'overleaf.id': { $exists: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
recurlyStatus: {
|
||||
state: {
|
||||
type: String,
|
||||
},
|
||||
trialStartedAt: {
|
||||
type: Date,
|
||||
},
|
||||
trialEndsAt: {
|
||||
type: Date,
|
||||
},
|
||||
},
|
||||
},
|
||||
recurlyStatus: {
|
||||
state: {
|
||||
type: String,
|
||||
},
|
||||
trialStartedAt: {
|
||||
type: Date,
|
||||
},
|
||||
trialEndsAt: {
|
||||
type: Date,
|
||||
},
|
||||
},
|
||||
})
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
// Subscriptions have no v1 data to fetch
|
||||
SubscriptionSchema.method('fetchV1Data', function (callback) {
|
||||
|
|
|
@ -40,6 +40,7 @@ const SurveySchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'surveys',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -2,8 +2,11 @@ const mongoose = require('../infrastructure/Mongoose')
|
|||
|
||||
const { Schema } = mongoose
|
||||
|
||||
const SystemMessageSchema = new Schema({
|
||||
content: { type: String, default: '' },
|
||||
})
|
||||
const SystemMessageSchema = new Schema(
|
||||
{
|
||||
content: { type: String, default: '' },
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.SystemMessage = mongoose.model('SystemMessage', SystemMessageSchema)
|
||||
|
|
|
@ -4,11 +4,14 @@ const { Schema } = mongoose
|
|||
// Note that for legacy reasons, user_id and project_ids are plain strings,
|
||||
// not ObjectIds.
|
||||
|
||||
const TagSchema = new Schema({
|
||||
user_id: { type: String, required: true },
|
||||
name: { type: String, required: true },
|
||||
project_ids: [String],
|
||||
})
|
||||
const TagSchema = new Schema(
|
||||
{
|
||||
user_id: { type: String, required: true },
|
||||
name: { type: String, required: true },
|
||||
project_ids: [String],
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.Tag = mongoose.model('Tag', TagSchema)
|
||||
exports.TagSchema = TagSchema
|
||||
|
|
|
@ -2,12 +2,15 @@ const mongoose = require('../infrastructure/Mongoose')
|
|||
|
||||
const { Schema } = mongoose
|
||||
|
||||
const TeamInviteSchema = new Schema({
|
||||
email: { type: String, required: true },
|
||||
token: { type: String },
|
||||
inviterName: { type: String },
|
||||
sentAt: { type: Date },
|
||||
})
|
||||
const TeamInviteSchema = new Schema(
|
||||
{
|
||||
email: { type: String, required: true },
|
||||
token: { type: String },
|
||||
inviterName: { type: String },
|
||||
sentAt: { type: Date },
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.TeamInvite = mongoose.model('TeamInvite', TeamInviteSchema)
|
||||
exports.TeamInviteSchema = TeamInviteSchema
|
||||
|
|
|
@ -7,173 +7,182 @@ const { ObjectId } = Schema
|
|||
// See https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address/574698#574698
|
||||
const MAX_EMAIL_LENGTH = 254
|
||||
|
||||
const UserSchema = new Schema({
|
||||
email: { type: String, default: '', maxlength: MAX_EMAIL_LENGTH },
|
||||
emails: [
|
||||
{
|
||||
email: { type: String, default: '', maxlength: MAX_EMAIL_LENGTH },
|
||||
reversedHostname: { type: String, default: '' },
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
const UserSchema = new Schema(
|
||||
{
|
||||
email: { type: String, default: '', maxlength: MAX_EMAIL_LENGTH },
|
||||
emails: [
|
||||
{
|
||||
email: { type: String, default: '', maxlength: MAX_EMAIL_LENGTH },
|
||||
reversedHostname: { type: String, default: '' },
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
confirmedAt: { type: Date },
|
||||
samlProviderId: { type: String },
|
||||
affiliationUnchecked: { type: Boolean },
|
||||
reconfirmedAt: { type: Date },
|
||||
},
|
||||
],
|
||||
first_name: { type: String, default: '' },
|
||||
last_name: { type: String, default: '' },
|
||||
role: { type: String, default: '' },
|
||||
institution: { type: String, default: '' },
|
||||
hashedPassword: String,
|
||||
isAdmin: { type: Boolean, default: false },
|
||||
staffAccess: {
|
||||
publisherMetrics: { type: Boolean, default: false },
|
||||
publisherManagement: { type: Boolean, default: false },
|
||||
institutionMetrics: { type: Boolean, default: false },
|
||||
institutionManagement: { type: Boolean, default: false },
|
||||
groupMetrics: { type: Boolean, default: false },
|
||||
groupManagement: { type: Boolean, default: false },
|
||||
adminMetrics: { type: Boolean, default: false },
|
||||
splitTestMetrics: { type: Boolean, default: false },
|
||||
splitTestManagement: { type: Boolean, default: false },
|
||||
},
|
||||
signUpDate: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
loginEpoch: { type: Number },
|
||||
lastActive: { type: Date },
|
||||
lastFailedLogin: { type: Date },
|
||||
lastLoggedIn: { type: Date },
|
||||
lastLoginIp: { type: String, default: '' },
|
||||
lastPrimaryEmailCheck: { type: Date },
|
||||
loginCount: { type: Number, default: 0 },
|
||||
holdingAccount: { type: Boolean, default: false },
|
||||
ace: {
|
||||
mode: { type: String, default: 'none' },
|
||||
theme: { type: String, default: 'textmate' },
|
||||
overallTheme: { type: String, default: '' },
|
||||
fontSize: { type: Number, default: '12' },
|
||||
autoComplete: { type: Boolean, default: true },
|
||||
autoPairDelimiters: { type: Boolean, default: true },
|
||||
spellCheckLanguage: { type: String, default: 'en' },
|
||||
pdfViewer: { type: String, default: 'pdfjs' },
|
||||
syntaxValidation: { type: Boolean },
|
||||
fontFamily: { type: String },
|
||||
lineHeight: { type: String },
|
||||
},
|
||||
features: {
|
||||
collaborators: {
|
||||
type: Number,
|
||||
default: Settings.defaultFeatures.collaborators,
|
||||
},
|
||||
versioning: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.versioning,
|
||||
},
|
||||
dropbox: { type: Boolean, default: Settings.defaultFeatures.dropbox },
|
||||
github: { type: Boolean, default: Settings.defaultFeatures.github },
|
||||
gitBridge: { type: Boolean, default: Settings.defaultFeatures.gitBridge },
|
||||
compileTimeout: {
|
||||
type: Number,
|
||||
default: Settings.defaultFeatures.compileTimeout,
|
||||
},
|
||||
compileGroup: {
|
||||
type: String,
|
||||
default: Settings.defaultFeatures.compileGroup,
|
||||
},
|
||||
templates: { type: Boolean, default: Settings.defaultFeatures.templates },
|
||||
references: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.references,
|
||||
},
|
||||
trackChanges: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.trackChanges,
|
||||
},
|
||||
mendeley: { type: Boolean, default: Settings.defaultFeatures.mendeley },
|
||||
zotero: { type: Boolean, default: Settings.defaultFeatures.zotero },
|
||||
referencesSearch: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.referencesSearch,
|
||||
},
|
||||
symbolPalette: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.symbolPalette,
|
||||
},
|
||||
},
|
||||
featuresOverrides: [
|
||||
{
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
expiresAt: { type: Date },
|
||||
note: { type: String },
|
||||
features: {
|
||||
collaborators: { type: Number },
|
||||
versioning: { type: Boolean },
|
||||
dropbox: { type: Boolean },
|
||||
github: { type: Boolean },
|
||||
gitBridge: { type: Boolean },
|
||||
compileTimeout: { type: Number },
|
||||
compileGroup: { type: String },
|
||||
templates: { type: Boolean },
|
||||
trackChanges: { type: Boolean },
|
||||
mendeley: { type: Boolean },
|
||||
zotero: { type: Boolean },
|
||||
referencesSearch: { type: Boolean },
|
||||
symbolPalette: { type: Boolean },
|
||||
},
|
||||
},
|
||||
confirmedAt: { type: Date },
|
||||
samlProviderId: { type: String },
|
||||
affiliationUnchecked: { type: Boolean },
|
||||
reconfirmedAt: { type: Date },
|
||||
},
|
||||
],
|
||||
first_name: { type: String, default: '' },
|
||||
last_name: { type: String, default: '' },
|
||||
role: { type: String, default: '' },
|
||||
institution: { type: String, default: '' },
|
||||
hashedPassword: String,
|
||||
isAdmin: { type: Boolean, default: false },
|
||||
staffAccess: {
|
||||
publisherMetrics: { type: Boolean, default: false },
|
||||
publisherManagement: { type: Boolean, default: false },
|
||||
institutionMetrics: { type: Boolean, default: false },
|
||||
institutionManagement: { type: Boolean, default: false },
|
||||
groupMetrics: { type: Boolean, default: false },
|
||||
groupManagement: { type: Boolean, default: false },
|
||||
adminMetrics: { type: Boolean, default: false },
|
||||
splitTestMetrics: { type: Boolean, default: false },
|
||||
splitTestManagement: { type: Boolean, default: false },
|
||||
},
|
||||
signUpDate: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
loginEpoch: { type: Number },
|
||||
lastActive: { type: Date },
|
||||
lastFailedLogin: { type: Date },
|
||||
lastLoggedIn: { type: Date },
|
||||
lastLoginIp: { type: String, default: '' },
|
||||
lastPrimaryEmailCheck: { type: Date },
|
||||
loginCount: { type: Number, default: 0 },
|
||||
holdingAccount: { type: Boolean, default: false },
|
||||
ace: {
|
||||
mode: { type: String, default: 'none' },
|
||||
theme: { type: String, default: 'textmate' },
|
||||
overallTheme: { type: String, default: '' },
|
||||
fontSize: { type: Number, default: '12' },
|
||||
autoComplete: { type: Boolean, default: true },
|
||||
autoPairDelimiters: { type: Boolean, default: true },
|
||||
spellCheckLanguage: { type: String, default: 'en' },
|
||||
pdfViewer: { type: String, default: 'pdfjs' },
|
||||
syntaxValidation: { type: Boolean },
|
||||
fontFamily: { type: String },
|
||||
lineHeight: { type: String },
|
||||
},
|
||||
features: {
|
||||
collaborators: {
|
||||
type: Number,
|
||||
default: Settings.defaultFeatures.collaborators,
|
||||
},
|
||||
versioning: { type: Boolean, default: Settings.defaultFeatures.versioning },
|
||||
dropbox: { type: Boolean, default: Settings.defaultFeatures.dropbox },
|
||||
github: { type: Boolean, default: Settings.defaultFeatures.github },
|
||||
gitBridge: { type: Boolean, default: Settings.defaultFeatures.gitBridge },
|
||||
compileTimeout: {
|
||||
type: Number,
|
||||
default: Settings.defaultFeatures.compileTimeout,
|
||||
},
|
||||
compileGroup: {
|
||||
],
|
||||
featuresUpdatedAt: { type: Date },
|
||||
featuresEpoch: {
|
||||
type: String,
|
||||
default: Settings.defaultFeatures.compileGroup,
|
||||
},
|
||||
templates: { type: Boolean, default: Settings.defaultFeatures.templates },
|
||||
references: { type: Boolean, default: Settings.defaultFeatures.references },
|
||||
trackChanges: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.trackChanges,
|
||||
},
|
||||
mendeley: { type: Boolean, default: Settings.defaultFeatures.mendeley },
|
||||
zotero: { type: Boolean, default: Settings.defaultFeatures.zotero },
|
||||
referencesSearch: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.referencesSearch,
|
||||
},
|
||||
symbolPalette: {
|
||||
type: Boolean,
|
||||
default: Settings.defaultFeatures.symbolPalette,
|
||||
},
|
||||
},
|
||||
featuresOverrides: [
|
||||
{
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date()
|
||||
},
|
||||
},
|
||||
expiresAt: { type: Date },
|
||||
note: { type: String },
|
||||
features: {
|
||||
collaborators: { type: Number },
|
||||
versioning: { type: Boolean },
|
||||
dropbox: { type: Boolean },
|
||||
github: { type: Boolean },
|
||||
gitBridge: { type: Boolean },
|
||||
compileTimeout: { type: Number },
|
||||
compileGroup: { type: String },
|
||||
templates: { type: Boolean },
|
||||
trackChanges: { type: Boolean },
|
||||
mendeley: { type: Boolean },
|
||||
zotero: { type: Boolean },
|
||||
referencesSearch: { type: Boolean },
|
||||
symbolPalette: { type: Boolean },
|
||||
// when auto-merged from SL and must-reconfirm is set, we may end up using
|
||||
// `sharelatexHashedPassword` to recover accounts...
|
||||
sharelatexHashedPassword: String,
|
||||
must_reconfirm: { type: Boolean, default: false },
|
||||
referal_id: {
|
||||
type: String,
|
||||
default() {
|
||||
return TokenGenerator.generateReferralId()
|
||||
},
|
||||
},
|
||||
],
|
||||
featuresUpdatedAt: { type: Date },
|
||||
featuresEpoch: {
|
||||
type: String,
|
||||
},
|
||||
// when auto-merged from SL and must-reconfirm is set, we may end up using
|
||||
// `sharelatexHashedPassword` to recover accounts...
|
||||
sharelatexHashedPassword: String,
|
||||
must_reconfirm: { type: Boolean, default: false },
|
||||
referal_id: {
|
||||
type: String,
|
||||
default() {
|
||||
return TokenGenerator.generateReferralId()
|
||||
refered_users: [{ type: ObjectId, ref: 'User' }],
|
||||
refered_user_count: { type: Number, default: 0 },
|
||||
refProviders: {
|
||||
// The actual values are managed by third-party-references.
|
||||
mendeley: Schema.Types.Mixed,
|
||||
zotero: Schema.Types.Mixed,
|
||||
},
|
||||
alphaProgram: { type: Boolean, default: false }, // experimental features
|
||||
betaProgram: { type: Boolean, default: false },
|
||||
labsProgram: { type: Boolean, default: false },
|
||||
labsProgramGalileo: { type: Boolean, default: false },
|
||||
overleaf: {
|
||||
id: { type: Number },
|
||||
accessToken: { type: String },
|
||||
refreshToken: { type: String },
|
||||
},
|
||||
awareOfV2: { type: Boolean, default: false },
|
||||
samlIdentifiers: { type: Array, default: [] },
|
||||
thirdPartyIdentifiers: { type: Array, default: [] },
|
||||
migratedAt: { type: Date },
|
||||
twoFactorAuthentication: {
|
||||
createdAt: { type: Date },
|
||||
enrolledAt: { type: Date },
|
||||
secretEncrypted: { type: String },
|
||||
},
|
||||
onboardingEmailSentAt: { type: Date },
|
||||
splitTests: Schema.Types.Mixed,
|
||||
analyticsId: { type: String },
|
||||
surveyResponses: Schema.Types.Mixed,
|
||||
},
|
||||
refered_users: [{ type: ObjectId, ref: 'User' }],
|
||||
refered_user_count: { type: Number, default: 0 },
|
||||
refProviders: {
|
||||
// The actual values are managed by third-party-references.
|
||||
mendeley: Schema.Types.Mixed,
|
||||
zotero: Schema.Types.Mixed,
|
||||
},
|
||||
alphaProgram: { type: Boolean, default: false }, // experimental features
|
||||
betaProgram: { type: Boolean, default: false },
|
||||
labsProgram: { type: Boolean, default: false },
|
||||
labsProgramGalileo: { type: Boolean, default: false },
|
||||
overleaf: {
|
||||
id: { type: Number },
|
||||
accessToken: { type: String },
|
||||
refreshToken: { type: String },
|
||||
},
|
||||
awareOfV2: { type: Boolean, default: false },
|
||||
samlIdentifiers: { type: Array, default: [] },
|
||||
thirdPartyIdentifiers: { type: Array, default: [] },
|
||||
migratedAt: { type: Date },
|
||||
twoFactorAuthentication: {
|
||||
createdAt: { type: Date },
|
||||
enrolledAt: { type: Date },
|
||||
secretEncrypted: { type: String },
|
||||
},
|
||||
onboardingEmailSentAt: { type: Date },
|
||||
splitTests: Schema.Types.Mixed,
|
||||
analyticsId: { type: String },
|
||||
surveyResponses: Schema.Types.Mixed,
|
||||
})
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
function formatSplitTestsSchema(next) {
|
||||
if (this.splitTests) {
|
||||
|
|
|
@ -12,6 +12,7 @@ const UserAuditLogEntrySchema = new Schema(
|
|||
},
|
||||
{
|
||||
collection: 'userAuditLogEntries',
|
||||
minimize: false,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -88,9 +88,7 @@ module.exports = {
|
|||
mongo: {
|
||||
options: {
|
||||
appname: 'web',
|
||||
useUnifiedTopology:
|
||||
(process.env.MONGO_USE_UNIFIED_TOPOLOGY || 'true') === 'true',
|
||||
poolSize: parseInt(process.env.MONGO_POOL_SIZE, 10) || 10,
|
||||
maxPoolSize: parseInt(process.env.MONGO_POOL_SIZE, 10) || 100,
|
||||
serverSelectionTimeoutMS:
|
||||
parseInt(process.env.MONGO_SERVER_SELECTION_TIMEOUT, 10) || 60000,
|
||||
socketTimeoutMS: parseInt(process.env.MONGO_SOCKET_TIMEOUT, 10) || 60000,
|
||||
|
|
|
@ -189,8 +189,8 @@
|
|||
"minimist": "^1.2.7",
|
||||
"mmmagic": "^0.5.3",
|
||||
"moment": "^2.29.4",
|
||||
"mongodb": "~3.6.0",
|
||||
"mongoose": "^5.13.11",
|
||||
"mongodb": "^4.13.0",
|
||||
"mongoose": "^6.9.1",
|
||||
"multer": "overleaf/multer#e1df247fbf8e7590520d20ae3601eaef9f3d2e9e",
|
||||
"nocache": "^2.1.0",
|
||||
"nock": "^13.1.3",
|
||||
|
|
|
@ -27,7 +27,7 @@ async function main() {
|
|||
})
|
||||
if (!DRY_RUN) {
|
||||
console.log(`updating doc ${DOC_ID} in mongo for project ${PROJECT_ID}`)
|
||||
const { result } = await db.docs.updateOne(
|
||||
const result = await db.docs.updateOne(
|
||||
{ _id: ObjectId(DOC_ID), project_id: ObjectId(PROJECT_ID) },
|
||||
{
|
||||
$set: { lines, version, ranges },
|
||||
|
@ -38,7 +38,11 @@ async function main() {
|
|||
}
|
||||
)
|
||||
console.log('mongo result', result)
|
||||
if (result.n !== 1 || result.nModified !== 1 || result.ok !== 1) {
|
||||
if (
|
||||
result.matchedCount !== 1 ||
|
||||
result.modifiedCount !== 1 ||
|
||||
!result.acknowledged
|
||||
) {
|
||||
throw new Error('unexpected result from mongo update')
|
||||
}
|
||||
console.log(`deleting doc ${DOC_ID} from redis for project ${PROJECT_ID}`)
|
||||
|
|
|
@ -54,8 +54,8 @@ async function updateImage(image, projectIds) {
|
|||
{ _id: { $in: projectIds.map(ObjectId) } },
|
||||
{ $set: { imageName: `quay.io/sharelatex/${image}` } }
|
||||
).exec()
|
||||
console.log(`Found ${res.n} out of ${projectIds.length} projects`)
|
||||
console.log(`Modified ${res.nModified} projects`)
|
||||
console.log(`Found ${res.matchedCount} out of ${projectIds.length} projects`)
|
||||
console.log(`Modified ${res.modifiedCount} projects`)
|
||||
}
|
||||
|
||||
main()
|
||||
|
|
11
services/web/test/unit/bootstrap.js
vendored
11
services/web/test/unit/bootstrap.js
vendored
|
@ -46,7 +46,16 @@ const SandboxedModule = require('sandboxed-module')
|
|||
SandboxedModule.configure({
|
||||
ignoreMissing: true,
|
||||
requires: getSandboxedModuleRequires(),
|
||||
globals: { AbortSignal, Buffer, Promise, console, process, URL },
|
||||
globals: {
|
||||
AbortSignal,
|
||||
Buffer,
|
||||
Promise,
|
||||
console,
|
||||
process,
|
||||
URL,
|
||||
TextEncoder,
|
||||
TextDecoder,
|
||||
},
|
||||
})
|
||||
|
||||
function getSandboxedModuleRequires() {
|
||||
|
|
|
@ -17,7 +17,7 @@ describe('AuthenticationManager', function () {
|
|||
requires: {
|
||||
'../../models/User': {
|
||||
User: (this.User = {
|
||||
updateOne: sinon.stub().callsArgWith(3, null, { nModified: 1 }),
|
||||
updateOne: sinon.stub().callsArgWith(3, null, { modifiedCount: 1 }),
|
||||
}),
|
||||
},
|
||||
'../../infrastructure/mongodb': {
|
||||
|
@ -99,7 +99,7 @@ describe('AuthenticationManager', function () {
|
|||
})
|
||||
|
||||
it('should return the user', function () {
|
||||
this.callback.calledWith(null, this.user).should.equal(true)
|
||||
this.callback.should.have.been.calledWith(null, this.user)
|
||||
})
|
||||
|
||||
it('should send metrics', function () {
|
||||
|
@ -147,7 +147,7 @@ describe('AuthenticationManager', function () {
|
|||
beforeEach(function () {
|
||||
this.User.updateOne = sinon
|
||||
.stub()
|
||||
.callsArgWith(3, null, { nModified: 0 })
|
||||
.callsArgWith(3, null, { modifiedCount: 0 })
|
||||
})
|
||||
|
||||
describe('correct password', function () {
|
||||
|
@ -171,7 +171,9 @@ describe('AuthenticationManager', function () {
|
|||
|
||||
describe('bad password', function () {
|
||||
beforeEach(function (done) {
|
||||
this.User.updateOne = sinon.stub().yields(null, { nModified: 0 })
|
||||
this.User.updateOne = sinon
|
||||
.stub()
|
||||
.yields(null, { modifiedCount: 0 })
|
||||
this.AuthenticationManager.authenticate(
|
||||
{ email: this.email },
|
||||
'notthecorrectpassword',
|
||||
|
|
|
@ -506,7 +506,7 @@ describe('CollaboratorsHandler', function () {
|
|||
}
|
||||
)
|
||||
.chain('exec')
|
||||
.resolves({ n: 1 })
|
||||
.resolves({ matchedCount: 1 })
|
||||
await this.CollaboratorsHandler.promises.setCollaboratorPrivilegeLevel(
|
||||
this.projectId,
|
||||
this.userId,
|
||||
|
@ -530,7 +530,7 @@ describe('CollaboratorsHandler', function () {
|
|||
}
|
||||
)
|
||||
.chain('exec')
|
||||
.resolves({ n: 1 })
|
||||
.resolves({ matchedCount: 1 })
|
||||
await this.CollaboratorsHandler.promises.setCollaboratorPrivilegeLevel(
|
||||
this.projectId,
|
||||
this.userId,
|
||||
|
@ -539,7 +539,9 @@ describe('CollaboratorsHandler', function () {
|
|||
})
|
||||
|
||||
it('throws a NotFoundError if the project or collaborator does not exist', async function () {
|
||||
this.ProjectMock.expects('updateOne').chain('exec').resolves({ n: 0 })
|
||||
this.ProjectMock.expects('updateOne')
|
||||
.chain('exec')
|
||||
.resolves({ matchedCount: 0 })
|
||||
await expect(
|
||||
this.CollaboratorsHandler.promises.setCollaboratorPrivilegeLevel(
|
||||
this.projectId,
|
||||
|
|
|
@ -75,7 +75,7 @@ describe('ProjectHistoryHandler', function () {
|
|||
.callsArgWith(1, null, this.project)
|
||||
this.ProjectModel.updateOne = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, { n: 1 })
|
||||
.callsArgWith(2, null, { matchedCount: 1 })
|
||||
return this.ProjectHistoryHandler.ensureHistoryExistsForProject(
|
||||
project_id,
|
||||
this.callback
|
||||
|
|
|
@ -40,7 +40,7 @@ describe('UserAuditLogHandler', function () {
|
|||
beforeEach(function () {
|
||||
this.dbUpdate = this.UserAuditLogEntryMock.expects('create')
|
||||
.chain('exec')
|
||||
.resolves({ nModified: 1 })
|
||||
.resolves({ modifiedCount: 1 })
|
||||
})
|
||||
it('writes a log', async function () {
|
||||
await this.UserAuditLogHandler.promises.addEntry(
|
||||
|
|
|
@ -35,9 +35,11 @@ describe('UserCreator', function () {
|
|||
}),
|
||||
'./UserUpdater': (this.UserUpdater = {
|
||||
promises: {
|
||||
addAffiliationForNewUser: sinon
|
||||
.stub()
|
||||
.resolves({ n: 1, nModified: 1, ok: 1 }),
|
||||
addAffiliationForNewUser: sinon.stub().resolves({
|
||||
matchedCount: 1,
|
||||
modifiedCount: 1,
|
||||
acknowledged: true,
|
||||
}),
|
||||
updateUser: sinon.stub().resolves(),
|
||||
},
|
||||
}),
|
||||
|
|
Loading…
Reference in a new issue