* feat: link email to participatn * fix: bugs * refactor: improve code * refactor: prevent repload * chore: remove unued * fix: type * refactor * fix: type * feat: restrict host * feat: type * feat: tests * fix: don't allow guest * fix: merk guest * fix: bugs * fix: test * fix: test * refactor: feedback * fix: tests --------- Co-authored-by: Volnei Munhoz <volnei.munhoz@gmail.com>
95 lines
3.4 KiB
TypeScript
95 lines
3.4 KiB
TypeScript
import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";
|
|
import { NextResponse } from "next/server";
|
|
import type { NextRequest } from "next/server";
|
|
import { z } from "zod";
|
|
|
|
import {
|
|
generateGuestMeetingTokenFromOwnerMeetingToken,
|
|
updateMeetingTokenIfExpired,
|
|
} from "@calcom/app-store/dailyvideo/lib/VideoApiAdapter";
|
|
import { getHostsAndGuests } from "@calcom/features/bookings/lib/getHostsAndGuests";
|
|
import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository";
|
|
import { getCalVideoReference } from "@calcom/features/get-cal-video-reference";
|
|
import { VideoCallGuestRepository } from "@calcom/features/video-call-guest/repositories/VideoCallGuestRepository";
|
|
import prisma from "@calcom/prisma";
|
|
import { validateCsrfToken } from "@calcom/web/lib/validateCsrfToken";
|
|
|
|
const videoCallGuestWithCsrfSchema = z.object({
|
|
bookingUid: z.string(),
|
|
email: z.string().email(),
|
|
name: z.string().min(1),
|
|
csrfToken: z.string().length(64, "Invalid CSRF token"),
|
|
});
|
|
|
|
async function handler(req: NextRequest) {
|
|
let appDirRequestBody;
|
|
try {
|
|
appDirRequestBody = await req.json();
|
|
} catch {
|
|
return NextResponse.json({ success: false, message: "Invalid JSON" }, { status: 400 });
|
|
}
|
|
|
|
const guestData = videoCallGuestWithCsrfSchema.parse(appDirRequestBody);
|
|
|
|
const csrfError = await validateCsrfToken(guestData.csrfToken);
|
|
if (csrfError) {
|
|
return csrfError;
|
|
}
|
|
|
|
const bookingRepo = new BookingRepository(prisma);
|
|
const booking = await bookingRepo.findBookingIncludeCalVideoSettingsAndReferences({
|
|
bookingUid: guestData.bookingUid,
|
|
});
|
|
|
|
if (!booking) {
|
|
return NextResponse.json({ error: "Booking not found" }, { status: 404 });
|
|
}
|
|
|
|
const { hosts, guests } = getHostsAndGuests(booking);
|
|
const isHost = hosts.some((host) => host.email.toLowerCase() === guestData.email.trim().toLowerCase());
|
|
const isGuest = guests.some((guest) => guest.email.toLowerCase() === guestData.email.trim().toLowerCase());
|
|
|
|
if (isHost) {
|
|
return NextResponse.json({ error: "hosts_must_use_login" }, { status: 403 });
|
|
} else if (!isGuest) {
|
|
return NextResponse.json({ error: "invalid_guest_email" }, { status: 403 });
|
|
}
|
|
|
|
const videoCallGuestRepo = new VideoCallGuestRepository(prisma);
|
|
const guestSession = await videoCallGuestRepo.upsertVideoCallGuest({
|
|
bookingUid: guestData.bookingUid,
|
|
email: guestData.email,
|
|
name: guestData.name,
|
|
});
|
|
|
|
const videoReference = getCalVideoReference(booking.references);
|
|
|
|
if (!videoReference) {
|
|
return NextResponse.json({ error: "Video reference not found" }, { status: 404 });
|
|
}
|
|
|
|
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: videoReference.id,
|
|
roomName: videoReference.uid,
|
|
meetingToken: videoReference.meetingPassword,
|
|
exp: epochTimeFourteenDaysAfter,
|
|
});
|
|
|
|
const guestMeetingPassword = await generateGuestMeetingTokenFromOwnerMeetingToken({
|
|
meetingToken: videoReferencePassword,
|
|
userId: guestSession.id,
|
|
});
|
|
|
|
return NextResponse.json({
|
|
guestSessionId: guestSession.id,
|
|
meetingPassword: guestMeetingPassword,
|
|
meetingUrl: videoReference.meetingUrl,
|
|
});
|
|
}
|
|
|
|
export const POST = defaultResponderForAppDir(handler);
|