From 03b056d4d926fb99917c75a9f98f5af33894deb6 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 12 Sep 2024 16:11:34 -0300 Subject: [PATCH 1/3] adhook init --- .../create-calendar-event.mjs | 67 +++++++ .../create-update-post/create-update-post.mjs | 72 +++++++ components/adhook/adhook.app.mjs | 181 +++++++++++++++++- components/adhook/package.json | 2 +- .../new-or-updated-post.mjs | 110 +++++++++++ .../adhook/sources/new-post/new-post.mjs | 98 ++++++++++ .../sources/updated-post/updated-post.mjs | 105 ++++++++++ 7 files changed, 631 insertions(+), 4 deletions(-) create mode 100644 components/adhook/actions/create-calendar-event/create-calendar-event.mjs create mode 100644 components/adhook/actions/create-update-post/create-update-post.mjs create mode 100644 components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs create mode 100644 components/adhook/sources/new-post/new-post.mjs create mode 100644 components/adhook/sources/updated-post/updated-post.mjs diff --git a/components/adhook/actions/create-calendar-event/create-calendar-event.mjs b/components/adhook/actions/create-calendar-event/create-calendar-event.mjs new file mode 100644 index 0000000000000..7f73e9453c2ca --- /dev/null +++ b/components/adhook/actions/create-calendar-event/create-calendar-event.mjs @@ -0,0 +1,67 @@ +import adhook from "../../adhook.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "adhook-create-calendar-event", + name: "Create Calendar Event", + description: "Generates a personalized calendar event in AdHook. [See the documentation](https://app.adhook.io/api-doc/)", + version: "0.0.{{ts}}", + type: "action", + props: { + adhook, + eventName: { + propDefinition: [ + adhook, + "eventName", + ], + }, + startDate: { + propDefinition: [ + adhook, + "startDate", + ], + }, + endDate: { + propDefinition: [ + adhook, + "endDate", + ], + }, + eventDescription: { + propDefinition: [ + adhook, + "eventDescription", + ], + optional: true, + }, + attendees: { + propDefinition: [ + adhook, + "attendees", + ], + optional: true, + }, + attachments: { + propDefinition: [ + adhook, + "attachments", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.adhook.createCalendarEvent({ + data: { + eventName: this.eventName, + startDate: this.startDate, + endDate: this.endDate, + eventDescription: this.eventDescription, + attendees: this.attendees, + attachments: this.attachments, + }, + }); + + $.export("$summary", `Successfully created calendar event: ${this.eventName}`); + return response; + }, +}; diff --git a/components/adhook/actions/create-update-post/create-update-post.mjs b/components/adhook/actions/create-update-post/create-update-post.mjs new file mode 100644 index 0000000000000..761dc7ec35e84 --- /dev/null +++ b/components/adhook/actions/create-update-post/create-update-post.mjs @@ -0,0 +1,72 @@ +import adhook from "../../adhook.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "adhook-create-update-post", + name: "Create or Update Post", + description: "Adds a new post or modifies an existing post in Adhook. [See the documentation](https://app.adhook.io/api-doc/)", + version: "0.0.{{ts}}", + type: "action", + props: { + adhook, + postId: { + propDefinition: [ + adhook, + "postId", + ], + optional: true, + }, + postContent: { + propDefinition: [ + adhook, + "postContent", + ], + }, + visibility: { + propDefinition: [ + adhook, + "visibility", + ], + }, + postAttachments: { + propDefinition: [ + adhook, + "postAttachments", + ], + optional: true, + }, + mentionUsers: { + propDefinition: [ + adhook, + "mentionUsers", + ], + optional: true, + }, + }, + async run({ $ }) { + const data = { + postContent: this.postContent, + visibility: this.visibility, + postAttachments: this.postAttachments, + mentionUsers: this.mentionUsers, + }; + + if (this.postId) { + data.postId = this.postId; + } + + const response = await axios($, { + method: "POST", + url: `${this.adhook._baseUrl()}/posts`, + headers: { + Authorization: `Bearer ${this.adhook.$auth.oauth_access_token}`, + }, + data, + }); + + $.export("$summary", `Successfully ${this.postId + ? "updated" + : "created"} post`); + return response; + }, +}; diff --git a/components/adhook/adhook.app.mjs b/components/adhook/adhook.app.mjs index bfbca6eb55ab1..341a6c8c5d7d7 100644 --- a/components/adhook/adhook.app.mjs +++ b/components/adhook/adhook.app.mjs @@ -1,11 +1,186 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "adhook", - propDefinitions: {}, + propDefinitions: { + postType: { + type: "string", + label: "Post Type", + description: "The type of the post", + optional: true, + }, + postAuthor: { + type: "string", + label: "Post Author", + description: "The author of the post", + optional: true, + }, + postTags: { + type: "string[]", + label: "Post Tags", + description: "Tags associated with the post", + optional: true, + }, + postId: { + type: "string", + label: "Post ID", + description: "The ID of the post", + }, + isNew: { + type: "boolean", + label: "Is New", + description: "Indicates if the post is new", + optional: true, + }, + updateType: { + type: "string", + label: "Update Type", + description: "Type of update made to the post", + optional: true, + }, + eventName: { + type: "string", + label: "Event Name", + description: "Name of the calendar event", + }, + startDate: { + type: "string", + label: "Start Date", + description: "Start date of the event", + }, + endDate: { + type: "string", + label: "End Date", + description: "End date of the event", + }, + eventDescription: { + type: "string", + label: "Event Description", + description: "Description of the event", + optional: true, + }, + attendees: { + type: "string[]", + label: "Attendees", + description: "List of attendees for the event", + optional: true, + }, + attachments: { + type: "string[]", + label: "Attachments", + description: "Attachments for the event", + optional: true, + }, + postContent: { + type: "string", + label: "Post Content", + description: "Content of the post", + }, + visibility: { + type: "string", + label: "Visibility", + description: "Visibility setting of the post", + }, + postAttachments: { + type: "string[]", + label: "Post Attachments", + description: "Attachments for the post", + optional: true, + }, + mentionUsers: { + type: "string[]", + label: "Mention Users", + description: "Users to mention in the post", + optional: true, + }, + }, methods: { - // this.$auth contains connected account data + _baseUrl() { + return "https://app.adhook.io/api"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, method = "GET", path = "/", headers, ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }, + }); + }, + async emitNewPostEvent(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/events/new_post", + data: { + postType: this.postType, + postAuthor: this.postAuthor, + postTags: this.postTags, + }, + ...opts, + }); + }, + async emitPostCreatedOrUpdatedEvent(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/events/post_created_or_updated", + data: { + postId: this.postId, + postAuthor: this.postAuthor, + postTags: this.postTags, + isNew: this.isNew, + }, + ...opts, + }); + }, + async emitPostUpdatedEvent(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/events/post_updated", + data: { + postId: this.postId, + postAuthor: this.postAuthor, + postTags: this.postTags, + updateType: this.updateType, + }, + ...opts, + }); + }, + async createCalendarEvent(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/events/calendar", + data: { + eventName: this.eventName, + startDate: this.startDate, + endDate: this.endDate, + eventDescription: this.eventDescription, + attendees: this.attendees, + attachments: this.attachments, + }, + ...opts, + }); + }, + async addOrUpdatePost(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/posts", + data: { + postContent: this.postContent, + visibility: this.visibility, + postAttachments: this.postAttachments, + mentionUsers: this.mentionUsers, + }, + ...opts, + }); + }, authKeys() { console.log(Object.keys(this.$auth)); }, }, -}; \ No newline at end of file +}; diff --git a/components/adhook/package.json b/components/adhook/package.json index bf2afd366cb66..7f87156e011f1 100644 --- a/components/adhook/package.json +++ b/components/adhook/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs b/components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs new file mode 100644 index 0000000000000..705effe572388 --- /dev/null +++ b/components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs @@ -0,0 +1,110 @@ +import adhook from "../../adhook.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "adhook-new-or-updated-post", + name: "New or Updated Post", + description: "Emit new event when a new post is created or an existing post is updated. [See the documentation](https://app.adhook.io/api-doc/)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + adhook, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60, + }, + }, + postId: { + propDefinition: [ + adhook, + "postId", + ], + }, + postAuthor: { + propDefinition: [ + adhook, + "postAuthor", + ], + optional: true, + }, + postTags: { + propDefinition: [ + adhook, + "postTags", + ], + optional: true, + }, + isNew: { + propDefinition: [ + adhook, + "isNew", + ], + optional: true, + }, + }, + hooks: { + async deploy() { + const events = await this.adhook.emitPostCreatedOrUpdatedEvent({ + postId: this.postId, + postAuthor: this.postAuthor, + postTags: this.postTags, + isNew: this.isNew, + }); + + for (const event of events.slice(0, 50)) { + this.$emit(event, { + id: event.postId, + summary: `Post ${event.isNew + ? "created" + : "updated"}: ${event.postId}`, + ts: Date.now(), + }); + } + }, + async activate() { + // Activate hook logic if needed + }, + async deactivate() { + // Deactivate hook logic if needed + }, + }, + methods: { + _getLastTimestamp() { + return this.db.get("lastTimestamp") || 0; + }, + _setLastTimestamp(ts) { + this.db.set("lastTimestamp", ts); + }, + }, + async run() { + const lastTimestamp = this._getLastTimestamp(); + const events = await this.adhook.emitPostCreatedOrUpdatedEvent({ + postId: this.postId, + postAuthor: this.postAuthor, + postTags: this.postTags, + isNew: this.isNew, + }); + + for (const event of events) { + const eventTimestamp = new Date(event.updatedAt).getTime(); + if (eventTimestamp > lastTimestamp) { + this.$emit(event, { + id: event.postId, + summary: `Post ${event.isNew + ? "created" + : "updated"}: ${event.postId}`, + ts: eventTimestamp, + }); + } + } + + if (events.length > 0) { + const latestEvent = events[0]; + const latestTimestamp = new Date(latestEvent.updatedAt).getTime(); + this._setLastTimestamp(latestTimestamp); + } + }, +}; diff --git a/components/adhook/sources/new-post/new-post.mjs b/components/adhook/sources/new-post/new-post.mjs new file mode 100644 index 0000000000000..88c84775c189b --- /dev/null +++ b/components/adhook/sources/new-post/new-post.mjs @@ -0,0 +1,98 @@ +import { axios } from "@pipedream/platform"; +import adhook from "../../adhook.app.mjs"; + +export default { + key: "adhook-new-post", + name: "New Post Created", + description: "Emit new event when a new post is created. [See the documentation](https://app.adhook.io/api-doc/)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + adhook, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60, + }, + }, + postType: { + propDefinition: [ + adhook, + "postType", + ], + }, + postAuthor: { + propDefinition: [ + adhook, + "postAuthor", + ], + }, + postTags: { + propDefinition: [ + adhook, + "postTags", + ], + }, + }, + hooks: { + async deploy() { + const posts = await this.adhook.emitNewPostEvent({ + params: { + postType: this.postType, + postAuthor: this.postAuthor, + postTags: this.postTags, + }, + }); + + for (const post of posts.slice(0, 50)) { + this.$emit(post, { + id: post.id, + summary: `New Post: ${post.title}`, + ts: new Date(post.createdAt).getTime(), + }); + } + }, + async activate() { + // Activate hook, if needed + }, + async deactivate() { + // Deactivate hook, if needed + }, + }, + methods: { + _getLastTimestamp() { + return this.db.get("lastTimestamp") || 0; + }, + _setLastTimestamp(timestamp) { + this.db.set("lastTimestamp", timestamp); + }, + }, + async run() { + const lastTimestamp = this._getLastTimestamp(); + + const posts = await this.adhook.emitNewPostEvent({ + params: { + postType: this.postType, + postAuthor: this.postAuthor, + postTags: this.postTags, + }, + }); + + for (const post of posts) { + const postTimestamp = new Date(post.createdAt).getTime(); + if (postTimestamp > lastTimestamp) { + this.$emit(post, { + id: post.id, + summary: `New Post: ${post.title}`, + ts: postTimestamp, + }); + } + } + + if (posts.length > 0) { + this._setLastTimestamp(new Date(posts[0].createdAt).getTime()); + } + }, +}; diff --git a/components/adhook/sources/updated-post/updated-post.mjs b/components/adhook/sources/updated-post/updated-post.mjs new file mode 100644 index 0000000000000..6d480dd09fc53 --- /dev/null +++ b/components/adhook/sources/updated-post/updated-post.mjs @@ -0,0 +1,105 @@ +import { axios } from "@pipedream/platform"; +import adhook from "../../adhook.app.mjs"; + +export default { + key: "adhook-updated-post", + name: "Adhook Updated Post", + description: "Emit new event when a post is updated. [See the documentation](https://app.adhook.io/api-doc/)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + adhook, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60, + }, + }, + postId: { + propDefinition: [ + adhook, + "postId", + ], + }, + postAuthor: { + propDefinition: [ + adhook, + "postAuthor", + ], + optional: true, + }, + postTags: { + propDefinition: [ + adhook, + "postTags", + ], + optional: true, + }, + updateType: { + propDefinition: [ + adhook, + "updateType", + ], + optional: true, + }, + }, + hooks: { + async deploy() { + const posts = await this.adhook.emitPostUpdatedEvent({ + data: { + postId: this.postId, + postAuthor: this.postAuthor, + postTags: this.postTags, + updateType: this.updateType, + }, + }); + + for (const post of posts.slice(0, 50)) { + this.$emit(post, { + id: post.id, + summary: `Post Updated: ${post.title}`, + ts: Date.parse(post.updated_at), + }); + } + }, + async activate() { + // Any activation logic if needed + }, + async deactivate() { + // Any deactivation logic if needed + }, + }, + methods: { + _getLastTimestamp() { + return this.db.get("lastTimestamp") || 0; + }, + _setLastTimestamp(ts) { + this.db.set("lastTimestamp", ts); + }, + }, + async run() { + const lastTimestamp = this._getLastTimestamp(); + const posts = await this.adhook.emitPostUpdatedEvent({ + data: { + postId: this.postId, + postAuthor: this.postAuthor, + postTags: this.postTags, + updateType: this.updateType, + }, + }); + + for (const post of posts) { + const postTimestamp = Date.parse(post.updated_at); + if (postTimestamp > lastTimestamp) { + this.$emit(post, { + id: post.id, + summary: `Post Updated: ${post.title}`, + ts: postTimestamp, + }); + this._setLastTimestamp(postTimestamp); + } + } + }, +}; From a7a1e750293f2411d8db711e7e95b997de834253 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 16 Sep 2024 12:37:21 -0300 Subject: [PATCH 2/3] [Components] adhook #13804 Sources - New Post Created - New Post Updated Actions - Create Calendar Event - Create Or Update Post --- .../create-calendar-event.mjs | 95 +++++--- .../create-update-post/create-update-post.mjs | 118 +++++++--- components/adhook/adhook.app.mjs | 212 +++++++----------- components/adhook/common/constants.mjs | 59 +++++ components/adhook/common/utils.mjs | 24 ++ components/adhook/package.json | 5 +- components/adhook/sources/common/base.mjs | 54 +++++ .../new-or-updated-post.mjs | 110 --------- .../adhook/sources/new-post/new-post.mjs | 99 ++------ .../adhook/sources/new-post/test-event.mjs | 50 +++++ .../sources/updated-post/test-event.mjs | 50 +++++ .../sources/updated-post/updated-post.mjs | 110 ++------- 12 files changed, 506 insertions(+), 480 deletions(-) create mode 100644 components/adhook/common/constants.mjs create mode 100644 components/adhook/common/utils.mjs create mode 100644 components/adhook/sources/common/base.mjs delete mode 100644 components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs create mode 100644 components/adhook/sources/new-post/test-event.mjs create mode 100644 components/adhook/sources/updated-post/test-event.mjs diff --git a/components/adhook/actions/create-calendar-event/create-calendar-event.mjs b/components/adhook/actions/create-calendar-event/create-calendar-event.mjs index 7f73e9453c2ca..8cfe8e244f647 100644 --- a/components/adhook/actions/create-calendar-event/create-calendar-event.mjs +++ b/components/adhook/actions/create-calendar-event/create-calendar-event.mjs @@ -1,67 +1,108 @@ import adhook from "../../adhook.app.mjs"; -import { axios } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "adhook-create-calendar-event", name: "Create Calendar Event", description: "Generates a personalized calendar event in AdHook. [See the documentation](https://app.adhook.io/api-doc/)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { adhook, - eventName: { - propDefinition: [ - adhook, - "eventName", - ], + title: { + type: "string", + label: "Event Title", + description: "The title of the calendar event", + optional: true, + }, + description: { + type: "string", + label: "Event Description", + description: "The description of the calendar event", + optional: true, }, - startDate: { + externalId: { propDefinition: [ adhook, - "startDate", + "externalId", ], + optional: true, + }, + start: { + type: "string", + label: "Start Date", + description: "Start date of the event. **Format: YYYY-MM-DDTHH:MM:SSZ**", + optional: true, + }, + end: { + type: "string", + label: "End Date", + description: "End date of the event. **Format: YYYY-MM-DDTHH:MM:SSZ**", + optional: true, + }, + allDay: { + type: "boolean", + label: "All Day", + description: "Whether the event lasts all day or not", + optional: true, + }, + color: { + type: "string", + label: "Color", + description: "The color of the event", + optional: true, }, - endDate: { + subtenantId: { propDefinition: [ adhook, - "endDate", + "subtenantId", ], + optional: true, }, - eventDescription: { + tags: { propDefinition: [ adhook, - "eventDescription", + "tags", ], optional: true, }, - attendees: { + topics: { propDefinition: [ adhook, - "attendees", + "topics", ], optional: true, }, attachments: { - propDefinition: [ - adhook, - "attachments", - ], + type: "string[]", + label: "Attachments", + description: "A list of objects of attachments for the event. **Format: {\"name\": \"Attachment name\", \"url\":\"https://attachment.com/file.pdf\", \"fileExtension\":\"pdf\"}**", optional: true, }, }, async run({ $ }) { - const response = await this.adhook.createCalendarEvent({ + const { + adhook, + tags, + topics, + attachments, + ...data + } = this; + + const response = await adhook.createCalendarEvent({ + $, data: { - eventName: this.eventName, - startDate: this.startDate, - endDate: this.endDate, - eventDescription: this.eventDescription, - attendees: this.attendees, - attachments: this.attachments, + type: "EVENT", + ...data, + tags: parseObject(tags), + topics: parseObject(topics)?.map((topic) => ({ + name: topic, + })), + attachments: parseObject(attachments), }, }); - $.export("$summary", `Successfully created calendar event: ${this.eventName}`); + $.export("$summary", `Successfully created calendar event: ${response.id}`); return response; }, }; diff --git a/components/adhook/actions/create-update-post/create-update-post.mjs b/components/adhook/actions/create-update-post/create-update-post.mjs index 761dc7ec35e84..13bec5285823f 100644 --- a/components/adhook/actions/create-update-post/create-update-post.mjs +++ b/components/adhook/actions/create-update-post/create-update-post.mjs @@ -1,11 +1,12 @@ import adhook from "../../adhook.app.mjs"; -import { axios } from "@pipedream/platform"; +import constants from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; export default { key: "adhook-create-update-post", name: "Create or Update Post", description: "Adds a new post or modifies an existing post in Adhook. [See the documentation](https://app.adhook.io/api-doc/)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { adhook, @@ -16,57 +17,122 @@ export default { ], optional: true, }, - postContent: { + name: { + type: "string", + label: "Name", + description: "The name of the post", + optional: true, + }, + type: { + type: "string", + label: "Type", + description: "The type of the post", + optional: true, + options: constants.TYPE_OPTIONS, + }, + subtenantId: { propDefinition: [ adhook, - "postContent", + "subtenantId", ], + optional: true, }, - visibility: { + status: { + type: "string", + label: "Status", + description: "The status of the post", + optional: true, + options: constants.STATUS_OPTIONS, + }, + tags: { propDefinition: [ adhook, - "visibility", + "tags", ], + optional: true, }, - postAttachments: { + topics: { propDefinition: [ adhook, - "postAttachments", + "topics", ], optional: true, }, - mentionUsers: { + schedule: { + type: "string", + label: "Schedule", + description: "Whether you want to schedule or publish the post", + optional: true, + options: constants.SCHEDULE_OPTIONS, + }, + message: { + type: "string", + label: "Message", + description: "A message to send with the post", + optional: true, + }, + promotionType: { + type: "string", + label: "Promotion Type", + description: "The type of the promotion in the post", + optional: true, + options: constants.PROMOTION_TYPE_OPTIONS, + }, + campaignName: { + type: "string", + label: "Campaign Name", + description: "The name of the campaign", + optional: true, + }, + externalId: { propDefinition: [ adhook, - "mentionUsers", + "externalId", ], optional: true, }, }, async run({ $ }) { - const data = { - postContent: this.postContent, - visibility: this.visibility, - postAttachments: this.postAttachments, - mentionUsers: this.mentionUsers, - }; + const { + adhook, + postId, + tags, + topics, + ...data + } = this; - if (this.postId) { - data.postId = this.postId; + let postData = {}; + + if (postId) { + const post = await adhook.getPost({ + postId, + }); + postData = post; } - const response = await axios($, { - method: "POST", - url: `${this.adhook._baseUrl()}/posts`, - headers: { - Authorization: `Bearer ${this.adhook.$auth.oauth_access_token}`, - }, - data, + postData = { + ...postData, + ...data, + tags: parseObject(tags) || postData.tags, + topics: parseObject(topics)?.map((topic) => ({ + name: topic, + })) || postData.topics, + }; + + const fn = postId + ? adhook.updatePost + : adhook.createPost; + + const response = await fn({ + $, + postId, + data: postData, }); - $.export("$summary", `Successfully ${this.postId + $.export("$summary", `Successfully ${postId ? "updated" : "created"} post`); + return response; }, }; diff --git a/components/adhook/adhook.app.mjs b/components/adhook/adhook.app.mjs index 341a6c8c5d7d7..0a3b5aa878e5a 100644 --- a/components/adhook/adhook.app.mjs +++ b/components/adhook/adhook.app.mjs @@ -1,186 +1,128 @@ import { axios } from "@pipedream/platform"; +import constants from "./common/constants.mjs"; export default { type: "app", app: "adhook", propDefinitions: { - postType: { + subtenantId: { type: "string", - label: "Post Type", - description: "The type of the post", - optional: true, - }, - postAuthor: { - type: "string", - label: "Post Author", - description: "The author of the post", - optional: true, - }, - postTags: { - type: "string[]", - label: "Post Tags", - description: "Tags associated with the post", - optional: true, + label: "Subtenant Id", + description: "The id of the subtenant.", + async options() { + const data = await this.listSubtenants(); + + return data.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, }, postId: { type: "string", label: "Post ID", description: "The ID of the post", - }, - isNew: { - type: "boolean", - label: "Is New", - description: "Indicates if the post is new", - optional: true, - }, - updateType: { - type: "string", - label: "Update Type", - description: "Type of update made to the post", - optional: true, - }, - eventName: { - type: "string", - label: "Event Name", - description: "Name of the calendar event", - }, - startDate: { - type: "string", - label: "Start Date", - description: "Start date of the event", - }, - endDate: { - type: "string", - label: "End Date", - description: "End date of the event", - }, - eventDescription: { - type: "string", - label: "Event Description", - description: "Description of the event", - optional: true, - }, - attendees: { + async options({ page }) { + const data = await this.listPosts({ + params: { + limit: constants.LIMIT, + skip: constants.LIMIT * page, + }, + }); + + return data.map(({ + id: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + tags: { type: "string[]", - label: "Attendees", - description: "List of attendees for the event", - optional: true, + label: "Tags", + description: "A list of tags.", }, - attachments: { + topics: { type: "string[]", - label: "Attachments", - description: "Attachments for the event", - optional: true, - }, - postContent: { - type: "string", - label: "Post Content", - description: "Content of the post", + label: "Topics", + description: "A list of topics.", }, - visibility: { + externalId: { type: "string", - label: "Visibility", - description: "Visibility setting of the post", - }, - postAttachments: { - type: "string[]", - label: "Post Attachments", - description: "Attachments for the post", - optional: true, - }, - mentionUsers: { - type: "string[]", - label: "Mention Users", - description: "Users to mention in the post", - optional: true, + label: "External Id", + description: "An external Id to the event", }, }, methods: { _baseUrl() { - return "https://app.adhook.io/api"; + return "https://app.adhook.io/api/v1"; + }, + _headers() { + return { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }; }, - async _makeRequest(opts = {}) { - const { - $ = this, method = "GET", path = "/", headers, ...otherOpts - } = opts; + _makeRequest({ + $ = this, path, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - Authorization: `Bearer ${this.$auth.oauth_access_token}`, - }, + headers: this._headers(), + ...opts, }); }, - async emitNewPostEvent(opts = {}) { + createCalendarEvent(opts = {}) { return this._makeRequest({ method: "POST", - path: "/events/new_post", - data: { - postType: this.postType, - postAuthor: this.postAuthor, - postTags: this.postTags, - }, + path: "/customEvents", ...opts, }); }, - async emitPostCreatedOrUpdatedEvent(opts = {}) { + listPosts(opts = {}) { return this._makeRequest({ - method: "POST", - path: "/events/post_created_or_updated", - data: { - postId: this.postId, - postAuthor: this.postAuthor, - postTags: this.postTags, - isNew: this.isNew, - }, + path: "/posts", ...opts, }); }, - async emitPostUpdatedEvent(opts = {}) { + listSubtenants(opts = {}) { return this._makeRequest({ - method: "POST", - path: "/events/post_updated", - data: { - postId: this.postId, - postAuthor: this.postAuthor, - postTags: this.postTags, - updateType: this.updateType, - }, + path: "/subtenants", ...opts, }); }, - async createCalendarEvent(opts = {}) { + createPost(opts = {}) { return this._makeRequest({ method: "POST", - path: "/events/calendar", - data: { - eventName: this.eventName, - startDate: this.startDate, - endDate: this.endDate, - eventDescription: this.eventDescription, - attendees: this.attendees, - attachments: this.attachments, - }, + path: "/posts", ...opts, }); }, - async addOrUpdatePost(opts = {}) { + getPost({ postId }) { return this._makeRequest({ - method: "POST", - path: "/posts", - data: { - postContent: this.postContent, - visibility: this.visibility, - postAttachments: this.postAttachments, - mentionUsers: this.mentionUsers, - }, + path: `/posts/${postId}`, + }); + }, + updatePost({ + postId, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/posts/${postId}`, ...opts, }); }, - authKeys() { - console.log(Object.keys(this.$auth)); + listCreatedPosts() { + return this._makeRequest({ + path: "/posts/recentlyCreated", + }); + }, + listUpdatedPosts() { + return this._makeRequest({ + path: "/posts/recentlyUpdated", + }); }, }, }; diff --git a/components/adhook/common/constants.mjs b/components/adhook/common/constants.mjs new file mode 100644 index 0000000000000..a917c3200b959 --- /dev/null +++ b/components/adhook/common/constants.mjs @@ -0,0 +1,59 @@ +const LIMIT = 100; + +const TYPE_OPTIONS = [ + "PERSONAL_POST", + "PAGE_POST", + "STORY", + "REELS", + "SHORTS", + "LINK_CAROUSEL", + "DOCUMENT", + "POLL", +]; + +const STATUS_OPTIONS = [ + "CREATED", + "READY", + "PLANNED", + "PUBLISHED", + "IN_REVIEW", + "ACTIVATING", + "MANUALLY_ACTIVATING", + "ERROR", + "DELETED", + "CHECK_REVIEW_FEEDBACK", + "IMPORTING", +]; + +const SCHEDULE_OPTIONS = [ + "PUBLISH_AS_SOON_AS_POSSIBLE", + "PLANNED_POST_PUBLISH", +]; + +const PROMOTION_TYPE_OPTIONS = [ + "TRAFFIC", + "CONVERSIONS", + "RETARGETING", + "SHOPPING", + "CARS", + "REAL_ESTATE", + "JOBS", + "EVENTS", + "APP", + "ENGAGEMENT", + "VIDEO_VIEWS", + "CALLS", + "REACH", + "FOLLOWERS", + "PROFILE_VIEWS", + "LEADS", + "PERFORMANCE_MAX", +]; + +export default { + LIMIT, + TYPE_OPTIONS, + STATUS_OPTIONS, + SCHEDULE_OPTIONS, + PROMOTION_TYPE_OPTIONS, +}; diff --git a/components/adhook/common/utils.mjs b/components/adhook/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/adhook/common/utils.mjs @@ -0,0 +1,24 @@ +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; +}; diff --git a/components/adhook/package.json b/components/adhook/package.json index 7f87156e011f1..9348175fade26 100644 --- a/components/adhook/package.json +++ b/components/adhook/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/adhook", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Adhook Components", "main": "adhook.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.1" } } diff --git a/components/adhook/sources/common/base.mjs b/components/adhook/sources/common/base.mjs new file mode 100644 index 0000000000000..9d139d58d36a3 --- /dev/null +++ b/components/adhook/sources/common/base.mjs @@ -0,0 +1,54 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import adhook from "../../adhook.app.mjs"; + +export default { + props: { + adhook, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastDate() { + return this.db.get("lastDate") || 0; + }, + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); + }, + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + const fieldDate = this.getFieldDate(); + const fn = this.getFunction(); + let response = await fn(); + + response = response.filter((item) => Date.parse(item[fieldDate]) > lastDate); + + if (response.length) { + if (maxResults && (response.length > maxResults)) { + response.length = maxResults; + } + this._setLastDate(Date.parse(response[0][fieldDate])); + } + + for (const item of response.reverse()) { + this.$emit(item, { + id: item.id, + summary: this.getSummary(item), + ts: Date.parse(item[fieldDate]), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs b/components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs deleted file mode 100644 index 705effe572388..0000000000000 --- a/components/adhook/sources/new-or-updated-post/new-or-updated-post.mjs +++ /dev/null @@ -1,110 +0,0 @@ -import adhook from "../../adhook.app.mjs"; -import { axios } from "@pipedream/platform"; - -export default { - key: "adhook-new-or-updated-post", - name: "New or Updated Post", - description: "Emit new event when a new post is created or an existing post is updated. [See the documentation](https://app.adhook.io/api-doc/)", - version: "0.0.{{ts}}", - type: "source", - dedupe: "unique", - props: { - adhook, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60, - }, - }, - postId: { - propDefinition: [ - adhook, - "postId", - ], - }, - postAuthor: { - propDefinition: [ - adhook, - "postAuthor", - ], - optional: true, - }, - postTags: { - propDefinition: [ - adhook, - "postTags", - ], - optional: true, - }, - isNew: { - propDefinition: [ - adhook, - "isNew", - ], - optional: true, - }, - }, - hooks: { - async deploy() { - const events = await this.adhook.emitPostCreatedOrUpdatedEvent({ - postId: this.postId, - postAuthor: this.postAuthor, - postTags: this.postTags, - isNew: this.isNew, - }); - - for (const event of events.slice(0, 50)) { - this.$emit(event, { - id: event.postId, - summary: `Post ${event.isNew - ? "created" - : "updated"}: ${event.postId}`, - ts: Date.now(), - }); - } - }, - async activate() { - // Activate hook logic if needed - }, - async deactivate() { - // Deactivate hook logic if needed - }, - }, - methods: { - _getLastTimestamp() { - return this.db.get("lastTimestamp") || 0; - }, - _setLastTimestamp(ts) { - this.db.set("lastTimestamp", ts); - }, - }, - async run() { - const lastTimestamp = this._getLastTimestamp(); - const events = await this.adhook.emitPostCreatedOrUpdatedEvent({ - postId: this.postId, - postAuthor: this.postAuthor, - postTags: this.postTags, - isNew: this.isNew, - }); - - for (const event of events) { - const eventTimestamp = new Date(event.updatedAt).getTime(); - if (eventTimestamp > lastTimestamp) { - this.$emit(event, { - id: event.postId, - summary: `Post ${event.isNew - ? "created" - : "updated"}: ${event.postId}`, - ts: eventTimestamp, - }); - } - } - - if (events.length > 0) { - const latestEvent = events[0]; - const latestTimestamp = new Date(latestEvent.updatedAt).getTime(); - this._setLastTimestamp(latestTimestamp); - } - }, -}; diff --git a/components/adhook/sources/new-post/new-post.mjs b/components/adhook/sources/new-post/new-post.mjs index 88c84775c189b..b4abb56b048f5 100644 --- a/components/adhook/sources/new-post/new-post.mjs +++ b/components/adhook/sources/new-post/new-post.mjs @@ -1,98 +1,25 @@ -import { axios } from "@pipedream/platform"; -import adhook from "../../adhook.app.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "adhook-new-post", name: "New Post Created", description: "Emit new event when a new post is created. [See the documentation](https://app.adhook.io/api-doc/)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - adhook, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60, - }, - }, - postType: { - propDefinition: [ - adhook, - "postType", - ], - }, - postAuthor: { - propDefinition: [ - adhook, - "postAuthor", - ], - }, - postTags: { - propDefinition: [ - adhook, - "postTags", - ], - }, - }, - hooks: { - async deploy() { - const posts = await this.adhook.emitNewPostEvent({ - params: { - postType: this.postType, - postAuthor: this.postAuthor, - postTags: this.postTags, - }, - }); - - for (const post of posts.slice(0, 50)) { - this.$emit(post, { - id: post.id, - summary: `New Post: ${post.title}`, - ts: new Date(post.createdAt).getTime(), - }); - } - }, - async activate() { - // Activate hook, if needed - }, - async deactivate() { - // Deactivate hook, if needed - }, - }, methods: { - _getLastTimestamp() { - return this.db.get("lastTimestamp") || 0; + ...common.methods, + getFunction() { + return this.adhook.listCreatedPosts; }, - _setLastTimestamp(timestamp) { - this.db.set("lastTimestamp", timestamp); + getFieldDate() { + return "createdAt"; + }, + getSummary(item) { + return `New Post: ${item.id}`; }, }, - async run() { - const lastTimestamp = this._getLastTimestamp(); - - const posts = await this.adhook.emitNewPostEvent({ - params: { - postType: this.postType, - postAuthor: this.postAuthor, - postTags: this.postTags, - }, - }); - - for (const post of posts) { - const postTimestamp = new Date(post.createdAt).getTime(); - if (postTimestamp > lastTimestamp) { - this.$emit(post, { - id: post.id, - summary: `New Post: ${post.title}`, - ts: postTimestamp, - }); - } - } - - if (posts.length > 0) { - this._setLastTimestamp(new Date(posts[0].createdAt).getTime()); - } - }, + sampleEmit, }; diff --git a/components/adhook/sources/new-post/test-event.mjs b/components/adhook/sources/new-post/test-event.mjs new file mode 100644 index 0000000000000..62430e0b0638a --- /dev/null +++ b/components/adhook/sources/new-post/test-event.mjs @@ -0,0 +1,50 @@ +export default { + "id": "66c57199f555a956148eaba0", + "message": "Message text", + "type": "PAGE_POST", + "status": "PUBLISHED", + "createdAt": "2024-08-21T04:48:25.666860864Z", + "createdByUserEmail": "user@email.com", + "createdByUserId": "66c57199f555a956148eaba0", + "tenantId": "66c57199f555a956148eaba0", + "tags": [ + { + "id": "66c57199f555a956148eaba0", + "userId": null, + "tenantId": "66c57199f555a956148eaba0", + "subtenantId": "66c57199f555a956148eaba0", + "text": "LinkedIn", + "color": null + } + ], + "topics": null, + "subtenantId": "66c57199f555a956148eaba0", + "processReviewFeedback": null, + "processTaskAssigneeUserId": null, + "processTaskAssigneeUserIds": null, + "imageUrl": null, + "videoUrl": null, + "videoThumbnailUrl": null, + "promotePost": false, + "nbrOfDays": 7, + "totalBudget": 0.0, + "currency": "USD", + "remark": null, + "impressions": 0, + "reach": 0, + "clicks": 0, + "likes": 0, + "comments": 0, + "shares": 0, + "videoViews": 0, + "reactions": 0, + "publishAt": "2024-02-02T18:39:23.22Z", + "publishedAt": "2024-02-02T18:39:23.22Z", + "schedule": "PLANNED_POST_PUBLISH", + "activationErrorMessage": null, + "activationErrorChannel": null, + "translationStatus": null, + "translationDate": null, + "deliverContentTillDate": null, + "reviewTillDate": null +} \ No newline at end of file diff --git a/components/adhook/sources/updated-post/test-event.mjs b/components/adhook/sources/updated-post/test-event.mjs new file mode 100644 index 0000000000000..62430e0b0638a --- /dev/null +++ b/components/adhook/sources/updated-post/test-event.mjs @@ -0,0 +1,50 @@ +export default { + "id": "66c57199f555a956148eaba0", + "message": "Message text", + "type": "PAGE_POST", + "status": "PUBLISHED", + "createdAt": "2024-08-21T04:48:25.666860864Z", + "createdByUserEmail": "user@email.com", + "createdByUserId": "66c57199f555a956148eaba0", + "tenantId": "66c57199f555a956148eaba0", + "tags": [ + { + "id": "66c57199f555a956148eaba0", + "userId": null, + "tenantId": "66c57199f555a956148eaba0", + "subtenantId": "66c57199f555a956148eaba0", + "text": "LinkedIn", + "color": null + } + ], + "topics": null, + "subtenantId": "66c57199f555a956148eaba0", + "processReviewFeedback": null, + "processTaskAssigneeUserId": null, + "processTaskAssigneeUserIds": null, + "imageUrl": null, + "videoUrl": null, + "videoThumbnailUrl": null, + "promotePost": false, + "nbrOfDays": 7, + "totalBudget": 0.0, + "currency": "USD", + "remark": null, + "impressions": 0, + "reach": 0, + "clicks": 0, + "likes": 0, + "comments": 0, + "shares": 0, + "videoViews": 0, + "reactions": 0, + "publishAt": "2024-02-02T18:39:23.22Z", + "publishedAt": "2024-02-02T18:39:23.22Z", + "schedule": "PLANNED_POST_PUBLISH", + "activationErrorMessage": null, + "activationErrorChannel": null, + "translationStatus": null, + "translationDate": null, + "deliverContentTillDate": null, + "reviewTillDate": null +} \ No newline at end of file diff --git a/components/adhook/sources/updated-post/updated-post.mjs b/components/adhook/sources/updated-post/updated-post.mjs index 6d480dd09fc53..61458ffcf22ee 100644 --- a/components/adhook/sources/updated-post/updated-post.mjs +++ b/components/adhook/sources/updated-post/updated-post.mjs @@ -1,105 +1,25 @@ -import { axios } from "@pipedream/platform"; -import adhook from "../../adhook.app.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "adhook-updated-post", - name: "Adhook Updated Post", - description: "Emit new event when a post is updated. [See the documentation](https://app.adhook.io/api-doc/)", - version: "0.0.{{ts}}", + name: "New Updated Post", + description: "Emit new event when a post is updated.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - adhook, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60, - }, - }, - postId: { - propDefinition: [ - adhook, - "postId", - ], - }, - postAuthor: { - propDefinition: [ - adhook, - "postAuthor", - ], - optional: true, - }, - postTags: { - propDefinition: [ - adhook, - "postTags", - ], - optional: true, - }, - updateType: { - propDefinition: [ - adhook, - "updateType", - ], - optional: true, - }, - }, - hooks: { - async deploy() { - const posts = await this.adhook.emitPostUpdatedEvent({ - data: { - postId: this.postId, - postAuthor: this.postAuthor, - postTags: this.postTags, - updateType: this.updateType, - }, - }); - - for (const post of posts.slice(0, 50)) { - this.$emit(post, { - id: post.id, - summary: `Post Updated: ${post.title}`, - ts: Date.parse(post.updated_at), - }); - } - }, - async activate() { - // Any activation logic if needed - }, - async deactivate() { - // Any deactivation logic if needed - }, - }, methods: { - _getLastTimestamp() { - return this.db.get("lastTimestamp") || 0; + ...common.methods, + getFunction() { + return this.adhook.listUpdatedPosts; }, - _setLastTimestamp(ts) { - this.db.set("lastTimestamp", ts); + getFieldDate() { + return "updatedAt"; + }, + getSummary(post) { + return `Post Updated: ${post.id}`; }, }, - async run() { - const lastTimestamp = this._getLastTimestamp(); - const posts = await this.adhook.emitPostUpdatedEvent({ - data: { - postId: this.postId, - postAuthor: this.postAuthor, - postTags: this.postTags, - updateType: this.updateType, - }, - }); - - for (const post of posts) { - const postTimestamp = Date.parse(post.updated_at); - if (postTimestamp > lastTimestamp) { - this.$emit(post, { - id: post.id, - summary: `Post Updated: ${post.title}`, - ts: postTimestamp, - }); - this._setLastTimestamp(postTimestamp); - } - } - }, + sampleEmit, }; From a4cd43435a664428bc39650fd56403661340d7ed Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 16 Sep 2024 12:38:06 -0300 Subject: [PATCH 3/3] pnpm update --- pnpm-lock.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29ab5043c849e..16bdbdcbbf2d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -236,7 +236,10 @@ importers: '@pipedream/platform': 3.0.0 components/adhook: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.1 + dependencies: + '@pipedream/platform': 3.0.1 components/adobe_pdf_services: specifiers: