Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
},
};
26 changes: 26 additions & 0 deletions components/yay_com/actions/get-documents/get-documents.mjs
Original file line number Diff line number Diff line change
@@ -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;
},
};
22 changes: 22 additions & 0 deletions components/yay_com/actions/get-phone-books/get-phone-books.mjs
Original file line number Diff line number Diff line change
@@ -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;
},
};
7 changes: 5 additions & 2 deletions components/yay_com/package.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand All @@ -11,5 +11,8 @@
"author": "Pipedream <[email protected]> (https://pipedream.com/)",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@pipedream/platform": "^3.1.0"
}
}
}
56 changes: 56 additions & 0 deletions components/yay_com/sources/common/polling.mjs
Original file line number Diff line number Diff line change
@@ -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);
},
},
};
50 changes: 50 additions & 0 deletions components/yay_com/sources/new-contact-added/new-contact-added.mjs
Original file line number Diff line number Diff line change
@@ -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;
},
Comment on lines +30 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Handle edge case where contact has no identifying information.

The getItemId method could return an empty string or just spaces if both the name and company name are empty or contain only whitespace.

Add fallback handling for contacts without identifying information:

  getItemId(contact) {
    let name = `${contact.first_name} ${contact.last_name}`;
    if (!name.trim()) {
      name = contact.company_name;
    }
+   if (!name || !name.trim()) {
+     name = contact.id || contact.uuid || `contact-${Date.now()}`;
+   }
    return name;
  },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getItemId(contact) {
let name = `${contact.first_name} ${contact.last_name}`;
if (!name.trim()) {
name = contact.company_name;
}
return name;
},
getItemId(contact) {
let name = `${contact.first_name} ${contact.last_name}`;
if (!name.trim()) {
name = contact.company_name;
}
if (!name || !name.trim()) {
name = contact.id || contact.uuid || `contact-${Date.now()}`;
}
return name;
},
🤖 Prompt for AI Agents
In components/yay_com/sources/new-contact-added/new-contact-added.mjs around
lines 30 to 36, the getItemId method may return an empty or whitespace-only
string if both the contact's first and last names and the company name are empty
or whitespace. To fix this, add a fallback return value such as a default string
like "Unknown Contact" or a unique identifier when no valid name or company name
is present, ensuring the method always returns a meaningful non-empty string.

async getItems() {
const { phoneBookId } = this;
const contacts = await this.yayCom.listPhoneBookContacts({
phoneBookId,
params: {
sort: "id",
limit: 100,
uuid: phoneBookId,
},
});
return contacts || [];
},
},
};
134 changes: 130 additions & 4 deletions components/yay_com/yay_com.app.mjs
Original file line number Diff line number Diff line change
@@ -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,
});
},
},
};
Loading
Loading