Skip to content

Commit

Permalink
feat: Add linting rule to recursively check for Prisma includes using… (
Browse files Browse the repository at this point in the history
#13652)

* feat: Add linting rule to recursively check for Prisma includes using only 'true'

* Fixing linting errors

* More linting fixes

* Disabled linting for forms

* Update recommended.ts

* Removed ignores

* Fixed warning

* Type fix

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
  • Loading branch information
Nis-Han and keithwillcode committed Apr 26, 2024
1 parent fc16ec5 commit 7c35432
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 18 deletions.
11 changes: 0 additions & 11 deletions apps/api/v2/next-i18next.config.js

This file was deleted.

2 changes: 1 addition & 1 deletion apps/api/v2/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
2 changes: 1 addition & 1 deletion apps/api/v2/src/ee/event-types/event-types.repository.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { CreateEventTypeInput } from "@/ee/event-types/inputs/create-event-type.input";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import type { PrismaClient } from "@calcom/prisma";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { UserWithProfile } from "@/modules/users/users.repository";
import { Injectable } from "@nestjs/common";

import { getEventTypeById } from "@calcom/platform-libraries";
import type { PrismaClient } from "@calcom/prisma";

@Injectable()
export class EventTypesRepository {
Expand Down
1 change: 1 addition & 0 deletions packages/embeds/embed-react/playwright/tests/basic.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from "@playwright/test";

import { getEmbedIframe } from "@calcom/embed-core/playwright/lib/testUtils";
// eslint-disable-next-line no-restricted-imports
import { test } from "@calcom/web/playwright/lib/fixtures";

test.describe("React Embed", () => {
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const recommended = {
"@calcom/eslint/deprecated-imports-next-router": "error",
"@calcom/eslint/avoid-web-storage": "error",
"@calcom/eslint/avoid-prisma-client-import-for-enums": "error",
"@calcom/eslint/no-prisma-include-true": "warn",
},
};

Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ 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,
"deprecated-imports-next-router": require("./deprecated-imports-next-router").default,
} as ESLint.Plugin["rules"];
100 changes: 100 additions & 0 deletions packages/eslint-plugin/src/rules/no-prisma-include-true.ts
Original file line number Diff line number Diff line change
@@ -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;
10 changes: 7 additions & 3 deletions packages/lib/entityPermissionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ async function getMembership(teamId: number | null, userId: number) {
},
},
include: {
members: true,
members: {
select: {
userId: true,
role: true,
},
},
},
})
: null;
Expand All @@ -81,8 +86,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;
}
Expand Down
10 changes: 9 additions & 1 deletion packages/lib/server/queries/teams/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,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;
Expand Down
6 changes: 5 additions & 1 deletion packages/lib/server/repository/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,11 @@ export class ProfileRepository {
user: {
select: userSelect,
},
movedFromUser: true,
movedFromUser: {
select: {
id: true,
},
},
organization: {
select: {
calVideoLogo: true,
Expand Down

0 comments on commit 7c35432

Please sign in to comment.