From 90c86cd1e915af28a03e232ab48e7f3e4b5488f0 Mon Sep 17 00:00:00 2001 From: Jessica Lawshe <5312836+lawshe@users.noreply.github.com> Date: Thu, 11 Apr 2024 08:27:17 -0500 Subject: [PATCH] Merge pull request #17841 from overleaf/jel-lint-populate [web] Add linting rule for mongoose `populate` GitOrigin-RevId: 625b2b5f9db4e88ce0d629752f083b8be71c7766 --- services/web/.eslintrc | 23 +++++++++++++++---- .../CollaboratorsEmailHandler.js | 1 + .../Subscription/SubscriptionLocator.js | 2 ++ .../Subscription/TeamInvitesController.js | 1 + .../acceptance/src/helpers/Subscription.js | 1 + 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/services/web/.eslintrc b/services/web/.eslintrc index eb410d0ce3..1dcae0df5f 100644 --- a/services/web/.eslintrc +++ b/services/web/.eslintrc @@ -93,22 +93,35 @@ // do not allow importing of devDependencies. "devDependencies": false }], - - // do not allow node-fetch in backend code "no-restricted-syntax": [ "error", + // do not allow node-fetch in backend code { "selector": "CallExpression[callee.name='require'] > .arguments[value='node-fetch']", "message": "Requiring node-fetch is not allowed in production services, please use fetch-utils." + }, + // mongoose populate must set fields to populate + { + "selector": "CallExpression[callee.property.name='populate'][arguments.length<2]", + "message": "Populate without a second argument returns the whole document. Use populate('field',['prop1','prop2']) instead" + }, + // 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" } ] } }, { - // Backend + backend tests specific rules - "files": ["**/app/src/**/*.js", "app.js", "**/test/**/*.*", "**/scripts/*.*"], + // Backend tests and scripts specific rules + "files": ["**/test/**/*.*", "**/scripts/*.*"], "rules": { - // do not allow node-fetch in backend code "no-restricted-syntax": [ "error", // Require `new` when constructing ObjectId (For mongo + mongoose upgrade) diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsEmailHandler.js b/services/web/app/src/Features/Collaborators/CollaboratorsEmailHandler.js index 5e9cdcb243..226a775134 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsEmailHandler.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsEmailHandler.js @@ -15,6 +15,7 @@ const CollaboratorsEmailHandler = { }, async notifyUserOfProjectInvite(projectId, email, invite, sendingUser) { + // eslint-disable-next-line no-restricted-syntax const project = await Project.findOne({ _id: projectId }) .select('name owner_ref') .populate('owner_ref') diff --git a/services/web/app/src/Features/Subscription/SubscriptionLocator.js b/services/web/app/src/Features/Subscription/SubscriptionLocator.js index 5953c91427..4a4d4cb1f2 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionLocator.js +++ b/services/web/app/src/Features/Subscription/SubscriptionLocator.js @@ -23,6 +23,7 @@ const SubscriptionLocator = { }, async getManagedGroupSubscriptions(userOrId) { + // eslint-disable-next-line no-restricted-syntax return await Subscription.find({ manager_ids: userOrId, groupPlan: true, @@ -33,6 +34,7 @@ const SubscriptionLocator = { async getMemberSubscriptions(userOrId) { const userId = SubscriptionLocator._getUserId(userOrId) + // eslint-disable-next-line no-restricted-syntax return await Subscription.find({ member_ids: userId }) .populate('admin_id') .exec() diff --git a/services/web/app/src/Features/Subscription/TeamInvitesController.js b/services/web/app/src/Features/Subscription/TeamInvitesController.js index 4a8c5e379f..3ec7388ef8 100644 --- a/services/web/app/src/Features/Subscription/TeamInvitesController.js +++ b/services/web/app/src/Features/Subscription/TeamInvitesController.js @@ -90,6 +90,7 @@ async function viewInvite(req, res, next) { if (subscription?.groupPolicy) { if (!subscription.populated('groupPolicy')) { + // eslint-disable-next-line no-restricted-syntax await subscription.populate('groupPolicy') } diff --git a/services/web/test/acceptance/src/helpers/Subscription.js b/services/web/test/acceptance/src/helpers/Subscription.js index 03f8c8a7c5..602ae1feec 100644 --- a/services/web/test/acceptance/src/helpers/Subscription.js +++ b/services/web/test/acceptance/src/helpers/Subscription.js @@ -46,6 +46,7 @@ class PromisifiedSubscription { } async getWithGroupPolicy() { + // eslint-disable-next-line no-restricted-syntax return await SubscriptionModel.findById(this._id) .populate('groupPolicy') .exec()