Fix/send responses everywhere customInputs were being sent. (#7898)

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
This commit is contained in:
Hariom Balhara
2023-04-04 10:29:09 +05:30
committed by GitHub
co-authored by Alex van Andel CarinaWolli
parent 72629ffee0
commit e504f5cd9e
15 changed files with 100 additions and 50 deletions
+2 -2
View File
@@ -13,6 +13,8 @@ import {
getGroupName,
getUsernameList,
} from "@calcom/lib/defaultEvents";
import getBooking from "@calcom/lib/getBooking";
import type { GetBookingType } from "@calcom/lib/getBooking";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import prisma, { bookEventTypeSelect } from "@calcom/prisma";
@@ -22,8 +24,6 @@ import {
userMetadata as userMetadataSchema,
} from "@calcom/prisma/zod-utils";
import type { GetBookingType } from "@lib/getBooking";
import getBooking from "@lib/getBooking";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import BookingPage from "@components/booking/pages/BookingPage";
@@ -3,6 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
import dayjs from "@calcom/dayjs";
import { sendOrganizerRequestReminderEmail } from "@calcom/emails";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
import { getTranslation } from "@calcom/lib/server/i18n";
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
@@ -48,8 +49,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
eventType: {
select: {
recurringEvent: true,
bookingFields: true,
},
},
responses: true,
uid: true,
destinationCalendar: true,
},
@@ -96,6 +99,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
title: booking.title,
description: booking.description || undefined,
customInputs: isPrismaObjOrUndefined(booking.customInputs),
...getCalEventResponses({
bookingFields: booking.eventType?.bookingFields ?? null,
booking,
}),
location: booking.location ?? "",
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
+1 -1
View File
@@ -36,6 +36,7 @@ import {
formatToLocalizedTimezone,
} from "@calcom/lib/date-fns";
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
import { getBookingWithResponses } from "@calcom/lib/getBooking";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
@@ -51,7 +52,6 @@ import { Button, EmailInput, HeadSeo, Badge } from "@calcom/ui";
import { FiX, FiExternalLink, FiChevronLeft, FiCheck, FiCalendar } from "@calcom/ui/components/icon";
import { timeZone } from "@lib/clock";
import { getBookingWithResponses } from "@lib/getBooking";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import CancelBooking from "@components/booking/CancelBooking";
+1 -1
View File
@@ -5,12 +5,12 @@ import type { LocationObject } from "@calcom/core/location";
import { privacyFilteredLocations } from "@calcom/core/location";
import { parseRecurringEvent } from "@calcom/lib";
import { getWorkingHours } from "@calcom/lib/availability";
import type { GetBookingType } from "@calcom/lib/getBooking";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import { availiblityPageEventTypeSelect } from "@calcom/prisma";
import prisma from "@calcom/prisma";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type { GetBookingType } from "@lib/getBooking";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
+2 -2
View File
@@ -4,13 +4,13 @@ import type { LocationObject } from "@calcom/core/location";
import { privacyFilteredLocations } from "@calcom/core/location";
import { parseRecurringEvent } from "@calcom/lib";
import { getWorkingHours } from "@calcom/lib/availability";
import getBooking from "@calcom/lib/getBooking";
import type { GetBookingType } from "@calcom/lib/getBooking";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import prisma from "@calcom/prisma";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { asStringOrNull } from "@lib/asStringOrNull";
import type { GetBookingType } from "@lib/getBooking";
import getBooking from "@lib/getBooking";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
+2 -2
View File
@@ -5,13 +5,13 @@ import type { LocationObject } from "@calcom/app-store/locations";
import { privacyFilteredLocations } from "@calcom/app-store/locations";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import { parseRecurringEvent } from "@calcom/lib";
import type { GetBookingType } from "@calcom/lib/getBooking";
import getBooking from "@calcom/lib/getBooking";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import prisma from "@calcom/prisma";
import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
import type { GetBookingType } from "@lib/getBooking";
import getBooking from "@lib/getBooking";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import BookingPage from "@components/booking/pages/BookingPage";
@@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getHumanReadableLocationValue } from "@calcom/core/location";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import findValidApiKey from "@calcom/features/ee/api-keys/lib/findValidApiKey";
import { defaultHandler, defaultResponder, getTranslation } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
@@ -31,6 +32,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
title: true,
description: true,
customInputs: true,
responses: true,
startTime: true,
endTime: true,
location: true,
@@ -53,6 +55,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
price: true,
currency: true,
length: true,
bookingFields: true,
},
},
attendees: {
@@ -68,7 +71,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const t = await getTranslation(bookings[0].user?.locale ?? "en", "common");
const updatedBookings = bookings.map((booking) => {
return { ...booking, location: getHumanReadableLocationValue(booking.location || "", t) };
return {
...booking,
...getCalEventResponses({
bookingFields: booking.eventType?.bookingFields ?? null,
booking,
}),
location: getHumanReadableLocationValue(booking.location || "", t),
};
});
res.status(201).json(updatedBookings);
@@ -2,23 +2,45 @@ import type z from "zod";
import { SystemField } from "@calcom/features/bookings/lib/getBookingFields";
import type { bookingResponsesDbSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema";
import type { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
import { getBookingWithResponses } from "@calcom/lib/getBooking";
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
import type { CalendarEvent } from "@calcom/types/Calendar";
import type { EventType, Prisma } from ".prisma/client";
export const getCalEventResponses = ({
bookingFields,
booking,
responses,
}: {
// If the eventType has been deleted and a booking is Accepted later on, then bookingFields will be null and we can't know the label of fields. So, we should store the label as well in the DB
// Also, it is no longer straightforward to identify if a field is system field or not
bookingFields: z.infer<typeof eventTypeBookingFields> | null;
responses: z.infer<typeof bookingResponsesDbSchema>;
bookingFields: z.infer<typeof eventTypeBookingFields> | EventType["bookingFields"] | null;
booking?: Prisma.BookingGetPayload<{
select: {
description: true;
customInputs: true;
attendees: {
select: {
email: true;
name: true;
};
};
location: true;
responses: true;
};
}>;
responses?: z.infer<typeof bookingResponsesDbSchema>;
}) => {
const calEventUserFieldsResponses = {} as NonNullable<CalendarEvent["userFieldsResponses"]>;
const calEventResponses = {} as NonNullable<CalendarEvent["responses"]>;
const parsedBookingFields = bookingFields ? eventTypeBookingFields.parse(bookingFields) : null;
const backwardCompatibleResponses =
responses ?? (booking ? getBookingWithResponses(booking).responses : null);
if (!backwardCompatibleResponses) throw new Error("Couldn't get responses");
if (bookingFields) {
bookingFields.forEach((field) => {
if (parsedBookingFields) {
parsedBookingFields.forEach((field) => {
const label = field.label || field.defaultLabel;
if (!label) {
throw new Error('Missing label for booking field "' + field.name + '"');
@@ -26,17 +48,17 @@ export const getCalEventResponses = ({
if (field.editable === "user" || field.editable === "user-readonly") {
calEventUserFieldsResponses[field.name] = {
label,
value: responses[field.name],
value: backwardCompatibleResponses[field.name],
};
}
calEventResponses[field.name] = {
label,
value: responses[field.name],
value: backwardCompatibleResponses[field.name],
};
});
} else {
// Alternative way to generate for a booking of whose eventType has been deleted
for (const [name, value] of Object.entries(responses)) {
for (const [name, value] of Object.entries(backwardCompatibleResponses)) {
const isSystemField = SystemField.safeParse(name);
// Use name for Label because we don't have access to the label. This will not be needed once we start storing the label along with the response
@@ -55,5 +77,5 @@ export const getCalEventResponses = ({
};
}
}
return { calEventUserFieldsResponses, calEventResponses };
return { userFieldsResponses: calEventUserFieldsResponses, responses: calEventResponses };
};
@@ -10,6 +10,7 @@ import { cancelScheduledJobs } from "@calcom/app-store/zapier/lib/nodeScheduler"
import { deleteMeeting, updateMeeting } from "@calcom/core/videoClient";
import dayjs from "@calcom/dayjs";
import { sendCancelledEmails, sendCancelledSeatEmails } from "@calcom/emails";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { deleteScheduledEmailReminder } from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager";
import { sendCancelledReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler";
import { deleteScheduledSMSReminder } from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager";
@@ -67,6 +68,7 @@ async function getBookingToDelete(id: number | undefined, uid: string | undefine
currency: true,
length: true,
seatsPerTimeSlot: true,
bookingFields: true,
seatsShowAttendees: true,
hosts: {
select: {
@@ -91,6 +93,7 @@ async function getBookingToDelete(id: number | undefined, uid: string | undefine
workflowReminders: true,
scheduledJobs: true,
seatsReferences: true,
responses: true,
},
});
}
@@ -173,6 +176,10 @@ async function handler(req: CustomRequest) {
type: (bookingToDelete?.eventType?.title as string) || bookingToDelete?.title,
description: bookingToDelete?.description || "",
customInputs: isPrismaObjOrUndefined(bookingToDelete.customInputs),
...getCalEventResponses({
bookingFields: bookingToDelete.eventType?.bookingFields ?? null,
booking: bookingToDelete,
}),
startTime: bookingToDelete?.startTime ? dayjs(bookingToDelete.startTime).format() : "",
endTime: bookingToDelete?.endTime ? dayjs(bookingToDelete.endTime).format() : "",
organizer: {
@@ -509,6 +516,10 @@ async function handler(req: CustomRequest) {
title: bookingToDelete.title,
description: bookingToDelete.description ?? "",
customInputs: isPrismaObjOrUndefined(bookingToDelete.customInputs),
...getCalEventResponses({
booking: bookingToDelete,
bookingFields: bookingToDelete.eventType?.bookingFields ?? null,
}),
startTime: bookingToDelete.startTime.toISOString(),
endTime: bookingToDelete.endTime.toISOString(),
organizer: {
@@ -404,10 +404,11 @@ function getBookingData({
const reqBody = bookingDataSchema.parse(req.body);
if ("responses" in reqBody) {
const responses = reqBody.responses;
const { calEventUserFieldsResponses, calEventResponses } = getCalEventResponses({
bookingFields: eventType.bookingFields,
responses,
});
const { userFieldsResponses: calEventUserFieldsResponses, responses: calEventResponses } =
getCalEventResponses({
bookingFields: eventType.bookingFields,
responses,
});
return {
...reqBody,
name: responses.name,
@@ -742,6 +743,7 @@ async function handler(
const uid = translator.fromUUID(uuidv5(seed, uuidv5.URL));
const bookingLocation = getLocationValueForDB(locationBodyString, eventType.locations);
const customInputs = getCustomInputsResponses(reqBody, eventType.customInputs);
const teamMemberPromises =
users.length > 1
@@ -7,6 +7,7 @@ import type Stripe from "stripe";
import stripe from "@calcom/app-store/stripepayment/lib/server";
import EventManager from "@calcom/core/EventManager";
import { sendScheduledEmails } from "@calcom/emails";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { handleConfirmation } from "@calcom/features/bookings/lib/handleConfirmation";
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
import { IS_PRODUCTION } from "@calcom/lib/constants";
@@ -65,6 +66,7 @@ async function handlePaymentSuccess(event: Stripe.Event) {
paid: true,
destinationCalendar: true,
status: true,
responses: true,
user: {
select: {
id: true,
@@ -114,6 +116,10 @@ async function handlePaymentSuccess(event: Stripe.Event) {
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
customInputs: isPrismaObjOrUndefined(booking.customInputs),
...getCalEventResponses({
booking: booking,
bookingFields: booking.eventType?.bookingFields || null,
}),
organizer: {
email: user.email,
name: user.name!,
@@ -46,6 +46,7 @@ function getZapierPayload(data: CalendarEvent & EventTypeInfo & { status?: strin
description: data.description,
customInputs: data.customInputs,
responses: data.responses,
userFieldsResponses: data.userFieldsResponses,
startTime: data.startTime,
endTime: data.endTime,
location: location,
@@ -14,7 +14,6 @@ type BookingSelect = {
};
};
location: true;
smsReminderNumber: true;
};
// Backward Compatibility for booking created before we had managed booking questions
@@ -104,4 +103,5 @@ export const getBookingWithResponses = <
responses: bookingResponsesDbSchema.parse(booking.responses || getResponsesFromOldBooking(booking)),
} as Omit<T, "responses"> & { responses: z.infer<typeof bookingResponsesDbSchema> };
};
export default getBooking;
+7 -1
View File
@@ -23,6 +23,7 @@ import dayjs from "@calcom/dayjs";
import { sendCancelledEmails, sendFeedbackEmail } from "@calcom/emails";
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
import { verifyPassword } from "@calcom/features/auth/lib/verifyPassword";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { samlTenantProduct } from "@calcom/features/ee/sso/lib/saml";
import { featureFlagRouter } from "@calcom/features/flags/server/router";
import { insightsRouter } from "@calcom/features/insights/server/trpc-router";
@@ -1008,6 +1009,7 @@ const loggedInViewerRouter = router({
...bookingMinimalSelect,
recurringEventId: true,
userId: true,
responses: true,
user: {
select: {
id: true,
@@ -1033,6 +1035,7 @@ const loggedInViewerRouter = router({
select: {
recurringEvent: true,
title: true,
bookingFields: true,
seatsPerTimeSlot: true,
seatsShowAttendees: true,
},
@@ -1093,12 +1096,15 @@ const loggedInViewerRouter = router({
const attendeesList = await Promise.all(attendeesListPromises);
const tOrganizer = await getTranslation(booking?.user?.locale ?? "en", "common");
await sendCancelledEmails({
type: booking?.eventType?.title as string,
title: booking.title,
description: booking.description,
customInputs: isPrismaObjOrUndefined(booking.customInputs),
...getCalEventResponses({
bookingFields: booking.eventType?.bookingFields ?? null,
booking,
}),
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
organizer: {
@@ -15,8 +15,6 @@ import dayjs from "@calcom/dayjs";
import { deleteScheduledEmailReminder } from "@calcom/ee/workflows/lib/reminders/emailReminderManager";
import { deleteScheduledSMSReminder } from "@calcom/ee/workflows/lib/reminders/smsReminderManager";
import { sendDeclinedEmails, sendLocationChangeEmails, sendRequestRescheduleEmail } from "@calcom/emails";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import { bookingResponsesDbSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { handleConfirmation } from "@calcom/features/bookings/lib/handleConfirmation";
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
@@ -418,6 +416,7 @@ export const bookingsRouter = router({
smsReminderNumber: true,
scheduledJobs: true,
workflowReminders: true,
responses: true,
},
where: {
uid: bookingId,
@@ -577,6 +576,10 @@ export const bookingsRouter = router({
type: event && event.title ? event.title : bookingToReschedule.title,
description: bookingToReschedule?.description || "",
customInputs: isPrismaObjOrUndefined(bookingToReschedule.customInputs),
...getCalEventResponses({
booking: bookingToReschedule,
bookingFields: bookingToReschedule.eventType?.bookingFields ?? null,
}),
startTime: bookingToReschedule?.startTime ? dayjs(bookingToReschedule.startTime).format() : "",
endTime: bookingToReschedule?.endTime ? dayjs(bookingToReschedule.endTime).format() : "",
organizer: userAsPeopleType,
@@ -722,7 +725,7 @@ export const bookingsRouter = router({
const tOrganizer = await getTranslation(user.locale ?? "en", "common");
const bookingRaw = await prisma.booking.findUniqueOrThrow({
const booking = await prisma.booking.findUniqueOrThrow({
where: {
id: bookingId,
},
@@ -776,21 +779,6 @@ export const bookingsRouter = router({
},
});
const bookingFields = bookingRaw.eventType
? getBookingFieldsWithSystemFields(bookingRaw.eventType)
: null;
const booking = {
...bookingRaw,
responses: bookingResponsesDbSchema.parse(bookingRaw.responses),
eventType: bookingRaw.eventType
? {
...bookingRaw.eventType,
bookingFields,
}
: null,
};
const authorized = async () => {
// if the organizer
if (booking.userId === user.id) {
@@ -848,18 +836,15 @@ export const bookingsRouter = router({
const attendeesList = await Promise.all(attendeesListPromises);
// TODO: Remove the usage of `bookingFields` in computing responses. We can do that by storing `label` with the response. Also, this would allow us to correctly show the label for a field even after the Event Type has been deleted.
const { calEventUserFieldsResponses, calEventResponses } = getCalEventResponses({
bookingFields: booking.eventType?.bookingFields ?? null,
responses: booking.responses,
});
const evt: CalendarEvent = {
type: booking.eventType?.title || booking.title,
title: booking.title,
description: booking.description,
responses: calEventResponses,
userFieldsResponses: calEventUserFieldsResponses,
// TODO: Remove the usage of `bookingFields` in computing responses. We can do that by storing `label` with the response. Also, this would allow us to correctly show the label for a field even after the Event Type has been deleted.
...getCalEventResponses({
bookingFields: booking.eventType?.bookingFields ?? null,
booking,
}),
customInputs: isPrismaObjOrUndefined(booking.customInputs),
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),