diff --git a/components/yay_com/actions/create-outbound-call/create-outbound-call.mjs b/components/yay_com/actions/create-outbound-call/create-outbound-call.mjs new file mode 100644 index 0000000000000..f00c013d1ce89 --- /dev/null +++ b/components/yay_com/actions/create-outbound-call/create-outbound-call.mjs @@ -0,0 +1,77 @@ +import { ConfigurationError } from "@pipedream/platform"; +import yayCom from "../../yay_com.app.mjs"; + +export default { + key: "yay_com-create-outbound-call", + name: "Create Outbound Call", + description: "Initiates an outbound call to a specified number. [See the documentation](https://www.yay.com/voip/api-docs/calls/outbound-call/)", + version: "0.0.1", + type: "action", + props: { + yayCom, + userUuid: { + propDefinition: [ + yayCom, + "sipUser", + ], + }, + destination: { + propDefinition: [ + yayCom, + "destination", + ], + }, + displayName: { + propDefinition: [ + yayCom, + "displayName", + ], + }, + sipUsers: { + propDefinition: [ + yayCom, + "sipUser", + ], + label: "Target SIP Users", + type: "string[]", + description: "One or more SIP users who will receive the outbound call request", + optional: true, + }, + huntGroups: { + propDefinition: [ + yayCom, + "huntGroups", + ], + }, + }, + async run({ $ }) { + // Combine sipUsers and huntGroups into the targets array + const targets = [ + ...(this.sipUsers?.map((uuid) => ({ + type: "sipuser", + uuid, + })) || []), + ...(this.huntGroups?.map((uuid) => ({ + type: "huntgroup", + uuid, + })) || []), + ]; + + if (!targets.length) { + throw new ConfigurationError("Please provide at least one target (SIP user or hunt group)"); + } + + const response = await this.yayCom.createOutboundCall({ + $, + data: { + user_uuid: this.userUuid, + destination: this.destination, + display_name: this.displayName, + targets, + }, + }); + + $.export("$summary", `Successfully initiated outbound call to ${this.destination}`); + return response; + }, +}; diff --git a/components/yay_com/actions/get-documents/get-documents.mjs b/components/yay_com/actions/get-documents/get-documents.mjs new file mode 100644 index 0000000000000..e57d0c70f1377 --- /dev/null +++ b/components/yay_com/actions/get-documents/get-documents.mjs @@ -0,0 +1,26 @@ +import yayCom from "../../yay_com.app.mjs"; + +export default { + key: "yay_com-get-documents", + name: "Get Documents", + description: + "Retrieves all documents available. [See the documentation](https://www.yay.com/voip/api-docs/account/document/)", + version: "0.0.1", + type: "action", + props: { + yayCom, + }, + async run({ $ }) { + const response = await this.yayCom.listDocuments({ + $, + }); + const { length } = response; + $.export( + "$summary", + `Successfully retrieved ${length} document${length === 1 + ? "" + : "s"}`, + ); + return response; + }, +}; diff --git a/components/yay_com/actions/get-phone-books/get-phone-books.mjs b/components/yay_com/actions/get-phone-books/get-phone-books.mjs new file mode 100644 index 0000000000000..717c52b2a7320 --- /dev/null +++ b/components/yay_com/actions/get-phone-books/get-phone-books.mjs @@ -0,0 +1,22 @@ +import yayCom from "../../yay_com.app.mjs"; + +export default { + key: "yay_com-get-phone-books", + name: "Get Phone Books", + description: "Retrieves all phone books available. [See the documentation](https://www.yay.com/voip/api-docs/phone-books/phone-book/)", + version: "0.0.1", + type: "action", + props: { + yayCom, + }, + async run({ $ }) { + const response = await this.yayCom.listPhoneBooks({ + $, + }); + const { length } = response; + $.export("$summary", `Successfully retrieved ${length} phone book${length === 1 + ? "" + : "s"}`); + return response; + }, +}; diff --git a/components/yay_com/package.json b/components/yay_com/package.json index 994ca7e4b9554..62a171dc5373b 100644 --- a/components/yay_com/package.json +++ b/components/yay_com/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/yay_com", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Yay.com Components", "main": "yay_com.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/components/yay_com/sources/common/polling.mjs b/components/yay_com/sources/common/polling.mjs new file mode 100644 index 0000000000000..f5bf0ad9bf2bb --- /dev/null +++ b/components/yay_com/sources/common/polling.mjs @@ -0,0 +1,56 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import yayCom from "../../yay_com.app.mjs"; + +export default { + props: { + yayCom, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getSavedIds() { + return this.db.get("savedIds") || []; + }, + _setSavedIds(ids) { + this.db.set("savedIds", ids); + }, + async startEvent(maxItems) { + const savedIds = this._getSavedIds(); + const items = await this.getItems(savedIds); + + const newIds = []; + for (const item of items) { + const id = this.getItemId(item); + if (!savedIds.includes(id)) { + const meta = this.generateMeta(item); + if (maxItems === undefined || (typeof maxItems === "number" && --maxItems >= 0)) { + this.$emit(item, meta); + } + newIds.push(id); + } + } + + if (newIds.length > 0) { + // Keep only the most recent IDs to prevent the array from growing indefinitely + const ids = [ + ...savedIds, + ...newIds, + ].slice(-100); + this._setSavedIds(ids); + } + }, + }, + async run() { + await this.startEvent(); + }, + hooks: { + async deploy() { + await this.startEvent(5); + }, + }, +}; diff --git a/components/yay_com/sources/new-contact-added/new-contact-added.mjs b/components/yay_com/sources/new-contact-added/new-contact-added.mjs new file mode 100644 index 0000000000000..7d9941355f517 --- /dev/null +++ b/components/yay_com/sources/new-contact-added/new-contact-added.mjs @@ -0,0 +1,50 @@ +import common from "../common/polling.mjs"; + +export default { + ...common, + key: "yay_com-new-contact-added", + name: "New Contact Added", + description: "Emit new event when a contact is added to a phone book. [See the documentation](https://www.yay.com/voip/api-docs/phone-books/phone-book-contact/)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + phoneBookId: { + propDefinition: [ + common.props.yayCom, + "phoneBookId", + ], + }, + }, + methods: { + ...common.methods, + generateMeta(contact) { + const name = this.getItemId(contact); + return { + id: name, + summary: `New Contact: ${name}`, + ts: Date.now(), + }; + }, + getItemId(contact) { + let name = `${contact.first_name} ${contact.last_name}`; + if (!name.trim()) { + name = contact.company_name; + } + return name; + }, + async getItems() { + const { phoneBookId } = this; + const contacts = await this.yayCom.listPhoneBookContacts({ + phoneBookId, + params: { + sort: "id", + limit: 100, + uuid: phoneBookId, + }, + }); + return contacts || []; + }, + }, +}; diff --git a/components/yay_com/yay_com.app.mjs b/components/yay_com/yay_com.app.mjs index 0218c54955d7f..3011f0c33831c 100644 --- a/components/yay_com/yay_com.app.mjs +++ b/components/yay_com/yay_com.app.mjs @@ -1,11 +1,137 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "yay_com", - propDefinitions: {}, + propDefinitions: { + sipUser: { + type: "string", + label: "SIP User ID", + description: "The SIP user to make the outbound call for", + async options() { + const users = await this.listSipUsers(); + return users?.map(({ + uuid: value, display_name, user_name, + }) => ({ + label: display_name || user_name, + value, + })) || []; + }, + }, + huntGroups: { + type: "string[]", + label: "Target Hunt Groups", + description: "One or more hunt groups who will receive the outbound call request", + optional: true, + async options() { + const groups = await this.listHuntGroups(); + return groups?.map(({ + uuid: value, name: label, + }) => ({ + label, + value, + })) || []; + }, + }, + phoneBookId: { + type: "string", + label: "Phone Book", + description: "The phone book to monitor for new contacts", + async options() { + const books = await this.listPhoneBooks(); + return books?.map(({ + uuid: value, name: label, + }) => ({ + label, + value, + })) || []; + }, + }, + destination: { + type: "string", + label: "Destination", + description: "The destination phone number to call (in E164 format for outbound calls). You may also provide extension numbers of your hunt groups, users and call routes.", + }, + displayName: { + type: "string", + label: "Display Name", + description: "What display name should be sent to the user, this will show as the name on their phone (where supported)", + optional: true, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _getBaseUrl() { + return `https://${this.$auth.api_hostname}`; + }, + _getHeaders() { + return { + "x-auth-reseller": `${this.$auth.reseller}`, + "x-auth-user": `${this.$auth.user}`, + "x-auth-password": `${this.$auth.password}`, + }; + }, + async _makeRequest({ + $ = this, + path, + headers, + ...args + }) { + const response = await axios($, { + url: `${this._getBaseUrl()}${path}`, + headers: { + ...headers, + ...this._getHeaders(), + }, + ...args, + }); + return response.result; + }, + async listSipUsers(args) { + return this._makeRequest({ + path: "/voip/user", + ...args, + }); + }, + async listHuntGroups(args) { + return this._makeRequest({ + path: "/voip/group", + ...args, + }); + }, + async listPhoneBooks(args) { + return this._makeRequest({ + path: "/voip/phone-book", + ...args, + }); + }, + async listPhoneBookContacts({ + phoneBookId, ...args + }) { + return this._makeRequest({ + path: `/voip/phone-book/${phoneBookId}`, + ...args, + }); + }, + async listMailboxMessages({ + mailboxId, ...args + }) { + return this._makeRequest({ + path: `/voip/mailbox/${mailboxId}/messages`, + ...args, + }); + }, + async listDocuments(args) { + return this._makeRequest({ + path: "/account/document", + ...args, + }); + }, + async createOutboundCall(args) { + return this._makeRequest({ + method: "POST", + path: "/calls/outbound", + ...args, + }); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b516660cfcfd5..29227eddf06b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5392,8 +5392,7 @@ importers: components/godial: {} - components/goformz: - specifiers: {} + components/goformz: {} components/gohighlevel: dependencies: @@ -8487,8 +8486,7 @@ importers: components/mollie: {} - components/momentum_ams: - specifiers: {} + components/momentum_ams: {} components/monday: dependencies: @@ -9467,8 +9465,7 @@ importers: components/order_sender: {} - components/orderspace: - specifiers: {} + components/orderspace: {} components/originality_ai: dependencies: @@ -15090,7 +15087,11 @@ importers: specifier: ^1.2.0 version: 1.6.6 - components/yay_com: {} + components/yay_com: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/yelp: dependencies: