diff --git a/components/rinkel/actions/add-note/add-note.mjs b/components/rinkel/actions/add-note/add-note.mjs new file mode 100644 index 0000000000000..fa0422934c89c --- /dev/null +++ b/components/rinkel/actions/add-note/add-note.mjs @@ -0,0 +1,34 @@ +import rinkel from "../../rinkel.app.mjs"; + +export default { + key: "rinkel-add-note", + name: "Add Note", + description: "Add a note to a call. [See the documentation](https://developers.rinkel.com/docs/api/add-a-note-to-a-call-detail-record)", + version: "0.0.1", + type: "action", + props: { + rinkel, + callId: { + propDefinition: [ + rinkel, + "callId", + ], + }, + content: { + type: "string", + label: "Content", + description: "The content of the note", + }, + }, + async run({ $ }) { + const response = await this.rinkel.addNote({ + $, + id: this.callId, + data: { + content: this.content, + }, + }); + $.export("$summary", `Note added to call ${this.callId}`); + return response; + }, +}; diff --git a/components/rinkel/actions/get-call-details/get-call-details.mjs b/components/rinkel/actions/get-call-details/get-call-details.mjs new file mode 100644 index 0000000000000..64aba5fdb5eb7 --- /dev/null +++ b/components/rinkel/actions/get-call-details/get-call-details.mjs @@ -0,0 +1,26 @@ +import rinkel from "../../rinkel.app.mjs"; + +export default { + key: "rinkel-get-call-details", + name: "Get Call Details", + description: "Get details about a call. [See the documentation](https://developers.rinkel.com/docs/api/get-a-specific-call-detail-record)", + version: "0.0.1", + type: "action", + props: { + rinkel, + callId: { + propDefinition: [ + rinkel, + "callId", + ], + }, + }, + async run({ $ }) { + const response = await this.rinkel.getCallDetailRecord({ + $, + id: this.callId, + }); + $.export("$summary", `Call details for ${this.callId} retrieved`); + return response; + }, +}; diff --git a/components/rinkel/actions/get-call-recording/get-call-recording.mjs b/components/rinkel/actions/get-call-recording/get-call-recording.mjs new file mode 100644 index 0000000000000..77155a0611f3a --- /dev/null +++ b/components/rinkel/actions/get-call-recording/get-call-recording.mjs @@ -0,0 +1,26 @@ +import rinkel from "../../rinkel.app.mjs"; + +export default { + key: "rinkel-get-call-recording", + name: "Get Call Recording", + description: "Get a call recording. [See the documentation](https://developers.rinkel.com/docs/api/get-a-recording)", + version: "0.0.1", + type: "action", + props: { + rinkel, + recordingId: { + propDefinition: [ + rinkel, + "recordingId", + ], + }, + }, + async run({ $ }) { + const response = await this.rinkel.getCallRecording({ + $, + id: this.recordingId, + }); + $.export("$summary", `Recording ${this.recordingId} retrieved`); + return response; + }, +}; diff --git a/components/rinkel/actions/get-voicemail/get-voicemail.mjs b/components/rinkel/actions/get-voicemail/get-voicemail.mjs new file mode 100644 index 0000000000000..8f9967bd9b3b5 --- /dev/null +++ b/components/rinkel/actions/get-voicemail/get-voicemail.mjs @@ -0,0 +1,26 @@ +import rinkel from "../../rinkel.app.mjs"; + +export default { + key: "rinkel-get-voicemail", + name: "Get Voicemail", + description: "Returns a URL to stream or download a voicemail. [See the documentation](https://developers.rinkel.com/docs/api/get-a-temporary-url-to-stream-or-download-a-voicemail)", + version: "0.0.1", + type: "action", + props: { + rinkel, + voicemailId: { + propDefinition: [ + rinkel, + "voicemailId", + ], + }, + }, + async run({ $ }) { + const response = await this.rinkel.getVoicemail({ + $, + id: this.voicemailId, + }); + $.export("$summary", `Voicemail ${this.voicemailId} retrieved`); + return response; + }, +}; diff --git a/components/rinkel/actions/update-note/update-note.mjs b/components/rinkel/actions/update-note/update-note.mjs new file mode 100644 index 0000000000000..5109ff9d88c19 --- /dev/null +++ b/components/rinkel/actions/update-note/update-note.mjs @@ -0,0 +1,44 @@ +import rinkel from "../../rinkel.app.mjs"; + +export default { + key: "rinkel-update-note", + name: "Update Note", + description: "Update a note on a call. [See the documentation](https://developers.rinkel.com/docs/api/update-a-note-in-a-call-detail-record)", + version: "0.0.1", + type: "action", + props: { + rinkel, + callId: { + propDefinition: [ + rinkel, + "callId", + ], + }, + noteId: { + propDefinition: [ + rinkel, + "noteId", + (c) => ({ + callId: c.callId, + }), + ], + }, + content: { + type: "string", + label: "Content", + description: "The content of the note", + }, + }, + async run({ $ }) { + const response = await this.rinkel.updateNote({ + $, + callId: this.callId, + noteId: this.noteId, + data: { + content: this.content, + }, + }); + $.export("$summary", `Note updated for call ${this.callId}`); + return response; + }, +}; diff --git a/components/rinkel/package.json b/components/rinkel/package.json index e586bc8f285b9..ac70203f77554 100644 --- a/components/rinkel/package.json +++ b/components/rinkel/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/rinkel", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Rinkel Components", "main": "rinkel.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/rinkel/rinkel.app.mjs b/components/rinkel/rinkel.app.mjs index d53fd832d0556..d74c0a7b8f539 100644 --- a/components/rinkel/rinkel.app.mjs +++ b/components/rinkel/rinkel.app.mjs @@ -1,11 +1,162 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "rinkel", - propDefinitions: {}, + propDefinitions: { + callId: { + type: "string", + label: "Call ID", + description: "The ID of the call to get the call detail records for", + async options({ page }) { + const response = await this.listCallDetailRecords({ + params: { + page: page + 1, + sort: "date", + sortOrder: "DESC", + }, + }); + return response.data.map((call) => call.id); + }, + }, + recordingId: { + type: "string", + label: "Recording ID", + description: "The ID of the recording to get the details for", + async options({ page }) { + const response = await this.listCallRecordings({ + params: { + page: page + 1, + sort: "date", + sortOrder: "DESC", + }, + }); + return response.data.map((recording) => recording.id); + }, + }, + voicemailId: { + type: "string", + label: "Voicemail ID", + description: "The ID of the voicemail to get the details for", + async options({ page }) { + const response = await this.listVoicemails({ + params: { + page: page + 1, + sort: "date", + sortOrder: "DESC", + }, + }); + return response.data.map((voicemail) => voicemail.id); + }, + }, + noteId: { + type: "string", + label: "Note ID", + description: "The ID of the note to update", + async options({ callId }) { + const response = await this.getCallDetailRecord({ + id: callId, + }); + const notes = response.data.notes; + return notes.map((note) => ({ + label: note.content, + value: note.id, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.rinkel.com/v1"; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + headers: { + "x-rinkel-api-key": this.$auth.api_key, + }, + ...opts, + }); + }, + createWebhook({ + event, ...opts + }) { + return this._makeRequest({ + path: `/webhooks/${event}`, + method: "POST", + ...opts, + }); + }, + deleteWebhook({ + event, ...opts + }) { + return this._makeRequest({ + path: `/webhooks/${event}`, + method: "DELETE", + ...opts, + }); + }, + getCallDetailRecord({ + id, ...opts + }) { + return this._makeRequest({ + path: `/call-detail-records/${id}`, + ...opts, + }); + }, + getCallRecording({ + id, ...opts + }) { + return this._makeRequest({ + path: `/recordings/${id}`, + ...opts, + }); + }, + getVoicemail({ + id, ...opts + }) { + return this._makeRequest({ + path: `/voicemails/${id}/stream`, + ...opts, + }); + }, + listCallDetailRecords(opts = {}) { + return this._makeRequest({ + path: "/call-detail-records", + ...opts, + }); + }, + listCallRecordings(opts = {}) { + return this._makeRequest({ + path: "/recordings", + ...opts, + }); + }, + listVoicemails(opts = {}) { + return this._makeRequest({ + path: "/voicemails", + ...opts, + }); + }, + addNote({ + id, ...opts + }) { + return this._makeRequest({ + path: `/call-detail-records/${id}/note`, + method: "PUT", + ...opts, + }); + }, + updateNote({ + callId, noteId, ...opts + }) { + return this._makeRequest({ + path: `/call-detail-records/${callId}/note/${noteId}`, + method: "PATCH", + ...opts, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/rinkel/sources/call-ended/call-ended.mjs b/components/rinkel/sources/call-ended/call-ended.mjs new file mode 100644 index 0000000000000..7865c767693f9 --- /dev/null +++ b/components/rinkel/sources/call-ended/call-ended.mjs @@ -0,0 +1,26 @@ +import common from "../common/base-webhook.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "rinkel-call-ended", + name: "Call Ended (Instant)", + description: "Emit new event when a call ends. [See the documentation](https://developers.rinkel.com/docs/api/subscribe-to-a-webhook)", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEvent() { + return "callEnd"; + }, + generateMeta(event) { + return { + id: event.id, + summary: `Call ended: ${event.cause}`, + ts: Date.parse(event.datetime), + }; + }, + }, + sampleEmit, +}; diff --git a/components/rinkel/sources/call-ended/test-event.mjs b/components/rinkel/sources/call-ended/test-event.mjs new file mode 100644 index 0000000000000..d61b5d770176e --- /dev/null +++ b/components/rinkel/sources/call-ended/test-event.mjs @@ -0,0 +1,5 @@ +export default { + id: '1c8b83a7c690084224ec3984515bc1a2', + datetime: '2023-06-14T13:56:24.969Z', + cause: 'ANSWERED' +} \ No newline at end of file diff --git a/components/rinkel/sources/common/base-webhook.mjs b/components/rinkel/sources/common/base-webhook.mjs new file mode 100644 index 0000000000000..dd27bf8cd4326 --- /dev/null +++ b/components/rinkel/sources/common/base-webhook.mjs @@ -0,0 +1,42 @@ +import rinkel from "../../rinkel.app.mjs"; +import { ConfigurationError } from "@pipedream/platform"; + +export default { + props: { + rinkel, + http: "$.interface.http", + }, + hooks: { + async activate() { + await this.rinkel.createWebhook({ + event: this.getEvent(), + data: { + url: this.http.endpoint, + contentType: "application/json", + active: true, + }, + }); + }, + async deactivate() { + await this.rinkel.deleteWebhook({ + event: this.getEvent(), + }); + }, + }, + methods: { + getEvent() { + throw new ConfigurationError("getEvent must be implemented"); + }, + generateMeta() { + throw new ConfigurationError("generateMeta must be implemented"); + }, + }, + async run(event) { + const { body } = event; + if (!body) { + return; + } + const meta = this.generateMeta(body); + this.$emit(body, meta); + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d69ccf45fdd07..16e37a4b24703 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11952,7 +11952,11 @@ importers: specifier: ^1.5.1 version: 1.6.6 - components/rinkel: {} + components/rinkel: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/rippling: dependencies: