UNPKG

zoomwebinarclient

Version:

A node client for handling Zoom webinars. Can be used to create webinars as well as get webinar attendance. Requires a zoom api and secret key.

432 lines (431 loc) 20.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _ZoomClient_timezone, _ZoomClient_user, _ZoomClient_apiKey, _ZoomClient_secretKey; Object.defineProperty(exports, "__esModule", { value: true }); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const axios_1 = __importDefault(require("axios")); class ZoomClient { constructor({ apiKey, secretKey, timezone, user }) { _ZoomClient_timezone.set(this, void 0); _ZoomClient_user.set(this, void 0); _ZoomClient_apiKey.set(this, void 0); _ZoomClient_secretKey.set(this, void 0); __classPrivateFieldSet(this, _ZoomClient_timezone, timezone !== null && timezone !== void 0 ? timezone : "Asia/Riyadh", "f"); __classPrivateFieldSet(this, _ZoomClient_user, user, "f"); __classPrivateFieldSet(this, _ZoomClient_apiKey, apiKey, "f"); __classPrivateFieldSet(this, _ZoomClient_secretKey, secretKey, "f"); this._zoom = axios_1.default.create({ baseURL: "https://api.zoom.us/v2", }); } getToken() { const tokenExpiry = Math.floor(Date.now() / 1000) + 1000; const token = jsonwebtoken_1.default.sign({ iss: __classPrivateFieldGet(this, _ZoomClient_apiKey, "f"), exp: Math.floor(Date.now() / 1000) + 10000, }, __classPrivateFieldGet(this, _ZoomClient_secretKey, "f")); return token; } createSingleWebinar(_a) { var params = __rest(_a, []); return __awaiter(this, void 0, void 0, function* () { if (!(params.start && params.duration && params.name)) { throw new Error("start, duration, and name are required parameters!"); } return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { var _b, _c; const startTime = new Date(params.start).toISOString(); const registrationCode = params.approval ? registrationTypeToNumber(params.approval) : 0; const requestBody = { topic: params.name, type: 5, start_time: startTime, timezone: __classPrivateFieldGet(this, _ZoomClient_timezone, "f"), settings: { host_video: true, panelists_video: true, hd_video: true, approval_type: registrationCode, auto_recording: (_b = params.recording) !== null && _b !== void 0 ? _b : "none", meeting_authentication: false, alternative_hosts: params.alterantiveHosts ? params.alterantiveHosts.join() : "", }, password: params.password, duration: params.duration, agenda: (_c = params.agenda) !== null && _c !== void 0 ? _c : "", }; const requestURL = params.account ? `users/${params.account}/webinars` : `users/${__classPrivateFieldGet(this, _ZoomClient_user, "f")}/webinars`; try { const response = yield this._zoom.post(requestURL, requestBody, { headers: { Authorization: `Bearer ${this.getToken()}` }, }); const webinarID = `${response.data.id}`; resolve(webinarID); } catch (error) { reject(error); } })); }); } createRecurringWebinar(_a) { var options = __rest(_a, []); return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { var _b, _c, _d; const startTime = new Date(options.start).toISOString(); const registrationCode = options.approval ? registrationTypeToNumber(options.approval) : 0; const requestBody = { topic: options.name, type: 9, start_time: startTime, timezone: __classPrivateFieldGet(this, _ZoomClient_timezone, "f"), password: (_b = options.password) !== null && _b !== void 0 ? _b : undefined, duration: options.duration, agenda: (_c = options.agenda) !== null && _c !== void 0 ? _c : "", settings: { meeting_authentication: false, host_video: true, panelists_video: true, hd_video: true, approval_type: registrationCode, auto_recording: (_d = options.recording) !== null && _d !== void 0 ? _d : "none", }, recurrence: options.type === "daily" ? generateRecurrenceJSON({ type: options.type, interval: options.interval, endAfter: options.endAfter, }) : generateRecurrenceJSON({ type: options.type, interval: options.interval, endAfter: options.endAfter, //@ts-expect-error because if type is week then monthly params are not assignable and vice versa params: options.params, }), }; const requestURL = options.account ? `users/${options.account}/webinars` : `users/${__classPrivateFieldGet(this, _ZoomClient_user, "f")}/webinars`; try { const response = yield this._zoom.post(requestURL, requestBody, { headers: { Authorization: `Bearer ${this.getToken()}` }, }); const webinarID = `${response.data.id}`; resolve(webinarID); } catch (error) { reject(error); } })); }); } registerToWebinar({ webinarID, firstName, lastName, email, }) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { const requestBody = { first_name: firstName, last_name: lastName, email, }; try { const resposne = yield this._zoom.post(`/webinars/${webinarID}/registrants`, requestBody, { headers: { Authorization: `Bearer ${this.getToken()}` }, }); const joinURL = resposne.data.join_url; resolve(joinURL); } catch (error) { reject(error); } })); }); } getWebinarAttendees(webinarID) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const instancesResponse = yield this._zoom.get(`/past_webinars/${webinarID}/instances`, { headers: { Authorization: `Bearer ${this.getToken()}` }, }); // because if its recurring we need to get attendance for every instances. const instances = instancesResponse.data.webinars.map((x) => encodeURIComponent(encodeURIComponent(x.uuid)) // https://marketplace.zoom.us/docs/api-reference/zoom-api/methods/#operation/reportWebinarParticipants yes its this dumb ); var userList = []; // this is what we will eventually resolve for (let i = 0; i < instances.length; i++) { // iterate through instances userList = userList.concat(yield paginationWebinarParticipants(this._zoom, instances[i], this.getToken())); } resolve(userList); } catch (error) { reject(error); } })); }); } deleteWebinar(webinarID) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const res = yield this._zoom.delete(`/webinars/${webinarID}`, { headers: { Authorization: `Bearer ${this.getToken()}` }, }); switch (res.status) { case 204: case 200: resolve(); break; case 300: throw new Error(`Invalid webinar ID. Zoom response: ${res.statusText}`); case 400: throw new Error(`Bad Request. Zoom response: ${res.statusText}`); case 404: throw new Error(`Webinar not found or expired. Zoom response: ${res.statusText}`); } resolve(); } catch (error) { reject(error); } })); }); } updateWebinar(_a) { var params = __rest(_a, []); return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { var _b, _c, _d, _e, _f, _g; const { options } = params; // recurrence always requires a type let recurrenceJSON; if (options.type) { const recurrenceParams = trimNullKeys({ endAfter: options.endAfter, interval: options.interval, type: options.type, // @ts-ignore no clue why not tho params: options.params, }); // @ts-expect-error idk how to validate this one lmao recurrenceJSON = generateRecurrenceJSON(recurrenceParams); } const requestBody = { agenda: (_b = options.agenda) !== null && _b !== void 0 ? _b : null, duration: (_c = options.duration) !== null && _c !== void 0 ? _c : null, password: (_d = options.password) !== null && _d !== void 0 ? _d : null, recurrence: recurrenceJSON !== null && recurrenceJSON !== void 0 ? recurrenceJSON : null, start_time: options.start ? new Date(options.start).toISOString() : null, timezone: (_e = __classPrivateFieldGet(this, _ZoomClient_timezone, "f")) !== null && _e !== void 0 ? _e : null, topic: (_f = options.name) !== null && _f !== void 0 ? _f : null, settings: { meeting_authentication: false, host_video: true, panelists_video: true, hd_video: true, auto_recording: (_g = options.recording) !== null && _g !== void 0 ? _g : "none", approval_type: options.approval ? registrationTypeToNumber(options.approval) : null, alternative_hosts: options.alterantiveHosts ? options.alterantiveHosts.join() : "", }, }; try { const res = yield this._zoom.patch(`/webinars/${params.id}/${params.occurrence_id ? `?occurrence_id=${params.occurrence_id}` : null}`, trimNullKeys(requestBody)); switch (res.status) { case 204: case 200: resolve(res.data); break; case 300: throw new Error(`Invalid webinar ID or invalid recurrence settings. Zoom response: ${res.statusText}`); case 400: throw new Error(`Bad Request. Zoom response: ${res.statusText}`); case 404: throw new Error(`Webinar not found or expired. Zoom response: ${res.statusText}`); } resolve(res.data); } catch (error) { reject(error); } })); }); } } exports.default = ZoomClient; _ZoomClient_timezone = new WeakMap(), _ZoomClient_user = new WeakMap(), _ZoomClient_apiKey = new WeakMap(), _ZoomClient_secretKey = new WeakMap(); // HELPFUL FUNCTIONS const trimNullKeys = (object) => { for (const key in object) { if (Object.prototype.hasOwnProperty.call(object, key)) { const element = object[key]; if (element === null) { delete object[key]; } else { if (typeof element === "object") { trimNullKeys(object[key]); } } } } return object; }; const generateRecurrenceJSON = (options) => { const returnValue = { repeat_interval: options.interval, type: 1 }; if (typeof options.endAfter === "number") { returnValue.end_times = options.endAfter; } else { // @ts-expect-error returnValue.end_date_time = options.endAfter.toISOString(); } switch (options.type) { case "daily": returnValue.type = 1; if (options.interval > 90) throw new Error("Daily interval must be less than or equal 90."); return returnValue; case "monthly": returnValue.type = 3; if (options.interval > 3) throw new Error("Monthly interval must be less than or equal 3"); // @ts-expect-error if (options.params.day) { // @ts-expect-error returnValue.monthly_day = options.params.day; } else { // @ts-expect-error const week = options.params.week; if (!(week >= 1 && week <= 4) && week != -1) throw new Error("Monthly recurrence week must be one of: (-1, 1, 2, 3, 4)"); returnValue.monthly_week = week; // @ts-expect-error returnValue.monthly_week_day = arrayOfWeekdaysToCSS( // @ts-expect-error options.params.weekdays); } return returnValue; case "weekly": returnValue.type = 2; if (options.interval > 12) throw new Error("Weekly interval must be less than or equal 12"); // how do i not need a ts-expect-error here lmao returnValue.weekly_days = arrayOfWeekdaysToCSS(options.params.weekdays); return returnValue; default: throw new Error("Recurrence type must be one of: weekly, monthly, daily"); } }; // css = comma seperated string function arrayOfWeekdaysToCSS(arr) { var returnString = ""; for (let i = 0; i < arr.length; i++) { returnString = returnString.concat(`${weekdaysToCode(arr[i])} ${i != arr.length - 1 ? `,` : ``}`); } return returnString; } function registrationTypeToNumber(registrationType) { switch (registrationType) { case "none": return 2; case "registration": return 0; case "registration+approval": return 1; default: return 2; } } function weekdaysToCode(day) { switch (day) { case "sunday": return 1; case "monday": return 2; case "tuesday": return 3; case "wednesday": return 4; case "thursday": return 5; case "friday": return 6; case "saturday": return 7; default: throw new Error(`weekdays must be one of "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday"`); } } function paginationWebinarParticipants(zoom, webinarID, token, nextPageToken, results) { return __awaiter(this, void 0, void 0, function* () { if (!results) { results = []; } try { const response = yield zoom.get(`/report/webinars/${webinarID}/participants?page_size=300${nextPageToken ? `&nextPageToken=${nextPageToken}` : ``}`, { headers: { Authorization: `Bearer ${token}` }, }); results = results.concat(response.data.participants); if (response.data.next_page_token) { nextPageToken = response.data.next_page_token; return paginationWebinarParticipants(zoom, webinarID, token, nextPageToken, results); } else { return results; } } catch (err) { throw err; } }); }