From 8fc65e1af67c8e56ac441468e082663b6cdcbfcd Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 1 Oct 2024 10:38:52 -0300 Subject: [PATCH] New Components - moaform (#14133) * moaform init * [Components] moaform #14132 Sources - New Submission (Instant) * pnpm update * Fix retention days label Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * some adjusts --------- Co-authored-by: Leo Vu Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- components/moaform/common/constants.mjs | 30 ++++++ components/moaform/moaform.app.mjs | 67 +++++++++++- components/moaform/package.json | 7 +- .../new-submission-instant.mjs | 100 ++++++++++++++++++ .../new-submission-instant/test-event.mjs | 18 ++++ pnpm-lock.yaml | 5 +- 6 files changed, 219 insertions(+), 8 deletions(-) create mode 100644 components/moaform/common/constants.mjs create mode 100644 components/moaform/sources/new-submission-instant/new-submission-instant.mjs create mode 100644 components/moaform/sources/new-submission-instant/test-event.mjs diff --git a/components/moaform/common/constants.mjs b/components/moaform/common/constants.mjs new file mode 100644 index 0000000000000..dbce28a0a61e4 --- /dev/null +++ b/components/moaform/common/constants.mjs @@ -0,0 +1,30 @@ +export const RETENTION_DAYS_OPTIONS = [ + { + label: "1", + value: 1, + }, + { + label: "3", + value: 3, + }, + { + label: "5", + value: 5, + }, + { + label: "7", + value: 7, + }, + { + label: "10", + value: 10, + }, + { + label: "15", + value: 15, + }, + { + label: "30", + value: 30, + }, +]; diff --git a/components/moaform/moaform.app.mjs b/components/moaform/moaform.app.mjs index 61ac154dc3314..09007f770c539 100644 --- a/components/moaform/moaform.app.mjs +++ b/components/moaform/moaform.app.mjs @@ -1,11 +1,68 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "moaform", - propDefinitions: {}, + propDefinitions: { + formId: { + type: "string", + label: "Form ID", + description: "The ID of the form to monitor for new submissions", + async options({ page }) { + const { items } = await this.getForms({ + params: { + page: page + 1, + }, + }); + return items.map(({ + id: value, title: label, + }) => ({ + label, + value, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.moaform.com/v1"; + }, + _headers() { + return { + Authorization: `Bearer ${this.$auth.api_key}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }); + }, + getForms(opts = {}) { + return this._makeRequest({ + ...opts, + path: "/forms", + }); + }, + createWebhook({ + formId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/forms/${formId}/webhooks`, + ...opts, + }); + }, + deleteWebhook({ + formId, webhookId, + }) { + return this._makeRequest({ + method: "DELETE", + path: `/forms/${formId}/webhooks/${webhookId}`, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/moaform/package.json b/components/moaform/package.json index e140fabbf0869..209996644a6c8 100644 --- a/components/moaform/package.json +++ b/components/moaform/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/moaform", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Moaform Components", "main": "moaform.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} diff --git a/components/moaform/sources/new-submission-instant/new-submission-instant.mjs b/components/moaform/sources/new-submission-instant/new-submission-instant.mjs new file mode 100644 index 0000000000000..85668ca7d3524 --- /dev/null +++ b/components/moaform/sources/new-submission-instant/new-submission-instant.mjs @@ -0,0 +1,100 @@ +import crypto from "crypto"; +import { RETENTION_DAYS_OPTIONS } from "../../common/constants.mjs"; +import moaform from "../../moaform.app.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + key: "moaform-new-submission-instant", + name: "New Submission (Instant)", + description: "Emit new event every time a new form submission is received.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + moaform, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + formId: { + propDefinition: [ + moaform, + "formId", + ], + }, + retentionDays: { + type: "integer", + label: "Retention Days", + description: "Resend restriction days", + options: RETENTION_DAYS_OPTIONS, + optional: true, + }, + secret: { + type: "string", + label: "Secret Code", + description: "This code is used to verify that the data received at the specified endpoint has indeed been sent from Moaform and has not been tampered with.", + secret: true, + optional: true, + }, + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + }, + hooks: { + async activate() { + const response = await this.moaform.createWebhook({ + formId: this.formId, + data: { + endpoint: this.http.endpoint, + enabled: true, + secret: this.secret, + verify_ssl: true, + retention_days: this.retentionDays, + }, + }); + this._setWebhookId(response.id); + }, + async deactivate() { + const webhookId = this.db.get("webhookId"); + await this.moaform.deleteWebhook({ + formId: this.formId, + webhookId, + }); + }, + }, + async run({ + bodyRaw, body, headers, + }) { + + if (this.secret) { + const signature = headers["moaform-signature"]; + const receivedSig = signature.split("sha256=")[1]; + + const calculatedSig = crypto + .createHmac("sha256", this.secret) + .update(bodyRaw) + .digest("base64"); + + if (receivedSig !== calculatedSig) { + return this.http.respond({ + status: 401, + body: "Unauthorized", + }); + } + } + + const ts = Date.parse(body.submitted_at); + this.$emit(body, { + id: body.event_id, + summary: `New submission received for form ${this.formId}`, + ts: ts, + }); + }, + sampleEmit, +}; diff --git a/components/moaform/sources/new-submission-instant/test-event.mjs b/components/moaform/sources/new-submission-instant/test-event.mjs new file mode 100644 index 0000000000000..6fc8f83f5c9f2 --- /dev/null +++ b/components/moaform/sources/new-submission-instant/test-event.mjs @@ -0,0 +1,18 @@ +export default { + "event_id": "105fa72f-9e6e-4667-8ead-22b0a3ed254a", + "event_type": "response_completed", + "hidden": {}, + "response_id": "test#123-45-67890", + "submitted_at": "2024-09-27T21:00:55Z", + "form": { + "id": "MG7eAk", + "title": "form title", + "report_url": "https://www.moaform.com/reports/q945EegynYD8G2xM", + "answer_url": "https://moaform.com/q/not-started-collecting" + }, + "answers": [], + "thankyou": { + "id": "cm1l7axyf2t9x0fqrly27vdn7", + "url": "https://answer.moaform.com/answers/MG7eAk/thankyou/Wo2b1Z09wx5" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 926c70f486320..7aba44d1406f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6073,7 +6073,10 @@ importers: '@pipedream/platform': 1.5.1 components/moaform: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/mobile_text_alerts: specifiers: {}