diff --git a/components/wati/app/wati.app.ts b/components/ai_textraction/ai_textraction.app.mjs similarity index 65% rename from components/wati/app/wati.app.ts rename to components/ai_textraction/ai_textraction.app.mjs index 208ee0d199f21..6d9749e003826 100644 --- a/components/wati/app/wati.app.ts +++ b/components/ai_textraction/ai_textraction.app.mjs @@ -1,8 +1,6 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ +export default { type: "app", - app: "wati", + app: "ai_textraction", propDefinitions: {}, methods: { // this.$auth contains connected account data @@ -10,4 +8,4 @@ export default defineApp({ console.log(Object.keys(this.$auth)); }, }, -}); \ No newline at end of file +}; diff --git a/components/ai_textraction/package.json b/components/ai_textraction/package.json new file mode 100644 index 0000000000000..2709b2b89931a --- /dev/null +++ b/components/ai_textraction/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/ai_textraction", + "version": "0.0.1", + "description": "Pipedream AI Textraction Components", + "main": "ai_textraction.app.mjs", + "keywords": [ + "pipedream", + "ai_textraction" + ], + "homepage": "https://pipedream.com/apps/ai_textraction", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/suitedash/app/suitedash.app.ts b/components/attractwell/attractwell.app.mjs similarity index 64% rename from components/suitedash/app/suitedash.app.ts rename to components/attractwell/attractwell.app.mjs index c8b2488f4b65c..4b793833e3ef3 100644 --- a/components/suitedash/app/suitedash.app.ts +++ b/components/attractwell/attractwell.app.mjs @@ -1,8 +1,6 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ +export default { type: "app", - app: "suitedash", + app: "attractwell", propDefinitions: {}, methods: { // this.$auth contains connected account data @@ -10,4 +8,4 @@ export default defineApp({ console.log(Object.keys(this.$auth)); }, }, -}); \ No newline at end of file +}; diff --git a/components/attractwell/package.json b/components/attractwell/package.json new file mode 100644 index 0000000000000..39f0ed5de2719 --- /dev/null +++ b/components/attractwell/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/attractwell", + "version": "0.0.1", + "description": "Pipedream AttractWell Components", + "main": "attractwell.app.mjs", + "keywords": [ + "pipedream", + "attractwell" + ], + "homepage": "https://pipedream.com/apps/attractwell", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/paperform/app/paperform.app.ts b/components/deepimage/deepimage.app.mjs similarity index 63% rename from components/paperform/app/paperform.app.ts rename to components/deepimage/deepimage.app.mjs index 6afce6d351aff..6d3b6cac93c3f 100644 --- a/components/paperform/app/paperform.app.ts +++ b/components/deepimage/deepimage.app.mjs @@ -1,8 +1,6 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ +export default { type: "app", - app: "paperform", + app: "deepimage", propDefinitions: {}, methods: { // this.$auth contains connected account data @@ -10,4 +8,4 @@ export default defineApp({ console.log(Object.keys(this.$auth)); }, }, -}); +}; diff --git a/components/deepimage/package.json b/components/deepimage/package.json new file mode 100644 index 0000000000000..5feea41b0a543 --- /dev/null +++ b/components/deepimage/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/deepimage", + "version": "0.0.1", + "description": "Pipedream DeepImage Components", + "main": "deepimage.app.mjs", + "keywords": [ + "pipedream", + "deepimage" + ], + "homepage": "https://pipedream.com/apps/deepimage", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/fakturoid/actions/cancel-uncancel-invoice/cancel-uncancel-invoice.mjs b/components/fakturoid/actions/cancel-uncancel-invoice/cancel-uncancel-invoice.mjs new file mode 100644 index 0000000000000..783fc302950e8 --- /dev/null +++ b/components/fakturoid/actions/cancel-uncancel-invoice/cancel-uncancel-invoice.mjs @@ -0,0 +1,49 @@ +import constants from "../../common/constants.mjs"; +import fakturoid from "../../fakturoid.app.mjs"; + +export default { + key: "fakturoid-cancel-uncancel-invoice", + name: "Cancel or Uncancel Invoice", + description: "Cancels an existing invoice or revokes previous cancellation. [See the documentation](https://www.fakturoid.cz/api/v3)", + version: "0.0.1", + type: "action", + props: { + fakturoid, + accountSlug: { + propDefinition: [ + fakturoid, + "accountSlug", + ], + }, + invoiceId: { + propDefinition: [ + fakturoid, + "invoiceId", + ({ accountSlug }) => ({ + accountSlug, + }), + ], + }, + action: { + type: "string", + label: "Action", + description: "The action to perform on the invoice (cancel or uncancel)", + options: constants.ACTION_OPTIONS, + }, + }, + async run({ $ }) { + const response = await this.fakturoid.fireInvoice({ + $, + accountSlug: this.accountSlug, + invoiceId: this.invoiceId, + params: { + event: this.action, + }, + }); + + $.export("$summary", `${this.action === "cancel" + ? "Cancelled" + : "Uncancelled"} invoice with ID ${this.invoiceId}`); + return response; + }, +}; diff --git a/components/fakturoid/actions/create-invoice/create-invoice.mjs b/components/fakturoid/actions/create-invoice/create-invoice.mjs new file mode 100644 index 0000000000000..f11db2fb28c54 --- /dev/null +++ b/components/fakturoid/actions/create-invoice/create-invoice.mjs @@ -0,0 +1,139 @@ +import constants, { parseObject } from "../../common/constants.mjs"; +import fakturoid from "../../fakturoid.app.mjs"; + +export default { + key: "fakturoid-create-invoice", + name: "Create Invoice", + description: "Creates a new invoice. [See the documentation](https://www.fakturoid.cz/api/v3/invoices)", + version: "0.0.1", + type: "action", + props: { + fakturoid, + accountSlug: { + propDefinition: [ + fakturoid, + "accountSlug", + ], + }, + customId: { + type: "string", + label: "Custom Id", + description: "Identifier in your application", + optional: true, + }, + documentType: { + type: "string", + label: "Document Type", + description: "Type of document", + options: constants.DOCUMENT_TYPE_OPTIONS, + reloadProps: true, + optional: true, + }, + subjectId: { + propDefinition: [ + fakturoid, + "subjectId", + ({ accountSlug }) => ({ + accountSlug, + }), + ], + }, + orderNumber: { + type: "string", + label: "Order Number", + description: "Order number in your application", + optional: true, + }, + note: { + type: "string", + label: "Note", + description: "Additional notes for the invoice", + optional: true, + }, + due: { + type: "string", + label: "Due", + description: "Invoice due date in number of days from today", + optional: true, + }, + issuedOn: { + type: "string", + label: "Issued On", + description: "Date of issue. **Format: YYYY-MM-DD**", + optional: true, + }, + taxableFulfillmentDue: { + type: "string", + label: "Taxable Fulfillment Due", + description: "Chargeable event date.", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "List of tags", + optional: true, + }, + roundTotal: { + type: "boolean", + label: "Round Total", + description: "Round total amount (VAT included)", + optional: true, + }, + subtotal: { + type: "string", + label: "Subtotal", + description: "Total without VAT", + optional: true, + }, + total: { + type: "string", + label: "Total", + description: "Total with VAT", + optional: true, + }, + lines: { + type: "string[]", + label: "Lines", + description: "List of object lines to invoice. [See the documentation](https://www.fakturoid.cz/api/v3/invoices#attributes). **Example: {\"name\": \"Hard work\",\"quantity\": \"1.0\",\"unit_name\": \"h\",\"unit_price\": \"40000\",\"vat_rate\": \"21\"}**", + }, + }, + async additionalProps() { + const props = {}; + if (this.documentType === "proforma") { + props.proformaFollowupDocument = { + type: "string", + label: "Proforma Followup Document", + description: "What to issue after a proforma is paid.", + options: constants.PROFORMA_OPTIONS, + optional: true, + }; + } + return props; + }, + async run({ $ }) { + const response = await this.fakturoid.createInvoice({ + $, + accountSlug: this.accountSlug, + data: { + custom_id: this.customId, + document_type: this.documentType, + proforma_followup_document: this.proformaFollowupDocument, + subject_id: this.subjectId, + order_number: this.orderNumber, + note: this.note, + due: this.due, + issued_on: this.issuedOn, + taxable_fulfillment_due: this.taxableFulfillmentDue, + tags: parseObject(this.tags), + round_total: this.roundTotal, + subtotal: this.subtotal && parseFloat(this.subtotal), + total: this.total && parseFloat(this.total), + lines: parseObject(this.lines), + }, + }); + + $.export("$summary", `Successfully created invoice with ID ${response.id}`); + return response; + }, +}; diff --git a/components/fakturoid/actions/pay-remove-payment-invoice/pay-remove-payment-invoice.mjs b/components/fakturoid/actions/pay-remove-payment-invoice/pay-remove-payment-invoice.mjs new file mode 100644 index 0000000000000..135fa078c2374 --- /dev/null +++ b/components/fakturoid/actions/pay-remove-payment-invoice/pay-remove-payment-invoice.mjs @@ -0,0 +1,109 @@ +import constants from "../../common/constants.mjs"; +import fakturoid from "../../fakturoid.app.mjs"; + +export default { + key: "fakturoid-pay-remove-payment-invoice", + name: "Pay or Remove Payment for Invoice", + description: "Executes payment for an invoice or removes an already applied payment. [See the documentation](https://www.fakturoid.cz/api/v3/invoice-payments)", + version: "0.0.1", + type: "action", + props: { + fakturoid, + accountSlug: { + propDefinition: [ + fakturoid, + "accountSlug", + ], + }, + invoiceId: { + propDefinition: [ + fakturoid, + "invoiceId", + ({ accountSlug }) => ({ + accountSlug, + }), + ], + }, + actionType: { + type: "string", + label: "Action Type", + description: "Specify if you want to execute or remove a payment", + options: constants.ACTION_TYPE_OPTIONS, + reloadProps: true, + }, + }, + async additionalProps() { + const props = {}; + if (this.actionType === "execute") { + props.paidOn = { + type: "string", + label: "Paid On", + description: "Payment date. **Format: YYYY-MM-DD** Default: Today", + optional: true, + }; + props.currency = { + type: "string", + label: "Currency", + description: "Currency [ISO Code](https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes) (same as invoice currency)", + optional: true, + }; + props.amount = { + type: "string", + label: "Amount", + description: "Paid amount in document currency. Default: Remaining amount to pay", + optional: true, + }; + props.markDocumentAsPaid = { + type: "boolean", + label: "Mark Document As Paid", + description: "Mark document as paid? Default: true if the total paid amount becomes greater or equal to remaining amount to pay", + optional: true, + }; + } else if (this.actionType === "remove") { + props.paymentId = { + type: "string", + label: "Payment ID", + description: "ID of the payment to be removed.", + options: async () => { + const { payments } = await this.fakturoid.getInvoice({ + accountSlug: this.accountSlug, + invoiceId: this.invoiceId, + }); + + return payments.map(({ + id: value, paid_on: pOn, currency, amount, + }) => ({ + label: `${currency} ${amount} (${pOn})`, + value, + })); + }, + }; + } + return props; + }, + async run({ $ }) { + if (this.actionType === "execute") { + const response = await this.fakturoid.payInvoice({ + accountSlug: this.accountSlug, + invoiceId: this.invoiceId, + data: { + paid_on: this.paidOn, + currency: this.currency, + amount: this.amount && parseFloat(this.amount), + mark_document_as_paid: this.markDocumentAsPaid, + }, + }); + $.export("$summary", `Successfully executed payment for invoice ID ${this.invoiceId}`); + return response; + } else if (this.actionType === "remove") { + const response = await this.fakturoid.removePayment({ + $, + accountSlug: this.accountSlug, + invoiceId: this.invoiceId, + paymentId: this.paymentId, + }); + $.export("$summary", `Successfully removed payment ID ${this.paymentId} from invoice ID ${this.invoiceId}`); + return response; + } + }, +}; diff --git a/components/fakturoid/common/constants.mjs b/components/fakturoid/common/constants.mjs new file mode 100644 index 0000000000000..97dbb8ff255b2 --- /dev/null +++ b/components/fakturoid/common/constants.mjs @@ -0,0 +1,159 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; + +const DOCUMENT_TYPE_OPTIONS = [ + { + label: "Invoice", + value: "invoice", + }, + { + label: "Proforma", + value: "proforma", + }, + { + label: "Legacy partial proforma (cannot be set for new documents)", + value: "partial_proforma", + }, + { + label: "Correction document for an invoice", + value: "correction", + }, + { + label: "Tax document for a received payment", + value: "tax_document", + }, + { + label: "Final invoice for tax documents", + value: "final_invoice", + }, +]; + +const PROFORMA_OPTIONS = [ + { + label: "Invoice paid", + value: "final_invoice_paid", + }, + { + label: "Invoice with edit", + value: "final_invoice", + }, + { + label: "Document to payment", + value: "tax_document", + }, + { + label: "None", + value: "none", + }, +]; + +const ACTION_OPTIONS = [ + { + label: "Cancel", + value: "cancel", + }, + { + label: "Uncancel", + value: "undo_cancel", + }, +]; + +const ACTION_TYPE_OPTIONS = [ + { + label: "Execute Payment", + value: "execute", + }, + { + label: "Remove Payment", + value: "remove", + }, +]; + +const EVENT_OPTIONS = [ + { + label: "Invoice was updated", + value: "invoice_updated", + }, + { + label: "Invoice was deleted and moved to the trash", + value: "invoice_removed", + }, + { + label: "Invoice was restored from the trash", + value: "invoice_restored", + }, + { + label: "Invoice was marked as overdue", + value: "invoice_overdue", + }, + { + label: "Payment was added to document and marked it as paid", + value: "invoice_paid", + }, + { + label: "Payment was added to the invoice, but didn't mark it as paid", + value: "invoice_payment_added", + }, + { + label: "Invoice was marked as unpaid, and the payments in the additional payload were removed", + value: "invoice_payment_removed", + }, + { + label: "Email with the invoice was sent to the subject", + value: "invoice_sent", + }, + { + label: "Invoice was locked", + value: "invoice_locked", + }, + { + label: "Invoice was unlocked", + value: "invoice_unlocked", + }, + { + label: "Invoice was marked as cancelled", + value: "invoice_cancelled", + }, + { + label: "Cancellation was removed", + value: "invoice_cancellation_removed", + }, + { + label: "Invoice was marked as uncollectible", + value: "invoice_uncollectible", + }, + { + label: "Uncollectibility was removed", + value: "invoice_uncollectible_removed", + }, +]; + +export default { + DOCUMENT_TYPE_OPTIONS, + PROFORMA_OPTIONS, + ACTION_OPTIONS, + ACTION_TYPE_OPTIONS, + EVENT_OPTIONS, +}; diff --git a/components/fakturoid/common/utils.mjs b/components/fakturoid/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/fakturoid/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/fakturoid/fakturoid.app.mjs b/components/fakturoid/fakturoid.app.mjs index a6c9980621f13..e4c7d5228ab71 100644 --- a/components/fakturoid/fakturoid.app.mjs +++ b/components/fakturoid/fakturoid.app.mjs @@ -1,11 +1,167 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "fakturoid", - propDefinitions: {}, + propDefinitions: { + accountSlug: { + type: "string", + label: "Account", + description: "The account you want to use", + async options() { + const { accounts } = await this.getLoggedUser(); + + return accounts.map(({ + slug: value, name: label, + }) => ({ + label, + value, + })); + }, + }, + subjectId: { + type: "string", + label: "Subject Id", + description: "The id of the subject", + async options({ + page, accountSlug, + }) { + const data = await this.listSubjects({ + accountSlug, + params: { + page: page + 1, + }, + }); + + return data.map(({ + id: value, name, full_name: fName, + }) => ({ + label: fName || name, + value, + })); + }, + }, + invoiceId: { + type: "string", + label: "Invoice ID", + description: "Unique identifier for the invoice", + async options({ + page, accountSlug, + }) { + const data = await this.listInvoices({ + accountSlug, + params: { + page: page + 1, + }, + }); + + return data.map(({ + id: value, client_name: cName, due_on: due, currency, total, + }) => ({ + label: `${cName} - ${currency} ${total} - Due On: ${due}`, + value, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl(accountSlug) { + return `https://app.fakturoid.cz/api/v3${accountSlug + ? `/accounts/${accountSlug}` + : ""}`; + }, + _headers() { + return { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }; + }, + _makeRequest({ + $ = this, accountSlug, path, ...opts + }) { + return axios($, { + url: this._baseUrl(accountSlug) + path, + headers: this._headers(), + ...opts, + }); + }, + getLoggedUser() { + return this._makeRequest({ + path: "/user.json", + }); + }, + getInvoice({ + invoiceId, ...opts + }) { + return this._makeRequest({ + path: `/invoices/${invoiceId}.json`, + ...opts, + }); + }, + listSubjects(opts = {}) { + return this._makeRequest({ + path: "/subjects.json", + ...opts, + }); + }, + listInvoices(opts = {}) { + return this._makeRequest({ + path: "/invoices.json", + ...opts, + }); + }, + createInvoice(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/invoices.json", + ...opts, + }); + }, + fireInvoice({ + invoiceId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/invoices/${invoiceId}/fire.json`, + ...opts, + }); + }, + payInvoice({ + invoiceId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/invoices/${invoiceId}/payments.json`, + ...opts, + }); + }, + removePayment({ + invoiceId, paymentId, ...opts + }) { + return this._makeRequest({ + method: "DELETE", + path: `/invoices/${invoiceId}/payments/${paymentId}.json`, + ...opts, + }); + }, + async *paginate({ + fn, params = {}, ...opts + }) { + let hasMore = false; + let page = 0; + + do { + params.page = ++page; + const data = await fn({ + params, + ...opts, + }); + for (const d of data) { + yield d; + } + + hasMore = data.length; + + } while (hasMore); }, }, -}; \ No newline at end of file +}; diff --git a/components/fakturoid/package.json b/components/fakturoid/package.json index 0b465740c1174..31085d2cedd89 100644 --- a/components/fakturoid/package.json +++ b/components/fakturoid/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/fakturoid", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Fakturoid Components", "main": "fakturoid.app.mjs", "keywords": [ @@ -11,5 +11,9 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} + diff --git a/components/fakturoid/sources/common/base.mjs b/components/fakturoid/sources/common/base.mjs new file mode 100644 index 0000000000000..45859d6c232b8 --- /dev/null +++ b/components/fakturoid/sources/common/base.mjs @@ -0,0 +1,77 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import fakturoid from "../../fakturoid.app.mjs"; + +export default { + props: { + fakturoid, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + accountSlug: { + propDefinition: [ + fakturoid, + "accountSlug", + ], + }, + }, + methods: { + _getLastDate() { + return this.db.get("lastDate") || "1970-01-01T00:00:00"; + }, + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); + }, + getParams(lastDate) { + return { + since: lastDate, + }; + }, + getDateField() { + return "created_at"; + }, + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + const dateField = this.getDateField(); + const response = this.fakturoid.paginate({ + fn: this.getFunction(), + accountSlug: this.accountSlug, + params: this.getParams(lastDate), + }); + + let responseArray = []; + for await (const item of response) { + responseArray.push(item); + } + + if (responseArray.length) { + responseArray = responseArray + .sort((a, b) => Date.parse(b[dateField]) - Date.parse(a[dateField])); + + if (maxResults && (responseArray.length > maxResults)) { + responseArray.length = maxResults; + } + this._setLastDate(responseArray[0][dateField]); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: `${item.id}-${item[dateField]}`, + summary: this.getSummary(item), + ts: Date.parse(item[dateField]), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/fakturoid/sources/invoice-updated/invoice-updated.mjs b/components/fakturoid/sources/invoice-updated/invoice-updated.mjs new file mode 100644 index 0000000000000..7a632c6c3615a --- /dev/null +++ b/components/fakturoid/sources/invoice-updated/invoice-updated.mjs @@ -0,0 +1,30 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "fakturoid-invoice-updated", + name: "New Invoice Updated", + description: "Emit new event when an invoice is created or updated.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFunction() { + return this.fakturoid.listInvoices; + }, + getSummary(invoice) { + return `New invoice updated: ${invoice.number}`; + }, + getParams(lastDate) { + return { + updated_since: lastDate, + }; + }, + getDateField() { + return "updated_at"; + }, + }, + sampleEmit, +}; diff --git a/components/fakturoid/sources/invoice-updated/test-event.mjs b/components/fakturoid/sources/invoice-updated/test-event.mjs new file mode 100644 index 0000000000000..63e50c797044c --- /dev/null +++ b/components/fakturoid/sources/invoice-updated/test-event.mjs @@ -0,0 +1,146 @@ +export default { + "id": 27, + "custom_id": null, + "document_type": "invoice", + "proforma_followup_document": null, + "correction_id": null, + "number": "2023-0021", + "number_format_id": 31, + "variable_symbol": "20230021", + "your_name": "Alexandr Hejsek", + "your_street": "Hopsinková 14", + "your_city": "Praha", + "your_zip": "10000", + "your_country": "CZ", + "your_registration_no": "87654321", + "your_vat_no": "CZ12121212", + "your_local_vat_no": null, + "client_name": "Apple Czech s.r.o.", + "client_street": "Klimentská 1216/46", + "client_city": "Praha", + "client_zip": "11000", + "client_country": "CZ", + "client_registration_no": "28897501", + "client_vat_no": "CZ28897501", + "client_local_vat_no": null, + "client_has_delivery_address": false, + "client_delivery_name": null, + "client_delivery_street": null, + "client_delivery_city": null, + "client_delivery_zip": null, + "client_delivery_country": null, + "subject_id": 16, + "subject_custom_id": null, + "generator_id": null, + "related_id": null, + "paypal": false, + "gopay": false, + "token": "69UqMuxhiA", + "status": "sent", + "order_number": null, + "issued_on": "2023-11-30", + "taxable_fulfillment_due": "2023-11-30", + "due": 14, + "due_on": "2023-12-14", + "sent_at": "2023-12-01T09:05:47.117+01:00", + "paid_on": null, + "reminder_sent_at": null, + "cancelled_at": null, + "uncollectible_at": null, + "locked_at": null, + "webinvoice_seen_on": null, + "note": "Fakturujeme Vám následující položky", + "footer_note": "", + "private_note": null, + "tags": [], + "bank_account": "1234/2010", + "iban": null, + "swift_bic": null, + "iban_visibility": "automatically", + "show_already_paid_note_in_pdf": false, + "payment_method": "bank", + "custom_payment_method": null, + "hide_bank_account": false, + "currency": "CZK", + "exchange_rate": "1.0", + "language": "cz", + "transferred_tax_liability": false, + "supply_code": null, + "oss": "disabled", + "vat_price_mode": "with_vat", + "subtotal": "9133.6", + "total": "11000.0", + "native_subtotal": "9133.6", + "native_total": "11000.0", + "remaining_amount": "11000.0", + "remaining_native_amount": "11000.0", + "eet_records": [], + "lines": [ + { + "id": 46, + "name": "Grafická karta", + "quantity": "1.0", + "unit_name": "", + "unit_price": "8264.0", + "vat_rate": 21, + "unit_price_without_vat": "8264.0", + "unit_price_with_vat": "10000.0", + "total_price_without_vat": "8264.0", + "total_vat": "1736.0", + "native_total_price_without_vat": "8264.0", + "native_total_vat": "1736.0", + "inventory": { + "item_id": 26, + "sku": "KU994RUR8465", + "article_number_type": null, + "article_number": null, + "move_id": 56 + } + }, + { + "id": 47, + "name": "Jídlo", + "quantity": "5.0", + "unit_name": "", + "unit_price": "173.92", + "vat_rate": 15, + "unit_price_without_vat": "173.92", + "unit_price_with_vat": "200.0", + "total_price_without_vat": "869.6", + "total_vat": "130.4", + "native_total_price_without_vat": "869.6", + "native_total_vat": "130.4", + "inventory": null + } + ], + "vat_rates_summary": [ + { + "vat_rate": 21, + "base": "8264.0", + "vat": "1736.0", + "currency": "CZK", + "native_base": "8264.0", + "native_vat": "1736.0", + "native_currency": "CZK" + }, + { + "vat_rate": 15, + "base": "869.6", + "vat": "130.4", + "currency": "CZK", + "native_base": "869.6", + "native_vat": "130.4", + "native_currency": "CZK" + } + ], + "paid_advances": [], + "payments": [], + "attachments": null, + "html_url": "https://app.fakturoid.cz/applecorp/invoices/27", + "public_html_url": "https://app.fakturoid.cz/applecorp/p/69UqMuxhiA/2023-0021", + "url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/invoices/27.json", + "pdf_url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/invoices/27/download.pdf", + "subject_url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/subjects/16.json", + "created_at": "2023-11-30T13:50:45.848+01:00", + "updated_at": "2023-12-01T09:05:47.187+01:00" +} \ No newline at end of file diff --git a/components/fakturoid/sources/new-contact/new-contact.mjs b/components/fakturoid/sources/new-contact/new-contact.mjs new file mode 100644 index 0000000000000..b90f04af741cf --- /dev/null +++ b/components/fakturoid/sources/new-contact/new-contact.mjs @@ -0,0 +1,22 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "fakturoid-new-contact", + name: "New Contact Added", + description: "Emit new event when a contact (subject) is added in Fakturoid.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFunction() { + return this.fakturoid.listSubjects; + }, + getSummary(contact) { + return `New Contact Added: ${contact.name}`; + }, + }, + sampleEmit, +}; diff --git a/components/fakturoid/sources/new-contact/test-event.mjs b/components/fakturoid/sources/new-contact/test-event.mjs new file mode 100644 index 0000000000000..4e23ba4496728 --- /dev/null +++ b/components/fakturoid/sources/new-contact/test-event.mjs @@ -0,0 +1,53 @@ +export default { + "id": 16, + "custom_id": null, + "user_id": null, + "type": "customer", + "name": "Apple Czech s.r.o.", + "full_name": null, + "email": "pokus@test.cz", + "email_copy": null, + "phone": null, + "web": "https://www.apple.cz", + "street": "Klimentská 1216/46", + "city": "Praha", + "zip": "11000", + "country": "CZ", + "has_delivery_address": false, + "delivery_name": null, + "delivery_street": null, + "delivery_city": null, + "delivery_zip": null, + "delivery_country": null, + "due": null, + "currency": null, + "language": null, + "private_note": null, + "registration_no": "28897501", + "vat_no": "CZ28897501", + "local_vat_no": null, + "unreliable": null, + "unreliable_checked_at": null, + "legal_form": null, + "vat_mode": null, + "bank_account": null, + "iban": null, + "swift_bic": null, + "variable_symbol": null, + "setting_update_from_ares": "inherit", + "ares_update": false, + "setting_invoice_pdf_attachments": "inherit", + "setting_estimate_pdf_attachments": "inherit", + "setting_invoice_send_reminders": "inherit", + "suggestion_enabled": true, + "custom_email_text": null, + "overdue_email_text": null, + "invoice_from_proforma_email_text": null, + "thank_you_email_text": null, + "custom_estimate_email_text": null, + "webinvoice_history": null, + "html_url": "https://app.fakturoid.cz/applecorp/subjects/16", + "url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/subjects/16.json", + "created_at": "2023-08-22T10:59:00.330+02:00", + "updated_at": "2023-08-22T10:59:00.330+02:00" +} \ No newline at end of file diff --git a/components/fakturoid/sources/new-invoice/new-invoice.mjs b/components/fakturoid/sources/new-invoice/new-invoice.mjs new file mode 100644 index 0000000000000..9369ed5788fc9 --- /dev/null +++ b/components/fakturoid/sources/new-invoice/new-invoice.mjs @@ -0,0 +1,22 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "fakturoid-new-invoice", + name: "New Invoice Created", + description: "Emit new event when a new invoice is created in Fakturoid.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFunction() { + return this.fakturoid.listInvoices; + }, + getSummary(invoice) { + return `New invoice created: ${invoice.number}`; + }, + }, + sampleEmit, +}; diff --git a/components/fakturoid/sources/new-invoice/test-event.mjs b/components/fakturoid/sources/new-invoice/test-event.mjs new file mode 100644 index 0000000000000..63e50c797044c --- /dev/null +++ b/components/fakturoid/sources/new-invoice/test-event.mjs @@ -0,0 +1,146 @@ +export default { + "id": 27, + "custom_id": null, + "document_type": "invoice", + "proforma_followup_document": null, + "correction_id": null, + "number": "2023-0021", + "number_format_id": 31, + "variable_symbol": "20230021", + "your_name": "Alexandr Hejsek", + "your_street": "Hopsinková 14", + "your_city": "Praha", + "your_zip": "10000", + "your_country": "CZ", + "your_registration_no": "87654321", + "your_vat_no": "CZ12121212", + "your_local_vat_no": null, + "client_name": "Apple Czech s.r.o.", + "client_street": "Klimentská 1216/46", + "client_city": "Praha", + "client_zip": "11000", + "client_country": "CZ", + "client_registration_no": "28897501", + "client_vat_no": "CZ28897501", + "client_local_vat_no": null, + "client_has_delivery_address": false, + "client_delivery_name": null, + "client_delivery_street": null, + "client_delivery_city": null, + "client_delivery_zip": null, + "client_delivery_country": null, + "subject_id": 16, + "subject_custom_id": null, + "generator_id": null, + "related_id": null, + "paypal": false, + "gopay": false, + "token": "69UqMuxhiA", + "status": "sent", + "order_number": null, + "issued_on": "2023-11-30", + "taxable_fulfillment_due": "2023-11-30", + "due": 14, + "due_on": "2023-12-14", + "sent_at": "2023-12-01T09:05:47.117+01:00", + "paid_on": null, + "reminder_sent_at": null, + "cancelled_at": null, + "uncollectible_at": null, + "locked_at": null, + "webinvoice_seen_on": null, + "note": "Fakturujeme Vám následující položky", + "footer_note": "", + "private_note": null, + "tags": [], + "bank_account": "1234/2010", + "iban": null, + "swift_bic": null, + "iban_visibility": "automatically", + "show_already_paid_note_in_pdf": false, + "payment_method": "bank", + "custom_payment_method": null, + "hide_bank_account": false, + "currency": "CZK", + "exchange_rate": "1.0", + "language": "cz", + "transferred_tax_liability": false, + "supply_code": null, + "oss": "disabled", + "vat_price_mode": "with_vat", + "subtotal": "9133.6", + "total": "11000.0", + "native_subtotal": "9133.6", + "native_total": "11000.0", + "remaining_amount": "11000.0", + "remaining_native_amount": "11000.0", + "eet_records": [], + "lines": [ + { + "id": 46, + "name": "Grafická karta", + "quantity": "1.0", + "unit_name": "", + "unit_price": "8264.0", + "vat_rate": 21, + "unit_price_without_vat": "8264.0", + "unit_price_with_vat": "10000.0", + "total_price_without_vat": "8264.0", + "total_vat": "1736.0", + "native_total_price_without_vat": "8264.0", + "native_total_vat": "1736.0", + "inventory": { + "item_id": 26, + "sku": "KU994RUR8465", + "article_number_type": null, + "article_number": null, + "move_id": 56 + } + }, + { + "id": 47, + "name": "Jídlo", + "quantity": "5.0", + "unit_name": "", + "unit_price": "173.92", + "vat_rate": 15, + "unit_price_without_vat": "173.92", + "unit_price_with_vat": "200.0", + "total_price_without_vat": "869.6", + "total_vat": "130.4", + "native_total_price_without_vat": "869.6", + "native_total_vat": "130.4", + "inventory": null + } + ], + "vat_rates_summary": [ + { + "vat_rate": 21, + "base": "8264.0", + "vat": "1736.0", + "currency": "CZK", + "native_base": "8264.0", + "native_vat": "1736.0", + "native_currency": "CZK" + }, + { + "vat_rate": 15, + "base": "869.6", + "vat": "130.4", + "currency": "CZK", + "native_base": "869.6", + "native_vat": "130.4", + "native_currency": "CZK" + } + ], + "paid_advances": [], + "payments": [], + "attachments": null, + "html_url": "https://app.fakturoid.cz/applecorp/invoices/27", + "public_html_url": "https://app.fakturoid.cz/applecorp/p/69UqMuxhiA/2023-0021", + "url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/invoices/27.json", + "pdf_url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/invoices/27/download.pdf", + "subject_url": "https://app.fakturoid.cz/api/v3/accounts/applecorp/subjects/16.json", + "created_at": "2023-11-30T13:50:45.848+01:00", + "updated_at": "2023-12-01T09:05:47.187+01:00" +} \ No newline at end of file diff --git a/components/fluidforms/fluidforms.app.mjs b/components/fluidforms/fluidforms.app.mjs new file mode 100644 index 0000000000000..e92ea8e9b831a --- /dev/null +++ b/components/fluidforms/fluidforms.app.mjs @@ -0,0 +1,11 @@ +export default { + type: "app", + app: "fluidforms", + propDefinitions: {}, + methods: { + // this.$auth contains connected account data + authKeys() { + console.log(Object.keys(this.$auth)); + }, + }, +}; diff --git a/components/fluidforms/package.json b/components/fluidforms/package.json new file mode 100644 index 0000000000000..70d8bad144f9f --- /dev/null +++ b/components/fluidforms/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/fluidforms", + "version": "0.0.1", + "description": "Pipedream FluidForms Components", + "main": "fluidforms.app.mjs", + "keywords": [ + "pipedream", + "fluidforms" + ], + "homepage": "https://pipedream.com/apps/fluidforms", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/gainsight_nxt/gainsight_nxt.app.mjs b/components/gainsight_nxt/gainsight_nxt.app.mjs new file mode 100644 index 0000000000000..7e2c5ff525189 --- /dev/null +++ b/components/gainsight_nxt/gainsight_nxt.app.mjs @@ -0,0 +1,11 @@ +export default { + type: "app", + app: "gainsight_nxt", + propDefinitions: {}, + methods: { + // this.$auth contains connected account data + authKeys() { + console.log(Object.keys(this.$auth)); + }, + }, +}; diff --git a/components/gainsight_nxt/package.json b/components/gainsight_nxt/package.json new file mode 100644 index 0000000000000..af6a3f4ee80c8 --- /dev/null +++ b/components/gainsight_nxt/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/gainsight_nxt", + "version": "0.0.1", + "description": "Pipedream Gainsight Components", + "main": "gainsight_nxt.app.mjs", + "keywords": [ + "pipedream", + "gainsight_nxt" + ], + "homepage": "https://pipedream.com/apps/gainsight_nxt", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/gainsight_px/gainsight_px.app.mjs b/components/gainsight_px/gainsight_px.app.mjs new file mode 100644 index 0000000000000..a871bea2efb9a --- /dev/null +++ b/components/gainsight_px/gainsight_px.app.mjs @@ -0,0 +1,11 @@ +export default { + type: "app", + app: "gainsight_px", + propDefinitions: {}, + methods: { + // this.$auth contains connected account data + authKeys() { + console.log(Object.keys(this.$auth)); + }, + }, +}; diff --git a/components/gainsight_px/package.json b/components/gainsight_px/package.json new file mode 100644 index 0000000000000..d206532557469 --- /dev/null +++ b/components/gainsight_px/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/gainsight_px", + "version": "0.0.1", + "description": "Pipedream Gainsight PX Components", + "main": "gainsight_px.app.mjs", + "keywords": [ + "pipedream", + "gainsight_px" + ], + "homepage": "https://pipedream.com/apps/gainsight_px", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/gmail/package.json b/components/gmail/package.json index 0cf5df98b7165..1551abd5d9a6a 100644 --- a/components/gmail/package.json +++ b/components/gmail/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/gmail", - "version": "0.1.8", + "version": "0.1.9", "description": "Pipedream Gmail Components", "main": "gmail.app.mjs", "keywords": [ diff --git a/components/gmail/sources/new-email-received/new-email-received.mjs b/components/gmail/sources/new-email-received/new-email-received.mjs index cac434de54f46..11e44da8d019f 100644 --- a/components/gmail/sources/new-email-received/new-email-received.mjs +++ b/components/gmail/sources/new-email-received/new-email-received.mjs @@ -15,7 +15,7 @@ export default { name: "New Email Received", description: "Emit new event when a new email is received.", type: "source", - version: "0.1.5", + version: "0.1.6", dedupe: "unique", props: { gmail, @@ -383,6 +383,20 @@ export default { ) : history.filter((item) => item.messagesAdded?.length); }, + async getMessageDetails(ids) { + const messages = await Promise.all(ids.map(async (id) => { + try { + const message = await this.gmail.getMessage({ + id, + }); + return message; + } catch { + console.log(`Could not find message ${id}`); + return null; + } + })); + return messages; + }, }, async run(event) { if (this.triggerType === "polling") { @@ -464,7 +478,7 @@ export default { // Fetch full message details for new messages const newMessageIds = newMessages?.map(({ id }) => id) || []; - const messageDetails = await this.gmail.getMessages(newMessageIds); + const messageDetails = await this.getMessageDetails(newMessageIds); if (!messageDetails?.length) { return; @@ -477,7 +491,11 @@ export default { this._setLastProcessedHistoryId(latestHistoryId); console.log("Updated lastProcessedHistoryId:", latestHistoryId); - messageDetails.forEach((message) => this.emitEvent(message)); + messageDetails.forEach((message) => { + if (message?.id) { + this.emitEvent(message); + } + }); } }, }; diff --git a/components/imagior/actions/generate-image/generate-image.mjs b/components/imagior/actions/generate-image/generate-image.mjs new file mode 100644 index 0000000000000..b377d7839bbf3 --- /dev/null +++ b/components/imagior/actions/generate-image/generate-image.mjs @@ -0,0 +1,80 @@ +import imagior from "../../imagior.app.mjs"; + +export default { + key: "imagior-generate-image", + name: "Generate Image", + description: "Generates a unique and robust image using a provided template. [See the documentation](https://docs.imagior.com/api-reference/image-generate)", + version: "0.0.1", + type: "action", + props: { + imagior, + templateId: { + propDefinition: [ + imagior, + "templateId", + ], + reloadProps: true, + }, + }, + async additionalProps() { + const props = {}; + if (!this.templateId) { + return props; + } + const { elements } = await this.imagior.listTemplateElements({ + templateId: this.templateId, + }); + for (const [ + key, + value, + ] of Object.entries(elements)) { + props[`customize_${key}`] = { + type: "boolean", + label: `Customize ${key}`, + optional: true, + reloadProps: true, + }; + if (this[`customize_${key}`]) { + for (const elementKey of Object.keys(value)) { + props[`${key}_${elementKey}`] = { + type: "string", + label: `${key} - ${elementKey}`, + optional: true, + }; + } + } + } + return props; + }, + async run({ $ }) { + const elements = {}; + const { elements: allElements } = await this.imagior.listTemplateElements({ + $, + templateId: this.templateId, + }); + for (const [ + key, + value, + ] of Object.entries(allElements)) { + if (!this[`customize_${key}`]) { + continue; + } + elements[key] = {}; + for (const elementKey of Object.keys(value)) { + if (this[`${key}_${elementKey}`]) { + elements[key][elementKey] = this[`${key}_${elementKey}`]; + } + } + } + + const response = await this.imagior.generateImage({ + $, + data: { + templateId: this.templateId, + elements, + }, + }); + $.export("$summary", `${response.message}`); + return response; + }, +}; diff --git a/components/imagior/imagior.app.mjs b/components/imagior/imagior.app.mjs index 6810c2e77d2d6..53d5897050d88 100644 --- a/components/imagior/imagior.app.mjs +++ b/components/imagior/imagior.app.mjs @@ -1,11 +1,62 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "imagior", - propDefinitions: {}, + propDefinitions: { + templateId: { + type: "string", + label: "Template ID", + description: "The unique ID of the design template to use", + async options() { + const templates = await this.listTemplates(); + return templates?.map(({ + id: value, name: label, + }) => ({ + value, + label, + })) || []; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.imagior.com"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, + path, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + url: `${this._baseUrl()}${path}`, + headers: { + Authorization: `Bearer ${this.$auth.api_key}`, + }, + }); + }, + listTemplates(opts = {}) { + return this._makeRequest({ + path: "/templates/all", + ...opts, + }); + }, + listTemplateElements({ + templateId, ...opts + }) { + return this._makeRequest({ + path: `/templates/${templateId}/elements`, + ...opts, + }); + }, + generateImage(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/image/generate", + ...opts, + }); }, }, }; diff --git a/components/imagior/package.json b/components/imagior/package.json index 62a18b0c136c2..6d05708249593 100644 --- a/components/imagior/package.json +++ b/components/imagior/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/imagior", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Imagior Components", "main": "imagior.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/imagior/sources/new-template/new-template.mjs b/components/imagior/sources/new-template/new-template.mjs new file mode 100644 index 0000000000000..124e8fd1cb377 --- /dev/null +++ b/components/imagior/sources/new-template/new-template.mjs @@ -0,0 +1,63 @@ +import imagior from "../../imagior.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + key: "imagior-new-template", + name: "New Template Created", + description: "Emit new event when a new template is created.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + imagior, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs") || 0; + }, + _setLastTs(lastTs) { + this.db.set("lastTs", lastTs); + }, + generateMeta(template) { + return { + id: template.id, + summary: `New Template: ${template.name}`, + ts: Date.parse(template.createdAt), + }; + }, + }, + async run() { + const lastTs = this._getLastTs(); + + const templates = await this.imagior.listTemplates({ + params: { + sort: "createdAt", + order: "desc", + }, + }); + + if (!templates?.length) { + return; + } + + const newTemplates = templates.filter(({ createdAt }) => Date.parse(createdAt) >= lastTs); + + if (!newTemplates?.length) { + return; + } + + this._setLastTs(Date.parse(newTemplates[0].createdAt)); + + newTemplates.forEach((template) => { + const meta = this.generateMeta(template); + this.$emit(template, meta); + }); + }, +}; diff --git a/components/little_green_light/README.md b/components/little_green_light/README.md index 45483012d2bf1..40abb84cb906c 100644 --- a/components/little_green_light/README.md +++ b/components/little_green_light/README.md @@ -2,6 +2,8 @@ The Little Green Light API provides access to a robust donor management platform, allowing for the creation, retrieval, update, and deletion of donor data. With the API, you can automate tasks related to fundraising, event management, and donor engagement. On Pipedream, you can harness this API to construct serverless workflows that trigger on various events, integrate with other apps, and automate repetitive tasks without managing infrastructure. +Note: Little Green Light strongly recommends against connecting your LGL account with any AI services like ChatGPT, as that could lead to unintended use of personal data. + # Example Use Cases - **Sync Donor Information to Google Sheets**: Whenever a new donor is added in Little Green Light, automatically add their details to a Google Sheet. This workflow can help maintain an up-to-date backup of donor data and facilitate easy sharing and reporting. diff --git a/components/motion/actions/get-schedules/get-schedules.mjs b/components/motion/actions/get-schedules/get-schedules.mjs new file mode 100644 index 0000000000000..acb237a8b737d --- /dev/null +++ b/components/motion/actions/get-schedules/get-schedules.mjs @@ -0,0 +1,25 @@ +import motion from "../../motion.app.mjs"; + +export default { + key: "motion-get-schedules", + name: "Retrieve Schedules", + version: "0.0.1", + description: "Get a list of schedules for your user. [See the documentation](https://docs.usemotion.com/docs/motion-rest-api/f9fec7bb61c6f-get-schedules)", + type: "action", + props: { + motion, + }, + methods: { + getSchedules($) { + return this.motion._makeRequest({ + $, + path: "schedules", + }); + }, + }, + async run({ $ }) { + const response = await this.getSchedules($); + $.export("$summary", `Successfully fetched ${response?.length} schedules`); + return response; + }, +}; diff --git a/components/motion/package.json b/components/motion/package.json index 7eaedfc5ddd1d..e0b19c52c9866 100644 --- a/components/motion/package.json +++ b/components/motion/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/motion", - "version": "0.1.0", + "version": "0.2.0", "description": "Pipedream Motion Components", "main": "motion.app.mjs", "keywords": [ @@ -13,6 +13,6 @@ "access": "public" }, "dependencies": { - "@pipedream/platform": "^1.5.1" + "@pipedream/platform": "^3.0.3" } } diff --git a/components/ngrok/actions/create-https-edge/create-https-edge.mjs b/components/ngrok/actions/create-https-edge/create-https-edge.mjs new file mode 100644 index 0000000000000..cef5483f17643 --- /dev/null +++ b/components/ngrok/actions/create-https-edge/create-https-edge.mjs @@ -0,0 +1,57 @@ +import app from "../../ngrok.app.mjs"; + +export default { + key: "ngrok-create-https-edge", + name: "Create HTTPS Edge", + description: "Create an HTTPS Edge. [See the documentation](https://ngrok.com/docs/api/resources/edges-https/#create-https-edge).", + version: "0.0.1", + type: "action", + props: { + app, + description: { + propDefinition: [ + app, + "description", + ], + }, + hostports: { + propDefinition: [ + app, + "hostports", + ], + }, + metadata: { + propDefinition: [ + app, + "metadata", + ], + }, + }, + methods: { + createHTTPSEdge(args = {}) { + return this.app.post({ + path: "/edges/https", + ...args, + }); + }, + }, + async run({ $ }) { + const { + createHTTPSEdge, + description, + hostports, + metadata, + } = this; + + const response = await createHTTPSEdge({ + $, + data: { + description, + hostports, + metadata: metadata && JSON.stringify(metadata), + }, + }); + $.export("$summary", `Successfully created new HTTPS edge with ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/ngrok/actions/delete-https-edge/delete-https-edge.mjs b/components/ngrok/actions/delete-https-edge/delete-https-edge.mjs new file mode 100644 index 0000000000000..d5ef8c4adafb4 --- /dev/null +++ b/components/ngrok/actions/delete-https-edge/delete-https-edge.mjs @@ -0,0 +1,42 @@ +import app from "../../ngrok.app.mjs"; + +export default { + key: "ngrok-delete-https-edge", + name: "Delete HTTPS Edge", + description: "Delete an HTTPS Edge. [See the documentation](https://ngrok.com/docs/api/resources/edges-https/#delete-https-edge).", + version: "0.0.1", + type: "action", + props: { + app, + edgeId: { + propDefinition: [ + app, + "edgeId", + ], + }, + }, + methods: { + deleteHTTPSEdge({ + edgeId, ...args + } = {}) { + return this.app.delete({ + path: `/edges/https/${edgeId}`, + ...args, + }); + }, + }, + async run({ $ }) { + const { + deleteHTTPSEdge, + edgeId, + } = this; + await deleteHTTPSEdge({ + $, + edgeId, + }); + $.export("$summary", "Successfully deleted HTTPS edge."); + return { + success: true, + }; + }, +}; diff --git a/components/ngrok/actions/get-https-edge/get-https-edge.mjs b/components/ngrok/actions/get-https-edge/get-https-edge.mjs new file mode 100644 index 0000000000000..522d1622682a2 --- /dev/null +++ b/components/ngrok/actions/get-https-edge/get-https-edge.mjs @@ -0,0 +1,40 @@ +import app from "../../ngrok.app.mjs"; + +export default { + key: "ngrok-get-https-edge", + name: "Get HTTPS Edge", + description: "Get the details of an HTTPS Edge. [See the documentation](https://ngrok.com/docs/api/resources/edges-https/#get-https-edge).", + version: "0.0.1", + type: "action", + props: { + app, + edgeId: { + propDefinition: [ + app, + "edgeId", + ], + }, + }, + methods: { + getHTTPSEdge({ + edgeId, ...args + } = {}) { + return this.app._makeRequest({ + path: `/edges/https/${edgeId}`, + ...args, + }); + }, + }, + async run({ $ }) { + const { + getHTTPSEdge, + edgeId, + } = this; + const response = await getHTTPSEdge({ + $, + edgeId, + }); + $.export("$summary", `Successfully retrieved HTTPS edge with ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/ngrok/actions/update-https-edge/update-https-edge.mjs b/components/ngrok/actions/update-https-edge/update-https-edge.mjs new file mode 100644 index 0000000000000..744fb9348f12a --- /dev/null +++ b/components/ngrok/actions/update-https-edge/update-https-edge.mjs @@ -0,0 +1,67 @@ +import app from "../../ngrok.app.mjs"; + +export default { + key: "ngrok-update-https-edge", + name: "Update HTTPS Edge", + description: "Updates an HTTPS Edge. [See the documentation](https://ngrok.com/docs/api/resources/edges-https/#update-https-edge).", + version: "0.0.1", + type: "action", + props: { + app, + edgeId: { + propDefinition: [ + app, + "edgeId", + ], + }, + description: { + propDefinition: [ + app, + "description", + ], + }, + hostports: { + propDefinition: [ + app, + "hostports", + ], + }, + metadata: { + propDefinition: [ + app, + "metadata", + ], + }, + }, + methods: { + updateHTTPSEdge({ + edgeId, ...args + } = {}) { + return this.app.patch({ + path: `/edges/https/${edgeId}`, + ...args, + }); + }, + }, + async run({ $ }) { + const { + updateHTTPSEdge, + edgeId, + description, + hostports, + metadata, + } = this; + + const response = await updateHTTPSEdge({ + $, + edgeId, + data: { + description, + hostports, + metadata: metadata && JSON.stringify(metadata), + }, + }); + $.export("$summary", `Successfully updated Agent Ingress ID \`${response.id}\`.`); + return response; + }, +}; diff --git a/components/ngrok/ngrok.app.mjs b/components/ngrok/ngrok.app.mjs index 8207685709577..d032d2f569bf4 100644 --- a/components/ngrok/ngrok.app.mjs +++ b/components/ngrok/ngrok.app.mjs @@ -1,11 +1,102 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "ngrok", - propDefinitions: {}, + propDefinitions: { + description: { + type: "string", + label: "Description", + description: "What this edge will be used for.", + }, + hostports: { + type: "string[]", + label: "Host Ports", + description: "Hostports served by this edge. Eg: `example.com:443`", + optional: true, + }, + metadata: { + type: "object", + label: "Metadata", + description: "The metadata of the agent ingress. Arbitrary user-defined machine-readable data.", + optional: true, + }, + edgeId: { + type: "string", + label: "Edge ID", + description: "The ID of the edge to update.", + async options({ prevContext: { url } }) { + if (url === null) { + return []; + } + const { + next_page_uri: nextPageUri, + https_edges: edges, + } = await this.listHTTPSEdges({ + url, + params: { + limit: 10, + }, + }); + const options = edges.map(({ + id: value, description: label, + }) => ({ + label, + value, + })); + return { + options, + context: { + url: nextPageUri, + }, + }; + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + getUrl(path) { + return `https://api.ngrok.com${path}`; + }, + getHeaders(headers) { + return { + ...headers, + "Authorization": `Bearer ${this.$auth.api_key}`, + "Content-Type": "application/json", + "Ngrok-Version": "2", + }; + }, + _makeRequest({ + $ = this, url, path, headers, ...args + } = {}) { + return axios($, { + ...args, + url: url || this.getUrl(path), + headers: this.getHeaders(headers), + }); + }, + post(args = {}) { + return this._makeRequest({ + method: "POST", + ...args, + }); + }, + patch(args = {}) { + return this._makeRequest({ + method: "PATCH", + ...args, + }); + }, + delete(args = {}) { + return this._makeRequest({ + method: "DELETE", + ...args, + }); + }, + listHTTPSEdges(args = {}) { + return this._makeRequest({ + path: "/edges/https", + ...args, + }); }, }, }; diff --git a/components/ngrok/package.json b/components/ngrok/package.json index 3314b55af4c19..cb986e652731f 100644 --- a/components/ngrok/package.json +++ b/components/ngrok/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/ngrok", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream ngrok Components", "main": "ngrok.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/nile_database/actions/create-user/create-user.mjs b/components/nile_database/actions/create-user/create-user.mjs index dcaf2e06c2c02..18920f39208d2 100644 --- a/components/nile_database/actions/create-user/create-user.mjs +++ b/components/nile_database/actions/create-user/create-user.mjs @@ -4,7 +4,7 @@ export default { key: "nile_database-create-user", name: "Create User", description: "Create a new database user by providing an email address and password. [See the documentation](https://www.thenile.dev/docs/reference/api-reference/users/create-user)", - version: "0.0.1", + version: "0.0.2", type: "action", props: { nile, @@ -18,6 +18,9 @@ export default { propDefinition: [ nile, "database", + (c) => ({ + workspace: c.workspace, + }), ], }, email: { diff --git a/components/nile_database/actions/execute-query/execute-query.mjs b/components/nile_database/actions/execute-query/execute-query.mjs index 1b8c0ca926268..68c13f60a0d1b 100644 --- a/components/nile_database/actions/execute-query/execute-query.mjs +++ b/components/nile_database/actions/execute-query/execute-query.mjs @@ -4,7 +4,7 @@ export default { name: "Execute Query", key: "nile_database-execute-query", description: "Execute a custom PostgreSQL query.", - version: "0.0.1", + version: "0.0.2", type: "action", props: { nile, @@ -18,6 +18,9 @@ export default { propDefinition: [ nile, "database", + (c) => ({ + workspace: c.workspace, + }), ], }, user: { diff --git a/components/nile_database/nile_database.app.mjs b/components/nile_database/nile_database.app.mjs index 0bad4b5983bc6..0e58af09fada9 100644 --- a/components/nile_database/nile_database.app.mjs +++ b/components/nile_database/nile_database.app.mjs @@ -18,8 +18,13 @@ export default { type: "string", label: "Database", description: "The database name", - async options() { - const { databases } = await this.getAuthenticatedUser(); + async options({ workspace }) { + if (!workspace) { + return []; + } + const databases = await this.listDatabases({ + workspace, + }); return databases?.map(({ name }) => name) || []; }, }, @@ -68,6 +73,14 @@ export default { ...opts, }); }, + listDatabases({ + workspace, ...opts + }) { + return this._makeRequest({ + url: `${this._globalBaseUrl()}/workspaces/${workspace}/databases`, + ...opts, + }); + }, getAuthenticatedUser(opts = {}) { return this._makeRequest({ url: `${this._globalBaseUrl()}/developers/me/full`, diff --git a/components/nile_database/package.json b/components/nile_database/package.json index 1d24c129fc4a7..b948c4735f286 100644 --- a/components/nile_database/package.json +++ b/components/nile_database/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/nile_database", - "version": "0.1.0", + "version": "0.1.1", "description": "Pipedream Nile Database Components", "main": "nile_database.app.mjs", "keywords": [ diff --git a/components/nile_database/sources/common/base.mjs b/components/nile_database/sources/common/base.mjs index 9d43dfb69515b..3a787d79281f2 100644 --- a/components/nile_database/sources/common/base.mjs +++ b/components/nile_database/sources/common/base.mjs @@ -1,5 +1,7 @@ import nile from "../../nile_database.app.mjs"; -import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import { + DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, ConfigurationError, +} from "@pipedream/platform"; export default { props: { @@ -21,9 +23,24 @@ export default { propDefinition: [ nile, "database", + (c) => ({ + workspace: c.workspace, + }), ], }, }, + hooks: { + async deploy() { + try { + await this.nile.getDatabase({ + workspace: this.workspace, + database: this.database, + }); + } catch { + throw new ConfigurationError(`Database "${this.database}" with workspace "${this.workspace}" not found`); + } + }, + }, methods: { getResourceFn() { throw new Error("getResourceFn is not implemented"); diff --git a/components/nile_database/sources/new-tenant-created/new-tenant-created.mjs b/components/nile_database/sources/new-tenant-created/new-tenant-created.mjs index fb0cd1c0249e9..067cc870d5926 100644 --- a/components/nile_database/sources/new-tenant-created/new-tenant-created.mjs +++ b/components/nile_database/sources/new-tenant-created/new-tenant-created.mjs @@ -5,7 +5,7 @@ export default { key: "nile_database-new-tenant-created", name: "New Tenant Created", description: "Emit new event when a new tenant is added to a Nile Database", - version: "0.0.1", + version: "0.0.2", type: "source", dedupe: "unique", methods: { diff --git a/components/nile_database/sources/new-user-created/new-user-created.mjs b/components/nile_database/sources/new-user-created/new-user-created.mjs index 2e7f3b6c29007..b37d2fcfe8b27 100644 --- a/components/nile_database/sources/new-user-created/new-user-created.mjs +++ b/components/nile_database/sources/new-user-created/new-user-created.mjs @@ -5,7 +5,7 @@ export default { key: "nile_database-new-user-created", name: "New User Created", description: "Emit new event when a new user is added in a Nile Database", - version: "0.0.1", + version: "0.0.2", type: "source", dedupe: "unique", methods: { diff --git a/components/paperform/.gitignore b/components/paperform/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/paperform/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/paperform/package.json b/components/paperform/package.json index a37b1da222c9f..25d4783c2b434 100644 --- a/components/paperform/package.json +++ b/components/paperform/package.json @@ -1,18 +1,18 @@ { "name": "@pipedream/paperform", - "version": "0.0.3", + "version": "0.1.0", "description": "Pipedream PaperForm Components", - "main": "dist/app/paperform.app.mjs", + "main": "paperform.app.mjs", "keywords": [ "pipedream", "paperform" ], - "files": [ - "dist" - ], "homepage": "https://pipedream.com/apps/paperform", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/paperform/paperform.app.mjs b/components/paperform/paperform.app.mjs new file mode 100644 index 0000000000000..fe4ba95739c90 --- /dev/null +++ b/components/paperform/paperform.app.mjs @@ -0,0 +1,88 @@ +import { axios } from "@pipedream/platform"; +const DEFAULT_LIMIT = 100; + +export default { + type: "app", + app: "paperform", + propDefinitions: { + formId: { + type: "string", + label: "Form ID", + description: "The ID of the form to monitor", + async options({ page }) { + const { results: { forms } } = await this.listForms({ + params: { + limit: DEFAULT_LIMIT, + skip: page * DEFAULT_LIMIT, + }, + }); + return forms?.map(({ + id: value, title: label, + }) => ({ + label, + value, + })) || []; + }, + }, + }, + methods: { + _baseUrl() { + return "https://api.paperform.co/v1"; + }, + _makeRequest(opts = {}) { + const { + $ = this, + path, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + url: `${this._baseUrl()}${path}`, + headers: { + Authorization: `Bearer ${this.$auth.api_key}`, + }, + }); + }, + listForms(opts = {}) { + return this._makeRequest({ + path: "/forms", + ...opts, + }); + }, + listSubmissions({ + formId, ...opts + }) { + return this._makeRequest({ + path: `/forms/${formId}/submissions`, + ...opts, + }); + }, + async *paginate({ + fn, args, resourceKey, max, + }) { + args = { + ...args, + params: { + ...args?.params, + limit: DEFAULT_LIMIT, + skip: 0, + }, + }; + let hasMore, count = 0; + do { + const { + results, has_more: more, + } = await fn(args); + const items = results[resourceKey]; + for (const item of items) { + yield item; + if (max && ++count >= max) { + return; + } + } + hasMore = more; + args.params.skip += args.params.limit; + } while (hasMore); + }, + }, +}; diff --git a/components/paperform/sources/new-submission/new-submission.mjs b/components/paperform/sources/new-submission/new-submission.mjs new file mode 100644 index 0000000000000..2ce46137114c6 --- /dev/null +++ b/components/paperform/sources/new-submission/new-submission.mjs @@ -0,0 +1,83 @@ +import paperform from "../../paperform.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + key: "paperform-new-submission", + name: "New Submission", + description: "Emit new event when a new submission is made on the specified form in Paperform. [See the documentation](https://paperform.readme.io/reference/listformsubmissions)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + paperform, + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + db: "$.service.db", + formId: { + propDefinition: [ + paperform, + "formId", + ], + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs") || 0; + }, + _setLastTs(lastTs) { + this.db.set("lastTs", lastTs); + }, + generateMeta(submission) { + return { + id: submission.id, + summary: `New Submission ID: ${submission.id}`, + ts: Date.parse(submission.created_at), + }; + }, + async processEvent(max) { + const lastTs = this._getLastTs(); + + const items = this.paperform.paginate({ + fn: this.paperform.listSubmissions, + args: { + formId: this.formId, + }, + resourceKey: "submissions", + max, + }); + + const submissions = []; + for await (const item of items) { + const ts = Date.parse(item.created_at); + if (ts >= lastTs) { + submissions.push(item); + } else { + break; + } + } + + if (!submissions?.length) { + return; + } + + this._setLastTs(Date.parse(submissions[0].created_at)); + + submissions.forEach((submission) => { + const meta = this.generateMeta(submission); + this.$emit(submission, meta); + }); + }, + }, + async run() { + await this.processEvent(); + }, +}; diff --git a/components/runware/package.json b/components/runware/package.json new file mode 100644 index 0000000000000..e910a1ab6268e --- /dev/null +++ b/components/runware/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pipedream/runware", + "version": "0.0.1", + "description": "Pipedream Runware Components", + "main": "runware.app.mjs", + "keywords": [ + "pipedream", + "runware" + ], + "homepage": "https://pipedream.com/apps/runware", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/components/runware/runware.app.mjs b/components/runware/runware.app.mjs new file mode 100644 index 0000000000000..c2dd1ce6d7cf9 --- /dev/null +++ b/components/runware/runware.app.mjs @@ -0,0 +1,11 @@ +export default { + type: "app", + app: "runware", + propDefinitions: {}, + methods: { + // this.$auth contains connected account data + authKeys() { + console.log(Object.keys(this.$auth)); + }, + }, +}; diff --git a/components/short_menu/actions/create-short-link/create-short-link.mjs b/components/short_menu/actions/create-short-link/create-short-link.mjs new file mode 100644 index 0000000000000..74355507d1fba --- /dev/null +++ b/components/short_menu/actions/create-short-link/create-short-link.mjs @@ -0,0 +1,45 @@ +import shortMenu from "../../short_menu.app.mjs"; + +export default { + key: "short_menu-create-short-link", + name: "Create Short Link", + description: "Create a new short link. [See the documentationo](https://docs.shortmenu.com/api-reference/endpoint/create-link)", + version: "0.0.1", + type: "action", + props: { + shortMenu, + destinationUrl: { + type: "string", + label: "Destination URL", + description: "Destination URL of the new short link. Must be a valid URL starting with a scheme such as `https`.", + }, + slug: { + type: "string", + label: "Slug", + description: "Optional slug for the new short link. If empty, a random slug will be generated. Must be unique within the domain.", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "Tags to assign to the new short link", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.shortMenu.createShortLink({ + $, + data: { + destinationUrl: this.destinationUrl, + domain: this.shortMenu.$auth.custom_domain, + slug: this.slug, + tags: this.tags?.map((tag) => ({ + name: tag, + })) || [], + }, + }); + + $.export("$summary", `Successfully created short link ${response.shortUrl}`); + return response; + }, +}; diff --git a/components/short_menu/package.json b/components/short_menu/package.json new file mode 100644 index 0000000000000..76167142a47ce --- /dev/null +++ b/components/short_menu/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipedream/short_menu", + "version": "0.1.0", + "description": "Pipedream Short Menu Components", + "main": "short_menu.app.mjs", + "keywords": [ + "pipedream", + "short_menu" + ], + "homepage": "https://pipedream.com/apps/short_menu", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" + } +} diff --git a/components/short_menu/short_menu.app.mjs b/components/short_menu/short_menu.app.mjs new file mode 100644 index 0000000000000..93d9a6d6528a3 --- /dev/null +++ b/components/short_menu/short_menu.app.mjs @@ -0,0 +1,31 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "short_menu", + methods: { + _baseUrl() { + return "https://api.shortmenu.com"; + }, + _makeRequest({ + $ = this, + path, + ...opts + }) { + return axios($, { + url: `${this._baseUrl()}${path}`, + headers: { + "x-api-key": `${this.$auth.api_key}`, + }, + ...opts, + }); + }, + createShortLink(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/links", + ...opts, + }); + }, + }, +}; diff --git a/components/suitedash/.gitignore b/components/suitedash/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/suitedash/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/suitedash/actions/create-company/create-company.mjs b/components/suitedash/actions/create-company/create-company.mjs new file mode 100644 index 0000000000000..c497119ddf5a0 --- /dev/null +++ b/components/suitedash/actions/create-company/create-company.mjs @@ -0,0 +1,79 @@ +import suitedash from "../../suitedash.app.mjs"; + +export default { + key: "suitedash-create-company", + name: "Create Company", + description: "Creates a new company in SuiteDash. [See the documentation](https://app.suitedash.com/secure-api/swagger)", + version: "0.0.1", + type: "action", + props: { + suitedash, + companyName: { + propDefinition: [ + suitedash, + "companyName", + ], + }, + companyRole: { + propDefinition: [ + suitedash, + "role", + ], + }, + firstName: { + type: "string", + label: "First Name", + description: "First name of the company's primary contact", + }, + lastName: { + type: "string", + label: "Last Name", + description: "Last name of the company's primary contact", + }, + email: { + type: "string", + label: "Email", + description: "Email address of the company's primary contact", + }, + sendWelcomeEmail: { + type: "boolean", + label: "Send Welcome Email", + description: "Send welcome email to the primary contact. Default: `false`", + optional: true, + default: false, + }, + createPrimaryContactIfNotExists: { + type: "boolean", + label: "Create Primary Contact If Not Exists", + description: "Create a Primary Contact with all provided data if the email does not exist. Default: `true`", + optional: true, + default: true, + }, + preventIndividualMode: { + type: "boolean", + label: "Prevent Individual Mode", + description: "Prevent this Primary Contact from switching into `Individual Mode`. Default: `false`", + optional: true, + default: false, + }, + }, + async run({ $ }) { + const response = await this.suitedash.createCompany({ + $, + data: { + name: this.companyName, + role: this.companyRole, + primaryContact: { + first_name: this.firstName, + last_name: this.lastName, + email: this.email, + send_welcome_email: this.sendWelcomeEmail, + create_primary_contact_if_not_exists: this.createPrimaryContactIfNotExists, + prevent_individual_mode: this.preventIndividualMode, + }, + }, + }); + $.export("$summary", `Successfully created company ${this.companyName}`); + return response; + }, +}; diff --git a/components/suitedash/actions/create-contact/create-contact.mjs b/components/suitedash/actions/create-contact/create-contact.mjs new file mode 100644 index 0000000000000..e81198c85fae6 --- /dev/null +++ b/components/suitedash/actions/create-contact/create-contact.mjs @@ -0,0 +1,55 @@ +import suitedash from "../../suitedash.app.mjs"; + +export default { + key: "suitedash-create-contact", + name: "Create Contact", + description: "Creates a new contact in SuiteDash. [See the documentation](https://app.suitedash.com/secure-api/swagger)", + version: "0.0.1", + type: "action", + props: { + suitedash, + firstName: { + type: "string", + label: "Contact First Name", + description: "The first name of the new contact", + }, + lastName: { + type: "string", + label: "Contact Last Name", + description: "The last name of the new contact", + }, + email: { + type: "string", + label: "Contact Email", + description: "The email of the new contact", + }, + role: { + propDefinition: [ + suitedash, + "role", + ], + label: "Contact Role", + description: "The role of the new contact", + }, + sendWelcomeEmail: { + type: "boolean", + label: "Send Welcome Email", + description: "Whether to send a welcome email to the new contact", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.suitedash.createContact({ + $, + data: { + first_name: this.firstName, + last_name: this.lastName, + email: this.email, + role: this.role, + send_welcome_email: this.sendWelcomeEmail, + }, + }); + $.export("$summary", `Successfully created contact ${this.firstName} ${this.lastName}`); + return response; + }, +}; diff --git a/components/suitedash/actions/update-company/update-company.mjs b/components/suitedash/actions/update-company/update-company.mjs new file mode 100644 index 0000000000000..ee0f0959e2182 --- /dev/null +++ b/components/suitedash/actions/update-company/update-company.mjs @@ -0,0 +1,82 @@ +import suitedash from "../../suitedash.app.mjs"; +import { ConfigurationError } from "@pipedream/platform"; + +export default { + key: "suitedash-update-company", + name: "Update Company", + description: "Updates an existing company's details in SuiteDash. [See the documentation](https://app.suitedash.com/secure-api/swagger)", + version: "0.0.1", + type: "action", + props: { + suitedash, + companyId: { + propDefinition: [ + suitedash, + "companyId", + ], + }, + companyName: { + propDefinition: [ + suitedash, + "companyName", + ], + optional: true, + }, + website: { + type: "string", + label: "Website", + description: "The website of the company.", + optional: true, + }, + phone: { + type: "string", + label: "Phone", + description: "The phone number of the company", + optional: true, + }, + companyAddress: { + type: "string", + label: "Company Address", + description: "The full address of the company. Example: dba Staybridge Suites Mount Laurel 324 Church Road Mount Laurel, NJ 09478", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "An array of tags associated with the company", + optional: true, + }, + backgroundInfo: { + type: "string", + label: "Background Info", + description: "Background information about the company", + optional: true, + }, + }, + async run({ $ }) { + if (!this.companyName + && !this.website + && !this.phone + && !this.companyAddress + && !this.tags + && !this.backgroundInfo + ) { + throw new ConfigurationError("Please enter at least one field to update"); + } + + const response = await this.suitedash.updateCompany({ + $, + companyId: this.companyId, + data: { + name: this.companyName, + website: this.website, + phone: this.phone, + full_address: this.companyAddress, + tags: this.tags, + background_info: this.backgroundInfo, + }, + }); + $.export("$summary", `Successfully updated company ${this.companyId}`); + return response; + }, +}; diff --git a/components/suitedash/package.json b/components/suitedash/package.json index 8eb4b2fddf4be..ea621228da30d 100644 --- a/components/suitedash/package.json +++ b/components/suitedash/package.json @@ -1,16 +1,18 @@ { "name": "@pipedream/suitedash", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream SuiteDash Components", "main": "dist/app/suitedash.app.mjs", "keywords": [ "pipedream", "suitedash" ], - "files": ["dist"], "homepage": "https://pipedream.com/apps/suitedash", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/suitedash/sources/common/base.mjs b/components/suitedash/sources/common/base.mjs new file mode 100644 index 0000000000000..13274bd46d638 --- /dev/null +++ b/components/suitedash/sources/common/base.mjs @@ -0,0 +1,79 @@ +import suitedash from "../../suitedash.app.mjs"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; + +export default { + props: { + suitedash, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + hooks: { + async deploy() { + await this.processEvent(25); + }, + }, + methods: { + _getLastTs() { + return this.db.get("lastTs") || 0; + }, + _setLastTs(lastTs) { + this.db.set("lastTs", lastTs); + }, + getParams() { + return {}; + }, + getTsField() { + return "created"; + }, + generateMeta(item) { + return { + id: item.uid, + summary: this.getSummary(item), + ts: Date.parse(item[this.getTsField()]), + }; + }, + getFn() { + throw new Error("getFn is not implemented"); + }, + getSummary() { + throw new Error("getSummary is not implemented"); + }, + async processEvent(max) { + const lastTs = this._getLastTs(); + let maxTs = lastTs; + let results = []; + + const items = this.suitedash.paginate({ + fn: this.getFn(), + params: this.getParams(), + }); + + for await (const item of items) { + const ts = Date.parse(item[this.getTsField()]); + if (ts >= lastTs) { + results.push(item); + maxTs = Math.max(ts, maxTs); + } + } + + this._setLastTs(maxTs); + + if (max) { + results = results.slice(-1 * max); + } + + results.forEach((item) => { + const meta = this.generateMeta(item); + this.$emit(item, meta); + }); + }, + }, + async run() { + await this.processEvent(); + }, +}; diff --git a/components/suitedash/sources/new-company/new-company.mjs b/components/suitedash/sources/new-company/new-company.mjs new file mode 100644 index 0000000000000..1606ba0fc2e2d --- /dev/null +++ b/components/suitedash/sources/new-company/new-company.mjs @@ -0,0 +1,24 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "suitedash-new-company", + name: "New Company Created", + description: "Emit new event when a new company is created in SuiteDash", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFn() { + return this.suitedash.listCompanies; + }, + getSummary(company) { + if (!company || typeof company !== "object") { + return "New Company: Unknown"; + } + const name = company.name || "Unnamed"; + return `New Company: ${name}`; + }, + }, +}; diff --git a/components/suitedash/sources/new-contact/new-contact.mjs b/components/suitedash/sources/new-contact/new-contact.mjs new file mode 100644 index 0000000000000..d8d13259f9144 --- /dev/null +++ b/components/suitedash/sources/new-contact/new-contact.mjs @@ -0,0 +1,26 @@ +import common from "../common/base.mjs"; + +export default { + ...common, + key: "suitedash-new-contact", + name: "New Contact Created", + description: "Emit new event when a new contact is created.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getFn() { + return this.suitedash.listContacts; + }, + getSummary(contact) { + const firstName = contact.first_name || ""; + const lastName = contact.last_name || ""; + const fullName = [ + firstName, + lastName, + ].filter(Boolean).join(" ") || "Unknown"; + return `New Contact: ${fullName}`; + }, + }, +}; diff --git a/components/suitedash/suitedash.app.mjs b/components/suitedash/suitedash.app.mjs new file mode 100644 index 0000000000000..a0dc627f72308 --- /dev/null +++ b/components/suitedash/suitedash.app.mjs @@ -0,0 +1,119 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "suitedash", + propDefinitions: { + companyId: { + type: "string", + label: "Company ID", + description: "The ID of the company", + async options({ page }) { + const { data } = await this.listCompanies({ + params: { + page: page + 1, + }, + }); + return data?.map(({ + uid: value, name: label, + }) => ({ + value, + label, + })) || []; + }, + }, + companyName: { + type: "string", + label: "Company Name", + description: "The name of the new company.", + }, + role: { + type: "string", + label: "Company Role", + description: "The role of the new company.", + options: [ + "Lead", + "Client", + "Prospect", + ], + }, + }, + methods: { + _baseUrl() { + return "https://app.suitedash.com/secure-api"; + }, + _makeRequest(opts = {}) { + const { + $ = this, + path, + ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + url: `${this._baseUrl()}${path}`, + headers: { + "Accept": "application/json", + "X-Public-ID": this.$auth.public_id, + "X-Secret-Key": this.$auth.secret_key, + }, + }); + }, + listCompanies(opts = {}) { + return this._makeRequest({ + path: "/companies", + ...opts, + }); + }, + listContacts(opts = {}) { + return this._makeRequest({ + path: "/contacts", + ...opts, + }); + }, + createCompany(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/company", + ...opts, + }); + }, + createContact(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/contact", + ...opts, + }); + }, + updateCompany({ + companyId, ...opts + }) { + return this._makeRequest({ + method: "PUT", + path: `/company/${companyId}`, + ...opts, + }); + }, + async *paginate({ + fn, + params, + }) { + params = { + ...params, + page: 1, + }; + let hasMore; + do { + const { + data, meta: { pagination }, + } = await fn({ + params, + }); + for (const item of data) { + yield item; + } + hasMore = params.page < pagination.totalPages; + params.page++; + } while (hasMore); + }, + }, +}; diff --git a/components/wati/.gitignore b/components/wati/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/wati/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/wati/actions/add-contact/add-contact.mjs b/components/wati/actions/add-contact/add-contact.mjs new file mode 100644 index 0000000000000..ec617afa928f9 --- /dev/null +++ b/components/wati/actions/add-contact/add-contact.mjs @@ -0,0 +1,53 @@ +import { ConfigurationError } from "@pipedream/platform"; +import wati from "../../wati.app.mjs"; + +export default { + key: "wati-add-contact", + name: "Add Contact", + description: "Adds a new contact on the WATI platform. [See the documentation](https://docs.wati.io/reference/post_api-v1-addcontact-whatsappnumber)", + version: "0.0.1", + type: "action", + props: { + wati, + whatsappNumber: { + propDefinition: [ + wati, + "whatsappNumber", + ], + }, + name: { + type: "string", + label: "Name", + description: "The name of the contact", + optional: true, + }, + customParams: { + propDefinition: [ + wati, + "customParams", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.wati.addContact({ + $, + whatsappNumber: this.whatsappNumber, + data: { + name: this.name, + customParams: this.customParams && Object.entries(this.customParams).map(([ + key, + value, + ]) => ({ + name: key, + value, + })), + }, + }); + if (!response.result) { + throw new ConfigurationError(response.info); + } + $.export("$summary", `Successfully added contact with phone number: ${this.whatsappNumber}`); + return response; + }, +}; diff --git a/components/wati/actions/send-template-message/send-template-message.mjs b/components/wati/actions/send-template-message/send-template-message.mjs new file mode 100644 index 0000000000000..3c02cc3974538 --- /dev/null +++ b/components/wati/actions/send-template-message/send-template-message.mjs @@ -0,0 +1,63 @@ +import { ConfigurationError } from "@pipedream/platform"; +import wati from "../../wati.app.mjs"; + +export default { + key: "wati-send-template-message", + name: "Send WhatsApp Template Message", + description: "Enables sending of WhatsApp messages using a pre-approved template. [See the documentation](https://docs.wati.io/reference/post_api-v2-sendtemplatemessage)", + version: "0.0.1", + type: "action", + props: { + wati, + whatsappNumber: { + propDefinition: [ + wati, + "whatsappNumber", + ], + }, + customParams: { + propDefinition: [ + wati, + "customParams", + ], + label: "Parameters", + description: "An object with template's custom params.", + }, + templateName: { + propDefinition: [ + wati, + "templateName", + ], + }, + broadcastName: { + type: "string", + label: "Broadcast Name", + description: "The name of broadcast.", + }, + }, + async run({ $ }) { + const response = await this.wati.sendTemplateMessage({ + $, + params: { + whatsappNumber: this.whatsappNumber, + }, + data: { + parameters: this.customParams && Object.entries(this.customParams).map(([ + key, + value, + ]) => ({ + name: key, + value, + })), + template_name: this.templateName, + broadcast_name: this.broadcastName, + }, + }); + if (!response.result) { + throw new ConfigurationError(response.info); + } + + $.export("$summary", `Successfully sent template message to ${this.whatsappNumber}`); + return response; + }, +}; diff --git a/components/wati/actions/update-contact-attribute/update-contact-attribute.mjs b/components/wati/actions/update-contact-attribute/update-contact-attribute.mjs new file mode 100644 index 0000000000000..d1254ea3183bc --- /dev/null +++ b/components/wati/actions/update-contact-attribute/update-contact-attribute.mjs @@ -0,0 +1,47 @@ +import { ConfigurationError } from "@pipedream/platform"; +import wati from "../../wati.app.mjs"; + +export default { + key: "wati-update-contact-attribute", + name: "Update Contact Attribute", + description: "Allows updating attributes/tags related to an existing contact. [See the documentation](https://docs.wati.io/reference/post_api-v1-updatecontactattributes-whatsappnumber)", + version: "0.0.1", + type: "action", + props: { + wati, + whatsappNumber: { + propDefinition: [ + wati, + "whatsappNumber", + ], + }, + customParams: { + propDefinition: [ + wati, + "customParams", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.wati.updateContactAttributes({ + $, + whatsappNumber: this.whatsappNumber, + data: { + customParams: this.customParams && Object.entries(this.customParams).map(([ + key, + value, + ]) => ({ + name: key, + value, + })), + }, + }); + if (!response.result) { + throw new ConfigurationError(response.info); + } + + $.export("$summary", `Successfully updated attributes for contact ${this.whatsappNumber}`); + return response; + }, +}; diff --git a/components/wati/package.json b/components/wati/package.json index 031b83cd95569..90b471a941a4e 100644 --- a/components/wati/package.json +++ b/components/wati/package.json @@ -1,16 +1,18 @@ { "name": "@pipedream/wati", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream WATI Components", - "main": "dist/app/wati.app.mjs", + "main": "wati.app.mjs", "keywords": [ "pipedream", "wati" ], - "files": ["dist"], "homepage": "https://pipedream.com/apps/wati", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} diff --git a/components/wati/sources/common/base.mjs b/components/wati/sources/common/base.mjs new file mode 100644 index 0000000000000..8e10715b02532 --- /dev/null +++ b/components/wati/sources/common/base.mjs @@ -0,0 +1,61 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import wati from "../../wati.app.mjs"; + +export default { + props: { + wati, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + prepareData(data) { + return data; + }, + _getLastDate() { + return this.db.get("lastDate") || 0; + }, + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); + }, + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + const dateField = this.getDateField(); + + const response = this.wati.paginate( + this.getPaginateOpts(maxResults), + ); + + let responseArray = []; + for await (const item of response) { + responseArray.push(item); + } + + responseArray = this.prepareData(responseArray, lastDate, maxResults); + + if (responseArray.length) { + this._setLastDate(responseArray[0][dateField]); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: item.id, + summary: this.getSummary(item), + ts: Date.parse(item[dateField]), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/wati/sources/new-contact-created/new-contact-created.mjs b/components/wati/sources/new-contact-created/new-contact-created.mjs new file mode 100644 index 0000000000000..0b5c33e00917d --- /dev/null +++ b/components/wati/sources/new-contact-created/new-contact-created.mjs @@ -0,0 +1,33 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "wati-new-contact-created", + name: "New Contact Created", + description: "Emit new event when a contact is created from an incoming WhatsApp message.", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getPaginateOpts(maxResults) { + return { + fn: this.wati.listContacts, + itemsField: "result", + optsField: "data", + maxResults, + }; + }, + getDateField() { + return "created"; + }, + checkBreak(item, lastDate) { + return Date.parse(item.created) < lastDate; + }, + getSummary(item) { + return `New contact created: ${item.wAid}`; + }, + }, + sampleEmit, +}; diff --git a/components/wati/sources/new-contact-created/test-event.mjs b/components/wati/sources/new-contact-created/test-event.mjs new file mode 100644 index 0000000000000..3a696c5a7d163 --- /dev/null +++ b/components/wati/sources/new-contact-created/test-event.mjs @@ -0,0 +1,33 @@ +export default { + "id": "670934c1d464c11dd46c3b7f", + "wAid": "17759865200", + "firstName": "+17759865200", + "fullName": "+17759865200", + "phone": "17759865200", + "source": null, + "contactStatus": "VALID", + "photo": null, + "created": "Oct-11-2024", + "customParams": [ + { + "name": "name", + "value": "+17759865200" + }, + { + "name": "phone", + "value": "17759865200" + } + ], + "optedIn": false, + "isDeleted": false, + "lastUpdated": "2024-10-11T15:09:36.047Z", + "allowBroadcast": true, + "allowSMS": true, + "teamIds": [ + "6708393ad464c11dd46b3d73" + ], + "isInFlow": false, + "lastFlowId": null, + "currentFlowNodeId": null, + "selectedHubspotId": null +} \ No newline at end of file diff --git a/components/wati/sources/new-incoming-message/new-incoming-message.mjs b/components/wati/sources/new-incoming-message/new-incoming-message.mjs new file mode 100644 index 0000000000000..448456aa51882 --- /dev/null +++ b/components/wati/sources/new-incoming-message/new-incoming-message.mjs @@ -0,0 +1,52 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "wati-new-incoming-message", + name: "New Incoming Message", + description: "Emit new event when there is an incoming message on your number.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + ...common.props, + contactId: { + propDefinition: [ + common.props.wati, + "contactId", + ], + }, + }, + methods: { + ...common.methods, + getPaginateOpts() { + return { + fn: this.wati.listContactMessages, + whatsappNumber: `+${this.contactId}`, + itemsField: [ + "messages", + ], + optsField: "params", + }; + }, + getDateField() { + return "timestamp"; + }, + prepareData(data, lastDate, maxResults) { + data = data + .filter((item) => item.statusString === "SENT" && Date.parse(item.created) > lastDate) + .sort((a, b) => Date.parse(b.created) - Date.parse(a.created)); + + if (maxResults && data.length > maxResults) data.length = maxResults; + return data; + }, + checkBreak(item, lastDate) { + return Date.parse(item.timestamp) < lastDate; + }, + getSummary(item) { + return `New message: ${item.text || "No content"}`; + }, + }, + sampleEmit, +}; diff --git a/components/wati/sources/new-incoming-message/test-event.mjs b/components/wati/sources/new-incoming-message/test-event.mjs new file mode 100644 index 0000000000000..c478a5e1f2f00 --- /dev/null +++ b/components/wati/sources/new-incoming-message/test-event.mjs @@ -0,0 +1,26 @@ +export default { + "replySourceMessage": null, + "messageReferral": null, + "text": "Know the Pricing", + "type": "text", + "data": null, + "timestamp": "1728656646", + "owner": false, + "statusString": "SENT", + "avatarUrl": null, + "assignedId": null, + "operatorName": null, + "localMessageId": null, + "failedDetail": null, + "referenceOrderId": null, + "contacts": null, + "messageProducts": null, + "orderProducts": null, + "interactiveData": null, + "orderDetailsViewModel": null, + "id": "67093506d464c11dd46c3bcf", + "created": "2024-10-11T14:24:06.891Z", + "conversationId": "670934f5d464c11dd46c3bc6", + "ticketId": "67093506d464c11dd46c3bcc", + "eventType": "message" +} \ No newline at end of file diff --git a/components/wati/wati.app.mjs b/components/wati/wati.app.mjs new file mode 100644 index 0000000000000..295552c153504 --- /dev/null +++ b/components/wati/wati.app.mjs @@ -0,0 +1,144 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "wati", + propDefinitions: { + contactId: { + type: "string", + label: "Contact Id", + description: "The Id of the contact.", + async options({ page }) { + const { result: { items } } = await this.listContacts({ + data: { + pageSize: 100, + pageNumber: page, + }, + }); + + return items.map(({ wAid }) => wAid); + }, + }, + whatsappNumber: { + type: "string", + label: "WhatsApp Number", + description: "Your WhatsApp number with country code.", + }, + customParams: { + type: "object", + label: "Custom Params", + description: "An object with contact's custom fields.", + }, + templateName: { + type: "string", + label: "Template Name", + description: "The name of template.", + async options({ page }) { + const { messageTemplates: data } = await this.listTemplates({ + params: { + pageSize: page + 1, + }, + }); + + return data.map(({ elementName }) => elementName); + }, + }, + }, + methods: { + _baseUrl() { + return `${this.$auth.api_endpoint}/api/v1`; + }, + _headers() { + return { + Authorization: `${this.$auth.access_token}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }); + }, + listContacts(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/contacts", + ...opts, + }); + }, + listContactMessages({ + whatsappNumber, ...opts + }) { + return this._makeRequest({ + path: `/getMessages/${whatsappNumber}`, + ...opts, + }); + }, + listTemplates(opts = {}) { + return this._makeRequest({ + path: "/getMessageTemplates", + ...opts, + }); + }, + addContact({ + whatsappNumber, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/addContact/${whatsappNumber}`, + ...opts, + }); + }, + sendTemplateMessage(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/sendTemplateMessage", + ...opts, + }); + }, + updateContactAttributes({ + whatsappNumber, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/updateContactAttributes/${whatsappNumber}`, + ...opts, + }); + }, + async *paginate({ + fn, itemsField, optsField, maxResults = null, data = {}, params = {}, ...otherOpts + }) { + let hasMore = false; + let count = 0; + let page = 0; + + const opts = { + data, + params, + ...otherOpts, + }; + + opts[optsField].pageSize = 100; + + do { + opts[optsField].pageNumber = page++; + const response = await fn(opts); + const items = response[itemsField].items; + + for (const d of items) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + hasMore = items.length; + + } while (hasMore); + }, + }, +}; diff --git a/components/wrike/actions/new-task/new-task.mjs b/components/wrike/actions/new-task/new-task.mjs index d18320fe19359..6d508001f408c 100644 --- a/components/wrike/actions/new-task/new-task.mjs +++ b/components/wrike/actions/new-task/new-task.mjs @@ -4,8 +4,8 @@ import _ from "lodash"; export default { key: "wrike-new-task", name: "New Task", - description: "Create a Wrike task under a specified folder ID. [See the docs](https://developers.wrike.com/api/v4/tasks/#create-task)", - version: "0.3.0", + description: "Create a Wrike task under a specified folder ID. [See the documentation](https://developers.wrike.com/api/v4/tasks/#create-task)", + version: "0.3.1", type: "action", props: { wrike, diff --git a/components/wrike/actions/update-task-custom-fields/update-task-custom-fields.mjs b/components/wrike/actions/update-task-custom-fields/update-task-custom-fields.mjs index 87805559f7b41..c3937fcca7fd1 100644 --- a/components/wrike/actions/update-task-custom-fields/update-task-custom-fields.mjs +++ b/components/wrike/actions/update-task-custom-fields/update-task-custom-fields.mjs @@ -4,8 +4,8 @@ import { ConfigurationError } from "@pipedream/platform"; export default { key: "wrike-update-task-custom-fields", name: "Update Task Custom Fields", - description: "Update the custom fields for a task. [See the docs](https://developers.wrike.com/api/v4/tasks/#modify-tasks)", - version: "0.0.1", + description: "Update the custom fields for a task. [See the documentation](https://developers.wrike.com/api/v4/tasks/#modify-tasks)", + version: "0.0.2", type: "action", props: { wrike, diff --git a/components/wrike/package.json b/components/wrike/package.json index 2a48749d28e6e..e361eb45ae766 100644 --- a/components/wrike/package.json +++ b/components/wrike/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/wrike", - "version": "0.0.2", + "version": "0.0.3", "description": "Pipedream Wrike Components", "main": "wrike.app.mjs", "keywords": [ @@ -14,7 +14,7 @@ "access": "public" }, "dependencies": { - "@pipedream/platform": "^1.3.0", + "@pipedream/platform": "^3.0.3", "lodash": "^4.17.21" } } diff --git a/components/wrike/sources/new-folder-created/new-folder-created.mjs b/components/wrike/sources/new-folder-created/new-folder-created.mjs index 70259569cb16d..886efed7dfd76 100644 --- a/components/wrike/sources/new-folder-created/new-folder-created.mjs +++ b/components/wrike/sources/new-folder-created/new-folder-created.mjs @@ -7,7 +7,7 @@ export default { name: "New Folder Created", description: "Emit new event when a folder is created", type: "source", - version: "0.0.1", + version: "0.0.2", props: { ...base.props, folderId: { @@ -17,7 +17,6 @@ export default { ], description: "Receive notifications for folders in a folder and, optionally, in its subfolders. Leave blank to receive notifications for all folders in the account", optional: true, - reloadProps: true, }, spaceId: { propDefinition: [ @@ -26,7 +25,6 @@ export default { ], description: "Receive notifications for changes to folders within a space. Leave blank to receive notifications for all folders in the account", optional: true, - reloadProps: true, }, recursive: { type: "boolean", diff --git a/components/wrike/sources/new-subtask-created/new-subtask-created.mjs b/components/wrike/sources/new-subtask-created/new-subtask-created.mjs index 1da225a321cd8..0c5a6291fa042 100644 --- a/components/wrike/sources/new-subtask-created/new-subtask-created.mjs +++ b/components/wrike/sources/new-subtask-created/new-subtask-created.mjs @@ -7,28 +7,32 @@ export default { name: "New Subtask Created", description: "Emit new event when a subtask is created", type: "source", - version: "0.0.1", + version: "0.0.2", props: { ...base.props, - taskId: { + taskIds: { propDefinition: [ base.props.wrike, "taskId", - (c) => ({ - folderId: c.folderId, - spaceId: c.spaceId, - }), ], - description: "Receive notifications for subtasks of a task", + type: "string[]", + label: "Task IDs", + description: "Receive notifications for subtasks of the specified task(s)", + optional: true, }, }, hooks: { ...base.hooks, async deploy() { console.log("Retrieving historical events..."); - const subtasks = await this.wrike.getSubtasks({ - taskId: this.taskId, - }); + const taskIds = this.taskIds || (await this.wrike.listTasks({}))?.map(({ id }) => id) || []; + const subtasks = []; + for (const taskId of taskIds) { + const taskSubtasks = await this.wrike.getSubtasks({ + taskId, + }); + subtasks.push(...taskSubtasks); + } for (const subtask of subtasks.slice(-constants.DEPLOY_LIMIT)) { this.emitEvent(subtask); } @@ -55,7 +59,7 @@ export default { const task = await this.wrike.getTask({ taskId: data.taskId, }); - if (task.superTaskIds.includes(this.taskId)) { + if (!this.taskIds || task.superTaskIds.some((id) => this.taskIds.includes(id))) { this.emitEvent(task); } } diff --git a/components/wrike/sources/new-task-created/new-task-created.mjs b/components/wrike/sources/new-task-created/new-task-created.mjs index b9c2416e36457..eb14112ef97ea 100644 --- a/components/wrike/sources/new-task-created/new-task-created.mjs +++ b/components/wrike/sources/new-task-created/new-task-created.mjs @@ -7,7 +7,7 @@ export default { name: "New Task Created", description: "Emit new event when a task is created", type: "source", - version: "0.0.1", + version: "0.0.2", props: { ...base.props, folderId: { @@ -17,7 +17,6 @@ export default { ], description: "Receive notifications for tasks in a folder and, optionally, in its subfolders. Leave blank to receive notifications for all tasks in the account", optional: true, - reloadProps: true, }, spaceId: { propDefinition: [ @@ -26,7 +25,6 @@ export default { ], description: "Receive notifications for changes to tasks, folders, and projects within a space. Leave blank to receive notifications for all tasks in the account", optional: true, - reloadProps: true, }, recursive: { type: "boolean", diff --git a/components/wrike/wrike.app.mjs b/components/wrike/wrike.app.mjs index 05f773aa3a8bc..557475dcca6e0 100644 --- a/components/wrike/wrike.app.mjs +++ b/components/wrike/wrike.app.mjs @@ -72,7 +72,7 @@ export default { }, methods: { _baseUrl() { - return "https://www.wrike.com/api/v4"; + return `https://${this.$auth.host}/api/v4`; }, _buildPath({ basePath, folderId, spaceId, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60c938f877efe..a4f0fa8eb6393 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -341,6 +341,9 @@ importers: components/ai_ml_api: specifiers: {} + components/ai_textraction: + specifiers: {} + components/aidbase: specifiers: '@pipedream/platform': ^3.0.0 @@ -797,6 +800,9 @@ importers: dependencies: '@pipedream/platform': 3.0.3 + components/attractwell: + specifiers: {} + components/autoblogger: specifiers: {} @@ -2422,6 +2428,9 @@ importers: dependencies: '@pipedream/platform': 1.5.1 + components/deepimage: + specifiers: {} + components/deepl: specifiers: {} @@ -3291,7 +3300,10 @@ importers: fs: 0.0.1-security components/fakturoid: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/faraday: specifiers: @@ -3501,6 +3513,9 @@ importers: components/fluent_support: specifiers: {} + components/fluidforms: + specifiers: {} + components/flutterwave: specifiers: '@pipedream/platform': ^1.5.1 @@ -3730,6 +3745,12 @@ importers: dependencies: '@pipedream/platform': 3.0.0 + components/gainsight_nxt: + specifiers: {} + + components/gainsight_px: + specifiers: {} + components/gami5d: specifiers: '@pipedream/platform': ^3.0.0 @@ -4819,7 +4840,10 @@ importers: form-data: 4.0.0 components/imagior: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/imap: specifiers: @@ -6289,9 +6313,9 @@ importers: components/motion: specifiers: - '@pipedream/platform': ^1.5.1 + '@pipedream/platform': ^3.0.3 dependencies: - '@pipedream/platform': 1.5.1 + '@pipedream/platform': 3.0.3 components/moxie: specifiers: @@ -6501,7 +6525,10 @@ importers: '@pipedream/platform': 1.5.1 components/ngrok: - specifiers: {} + specifiers: + '@pipedream/platform': 3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/niceboard: specifiers: {} @@ -7027,7 +7054,10 @@ importers: form-data: 4.0.0 components/paperform: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/papertrail: specifiers: {} @@ -8442,6 +8472,9 @@ importers: components/runpod: specifiers: {} + components/runware: + specifiers: {} + components/rytr: specifiers: {} @@ -9019,6 +9052,12 @@ importers: '@pipedream/platform': 1.5.1 lodash: 4.17.21 + components/short_menu: + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 + components/shortcut: specifiers: async-retry: ^1.3.1 @@ -9669,7 +9708,10 @@ importers: specifiers: {} components/suitedash: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/summit: specifiers: @@ -11003,7 +11045,10 @@ importers: specifiers: {} components/wati: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/watsonx_ai: specifiers: {} @@ -11293,10 +11338,10 @@ importers: components/wrike: specifiers: - '@pipedream/platform': ^1.3.0 + '@pipedream/platform': ^3.0.3 lodash: ^4.17.21 dependencies: - '@pipedream/platform': 1.5.1 + '@pipedream/platform': 3.0.3 lodash: 4.17.21 components/writer: @@ -13047,6 +13092,55 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso-oidc/3.600.0_tdq3komn4zwyd65w7klbptsu34: + resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.2.1 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.2 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.6 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.2 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + dev: false + /@aws-sdk/client-sso/3.423.0: resolution: {integrity: sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==} engines: {node: '>=14.0.0'} @@ -13282,7 +13376,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 + '@aws-sdk/client-sso-oidc': 3.600.0_tdq3komn4zwyd65w7klbptsu34 '@aws-sdk/core': 3.598.0 '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 '@aws-sdk/middleware-host-header': 3.598.0 @@ -13324,55 +13418,6 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sts/3.600.0_dseaa2p5u2yk67qiepewcq3hkq: - resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 - '@aws-sdk/core': 3.598.0 - '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 - '@aws-sdk/middleware-host-header': 3.598.0 - '@aws-sdk/middleware-logger': 3.598.0 - '@aws-sdk/middleware-recursion-detection': 3.598.0 - '@aws-sdk/middleware-user-agent': 3.598.0 - '@aws-sdk/region-config-resolver': 3.598.0 - '@aws-sdk/types': 3.598.0 - '@aws-sdk/util-endpoints': 3.598.0 - '@aws-sdk/util-user-agent-browser': 3.598.0 - '@aws-sdk/util-user-agent-node': 3.598.0 - '@smithy/config-resolver': 3.0.3 - '@smithy/core': 2.2.3 - '@smithy/fetch-http-handler': 3.2.1 - '@smithy/hash-node': 3.0.2 - '@smithy/invalid-dependency': 3.0.2 - '@smithy/middleware-content-length': 3.0.2 - '@smithy/middleware-endpoint': 3.0.4 - '@smithy/middleware-retry': 3.0.6 - '@smithy/middleware-serde': 3.0.3 - '@smithy/middleware-stack': 3.0.3 - '@smithy/node-config-provider': 3.1.3 - '@smithy/node-http-handler': 3.1.2 - '@smithy/protocol-http': 4.0.3 - '@smithy/smithy-client': 3.1.6 - '@smithy/types': 3.3.0 - '@smithy/url-parser': 3.0.3 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.6 - '@smithy/util-defaults-mode-node': 3.0.6 - '@smithy/util-endpoints': 2.0.3 - '@smithy/util-middleware': 3.0.3 - '@smithy/util-retry': 3.0.2 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: false - /@aws-sdk/core/3.556.0: resolution: {integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==} engines: {node: '>=14.0.0'} @@ -17722,7 +17767,7 @@ packages: '@aws-sdk/client-sns': 3.423.0 '@aws-sdk/client-sqs': 3.423.0 '@aws-sdk/client-ssm': 3.423.0 - '@aws-sdk/client-sts': 3.600.0_dseaa2p5u2yk67qiepewcq3hkq + '@aws-sdk/client-sts': 3.600.0 '@aws-sdk/s3-request-presigner': 3.609.0 '@pipedream/helper_functions': 0.3.12 '@pipedream/platform': 1.6.6