refactor: cleanup use of rawInput and pipe mdwr in trpc router (#7422)
* cleanup use of rawInput and pipe mdwr * Update ssg.ts * Update ssg.ts * Update viewer.tsx --------- Co-authored-by: zomars <zomars@me.com>pull/7409/head
parent
2529f71770
commit
e4b766b9d6
|
@ -26,6 +26,7 @@ export async function ssgInit<TParams extends { locale?: string }>(opts: GetStat
|
|||
const ssg = createProxySSGHelpers({
|
||||
router: appRouter,
|
||||
transformer: superjson,
|
||||
// @ts-expect-error FIXME The signature expects req and res. Which we don't have in an SSG context.
|
||||
ctx: {
|
||||
prisma,
|
||||
session: null,
|
||||
|
|
|
@ -18,12 +18,17 @@ module.exports = {
|
|||
"jsx-a11y/role-supports-aria-props": "off", // @see https://github.com/vercel/next.js/issues/27989#issuecomment-897638654
|
||||
"react/jsx-curly-brace-presence": ["error", { props: "never", children: "never" }],
|
||||
"react/self-closing-comp": ["error", { component: true, html: true }],
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"unused-imports/no-unused-vars": [
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ vars: "all", varsIgnorePattern: "^_", args: "after-used", argsIgnorePattern: "^_" },
|
||||
{
|
||||
vars: "all",
|
||||
varsIgnorePattern: "^_",
|
||||
args: "after-used",
|
||||
argsIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
@ -45,16 +50,18 @@ module.exports = {
|
|||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["playwright/**/*.{tsx,ts}"],
|
||||
files: ["**/playwright/**/*.{tsx,ts}"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"no-undef": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
files: ["playwright/**/*.{js,jsx}"],
|
||||
files: ["**/playwright/**/*.{js,jsx}"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"no-undef": "off",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,12 +5,16 @@
|
|||
"authors": "zomars",
|
||||
"version": "1.0.0",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^4.3.9",
|
||||
"@trpc/client": "^10.10.0",
|
||||
"@trpc/next": "^10.10.0",
|
||||
"@trpc/react-query": "^10.10.0",
|
||||
"@trpc/server": "^10.10.0",
|
||||
"@trpc/client": "^10.13.0",
|
||||
"@trpc/next": "^10.13.0",
|
||||
"@trpc/react-query": "^10.13.0",
|
||||
"@trpc/server": "^10.13.0",
|
||||
"superjson": "1.9.1",
|
||||
"zod": "^3.20.2"
|
||||
}
|
||||
|
|
|
@ -8,11 +8,10 @@ import { getLocaleFromHeaders } from "@calcom/lib/i18n";
|
|||
import { defaultAvatarSrc } from "@calcom/lib/profile";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import * as trpc from "@trpc/server";
|
||||
import { Maybe } from "@trpc/server";
|
||||
import * as trpcNext from "@trpc/server/adapters/next";
|
||||
import type { Maybe } from "@trpc/server";
|
||||
import type { CreateNextContextOptions } from "@trpc/server/adapters/next";
|
||||
|
||||
type CreateContextOptions = trpcNext.CreateNextContextOptions | GetServerSidePropsContext;
|
||||
type CreateContextOptions = CreateNextContextOptions | GetServerSidePropsContext;
|
||||
|
||||
async function getUserFromSession({
|
||||
session,
|
||||
|
@ -24,6 +23,7 @@ async function getUserFromSession({
|
|||
if (!session?.user?.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: session.user.id,
|
||||
|
@ -143,5 +143,3 @@ export const createContext = async ({ req, res }: CreateContextOptions, sessionG
|
|||
res,
|
||||
};
|
||||
};
|
||||
|
||||
export type Context = trpc.inferAsyncReturnType<typeof createContextInner>;
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
import { Availability as AvailabilityModel, Prisma, Schedule as ScheduleModel, User } from "@prisma/client";
|
||||
import type {
|
||||
Availability as AvailabilityModel,
|
||||
Prisma,
|
||||
Schedule as ScheduleModel,
|
||||
User,
|
||||
} from "@prisma/client";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getUserAvailability } from "@calcom/core/getUserAvailability";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule, getWorkingHours } from "@calcom/lib/availability";
|
||||
import { yyyymmdd } from "@calcom/lib/date-fns";
|
||||
import { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
||||
import { Schedule, TimeRange } from "@calcom/types/schedule";
|
||||
import type { Schedule, TimeRange } from "@calcom/types/schedule";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
|
@ -464,7 +469,7 @@ const setupDefaultSchedule = async (userId: number, scheduleId: number, prisma:
|
|||
});
|
||||
};
|
||||
|
||||
const isDefaultSchedule = (scheduleId: number, user: Partial<User>) => {
|
||||
const _isDefaultSchedule = (scheduleId: number, user: Partial<User>) => {
|
||||
return !user.defaultScheduleId || user.defaultScheduleId === scheduleId;
|
||||
};
|
||||
|
||||
|
|
|
@ -117,10 +117,17 @@ const EventTypeDuplicateInput = z.object({
|
|||
length: z.number(),
|
||||
});
|
||||
|
||||
const eventOwnerProcedure = authedProcedure.use(async ({ ctx, rawInput, next }) => {
|
||||
const eventOwnerProcedure = authedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
users: z.array(z.string()).optional().default([]),
|
||||
})
|
||||
)
|
||||
.use(async ({ ctx, input, next }) => {
|
||||
// Prevent non-owners to update/delete a team event
|
||||
const event = await ctx.prisma.eventType.findUnique({
|
||||
where: { id: (rawInput as Record<"id", number>)?.id },
|
||||
where: { id: input.id },
|
||||
include: {
|
||||
users: true,
|
||||
team: {
|
||||
|
@ -155,18 +162,18 @@ const eventOwnerProcedure = authedProcedure.use(async ({ ctx, rawInput, next })
|
|||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
|
||||
const inputUsers = (rawInput as any).users || [];
|
||||
|
||||
const isAllowed = (function () {
|
||||
if (event.team) {
|
||||
const allTeamMembers = event.team.members.map((member) => member.userId);
|
||||
return inputUsers.every((userId: string) => allTeamMembers.includes(Number.parseInt(userId)));
|
||||
return input.users.every((userId: string) => allTeamMembers.includes(Number.parseInt(userId)));
|
||||
}
|
||||
return inputUsers.every((userId: string) => Number.parseInt(userId) === ctx.user.id);
|
||||
return input.users.every((userId: string) => Number.parseInt(userId) === ctx.user.id);
|
||||
})();
|
||||
|
||||
if (!isAllowed) {
|
||||
console.warn(`User ${ctx.user.id} attempted to an create an event for users ${inputUsers.join(", ")}.`);
|
||||
console.warn(
|
||||
`User ${ctx.user.id} attempted to an create an event for users ${input.users.join(", ")}.`
|
||||
);
|
||||
throw new TRPCError({ code: "FORBIDDEN" });
|
||||
}
|
||||
|
||||
|
@ -764,9 +771,6 @@ export const eventTypesRouter = router({
|
|||
webhooks: _webhooks,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
schedule: _schedule,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore - not typed correctly as its set on SSR
|
||||
descriptionAsSafeHTML: _descriptionAsSafeHTML,
|
||||
...rest
|
||||
} = eventType;
|
||||
|
||||
|
|
|
@ -4,15 +4,17 @@ import { z } from "zod";
|
|||
import { getAggregateWorkingHours } from "@calcom/core/getAggregateWorkingHours";
|
||||
import type { CurrentSeats } from "@calcom/core/getUserAvailability";
|
||||
import { getUserAvailability } from "@calcom/core/getUserAvailability";
|
||||
import dayjs, { Dayjs } from "@calcom/dayjs";
|
||||
import type { Dayjs } from "@calcom/dayjs";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
|
||||
import isTimeOutOfBounds from "@calcom/lib/isOutOfBounds";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { performance } from "@calcom/lib/server/perfObserver";
|
||||
import getTimeSlots from "@calcom/lib/slots";
|
||||
import prisma, { availabilityUserSelect } from "@calcom/prisma";
|
||||
import type prisma from "@calcom/prisma";
|
||||
import { availabilityUserSelect } from "@calcom/prisma";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { EventBusyDate } from "@calcom/types/Calendar";
|
||||
import type { EventBusyDate } from "@calcom/types/Calendar";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ export const viewerTeamsRouter = router({
|
|||
// If we save slug, we don't need the requestedSlug anymore
|
||||
const metadataParse = teamMetadataSchema.safeParse(prevTeam.metadata);
|
||||
if (metadataParse.success) {
|
||||
const { requestedSlug, ...cleanMetadata } = metadataParse.data || {};
|
||||
const { requestedSlug: _, ...cleanMetadata } = metadataParse.data || {};
|
||||
data.metadata = {
|
||||
...cleanMetadata,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import { v4 } from "uuid";
|
||||
import { z } from "zod";
|
||||
|
||||
|
@ -19,16 +19,12 @@ const webhookIdAndEventTypeIdSchema = z.object({
|
|||
eventTypeId: z.number().optional(),
|
||||
});
|
||||
|
||||
const webhookProcedure = authedProcedure.use(async ({ ctx, rawInput, next }) => {
|
||||
const webhookProcedure = authedProcedure
|
||||
.input(webhookIdAndEventTypeIdSchema.optional())
|
||||
.use(async ({ ctx, input, next }) => {
|
||||
// Endpoints that just read the logged in user's data - like 'list' don't necessary have any input
|
||||
if (!rawInput) {
|
||||
return next();
|
||||
}
|
||||
const webhookIdAndEventTypeId = webhookIdAndEventTypeIdSchema.safeParse(rawInput);
|
||||
if (!webhookIdAndEventTypeId.success) {
|
||||
throw new TRPCError({ code: "PARSE_ERROR" });
|
||||
}
|
||||
const { eventTypeId, id } = webhookIdAndEventTypeId.data;
|
||||
if (!input) return next();
|
||||
const { eventTypeId, id } = input;
|
||||
|
||||
// A webhook is either linked to Event Type or to a user.
|
||||
if (eventTypeId) {
|
||||
|
@ -72,7 +68,6 @@ export const webhookRouter = router({
|
|||
.input(
|
||||
z
|
||||
.object({
|
||||
eventTypeId: z.number().optional(),
|
||||
appId: z.string().optional(),
|
||||
})
|
||||
.optional()
|
||||
|
|
|
@ -890,7 +890,7 @@ export const workflowsRouter = router({
|
|||
if (!userWorkflow.user?.teams.length && isSMSAction(s.action)) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
const { id: stepId, ...stepToAdd } = s;
|
||||
const { id: _stepId, ...stepToAdd } = s;
|
||||
return stepToAdd;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import superjson from "superjson";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import rateLimit from "@calcom/lib/rateLimit";
|
||||
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
|
||||
import { Context } from "./createContext";
|
||||
import type { createContext } from "./createContext";
|
||||
|
||||
const t = initTRPC.context<Context>().create({
|
||||
const t = initTRPC.context<typeof createContext>().create({
|
||||
transformer: superjson,
|
||||
});
|
||||
|
||||
|
@ -32,18 +31,15 @@ const isAuthedMiddleware = t.middleware(({ ctx, next }) => {
|
|||
});
|
||||
});
|
||||
|
||||
const isAdminMiddleware = t.middleware(({ ctx, next }) => {
|
||||
if (!ctx.user || !ctx.session || ctx.user.role !== "ADMIN") {
|
||||
const isAdminMiddleware = isAuthedMiddleware.unstable_pipe(({ ctx, next }) => {
|
||||
if (ctx.user.role !== "ADMIN") {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
return next({
|
||||
ctx: {
|
||||
// infers that `user` and `session` are non-nullable to downstream procedures
|
||||
session: ctx.session,
|
||||
user: ctx.user,
|
||||
},
|
||||
ctx: { user: ctx.user },
|
||||
});
|
||||
});
|
||||
|
||||
interface IRateLimitOptions {
|
||||
intervalInMs: number;
|
||||
limit: number;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"extends": "@calcom/tsconfig/react-library.json"
|
||||
"extends": "@calcom/tsconfig/react-library.json",
|
||||
"include": ["client", "next", "react", "server"]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { User as PrismaUser } from "@prisma/client";
|
||||
import { DefaultUser } from "next-auth";
|
||||
import type { User as PrismaUser } from "@prisma/client";
|
||||
import type { DefaultUser } from "next-auth";
|
||||
|
||||
declare module "next-auth" {
|
||||
/**
|
||||
|
|
32
yarn.lock
32
yarn.lock
|
@ -7910,27 +7910,27 @@
|
|||
javascript-natural-sort "0.7.1"
|
||||
lodash "4.17.21"
|
||||
|
||||
"@trpc/client@^10.10.0":
|
||||
version "10.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/client/-/client-10.10.0.tgz#5abdbf399639f2fdfe605682d2cdf3f9dba87cb1"
|
||||
integrity sha512-HRVGkOsR4FIYpyQILP84HLbj6pRnLKgxy4AIelTf9d9TxD60M5bNhbR2Uz3hqNSb9a2ppaRJBLv7twlV9b4qHQ==
|
||||
"@trpc/client@^10.13.0":
|
||||
version "10.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/client/-/client-10.13.0.tgz#8999a7ba068a684629071b77a07c00a141585eca"
|
||||
integrity sha512-r4KuN0os2J194lxg5jn4+o3uNlqunLFYptwTHcVW4Q0XGO0ZoTKLHuxT7c9IeDivkAs6G5oVEPiKhptkag36dQ==
|
||||
|
||||
"@trpc/next@^10.10.0":
|
||||
version "10.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/next/-/next-10.10.0.tgz#083ff327b68b005d60b19af07008377f830ad73a"
|
||||
integrity sha512-7d84L2OoF0RW06drTbNGOOggwMes8JxI3Ln/VOIaYeERzwOFNCtWPmGjWCdq4l1SKbXC6+baS+b9n5cXc+euwA==
|
||||
"@trpc/next@^10.13.0":
|
||||
version "10.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/next/-/next-10.13.0.tgz#64393f0d8dbfae7d87e54260dea532702bd1ecdf"
|
||||
integrity sha512-Q4rnuuiSUXDYv34f8FNUKhEMQFgLJTTJean78YjhG3Aaci+r4sew4hPmRvDRut8fBpa+EtExq+dv1EUbzlXgJg==
|
||||
dependencies:
|
||||
react-ssr-prepass "^1.5.0"
|
||||
|
||||
"@trpc/react-query@^10.10.0":
|
||||
version "10.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/react-query/-/react-query-10.10.0.tgz#1faf32056aa3ee5ecb2ffd0d15e8abbcd7eff911"
|
||||
integrity sha512-Jc/uii1MPevf95/z/W3ufYGHvrFvrtkjxQ8UuXhJCzOgv/FGPqhmA5PH124nLHEgGLBA7zQxHumofhdXosEhUQ==
|
||||
"@trpc/react-query@^10.13.0":
|
||||
version "10.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/react-query/-/react-query-10.13.0.tgz#ca5a1da0ea126976d7435775f2ba1846cb7fad59"
|
||||
integrity sha512-y4jbojrDFdEl1KBejBoMWIofcUXDHQA8wf01eKMEDV7Jwc7lhq6R1dxYtKzeF+s5wqfnPWFOGZDmB3flzv07Dw==
|
||||
|
||||
"@trpc/server@^10.10.0":
|
||||
version "10.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/server/-/server-10.10.0.tgz#0b494335140d4fd5e1452f7b57dcc9b8886720a4"
|
||||
integrity sha512-tCTqcqBT+3nebYFTHtwM877qo5xQPtVlptxKdUzMVWleWT4lFTL4oddk45qVURToci2iMbVJjd4jQU9y9/XwlQ==
|
||||
"@trpc/server@^10.13.0":
|
||||
version "10.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@trpc/server/-/server-10.13.0.tgz#0945b5210a18934c2284c8679cb6692ecb5b054c"
|
||||
integrity sha512-d/bu6utCC4ALxhTJkolEPAHMOSuCAu3mG79TZswa6wD2ob0/Z3AIvBF/meeSTqDxe4tvXY78lQqOkQI81dgi/g==
|
||||
|
||||
"@tryvital/vital-node@^1.4.6":
|
||||
version "1.4.6"
|
||||
|
|
Loading…
Reference in New Issue