From b476fcf928a4f2cfbc6fdbecb6c84a5980664c45 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 12 Nov 2024 15:58:05 -0300 Subject: [PATCH 1/4] zoho_sheet init --- .../actions/create-row/create-row.mjs | 34 ++++ .../search-delete-row/search-delete-row.mjs | 34 ++++ .../actions/update-row/update-row.mjs | 41 +++++ .../new-or-updated-row-instant.mjs | 101 ++++++++++++ .../new-row-instant/new-row-instant.mjs | 73 +++++++++ .../new-workbook-instant.mjs | 72 +++++++++ components/zoho_sheet/zoho_sheet.app.mjs | 146 ++++++++++++++++++ 7 files changed, 501 insertions(+) create mode 100644 components/zoho_sheet/actions/create-row/create-row.mjs create mode 100644 components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs create mode 100644 components/zoho_sheet/actions/update-row/update-row.mjs create mode 100644 components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs create mode 100644 components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs create mode 100644 components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs create mode 100644 components/zoho_sheet/zoho_sheet.app.mjs diff --git a/components/zoho_sheet/actions/create-row/create-row.mjs b/components/zoho_sheet/actions/create-row/create-row.mjs new file mode 100644 index 0000000000000..f8edf0f019572 --- /dev/null +++ b/components/zoho_sheet/actions/create-row/create-row.mjs @@ -0,0 +1,34 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "zoho_sheet-create-row", + name: "Create Row", + description: "Creates a new row in the specified worksheet. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", + version: "0.0.1", + type: "action", + props: { + zohoSheet, + worksheet: { + propDefinition: [ + zohoSheet, + "worksheet", + ], + }, + data: { + propDefinition: [ + zohoSheet, + "data", + ], + }, + }, + async run({ $ }) { + const response = await this.zohoSheet.createRow({ + worksheet: this.worksheet, + data: this.data, + }); + + $.export("$summary", `Successfully created a row in the worksheet: ${this.worksheet}`); + return response; + }, +}; diff --git a/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs b/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs new file mode 100644 index 0000000000000..a4b8369f74a6d --- /dev/null +++ b/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs @@ -0,0 +1,34 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "zoho_sheet-search-delete-row", + name: "Search and Delete Row", + description: "Searches for a row based on provided criteria and deletes it. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", + version: "0.0.{{ts}}", + type: "action", + props: { + zohoSheet, + worksheet: { + propDefinition: [ + zohoSheet, + "worksheet", + ], + }, + criteria: { + propDefinition: [ + zohoSheet, + "criteria", + ], + }, + }, + async run({ $ }) { + const response = await this.zohoSheet.deleteRow({ + worksheet: this.worksheet, + criteria: this.criteria, + }); + + $.export("$summary", `Row matching criteria deleted successfully from worksheet ${this.worksheet}`); + return response; + }, +}; diff --git a/components/zoho_sheet/actions/update-row/update-row.mjs b/components/zoho_sheet/actions/update-row/update-row.mjs new file mode 100644 index 0000000000000..6bdb28f01cb46 --- /dev/null +++ b/components/zoho_sheet/actions/update-row/update-row.mjs @@ -0,0 +1,41 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "zoho_sheet-update-row", + name: "Update Row", + description: "Finds a specific row by its index and updates its content. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", + version: "0.0.1", + type: "action", + props: { + zohoSheet, + worksheet: { + propDefinition: [ + zohoSheet, + "worksheet", + ], + }, + rowIndex: { + propDefinition: [ + zohoSheet, + "rowIndex", + ], + }, + data: { + propDefinition: [ + zohoSheet, + "data", + ], + }, + }, + async run({ $ }) { + const response = await this.zohoSheet.updateRow({ + worksheet: this.worksheet, + rowIndex: this.rowIndex, + data: this.data, + }); + + $.export("$summary", `Successfully updated row ${this.rowIndex} in worksheet ${this.worksheet}`); + return response; + }, +}; diff --git a/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs b/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs new file mode 100644 index 0000000000000..970f701642a75 --- /dev/null +++ b/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs @@ -0,0 +1,101 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; +import crypto from "crypto"; +import { axios } from "@pipedream/platform"; + +export default { + key: "zoho_sheet-new-or-updated-row-instant", + name: "New or Updated Row Instant", + description: "Emit new event whenever a row is added or modified. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + zohoSheet, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + worksheet: { + propDefinition: [ + zohoSheet, + "worksheet", + ], + }, + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + async _emitEvent(event) { + this.$emit(event, { + id: `${event.id}-${new Date().getTime()}`, + summary: `Row ${event.type} in worksheet`, + ts: new Date(), + }); + }, + }, + hooks: { + async deploy() { + try { + const events = await this.zohoSheet.emitNewRowEvent({ + worksheet: this.worksheet, + }); + for (const event of events) { + await this._emitEvent(event); + } + } catch (error) { + console.error("Error during deploy:", error); + } + }, + async activate() { + const hookId = await this.zohoSheet.emitRowChangeEvent({ + worksheet: this.worksheet, + }); + this._setWebhookId(hookId); + }, + async deactivate() { + const id = this._getWebhookId(); + if (id) { + // Assuming a method to delete webhook has a similar signature + await this.zohoSheet.deleteWebhook({ + worksheet: this.worksheet, + webhookId: id, + }); + } + }, + }, + async run(event) { + try { + const signature = event.headers["x-zoho-signature"]; + const rawBody = event.rawBody; + const computedSignature = crypto.createHmac("sha256", this.zohoSheet.$auth.oauth_access_token).update(rawBody) + .digest("base64"); + + if (signature !== computedSignature) { + this.http.respond({ + status: 401, + body: "Unauthorized", + }); + return; + } + + const { data } = event.body; + await this._emitEvent(data); + + this.http.respond({ + status: 200, + body: "OK", + }); + } catch (error) { + console.error("Error processing webhook:", error); + this.http.respond({ + status: 500, + body: "Error", + }); + } + }, +}; diff --git a/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs b/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs new file mode 100644 index 0000000000000..5e75bda3ddfb2 --- /dev/null +++ b/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs @@ -0,0 +1,73 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "zoho_sheet-new-row-instant", + name: "New Row Created (Instant)", + description: "Emit new event each time a new row is created in a Zoho Sheet worksheet. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + zohoSheet, + http: { + type: "$.interface.http", + customResponse: false, + }, + db: "$.service.db", + worksheet: { + propDefinition: [ + zohoSheet, + "worksheet", + ], + }, + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + }, + hooks: { + async deploy() { + // Emits the 50 most recent row entries from the specified worksheet + const recentRows = await this.zohoSheet.emitNewRowEvent({ + worksheet: this.worksheet, + }); + for (const row of recentRows.slice(-50).reverse()) { + this.$emit(row, { + id: row.id, + summary: `New row in worksheet: ${row.worksheetId}`, + ts: Date.now(), + }); + } + }, + async activate() { + const webhookId = await this.zohoSheet.emitNewRowEvent({ + worksheet: this.worksheet, + }); + this._setWebhookId(webhookId); + }, + async deactivate() { + const id = this._getWebhookId(); + if (id) { + await this.zohoSheet.deleteRow({ + worksheet: this.worksheet, + criteria: { + webhook_id: id, + }, + }); + } + }, + }, + async run(event) { + const { body } = event; + this.$emit(body, { + id: body.id, + summary: `New row created in worksheet: ${this.worksheet}`, + ts: Date.now(), + }); + }, +}; diff --git a/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs b/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs new file mode 100644 index 0000000000000..e88adb0cd06e7 --- /dev/null +++ b/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs @@ -0,0 +1,72 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "zoho_sheet-new-workbook-instant", + name: "New Workbook Created", + description: "Emit new event whenever a new workbook is created. [See the documentation](https://www.zoho.com/sheet/help/api/)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + zohoSheet, + db: "$.service.db", + http: { + type: "$.interface.http", + customResponse: false, + }, + location: { + propDefinition: [ + zohoSheet, + "location", + ], + optional: true, + }, + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + }, + hooks: { + async deploy() { + const events = await this.zohoSheet.emitNewWorkbookEvent({ + location: this.location, + }); + events.slice(0, 50).forEach((event) => { + this.$emit(event, { + id: event.id, + summary: `New workbook: ${event.name}`, + ts: Date.parse(event.created_time), + }); + }); + }, + async activate() { + const options = { + location: this.location, + }; + const webhookId = await this.zohoSheet.emitNewWorkbookEvent(options); + this._setWebhookId(webhookId); + }, + async deactivate() { + const id = this._getWebhookId(); + if (id) { + await this.zohoSheet.emitNewWorkbookEvent({ + id, + method: "DELETE", + }); + } + }, + }, + async run(event) { + const { body } = event; + this.$emit(body, { + id: body.id, + summary: `New workbook: ${body.name}`, + ts: Date.parse(body.created_time), + }); + }, +}; diff --git a/components/zoho_sheet/zoho_sheet.app.mjs b/components/zoho_sheet/zoho_sheet.app.mjs new file mode 100644 index 0000000000000..50fcc048e8783 --- /dev/null +++ b/components/zoho_sheet/zoho_sheet.app.mjs @@ -0,0 +1,146 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "zoho_sheet", + propDefinitions: { + worksheet: { + type: "string", + label: "Worksheet", + description: "The name or ID of the worksheet", + async options() { + const worksheets = await this.listWorksheets(); + return worksheets.map((ws) => ({ + label: ws.name, + value: ws.id, + })); + }, + }, + data: { + type: "object", + label: "Data", + description: "The data for the row content, including the column headers as keys", + }, + criteria: { + type: "object", + label: "Criteria", + description: "Conditions to locate the row to delete", + }, + rowIndex: { + type: "integer", + label: "Row Index", + description: "The index of the row to update", + }, + location: { + type: "string", + label: "Workbook Location", + description: "Optional: Specific location to monitor in Zoho Sheet", + optional: true, + }, + }, + methods: { + _baseUrl() { + return "https://www.zohoapis.com/sheet/v2"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, method = "GET", path = "/", headers, ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }, + }); + }, + async listWorksheets() { + return this._makeRequest({ + path: "/worksheets", + }); + }, + async emitNewRowEvent({ + worksheet, ...opts + }) { + const path = `/workbooks/${worksheet}/new_row_event`; + return this._makeRequest({ + ...opts, + path, + }); + }, + async emitRowChangeEvent({ + worksheet, ...opts + }) { + const path = `/workbooks/${worksheet}/row_change_event`; + return this._makeRequest({ + ...opts, + path, + }); + }, + async emitNewWorkbookEvent({ + location, ...opts + }) { + const path = "/workbooks/new_workbook_event"; + const params = location + ? { + location, + } + : {}; + return this._makeRequest({ + ...opts, + path, + params, + }); + }, + async createRow({ + worksheet, data, + }) { + return this._makeRequest({ + method: "POST", + path: `/worksheet/${worksheet}/row`, + data, + }); + }, + async deleteRow({ + worksheet, criteria, + }) { + return this._makeRequest({ + method: "DELETE", + path: `/worksheet/${worksheet}/row`, + params: { + criteria, + }, + }); + }, + async updateRow({ + worksheet, rowIndex, data, + }) { + return this._makeRequest({ + method: "PUT", + path: `/worksheet/${worksheet}/row/${rowIndex}`, + data, + }); + }, + async paginate(fn, ...opts) { + let results = []; + let page = 1; + let response; + + do { + response = await fn({ + ...opts, + params: { + ...opts.params, + page, + }, + }); + results = results.concat(response); + page += 1; + } while (response && response.length > 0); + + return results; + }, + }, +}; From 18316f960b2e1e16ecdf139ec9b7678f3bd3b139 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 13 Nov 2024 17:48:35 -0300 Subject: [PATCH 2/4] [Components] zoho_sheet #14584 Sources - New Row (Instant) - New Or Updated Row (Instant) - New Workbook (Instant) Actions - Create Row - Search Delete Row - Update Row --- components/zoho_sheet/.gitignore | 3 - .../actions/create-row/create-row.mjs | 28 ++- .../search-delete-row/search-delete-row.mjs | 62 +++++- .../actions/update-row/update-row.mjs | 54 +++++- components/zoho_sheet/app/zoho_sheet.app.ts | 13 -- components/zoho_sheet/common/utils.mjs | 24 +++ components/zoho_sheet/package.json | 10 +- components/zoho_sheet/sources/common/base.mjs | 50 +++++ .../new-or-updated-row-instant.mjs | 119 ++++-------- .../new-or-updated-row-instant/test-event.mjs | 17 ++ .../new-row-instant/new-row-instant.mjs | 82 +++----- .../sources/new-row-instant/test-event.mjs | 17 ++ .../new-workbook-instant.mjs | 74 ++------ .../new-workbook-instant/test-event.mjs | 8 + components/zoho_sheet/zoho_sheet.app.mjs | 177 +++++++++--------- 15 files changed, 415 insertions(+), 323 deletions(-) delete mode 100644 components/zoho_sheet/.gitignore delete mode 100644 components/zoho_sheet/app/zoho_sheet.app.ts create mode 100644 components/zoho_sheet/common/utils.mjs create mode 100644 components/zoho_sheet/sources/common/base.mjs create mode 100644 components/zoho_sheet/sources/new-or-updated-row-instant/test-event.mjs create mode 100644 components/zoho_sheet/sources/new-row-instant/test-event.mjs create mode 100644 components/zoho_sheet/sources/new-workbook-instant/test-event.mjs diff --git a/components/zoho_sheet/.gitignore b/components/zoho_sheet/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/zoho_sheet/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/zoho_sheet/actions/create-row/create-row.mjs b/components/zoho_sheet/actions/create-row/create-row.mjs index f8edf0f019572..882a067ba3c02 100644 --- a/components/zoho_sheet/actions/create-row/create-row.mjs +++ b/components/zoho_sheet/actions/create-row/create-row.mjs @@ -1,5 +1,5 @@ +import { parseObject } from "../../common/utils.mjs"; import zohoSheet from "../../zoho_sheet.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "zoho_sheet-create-row", @@ -9,12 +9,27 @@ export default { type: "action", props: { zohoSheet, + workbookId: { + propDefinition: [ + zohoSheet, + "workbookId", + ], + }, worksheet: { propDefinition: [ zohoSheet, "worksheet", + ({ workbookId }) => ({ + workbookId, + }), ], }, + headerRow: { + type: "integer", + label: "Header Row", + description: "Default value is 1. This can be mentioned if the table header is not in the first row of the worksheet.", + optional: true, + }, data: { propDefinition: [ zohoSheet, @@ -24,11 +39,16 @@ export default { }, async run({ $ }) { const response = await this.zohoSheet.createRow({ - worksheet: this.worksheet, - data: this.data, + $, + workbookId: this.workbookId, + data: { + worksheet_id: this.worksheet, + header_row: this.headerRow || 1, + json_data: JSON.stringify(parseObject(this.data)), + }, }); - $.export("$summary", `Successfully created a row in the worksheet: ${this.worksheet}`); + $.export("$summary", `Successfully created a row in the worksheet: ${response.sheet_name}`); return response; }, }; diff --git a/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs b/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs index a4b8369f74a6d..da2705b497491 100644 --- a/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs +++ b/components/zoho_sheet/actions/search-delete-row/search-delete-row.mjs @@ -1,31 +1,85 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; import zohoSheet from "../../zoho_sheet.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "zoho_sheet-search-delete-row", name: "Search and Delete Row", description: "Searches for a row based on provided criteria and deletes it. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { zohoSheet, + workbookId: { + propDefinition: [ + zohoSheet, + "workbookId", + ], + }, worksheet: { propDefinition: [ zohoSheet, "worksheet", + ({ workbookId }) => ({ + workbookId, + }), ], }, + headerRow: { + propDefinition: [ + zohoSheet, + "headerRow", + ], + optional: true, + }, criteria: { propDefinition: [ zohoSheet, "criteria", ], + optional: true, + }, + rowArray: { + type: "integer[]", + label: "Row Array", + description: "Array of row indexs, which needs to be deleted.", + optional: true, + }, + firstMatchOnly: { + propDefinition: [ + zohoSheet, + "firstMatchOnly", + ], + }, + isCaseSensitive: { + propDefinition: [ + zohoSheet, + "isCaseSensitive", + ], + }, + deleteRows: { + type: "boolean", + label: "Delete Rows", + description: "If true it will delete the rows completely, otherwise the records are only erased by default.", + default: false, }, }, async run({ $ }) { + if (!this.criteria && !this.rowArray) { + throw new ConfigurationError("You must provide at least **Criteria** or **Row Array** to process this request."); + } const response = await this.zohoSheet.deleteRow({ - worksheet: this.worksheet, - criteria: this.criteria, + $, + workbookId: this.workbookId, + data: { + worksheet_id: this.worksheet, + header_row: this.headerRow, + criteria: this.criteria, + row_array: JSON.stringify(parseObject(this.rowArray)), + first_match_only: this.firstMatchOnly, + is_case_sensitive: this.isCaseSensitive, + delete_rows: this.deleteRows, + }, }); $.export("$summary", `Row matching criteria deleted successfully from worksheet ${this.worksheet}`); diff --git a/components/zoho_sheet/actions/update-row/update-row.mjs b/components/zoho_sheet/actions/update-row/update-row.mjs index 6bdb28f01cb46..4dfd8bdf696e6 100644 --- a/components/zoho_sheet/actions/update-row/update-row.mjs +++ b/components/zoho_sheet/actions/update-row/update-row.mjs @@ -1,5 +1,5 @@ +import { parseObject } from "../../common/utils.mjs"; import zohoSheet from "../../zoho_sheet.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "zoho_sheet-update-row", @@ -9,16 +9,47 @@ export default { type: "action", props: { zohoSheet, + workbookId: { + propDefinition: [ + zohoSheet, + "workbookId", + ], + }, worksheet: { propDefinition: [ zohoSheet, "worksheet", + ({ workbookId }) => ({ + workbookId, + }), + ], + }, + headerRow: { + propDefinition: [ + zohoSheet, + "headerRow", + ], + optional: true, + }, + criteria: { + propDefinition: [ + zohoSheet, + "criteria", + ], + description: "If criteria is not set all available rows will get updated. Mention the criteria as described above.", + optional: true, + }, + firstMatchOnly: { + propDefinition: [ + zohoSheet, + "firstMatchOnly", ], + description: "If true and if there are multiple records on the specified criteria, records will be updated for first match alone. Otherwise, all the matched records will be updated.", }, - rowIndex: { + isCaseSensitive: { propDefinition: [ zohoSheet, - "rowIndex", + "isCaseSensitive", ], }, data: { @@ -26,16 +57,25 @@ export default { zohoSheet, "data", ], + type: "object", + description: "The JSON data that needs to be updated. Example:{\"Month\":\"May\",\"Amount\":50}", }, }, async run({ $ }) { const response = await this.zohoSheet.updateRow({ - worksheet: this.worksheet, - rowIndex: this.rowIndex, - data: this.data, + $, + workbookId: this.workbookId, + data: { + worksheet_id: this.worksheet, + header_row: this.headerRow, + criteria: this.criteria, + first_match_only: this.firstMatchOnly, + is_case_sensitive: this.isCaseSensitive, + data: JSON.stringify(parseObject(this.data)), + }, }); - $.export("$summary", `Successfully updated row ${this.rowIndex} in worksheet ${this.worksheet}`); + $.export("$summary", `Successfully updated ${response.no_of_affected_rows} row(s) in worksheet ${this.worksheet}`); return response; }, }; diff --git a/components/zoho_sheet/app/zoho_sheet.app.ts b/components/zoho_sheet/app/zoho_sheet.app.ts deleted file mode 100644 index 7b57f52e4f210..0000000000000 --- a/components/zoho_sheet/app/zoho_sheet.app.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ - type: "app", - app: "zoho_sheet", - propDefinitions: {}, - methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); - }, - }, -}); diff --git a/components/zoho_sheet/common/utils.mjs b/components/zoho_sheet/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/zoho_sheet/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/zoho_sheet/package.json b/components/zoho_sheet/package.json index dd257a1f16d70..7c6ae868bb86f 100644 --- a/components/zoho_sheet/package.json +++ b/components/zoho_sheet/package.json @@ -1,18 +1,18 @@ { "name": "@pipedream/zoho_sheet", - "version": "0.0.3", + "version": "0.1.0", "description": "Pipedream Zoho Sheet Components", - "main": "dist/app/zoho_sheet.app.mjs", + "main": "zoho_sheet.app.mjs", "keywords": [ "pipedream", "zoho_sheet" ], - "files": [ - "dist" - ], "homepage": "https://pipedream.com/apps/zoho_sheet", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/zoho_sheet/sources/common/base.mjs b/components/zoho_sheet/sources/common/base.mjs new file mode 100644 index 0000000000000..fd945d3a1f8e0 --- /dev/null +++ b/components/zoho_sheet/sources/common/base.mjs @@ -0,0 +1,50 @@ +import zohoSheet from "../../zoho_sheet.app.mjs"; + +export default { + props: { + zohoSheet, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + serviceName: { + type: "string", + label: "Service Name", + description: "The name of the webhook.", + }, + }, + methods: { + getExtraData() { + return {}; + }, + }, + hooks: { + async activate() { + await this.zohoSheet.createWebhook({ + data: { + service_name: this.serviceName.replace(/\s/g, ""), + target_url: this.http.endpoint, + event: this.getEvent(), + ...this.getExtraData(), + }, + }); + }, + async deactivate() { + await this.zohoSheet.deleteWebhook({ + data: { + target_url: this.http.endpoint, + ...this.getExtraData(), + }, + }); + }, + }, + async run({ body }) { + const ts = Date.parse(new Date()); + this.$emit(body, { + id: `${ts}`, + summary: this.getSummary(body), + ts: ts, + }); + }, +}; diff --git a/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs b/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs index 970f701642a75..645345c7f31e3 100644 --- a/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs +++ b/components/zoho_sheet/sources/new-or-updated-row-instant/new-or-updated-row-instant.mjs @@ -1,101 +1,54 @@ -import zohoSheet from "../../zoho_sheet.app.mjs"; -import crypto from "crypto"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "zoho_sheet-new-or-updated-row-instant", - name: "New or Updated Row Instant", - description: "Emit new event whenever a row is added or modified. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", - version: "0.0.{{ts}}", + name: "New or Updated Row (Instant)", + description: "Emit new event whenever a row is added or modified.", + version: "0.0.1", type: "source", dedupe: "unique", props: { - zohoSheet, - http: { - type: "$.interface.http", - customResponse: true, + ...common.props, + workbookId: { + propDefinition: [ + common.props.zohoSheet, + "workbookId", + ], }, - db: "$.service.db", - worksheet: { + worksheetId: { propDefinition: [ - zohoSheet, + common.props.zohoSheet, "worksheet", + ({ workbookId }) => ({ + workbookId, + }), ], + withLabel: true, }, - }, - methods: { - _getWebhookId() { - return this.db.get("webhookId"); - }, - _setWebhookId(id) { - this.db.set("webhookId", id); - }, - async _emitEvent(event) { - this.$emit(event, { - id: `${event.id}-${new Date().getTime()}`, - summary: `Row ${event.type} in worksheet`, - ts: new Date(), - }); + alert: { + type: "alert", + alertType: "info", + content: "**New row** will be triggered only after the entire row is completed.", }, }, - hooks: { - async deploy() { - try { - const events = await this.zohoSheet.emitNewRowEvent({ - worksheet: this.worksheet, - }); - for (const event of events) { - await this._emitEvent(event); - } - } catch (error) { - console.error("Error during deploy:", error); - } + methods: { + ...common.methods, + getEvent() { + return "update_worksheet"; }, - async activate() { - const hookId = await this.zohoSheet.emitRowChangeEvent({ - worksheet: this.worksheet, - }); - this._setWebhookId(hookId); + getExtraData() { + return { + resource_id: this.workbookId, + worksheet_id: this.worksheetId.value, + }; }, - async deactivate() { - const id = this._getWebhookId(); - if (id) { - // Assuming a method to delete webhook has a similar signature - await this.zohoSheet.deleteWebhook({ - worksheet: this.worksheet, - webhookId: id, - }); - } + getSummary({ updated_rows }) { + return `Row ${updated_rows[0].row_type === "NEW" + ? "created" + : "updated"} in worksheet ${this.worksheetId.label}`; }, }, - async run(event) { - try { - const signature = event.headers["x-zoho-signature"]; - const rawBody = event.rawBody; - const computedSignature = crypto.createHmac("sha256", this.zohoSheet.$auth.oauth_access_token).update(rawBody) - .digest("base64"); - - if (signature !== computedSignature) { - this.http.respond({ - status: 401, - body: "Unauthorized", - }); - return; - } - - const { data } = event.body; - await this._emitEvent(data); - - this.http.respond({ - status: 200, - body: "OK", - }); - } catch (error) { - console.error("Error processing webhook:", error); - this.http.respond({ - status: 500, - body: "Error", - }); - } - }, + sampleEmit, }; diff --git a/components/zoho_sheet/sources/new-or-updated-row-instant/test-event.mjs b/components/zoho_sheet/sources/new-or-updated-row-instant/test-event.mjs new file mode 100644 index 0000000000000..23b39924bf5be --- /dev/null +++ b/components/zoho_sheet/sources/new-or-updated-row-instant/test-event.mjs @@ -0,0 +1,17 @@ +export default { + "updated_rows" : [ + { + "Name": "John", + "Age": 24, + "Marks": 34, + "row_index": 3, + "row_type": "update" + } + ], + "header_row_index": 1, + "start_column": 1, + "end_column": 3, + "webhook_id": "", + "service_name": "", + "event": "update_worksheet" +} \ No newline at end of file diff --git a/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs b/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs index 5e75bda3ddfb2..7502ed121f841 100644 --- a/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs +++ b/components/zoho_sheet/sources/new-row-instant/new-row-instant.mjs @@ -1,73 +1,47 @@ -import zohoSheet from "../../zoho_sheet.app.mjs"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "zoho_sheet-new-row-instant", name: "New Row Created (Instant)", - description: "Emit new event each time a new row is created in a Zoho Sheet worksheet. [See the documentation](https://www.zoho.com/sheet/help/api/v2/)", - version: "0.0.{{ts}}", + description: "Emit new event each time a new row is created in a Zoho Sheet worksheet.", + version: "0.0.1", type: "source", dedupe: "unique", props: { - zohoSheet, - http: { - type: "$.interface.http", - customResponse: false, + ...common.props, + workbookId: { + propDefinition: [ + common.props.zohoSheet, + "workbookId", + ], }, - db: "$.service.db", - worksheet: { + worksheetId: { propDefinition: [ - zohoSheet, + common.props.zohoSheet, "worksheet", + ({ workbookId }) => ({ + workbookId, + }), ], + withLabel: true, }, }, methods: { - _getWebhookId() { - return this.db.get("webhookId"); - }, - _setWebhookId(id) { - this.db.set("webhookId", id); + ...common.methods, + getEvent() { + return "new_row"; }, - }, - hooks: { - async deploy() { - // Emits the 50 most recent row entries from the specified worksheet - const recentRows = await this.zohoSheet.emitNewRowEvent({ - worksheet: this.worksheet, - }); - for (const row of recentRows.slice(-50).reverse()) { - this.$emit(row, { - id: row.id, - summary: `New row in worksheet: ${row.worksheetId}`, - ts: Date.now(), - }); - } - }, - async activate() { - const webhookId = await this.zohoSheet.emitNewRowEvent({ - worksheet: this.worksheet, - }); - this._setWebhookId(webhookId); + getExtraData() { + return { + resource_id: this.workbookId, + worksheet_id: this.worksheetId.value, + }; }, - async deactivate() { - const id = this._getWebhookId(); - if (id) { - await this.zohoSheet.deleteRow({ - worksheet: this.worksheet, - criteria: { - webhook_id: id, - }, - }); - } + getSummary() { + return `New row in worksheet ${this.worksheetId.label}`; }, }, - async run(event) { - const { body } = event; - this.$emit(body, { - id: body.id, - summary: `New row created in worksheet: ${this.worksheet}`, - ts: Date.now(), - }); - }, + sampleEmit, }; diff --git a/components/zoho_sheet/sources/new-row-instant/test-event.mjs b/components/zoho_sheet/sources/new-row-instant/test-event.mjs new file mode 100644 index 0000000000000..42946d13d2528 --- /dev/null +++ b/components/zoho_sheet/sources/new-row-instant/test-event.mjs @@ -0,0 +1,17 @@ +export default { + "updated_rows" : [ + { + "Name": "John", + "Age": 24, + "Marks": 34, + "row_index": 3, + "row_type": "update" + } + ], + "header_row_index": 1, + "start_column": 1, + "end_column": 3, + "webhook_id": "", + "service_name": "", + "event": "new_row" +} \ No newline at end of file diff --git a/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs b/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs index e88adb0cd06e7..7de4a80469a0d 100644 --- a/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs +++ b/components/zoho_sheet/sources/new-workbook-instant/new-workbook-instant.mjs @@ -1,72 +1,22 @@ -import zohoSheet from "../../zoho_sheet.app.mjs"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "zoho_sheet-new-workbook-instant", - name: "New Workbook Created", - description: "Emit new event whenever a new workbook is created. [See the documentation](https://www.zoho.com/sheet/help/api/)", - version: "0.0.{{ts}}", + name: "New Workbook Created (Instant)", + description: "Emit new event whenever a new workbook is created.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - zohoSheet, - db: "$.service.db", - http: { - type: "$.interface.http", - customResponse: false, - }, - location: { - propDefinition: [ - zohoSheet, - "location", - ], - optional: true, - }, - }, methods: { - _getWebhookId() { - return this.db.get("webhookId"); - }, - _setWebhookId(id) { - this.db.set("webhookId", id); + ...common.methods, + getEvent() { + return "new_workbook"; }, - }, - hooks: { - async deploy() { - const events = await this.zohoSheet.emitNewWorkbookEvent({ - location: this.location, - }); - events.slice(0, 50).forEach((event) => { - this.$emit(event, { - id: event.id, - summary: `New workbook: ${event.name}`, - ts: Date.parse(event.created_time), - }); - }); - }, - async activate() { - const options = { - location: this.location, - }; - const webhookId = await this.zohoSheet.emitNewWorkbookEvent(options); - this._setWebhookId(webhookId); + getSummary(event) { + return `New workbook: ${event.workbook_name} (${event.resource_id})`; }, - async deactivate() { - const id = this._getWebhookId(); - if (id) { - await this.zohoSheet.emitNewWorkbookEvent({ - id, - method: "DELETE", - }); - } - }, - }, - async run(event) { - const { body } = event; - this.$emit(body, { - id: body.id, - summary: `New workbook: ${body.name}`, - ts: Date.parse(body.created_time), - }); }, + sampleEmit, }; diff --git a/components/zoho_sheet/sources/new-workbook-instant/test-event.mjs b/components/zoho_sheet/sources/new-workbook-instant/test-event.mjs new file mode 100644 index 0000000000000..f591adf0eb33b --- /dev/null +++ b/components/zoho_sheet/sources/new-workbook-instant/test-event.mjs @@ -0,0 +1,8 @@ +export default { + "workbook_url": "", + "resource_id": "", + "workbook_name": "", + "webhook_id": "", + "service_name": "", + "event": "new_workbook" +} \ No newline at end of file diff --git a/components/zoho_sheet/zoho_sheet.app.mjs b/components/zoho_sheet/zoho_sheet.app.mjs index 50fcc048e8783..12e2617345c12 100644 --- a/components/zoho_sheet/zoho_sheet.app.mjs +++ b/components/zoho_sheet/zoho_sheet.app.mjs @@ -4,143 +4,144 @@ export default { type: "app", app: "zoho_sheet", propDefinitions: { - worksheet: { + workbookId: { type: "string", label: "Worksheet", - description: "The name or ID of the worksheet", + description: "The ID of the workbook (Spreadsheet)", async options() { - const worksheets = await this.listWorksheets(); - return worksheets.map((ws) => ({ - label: ws.name, - value: ws.id, + const { workbooks } = await this.listWorkbooks({}); + return workbooks.map(({ + resource_id: value, workbook_name: label, + }) => ({ + label, + value, + })); + }, + }, + worksheet: { + type: "string", + label: "Worksheet", + description: "The ID of the worksheet (Sheet of the Spreadsheet)", + async options({ workbookId }) { + const { worksheet_names: worksheets } = await this.listWorksheets({ + workbookId, + }); + return worksheets.map(({ + worksheet_id: value, worksheet_name: label, + }) => ({ + label, + value, })); }, }, data: { - type: "object", - label: "Data", - description: "The data for the row content, including the column headers as keys", + type: "string[]", + label: "JSON Data", + description: "An array of objects of the data for the row content, including the column headers as keys. **Example: {\"Name\":\"Joe\",\"Region\":\"South\",\"Units\":284}**", + }, + headerRow: { + type: "integer", + label: "Header Row", + description: "By default, first row of the worksheet is considered as header row. This can be used if tabular data starts from any row other than the first row..", }, criteria: { - type: "object", + type: "string", label: "Criteria", - description: "Conditions to locate the row to delete", + description: "Conditions to locate the row to delete. **Example: \"Month\"=\"March\" and \"Amount\">50**", }, - rowIndex: { - type: "integer", - label: "Row Index", - description: "The index of the row to update", + firstMatchOnly: { + type: "boolean", + label: "First Match Only", + description: "If true and if there are multiple records on the specified criteria, records will be deleted for first match alone. Otherwise, all the matched records will be deleted. This parameter will be ignored if criteria is not mentioned.", + default: false, }, - location: { - type: "string", - label: "Workbook Location", - description: "Optional: Specific location to monitor in Zoho Sheet", - optional: true, + isCaseSensitive: { + type: "boolean", + label: "Is Case Sensitive", + description: "Can be set as false for case insensitive search.", + default: true, }, }, methods: { _baseUrl() { - return "https://www.zohoapis.com/sheet/v2"; + return `https://sheet.${this.$auth.base_api_uri}/api/v2`; + }, + _headers() { + return { + "Authorization": `Zoho-oauthtoken ${this.$auth.oauth_access_token}`, + "Content-Type": "application/x-www-form-urlencoded", + }; }, - async _makeRequest(opts = {}) { - const { - $ = this, method = "GET", path = "/", headers, ...otherOpts - } = opts; + _makeRequest({ + $ = this, path, data, method, ...opts + }) { return axios($, { - ...otherOpts, - method, + method: "POST", url: this._baseUrl() + path, - headers: { - ...headers, - Authorization: `Bearer ${this.$auth.oauth_access_token}`, + headers: this._headers(), + data: { + ...data, + method, }, + ...opts, }); }, - async listWorksheets() { + listWorkbooks(opts = {}) { return this._makeRequest({ - path: "/worksheets", + path: "/workbooks", + method: "workbook.list", + ...opts, }); }, - async emitNewRowEvent({ - worksheet, ...opts + listWorksheets({ + workbookId, ...opts }) { - const path = `/workbooks/${worksheet}/new_row_event`; return this._makeRequest({ + path: `/${workbookId}`, + method: "worksheet.list", ...opts, - path, }); }, - async emitRowChangeEvent({ - worksheet, ...opts + createRow({ + workbookId, ...opts }) { - const path = `/workbooks/${worksheet}/row_change_event`; return this._makeRequest({ + path: `/${workbookId}`, + method: "worksheet.records.add", ...opts, - path, }); }, - async emitNewWorkbookEvent({ - location, ...opts + deleteRow({ + workbookId, ...opts }) { - const path = "/workbooks/new_workbook_event"; - const params = location - ? { - location, - } - : {}; return this._makeRequest({ + path: `/${workbookId}`, + method: "worksheet.records.delete", ...opts, - path, - params, }); }, - async createRow({ - worksheet, data, + updateRow({ + workbookId, ...opts }) { return this._makeRequest({ - method: "POST", - path: `/worksheet/${worksheet}/row`, - data, + path: `/${workbookId}`, + method: "worksheet.records.update", + ...opts, }); }, - async deleteRow({ - worksheet, criteria, - }) { + createWebhook(opts = {}) { return this._makeRequest({ - method: "DELETE", - path: `/worksheet/${worksheet}/row`, - params: { - criteria, - }, + path: "/webhook", + method: "webhook.subscribe", + ...opts, }); }, - async updateRow({ - worksheet, rowIndex, data, - }) { + deleteWebhook(opts = {}) { return this._makeRequest({ - method: "PUT", - path: `/worksheet/${worksheet}/row/${rowIndex}`, - data, + path: "/webhook", + method: "webhook.unsubscribe", + ...opts, }); }, - async paginate(fn, ...opts) { - let results = []; - let page = 1; - let response; - - do { - response = await fn({ - ...opts, - params: { - ...opts.params, - page, - }, - }); - results = results.concat(response); - page += 1; - } while (response && response.length > 0); - - return results; - }, }, }; From d3f0fd68f0e0fc3978f7e040057b06a9ac50ea15 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 13 Nov 2024 17:50:02 -0300 Subject: [PATCH 3/4] pnpm update --- pnpm-lock.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7315a9f70c3f..dae46dedb41a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12010,7 +12010,10 @@ importers: '@pipedream/platform': 1.5.1 components/zoho_sheet: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/zoho_sign: specifiers: From 012035079ca4acc557d6e3e964414018a5ee393d Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 14 Nov 2024 12:17:00 -0300 Subject: [PATCH 4/4] Update components/zoho_sheet/sources/common/base.mjs Co-authored-by: Jorge Cortes --- components/zoho_sheet/sources/common/base.mjs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/zoho_sheet/sources/common/base.mjs b/components/zoho_sheet/sources/common/base.mjs index fd945d3a1f8e0..68b830a1fb559 100644 --- a/components/zoho_sheet/sources/common/base.mjs +++ b/components/zoho_sheet/sources/common/base.mjs @@ -3,10 +3,7 @@ import zohoSheet from "../../zoho_sheet.app.mjs"; export default { props: { zohoSheet, - http: { - type: "$.interface.http", - customResponse: true, - }, + http: "$.interface.http", db: "$.service.db", serviceName: { type: "string",