Files
calendar/apps/web/lib/video/[uid]/getServerSideProps.ts
T

309 lines
9.4 KiB
TypeScript

import MarkdownIt from "markdown-it";
import type { GetServerSidePropsContext } from "next";
import {
generateGuestMeetingTokenFromOwnerMeetingToken,
setEnableRecordingUIAndUserIdForOrganizer,
updateMeetingTokenIfExpired,
} from "@calcom/app-store/dailyvideo/lib/VideoApiAdapter";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
import { getCalVideoReference } from "@calcom/features/get-cal-video-reference";
import { CAL_VIDEO_MEETING_LINK_FOR_TESTING } from "@calcom/lib/constants";
import { isENVDev } from "@calcom/lib/env";
import { BookingRepository } from "@calcom/lib/server/repository/booking";
import { EventTypeRepository } from "@calcom/lib/server/repository/eventTypeRepository";
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
import { UserRepository } from "@calcom/lib/server/repository/user";
import prisma from "@calcom/prisma";
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
type CalVideoSettings = {
disableRecordingForGuests: boolean;
disableRecordingForOrganizer: boolean;
enableAutomaticTranscription: boolean;
enableAutomaticRecordingForOrganizer: boolean;
disableTranscriptionForGuests: boolean;
disableTranscriptionForOrganizer: boolean;
};
const shouldEnableRecordButton = ({
hasTeamPlan,
calVideoSettings,
isOrganizer,
}: {
hasTeamPlan: boolean;
calVideoSettings?: CalVideoSettings | null;
isOrganizer: boolean;
}) => {
if (!hasTeamPlan) return false;
if (!calVideoSettings) return true;
if (isOrganizer) {
return !calVideoSettings.disableRecordingForOrganizer;
}
return !calVideoSettings.disableRecordingForGuests;
};
const shouldEnableAutomaticTranscription = ({
hasTeamPlan,
calVideoSettings,
}: {
hasTeamPlan: boolean;
calVideoSettings?: CalVideoSettings | null;
}) => {
if (!hasTeamPlan) return false;
if (!calVideoSettings) return false;
return !!calVideoSettings.enableAutomaticTranscription;
};
const shouldEnableAutomaticRecording = ({
hasTeamPlan,
calVideoSettings,
isOrganizer,
}: {
hasTeamPlan: boolean;
calVideoSettings?: CalVideoSettings | null;
isOrganizer: boolean;
}) => {
if (!hasTeamPlan || !isOrganizer) return false;
if (!calVideoSettings) return false;
return !!calVideoSettings.enableAutomaticRecordingForOrganizer;
};
const shouldEnableTranscriptionButton = ({
hasTeamPlan,
calVideoSettings,
isOrganizer,
}: {
hasTeamPlan: boolean;
calVideoSettings?: CalVideoSettings | null;
isOrganizer: boolean;
}) => {
if (!hasTeamPlan) return false;
if (!calVideoSettings) return true;
if (isOrganizer) {
return !calVideoSettings.disableTranscriptionForOrganizer;
}
return !calVideoSettings.disableTranscriptionForGuests;
};
const checkIfUserIsHost = async ({
booking,
sessionUserId,
}: {
booking: {
user: { id: number } | null;
eventTypeId: number | undefined;
};
sessionUserId?: number;
}) => {
if (!sessionUserId) return false;
if (!booking.eventTypeId) {
return booking.user?.id === sessionUserId;
}
const eventTypeRepo = new EventTypeRepository(prisma);
const eventType = await eventTypeRepo.findByIdWithUserAccess({
id: booking.eventTypeId,
userId: sessionUserId,
});
// If eventType exists, it means user is either owner, host or user
return !!eventType;
};
export async function getServerSideProps(context: GetServerSidePropsContext) {
const { req } = context;
const bookingRepo = new BookingRepository(prisma);
const booking = await bookingRepo.findBookingForMeetingPage({
bookingUid: context.query.uid as string,
});
// Below if block is for local testing purposes only
// STARTS------------------------------------------------------------------------------
if (booking?.references[0] && isENVDev && CAL_VIDEO_MEETING_LINK_FOR_TESTING) {
// meetingUrl is `null` in dev env, so setting a dummy meetingUrl (it's a past but real meeting link in production env)
booking.references[0].meetingUrl = CAL_VIDEO_MEETING_LINK_FOR_TESTING;
}
// ENDS--------------------------------------------------------------------------------
if (!booking || booking.references.length === 0 || !booking.references[0].meetingUrl) {
return {
redirect: {
destination: "/video/no-meeting-found",
permanent: false,
},
};
}
const hasTeamPlan = booking.user?.id
? await prisma.membership.findFirst({
where: {
userId: booking.user.id,
team: {
slug: {
not: null,
},
},
},
})
: false;
const userRepo = new UserRepository(prisma);
const profile = booking.user
? (
await userRepo.enrichUserWithItsProfile({
user: booking.user,
})
).profile
: null;
const calVideoLogo = profile?.organization
? await OrganizationRepository.findCalVideoLogoByOrgId({ id: profile.organization.id })
: null;
//daily.co calls have a 14 days exit buffer when a user enters a call when it's not available it will trigger the modals
const now = new Date();
const exitDate = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1000);
//find out if the meeting is in the past
const isPast = booking?.endTime <= exitDate;
const testingUid =
CAL_VIDEO_MEETING_LINK_FOR_TESTING && CAL_VIDEO_MEETING_LINK_FOR_TESTING?.split("/").pop();
const isTestingLink = booking?.uid === testingUid;
if (isPast && !isTestingLink) {
return {
redirect: {
destination: `/video/meeting-ended/${booking?.uid}`,
permanent: false,
},
};
}
const bookingObj = Object.assign({}, booking, {
startTime: booking.startTime.toString(),
endTime: booking.endTime.toString(),
});
const session = await getServerSession({ req });
const oldVideoReference = getCalVideoReference(bookingObj.references);
const endTime = new Date(booking.endTime);
const fourteenDaysAfter = new Date(endTime.getTime() + 14 * 24 * 60 * 60 * 1000);
const epochTimeFourteenDaysAfter = Math.floor(fourteenDaysAfter.getTime() / 1000);
const videoReferencePassword = await updateMeetingTokenIfExpired({
bookingReferenceId: oldVideoReference.id,
roomName: oldVideoReference.uid,
meetingToken: oldVideoReference.meetingPassword,
exp: epochTimeFourteenDaysAfter,
});
const sessionUserId = !!session?.user?.impersonatedBy ? session.user.impersonatedBy.id : session?.user.id;
const isOrganizer = await checkIfUserIsHost({
booking: {
eventTypeId: bookingObj.eventType?.id,
user: bookingObj.user,
},
sessionUserId,
});
// set meetingPassword for guests
if (!isOrganizer) {
const guestMeetingPassword = await generateGuestMeetingTokenFromOwnerMeetingToken({
meetingToken: videoReferencePassword,
userId: sessionUserId,
});
bookingObj.references.forEach((bookRef) => {
bookRef.meetingPassword = guestMeetingPassword;
});
}
// Only for backward compatibility and setting user id in participants for organizer
else {
const meetingPassword = await setEnableRecordingUIAndUserIdForOrganizer(
oldVideoReference.id,
videoReferencePassword,
sessionUserId
);
if (!!meetingPassword) {
bookingObj.references.forEach((bookRef) => {
bookRef.meetingPassword = meetingPassword;
});
}
}
const videoReference = getCalVideoReference(bookingObj.references);
const featureRepo = new FeaturesRepository(prisma);
const displayLogInOverlay = profile?.organizationId
? await featureRepo.checkIfTeamHasFeature(profile.organizationId, "cal-video-log-in-overlay")
: false;
const showRecordingButton = shouldEnableRecordButton({
hasTeamPlan: !!hasTeamPlan,
calVideoSettings: bookingObj.eventType?.calVideoSettings,
isOrganizer,
});
const enableAutomaticTranscription = shouldEnableAutomaticTranscription({
hasTeamPlan: !!hasTeamPlan,
calVideoSettings: bookingObj.eventType?.calVideoSettings,
});
const enableAutomaticRecordingForOrganizer = shouldEnableAutomaticRecording({
hasTeamPlan: !!hasTeamPlan,
calVideoSettings: bookingObj.eventType?.calVideoSettings,
isOrganizer,
});
const showTranscriptionButton = shouldEnableTranscriptionButton({
hasTeamPlan: !!hasTeamPlan,
calVideoSettings: bookingObj.eventType?.calVideoSettings,
isOrganizer,
});
return {
props: {
meetingUrl: videoReference.meetingUrl ?? "",
...(typeof videoReference.meetingPassword === "string" && {
meetingPassword: videoReference.meetingPassword,
}),
booking: {
...bookingObj,
...(bookingObj.description && { description: md.render(bookingObj.description) }),
user: bookingObj.user
? {
...bookingObj.user,
organization: profile?.organization,
}
: bookingObj.user,
},
hasTeamPlan: !!hasTeamPlan,
calVideoLogo,
displayLogInOverlay,
loggedInUserName: sessionUserId ? session?.user?.name : undefined,
showRecordingButton,
enableAutomaticTranscription,
enableAutomaticRecordingForOrganizer,
showTranscriptionButton,
rediectAttendeeToOnExit: isOrganizer
? undefined
: bookingObj.eventType?.calVideoSettings?.redirectUrlOnExit,
overrideName: Array.isArray(context.query.name) ? context.query.name[0] : context.query.name,
},
};
}