chore: Couple fixes to improve error reporting (#16895)

* chore: Couple fixes to improve error reporting

* tweak: Fix error message

* refactor: Use findUniqueOrThrow instead of guard

* fix: Broken test, missing ID - suspect it passes because only one record exists

* chore: Minor refactor to split ZodEffect from ZodType

* fix: Satify typescript
This commit is contained in:
Alex van Andel
2024-10-01 09:18:51 -03:00
committed by GitHub
parent 4b6a389212
commit a95729f4a1
9 changed files with 31 additions and 28 deletions
@@ -2,7 +2,7 @@ import type { NextApiRequest } from "next";
import handleCancelBooking from "@calcom/features/bookings/lib/handleCancelBooking";
import { defaultResponder } from "@calcom/lib/server";
import { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import { bookingCancelSchema } from "@calcom/prisma/zod-utils";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -65,7 +65,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
*/
async function handler(req: NextApiRequest) {
const { id, allRemainingBookings, cancellationReason } = schemaQueryIdParseInt
.merge(schemaBookingCancelParams.pick({ allRemainingBookings: true, cancellationReason: true }))
.merge(bookingCancelSchema.pick({ allRemainingBookings: true, cancellationReason: true }))
.parse({
...req.query,
allRemainingBookings: req.query.allRemainingBookings === "true",
@@ -1,7 +1,7 @@
import type z from "zod";
import type { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import type { bookingCancelSchema } from "@calcom/prisma/zod-utils";
export function getMockRequestDataForCancelBooking(data: z.infer<typeof schemaBookingCancelParams>) {
export function getMockRequestDataForCancelBooking(data: z.infer<typeof bookingCancelSchema>) {
return data;
}
@@ -28,11 +28,7 @@ import prisma, { bookingMinimalSelect } from "@calcom/prisma";
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { BookingStatus } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import {
bookingMetadataSchema,
EventTypeMetaDataSchema,
schemaBookingCancelParams,
} from "@calcom/prisma/zod-utils";
import { bookingMetadataSchema, EventTypeMetaDataSchema, bookingCancelInput } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import { getAllWorkflowsFromEventType } from "@calcom/trpc/server/routers/viewer/workflows/util";
import type { CalendarEvent } from "@calcom/types/Calendar";
@@ -43,7 +39,7 @@ import cancelAttendeeSeat from "./handleSeats/cancel/cancelAttendeeSeat";
const log = logger.getSubLogger({ prefix: ["handleCancelBooking"] });
async function getBookingToDelete(id: number | undefined, uid: string | undefined) {
return await prisma.booking.findUnique({
return await prisma.booking.findUniqueOrThrow({
where: {
id,
uid,
@@ -160,7 +156,7 @@ export type HandleCancelBookingResponse = {
async function handler(req: CustomRequest) {
const { id, uid, allRemainingBookings, cancellationReason, seatReferenceUid, cancelledBy } =
schemaBookingCancelParams.parse(req.body);
bookingCancelInput.parse(req.body);
req.bookingToDelete = await getBookingToDelete(id, uid);
const {
bookingToDelete,
@@ -172,11 +168,7 @@ async function handler(req: CustomRequest) {
arePlatformEmailsEnabled,
} = req;
if (!bookingToDelete || !bookingToDelete.user) {
throw new HttpError({ statusCode: 400, message: "Booking not found" });
}
if (!bookingToDelete.userId) {
if (!bookingToDelete.userId || !bookingToDelete.user) {
throw new HttpError({ statusCode: 400, message: "User not found" });
}
@@ -11,7 +11,7 @@ import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import prisma from "@calcom/prisma";
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import { bookingCancelAttendeeSeatSchema } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import type { CalendarEvent } from "@calcom/types/Calendar";
@@ -32,9 +32,10 @@ async function cancelAttendeeSeat(
},
eventTypeMetadata: EventTypeMetadata
) {
const { seatReferenceUid } = schemaBookingCancelParams.parse(req.body);
const input = bookingCancelAttendeeSeatSchema.safeParse(req.body);
const { webhooks, evt, eventTypeInfo } = dataForWebhooks;
if (!seatReferenceUid) return;
if (!input.success) return;
const { seatReferenceUid } = input.data;
const bookingToDelete = req.bookingToDelete;
if (!bookingToDelete?.attendees.length || bookingToDelete.attendees.length < 2) return;
@@ -2664,6 +2664,7 @@ describe("handleSeats", () => {
const mockBookingData = getMockRequestDataForBooking({
data: {
id: firstBookingId,
eventTypeId: 1,
responses: {
email: booker.email,
+6 -5
View File
@@ -17,12 +17,13 @@ export function defaultResponder<T>(f: Handle<T>) {
return res.json(result);
}
} catch (err) {
console.error(err);
const error = getServerErrorFromUnknown(err);
// dynamic import of Sentry so it's only loaded when something goes wrong.
const captureException = (await import("@sentry/nextjs")).captureException;
captureException(err);
// return API route response
// we don't want to report Bad Request errors to Sentry / console
if (!(error.statusCode >= 400 && error.statusCode < 500)) {
console.error(err);
const captureException = (await import("@sentry/nextjs")).captureException;
captureException(err);
}
return res
.status(error.statusCode)
.json({ message: error.message, url: error.url, method: error.method });
@@ -28,7 +28,6 @@ function parseZodErrorIssues(issues: ZodIssue[]): string {
export function getServerErrorFromUnknown(cause: unknown): HttpError {
if (isZodError(cause)) {
console.log("cause", cause);
return new HttpError({
statusCode: 400,
message: parseZodErrorIssues(cause.issues),
@@ -3,7 +3,7 @@ import type { z } from "zod";
import { SUCCESS_STATUS } from "@calcom/platform-constants";
import type { ApiResponse, ApiErrorResponse } from "@calcom/platform-types";
import type { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import type { bookingCancelSchema } from "@calcom/prisma/zod-utils";
import http from "../lib/http";
@@ -12,7 +12,7 @@ interface IUseCancelBooking {
onError?: (err: ApiErrorResponse | Error) => void;
}
type inputParams = z.infer<typeof schemaBookingCancelParams>;
type inputParams = z.infer<typeof bookingCancelSchema>;
export const useCancelBooking = (
{ onSuccess, onError }: IUseCancelBooking = {
+10 -1
View File
@@ -314,7 +314,7 @@ export const bookingCreateBodySchemaForApi = extendedBookingCreateBody.merge(
bookingCreateSchemaLegacyPropsForApi.partial()
);
export const schemaBookingCancelParams = z.object({
export const bookingCancelSchema = z.object({
id: z.number().optional(),
uid: z.string().optional(),
allRemainingBookings: z.boolean().optional(),
@@ -323,6 +323,15 @@ export const schemaBookingCancelParams = z.object({
cancelledBy: z.string().email({ message: "Invalid email" }).optional(),
});
export const bookingCancelAttendeeSeatSchema = z.object({
seatReferenceUid: z.string(),
});
export const bookingCancelInput = bookingCancelSchema.refine(
(data) => !!data.id || !!data.uid,
"At least one of the following required: 'id', 'uid'."
);
export const vitalSettingsUpdateSchema = z.object({
connected: z.boolean().optional(),
selectedParam: z.string().optional(),