From 06b8415cd68057f312827a112a342ce2ef17f26d Mon Sep 17 00:00:00 2001 From: Nishan Date: Tue, 13 Feb 2024 16:39:50 +0530 Subject: [PATCH 1/8] feat: Add linting rule to recursively check for Prisma includes using only 'true' --- .../eslint-plugin/src/configs/recommended.ts | 1 + packages/eslint-plugin/src/rules/index.ts | 1 + .../src/rules/no-prisma-include-true.ts | 100 ++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 packages/eslint-plugin/src/rules/no-prisma-include-true.ts diff --git a/packages/eslint-plugin/src/configs/recommended.ts b/packages/eslint-plugin/src/configs/recommended.ts index f1e114d4be469..30033ed964947 100644 --- a/packages/eslint-plugin/src/configs/recommended.ts +++ b/packages/eslint-plugin/src/configs/recommended.ts @@ -5,6 +5,7 @@ const recommended = { "@calcom/eslint/deprecated-imports": "error", "@calcom/eslint/avoid-web-storage": "error", "@calcom/eslint/avoid-prisma-client-import-for-enums": "error", + "@calcom/eslint/no-prisma-include-true": "error", }, }; diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 60ce1261782a7..07c5a3068e858 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -5,4 +5,5 @@ export default { "deprecated-imports": require("./deprecated-imports").default, "avoid-web-storage": require("./avoid-web-storage").default, "avoid-prisma-client-import-for-enums": require("./avoid-prisma-client-import-for-enums").default, + "no-prisma-include-true": require("./no-prisma-include-true").default, } as ESLint.Plugin["rules"]; diff --git a/packages/eslint-plugin/src/rules/no-prisma-include-true.ts b/packages/eslint-plugin/src/rules/no-prisma-include-true.ts new file mode 100644 index 0000000000000..a80fb175f4b02 --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-prisma-include-true.ts @@ -0,0 +1,100 @@ +import type { TSESTree } from "@typescript-eslint/utils"; +import { ESLintUtils } from "@typescript-eslint/utils"; +import type { ReportDescriptor } from "@typescript-eslint/utils/dist/ts-eslint"; + +const createRule = ESLintUtils.RuleCreator((name) => `https://developer.cal.com/eslint/rule/${name}`); + +const assesIncludePropertyIncludesTrue = ( + includeProperty: TSESTree.Property, + reporter: { (reportObj: ReportDescriptor<"no-prisma-include-true">): void } +) => { + if (includeProperty.value.type === "ObjectExpression") { + includeProperty.value.properties.forEach((childProperty) => { + if ( + childProperty.type === "Property" && + childProperty.value.type === "Literal" && + childProperty.value.value === true + ) { + reporter({ + node: childProperty, + messageId: "no-prisma-include-true", + }); + } + }); + } +}; + +const searchIncludeProperty = ( + property: TSESTree.Property, + reporter: { (reportObj: ReportDescriptor<"no-prisma-include-true">): void } +) => { + if (property.type === "Property") { + // If property is include, check if it has a child property with value true + if (property.key.type === "Identifier" && property.key.name === "include") { + assesIncludePropertyIncludesTrue(property, reporter); + } + + // If property value is also an object, recursively search for include property + if (property.value.type === "ObjectExpression") { + property.value.properties.forEach((childProperty) => { + if (childProperty.type === "Property") { + searchIncludeProperty(childProperty, reporter); + } + }); + } + } +}; + +const rule = createRule({ + create: function (context) { + return { + CallExpression(node) { + if (!(node.callee as TSESTree.MemberExpression).property) { + return null; + } + + const nodeName = ((node.callee as TSESTree.MemberExpression).property as TSESTree.Identifier).name; + + if ( + !["findUnique", "findUniqueOrThrow", "findFirst", "findFirstOrThrow", "findMany"].includes(nodeName) + ) { + return null; + } + + const nodeArgs = node.arguments[0] as TSESTree.ObjectExpression; + if (!nodeArgs) { + return null; + } + + const backReporter = (reportObj: ReportDescriptor<"no-prisma-include-true">) => { + context.report(reportObj); + }; + + nodeArgs.properties.forEach((property) => { + if (property.type === "Property") { + searchIncludeProperty(property, backReporter); + } + }); + return null; + }, + }; + }, + + name: "no-prisma-include-true", + meta: { + type: "problem", + docs: { + description: + "Disallow passing argument object with include: { AnyPropertyName: true } to prisma methods", + recommended: "error", + }, + messages: { + "no-prisma-include-true": `Do not pass argument object with include: { AnyPropertyName: true } to prisma methods`, + }, + fixable: "code", + schema: [], + }, + defaultOptions: [], +}); + +export default rule; From 547ddb52b0a2e2e20f552449fc121b1bd52e5928 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Tue, 13 Feb 2024 13:33:51 -0300 Subject: [PATCH 2/8] Fixing linting errors --- packages/lib/entityPermissionUtils.ts | 10 +++++++--- packages/lib/getEventTypeById.ts | 1 + packages/lib/server/queries/teams/index.ts | 10 +++++++++- packages/lib/server/repository/profile.ts | 6 +++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/lib/entityPermissionUtils.ts b/packages/lib/entityPermissionUtils.ts index 1c273f5c66e22..67d8ea25566b4 100644 --- a/packages/lib/entityPermissionUtils.ts +++ b/packages/lib/entityPermissionUtils.ts @@ -69,7 +69,12 @@ async function getMembership(teamId: number | null, userId: number) { }, }, include: { - members: true, + members: { + select: { + userId: true, + role: true, + }, + }, }, }) : null; @@ -86,8 +91,7 @@ export async function canCreateEntity({ if (targetTeamId) { // If it doesn't exist and it is being created for a team. Check if user is the member of the team const membership = await getMembership(targetTeamId, userId); - const creationAllowed = membership ? withRoleCanCreateEntity(membership.role) : false; - return creationAllowed; + return membership ? withRoleCanCreateEntity(membership.role) : false; } return true; } diff --git a/packages/lib/getEventTypeById.ts b/packages/lib/getEventTypeById.ts index 9a9b21c3ba81f..bc8e84686dc01 100644 --- a/packages/lib/getEventTypeById.ts +++ b/packages/lib/getEventTypeById.ts @@ -229,6 +229,7 @@ export default async function getEventTypeById({ }, }, }, + // eslint-disable-next-line @calcom/eslint/no-prisma-include-true steps: true, }, }, diff --git a/packages/lib/server/queries/teams/index.ts b/packages/lib/server/queries/teams/index.ts index 032841a70817a..a56263ddf7c39 100644 --- a/packages/lib/server/queries/teams/index.ts +++ b/packages/lib/server/queries/teams/index.ts @@ -253,7 +253,15 @@ export async function isTeamAdmin(userId: number, teamId: number) { accepted: true, OR: [{ role: "ADMIN" }, { role: "OWNER" }], }, - include: { team: true }, + include: { + team: { + select: { + metadata: true, + parentId: true, + isOrganization: true, + }, + }, + }, }); if (!team) return false; return team; diff --git a/packages/lib/server/repository/profile.ts b/packages/lib/server/repository/profile.ts index 8fbfc9f036bef..89da31a0abd37 100644 --- a/packages/lib/server/repository/profile.ts +++ b/packages/lib/server/repository/profile.ts @@ -346,7 +346,11 @@ export class ProfileRepository { user: { select: userSelect, }, - movedFromUser: true, + movedFromUser: { + select: { + id: true, + } + }, organization: { include: { members: { From b7c7846476aad43ded6d4dafe644d688749c01d4 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Tue, 13 Feb 2024 13:40:31 -0300 Subject: [PATCH 3/8] More linting fixes --- packages/lib/server/queries/teams/index.ts | 1 - packages/lib/server/repository/profile.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/lib/server/queries/teams/index.ts b/packages/lib/server/queries/teams/index.ts index a56263ddf7c39..eeec2559f0018 100644 --- a/packages/lib/server/queries/teams/index.ts +++ b/packages/lib/server/queries/teams/index.ts @@ -258,7 +258,6 @@ export async function isTeamAdmin(userId: number, teamId: number) { select: { metadata: true, parentId: true, - isOrganization: true, }, }, }, diff --git a/packages/lib/server/repository/profile.ts b/packages/lib/server/repository/profile.ts index 89da31a0abd37..7a13a02700b06 100644 --- a/packages/lib/server/repository/profile.ts +++ b/packages/lib/server/repository/profile.ts @@ -349,7 +349,7 @@ export class ProfileRepository { movedFromUser: { select: { id: true, - } + }, }, organization: { include: { From eb4a528c7c39c9e6725df1b8dbc1fc05bdbd08f4 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Tue, 13 Feb 2024 14:02:23 -0300 Subject: [PATCH 4/8] Disabled linting for forms --- packages/app-store/routing-forms/trpc/forms.handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/app-store/routing-forms/trpc/forms.handler.ts b/packages/app-store/routing-forms/trpc/forms.handler.ts index 30e91677b5a5a..b87eff233d35a 100644 --- a/packages/app-store/routing-forms/trpc/forms.handler.ts +++ b/packages/app-store/routing-forms/trpc/forms.handler.ts @@ -37,6 +37,7 @@ export const formsHandler = async ({ ctx, input }: FormsHandlerOptions) => { include: { team: { include: { + // eslint-disable-next-line @calcom/eslint/no-prisma-include-true members: true, }, }, From 6e6a2ce4c5dc9bb96c82766cfd43d6d25e504512 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Fri, 26 Apr 2024 17:14:25 -0300 Subject: [PATCH 5/8] Update recommended.ts --- packages/eslint-plugin/src/configs/recommended.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/configs/recommended.ts b/packages/eslint-plugin/src/configs/recommended.ts index 30033ed964947..beeb5199d2565 100644 --- a/packages/eslint-plugin/src/configs/recommended.ts +++ b/packages/eslint-plugin/src/configs/recommended.ts @@ -5,7 +5,7 @@ const recommended = { "@calcom/eslint/deprecated-imports": "error", "@calcom/eslint/avoid-web-storage": "error", "@calcom/eslint/avoid-prisma-client-import-for-enums": "error", - "@calcom/eslint/no-prisma-include-true": "error", + "@calcom/eslint/no-prisma-include-true": "warning", }, }; From 586c2de0b380d42c53fb444be79dbe05f9fe1f7d Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Fri, 26 Apr 2024 17:35:21 -0300 Subject: [PATCH 6/8] Removed ignores --- packages/app-store/routing-forms/trpc/forms.handler.ts | 1 - packages/lib/event-types/getEventTypeById.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/app-store/routing-forms/trpc/forms.handler.ts b/packages/app-store/routing-forms/trpc/forms.handler.ts index b87eff233d35a..30e91677b5a5a 100644 --- a/packages/app-store/routing-forms/trpc/forms.handler.ts +++ b/packages/app-store/routing-forms/trpc/forms.handler.ts @@ -37,7 +37,6 @@ export const formsHandler = async ({ ctx, input }: FormsHandlerOptions) => { include: { team: { include: { - // eslint-disable-next-line @calcom/eslint/no-prisma-include-true members: true, }, }, diff --git a/packages/lib/event-types/getEventTypeById.ts b/packages/lib/event-types/getEventTypeById.ts index e134e5de8c215..471783a6aa2d9 100644 --- a/packages/lib/event-types/getEventTypeById.ts +++ b/packages/lib/event-types/getEventTypeById.ts @@ -238,7 +238,6 @@ export const getEventTypeById = async ({ }, }, }, - // eslint-disable-next-line @calcom/eslint/no-prisma-include-true steps: true, }, }, From bd7f782b5860ca92871c38b119afc01442dfcc4f Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Fri, 26 Apr 2024 17:37:10 -0300 Subject: [PATCH 7/8] Fixed warning --- apps/api/v2/src/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/v2/src/app.ts b/apps/api/v2/src/app.ts index 417839abbc186..eb798b2cc5e82 100644 --- a/apps/api/v2/src/app.ts +++ b/apps/api/v2/src/app.ts @@ -4,7 +4,7 @@ import { PrismaExceptionFilter } from "@/filters/prisma-exception.filter"; import { SentryFilter } from "@/filters/sentry-exception.filter"; import { ZodExceptionFilter } from "@/filters/zod-exception.filter"; import type { ValidationError } from "@nestjs/common"; -import { BadRequestException, RequestMethod, ValidationPipe, VersioningType } from "@nestjs/common"; +import { BadRequestException, ValidationPipe, VersioningType } from "@nestjs/common"; import { HttpAdapterHost } from "@nestjs/core"; import type { NestExpressApplication } from "@nestjs/platform-express"; import * as Sentry from "@sentry/node"; From fb579733dd5f3f90b204dd4142a38c4e36f7c417 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Fri, 26 Apr 2024 17:48:00 -0300 Subject: [PATCH 8/8] Type fix --- packages/lib/server/queries/teams/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/lib/server/queries/teams/index.ts b/packages/lib/server/queries/teams/index.ts index 8e4bb47efeeb1..fffa5ea9d740b 100644 --- a/packages/lib/server/queries/teams/index.ts +++ b/packages/lib/server/queries/teams/index.ts @@ -266,6 +266,7 @@ export async function isTeamAdmin(userId: number, teamId: number) { select: { metadata: true, parentId: true, + isOrganization: true, }, }, },