| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  | import { Credential } from "@prisma/client"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-23 22:00:30 +00:00
										 |  |  | import { BASE_URL } from "@calcom/lib/constants"; | 
					
						
							| 
									
										
										
										
											2022-03-16 23:36:43 +00:00
										 |  |  | import { handleErrorsJson } from "@calcom/lib/errors"; | 
					
						
							| 
									
										
										
										
											2022-03-23 22:00:30 +00:00
										 |  |  | import prisma from "@calcom/prisma"; | 
					
						
							|  |  |  | import type { CalendarEvent } from "@calcom/types/Calendar"; | 
					
						
							|  |  |  | import type { PartialReference } from "@calcom/types/EventManager"; | 
					
						
							|  |  |  | import type { VideoApiAdapter, VideoCallData } from "@calcom/types/VideoApiAdapter"; | 
					
						
							| 
									
										
										
										
											2022-03-16 23:36:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-23 22:00:30 +00:00
										 |  |  | /** @link https://docs.daily.co/reference/rest-api/rooms/create-room */ | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  | export interface DailyReturnType { | 
					
						
							|  |  |  |   /** Long UID string ie: 987b5eb5-d116-4a4e-8e2c-14fcb5710966 */ | 
					
						
							|  |  |  |   id: string; | 
					
						
							|  |  |  |   /** Not a real name, just a random generated string ie: "ePR84NQ1bPigp79dDezz" */ | 
					
						
							|  |  |  |   name: string; | 
					
						
							|  |  |  |   api_created: boolean; | 
					
						
							|  |  |  |   privacy: "private" | "public"; | 
					
						
							|  |  |  |   /** https://api-demo.daily.co/ePR84NQ1bPigp79dDezz */ | 
					
						
							|  |  |  |   url: string; | 
					
						
							|  |  |  |   created_at: string; | 
					
						
							|  |  |  |   config: { | 
					
						
							| 
									
										
										
										
											2022-03-23 22:00:30 +00:00
										 |  |  |     /** Timestamps expressed in seconds, not in milliseconds */ | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |     nbf: number; | 
					
						
							| 
									
										
										
										
											2022-03-23 22:00:30 +00:00
										 |  |  |     /** Timestamps expressed in seconds, not in milliseconds */ | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |     exp: number; | 
					
						
							|  |  |  |     enable_chat: boolean; | 
					
						
							|  |  |  |     enable_knocking: boolean; | 
					
						
							|  |  |  |     enable_prejoin_ui: boolean; | 
					
						
							|  |  |  |     enable_new_call_ui: boolean; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export interface DailyEventResult { | 
					
						
							|  |  |  |   id: string; | 
					
						
							|  |  |  |   name: string; | 
					
						
							|  |  |  |   api_created: boolean; | 
					
						
							|  |  |  |   privacy: string; | 
					
						
							|  |  |  |   url: string; | 
					
						
							|  |  |  |   created_at: string; | 
					
						
							|  |  |  |   config: Record<string, unknown>; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export interface DailyVideoCallData { | 
					
						
							|  |  |  |   type: string; | 
					
						
							|  |  |  |   id: string; | 
					
						
							|  |  |  |   password: string; | 
					
						
							|  |  |  |   url: string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type DailyKey = { | 
					
						
							|  |  |  |   apikey: string; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-23 22:00:30 +00:00
										 |  |  | /** @deprecated use metadata on index file */ | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  | export const FAKE_DAILY_CREDENTIAL: Credential = { | 
					
						
							|  |  |  |   id: +new Date().getTime(), | 
					
						
							|  |  |  |   type: "daily_video", | 
					
						
							|  |  |  |   key: { apikey: process.env.DAILY_API_KEY }, | 
					
						
							|  |  |  |   userId: +new Date().getTime(), | 
					
						
							| 
									
										
										
										
											2022-05-02 20:39:35 +00:00
										 |  |  |   appId: "daily-video", | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const DailyVideoApiAdapter = (credential: Credential): VideoApiAdapter => { | 
					
						
							|  |  |  |   const dailyApiToken = (credential.key as DailyKey).apikey; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function postToDailyAPI(endpoint: string, body: Record<string, any>) { | 
					
						
							|  |  |  |     return fetch("https://api.daily.co/v1" + endpoint, { | 
					
						
							|  |  |  |       method: "POST", | 
					
						
							|  |  |  |       headers: { | 
					
						
							|  |  |  |         Authorization: "Bearer " + dailyApiToken, | 
					
						
							|  |  |  |         "Content-Type": "application/json", | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       body: JSON.stringify(body), | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-26 11:03:43 +00:00
										 |  |  |   async function createOrUpdateMeeting(endpoint: string, event: CalendarEvent): Promise<VideoCallData> { | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |     if (!event.uid) { | 
					
						
							|  |  |  |       throw new Error("We need need the booking uid to create the Daily reference in DB"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const response = await postToDailyAPI(endpoint, translateEvent(event)); | 
					
						
							|  |  |  |     const dailyEvent: DailyReturnType = await handleErrorsJson(response); | 
					
						
							|  |  |  |     const res = await postToDailyAPI("/meeting-tokens", { | 
					
						
							|  |  |  |       properties: { room_name: dailyEvent.name, is_owner: true }, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const meetingToken: { token: string } = await handleErrorsJson(res); | 
					
						
							|  |  |  |     await prisma.dailyEventReference.create({ | 
					
						
							|  |  |  |       data: { | 
					
						
							|  |  |  |         dailyurl: dailyEvent.url, | 
					
						
							|  |  |  |         dailytoken: meetingToken.token, | 
					
						
							|  |  |  |         booking: { | 
					
						
							|  |  |  |           connect: { | 
					
						
							|  |  |  |             uid: event.uid, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-26 11:03:43 +00:00
										 |  |  |     return Promise.resolve({ | 
					
						
							|  |  |  |       type: "daily_video", | 
					
						
							|  |  |  |       id: dailyEvent.name, | 
					
						
							|  |  |  |       password: "", | 
					
						
							| 
									
										
										
										
											2022-02-15 12:46:27 +00:00
										 |  |  |       url: BASE_URL + "/video/" + event.uid, | 
					
						
							| 
									
										
										
										
											2021-11-26 11:03:43 +00:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const translateEvent = (event: CalendarEvent) => { | 
					
						
							|  |  |  |     // Documentation at: https://docs.daily.co/reference#list-rooms
 | 
					
						
							| 
									
										
										
										
											2022-02-19 00:39:10 +00:00
										 |  |  |     // added a 1 hour buffer for room expiration
 | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |     const exp = Math.round(new Date(event.endTime).getTime() / 1000) + 60 * 60; | 
					
						
							| 
									
										
										
										
											2021-11-16 14:12:10 +00:00
										 |  |  |     const scalePlan = process.env.DAILY_SCALE_PLAN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (scalePlan === "true") { | 
					
						
							|  |  |  |       return { | 
					
						
							| 
									
										
										
										
											2022-01-11 10:24:37 +00:00
										 |  |  |         privacy: "public", | 
					
						
							| 
									
										
										
										
											2021-11-16 14:12:10 +00:00
										 |  |  |         properties: { | 
					
						
							|  |  |  |           enable_new_call_ui: true, | 
					
						
							|  |  |  |           enable_prejoin_ui: true, | 
					
						
							|  |  |  |           enable_knocking: true, | 
					
						
							|  |  |  |           enable_screenshare: true, | 
					
						
							|  |  |  |           enable_chat: true, | 
					
						
							|  |  |  |           exp: exp, | 
					
						
							|  |  |  |           enable_recording: "local", | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2022-01-11 10:24:37 +00:00
										 |  |  |       privacy: "public", | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |       properties: { | 
					
						
							|  |  |  |         enable_new_call_ui: true, | 
					
						
							|  |  |  |         enable_prejoin_ui: true, | 
					
						
							|  |  |  |         enable_knocking: true, | 
					
						
							|  |  |  |         enable_screenshare: true, | 
					
						
							|  |  |  |         enable_chat: true, | 
					
						
							|  |  |  |         exp: exp, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     /** Daily doesn't need to return busy times, so we return empty */ | 
					
						
							|  |  |  |     getAvailability: () => { | 
					
						
							|  |  |  |       return Promise.resolve([]); | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-11-26 11:03:43 +00:00
										 |  |  |     createMeeting: async (event: CalendarEvent): Promise<VideoCallData> => | 
					
						
							|  |  |  |       createOrUpdateMeeting("/rooms", event), | 
					
						
							|  |  |  |     deleteMeeting: async (uid: string): Promise<void> => { | 
					
						
							|  |  |  |       await fetch("https://api.daily.co/v1/rooms/" + uid, { | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |         method: "DELETE", | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |           Authorization: "Bearer " + dailyApiToken, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2021-11-26 11:03:43 +00:00
										 |  |  |       }).then(handleErrorsJson); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return Promise.resolve(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     updateMeeting: (bookingRef: PartialReference, event: CalendarEvent): Promise<VideoCallData> => | 
					
						
							|  |  |  |       createOrUpdateMeeting("/rooms/" + bookingRef.uid, event), | 
					
						
							| 
									
										
										
										
											2021-10-26 16:17:24 +00:00
										 |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default DailyVideoApiAdapter; |