fix: include orgs slug in getUserByUsername just like [user]/[type] page (#10723)

Co-authored-by: Omar López <zomars@me.com>
This commit is contained in:
alannnc 2023-08-24 16:41:06 -07:00 committed by GitHub
parent d6740503be
commit 1eef5a56c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 177 additions and 110 deletions

View File

@ -269,12 +269,14 @@ describe("getSchedule", () => {
createBookingScenario(scenarioData);
const scheduleForDayWithAGoogleCalendarBooking = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
},
});
// As per Google Calendar Availability, only 4PM(4-4:45PM) GMT slot would be available
@ -353,13 +355,15 @@ describe("getSchedule", () => {
// Day Plus 2 is completely free - It only has non accepted bookings
const scheduleOnCompletelyFreeDay = await getSchedule({
eventTypeId: 1,
// EventTypeSlug doesn't matter for non-dynamic events
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
// EventTypeSlug doesn't matter for non-dynamic events
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
// getSchedule returns timeslots in GMT
@ -384,12 +388,14 @@ describe("getSchedule", () => {
// Day plus 3
const scheduleForDayWithOneBooking = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus2DateString}T18:30:00.000Z`,
endTime: `${plus3DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus2DateString}T18:30:00.000Z`,
endTime: `${plus3DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForDayWithOneBooking).toHaveTimeSlots(
@ -448,12 +454,14 @@ describe("getSchedule", () => {
const { dateString: plus1DateString } = getDate({ dateIncrement: 1 });
const { dateString: plus2DateString } = getDate({ dateIncrement: 2 });
const scheduleForEventWith30Length = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForEventWith30Length).toHaveTimeSlots(
@ -482,12 +490,14 @@ describe("getSchedule", () => {
);
const scheduleForEventWith30minsLengthAndSlotInterval2hrs = await getSchedule({
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
// `slotInterval` takes precedence over `length`
// 4:30 is utc so it is 10:00 in IST
@ -545,12 +555,14 @@ describe("getSchedule", () => {
const { dateString: todayDateString } = getDate();
const { dateString: minus1DateString } = getDate({ dateIncrement: -1 });
const scheduleForEventWithBookingNotice13Hrs = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${minus1DateString}T18:30:00.000Z`,
endTime: `${todayDateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${minus1DateString}T18:30:00.000Z`,
endTime: `${todayDateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForEventWithBookingNotice13Hrs).toHaveTimeSlots(
[
@ -564,12 +576,14 @@ describe("getSchedule", () => {
);
const scheduleForEventWithBookingNotice10Hrs = await getSchedule({
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${minus1DateString}T18:30:00.000Z`,
endTime: `${todayDateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${minus1DateString}T18:30:00.000Z`,
endTime: `${todayDateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForEventWithBookingNotice10Hrs).toHaveTimeSlots(
[
@ -627,12 +641,14 @@ describe("getSchedule", () => {
createBookingScenario(scenarioData);
const scheduleForEventOnADayWithNonCalBooking = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus2DateString}T18:30:00.000Z`,
endTime: `${plus3DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus2DateString}T18:30:00.000Z`,
endTime: `${plus3DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForEventOnADayWithNonCalBooking).toHaveTimeSlots(
@ -700,12 +716,14 @@ describe("getSchedule", () => {
createBookingScenario(scenarioData);
const scheduleForEventOnADayWithCalBooking = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForEventOnADayWithCalBooking).toHaveTimeSlots(
@ -757,12 +775,14 @@ describe("getSchedule", () => {
createBookingScenario(scenarioData);
const schedule = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(schedule).toHaveTimeSlots(
@ -820,12 +840,14 @@ describe("getSchedule", () => {
createBookingScenario(scenarioData);
const scheduleForEventOnADayWithDateOverride = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(scheduleForEventOnADayWithDateOverride).toHaveTimeSlots(
@ -905,12 +927,14 @@ describe("getSchedule", () => {
// Requesting this user's availability for their
// individual Event Type
const thisUserAvailability = await getSchedule({
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
input: {
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
}
});
expect(thisUserAvailability).toHaveTimeSlots(
@ -1002,12 +1026,14 @@ describe("getSchedule", () => {
});
const scheduleForTeamEventOnADayWithNoBooking = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${todayDateString}T18:30:00.000Z`,
endTime: `${plus1DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${todayDateString}T18:30:00.000Z`,
endTime: `${plus1DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
}
});
expect(scheduleForTeamEventOnADayWithNoBooking).toHaveTimeSlots(
@ -1030,12 +1056,14 @@ describe("getSchedule", () => {
);
const scheduleForTeamEventOnADayWithOneBookingForEachUser = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
}
});
// A user with blocked time in another event, still affects Team Event availability
@ -1137,12 +1165,14 @@ describe("getSchedule", () => {
hosts: [],
});
const scheduleForTeamEventOnADayWithOneBookingForEachUserButOnDifferentTimeslots = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T18:30:00.000Z`,
endTime: `${plus2DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
}
});
// A user with blocked time in another event, still affects Team Event availability
expect(scheduleForTeamEventOnADayWithOneBookingForEachUserButOnDifferentTimeslots).toHaveTimeSlots(
@ -1163,12 +1193,14 @@ describe("getSchedule", () => {
);
const scheduleForTeamEventOnADayWithOneBookingForEachUserOnSameTimeSlot = await getSchedule({
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus2DateString}T18:30:00.000Z`,
endTime: `${plus3DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus2DateString}T18:30:00.000Z`,
endTime: `${plus3DateString}T18:29:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: true,
}
});
// A user with blocked time in another event, still affects Team Event availability
expect(scheduleForTeamEventOnADayWithOneBookingForEachUserOnSameTimeSlot).toHaveTimeSlots(

View File

@ -1,11 +1,17 @@
import type { IncomingMessage } from "http";
import type { TGetScheduleInputSchema } from "./getSchedule.schema";
import { getAvailableSlots } from "./util";
type GetScheduleOptions = {
ctx: Record<string, unknown>;
export type GetScheduleOptions = {
ctx?: ContextForGetSchedule;
input: TGetScheduleInputSchema;
};
export const getScheduleHandler = async ({ input }: GetScheduleOptions) => {
return await getAvailableSlots(input);
interface ContextForGetSchedule extends Record<string, unknown> {
req?: (IncomingMessage & { cookies: Partial<{ [key: string]: string }> }) | undefined;
}
export const getScheduleHandler = async ({ ctx, input }: GetScheduleOptions) => {
return await getAvailableSlots({ ctx, input });
};

View File

@ -7,6 +7,7 @@ import type { CurrentSeats } from "@calcom/core/getUserAvailability";
import { getUserAvailability } from "@calcom/core/getUserAvailability";
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import { getSlugOrRequestedSlug, orgDomainConfig } from "@calcom/ee/organizations/lib/orgDomains";
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
import isTimeOutOfBounds from "@calcom/lib/isOutOfBounds";
import logger from "@calcom/lib/logger";
@ -19,6 +20,7 @@ import type { EventBusyDate } from "@calcom/types/Calendar";
import { TRPCError } from "@trpc/server";
import type { GetScheduleOptions } from "./getSchedule.handler";
import type { TGetScheduleInputSchema } from "./getSchedule.schema";
export const checkIfIsAvailable = ({
@ -74,19 +76,27 @@ async function getEventTypeId({
slug,
eventTypeSlug,
isTeamEvent,
organizationDetails,
}: {
slug?: string;
eventTypeSlug?: string;
isTeamEvent: boolean;
organizationDetails?: { currentOrgDomain: string | null; isValidOrgDomain: boolean };
}) {
if (!eventTypeSlug || !slug) return null;
let teamId;
let userId;
if (isTeamEvent) {
teamId = await getTeamIdFromSlug(slug);
teamId = await getTeamIdFromSlug(
slug,
organizationDetails ?? { currentOrgDomain: null, isValidOrgDomain: false }
);
} else {
userId = await getUserIdFromUsername(slug);
userId = await getUserIdFromUsername(
slug,
organizationDetails ?? { currentOrgDomain: null, isValidOrgDomain: false }
);
}
const eventType = await prisma.eventType.findFirst({
where: {
@ -104,7 +114,10 @@ async function getEventTypeId({
return eventType?.id;
}
export async function getEventType(input: TGetScheduleInputSchema) {
export async function getEventType(
input: TGetScheduleInputSchema,
organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
) {
const { eventTypeSlug, usernameList, isTeamEvent } = input;
const eventTypeId =
input.eventTypeId ||
@ -113,6 +126,7 @@ export async function getEventType(input: TGetScheduleInputSchema) {
slug: usernameList?.[0],
eventTypeSlug: eventTypeSlug,
isTeamEvent,
organizationDetails,
}));
if (!eventTypeId) {
@ -223,12 +237,17 @@ export async function getDynamicEventType(input: TGetScheduleInputSchema) {
});
}
export function getRegularOrDynamicEventType(input: TGetScheduleInputSchema) {
export function getRegularOrDynamicEventType(
input: TGetScheduleInputSchema,
organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
) {
const isDynamicBooking = input.usernameList && input.usernameList.length > 1;
return isDynamicBooking ? getDynamicEventType(input) : getEventType(input);
return isDynamicBooking ? getDynamicEventType(input) : getEventType(input, organizationDetails);
}
export async function getAvailableSlots(input: TGetScheduleInputSchema) {
export async function getAvailableSlots({ input, ctx }: GetScheduleOptions) {
const orgDetails = orgDomainConfig(ctx?.req?.headers.host ?? "");
if (input.debug === true) {
logger.setSettings({ minLevel: "debug" });
}
@ -236,7 +255,7 @@ export async function getAvailableSlots(input: TGetScheduleInputSchema) {
logger.setSettings({ minLevel: "silly" });
}
const startPrismaEventTypeGet = performance.now();
const eventType = await getRegularOrDynamicEventType(input);
const eventType = await getRegularOrDynamicEventType(input, orgDetails);
const endPrismaEventTypeGet = performance.now();
logger.debug(
`Prisma eventType get took ${endPrismaEventTypeGet - startPrismaEventTypeGet}ms for event:${
@ -492,10 +511,15 @@ export async function getAvailableSlots(input: TGetScheduleInputSchema) {
};
}
async function getUserIdFromUsername(username: string) {
async function getUserIdFromUsername(
username: string,
organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
) {
const { currentOrgDomain, isValidOrgDomain } = organizationDetails;
const user = await prisma.user.findFirst({
where: {
username,
organization: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null,
},
select: {
id: true,
@ -504,10 +528,15 @@ async function getUserIdFromUsername(username: string) {
return user?.id;
}
async function getTeamIdFromSlug(slug: string) {
async function getTeamIdFromSlug(
slug: string,
organizationDetails: { currentOrgDomain: string | null; isValidOrgDomain: boolean }
) {
const { currentOrgDomain, isValidOrgDomain } = organizationDetails;
const team = await prisma.team.findFirst({
where: {
slug,
parent: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null,
},
select: {
id: true,