From 783c30c3504d61b1e953d1a39cf0290b260c7e75 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 27 May 2024 13:08:40 -0400 Subject: [PATCH] New Components - hippo_video (#12009) * hippo_video init * [Components] hippo_video #10752 Sources: - New Event Triggered (Instant) Actions - Send Personalization Request - Upload Video - Create Contact * pnpm update * add form-data * pnpm update * some adjusts * Update components/hippo_video/actions/send-personalization-request/send-personalization-request.mjs * some adjusts --------- Co-authored-by: Leo Vu <18277920+vunguyenhung@users.noreply.github.com> --- .../actions/create-contact/create-contact.mjs | 71 ++++++++++++ .../send-personalization-request.mjs | 46 ++++++++ .../actions/upload-video/upload-video.mjs | 37 ++++++ components/hippo_video/common/constants.mjs | 26 +++++ components/hippo_video/common/utils.mjs | 31 +++++ components/hippo_video/hippo_video.app.mjs | 109 +++++++++++++++++- components/hippo_video/package.json | 8 +- .../new-triggered-event-instant.mjs | 67 +++++++++++ pnpm-lock.yaml | 7 +- 9 files changed, 394 insertions(+), 8 deletions(-) create mode 100644 components/hippo_video/actions/create-contact/create-contact.mjs create mode 100644 components/hippo_video/actions/send-personalization-request/send-personalization-request.mjs create mode 100644 components/hippo_video/actions/upload-video/upload-video.mjs create mode 100644 components/hippo_video/common/constants.mjs create mode 100644 components/hippo_video/common/utils.mjs create mode 100644 components/hippo_video/sources/new-triggered-event-instant/new-triggered-event-instant.mjs diff --git a/components/hippo_video/actions/create-contact/create-contact.mjs b/components/hippo_video/actions/create-contact/create-contact.mjs new file mode 100644 index 0000000000000..b2b6694500d2b --- /dev/null +++ b/components/hippo_video/actions/create-contact/create-contact.mjs @@ -0,0 +1,71 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; +import hippoVideo from "../../hippo_video.app.mjs"; + +export default { + key: "hippo_video-create-contact", + name: "Create Contact", + description: "Creates a new contact in Hippo Video. [See the documentation](https://documenter.getpostman.com/view/5278433/Tz5naxpW#a4d73ffe-a2b6-4d68-a1ee-9fbc1417a955)", + version: "0.0.1", + type: "action", + props: { + hippoVideo, + contactEmail: { + type: "string", + label: "Contact Email", + description: "Email Address of the Contact/Lead/Prospect.", + }, + firstName: { + type: "string", + label: "First Name", + description: "First Name of the Contact/Lead/Prospect.", + }, + lastName: { + type: "string", + label: "Last Name", + description: "Last Name of the Contact/Lead/Prospect.", + }, + companyName: { + type: "string", + label: "Company name", + description: "Company Name of the Contact/Lead/Prospect.", + }, + notes: { + type: "string", + label: "Notes", + description: "Notes for the lead/prospect/contact.", + }, + context: { + type: "string", + label: "Context", + description: "If sales, will be added as a prospect. If empty, will be added as people.", + optional: true, + }, + listIds: { + propDefinition: [ + hippoVideo, + "listIds", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.hippoVideo.createContact({ + $, + data: { + contact_email: this.contactEmail, + first_name: this.firstName, + last_name: this.lastName, + company_name: this.companyName, + notes: this.notes, + context: this.context, + list_ids: parseObject(this.listIds)?.join(), + }, + }); + + if (!response.status) throw new ConfigurationError(response.message); + + $.export("$summary", `Successfully created contact with Id: ${response.contact_id}`); + return response; + }, +}; diff --git a/components/hippo_video/actions/send-personalization-request/send-personalization-request.mjs b/components/hippo_video/actions/send-personalization-request/send-personalization-request.mjs new file mode 100644 index 0000000000000..9dfe67b622905 --- /dev/null +++ b/components/hippo_video/actions/send-personalization-request/send-personalization-request.mjs @@ -0,0 +1,46 @@ +import { ConfigurationError } from "@pipedream/platform"; +import FormData from "form-data"; +import fs from "fs"; +import { checkTmp } from "../../common/utils.mjs"; +import hippoVideo from "../../hippo_video.app.mjs"; + +export default { + key: "hippo_video-send-personalization-request", + name: "Send Personalization Request", + description: "Sends a personalization request for a specified video. [See the documentation](https://help.hippovideo.io/support/solutions/articles/19000099793-bulk-video-personalization-and-tracking-api)", + version: "0.0.1", + type: "action", + props: { + hippoVideo, + videoId: { + propDefinition: [ + hippoVideo, + "videoId", + ], + }, + file: { + type: "string", + label: "File", + description: "csv, xls, and xlsx file saved to the [`/tmp` directory](https://pipedream.com/docs/workflows/steps/code/nodejs/working-with-files/#the-tmp-directory). To get file schema, [see documentation](https://help.hippovideo.io/support/solutions/articles/19000099793-bulk-video-personalization-and-tracking-api)", + }, + }, + async run({ $ }) { + const formData = new FormData(); + const file = fs.createReadStream(checkTmp(this.file)); + + formData.append("file", file); + formData.append("video_id", this.videoId); + + const response = await this.hippoVideo.personalizeVideo({ + $, + data: formData, + headers: formData.getHeaders(), + maxBodyLength: Infinity, + }); + + if (response.code != 200) throw new ConfigurationError(response.message || response.type); + + $.export("$summary", `Successfully sent personalization request for video Id: ${this.videoId}`); + return response; + }, +}; diff --git a/components/hippo_video/actions/upload-video/upload-video.mjs b/components/hippo_video/actions/upload-video/upload-video.mjs new file mode 100644 index 0000000000000..847aa58e9994e --- /dev/null +++ b/components/hippo_video/actions/upload-video/upload-video.mjs @@ -0,0 +1,37 @@ +import { ConfigurationError } from "@pipedream/platform"; +import hippoVideo from "../../hippo_video.app.mjs"; + +export default { + key: "hippo_video-upload-video", + name: "Upload Video", + description: "Uploads a video from a given URL. [See the documentation](https://help.hippovideo.io/support/solutions/articles/19000100703-import-api)", + version: "0.0.1", + type: "action", + props: { + hippoVideo, + title: { + type: "string", + label: "Title", + description: "Title of the video.", + }, + url: { + type: "string", + label: "Video URL", + description: "Public URL of the videos to be downloaded and uploaded to HippoVideo.", + }, + }, + async run({ $ }) { + const response = await this.hippoVideo.uploadVideo({ + $, + data: { + title: this.title, + url: this.url, + }, + }); + + if (response.code != "200") throw new ConfigurationError(response.message); + + $.export("$summary", `Video uploaded successfully with Id: ${response.video_id}`); + return response; + }, +}; diff --git a/components/hippo_video/common/constants.mjs b/components/hippo_video/common/constants.mjs new file mode 100644 index 0000000000000..a3fed4e052594 --- /dev/null +++ b/components/hippo_video/common/constants.mjs @@ -0,0 +1,26 @@ +export const EVENT_OPTIONS = [ + { + value: "3", + label: "Viewing Sessions", + }, + { + value: "1", + label: "Video Created", + }, + { + value: "4", + label: "CTA Lead Genaration", + }, + { + value: "5", + label: "CTA Annotations", + }, + { + value: "6", + label: "CT", + }, + { + value: "18", + label: "Video Transcode", + }, +]; diff --git a/components/hippo_video/common/utils.mjs b/components/hippo_video/common/utils.mjs new file mode 100644 index 0000000000000..d1e7ed1a22d98 --- /dev/null +++ b/components/hippo_video/common/utils.mjs @@ -0,0 +1,31 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; + +export const checkTmp = (filename) => { + if (!filename.startsWith("/tmp")) { + return `/tmp/${filename}`; + } + return filename; +}; diff --git a/components/hippo_video/hippo_video.app.mjs b/components/hippo_video/hippo_video.app.mjs index 18c2c58a0e6cd..e6e6ff9448dc9 100644 --- a/components/hippo_video/hippo_video.app.mjs +++ b/components/hippo_video/hippo_video.app.mjs @@ -1,11 +1,110 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "hippo_video", - propDefinitions: {}, + propDefinitions: { + listIds: { + type: "string[]", + label: "List Ids", + description: "A list of lists you want to add the prospect.", + async options({ page }) { + const { contacts_list: data } = await this.listLists({ + params: { + page, + }, + }); + + return data.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + videoId: { + type: "string", + label: "Video ID", + description: "The ID of the video to be personalized.", + async options({ page }) { + const { videos } = await this.listVideos({ + params: { + page: page + 1, + }, + }); + + return videos.map(({ + id: value, title: label, + }) => ({ + label, + value, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://www.hippovideo.io"; + }, + _params(params = {}) { + return { + ...params, + email: `${this.$auth.email}`, + api_key: `${this.$auth.api_key}`, + }; + }, + _makeRequest({ + $ = this, path, params, ...opts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + params: this._params(params), + headers: { + "Accept": "*/*", + }, + ...opts, + }); + }, + createContact(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/contacts", + ...opts, + }); + }, + listLists(opts = {}) { + return this._makeRequest({ + path: "/contacts/names", + ...opts, + }); + }, + listVideos(opts = {}) { + return this._makeRequest({ + path: "/api/v1/me/videos/list", + ...opts, + }); + }, + personalizeVideo(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/api/v1/me/video/bulk_personalize", + ...opts, + }); + }, + uploadVideo(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/api/v1/me/video/import", + ...opts, + }); + }, + updateWebhook(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/webhook", + ...opts, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/hippo_video/package.json b/components/hippo_video/package.json index 017dfdfae0fdb..b1fa650fe4391 100644 --- a/components/hippo_video/package.json +++ b/components/hippo_video/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/hippo_video", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Hippo Video Components", "main": "hippo_video.app.mjs", "keywords": [ @@ -11,5 +11,9 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^1.6.5", + "form-data": "^4.0.0" } -} \ No newline at end of file +} diff --git a/components/hippo_video/sources/new-triggered-event-instant/new-triggered-event-instant.mjs b/components/hippo_video/sources/new-triggered-event-instant/new-triggered-event-instant.mjs new file mode 100644 index 0000000000000..35c5258e13690 --- /dev/null +++ b/components/hippo_video/sources/new-triggered-event-instant/new-triggered-event-instant.mjs @@ -0,0 +1,67 @@ +import { v4 as uuidv4 } from "uuid"; +import { EVENT_OPTIONS } from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; +import hippoVideo from "../../hippo_video.app.mjs"; + +export default { + key: "hippo_video-new-triggered-event-instant", + name: "New Event Triggered (Instant)", + description: "Emit new event when any of the selected events are triggered.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + hippoVideo, + db: "$.service.db", + http: { + type: "$.interface.http", + customResponse: true, + }, + alert: { + type: "alert", + alertType: "warning", + content: "Please note that you can have only one webhook in your Hippo Video account, any change here will overwrite the current webhook configuration.", + }, + eventIds: { + type: "string[]", + label: "Event Ids", + description: "The Id of the events you want to be triggered.", + options: EVENT_OPTIONS, + }, + }, + methods: { + removeHook() { + this.hippoVideo.updateWebhook({ + data: { + url: this.http.endpoint, + secret_key: uuidv4(), + }, + }); + }, + }, + hooks: { + async activate() { + await this.removeHook(); + await this.hippoVideo.updateWebhook({ + data: { + events: parseObject(this.eventIds), + url: this.http.endpoint, + secret_key: uuidv4(), + }, + }); + }, + async deactivate() { + await this.removeHook(); + }, + }, + async run(event) { + const { body } = event; + const ts = Date.parse(body.eventTimestamp || new Date()); + + this.$emit(body, { + id: body.hook?.uuid || body.video_token, + summary: `New event with event name: ${body.eventName || body.type} successfully triggered!`, + ts: ts, + }); + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4faf96a90ed3..98c69fdd69f0e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3920,7 +3920,12 @@ importers: '@pipedream/platform': 1.6.2 components/hippo_video: - specifiers: {} + specifiers: + '@pipedream/platform': ^1.6.5 + form-data: ^4.0.0 + dependencies: + '@pipedream/platform': 1.6.5 + form-data: 4.0.0 components/hive: specifiers: