Skip to content

Commit a981fcf

Browse files
authored
New Components - openphone (#14505)
* openphone init * [Components] openphone #14493 Sources - New Call Recording Completed (Instant) - New Outgoing Call Completed (Instant) - New Incoming Call Completed (Instant) Actions - Send Message - Create Contact - Update Contact * pnpm update * fix source
1 parent ac89f9b commit a981fcf

File tree

14 files changed

+599
-7
lines changed

14 files changed

+599
-7
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { parseObject } from "../../common/utils.mjs";
2+
import openphone from "../../openphone.app.mjs";
3+
4+
export default {
5+
key: "openphone-create-contact",
6+
name: "Create Contact",
7+
description: "Create a new contact in OpenPhone. [See the documentation](https://www.openphone.com/docs/api-reference/contacts/create-a-contact)",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
openphone,
12+
firstName: {
13+
propDefinition: [
14+
openphone,
15+
"firstName",
16+
],
17+
},
18+
lastName: {
19+
propDefinition: [
20+
openphone,
21+
"lastName",
22+
],
23+
optional: true,
24+
},
25+
company: {
26+
propDefinition: [
27+
openphone,
28+
"company",
29+
],
30+
optional: true,
31+
},
32+
role: {
33+
propDefinition: [
34+
openphone,
35+
"role",
36+
],
37+
optional: true,
38+
},
39+
emails: {
40+
propDefinition: [
41+
openphone,
42+
"emails",
43+
],
44+
optional: true,
45+
},
46+
phoneNumbers: {
47+
propDefinition: [
48+
openphone,
49+
"phoneNumbers",
50+
],
51+
optional: true,
52+
},
53+
customFields: {
54+
propDefinition: [
55+
openphone,
56+
"customFields",
57+
],
58+
optional: true,
59+
},
60+
},
61+
async run({ $ }) {
62+
const response = await this.openphone.createContact({
63+
$,
64+
data: {
65+
defaultFields: {
66+
firstName: this.firstName,
67+
lastName: this.lastName,
68+
company: this.company,
69+
role: this.role,
70+
emails: parseObject(this.emails),
71+
phoneNumbers: parseObject(this.phoneNumbers),
72+
},
73+
customFields: parseObject(this.customFields),
74+
},
75+
});
76+
77+
$.export("$summary", `Successfully created contact with ID: ${response.data.id}`);
78+
return response;
79+
},
80+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { ConfigurationError } from "@pipedream/platform";
2+
import openphone from "../../openphone.app.mjs";
3+
4+
export default {
5+
key: "openphone-send-message",
6+
name: "Send a Text Message via OpenPhone",
7+
description: "Send a text message from your OpenPhone number to a recipient. [See the documentation](https://www.openphone.com/docs/api-reference/messages/send-a-text-message)",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
openphone,
12+
from: {
13+
propDefinition: [
14+
openphone,
15+
"from",
16+
],
17+
},
18+
to: {
19+
type: "string",
20+
label: "To",
21+
description: "Recipient phone number in E.164 format.",
22+
},
23+
content: {
24+
type: "string",
25+
label: "Content",
26+
description: "The text content of the message to be sent.",
27+
},
28+
},
29+
async run({ $ }) {
30+
try {
31+
const response = await this.openphone.sendTextMessage({
32+
$,
33+
data: {
34+
content: this.content,
35+
from: this.from,
36+
to: [
37+
this.to,
38+
],
39+
setInboxStatus: "done",
40+
},
41+
});
42+
$.export("$summary", `Successfully sent message to ${this.to}`);
43+
return response;
44+
45+
} catch ({ response }) {
46+
let errorMessage = "";
47+
48+
if (response.data.errors) {
49+
errorMessage = `Prop: ${response.data.errors[0].path} - ${response.data.errors[0].message}`;
50+
} else {
51+
errorMessage = response.data.message;
52+
}
53+
54+
throw new ConfigurationError(errorMessage);
55+
}
56+
},
57+
};
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { parseObject } from "../../common/utils.mjs";
2+
import openphone from "../../openphone.app.mjs";
3+
4+
export default {
5+
key: "openphone-update-contact",
6+
name: "Update Contact",
7+
description: "Update an existing contact on OpenPhone. [See the documentation](https://www.openphone.com/docs/api-reference/contacts/update-a-contact-by-id)",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
openphone,
12+
contactId: {
13+
type: "string",
14+
label: "Contact ID",
15+
description: "The unique identifier of the contact.",
16+
},
17+
firstName: {
18+
propDefinition: [
19+
openphone,
20+
"firstName",
21+
],
22+
optional: true,
23+
},
24+
lastName: {
25+
propDefinition: [
26+
openphone,
27+
"lastName",
28+
],
29+
optional: true,
30+
},
31+
company: {
32+
propDefinition: [
33+
openphone,
34+
"company",
35+
],
36+
optional: true,
37+
},
38+
role: {
39+
propDefinition: [
40+
openphone,
41+
"role",
42+
],
43+
optional: true,
44+
},
45+
emails: {
46+
propDefinition: [
47+
openphone,
48+
"emails",
49+
],
50+
optional: true,
51+
},
52+
phoneNumbers: {
53+
propDefinition: [
54+
openphone,
55+
"phoneNumbers",
56+
],
57+
optional: true,
58+
},
59+
customFields: {
60+
propDefinition: [
61+
openphone,
62+
"customFields",
63+
],
64+
optional: true,
65+
},
66+
},
67+
async run({ $ }) {
68+
const response = await this.openphone.updateContact({
69+
$,
70+
contactId: this.contactId,
71+
data: {
72+
defaultFields: {
73+
firstName: this.firstName,
74+
lastName: this.lastName,
75+
company: this.company,
76+
role: this.role,
77+
emails: parseObject(this.emails),
78+
phoneNumbers: parseObject(this.phoneNumbers),
79+
},
80+
customFields: parseObject(this.customFields),
81+
},
82+
});
83+
84+
$.export("$summary", `Successfully updated contact with ID ${this.contactId}`);
85+
return response;
86+
},
87+
};

components/openphone/common/utils.mjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export const parseObject = (obj) => {
2+
if (!obj) return undefined;
3+
4+
let parsedObj = obj;
5+
if (typeof obj === "string") {
6+
try {
7+
parsedObj = JSON.parse(obj);
8+
} catch (e) {
9+
return obj;
10+
}
11+
}
12+
13+
if (Array.isArray(parsedObj)) {
14+
return parsedObj.map((item) => parseObject(item));
15+
}
16+
if (typeof parsedObj === "object") {
17+
for (const [
18+
key,
19+
value,
20+
] of Object.entries(parsedObj)) {
21+
parsedObj[key] = parseObject(value);
22+
}
23+
}
24+
25+
return parsedObj;
26+
};
Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,121 @@
1+
import { axios } from "@pipedream/platform";
2+
13
export default {
24
type: "app",
35
app: "openphone",
4-
propDefinitions: {},
6+
propDefinitions: {
7+
from: {
8+
type: "string",
9+
label: "From",
10+
description: "The sender's phone number. Can be either your OpenPhone phone number ID or the full phone number in E.164 format.",
11+
async options() {
12+
const { data } = await this.listPhoneNumbers();
13+
return data.map(({
14+
id: value, name, formattedNumber,
15+
}) => ({
16+
label: `${name} - ${formattedNumber}`,
17+
value,
18+
}));
19+
},
20+
},
21+
firstName: {
22+
type: "string",
23+
label: "First Name",
24+
description: "The contact's first name.",
25+
},
26+
lastName: {
27+
type: "string",
28+
label: "Last Name",
29+
description: "The contact's last name.",
30+
optional: true,
31+
},
32+
company: {
33+
type: "string",
34+
label: "Company",
35+
description: "The contact's company name.",
36+
optional: true,
37+
},
38+
role: {
39+
type: "string",
40+
label: "Role",
41+
description: "The contact's role.",
42+
optional: true,
43+
},
44+
emails: {
45+
type: "string[]",
46+
label: "Emails",
47+
description: "Array of objects of contact's emails. **Example:** `{\"name\": \"Company Email\", \"value\": \"[email protected]\"}`.",
48+
},
49+
phoneNumbers: {
50+
type: "string[]",
51+
label: "Phone Numbers",
52+
description: "Array of objects of contact's phone numbers. **Example:** `{\"name\": \"Company Phone\", \"value\": \"+12345678901\"}`.",
53+
},
54+
customFields: {
55+
type: "string[]",
56+
label: "Custom Fields",
57+
description: "Array of objects of custom fields for the contact. **Example:** `{\"key\": \"inbound-lead\", \"value\": \"[\"option1\", \"option2\"]\"}`.",
58+
},
59+
},
560
methods: {
6-
// this.$auth contains connected account data
7-
authKeys() {
8-
console.log(Object.keys(this.$auth));
61+
_baseUrl() {
62+
return "https://api.openphone.com/v1";
63+
},
64+
_headers() {
65+
return {
66+
Authorization: `${this.$auth.api_key}`,
67+
};
68+
},
69+
_makeRequest({
70+
$ = this, path, ...opts
71+
}) {
72+
return axios($, {
73+
url: this._baseUrl() + path,
74+
headers: this._headers(),
75+
...opts,
76+
});
77+
},
78+
listPhoneNumbers(opts = {}) {
79+
return this._makeRequest({
80+
path: "/phone-numbers",
81+
...opts,
82+
});
83+
},
84+
createWebhook(opts = {}) {
85+
return this._makeRequest({
86+
method: "POST",
87+
path: "/webhooks/calls",
88+
...opts,
89+
});
90+
},
91+
deleteWebhook(webhookId) {
92+
return this._makeRequest({
93+
method: "DELETE",
94+
path: `/webhooks/${webhookId}`,
95+
});
96+
},
97+
sendTextMessage(opts = {}) {
98+
return this._makeRequest({
99+
method: "POST",
100+
path: "/messages",
101+
...opts,
102+
});
103+
},
104+
createContact(opts = {}) {
105+
return this._makeRequest({
106+
method: "POST",
107+
path: "/contacts",
108+
...opts,
109+
});
110+
},
111+
updateContact({
112+
contactId, ...opts
113+
}) {
114+
return this._makeRequest({
115+
method: "PATCH",
116+
path: `/contacts/${contactId}`,
117+
...opts,
118+
});
9119
},
10120
},
11121
};

components/openphone/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pipedream/openphone",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"description": "Pipedream OpenPhone Components",
55
"main": "openphone.app.mjs",
66
"keywords": [
@@ -11,5 +11,8 @@
1111
"author": "Pipedream <[email protected]> (https://pipedream.com/)",
1212
"publishConfig": {
1313
"access": "public"
14+
},
15+
"dependencies": {
16+
"@pipedream/platform": "^3.0.3"
1417
}
15-
}
18+
}

0 commit comments

Comments
 (0)