Explorar el Código

Merge pull request #16186 from overleaf/mj-mongo-object-id

[web] Use constructor for ObjectId

GitOrigin-RevId: 9eb8b377ea599605b72af237d1ab12f4d8287162
Mathias Jakobsen hace 2 años
padre
commit
c371732e6e
Se han modificado 100 ficheros con 423 adiciones y 368 borrados
  1. 20 0
      services/web/.eslintrc
  2. 1 1
      services/web/app/src/Features/Authentication/AuthenticationManager.js
  3. 3 3
      services/web/app/src/Features/Collaborators/CollaboratorsController.js
  4. 2 2
      services/web/app/src/Features/Collaborators/CollaboratorsGetter.js
  5. 3 3
      services/web/app/src/Features/Helpers/Mongo.js
  6. 4 4
      services/web/app/src/Features/Institutions/InstitutionsManager.js
  7. 1 1
      services/web/app/src/Features/Project/FolderStructureBuilder.js
  8. 10 10
      services/web/app/src/Features/Project/ProjectCollabratecDetailsHandler.js
  9. 2 2
      services/web/app/src/Features/Project/ProjectController.js
  10. 4 4
      services/web/app/src/Features/Project/ProjectDeleter.js
  11. 3 3
      services/web/app/src/Features/Project/ProjectEntityHandler.js
  12. 1 1
      services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.js
  13. 3 3
      services/web/app/src/Features/Project/ProjectHelper.js
  14. 2 2
      services/web/app/src/Features/Subscription/RecurlyEventHandler.js
  15. 4 4
      services/web/app/src/Features/Subscription/SubscriptionUpdater.js
  16. 1 1
      services/web/app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js
  17. 4 4
      services/web/app/src/Features/TokenAccess/TokenAccessHandler.js
  18. 1 1
      services/web/app/src/Features/User/SAMLIdentityManager.js
  19. 1 1
      services/web/app/src/Features/User/UserInfoController.js
  20. 1 1
      services/web/app/src/Features/UserMembership/UserMembershipHandler.js
  21. 3 2
      services/web/app/src/models/Project.js
  22. 5 5
      services/web/modules/history-v1/test/acceptance/src/HistoryTests.js
  23. 1 1
      services/web/modules/server-ce-scripts/scripts/change-compile-timeout.js
  24. 1 1
      services/web/modules/server-ce-scripts/scripts/check-mongodb.js
  25. 1 1
      services/web/scripts/add_feature_override.js
  26. 1 1
      services/web/scripts/back_fill_dummy_doc_meta.js
  27. 1 1
      services/web/scripts/count_project_size.js
  28. 4 4
      services/web/scripts/delete-orphaned-docs/delete-orphaned-docs.js
  29. 1 1
      services/web/scripts/delete_dangling_file_refs.js
  30. 1 1
      services/web/scripts/delete_orphaned_chat_threads.js
  31. 2 2
      services/web/scripts/delete_orphaned_docs_online_check.js
  32. 2 2
      services/web/scripts/delete_orphaned_project_archives.js
  33. 2 2
      services/web/scripts/delete_subscriptions.js
  34. 3 3
      services/web/scripts/fix_malformed_filetree.js
  35. 2 2
      services/web/scripts/fix_oversized_docs.js
  36. 1 1
      services/web/scripts/force_doc_flush.js
  37. 3 3
      services/web/scripts/helpers/batchedUpdate.js
  38. 1 1
      services/web/scripts/invalidate_tokens.js
  39. 2 2
      services/web/scripts/merge_group_subscription_members.js
  40. 2 2
      services/web/scripts/migrate_audit_logs.js
  41. 1 1
      services/web/scripts/oauth/register_client.js
  42. 2 2
      services/web/scripts/recover_docs_from_redis.js
  43. 2 2
      services/web/scripts/set_tex_live_image.js
  44. 1 1
      services/web/scripts/stress_test.js
  45. 4 4
      services/web/test/acceptance/src/AuthenticationTests.js
  46. 9 9
      services/web/test/acceptance/src/BackFillDeletedFilesTests.js
  47. 5 5
      services/web/test/acceptance/src/BackFillDocNameForDeletedDocsTests.js
  48. 3 3
      services/web/test/acceptance/src/BackFillDocRevTests.js
  49. 3 3
      services/web/test/acceptance/src/ConvertArchivedState.js
  50. 6 2
      services/web/test/acceptance/src/DeletionTests.js
  51. 1 1
      services/web/test/acceptance/src/DocUpdateTests.js
  52. 4 2
      services/web/test/acceptance/src/MongoHelper.js
  53. 3 3
      services/web/test/acceptance/src/ProjectCRUDTests.js
  54. 1 1
      services/web/test/acceptance/src/helpers/Institution.js
  55. 1 1
      services/web/test/acceptance/src/helpers/Publisher.js
  56. 1 1
      services/web/test/acceptance/src/helpers/RecurlySubscription.js
  57. 3 3
      services/web/test/acceptance/src/helpers/Subscription.js
  58. 10 10
      services/web/test/acceptance/src/helpers/User.js
  59. 1 1
      services/web/test/acceptance/src/helpers/UserHelper.js
  60. 1 1
      services/web/test/acceptance/src/mocks/MockDocstoreApi.js
  61. 5 5
      services/web/test/unit/src/Analytics/AnalyticsManagerTests.js
  62. 1 1
      services/web/test/unit/src/Authentication/AuthenticationControllerTests.js
  63. 2 2
      services/web/test/unit/src/Authentication/AuthenticationManagerTests.js
  64. 1 1
      services/web/test/unit/src/Authentication/SessionManagerTests.js
  65. 2 2
      services/web/test/unit/src/Collaborators/CollaboratorsControllerTests.js
  66. 10 10
      services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js
  67. 11 11
      services/web/test/unit/src/Collaborators/CollaboratorsHandlerTests.js
  68. 4 4
      services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js
  69. 13 13
      services/web/test/unit/src/Collaborators/CollaboratorsInviteHandlerTests.js
  70. 8 5
      services/web/test/unit/src/Collaborators/OwnershipTransferHandlerTests.js
  71. 1 1
      services/web/test/unit/src/History/HistoryManagerTests.js
  72. 36 18
      services/web/test/unit/src/Institutions/InstitutionsManagerTests.js
  73. 9 4
      services/web/test/unit/src/Project/FolderStructureBuilderTests.js
  74. 5 5
      services/web/test/unit/src/Project/ProjectCollabratecDetailsTest.js
  75. 3 3
      services/web/test/unit/src/Project/ProjectControllerTests.js
  76. 8 8
      services/web/test/unit/src/Project/ProjectDeleterTests.js
  77. 3 3
      services/web/test/unit/src/Project/ProjectDetailsHandlerTests.js
  78. 21 21
      services/web/test/unit/src/Project/ProjectEntityMongoUpdateHandlerTests.js
  79. 4 4
      services/web/test/unit/src/Project/ProjectEntityUpdateHandlerTests.js
  80. 35 31
      services/web/test/unit/src/Project/ProjectHelperTests.js
  81. 2 2
      services/web/test/unit/src/Project/ProjectListControllerTests.js
  82. 3 3
      services/web/test/unit/src/SplitTests/SplitTestHandlerTests.js
  83. 1 1
      services/web/test/unit/src/Subscription/GroupSSOHandlerTests.js
  84. 9 9
      services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js
  85. 4 4
      services/web/test/unit/src/Tags/TagsHandlerTests.js
  86. 9 9
      services/web/test/unit/src/ThirdPartyDataStore/TpdsControllerTests.js
  87. 2 2
      services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js
  88. 4 4
      services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateHandlerTests.js
  89. 3 3
      services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSenderTests.js
  90. 3 3
      services/web/test/unit/src/ThirdPartyDataStore/UpdateMergerTests.js
  91. 2 2
      services/web/test/unit/src/TokenAccess/TokenAccessControllerTests.js
  92. 3 3
      services/web/test/unit/src/TokenAccess/TokenAccessHandlerTests.js
  93. 1 1
      services/web/test/unit/src/User/SAMLIdentityManagerTests.js
  94. 2 2
      services/web/test/unit/src/User/UserAuditLogHandlerTests.js
  95. 2 2
      services/web/test/unit/src/User/UserDeleterTests.js
  96. 7 7
      services/web/test/unit/src/User/UserInfoControllerTests.js
  97. 2 4
      services/web/test/unit/src/User/UserUpdaterTests.js
  98. 7 7
      services/web/test/unit/src/UserMembership/UserMembershipHandlerTests.js
  99. 2 2
      services/web/test/unit/src/UserMembership/UserMembershipViewModelTests.js
  100. 1 1
      services/web/test/unit/src/UserMembership/UserMembershipsHandlerTests.js

+ 20 - 0
services/web/.eslintrc

@@ -102,6 +102,26 @@
         ]
       }
     },
+    {
+      // Backend + backend tests specific rules
+      "files": ["**/app/src/**/*.js", "app.js", "**/test/**/*.*", "**/scripts/*.*"],
+      "rules": {
+        // do not allow node-fetch in backend code
+        "no-restricted-syntax": [
+          "error",
+          // Require `new` when constructing ObjectId (For mongo + mongoose upgrade)
+          {
+            "selector": "CallExpression[callee.name='ObjectId'], CallExpression[callee.property.name='ObjectId']",
+            "message": "Construct ObjectId with `new ObjectId()` instead of `ObjectId()`"
+          },
+          // Require `new` when mapping a list of ids to a list of ObjectId (For mongo + mongoose upgrade)
+          {
+            "selector": "CallExpression[callee.property.name='map'] Identifier[name='ObjectId']:first-child, CallExpression[callee.property.name='map'] MemberExpression[property.name='ObjectId']:first-child",
+            "message": "Don't map ObjectId directly. Use `id => new ObjectId(id)` instead"
+          }
+        ]
+      }
+    },
     {
       // Cypress specific rules
       "files": ["cypress/**/*.{js,jsx,ts,tsx}", "**/test/frontend/**/*.spec.{js,jsx,ts,tsx}"],

+ 1 - 1
services/web/app/src/Features/Authentication/AuthenticationManager.js

@@ -369,7 +369,7 @@ const AuthenticationManager = {
         return callback(error)
       }
       db.users.updateOne(
-        { _id: ObjectId(user._id.toString()) },
+        { _id: new ObjectId(user._id.toString()) },
         {
           $set: {
             hashedPassword: hash,

+ 3 - 3
services/web/app/src/Features/Collaborators/CollaboratorsController.js

@@ -105,7 +105,7 @@ async function transferOwnership(req, res, next) {
       toUserId,
       {
         allowTransferToNonCollaborators: hasAdminAccess(sessionUser),
-        sessionUserId: ObjectId(sessionUser._id),
+        sessionUserId: new ObjectId(sessionUser._id),
       }
     )
     res.sendStatus(204)
@@ -143,8 +143,8 @@ async function getShareTokens(req, res) {
   let tokens
   if (userId) {
     tokens = await CollaboratorsGetter.promises.getPublicShareTokens(
-      ObjectId(userId),
-      ObjectId(projectId)
+      new ObjectId(userId),
+      new ObjectId(projectId)
     )
   } else {
     // anonymous access, the token is already available in the session

+ 2 - 2
services/web/app/src/Features/Collaborators/CollaboratorsGetter.js

@@ -209,8 +209,8 @@ async function getAllInvitedMembers(projectId) {
 }
 
 async function userIsTokenMember(userId, projectId) {
-  userId = ObjectId(userId.toString())
-  projectId = ObjectId(projectId.toString())
+  userId = new ObjectId(userId.toString())
+  projectId = new ObjectId(projectId.toString())
   const project = await Project.findOne(
     {
       _id: projectId,

+ 3 - 3
services/web/app/src/Features/Helpers/Mongo.js

@@ -4,11 +4,11 @@ const { ObjectId: MongooseObjectId } = require('mongoose').mongo
 
 function _getObjectIdInstance(id) {
   if (typeof id === 'string') {
-    return ObjectId(id)
+    return new ObjectId(id)
   } else if (id instanceof ObjectId) {
     return id
   } else if (id instanceof MongooseObjectId) {
-    return ObjectId(id.toString())
+    return new ObjectId(id.toString())
   } else {
     throw new OError('unexpected object id', { id })
   }
@@ -25,7 +25,7 @@ function normalizeQuery(query) {
   ) {
     return { _id: _getObjectIdInstance(query) }
   } else if (typeof query._id === 'string') {
-    query._id = ObjectId(query._id)
+    query._id = new ObjectId(query._id)
     return query
   } else {
     return query

+ 4 - 4
services/web/app/src/Features/Institutions/InstitutionsManager.js

@@ -244,8 +244,8 @@ const InstitutionsManager = {
       if (error) {
         return callback(error)
       }
-      const userIds = affiliations.map(affiliation =>
-        ObjectId(affiliation.user_id)
+      const userIds = affiliations.map(
+        affiliation => new ObjectId(affiliation.user_id)
       )
       Subscription.find({ admin_id: userIds })
         .populate('admin_id', 'email')
@@ -294,12 +294,12 @@ const fetchInstitutionAndAffiliations = (institutionId, callback) =>
   )
 
 function refreshFeatures(affiliation, callback) {
-  const userId = ObjectId(affiliation.user_id)
+  const userId = new ObjectId(affiliation.user_id)
   FeaturesUpdater.refreshFeatures(userId, 'refresh-institution-users', callback)
 }
 
 function refreshFeaturesAndNotify(affiliation, callback) {
-  const userId = ObjectId(affiliation.user_id)
+  const userId = new ObjectId(affiliation.user_id)
   async.waterfall(
     [
       cb =>

+ 1 - 1
services/web/app/src/Features/Project/FolderStructureBuilder.js

@@ -63,7 +63,7 @@ class FolderStructureBuilder {
 
   createFolder(name) {
     return {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name,
       folders: [],
       docs: [],

+ 10 - 10
services/web/app/src/Features/Project/ProjectCollabratecDetailsHandler.js

@@ -43,8 +43,8 @@ module.exports = ProjectCollabratecDetailsHandler = {
       callback = function () {}
     }
     try {
-      projectId = ObjectId(projectId)
-      userId = ObjectId(userId)
+      projectId = new ObjectId(projectId)
+      userId = new ObjectId(userId)
     } catch (error) {
       const err = error
       return callback(err)
@@ -75,8 +75,8 @@ module.exports = ProjectCollabratecDetailsHandler = {
       callback = function () {}
     }
     try {
-      projectId = ObjectId(projectId)
-      userId = ObjectId(userId)
+      projectId = new ObjectId(projectId)
+      userId = new ObjectId(userId)
     } catch (error) {
       const err = error
       return callback(err)
@@ -109,7 +109,7 @@ module.exports = ProjectCollabratecDetailsHandler = {
       callback = function () {}
     }
     try {
-      projectId = ObjectId(projectId)
+      projectId = new ObjectId(projectId)
     } catch (error) {
       err = error
       return callback(err)
@@ -119,7 +119,7 @@ module.exports = ProjectCollabratecDetailsHandler = {
     }
     for (const collabratecUser of Array.from(collabratecUsers)) {
       try {
-        collabratecUser.user_id = ObjectId(collabratecUser.user_id)
+        collabratecUser.user_id = new ObjectId(collabratecUser.user_id)
       } catch (error1) {
         err = error1
         return callback(err)
@@ -134,8 +134,8 @@ module.exports = ProjectCollabratecDetailsHandler = {
       callback = function () {}
     }
     try {
-      projectId = ObjectId(projectId)
-      userId = ObjectId(userId)
+      projectId = new ObjectId(projectId)
+      userId = new ObjectId(userId)
     } catch (error) {
       const err = error
       return callback(err)
@@ -156,8 +156,8 @@ module.exports = ProjectCollabratecDetailsHandler = {
       callback = function () {}
     }
     try {
-      oldUserId = ObjectId(oldUserId)
-      newUserId = ObjectId(newUserId)
+      oldUserId = new ObjectId(oldUserId)
+      newUserId = new ObjectId(newUserId)
     } catch (error) {
       const err = error
       return callback(err)

+ 2 - 2
services/web/app/src/Features/Project/ProjectController.js

@@ -435,7 +435,7 @@ const ProjectController = {
             cb(null, defaultSettingsForAnonymousUser(userId))
           } else {
             User.updateOne(
-              { _id: ObjectId(userId) },
+              { _id: new ObjectId(userId) },
               { $set: { lastActive: new Date() } },
               {},
               () => {}
@@ -753,7 +753,7 @@ const ProjectController = {
             } else if (
               Settings.wsUrlV2 &&
               Settings.wsUrlV2Percentage > 0 &&
-              (ObjectId(projectId).getTimestamp() / 1000) % 100 <
+              (new ObjectId(projectId).getTimestamp() / 1000) % 100 <
                 Settings.wsUrlV2Percentage
             ) {
               wsUrl = Settings.wsUrlV2

+ 4 - 4
services/web/app/src/Features/Project/ProjectDeleter.js

@@ -128,7 +128,7 @@ async function archiveProject(projectId, userId) {
 
     await Project.updateOne(
       { _id: projectId },
-      { $set: { archived }, $pull: { trashed: ObjectId(userId) } }
+      { $set: { archived }, $pull: { trashed: new ObjectId(userId) } }
     )
   } catch (err) {
     logger.warn({ err }, 'problem archiving project')
@@ -172,7 +172,7 @@ async function trashProject(projectId, userId) {
     await Project.updateOne(
       { _id: projectId },
       {
-        $addToSet: { trashed: ObjectId(userId) },
+        $addToSet: { trashed: new ObjectId(userId) },
         $set: { archived },
       }
     )
@@ -191,7 +191,7 @@ async function untrashProject(projectId, userId) {
 
     await Project.updateOne(
       { _id: projectId },
-      { $pull: { trashed: ObjectId(userId) } }
+      { $pull: { trashed: new ObjectId(userId) } }
     )
   } catch (err) {
     logger.warn({ err }, 'problem untrashing project')
@@ -280,7 +280,7 @@ async function deleteProject(projectId, options = {}) {
 }
 
 async function undeleteProject(projectId, options = {}) {
-  projectId = ObjectId(projectId)
+  projectId = new ObjectId(projectId)
   const deletedProject = await DeletedProject.findOne({
     'deleterData.deletedProjectId': projectId,
   }).exec()

+ 3 - 3
services/web/app/src/Features/Project/ProjectEntityHandler.js

@@ -148,8 +148,8 @@ const ProjectEntityHandler = {
   },
 
   /**
-   * @param {ObjectID | string} projectId
-   * @param {ObjectID | string} docId
+   * @param {ObjectId | string} projectId
+   * @param {ObjectId | string} docId
    * @param {Function} callback
    */
   getDocPathByProjectIdAndDocId(projectId, docId, callback) {
@@ -176,7 +176,7 @@ const ProjectEntityHandler = {
 
   /**
    * @param {Project} project
-   * @param {ObjectID | string} docId
+   * @param {ObjectId | string} docId
    * @param {Function} callback
    */
   getDocPathFromProjectByDocId(project, docId, callback) {

+ 1 - 1
services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.js

@@ -568,7 +568,7 @@ async function _putElement(project, folderId, element, type) {
     throw new Errors.InvalidNameError('blocked element name')
   }
   _checkValidElementName(folder, element.name)
-  element._id = ObjectId(element._id.toString())
+  element._id = new ObjectId(element._id.toString())
   const mongoPath = `${path.mongo}.${pathSegment}`
   const newProject = await Project.findOneAndUpdate(
     { _id: project._id, [path.mongo]: { $exists: true } },

+ 3 - 3
services/web/app/src/Features/Project/ProjectHelper.js

@@ -37,7 +37,7 @@ function compilerFromV1Engine(engine) {
  * @returns {boolean}
  */
 function isArchived(project, userId) {
-  userId = ObjectId(userId)
+  userId = new ObjectId(userId)
 
   return (project.archived || []).some(id => id.equals(userId))
 }
@@ -48,7 +48,7 @@ function isArchived(project, userId) {
  * @returns {boolean}
  */
 function isTrashed(project, userId) {
-  userId = ObjectId(userId)
+  userId = new ObjectId(userId)
 
   return (project.trashed || []).some(id => id.equals(userId))
 }
@@ -75,7 +75,7 @@ function _allCollaborators(project) {
 
 function calculateArchivedArray(project, userId, action) {
   let archived = project.archived
-  userId = ObjectId(userId)
+  userId = new ObjectId(userId)
 
   if (archived === true) {
     archived = _allCollaborators(project)

+ 2 - 2
services/web/app/src/Features/Subscription/RecurlyEventHandler.js

@@ -1,12 +1,12 @@
 const AnalyticsManager = require('../Analytics/AnalyticsManager')
 const SubscriptionEmailHandler = require('./SubscriptionEmailHandler')
-const { ObjectID } = require('mongodb')
+const { ObjectId } = require('mongodb')
 
 const INVOICE_SUBSCRIPTION_LIMIT = 10
 
 async function sendRecurlyAnalyticsEvent(event, eventData) {
   const userId = _getUserId(eventData)
-  if (!ObjectID.isValid(userId)) {
+  if (!ObjectId.isValid(userId)) {
     return
   }
 

+ 4 - 4
services/web/app/src/Features/Subscription/SubscriptionUpdater.js

@@ -27,16 +27,16 @@ const UserAuditLogHandler = require('../User/UserAuditLogHandler')
  */
 async function updateAdmin(subscription, adminId) {
   const query = {
-    _id: ObjectId(subscription._id),
+    _id: new ObjectId(subscription._id),
     customAccount: true,
   }
   const update = {
-    $set: { admin_id: ObjectId(adminId) },
+    $set: { admin_id: new ObjectId(adminId) },
   }
   if (subscription.groupPlan) {
-    update.$addToSet = { manager_ids: ObjectId(adminId) }
+    update.$addToSet = { manager_ids: new ObjectId(adminId) }
   } else {
-    update.$set.manager_ids = [ObjectId(adminId)]
+    update.$set.manager_ids = [new ObjectId(adminId)]
   }
   await Subscription.updateOne(query, update).exec()
 }

+ 1 - 1
services/web/app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js

@@ -224,7 +224,7 @@ async function getProjectUsersIds(projectId) {
   // filter invited users to only return those with dropbox linked
   const dropboxUsers = await UserGetter.getUsers(
     {
-      _id: { $in: userIds.map(id => ObjectId(id)) },
+      _id: { $in: userIds.map(id => new ObjectId(id)) },
       'dropbox.access_token.uid': { $ne: null },
     },
     {

+ 4 - 4
services/web/app/src/Features/TokenAccess/TokenAccessHandler.js

@@ -168,8 +168,8 @@ const TokenAccessHandler = {
   },
 
   addReadOnlyUserToProject(userId, projectId, callback) {
-    userId = ObjectId(userId.toString())
-    projectId = ObjectId(projectId.toString())
+    userId = new ObjectId(userId.toString())
+    projectId = new ObjectId(projectId.toString())
     Analytics.recordEventForUser(userId, 'project-joined', {
       mode: 'read-only',
     })
@@ -185,8 +185,8 @@ const TokenAccessHandler = {
   },
 
   addReadAndWriteUserToProject(userId, projectId, callback) {
-    userId = ObjectId(userId.toString())
-    projectId = ObjectId(projectId.toString())
+    userId = new ObjectId(userId.toString())
+    projectId = new ObjectId(projectId.toString())
     Analytics.recordEventForUser(userId, 'project-joined', {
       mode: 'read-write',
     })

+ 1 - 1
services/web/app/src/Features/User/SAMLIdentityManager.js

@@ -24,7 +24,7 @@ async function _addAuditLogEntry(operation, userId, auditLog, extraInfo) {
 
 async function _ensureCanAddIdentifier(userId, institutionEmail, providerId) {
   const userWithProvider = await UserGetter.promises.getUser(
-    { _id: ObjectId(userId), 'samlIdentifiers.providerId': providerId },
+    { _id: new ObjectId(userId), 'samlIdentifiers.providerId': providerId },
     { _id: 1 }
   )
 

+ 1 - 1
services/web/app/src/Features/User/UserInfoController.js

@@ -33,7 +33,7 @@ function getPersonalInfo(req, res, next) {
   if (/^\d+$/.test(userId)) {
     query = { 'overleaf.id': parseInt(userId, 10) }
   } else if (/^[a-f0-9]{24}$/.test(userId)) {
-    query = { _id: ObjectId(userId) }
+    query = { _id: new ObjectId(userId) }
   } else {
     return res.sendStatus(400)
   }

+ 1 - 1
services/web/app/src/Features/UserMembership/UserMembershipHandler.js

@@ -143,7 +143,7 @@ function removeUserFromEntity(entity, attribute, userId, callback) {
 
 function buildEntityQuery(entityId, entityConfig, loggedInUser) {
   if (ObjectId.isValid(entityId.toString())) {
-    entityId = ObjectId(entityId)
+    entityId = new ObjectId(entityId)
   }
   const query = Object.assign({}, entityConfig.baseQuery)
   query[entityConfig.fields.primaryKey] = entityId

+ 3 - 2
services/web/app/src/models/Project.js

@@ -3,7 +3,7 @@ const _ = require('underscore')
 const { FolderSchema } = require('./Folder')
 const Errors = require('../Features/Errors/Errors')
 
-const concreteObjectId = mongoose.Types.ObjectId
+const ConcreteObjectId = mongoose.Types.ObjectId
 const { Schema } = mongoose
 const { ObjectId } = Schema
 
@@ -119,7 +119,8 @@ ProjectSchema.statics.getProject = function (projectOrId, fields, callback) {
     callback(null, projectOrId)
   } else {
     try {
-      concreteObjectId(projectOrId.toString())
+      // eslint-disable-next-line no-new
+      new ConcreteObjectId(projectOrId.toString())
     } catch (e) {
       return callback(new Errors.NotFoundError(e.message))
     }

+ 5 - 5
services/web/modules/history-v1/test/acceptance/src/HistoryTests.js

@@ -42,7 +42,7 @@ describe('History', function () {
         this.v1_history_id = 42
         return db.projects.updateOne(
           {
-            _id: ObjectId(this.project_id),
+            _id: new ObjectId(this.project_id),
           },
           {
             $set: {
@@ -90,7 +90,7 @@ describe('History', function () {
           }
           this.v1_history_id = 42
           db.projects.updateOne(
-            { _id: ObjectId(this.project_id) },
+            { _id: new ObjectId(this.project_id) },
             {
               $set: {
                 'overleaf.history.id': this.v1_history_id,
@@ -202,7 +202,7 @@ describe('History', function () {
         }
         return db.projects.updateOne(
           {
-            _id: ObjectId(this.project_id),
+            _id: new ObjectId(this.project_id),
           },
           {
             $unset: {
@@ -260,7 +260,7 @@ describe('History', function () {
         this.v1_history_id = 42
         return db.projects.updateOne(
           {
-            _id: ObjectId(this.project_id),
+            _id: new ObjectId(this.project_id),
           },
           {
             $set: {
@@ -324,7 +324,7 @@ describe('History', function () {
         this.v1_history_id = 42
         return db.projects.updateOne(
           {
-            _id: ObjectId(this.project_id),
+            _id: new ObjectId(this.project_id),
           },
           {
             $set: {

+ 1 - 1
services/web/modules/server-ce-scripts/scripts/change-compile-timeout.js

@@ -34,7 +34,7 @@ async function main() {
   }
 
   await db.users.updateOne(
-    { _id: ObjectId(userId) },
+    { _id: new ObjectId(userId) },
     { $set: { 'features.compileTimeout': compileTimeout } }
   )
 }

+ 1 - 1
services/web/modules/server-ce-scripts/scripts/check-mongodb.js

@@ -22,7 +22,7 @@ async function testTransactions() {
   const session = mongoClient.startSession()
   try {
     await session.withTransaction(async () => {
-      await db.users.findOne({ _id: ObjectId() }, { session })
+      await db.users.findOne({ _id: new ObjectId() }, { session })
     })
   } finally {
     await session.endSession()

+ 1 - 1
services/web/scripts/add_feature_override.js

@@ -168,7 +168,7 @@ async function processUsers(userIds) {
 
   const limit = pLimit(CONCURRENCY)
   const results = await Promise.allSettled(
-    userIds.map(userId => limit(() => _handleUser(ObjectId(userId))))
+    userIds.map(userId => limit(() => _handleUser(new ObjectId(userId))))
   )
   results.forEach((result, idx) => {
     if (result.status !== 'fulfilled') {

+ 1 - 1
services/web/scripts/back_fill_dummy_doc_meta.js

@@ -29,7 +29,7 @@ async function main(options) {
   _.defaults(options, {
     dryRun: process.env.DRY_RUN === 'true',
     cacheSize: parseInt(process.env.CACHE_SIZE, 10) || 100,
-    firstProjectId: ObjectId(process.env.FIRST_PROJECT_ID),
+    firstProjectId: new ObjectId(process.env.FIRST_PROJECT_ID),
     incrementByS: parseInt(process.env.INCREMENT_BY_S, 10) || ONE_WEEK_IN_S,
     batchSize: parseInt(process.env.BATCH_SIZE, 10) || 1000,
     stopAtS: parseInt(process.env.STOP_AT_S, 10) || NOW_IN_S,

+ 1 - 1
services/web/scripts/count_project_size.js

@@ -100,7 +100,7 @@ async function countDocsSizes(docs) {
   for (const docId of ids) {
     const result = await db.docs.aggregate([
       {
-        $match: { _id: ObjectId(docId) },
+        $match: { _id: new ObjectId(docId) },
       },
       {
         $project: {

+ 4 - 4
services/web/scripts/delete-orphaned-docs/delete-orphaned-docs.js

@@ -48,8 +48,8 @@ rl.on('line', async line => {
   projectId = projectId.replace(/^ObjectId\(/, '').replace(/\)$/, '')
 
   try {
-    docId = ObjectId(docId).toString()
-    projectId = ObjectId(projectId).toString()
+    docId = new ObjectId(docId).toString()
+    projectId = new ObjectId(projectId).toString()
   } catch (err) {
     console.error(`Invalid id: ${docId}, ${projectId}`)
     return
@@ -114,14 +114,14 @@ async function projectIdExists(projectId) {
 
 async function findProject(projectId) {
   return db.projects.findOne(
-    { _id: ObjectId(projectId) },
+    { _id: new ObjectId(projectId) },
     { projection: { _id: 1 } }
   )
 }
 
 async function findDeletedProject(projectId) {
   return db.deletedProjects.findOne(
-    { 'project._id': ObjectId(projectId) },
+    { 'project._id': new ObjectId(projectId) },
     { projection: { _id: 1 } }
   )
 }

+ 1 - 1
services/web/scripts/delete_dangling_file_refs.js

@@ -43,7 +43,7 @@ async function main() {
 }
 
 async function getProjects() {
-  const projectIds = OPTIONS.projectIds.map(id => ObjectId(id))
+  const projectIds = OPTIONS.projectIds.map(id => new ObjectId(id))
   const projects = await db.projects
     .find(
       { _id: { $in: projectIds } },

+ 1 - 1
services/web/scripts/delete_orphaned_chat_threads.js

@@ -38,7 +38,7 @@ async function processBatch(rooms) {
   }
   const projectIds = Array.from(
     new Set(rooms.map(room => room.project_id.toString()))
-  ).map(ObjectId)
+  ).map(id => new ObjectId(id))
   console.log(
     `Checking projects (${projectIds.length})`,
     JSON.stringify(projectIds)

+ 2 - 2
services/web/scripts/delete_orphaned_docs_online_check.js

@@ -20,7 +20,7 @@ if (!process.env.BATCH_LAST_ID) {
   console.error('Set BATCH_LAST_ID and re-run.')
   process.exit(1)
 }
-const BATCH_LAST_ID = ObjectId(process.env.BATCH_LAST_ID)
+const BATCH_LAST_ID = new ObjectId(process.env.BATCH_LAST_ID)
 const INCREMENT_BY_S = parseInt(process.env.INCREMENT_BY_S, 10) || ONE_WEEK_IN_S
 const BATCH_SIZE = parseInt(process.env.BATCH_SIZE, 10) || 1000
 const READ_CONCURRENCY_SECONDARY =
@@ -66,7 +66,7 @@ async function main() {
     if (docs.length) {
       const projectIds = Array.from(
         new Set(docs.map(doc => doc.project_id.toString()))
-      ).map(ObjectId)
+      ).map(id => new ObjectId(id))
       console.log('Checking projects', JSON.stringify(projectIds))
       const { nProjectsWithOrphanedDocs, nDeletedDocs } = await processBatch(
         projectIds

+ 2 - 2
services/web/scripts/delete_orphaned_project_archives.js

@@ -59,8 +59,8 @@ async function processBatch(entries) {
     prefixes.push(prefix)
     projectIdToPrefix.set(projectId, prefixes)
   }
-  const projectIds = Array.from(projectIdToPrefix.keys()).map(id =>
-    ObjectId(id)
+  const projectIds = Array.from(projectIdToPrefix.keys()).map(
+    id => new ObjectId(id)
   )
   const projectsWithOrphanedArchive = await getHardDeletedProjectIds({
     projectIds,

+ 2 - 2
services/web/scripts/delete_subscriptions.js

@@ -8,7 +8,7 @@ const { ObjectId } = require('mongodb')
 const run = async () => {
   for (const id of ids) {
     console.log('id', id)
-    const subscription = await Subscription.findOne({ _id: ObjectId(id) })
+    const subscription = await Subscription.findOne({ _id: new ObjectId(id) })
     await SubscriptionUpdater.promises.deleteSubscription(
       subscription,
       deleterData
@@ -33,7 +33,7 @@ const setup = () => {
     process.exit(1)
   }
 
-  deleterData = { id: ObjectId(deleterId) }
+  deleterData = { id: new ObjectId(deleterId) }
 }
 
 setup()

+ 3 - 3
services/web/scripts/fix_malformed_filetree.js

@@ -45,7 +45,7 @@ function parseArgs() {
     process.exit(1)
   }
   const [projectId, mongoPath] = args
-  return { projectId: ObjectId(projectId), mongoPath }
+  return { projectId: new ObjectId(projectId), mongoPath }
 }
 
 function isRootFolder(path) {
@@ -86,7 +86,7 @@ async function fixRootFolder(projectId) {
       $set: {
         rootFolder: [
           {
-            _id: ObjectId(),
+            _id: new ObjectId(),
             name: 'rootFolder',
             folders: [],
             docs: [],
@@ -127,7 +127,7 @@ async function fixArray(projectId, path) {
 async function fixFolderId(projectId, path) {
   const result = await db.projects.updateOne(
     { _id: projectId, [path]: { $exists: false } },
-    { $set: { [path]: ObjectId() } }
+    { $set: { [path]: new ObjectId() } }
   )
   return result.modifiedCount
 }

+ 2 - 2
services/web/scripts/fix_oversized_docs.js

@@ -75,8 +75,8 @@ async function processDoc(projectId, docId) {
     if (opts.commit) {
       const fileRef = await sendDocToFilestore(projectId, doc)
       await ProjectEntityMongoUpdateHandler.promises.replaceDocWithFile(
-        ObjectId(projectId),
-        ObjectId(docId),
+        new ObjectId(projectId),
+        new ObjectId(docId),
         fileRef
       )
       await deleteDocFromMongo(projectId, doc)

+ 1 - 1
services/web/scripts/force_doc_flush.js

@@ -28,7 +28,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(
-      { _id: ObjectId(DOC_ID), project_id: ObjectId(PROJECT_ID) },
+      { _id: new ObjectId(DOC_ID), project_id: new ObjectId(PROJECT_ID) },
       {
         $set: { lines, version, ranges },
         $inc: { rev: 1 }, // maintain same behaviour as Docstore upsertIntoDocCollection

+ 3 - 3
services/web/scripts/helpers/batchedUpdate.js

@@ -22,9 +22,9 @@ function refreshGlobalOptionsForBatchedUpdate(options = {}) {
   BATCH_SIZE = parseInt(options.BATCH_SIZE, 10) || 1000
   VERBOSE_LOGGING = options.VERBOSE_LOGGING === 'true'
   if (options.BATCH_LAST_ID) {
-    BATCH_RANGE_START = ObjectId(options.BATCH_LAST_ID)
+    BATCH_RANGE_START = new ObjectId(options.BATCH_LAST_ID)
   } else if (options.BATCH_RANGE_START) {
-    BATCH_RANGE_START = ObjectId(options.BATCH_RANGE_START)
+    BATCH_RANGE_START = new ObjectId(options.BATCH_RANGE_START)
   } else {
     if (BATCH_DESCENDING) {
       BATCH_RANGE_START = ID_EDGE_FUTURE
@@ -35,7 +35,7 @@ function refreshGlobalOptionsForBatchedUpdate(options = {}) {
   BATCH_MAX_TIME_SPAN_IN_MS =
     parseInt(options.BATCH_MAX_TIME_SPAN_IN_MS, 10) || ONE_MONTH_IN_MS
   if (options.BATCH_RANGE_END) {
-    BATCH_RANGE_END = ObjectId(options.BATCH_RANGE_END)
+    BATCH_RANGE_END = new ObjectId(options.BATCH_RANGE_END)
   } else {
     if (BATCH_DESCENDING) {
       BATCH_RANGE_END = ID_EDGE_PAST

+ 1 - 1
services/web/scripts/invalidate_tokens.js

@@ -3,7 +3,7 @@ const minimist = require('minimist')
 const argv = minimist(process.argv.slice(2))
 const commit = argv.commit !== undefined
 const projectIds = argv._.map(x => {
-  return ObjectId(x)
+  return new ObjectId(x)
 })
 
 if (!commit) {

+ 2 - 2
services/web/scripts/merge_group_subscription_members.js

@@ -44,8 +44,8 @@ async function main() {
 
   await waitForDb()
 
-  const targetSubscription = await getSubscription(ObjectId(target))
-  const sourceSubscription = await getSubscription(ObjectId(source))
+  const targetSubscription = await getSubscription(new ObjectId(target))
+  const sourceSubscription = await getSubscription(new ObjectId(source))
 
   if (!targetSubscription) {
     throw new Error('couldnt find target (to) subscription')

+ 2 - 2
services/web/scripts/migrate_audit_logs.js

@@ -25,7 +25,7 @@ async function main(options) {
   if (options.projectId) {
     console.log('migrating projectId=' + options.projectId)
     const project = await db.projects.findOne(
-      { _id: ObjectId(options.projectId) },
+      { _id: new ObjectId(options.projectId) },
       { _id: 1, auditLog: 1 }
     )
     if (!project || !project.auditLog) {
@@ -36,7 +36,7 @@ async function main(options) {
   } else if (options.userId) {
     console.log('migrating userId=' + options.userId)
     const user = await db.users.findOne(
-      { _id: ObjectId(options.userId) },
+      { _id: new ObjectId(options.userId) },
       { _id: 1, auditLog: 1 }
     )
     if (!user || !user.auditLog) {

+ 1 - 1
services/web/scripts/oauth/register_client.js

@@ -61,7 +61,7 @@ async function upsertApplication(opts) {
     defaults.redirectUris = []
   }
   if (opts.mongoId != null) {
-    defaults._id = ObjectId(opts.mongoId)
+    defaults._id = new ObjectId(opts.mongoId)
   }
 
   await db.oauthApplications.updateOne(

+ 2 - 2
services/web/scripts/recover_docs_from_redis.js

@@ -53,7 +53,7 @@ async function main() {
 
 async function processDoc(docId) {
   // check if the doc is in mongo.. if so ignore it
-  const docCount = await db.docs.find({ _id: ObjectId(docId) }).count()
+  const docCount = await db.docs.find({ _id: new ObjectId(docId) }).count()
   if (docCount > 0) {
     logger.debug({ docId }, 'doc is present in mongo - no recovery needed')
     return
@@ -70,7 +70,7 @@ async function processDoc(docId) {
     return
   }
   // check that the project is in mongo, if not delete the doc
-  const project = await db.projects.findOne({ _id: ObjectId(projectId) })
+  const project = await db.projects.findOne({ _id: new ObjectId(projectId) })
   if (!project) {
     logger.warn(
       { docId },

+ 2 - 2
services/web/scripts/set_tex_live_image.js

@@ -39,7 +39,7 @@ function parseProjectIds(projectIds) {
   for (const projectId of projectIds) {
     let oid
     try {
-      oid = ObjectId(projectId)
+      oid = new ObjectId(projectId)
     } catch (err) {
       console.error(`Invalid project id: ${projectId}`)
       process.exit(1)
@@ -51,7 +51,7 @@ function parseProjectIds(projectIds) {
 
 async function updateImage(image, projectIds) {
   const res = await Project.updateMany(
-    { _id: { $in: projectIds.map(ObjectId) } },
+    { _id: { $in: projectIds.map(id => new ObjectId(id)) } },
     { $set: { imageName: `quay.io/sharelatex/${image}` } }
   ).exec()
   console.log(`Found ${res.matchedCount} out of ${projectIds.length} projects`)

+ 1 - 1
services/web/scripts/stress_test.js

@@ -363,7 +363,7 @@ async function uploadFile(projectId) {
   async function upload(abortSignal, deleteFile = true) {
     const size = userSize.get()
     const buffer = Buffer.alloc(size, crypto.randomUUID())
-    const fileId = ObjectId()
+    const fileId = new ObjectId()
     const url = `${settings.apis.filestore.url}/project/${projectId}/file/${fileId}`
     const md5 = computeMD5Hash(buffer)
     const response = await fetch(url, {

+ 4 - 4
services/web/test/acceptance/src/AuthenticationTests.js

@@ -63,8 +63,8 @@ describe('Authentication', function () {
       const auditLogEntry = auditLog[0]
       expect(auditLogEntry).to.exist
       expect(auditLogEntry.timestamp).to.exist
-      expect(auditLogEntry.initiatorId).to.deep.equal(ObjectId(user.id))
-      expect(auditLogEntry.userId).to.deep.equal(ObjectId(user.id))
+      expect(auditLogEntry.initiatorId).to.deep.equal(new ObjectId(user.id))
+      expect(auditLogEntry.userId).to.deep.equal(new ObjectId(user.id))
       expect(auditLogEntry.operation).to.equal('login')
       expect(auditLogEntry.info).to.deep.equal({
         method: 'Password login',
@@ -96,8 +96,8 @@ describe('Authentication', function () {
       const auditLogEntry = auditLog.pop()
       expect(auditLogEntry).to.exist
       expect(auditLogEntry.timestamp).to.exist
-      expect(auditLogEntry.initiatorId).to.deep.equal(ObjectId(user.id))
-      expect(auditLogEntry.userId).to.deep.equal(ObjectId(user.id))
+      expect(auditLogEntry.initiatorId).to.deep.equal(new ObjectId(user.id))
+      expect(auditLogEntry.userId).to.deep.equal(new ObjectId(user.id))
       expect(auditLogEntry.operation).to.equal('failed-password-match')
       expect(auditLogEntry.info).to.deep.equal({
         method: 'Password login',

+ 9 - 9
services/web/test/acceptance/src/BackFillDeletedFilesTests.js

@@ -27,20 +27,20 @@ describe('BackFillDeletedFiles', function () {
     user = new User()
     await user.login()
 
-    projectId1 = ObjectId(await user.createProject('project1'))
-    projectId2 = ObjectId(await user.createProject('project2'))
-    projectId3 = ObjectId(await user.createProject('project3'))
-    projectId4 = ObjectId(await user.createProject('project4'))
-    projectId5 = ObjectId(await user.createProject('project5'))
+    projectId1 = new ObjectId(await user.createProject('project1'))
+    projectId2 = new ObjectId(await user.createProject('project2'))
+    projectId3 = new ObjectId(await user.createProject('project3'))
+    projectId4 = new ObjectId(await user.createProject('project4'))
+    projectId5 = new ObjectId(await user.createProject('project5'))
   })
 
   let fileId1, fileId2, fileId3, fileId4
   beforeEach('create files', function () {
     // take a short cut and just allocate file ids
-    fileId1 = ObjectId()
-    fileId2 = ObjectId()
-    fileId3 = ObjectId()
-    fileId4 = ObjectId()
+    fileId1 = new ObjectId()
+    fileId2 = new ObjectId()
+    fileId3 = new ObjectId()
+    fileId4 = new ObjectId()
   })
   const otherFileDetails = {
     name: 'universe.jpg',

+ 5 - 5
services/web/test/acceptance/src/BackFillDocNameForDeletedDocsTests.js

@@ -19,17 +19,17 @@ describe('BackFillDocNameForDeletedDocs', function () {
     user = new User()
     await user.login()
 
-    projectId1 = ObjectId(await user.createProject('project1'))
-    projectId2 = ObjectId(await user.createProject('project2'))
+    projectId1 = new ObjectId(await user.createProject('project1'))
+    projectId2 = new ObjectId(await user.createProject('project2'))
   })
   beforeEach('create docs', async function () {
-    docId1 = ObjectId(
+    docId1 = new ObjectId(
       await user.createDocInProject(projectId1, null, 'doc1.tex')
     )
-    docId2 = ObjectId(
+    docId2 = new ObjectId(
       await user.createDocInProject(projectId1, null, 'doc2.tex')
     )
-    docId3 = ObjectId(
+    docId3 = new ObjectId(
       await user.createDocInProject(projectId2, null, 'doc3.tex')
     )
   })

+ 3 - 3
services/web/test/acceptance/src/BackFillDocRevTests.js

@@ -5,9 +5,9 @@ const logger = require('@overleaf/logger/logging-manager')
 const { expect } = require('chai')
 
 describe('BackFillDocRevTests', function () {
-  const docId1 = ObjectId()
-  const docId2 = ObjectId()
-  const docId3 = ObjectId()
+  const docId1 = new ObjectId()
+  const docId2 = new ObjectId()
+  const docId3 = new ObjectId()
 
   beforeEach('insert docs', async function () {
     await db.docs.insertMany([

+ 3 - 3
services/web/test/acceptance/src/ConvertArchivedState.js

@@ -52,9 +52,9 @@ describe('ConvertArchivedState', function () {
     })
     projectThree = await userOne.getProject(projectThreeId)
     projectThree.archived = [
-      ObjectId(userOne._id),
-      ObjectId(userTwo._id),
-      ObjectId(userFour._id),
+      new ObjectId(userOne._id),
+      new ObjectId(userTwo._id),
+      new ObjectId(userFour._id),
     ]
     projectThree.collaberator_refs.push(userTwo._id)
     projectThree.tokenAccessReadOnly_refs.push(userFour._id)

+ 6 - 2
services/web/test/acceptance/src/DeletionTests.js

@@ -432,7 +432,7 @@ describe('Deleting a project', function () {
 
       it('Should remove the project data from mongo', function (done) {
         db.deletedProjects.findOne(
-          { 'deleterData.deletedProjectId': ObjectId(this.projectId) },
+          { 'deleterData.deletedProjectId': new ObjectId(this.projectId) },
           (error, deletedProject) => {
             expect(error).not.to.exist
             expect(deletedProject).to.exist
@@ -454,7 +454,11 @@ describe('Deleting a project', function () {
                 expect(res.statusCode).to.equal(200)
 
                 db.deletedProjects.findOne(
-                  { 'deleterData.deletedProjectId': ObjectId(this.projectId) },
+                  {
+                    'deleterData.deletedProjectId': new ObjectId(
+                      this.projectId
+                    ),
+                  },
                   (error, deletedProject) => {
                     expect(error).not.to.exist
                     expect(deletedProject).to.exist

+ 1 - 1
services/web/test/acceptance/src/DocUpdateTests.js

@@ -135,7 +135,7 @@ describe('DocUpdate', function () {
 
   describe('unknown doc', function () {
     beforeEach(function () {
-      writeOptions.docId = ObjectId()
+      writeOptions.docId = new ObjectId()
     })
 
     shouldBlockChanges()

+ 4 - 2
services/web/test/acceptance/src/MongoHelper.js

@@ -37,7 +37,7 @@ describe('MongoTests', function () {
 
       expect(query).to.exist
       expect(query._id).to.be.instanceof(NativeObjectId)
-      expect(query._id).to.deep.equal(NativeObjectId(userIdAsString))
+      expect(query._id).to.deep.equal(new NativeObjectId(userIdAsString))
 
       const user = await db.users.findOne(query)
       expect(user).to.exist
@@ -79,7 +79,9 @@ describe('MongoTests', function () {
     describe('with an ObjectId from the native driver', function () {
       let user
       beforeEach(async function getUser() {
-        user = await db.users.findOne({ _id: NativeObjectId(userIdAsString) })
+        user = await db.users.findOne({
+          _id: new NativeObjectId(userIdAsString),
+        })
         expect(user).to.exist
         expect(user._id).to.exist
         expect(user.email).to.equal(userEmail)

+ 3 - 3
services/web/test/acceptance/src/ProjectCRUDTests.js

@@ -78,7 +78,7 @@ describe('Project CRUD', function () {
       it('should mark the project as not archived for the user', async function () {
         await Project.updateOne(
           { _id: this.projectId },
-          { $set: { archived: [ObjectId(this.user._id)] } }
+          { $set: { archived: [new ObjectId(this.user._id)] } }
         ).exec()
 
         const { response } = await this.user.doRequest(
@@ -117,7 +117,7 @@ describe('Project CRUD', function () {
     it('should mark the project as untrashed for the user', async function () {
       await Project.updateOne(
         { _id: this.projectId },
-        { trashed: [ObjectId(this.user._id)] }
+        { trashed: [new ObjectId(this.user._id)] }
       ).exec()
       const { response } = await this.user.doRequest(
         'DELETE',
@@ -132,7 +132,7 @@ describe('Project CRUD', function () {
     it('does nothing if the user has already untrashed the project', async function () {
       await Project.updateOne(
         { _id: this.projectId },
-        { trashed: [ObjectId(this.user._id)] }
+        { trashed: [new ObjectId(this.user._id)] }
       ).exec()
       // Mark as untrashed the first time
       await this.user.doRequest('DELETE', `/project/${this.projectId}/trash`)

+ 1 - 1
services/web/test/acceptance/src/helpers/Institution.js

@@ -28,7 +28,7 @@ class Institution {
 
   setManagerIds(managerIds, callback) {
     return InstitutionModel.findOneAndUpdate(
-      { _id: ObjectId(this._id) },
+      { _id: new ObjectId(this._id) },
       { managerIds },
       callback
     )

+ 1 - 1
services/web/test/acceptance/src/helpers/Publisher.js

@@ -22,7 +22,7 @@ class Publisher {
 
   setManagerIds(managerIds, callback) {
     return PublisherModel.findOneAndUpdate(
-      { _id: ObjectId(this._id) },
+      { _id: new ObjectId(this._id) },
       { managerIds },
       callback
     )

+ 1 - 1
services/web/test/acceptance/src/helpers/RecurlySubscription.js

@@ -12,7 +12,7 @@ before(function () {
 
 class RecurlySubscription {
   constructor(options = {}) {
-    options.recurlySubscription_id = ObjectId().toString()
+    options.recurlySubscription_id = new ObjectId().toString()
     this.subscription = new Subscription(options)
 
     this.uuid = options.recurlySubscription_id

+ 3 - 3
services/web/test/acceptance/src/helpers/Subscription.js

@@ -12,7 +12,7 @@ const Modules = require('../../../../app/src/infrastructure/Modules')
 
 class Subscription {
   constructor(options = {}) {
-    this.admin_id = options.adminId || ObjectId()
+    this.admin_id = options.adminId || new ObjectId()
     this.overleaf = options.overleaf || {}
     this.groupPlan = options.groupPlan
     this.manager_ids = options.managerIds || [this.admin_id]
@@ -48,7 +48,7 @@ class Subscription {
   }
 
   get(callback) {
-    db.subscriptions.findOne({ _id: ObjectId(this._id) }, callback)
+    db.subscriptions.findOne({ _id: new ObjectId(this._id) }, callback)
   }
 
   getWithGroupPolicy(callback) {
@@ -57,7 +57,7 @@ class Subscription {
 
   setManagerIds(managerIds, callback) {
     return SubscriptionModel.findOneAndUpdate(
-      { _id: ObjectId(this._id) },
+      { _id: new ObjectId(this._id) },
       { manager_ids: managerIds },
       callback
     )

+ 10 - 10
services/web/test/acceptance/src/helpers/User.js

@@ -44,7 +44,7 @@ class User {
   }
 
   get(callback) {
-    db.users.findOne({ _id: ObjectId(this._id) }, callback)
+    db.users.findOne({ _id: new ObjectId(this._id) }, callback)
   }
 
   getAuditLog(callback) {
@@ -53,7 +53,7 @@ class User {
       if (!user) return callback(new Error('User not found'))
 
       db.userAuditLogEntries
-        .find({ userId: ObjectId(this._id) })
+        .find({ userId: new ObjectId(this._id) })
         .toArray((error, auditLog) => {
           if (error) return callback(error)
           callback(null, auditLog || [])
@@ -74,7 +74,7 @@ class User {
   }
 
   mongoUpdate(updateOp, callback) {
-    db.users.updateOne({ _id: ObjectId(this._id) }, updateOp, callback)
+    db.users.updateOne({ _id: new ObjectId(this._id) }, updateOp, callback)
   }
 
   register(callback) {
@@ -347,7 +347,7 @@ class User {
 
   getFeatures(callback) {
     db.users.findOne(
-      { _id: ObjectId(this.id) },
+      { _id: new ObjectId(this.id) },
       { projection: { features: 1 } },
       (error, user) => callback(error, user && user.features)
     )
@@ -362,11 +362,11 @@ class User {
         return callback()
       }
       const userId = user._id
-      db.projects.deleteMany({ owner_ref: ObjectId(userId) }, err => {
+      db.projects.deleteMany({ owner_ref: new ObjectId(userId) }, err => {
         if (err != null) {
           callback(err)
         }
-        db.users.deleteOne({ _id: ObjectId(userId) }, callback)
+        db.users.deleteOne({ _id: new ObjectId(userId) }, callback)
       })
     })
   }
@@ -401,7 +401,7 @@ class User {
   }
 
   getProject(projectId, callback) {
-    db.projects.findOne({ _id: ObjectId(projectId.toString()) }, callback)
+    db.projects.findOne({ _id: new ObjectId(projectId.toString()) }, callback)
   }
 
   saveProject(project, callback) {
@@ -498,7 +498,7 @@ class User {
   }
 
   deleteProjects(callback) {
-    db.projects.deleteMany({ owner_ref: ObjectId(this.id) }, callback)
+    db.projects.deleteMany({ owner_ref: new ObjectId(this.id) }, callback)
   }
 
   openProject(projectId, callback) {
@@ -721,14 +721,14 @@ class User {
     } else if (privileges === 'readOnly') {
       updateOp = { $addToSet: { readOnly_refs: user._id } }
     }
-    db.projects.updateOne({ _id: ObjectId(projectId) }, updateOp, callback)
+    db.projects.updateOne({ _id: new ObjectId(projectId) }, updateOp, callback)
   }
 
   makePublic(projectId, level, callback) {
     // A fudge, to get around the fact that `readOnly` and `readAndWrite` are now disallowed
     // via the API, but we still need to test the behaviour of projects with these values set.
     db.projects.updateOne(
-      { _id: ObjectId(projectId) },
+      { _id: new ObjectId(projectId) },
       // NOTE: Yes, there is a typo in the db schema.
       { $set: { publicAccesLevel: level } },
       callback

+ 1 - 1
services/web/test/acceptance/src/helpers/UserHelper.js

@@ -238,7 +238,7 @@ class UserHelper {
   static async updateUser(userId, update) {
     // TODO(das7pad): revert back to args pass-through after mongo upgrades
     const user = await UserUpdater.promises.updateUser(
-      { _id: ObjectId(userId) },
+      { _id: new ObjectId(userId) },
       update
     )
 

+ 1 - 1
services/web/test/acceptance/src/mocks/MockDocstoreApi.js

@@ -91,7 +91,7 @@ class MockDocstoreApi extends AbstractMockApi {
     this.app.post('/project/:projectId/destroy', async (req, res) => {
       const { projectId } = req.params
       delete this.docs[projectId]
-      await db.docs.deleteMany({ project_id: ObjectId(projectId) })
+      await db.docs.deleteMany({ project_id: new ObjectId(projectId) })
       res.sendStatus(204)
     })
   }

+ 5 - 5
services/web/test/unit/src/Analytics/AnalyticsManagerTests.js

@@ -4,7 +4,7 @@ const sinon = require('sinon')
 const MockRequest = require('../helpers/MockRequest')
 const MockResponse = require('../helpers/MockResponse')
 const { assert } = require('chai')
-const { ObjectID } = require('mongodb')
+const { ObjectId } = require('mongodb')
 
 const MODULE_PATH = path.join(
   __dirname,
@@ -85,7 +85,7 @@ describe('AnalyticsManager', function () {
 
     it('analyticsId is missing', function () {
       this.AnalyticsManager.identifyUser(
-        new ObjectID(this.fakeUserId),
+        new ObjectId(this.fakeUserId),
         undefined
       )
       sinon.assert.notCalled(this.Queues.createScheduledJob)
@@ -93,7 +93,7 @@ describe('AnalyticsManager', function () {
 
     it('analyticsId is not a valid UUID', function () {
       this.AnalyticsManager.identifyUser(
-        new ObjectID(this.fakeUserId),
+        new ObjectId(this.fakeUserId),
         this.fakeUserId
       )
       sinon.assert.notCalled(this.Queues.createScheduledJob)
@@ -101,8 +101,8 @@ describe('AnalyticsManager', function () {
 
     it('userId and analyticsId are the same Mongo ID', function () {
       this.AnalyticsManager.identifyUser(
-        new ObjectID(this.fakeUserId),
-        new ObjectID(this.fakeUserId)
+        new ObjectId(this.fakeUserId),
+        new ObjectId(this.fakeUserId)
       )
       sinon.assert.notCalled(this.Queues.createScheduledJob)
     })

+ 1 - 1
services/web/test/unit/src/Authentication/AuthenticationControllerTests.js

@@ -17,7 +17,7 @@ describe('AuthenticationController', function () {
       'valid-test-user': Math.random().toString(16).slice(2),
     }
     this.user = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       email: (this.email = 'USER@example.com'),
       first_name: 'bob',
       last_name: 'brown',

+ 2 - 2
services/web/test/unit/src/Authentication/AuthenticationManagerTests.js

@@ -747,7 +747,7 @@ describe('AuthenticationManager', function () {
 
   describe('setUserPassword', function () {
     beforeEach(function () {
-      this.user_id = ObjectId()
+      this.user_id = new ObjectId()
       this.password = 'bananagram'
       this.hashedPassword = 'asdkjfa;osiuvandf'
       this.salt = 'saltaasdfasdfasdf'
@@ -955,7 +955,7 @@ describe('AuthenticationManager', function () {
       it("should update the user's password in the database", function () {
         const { args } = this.db.users.updateOne.lastCall
         expect(args[0]).to.deep.equal({
-          _id: ObjectId(this.user_id.toString()),
+          _id: new ObjectId(this.user_id.toString()),
         })
         expect(args[1]).to.deep.equal({
           $set: {

+ 1 - 1
services/web/test/unit/src/Authentication/SessionManagerTests.js

@@ -13,7 +13,7 @@ describe('SessionManager', function () {
       requires: {},
     })
     this.user = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       email: (this.email = 'USER@example.com'),
       first_name: 'bob',
       last_name: 'brown',

+ 2 - 2
services/web/test/unit/src/Collaborators/CollaboratorsControllerTests.js

@@ -14,8 +14,8 @@ describe('CollaboratorsController', function () {
     this.res = new MockResponse()
     this.req = new MockRequest()
 
-    this.user = { _id: ObjectId() }
-    this.projectId = ObjectId()
+    this.user = { _id: new ObjectId() }
+    this.projectId = new ObjectId()
     this.callback = sinon.stub()
 
     this.CollaboratorsHandler = {

+ 10 - 10
services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js

@@ -14,16 +14,16 @@ const MODULE_PATH = Path.join(
 describe('CollaboratorsGetter', function () {
   beforeEach(function () {
     this.userId = 'mock-user-id'
-    this.ownerRef = ObjectId()
-    this.readOnlyRef1 = ObjectId()
-    this.readOnlyRef2 = ObjectId()
-    this.readWriteRef1 = ObjectId()
-    this.readWriteRef2 = ObjectId()
-    this.readOnlyTokenRef = ObjectId()
-    this.readWriteTokenRef = ObjectId()
-    this.nonMemberRef = ObjectId()
+    this.ownerRef = new ObjectId()
+    this.readOnlyRef1 = new ObjectId()
+    this.readOnlyRef2 = new ObjectId()
+    this.readWriteRef1 = new ObjectId()
+    this.readWriteRef2 = new ObjectId()
+    this.readOnlyTokenRef = new ObjectId()
+    this.readWriteTokenRef = new ObjectId()
+    this.nonMemberRef = new ObjectId()
     this.project = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       owner_ref: [this.ownerRef],
       readOnly_refs: [this.readOnlyRef1, this.readOnlyRef2],
       collaberator_refs: [this.readWriteRef1, this.readWriteRef2],
@@ -366,7 +366,7 @@ describe('CollaboratorsGetter', function () {
   })
 
   describe('getPublicShareTokens', function () {
-    const userMock = ObjectId()
+    const userMock = new ObjectId()
 
     it('should return null when the project is not found', async function () {
       this.ProjectMock.expects('findOne').chain('exec').resolves(undefined)

+ 11 - 11
services/web/test/unit/src/Collaborators/CollaboratorsHandlerTests.js

@@ -16,21 +16,21 @@ const sleep = promisify(setTimeout)
 
 describe('CollaboratorsHandler', function () {
   beforeEach(function () {
-    this.userId = ObjectId()
-    this.addingUserId = ObjectId()
+    this.userId = new ObjectId()
+    this.addingUserId = new ObjectId()
     this.project = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       owner_ref: this.addingUserId,
       name: 'Foo',
     }
 
     this.archivedProject = {
-      _id: ObjectId(),
-      archived: [ObjectId(this.userId)],
+      _id: new ObjectId(),
+      archived: [new ObjectId(this.userId)],
     }
 
     this.oldArchivedProject = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       archived: true,
     }
 
@@ -124,7 +124,7 @@ describe('CollaboratorsHandler', function () {
 
     describe('an archived project, archived with a boolean value', function () {
       beforeEach(function () {
-        const archived = [ObjectId(this.userId)]
+        const archived = [new ObjectId(this.userId)]
         this.ProjectHelper.calculateArchivedArray.returns(archived)
 
         this.ProjectMock.expects('findOne')
@@ -394,14 +394,14 @@ describe('CollaboratorsHandler', function () {
 
   describe('transferProjects', function () {
     beforeEach(function () {
-      this.fromUserId = ObjectId()
-      this.toUserId = ObjectId()
+      this.fromUserId = new ObjectId()
+      this.toUserId = new ObjectId()
       this.projects = [
         {
-          _id: ObjectId(),
+          _id: new ObjectId(),
         },
         {
-          _id: ObjectId(),
+          _id: new ObjectId(),
         },
       ]
       this.ProjectMock.expects('find')

+ 4 - 4
services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js

@@ -20,7 +20,7 @@ describe('CollaboratorsInviteController', function () {
       email: 'current-user@example.com',
     }
     this.invite = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       token: this.token,
       sendingUserId: this.currentUser._id,
       projectId: this.projectId,
@@ -116,8 +116,8 @@ describe('CollaboratorsInviteController', function () {
   describe('getAllInvites', function () {
     beforeEach(function () {
       this.fakeInvites = [
-        { _id: ObjectId(), one: 1 },
-        { _id: ObjectId(), two: 2 },
+        { _id: new ObjectId(), one: 1 },
+        { _id: new ObjectId(), two: 2 },
       ]
       this.req.params = { Project_id: this.projectId }
     })
@@ -1295,7 +1295,7 @@ describe('CollaboratorsInviteController', function () {
 
       describe('when user account is present', function () {
         beforeEach(function () {
-          this.user = { _id: ObjectId().toString() }
+          this.user = { _id: new ObjectId().toString() }
           this.UserGetter.promises.getUserByAnyEmail.resolves(this.user)
         })
 

+ 13 - 13
services/web/test/unit/src/Collaborators/CollaboratorsInviteHandlerTests.js

@@ -14,7 +14,7 @@ describe('CollaboratorsInviteHandler', function () {
         if (options == null) {
           options = {}
         }
-        this._id = ObjectId()
+        this._id = new ObjectId()
         for (const k in options) {
           const v = options[k]
           this[k] = v
@@ -55,19 +55,19 @@ describe('CollaboratorsInviteHandler', function () {
       },
     })
 
-    this.projectId = ObjectId()
-    this.sendingUserId = ObjectId()
+    this.projectId = new ObjectId()
+    this.sendingUserId = new ObjectId()
     this.sendingUser = {
       _id: this.sendingUserId,
       name: 'Bob',
     }
     this.email = 'user@example.com'
-    this.userId = ObjectId()
+    this.userId = new ObjectId()
     this.user = {
       _id: this.userId,
       email: 'someone@example.com',
     }
-    this.inviteId = ObjectId()
+    this.inviteId = new ObjectId()
     this.token = 'hnhteaosuhtaeosuahs'
     this.privileges = 'readAndWrite'
     this.fakeInvite = {
@@ -114,8 +114,8 @@ describe('CollaboratorsInviteHandler', function () {
   describe('getAllInvites', function () {
     beforeEach(function () {
       this.fakeInvites = [
-        { _id: ObjectId(), one: 1 },
-        { _id: ObjectId(), two: 2 },
+        { _id: new ObjectId(), one: 1 },
+        { _id: new ObjectId(), two: 2 },
       ]
       this.ProjectInvite.find.returns({
         exec: sinon.stub().resolves(this.fakeInvites),
@@ -607,8 +607,8 @@ describe('CollaboratorsInviteHandler', function () {
 
   describe('_tryCancelInviteNotification', function () {
     beforeEach(function () {
-      this.inviteId = ObjectId()
-      this.currentUser = { _id: ObjectId() }
+      this.inviteId = new ObjectId()
+      this.currentUser = { _id: new ObjectId() }
       this.notification = { read: sinon.stub().resolves() }
       this.NotificationsBuilder.promises.projectInvite = sinon
         .stub()
@@ -644,18 +644,18 @@ describe('CollaboratorsInviteHandler', function () {
   describe('_trySendInviteNotification', function () {
     beforeEach(function () {
       this.invite = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         token: 'some_token',
-        sendingUserId: ObjectId(),
+        sendingUserId: new ObjectId(),
         projectId: this.project_id,
         targetEmail: 'user@example.com',
         createdAt: new Date(),
       }
       this.sendingUser = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         first_name: 'jim',
       }
-      this.existingUser = { _id: ObjectId() }
+      this.existingUser = { _id: new ObjectId() }
       this.UserGetter.promises.getUserByAnyEmail = sinon
         .stub()
         .resolves(this.existingUser)

+ 8 - 5
services/web/test/unit/src/Collaborators/OwnershipTransferHandlerTests.js

@@ -10,10 +10,13 @@ const MODULE_PATH =
 
 describe('OwnershipTransferHandler', function () {
   beforeEach(function () {
-    this.user = { _id: ObjectId(), email: 'owner@example.com' }
-    this.collaborator = { _id: ObjectId(), email: 'collaborator@example.com' }
+    this.user = { _id: new ObjectId(), email: 'owner@example.com' }
+    this.collaborator = {
+      _id: new ObjectId(),
+      email: 'collaborator@example.com',
+    }
     this.project = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'project',
       owner_ref: this.user._id,
       collaberator_refs: [this.collaborator._id],
@@ -205,7 +208,7 @@ describe('OwnershipTransferHandler', function () {
     })
 
     it('should track the change in BigQuery', async function () {
-      const sessionUserId = ObjectId()
+      const sessionUserId = new ObjectId()
       await this.handler.promises.transferOwnership(
         this.project._id,
         this.collaborator._id,
@@ -222,7 +225,7 @@ describe('OwnershipTransferHandler', function () {
     })
 
     it('should write an entry in the audit log', async function () {
-      const sessionUserId = ObjectId()
+      const sessionUserId = new ObjectId()
       await this.handler.promises.transferOwnership(
         this.project._id,
         this.collaborator._id,

+ 1 - 1
services/web/test/unit/src/History/HistoryManagerTests.js

@@ -8,7 +8,7 @@ const MODULE_PATH = '../../../../app/src/Features/History/HistoryManager'
 describe('HistoryManager', function () {
   beforeEach(function () {
     this.user_id = 'user-id-123'
-    this.historyId = ObjectId().toString()
+    this.historyId = new ObjectId().toString()
     this.AuthenticationController = {
       getLoggedInUserId: sinon.stub().returns(this.user_id),
     }

+ 36 - 18
services/web/test/unit/src/Institutions/InstitutionsManagerTests.js

@@ -2,6 +2,7 @@ const SandboxedModule = require('sandboxed-module')
 const path = require('path')
 const sinon = require('sinon')
 const { expect } = require('chai')
+const { ObjectId } = require('mongodb')
 const modulePath = path.join(
   __dirname,
   '../../../../app/src/Features/Institutions/InstitutionsManager'
@@ -16,19 +17,23 @@ describe('InstitutionsManager', function () {
     this.getConfirmedInstitutionAffiliations = sinon.stub()
     this.addAffiliation = sinon.stub().callsArgWith(3, null)
     this.refreshFeatures = sinon.stub().yields()
+    const lapsedUser = {
+      _id: '657300a08a14461b3d1aac3e',
+      features: {},
+    }
     this.users = [
-      { _id: 'lapsed', features: {} },
-      { _id: '1a', features: {} },
-      { _id: '2b', features: {} },
-      { _id: '3c', features: {} },
+      lapsedUser,
+      { _id: '657300a08a14461b3d1aac3f', features: {} },
+      { _id: '657300a08a14461b3d1aac40', features: {} },
+      { _id: '657300a08a14461b3d1aac41', features: {} },
     ]
     this.ssoUsers = [
       {
-        _id: '1a',
+        _id: '657300a08a14461b3d1aac3f',
         samlIdentifiers: [{ providerId: this.institutionId.toString() }],
       },
       {
-        _id: '2b',
+        _id: '657300a08a14461b3d1aac40',
         samlIdentifiers: [
           {
             providerId: this.institutionId.toString(),
@@ -37,7 +42,7 @@ describe('InstitutionsManager', function () {
         ],
       },
       {
-        _id: 'lapsed',
+        _id: '657300a08a14461b3d1aac3e',
         samlIdentifiers: [{ providerId: this.institutionId.toString() }],
         hasEntitlement: true,
       },
@@ -83,12 +88,15 @@ describe('InstitutionsManager', function () {
         }),
       },
     }
-    this.Mongo = { ObjectId: sinon.stub().returnsArg(0) }
+
+    this.Mongo = {
+      ObjectId,
+    }
 
     this.v1Counts = {
       user_ids: this.users.map(user => user._id),
       current_users_count: 3,
-      lapsed_user_ids: ['lapsed'],
+      lapsed_user_ids: [lapsedUser._id],
       entitled_via_sso: 1, // 2 entitled, but 1 lapsed
       with_confirmed_email: 2, // 1 non entitled SSO + 1 email user
     }
@@ -151,8 +159,8 @@ describe('InstitutionsManager', function () {
     beforeEach(function () {
       this.user1Id = '123abc123abc123abc123abc'
       this.user2Id = '456def456def456def456def'
-      this.user3Id = 'trial123abc'
-      this.user4Id = 'group123abc'
+      this.user3Id = '789abd789abd789abd789abd'
+      this.user4Id = '321cba321cba321cba321cba'
       this.affiliations = [
         { user_id: this.user1Id },
         { user_id: this.user2Id },
@@ -164,10 +172,18 @@ describe('InstitutionsManager', function () {
       this.user3 = { _id: this.user3Id }
       this.user4 = { _id: this.user4Id }
 
-      this.UserGetter.getUser.withArgs(this.user1Id).yields(null, this.user1)
-      this.UserGetter.getUser.withArgs(this.user2Id).yields(null, this.user2)
-      this.UserGetter.getUser.withArgs(this.user3Id).yields(null, this.user3)
-      this.UserGetter.getUser.withArgs(this.user4Id).yields(null, this.user4)
+      this.UserGetter.getUser
+        .withArgs(new ObjectId(this.user1Id))
+        .yields(null, this.user1)
+      this.UserGetter.getUser
+        .withArgs(new ObjectId(this.user2Id))
+        .yields(null, this.user2)
+      this.UserGetter.getUser
+        .withArgs(new ObjectId(this.user3Id))
+        .yields(null, this.user3)
+      this.UserGetter.getUser
+        .withArgs(new ObjectId(this.user4Id))
+        .yields(null, this.user4)
 
       this.SubscriptionLocator.getUsersSubscription
         .withArgs(this.user2)
@@ -188,7 +204,9 @@ describe('InstitutionsManager', function () {
           groupPlan: true,
         })
 
-      this.refreshFeatures.withArgs(this.user1Id).yields(null, {}, true)
+      this.refreshFeatures
+        .withArgs(new ObjectId(this.user1Id))
+        .yields(null, {}, true)
       this.getInstitutionAffiliations.yields(null, this.affiliations)
       this.getConfirmedInstitutionAffiliations.yields(null, this.affiliations)
     })
@@ -370,7 +388,7 @@ describe('InstitutionsManager', function () {
     beforeEach(function () {
       this.host = 'mit.edu'.split('').reverse().join('')
       this.stubbedUser1 = {
-        _id: '3131231',
+        _id: '6573014d8a14461b3d1aac3f',
         name: 'bob',
         email: 'hello@world.com',
         emails: [
@@ -393,7 +411,7 @@ describe('InstitutionsManager', function () {
         },
       ]
       this.stubbedUser2 = {
-        _id: '3131232',
+        _id: '6573014d8a14461b3d1aac40',
         name: 'test',
         email: 'hello2@world.com',
         emails: [{ email: 'subb2@mit.edu', reversedHostname: this.host }],

+ 9 - 4
services/web/test/unit/src/Project/FolderStructureBuilderTests.js

@@ -1,17 +1,22 @@
 const { expect } = require('chai')
-const sinon = require('sinon')
 const SandboxedModule = require('sandboxed-module')
+const { ObjectId } = require('mongodb')
 
 const MODULE_PATH =
   '../../../../app/src/Features/Project/FolderStructureBuilder'
-const MOCK_OBJECT_ID = 'MOCK_OBJECT_ID'
+const MOCK_OBJECT_ID = new ObjectId('657306930a1cf28031c358da')
 
 describe('FolderStructureBuilder', function () {
   beforeEach(function () {
-    this.ObjectId = sinon.stub().returns(MOCK_OBJECT_ID)
     this.FolderStructureBuilder = SandboxedModule.require(MODULE_PATH, {
       requires: {
-        mongodb: { ObjectId: this.ObjectId },
+        mongodb: {
+          ObjectId: class {
+            constructor() {
+              return MOCK_OBJECT_ID
+            }
+          },
+        },
       },
     })
   })

+ 5 - 5
services/web/test/unit/src/Project/ProjectCollabratecDetailsTest.js

@@ -25,9 +25,9 @@ const modulePath = Path.join(
 
 describe('ProjectCollabratecDetailsHandler', function () {
   beforeEach(function () {
-    this.projectId = ObjectId('5bea8747c7bba6012fcaceb3')
-    this.userId = ObjectId('5be316a9c7f6aa03802ea8fb')
-    this.userId2 = ObjectId('5c1794b3f0e89b1d1c577eca')
+    this.projectId = new ObjectId('5bea8747c7bba6012fcaceb3')
+    this.userId = new ObjectId('5be316a9c7f6aa03802ea8fb')
+    this.userId2 = new ObjectId('5c1794b3f0e89b1d1c577eca')
     this.ProjectModel = {}
     this.ProjectCollabratecDetailsHandler = SandboxedModule.require(
       modulePath,
@@ -132,10 +132,10 @@ describe('ProjectCollabratecDetailsHandler', function () {
         it('should call find with project and user id', function () {
           return expect(this.ProjectModel.findOne).to.have.been.calledWithMatch(
             {
-              _id: ObjectId(this.projectId),
+              _id: new ObjectId(this.projectId),
               collabratecUsers: {
                 $elemMatch: {
-                  user_id: ObjectId(this.userId),
+                  user_id: new ObjectId(this.userId),
                 },
               },
             }

+ 3 - 3
services/web/test/unit/src/Project/ProjectControllerTests.js

@@ -11,10 +11,10 @@ const MODULE_PATH = path.join(
 
 describe('ProjectController', function () {
   beforeEach(function () {
-    this.project_id = ObjectId('abcdefabcdefabcdefabcdef')
+    this.project_id = new ObjectId('abcdefabcdefabcdefabcdef')
 
     this.user = {
-      _id: ObjectId('123456123456123456123456'),
+      _id: new ObjectId('123456123456123456123456'),
       email: 'test@overleaf.com',
       first_name: 'bjkdsjfk',
       features: {},
@@ -590,7 +590,7 @@ describe('ProjectController', function () {
       this.res.render = (pageName, opts) => {
         expect(this.UserModel.updateOne).to.have.been.calledOnce
         expect(this.UserModel.updateOne.args[0][0]).to.deep.equal({
-          _id: ObjectId(this.user._id),
+          _id: new ObjectId(this.user._id),
         })
         expect(this.UserModel.updateOne.args[0][1].$set.lastActive).to.exist
         done()

+ 8 - 8
services/web/test/unit/src/Project/ProjectDeleterTests.js

@@ -567,7 +567,7 @@ describe('ProjectDeleter', function () {
 
   describe('archiveProject', function () {
     beforeEach(function () {
-      const archived = [ObjectId(this.user._id)]
+      const archived = [new ObjectId(this.user._id)]
       this.ProjectHelper.calculateArchivedArray.returns(archived)
 
       this.ProjectMock.expects('findOne')
@@ -580,7 +580,7 @@ describe('ProjectDeleter', function () {
           { _id: this.project._id },
           {
             $set: { archived },
-            $pull: { trashed: ObjectId(this.user._id) },
+            $pull: { trashed: new ObjectId(this.user._id) },
           }
         )
         .resolves()
@@ -609,7 +609,7 @@ describe('ProjectDeleter', function () {
 
   describe('unarchiveProject', function () {
     beforeEach(function () {
-      const archived = [ObjectId(this.user._id)]
+      const archived = [new ObjectId(this.user._id)]
       this.ProjectHelper.calculateArchivedArray.returns(archived)
 
       this.ProjectMock.expects('findOne')
@@ -645,7 +645,7 @@ describe('ProjectDeleter', function () {
 
   describe('trashProject', function () {
     beforeEach(function () {
-      const archived = [ObjectId(this.user._id)]
+      const archived = [new ObjectId(this.user._id)]
       this.ProjectHelper.calculateArchivedArray.returns(archived)
 
       this.ProjectMock.expects('findOne')
@@ -657,7 +657,7 @@ describe('ProjectDeleter', function () {
         .withArgs(
           { _id: this.project._id },
           {
-            $addToSet: { trashed: ObjectId(this.user._id) },
+            $addToSet: { trashed: new ObjectId(this.user._id) },
             $set: { archived },
           }
         )
@@ -695,7 +695,7 @@ describe('ProjectDeleter', function () {
       this.ProjectMock.expects('updateOne')
         .withArgs(
           { _id: this.project._id },
-          { $pull: { trashed: ObjectId(this.user._id) } }
+          { $pull: { trashed: new ObjectId(this.user._id) } }
         )
         .resolves()
     })
@@ -731,8 +731,8 @@ describe('ProjectDeleter', function () {
 
   describe('undeleteProject', function () {
     beforeEach(function () {
-      this.unknownProjectId = ObjectId()
-      this.purgedProjectId = ObjectId()
+      this.unknownProjectId = new ObjectId()
+      this.purgedProjectId = new ObjectId()
 
       this.deletedProject = {
         _id: 'deleted',

+ 3 - 3
services/web/test/unit/src/Project/ProjectDetailsHandlerTests.js

@@ -10,16 +10,16 @@ const MODULE_PATH = '../../../../app/src/Features/Project/ProjectDetailsHandler'
 describe('ProjectDetailsHandler', function () {
   beforeEach(function () {
     this.user = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       email: 'user@example.com',
       features: 'mock-features',
     }
     this.collaborator = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       email: 'collaborator@example.com',
     }
     this.project = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'project',
       description: 'this is a great project',
       something: 'should not exist',

+ 21 - 21
services/web/test/unit/src/Project/ProjectEntityMongoUpdateHandlerTests.js

@@ -13,7 +13,7 @@ const MODULE_PATH =
 describe('ProjectEntityMongoUpdateHandler', function () {
   beforeEach(function () {
     this.doc = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'test-doc.txt',
       lines: ['hello', 'world'],
       rev: 1234,
@@ -23,7 +23,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
       fileSystem: '/test-doc.txt',
     }
     this.file = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'something.jpg',
       linkedFileData: { provider: 'url' },
       hash: 'some-hash',
@@ -32,18 +32,18 @@ describe('ProjectEntityMongoUpdateHandler', function () {
       fileSystem: '/something.png',
       mongo: 'rootFolder.0.fileRefs.0',
     }
-    this.subfolder = { _id: ObjectId(), name: 'test-subfolder' }
+    this.subfolder = { _id: new ObjectId(), name: 'test-subfolder' }
     this.subfolderPath = {
       fileSystem: '/test-folder/test-subfolder',
       mongo: 'rootFolder.0.folders.0.folders.0',
     }
-    this.notSubfolder = { _id: ObjectId(), name: 'test-folder-2' }
+    this.notSubfolder = { _id: new ObjectId(), name: 'test-folder-2' }
     this.notSubfolderPath = {
       fileSystem: '/test-folder-2/test-subfolder',
       mongo: 'rootFolder.0.folders.0.folders.0',
     }
     this.folder = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'test-folder',
       folders: [this.subfolder],
     }
@@ -52,7 +52,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
       mongo: 'rootFolder.0.folders.0',
     }
     this.rootFolder = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       folders: [this.folder],
       docs: [this.doc],
       fileRefs: [this.file],
@@ -62,7 +62,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
       mongo: 'rootFolder.0',
     }
     this.project = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'project name',
       rootFolder: [this.rootFolder],
     }
@@ -221,7 +221,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
   describe('addDoc', function () {
     beforeEach(async function () {
-      const doc = { _id: ObjectId(), name: 'other.txt' }
+      const doc = { _id: new ObjectId(), name: 'other.txt' }
       this.ProjectMock.expects('findOneAndUpdate')
         .withArgs(
           {
@@ -261,7 +261,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
   describe('addFile', function () {
     beforeEach(function () {
-      this.newFile = { _id: ObjectId(), name: 'picture.jpg' }
+      this.newFile = { _id: new ObjectId(), name: 'picture.jpg' }
       this.ProjectMock.expects('findOneAndUpdate')
         .withArgs(
           {
@@ -329,7 +329,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
     beforeEach(async function () {
       const folderName = 'New folder'
       this.FolderModel.withArgs({ name: folderName }).returns({
-        _id: ObjectId(),
+        _id: new ObjectId(),
         name: folderName,
       })
       this.ProjectMock.expects('findOneAndUpdate')
@@ -364,7 +364,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
   describe('replaceFileWithNew', function () {
     beforeEach(async function () {
       const newFile = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         name: 'some-other-file.png',
         linkedFileData: { some: 'data' },
         hash: 'some-hash',
@@ -460,7 +460,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
     describe('when the path is a new folder at the top level', function () {
       beforeEach(async function () {
-        this.newFolder = { _id: ObjectId(), name: 'new-folder' }
+        this.newFolder = { _id: new ObjectId(), name: 'new-folder' }
         this.FolderModel.returns(this.newFolder)
         this.exactCaseMatch = false
         this.ProjectMock.expects('findOneAndUpdate')
@@ -504,7 +504,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
     describe('adding a subfolder', function () {
       beforeEach(async function () {
-        this.newFolder = { _id: ObjectId(), name: 'new-folder' }
+        this.newFolder = { _id: new ObjectId(), name: 'new-folder' }
         this.FolderModel.returns(this.newFolder)
         this.ProjectMock.expects('findOneAndUpdate')
           .withArgs(
@@ -548,12 +548,12 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
     describe('when mutliple folders are missing', async function () {
       beforeEach(function () {
-        this.folder1 = { _id: ObjectId(), name: 'folder1' }
+        this.folder1 = { _id: new ObjectId(), name: 'folder1' }
         this.folder1Path = {
           fileSystem: '/test-folder/folder1',
           mongo: 'rootFolder.0.folders.0.folders.0',
         }
-        this.folder2 = { _id: ObjectId(), name: 'folder2' }
+        this.folder2 = { _id: new ObjectId(), name: 'folder2' }
         this.folder2Path = {
           fileSystem: '/test-folder/folder1/folder2',
           mongo: 'rootFolder.0.folders.0.folders.0.folders.0',
@@ -865,7 +865,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
     describe('updating the project', function () {
       describe('when the parent folder is given', function () {
         beforeEach(function () {
-          this.newFile = { _id: ObjectId(), name: 'new file.png' }
+          this.newFile = { _id: new ObjectId(), name: 'new file.png' }
           this.ProjectMock.expects('findOneAndUpdate')
             .withArgs(
               {
@@ -927,7 +927,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
         })
 
         it('should error if element name contains invalid characters', async function () {
-          const file = { _id: ObjectId(), name: 'something*bad' }
+          const file = { _id: new ObjectId(), name: 'something*bad' }
           await expect(
             this.subject.promises._putElement(
               this.project,
@@ -940,7 +940,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
         it('should error if element name is too long', async function () {
           const file = {
-            _id: ObjectId(),
+            _id: new ObjectId(),
             name: 'long-'.repeat(1000) + 'something',
           }
           await expect(
@@ -955,7 +955,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
         it('should error if the folder name is too long', async function () {
           const file = {
-            _id: ObjectId(),
+            _id: new ObjectId(),
             name: 'something',
           }
           this.ProjectLocator.promises.findElement
@@ -980,7 +980,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
         ;['file', 'doc', 'folder'].forEach(entityType => {
           it(`should error if a ${entityType} already exists with the same name`, async function () {
             const file = {
-              _id: ObjectId(),
+              _id: new ObjectId(),
               name: this[entityType].name,
             }
             await expect(
@@ -998,7 +998,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
 
     describe('when the parent folder is not given', function () {
       it('should default to root folder insert', async function () {
-        this.newFile = { _id: ObjectId(), name: 'new file.png' }
+        this.newFile = { _id: new ObjectId(), name: 'new file.png' }
         this.ProjectMock.expects('findOneAndUpdate')
           .withArgs(
             { _id: this.project._id, 'rootFolder.0': { $exists: true } },

+ 4 - 4
services/web/test/unit/src/Project/ProjectEntityUpdateHandlerTests.js

@@ -182,7 +182,7 @@ describe('ProjectEntityUpdateHandler', function () {
       this.ranges = { mock: 'ranges' }
       this.lastUpdatedAt = new Date().getTime()
       this.lastUpdatedBy = 'fake-last-updater-id'
-      this.parentFolder = { _id: ObjectId() }
+      this.parentFolder = { _id: new ObjectId() }
       this.DocstoreManager.isDocDeleted.yields(null, false)
       this.ProjectGetter.getProject.yields(null, this.project)
       this.ProjectLocator.findElement.yields(
@@ -1011,7 +1011,7 @@ describe('ProjectEntityUpdateHandler', function () {
     describe('updating an existing file', function () {
       beforeEach(function () {
         this.existingFile = { _id: fileId, name: this.fileName, rev: 1 }
-        this.newFile = { _id: ObjectId(), name: this.fileName, rev: 3 }
+        this.newFile = { _id: new ObjectId(), name: this.fileName, rev: 3 }
         this.folder = { _id: folderId, fileRefs: [this.existingFile], docs: [] }
         this.ProjectLocator.findElement.yields(null, this.folder)
         this.newProject = 'new-project-stub'
@@ -2634,7 +2634,7 @@ describe('ProjectEntityUpdateHandler', function () {
   describe('_cleanUpDoc', function () {
     beforeEach(function () {
       this.doc = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         name: 'test.tex',
       }
       this.path = '/path/to/doc'
@@ -2679,7 +2679,7 @@ describe('ProjectEntityUpdateHandler', function () {
 
     describe('when the doc is not the root doc', function () {
       beforeEach(function () {
-        this.project.rootDoc_id = ObjectId()
+        this.project.rootDoc_id = new ObjectId()
         this.ProjectEntityUpdateHandler._cleanUpDoc(
           this.project,
           this.doc,

+ 35 - 31
services/web/test/unit/src/Project/ProjectHelperTests.js

@@ -47,8 +47,8 @@ describe('ProjectHelper', function () {
     describe('project.archived being an array', function () {
       it('returns true if user id is found', function () {
         this.project.archived = [
-          ObjectId('588f3ddae8ebc1bac07c9fa4'),
-          ObjectId('5c41deb2b4ca500153340809'),
+          new ObjectId('588f3ddae8ebc1bac07c9fa4'),
+          new ObjectId('5c41deb2b4ca500153340809'),
         ]
         expect(
           this.ProjectHelper.isArchived(this.project, this.user._id)
@@ -76,8 +76,8 @@ describe('ProjectHelper', function () {
   describe('isTrashed', function () {
     it('returns true if user id is found', function () {
       this.project.trashed = [
-        ObjectId('588f3ddae8ebc1bac07c9fa4'),
-        ObjectId('5c41deb2b4ca500153340809'),
+        new ObjectId('588f3ddae8ebc1bac07c9fa4'),
+        new ObjectId('5c41deb2b4ca500153340809'),
       ]
       expect(
         this.ProjectHelper.isTrashed(this.project, this.user._id)
@@ -107,17 +107,17 @@ describe('ProjectHelper', function () {
         const project = { archived: [] }
         const result = this.ProjectHelper.calculateArchivedArray(
           project,
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
           'ARCHIVE'
         )
-        expect(result).to.deep.equal([ObjectId('5c922599cdb09e014aa7d499')])
+        expect(result).to.deep.equal([new ObjectId('5c922599cdb09e014aa7d499')])
       })
 
       it('returns an array without the current user id when unarchiving', function () {
-        const project = { archived: [ObjectId('5c922599cdb09e014aa7d499')] }
+        const project = { archived: [new ObjectId('5c922599cdb09e014aa7d499')] }
         const result = this.ProjectHelper.calculateArchivedArray(
           project,
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
           'UNARCHIVE'
         )
         expect(result).to.deep.equal([])
@@ -130,11 +130,13 @@ describe('ProjectHelper', function () {
           archived: true,
           owner_ref: this.user._id,
           collaberator_refs: [
-            ObjectId('4f2cfb341eb5855a5b000f8b'),
-            ObjectId('5c45f3bd425ead01488675aa'),
+            new ObjectId('4f2cfb341eb5855a5b000f8b'),
+            new ObjectId('5c45f3bd425ead01488675aa'),
+          ],
+          readOnly_refs: [new ObjectId('5c92243fcdb09e014aa7d487')],
+          tokenAccessReadAndWrite_refs: [
+            new ObjectId('5c922599cdb09e014aa7d499'),
           ],
-          readOnly_refs: [ObjectId('5c92243fcdb09e014aa7d487')],
-          tokenAccessReadAndWrite_refs: [ObjectId('5c922599cdb09e014aa7d499')],
           tokenAccessReadOnly_refs: [],
         }
 
@@ -145,10 +147,10 @@ describe('ProjectHelper', function () {
         )
         expect(result).to.deep.equal([
           this.user._id,
-          ObjectId('4f2cfb341eb5855a5b000f8b'),
-          ObjectId('5c45f3bd425ead01488675aa'),
-          ObjectId('5c92243fcdb09e014aa7d487'),
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('4f2cfb341eb5855a5b000f8b'),
+          new ObjectId('5c45f3bd425ead01488675aa'),
+          new ObjectId('5c92243fcdb09e014aa7d487'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
         ])
       })
 
@@ -157,12 +159,14 @@ describe('ProjectHelper', function () {
           archived: true,
           owner_ref: this.user._id,
           collaberator_refs: [
-            ObjectId('4f2cfb341eb5855a5b000f8b'),
-            ObjectId('5c45f3bd425ead01488675aa'),
-            ObjectId('5c922599cdb09e014aa7d499'),
+            new ObjectId('4f2cfb341eb5855a5b000f8b'),
+            new ObjectId('5c45f3bd425ead01488675aa'),
+            new ObjectId('5c922599cdb09e014aa7d499'),
+          ],
+          readOnly_refs: [new ObjectId('5c92243fcdb09e014aa7d487')],
+          tokenAccessReadAndWrite_refs: [
+            new ObjectId('5c922599cdb09e014aa7d499'),
           ],
-          readOnly_refs: [ObjectId('5c92243fcdb09e014aa7d487')],
-          tokenAccessReadAndWrite_refs: [ObjectId('5c922599cdb09e014aa7d499')],
           tokenAccessReadOnly_refs: [],
         }
 
@@ -172,10 +176,10 @@ describe('ProjectHelper', function () {
           'UNARCHIVE'
         )
         expect(result).to.deep.equal([
-          ObjectId('4f2cfb341eb5855a5b000f8b'),
-          ObjectId('5c45f3bd425ead01488675aa'),
-          ObjectId('5c922599cdb09e014aa7d499'),
-          ObjectId('5c92243fcdb09e014aa7d487'),
+          new ObjectId('4f2cfb341eb5855a5b000f8b'),
+          new ObjectId('5c45f3bd425ead01488675aa'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c92243fcdb09e014aa7d487'),
         ])
       })
     })
@@ -185,17 +189,17 @@ describe('ProjectHelper', function () {
         const project = { archived: false }
         const result = this.ProjectHelper.calculateArchivedArray(
           project,
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
           'ARCHIVE'
         )
-        expect(result).to.deep.equal([ObjectId('5c922599cdb09e014aa7d499')])
+        expect(result).to.deep.equal([new ObjectId('5c922599cdb09e014aa7d499')])
       })
 
       it('returns an empty array when unarchiving', function () {
         const project = { archived: false }
         const result = this.ProjectHelper.calculateArchivedArray(
           project,
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
           'UNARCHIVE'
         )
         expect(result).to.deep.equal([])
@@ -207,17 +211,17 @@ describe('ProjectHelper', function () {
         const project = { archived: undefined }
         const result = this.ProjectHelper.calculateArchivedArray(
           project,
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
           'ARCHIVE'
         )
-        expect(result).to.deep.equal([ObjectId('5c922599cdb09e014aa7d499')])
+        expect(result).to.deep.equal([new ObjectId('5c922599cdb09e014aa7d499')])
       })
 
       it('returns an empty array when unarchiving', function () {
         const project = { archived: undefined }
         const result = this.ProjectHelper.calculateArchivedArray(
           project,
-          ObjectId('5c922599cdb09e014aa7d499'),
+          new ObjectId('5c922599cdb09e014aa7d499'),
           'UNARCHIVE'
         )
         expect(result).to.deep.equal([])

+ 2 - 2
services/web/test/unit/src/Project/ProjectListControllerTests.js

@@ -12,10 +12,10 @@ const MODULE_PATH = path.join(
 
 describe('ProjectListController', function () {
   beforeEach(function () {
-    this.project_id = ObjectId('abcdefabcdefabcdefabcdef')
+    this.project_id = new ObjectId('abcdefabcdefabcdefabcdef')
 
     this.user = {
-      _id: ObjectId('123456123456123456123456'),
+      _id: new ObjectId('123456123456123456123456'),
       email: 'test@overleaf.com',
       first_name: 'bjkdsjfk',
       features: {},

+ 3 - 3
services/web/test/unit/src/SplitTests/SplitTestHandlerTests.js

@@ -79,7 +79,7 @@ describe('SplitTestHandler', function () {
   describe('with an existing user', function () {
     beforeEach(async function () {
       this.user = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         splitTests: {
           'active-test': [
             {
@@ -149,7 +149,7 @@ describe('SplitTestHandler', function () {
 
   describe('with an non-existent user', function () {
     beforeEach(async function () {
-      const unknownUserId = ObjectId()
+      const unknownUserId = new ObjectId()
       this.assignments =
         await this.SplitTestHandler.promises.getActiveAssignmentsForUser(
           unknownUserId
@@ -163,7 +163,7 @@ describe('SplitTestHandler', function () {
 
   describe('with a user without assignments', function () {
     beforeEach(async function () {
-      this.user = { _id: ObjectId() }
+      this.user = { _id: new ObjectId() }
       this.UserGetter.promises.getUser
         .withArgs(this.user._id)
         .resolves(this.user)

+ 1 - 1
services/web/test/unit/src/Subscription/GroupSSOHandlerTests.js

@@ -11,7 +11,7 @@ describe('GroupSSOHandler', function () {
   beforeEach(function () {
     this.user = { _id: new ObjectId(), enrollment: { sso: [] } }
     this.subscription = {
-      _id: ObjectId().toString(),
+      _id: new ObjectId().toString(),
       admin_id: new ObjectId(),
       member_ids: [this.user._id],
     }

+ 9 - 9
services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js

@@ -181,12 +181,12 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId
       )
       const query = {
-        _id: ObjectId(this.subscription._id),
+        _id: new ObjectId(this.subscription._id),
         customAccount: true,
       }
       const update = {
-        $set: { admin_id: ObjectId(this.otherUserId) },
-        $addToSet: { manager_ids: ObjectId(this.otherUserId) },
+        $set: { admin_id: new ObjectId(this.otherUserId) },
+        $addToSet: { manager_ids: new ObjectId(this.otherUserId) },
       }
       this.SubscriptionModel.updateOne.should.have.been.calledOnce
       this.SubscriptionModel.updateOne.should.have.been.calledWith(
@@ -201,13 +201,13 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId
       )
       const query = {
-        _id: ObjectId(this.subscription._id),
+        _id: new ObjectId(this.subscription._id),
         customAccount: true,
       }
       const update = {
         $set: {
-          admin_id: ObjectId(this.otherUserId),
-          manager_ids: [ObjectId(this.otherUserId)],
+          admin_id: new ObjectId(this.otherUserId),
+          manager_ids: [new ObjectId(this.otherUserId)],
         },
       }
       this.SubscriptionModel.updateOne.should.have.been.calledOnce
@@ -710,10 +710,10 @@ describe('SubscriptionUpdater', function () {
   describe('deleteSubscription', function () {
     beforeEach(async function () {
       this.subscription = {
-        _id: ObjectId().toString(),
+        _id: new ObjectId().toString(),
         mock: 'subscription',
-        admin_id: ObjectId(),
-        member_ids: [ObjectId(), ObjectId(), ObjectId()],
+        admin_id: new ObjectId(),
+        member_ids: [new ObjectId(), new ObjectId(), new ObjectId()],
       }
       await this.SubscriptionUpdater.promises.deleteSubscription(
         this.subscription,

+ 4 - 4
services/web/test/unit/src/Tags/TagsHandlerTests.js

@@ -10,13 +10,13 @@ const modulePath = require('path').join(
 
 describe('TagsHandler', function () {
   beforeEach(function () {
-    this.userId = ObjectId().toString()
+    this.userId = new ObjectId().toString()
     this.callback = sinon.stub()
 
     this.tag = { user_id: this.userId, name: 'some name', color: '#3399CC' }
-    this.tagId = ObjectId().toString()
-    this.projectId = ObjectId().toString()
-    this.projectIds = [ObjectId().toString(), ObjectId().toString()]
+    this.tagId = new ObjectId().toString()
+    this.projectId = new ObjectId().toString()
+    this.projectIds = [new ObjectId().toString(), new ObjectId().toString()]
 
     this.mongodb = { ObjectId }
     this.TagMock = sinon.mock(Tag)

+ 9 - 9
services/web/test/unit/src/ThirdPartyDataStore/TpdsControllerTests.js

@@ -12,9 +12,9 @@ const MODULE_PATH =
 describe('TpdsController', function () {
   beforeEach(function () {
     this.metadata = {
-      projectId: ObjectId(),
-      entityId: ObjectId(),
-      folderId: ObjectId(),
+      projectId: new ObjectId(),
+      entityId: new ObjectId(),
+      folderId: new ObjectId(),
       entityType: 'doc',
       rev: 2,
     }
@@ -46,7 +46,7 @@ describe('TpdsController', function () {
       conflict: sinon.stub(),
     }
 
-    this.newProject = { _id: ObjectId() }
+    this.newProject = { _id: new ObjectId() }
     this.ProjectCreationHandler = {
       promises: { createBlankProject: sinon.stub().resolves(this.newProject) },
     }
@@ -291,10 +291,10 @@ describe('TpdsController', function () {
 
     it("creates a folder if it doesn't exist", function (done) {
       const metadata = {
-        folderId: ObjectId(),
-        projectId: ObjectId(),
+        folderId: new ObjectId(),
+        projectId: new ObjectId(),
         path: '/def/ghi.txt',
-        parentFolderId: ObjectId(),
+        parentFolderId: new ObjectId(),
       }
       this.TpdsUpdateHandler.promises.createFolder.resolves(metadata)
       this.res.json.callsFake(body => {
@@ -311,8 +311,8 @@ describe('TpdsController', function () {
 
     it('supports top level folders', function (done) {
       const metadata = {
-        folderId: ObjectId(),
-        projectId: ObjectId(),
+        folderId: new ObjectId(),
+        projectId: new ObjectId(),
         path: '/',
         parentFolderId: null,
       }

+ 2 - 2
services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js

@@ -9,8 +9,8 @@ const MODULE_PATH =
 
 describe('TpdsProjectFlusher', function () {
   beforeEach(function () {
-    this.project = { _id: ObjectId() }
-    this.folder = { _id: ObjectId() }
+    this.project = { _id: new ObjectId() }
+    this.folder = { _id: new ObjectId() }
     this.docs = {
       '/doc/one': {
         _id: 'mock-doc-1',

+ 4 - 4
services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateHandlerTests.js

@@ -38,8 +38,8 @@ describe('TpdsUpdateHandler', function () {
     this.update = {}
     this.folderPath = '/some/folder'
     this.folder = {
-      _id: ObjectId(),
-      parentFolder_id: ObjectId(),
+      _id: new ObjectId(),
+      parentFolder_id: new ObjectId(),
     }
 
     this.CooldownManager = {
@@ -125,7 +125,7 @@ describe('TpdsUpdateHandler', function () {
     describe('byId', function () {
       describe('with no matching project', function () {
         beforeEach(function () {
-          this.projectId = ObjectId().toString()
+          this.projectId = new ObjectId().toString()
         })
         receiveUpdateById()
         expectProjectNotCreated()
@@ -222,7 +222,7 @@ describe('TpdsUpdateHandler', function () {
     describe('byId', function () {
       describe('with no matching project', function () {
         beforeEach(function () {
-          this.projectId = ObjectId().toString()
+          this.projectId = new ObjectId().toString()
         })
         receiveFileDeleteById()
         expectDeleteNotProcessed()

+ 3 - 3
services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSenderTests.js

@@ -10,9 +10,9 @@ const modulePath = path.join(
 )
 
 const projectId = 'project_id_here'
-const userId = ObjectId()
-const readOnlyRef = ObjectId()
-const collaberatorRef = ObjectId()
+const userId = new ObjectId()
+const readOnlyRef = new ObjectId()
+const collaberatorRef = new ObjectId()
 const projectName = 'project_name_here'
 
 const thirdPartyDataStoreApiUrl = 'http://third-party-json-store.herokuapp.com'

+ 3 - 3
services/web/test/unit/src/ThirdPartyDataStore/UpdateMergerTests.js

@@ -48,17 +48,17 @@ describe('UpdateMerger :', function () {
     }
 
     this.doc = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       rev: 2,
     }
 
     this.file = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       rev: 6,
     }
 
     this.folder = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
     }
 
     this.EditorController = {

+ 2 - 2
services/web/test/unit/src/TokenAccess/TokenAccessControllerTests.js

@@ -12,9 +12,9 @@ const MODULE_PATH =
 describe('TokenAccessController', function () {
   beforeEach(function () {
     this.token = 'abc123'
-    this.user = { _id: ObjectId() }
+    this.user = { _id: new ObjectId() }
     this.project = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       tokenAccessReadAndWrite_refs: [],
       tokenAccessReadOnly_refs: [],
     }

+ 3 - 3
services/web/test/unit/src/TokenAccess/TokenAccessHandlerTests.js

@@ -11,13 +11,13 @@ const { ObjectId } = require('mongodb')
 describe('TokenAccessHandler', function () {
   beforeEach(function () {
     this.token = 'abcdefabcdef'
-    this.projectId = ObjectId()
+    this.projectId = new ObjectId()
     this.project = {
       _id: this.projectId,
       publicAccesLevel: 'tokenBased',
-      owner_ref: ObjectId(),
+      owner_ref: new ObjectId(),
     }
-    this.userId = ObjectId()
+    this.userId = new ObjectId()
     this.req = {}
     this.TokenAccessHandler = SandboxedModule.require(modulePath, {
       requires: {

+ 1 - 1
services/web/test/unit/src/User/SAMLIdentityManagerTests.js

@@ -370,7 +370,7 @@ describe('SAMLIdentityManager', function () {
             expect(
               this.UserGetter.promises.getUser
             ).to.have.been.calledWithMatch({
-              _id: ObjectId('6005c75b12cbcaf771f4a105'),
+              _id: new ObjectId('6005c75b12cbcaf771f4a105'),
               'samlIdentifiers.providerId': '123456',
             })
             expect(error).to.be.instanceof(Errors.SAMLAlreadyLinkedError)

+ 2 - 2
services/web/test/unit/src/User/UserAuditLogHandlerTests.js

@@ -8,8 +8,8 @@ const MODULE_PATH = '../../../../app/src/Features/User/UserAuditLogHandler'
 
 describe('UserAuditLogHandler', function () {
   beforeEach(function () {
-    this.userId = ObjectId()
-    this.initiatorId = ObjectId()
+    this.userId = new ObjectId()
+    this.initiatorId = new ObjectId()
     this.action = {
       operation: 'clear-sessions',
       initiatorId: this.initiatorId,

+ 2 - 2
services/web/test/unit/src/User/UserDeleterTests.js

@@ -14,7 +14,7 @@ describe('UserDeleter', function () {
   beforeEach(function () {
     tk.freeze(Date.now())
 
-    this.userId = ObjectId()
+    this.userId = new ObjectId()
 
     this.UserMock = sinon.mock(User)
     this.DeletedUserMock = sinon.mock(DeletedUser)
@@ -289,7 +289,7 @@ describe('UserDeleter', function () {
       describe('when a user and IP address are specified', function () {
         beforeEach(function () {
           this.ipAddress = '1.2.3.4'
-          this.deleterId = ObjectId()
+          this.deleterId = new ObjectId()
 
           this.deletedUser.deleterData.deleterIpAddress = this.ipAddress
           this.deletedUser.deleterData.deleterId = this.deleterId

+ 7 - 7
services/web/test/unit/src/User/UserInfoControllerTests.js

@@ -32,8 +32,8 @@ describe('UserInfoController', function () {
   describe('getPersonalInfo', function () {
     describe('when the user exists with sharelatex id', function () {
       beforeEach(function () {
-        this.user_id = ObjectId().toString()
-        this.user = { _id: ObjectId(this.user_id) }
+        this.user_id = new ObjectId().toString()
+        this.user = { _id: new ObjectId(this.user_id) }
         this.req.params = { user_id: this.user_id }
         this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, this.user)
         this.UserInfoController.sendFormattedPersonalInfo = sinon.stub()
@@ -43,7 +43,7 @@ describe('UserInfoController', function () {
       it('should look up the user in the database', function () {
         this.UserGetter.getUser
           .calledWith(
-            { _id: ObjectId(this.user_id) },
+            { _id: new ObjectId(this.user_id) },
             { _id: true, first_name: true, last_name: true, email: true }
           )
           .should.equal(true)
@@ -54,7 +54,7 @@ describe('UserInfoController', function () {
       beforeEach(function () {
         this.user_id = 12345
         this.user = {
-          _id: ObjectId(),
+          _id: new ObjectId(),
           overleaf: {
             id: this.user_id,
           },
@@ -76,7 +76,7 @@ describe('UserInfoController', function () {
 
     describe('when the user does not exist', function () {
       beforeEach(function () {
-        this.user_id = ObjectId().toString()
+        this.user_id = new ObjectId().toString()
         this.req.params = { user_id: this.user_id }
         this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, null)
         this.UserInfoController.getPersonalInfo(this.req, this.res, this.next)
@@ -104,7 +104,7 @@ describe('UserInfoController', function () {
   describe('sendFormattedPersonalInfo', function () {
     beforeEach(function () {
       this.user = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         first_name: 'Douglas',
         last_name: 'Adams',
         email: 'doug@sharelatex.com',
@@ -126,7 +126,7 @@ describe('UserInfoController', function () {
   describe('formatPersonalInfo', function () {
     it('should return the correctly formatted data', function () {
       this.user = {
-        _id: ObjectId(),
+        _id: new ObjectId(),
         first_name: 'Douglas',
         last_name: 'Adams',
         email: 'doug@sharelatex.com',

+ 2 - 4
services/web/test/unit/src/User/UserUpdaterTests.js

@@ -18,7 +18,7 @@ describe('UserUpdater', function () {
     tk.freeze(Date.now())
 
     this.user = {
-      _id: ObjectId(),
+      _id: new ObjectId(),
       name: 'bob',
       email: 'hello@world.com',
       emails: [{ email: 'hello@world.com' }],
@@ -31,9 +31,7 @@ describe('UserUpdater', function () {
     }
     this.mongodb = {
       db: this.db,
-      ObjectId(id) {
-        return id
-      },
+      ObjectId,
     }
 
     this.UserGetter = {

+ 7 - 7
services/web/test/unit/src/UserMembership/UserMembershipHandlerTests.js

@@ -27,15 +27,15 @@ const {
 
 describe('UserMembershipHandler', function () {
   beforeEach(function () {
-    this.user = { _id: ObjectId() }
-    this.newUser = { _id: ObjectId(), email: 'new-user-email@foo.bar' }
-    this.fakeEntityId = ObjectId()
+    this.user = { _id: new ObjectId() }
+    this.newUser = { _id: new ObjectId(), email: 'new-user-email@foo.bar' }
+    this.fakeEntityId = new ObjectId()
     this.subscription = {
       _id: 'mock-subscription-id',
       groupPlan: true,
       membersLimit: 10,
-      member_ids: [ObjectId(), ObjectId()],
-      manager_ids: [ObjectId()],
+      member_ids: [new ObjectId(), new ObjectId()],
+      manager_ids: [new ObjectId()],
       invited_emails: ['mock-email-1@foo.com'],
       teamInvites: [{ email: 'mock-email-1@bar.com' }],
       update: sinon.stub().yields(null),
@@ -43,13 +43,13 @@ describe('UserMembershipHandler', function () {
     this.institution = {
       _id: 'mock-institution-id',
       v1Id: 123,
-      managerIds: [ObjectId(), ObjectId(), ObjectId()],
+      managerIds: [new ObjectId(), new ObjectId(), new ObjectId()],
       updateOne: sinon.stub().yields(null),
     }
     this.publisher = {
       _id: 'mock-publisher-id',
       slug: 'slug',
-      managerIds: [ObjectId(), ObjectId()],
+      managerIds: [new ObjectId(), new ObjectId()],
       updateOne: sinon.stub().yields(null),
     }
 

+ 2 - 2
services/web/test/unit/src/UserMembership/UserMembershipViewModelTests.js

@@ -109,7 +109,7 @@ describe('UserMembershipViewModel', function () {
     it('build user id', function (done) {
       this.UserGetter.getUser.yields(null, this.user)
       return this.UserMembershipViewModel.buildAsync(
-        ObjectId(),
+        new ObjectId(),
         (error, viewModel) => {
           expect(error).not.to.exist
           assertNotCalled(this.UserMembershipViewModel.build)
@@ -127,7 +127,7 @@ describe('UserMembershipViewModel', function () {
 
     it('build user id with error', function (done) {
       this.UserGetter.getUser.yields(new Error('nope'))
-      const userId = ObjectId()
+      const userId = new ObjectId()
       return this.UserMembershipViewModel.buildAsync(
         userId,
         (error, viewModel) => {

+ 1 - 1
services/web/test/unit/src/UserMembership/UserMembershipsHandlerTests.js

@@ -19,7 +19,7 @@ const SandboxedModule = require('sandboxed-module')
 
 describe('UserMembershipsHandler', function () {
   beforeEach(function () {
-    this.user = { _id: ObjectId() }
+    this.user = { _id: new ObjectId() }
 
     this.Institution = { updateMany: sinon.stub().yields(null) }
     this.Subscription = { updateMany: sinon.stub().yields(null) }