From e4d26ca1f925b4e3b79455ff755f36c201795aba Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 9 Sep 2024 12:07:31 -0300 Subject: [PATCH 1/5] agrello init --- .../create-document-from-template.mjs | 83 ++++++++ .../actions/get-document/get-document.mjs | 26 +++ .../upload-document/upload-document.mjs | 34 ++++ components/agrello/agrello.app.mjs | 183 +++++++++++++++++- components/agrello/package.json | 2 +- .../sources/new-document/new-document.mjs | 73 +++++++ .../new-signature-instant.mjs | 84 ++++++++ .../new-signed-document-instant.mjs | 63 ++++++ 8 files changed, 542 insertions(+), 6 deletions(-) create mode 100644 components/agrello/actions/create-document-from-template/create-document-from-template.mjs create mode 100644 components/agrello/actions/get-document/get-document.mjs create mode 100644 components/agrello/actions/upload-document/upload-document.mjs create mode 100644 components/agrello/sources/new-document/new-document.mjs create mode 100644 components/agrello/sources/new-signature-instant/new-signature-instant.mjs create mode 100644 components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs diff --git a/components/agrello/actions/create-document-from-template/create-document-from-template.mjs b/components/agrello/actions/create-document-from-template/create-document-from-template.mjs new file mode 100644 index 0000000000000..ea79ba74000e8 --- /dev/null +++ b/components/agrello/actions/create-document-from-template/create-document-from-template.mjs @@ -0,0 +1,83 @@ +import agrello from "../../agrello.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agrello-create-document-from-template", + name: "Create Document from Template", + description: "Creates a new document in Agrello, invites participants, and fills file variables. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", + version: "0.0.{{ts}}", + type: "action", + props: { + agrello, + folderId: { + propDefinition: [ + agrello, + "folderId", + ], + }, + name: { + type: "string", + label: "Document Name", + description: "The name of the document", + }, + outputType: { + type: "string", + label: "Output Type", + description: "The output type of the document", + options: [ + "pdf", + "asice", + "zip", + ], + }, + variables: { + type: "object", + label: "Variables", + description: "The variables for the document", + }, + signers: { + type: "string[]", + label: "Signers", + description: "The signers of the document", + }, + viewers: { + type: "string[]", + label: "Viewers", + description: "The viewers of the document", + }, + immediatePublish: { + type: "boolean", + label: "Immediate Publish", + description: "Whether to publish the document immediately", + }, + metadata: { + type: "object", + label: "Metadata", + description: "The metadata for the document", + }, + templateId: { + propDefinition: [ + agrello, + "templateId", + ], + optional: true, + }, + }, + async run({ $ }) { + const data = { + folderId: this.folderId, + name: this.name, + outputType: this.outputType, + variables: this.variables, + signers: this.signers, + viewers: this.viewers, + immediatePublish: this.immediatePublish, + metadata: this.metadata, + templateId: this.templateId, + }; + + const response = await this.agrello.createDocument(data); + $.export("$summary", `Successfully created document with ID ${response.id}`); + return response; + }, +}; diff --git a/components/agrello/actions/get-document/get-document.mjs b/components/agrello/actions/get-document/get-document.mjs new file mode 100644 index 0000000000000..45f95f00e7b31 --- /dev/null +++ b/components/agrello/actions/get-document/get-document.mjs @@ -0,0 +1,26 @@ +import agrello from "../../agrello.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agrello-get-document", + name: "Get Document", + description: "Get a document in Agrello. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", + version: "0.0.{{ts}}", + type: "action", + props: { + agrello, + documentId: { + propDefinition: [ + agrello, + "documentId", + ], + }, + }, + async run({ $ }) { + const response = await this.agrello.getDocument({ + documentId: this.documentId, + }); + $.export("$summary", `Successfully retrieved document with ID ${this.documentId}`); + return response; + }, +}; diff --git a/components/agrello/actions/upload-document/upload-document.mjs b/components/agrello/actions/upload-document/upload-document.mjs new file mode 100644 index 0000000000000..07f8b447cc629 --- /dev/null +++ b/components/agrello/actions/upload-document/upload-document.mjs @@ -0,0 +1,34 @@ +import agrello from "../../agrello.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agrello-upload-document", + name: "Upload Document", + description: "Uploads a document to Agrello. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", + version: "0.0.{{ts}}", + type: "action", + props: { + agrello, + folderId: { + propDefinition: [ + agrello, + "folderId", + ], + }, + file: { + propDefinition: [ + agrello, + "file", + ], + }, + }, + async run({ $ }) { + const response = await this.agrello.uploadDocument({ + folderId: this.folderId, + file: this.file, + }); + + $.export("$summary", `Successfully uploaded document to folder ID ${this.folderId}`); + return response; + }, +}; diff --git a/components/agrello/agrello.app.mjs b/components/agrello/agrello.app.mjs index 86b3689445f7a..047150f74713d 100644 --- a/components/agrello/agrello.app.mjs +++ b/components/agrello/agrello.app.mjs @@ -1,11 +1,184 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "agrello", - propDefinitions: {}, + propDefinitions: { + folderId: { + type: "string", + label: "Folder ID", + description: "The ID of the folder", + async options() { + const folders = await this.listFolders(); + return folders.map((folder) => ({ + label: folder.name, + value: folder.id, + })); + }, + }, + documentId: { + type: "string", + label: "Document ID", + description: "The ID of the document", + async options() { + const documents = await this.listDocuments(); + return documents.map((document) => ({ + label: document.name, + value: document.id, + })); + }, + }, + templateId: { + type: "string", + label: "Template ID", + description: "The ID of the template", + optional: true, + async options() { + const templates = await this.listTemplates(); + return templates.map((template) => ({ + label: template.name, + value: template.id, + })); + }, + }, + file: { + type: "string", + label: "File", + description: "The file to upload", + }, + name: { + type: "string", + label: "Document Name", + description: "The name of the document", + }, + outputType: { + type: "string", + label: "Output Type", + description: "The output type of the document", + options: [ + "pdf", + "asice", + "zip", + ], + }, + variables: { + type: "object", + label: "Variables", + description: "The variables for the document", + }, + signers: { + type: "string[]", + label: "Signers", + description: "The signers of the document", + }, + viewers: { + type: "string[]", + label: "Viewers", + description: "The viewers of the document", + }, + immediatePublish: { + type: "boolean", + label: "Immediate Publish", + description: "Whether to publish the document immediately", + }, + metadata: { + type: "object", + label: "Metadata", + description: "The metadata for the document", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.agrello.io"; + }, + 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 listFolders() { + return this._makeRequest({ + path: "/v3/folders", + }); + }, + async listDocuments() { + return this._makeRequest({ + path: "/v3/documents", + }); + }, + async listTemplates() { + return this._makeRequest({ + path: "/v3/templates", + }); + }, + async uploadDocument({ + folderId, file, + }) { + const formData = new FormData(); + formData.append("file", file); + return this._makeRequest({ + method: "POST", + path: `/folders/${folderId}/documents`, + data: formData, + headers: { + "Content-Type": "multipart/form-data", + }, + }); + }, + async getDocument({ documentId }) { + return this._makeRequest({ + path: `/documents/${documentId}`, + }); + }, + async createDocument({ + folderId, + name, + outputType, + variables, + signers, + viewers, + immediatePublish, + metadata, + templateId, + }) { + const data = { + folderId, + name, + outputType, + variables, + signers, + viewers, + immediatePublish, + metadata, + templateId, + }; + return this._makeRequest({ + method: "POST", + path: "/documents", + data, + }); + }, + async emitDocumentSignatureAdded() { + // Implementation to emit event when a signature is added to a document + }, + async emitDocumentSigned() { + // Implementation to emit event when a document is signed by all parties + }, + async emitUserAddedDocumentToFolder({ folderId }) { + // Implementation to emit event when a user adds a document to a specific folder }, }, -}; \ No newline at end of file +}; diff --git a/components/agrello/package.json b/components/agrello/package.json index e88166bb32ce1..319ca1beb0bbe 100644 --- a/components/agrello/package.json +++ b/components/agrello/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/agrello/sources/new-document/new-document.mjs b/components/agrello/sources/new-document/new-document.mjs new file mode 100644 index 0000000000000..738bc42f62c81 --- /dev/null +++ b/components/agrello/sources/new-document/new-document.mjs @@ -0,0 +1,73 @@ +import { axios } from "@pipedream/platform"; +import agrello from "../../agrello.app.mjs"; + +export default { + key: "agrello-new-document", + name: "New Document Added to Folder", + description: "Emit new event when a user adds a document to a specific folder. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + agrello, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60 * 15, // Default to 15 minutes + }, + }, + folderId: { + propDefinition: [ + agrello, + "folderId", + ], + }, + }, + methods: { + _getLastDocumentId() { + return this.db.get("lastDocumentId"); + }, + _setLastDocumentId(id) { + return this.db.set("lastDocumentId", id); + }, + async _getDocumentsInFolder(folderId) { + const documents = await this.agrello.listDocuments(); + return documents.filter((doc) => doc.folderId === folderId); + }, + }, + hooks: { + async deploy() { + const documents = await this._getDocumentsInFolder(this.folderId); + documents.slice(0, 50).forEach((doc) => this.$emit(doc, { + id: doc.id, + summary: `New Document: ${doc.name}`, + ts: Date.parse(doc.createdAt), + })); + if (documents.length > 0) { + this._setLastDocumentId(documents[0].id); + } + }, + async activate() { + // Add any activation logic here if needed + }, + async deactivate() { + // Add any deactivation logic here if needed + }, + }, + async run() { + const lastDocumentId = this._getLastDocumentId(); + const documents = await this._getDocumentsInFolder(this.folderId); + const newDocuments = documents.filter((doc) => doc.id > lastDocumentId); + + newDocuments.forEach((doc) => this.$emit(doc, { + id: doc.id, + summary: `New Document: ${doc.name}`, + ts: Date.parse(doc.createdAt), + })); + + if (newDocuments.length > 0) { + this._setLastDocumentId(newDocuments[0].id); + } + }, +}; diff --git a/components/agrello/sources/new-signature-instant/new-signature-instant.mjs b/components/agrello/sources/new-signature-instant/new-signature-instant.mjs new file mode 100644 index 0000000000000..a2c9486c5ae69 --- /dev/null +++ b/components/agrello/sources/new-signature-instant/new-signature-instant.mjs @@ -0,0 +1,84 @@ +import agrello from "../../agrello.app.mjs"; +import crypto from "crypto"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agrello-new-signature-instant", + name: "New Signature Added to Document", + description: "Emit new event when a signature is added to a document. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + agrello: { + type: "app", + app: "agrello", + }, + http: { + type: "$.interface.http", + customResponse: true, + }, + db: "$.service.db", + }, + methods: { + _getWebhookId() { + return this.db.get("webhookId"); + }, + _setWebhookId(id) { + this.db.set("webhookId", id); + }, + }, + hooks: { + async deploy() { + const documents = await this.agrello.listDocuments(); + for (const document of documents) { + const signatures = document.signatures || []; + for (const signature of signatures) { + this.$emit(signature, { + id: signature.id, + summary: `New signature added to document: ${document.name}`, + ts: Date.parse(signature.timestamp), + }); + } + } + }, + async activate() { + const webhookId = await this.agrello.createWebhook({ + url: this.http.endpoint, + event: "document_signature_added", + }); + this._setWebhookId(webhookId); + }, + async deactivate() { + const webhookId = this._getWebhookId(); + if (webhookId) { + await this.agrello.deleteWebhook(webhookId); + } + }, + }, + async run(event) { + const computedSignature = crypto + .createHmac("sha256", this.agrello.$auth.secret) + .update(event.body) + .digest("base64"); + + if (computedSignature !== event.headers["x-agrello-signature"]) { + this.http.respond({ + status: 401, + body: "Unauthorized", + }); + return; + } + + this.$emit(event.body, { + id: event.body.id, + summary: `New signature added to document ${event.body.documentId}`, + ts: Date.parse(event.body.timestamp), + }); + + this.http.respond({ + status: 200, + body: "OK", + }); + }, +}; diff --git a/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs b/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs new file mode 100644 index 0000000000000..9683a7f575216 --- /dev/null +++ b/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs @@ -0,0 +1,63 @@ +import agrello from "../../agrello.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "agrello-new-signed-document-instant", + name: "New Signed Document Instant", + description: "Emit new event when a given document is signed by all parties. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + agrello: { + type: "app", + app: "agrello", + }, + http: { + type: "$.interface.http", + customResponse: false, + }, + db: "$.service.db", + }, + hooks: { + async deploy() { + const documents = await this.agrello.listDocuments(); + const signedDocuments = documents.filter((doc) => doc.status === "signed"); + for (const doc of signedDocuments.slice(0, 50)) { + this.$emit(doc, { + id: doc.id, + summary: `Document signed: ${doc.name}`, + ts: Date.parse(doc.updatedAt), + }); + } + }, + async activate() { + const webhookId = await this.agrello.createWebhook({ + event: "document.signed", + url: this.http.endpoint, + }); + this.db.set("webhookId", webhookId); + }, + async deactivate() { + const webhookId = this.db.get("webhookId"); + if (webhookId) { + await this.agrello.deleteWebhook({ + id: webhookId, + }); + } + }, + }, + async run(event) { + const { documentId } = event.body; + const document = await this.agrello.getDocument({ + documentId, + }); + if (document.status === "signed") { + this.$emit(document, { + id: document.id, + summary: `Document signed: ${document.name}`, + ts: Date.parse(document.updatedAt), + }); + } + }, +}; From 6f551156b240a9a80189bd0808ca5277353bd345 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 9 Sep 2024 18:55:44 -0300 Subject: [PATCH 2/5] [Components] agrello #13863 Sources - New Signature (Instant) - New Signed Document (Instant) - New Document Actions - Get Document --- .../create-document-from-template.mjs | 83 ------- .../actions/get-document/get-document.mjs | 13 +- .../upload-document/upload-document.mjs | 34 --- components/agrello/agrello.app.mjs | 234 ++++++++---------- components/agrello/common/utils.mjs | 31 +++ components/agrello/package.json | 6 +- components/agrello/sources/common/base.mjs | 44 ++++ .../sources/new-document/new-document.mjs | 79 +++--- .../sources/new-document/test-event.mjs | 70 ++++++ .../new-signature-instant.mjs | 86 +------ .../new-signature-instant/test-event.mjs | 10 + .../new-signed-document-instant.mjs | 67 +---- .../test-event.mjs | 9 + 13 files changed, 344 insertions(+), 422 deletions(-) delete mode 100644 components/agrello/actions/create-document-from-template/create-document-from-template.mjs delete mode 100644 components/agrello/actions/upload-document/upload-document.mjs create mode 100644 components/agrello/common/utils.mjs create mode 100644 components/agrello/sources/common/base.mjs create mode 100644 components/agrello/sources/new-document/test-event.mjs create mode 100644 components/agrello/sources/new-signature-instant/test-event.mjs create mode 100644 components/agrello/sources/new-signed-document-instant/test-event.mjs diff --git a/components/agrello/actions/create-document-from-template/create-document-from-template.mjs b/components/agrello/actions/create-document-from-template/create-document-from-template.mjs deleted file mode 100644 index ea79ba74000e8..0000000000000 --- a/components/agrello/actions/create-document-from-template/create-document-from-template.mjs +++ /dev/null @@ -1,83 +0,0 @@ -import agrello from "../../agrello.app.mjs"; -import { axios } from "@pipedream/platform"; - -export default { - key: "agrello-create-document-from-template", - name: "Create Document from Template", - description: "Creates a new document in Agrello, invites participants, and fills file variables. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", - version: "0.0.{{ts}}", - type: "action", - props: { - agrello, - folderId: { - propDefinition: [ - agrello, - "folderId", - ], - }, - name: { - type: "string", - label: "Document Name", - description: "The name of the document", - }, - outputType: { - type: "string", - label: "Output Type", - description: "The output type of the document", - options: [ - "pdf", - "asice", - "zip", - ], - }, - variables: { - type: "object", - label: "Variables", - description: "The variables for the document", - }, - signers: { - type: "string[]", - label: "Signers", - description: "The signers of the document", - }, - viewers: { - type: "string[]", - label: "Viewers", - description: "The viewers of the document", - }, - immediatePublish: { - type: "boolean", - label: "Immediate Publish", - description: "Whether to publish the document immediately", - }, - metadata: { - type: "object", - label: "Metadata", - description: "The metadata for the document", - }, - templateId: { - propDefinition: [ - agrello, - "templateId", - ], - optional: true, - }, - }, - async run({ $ }) { - const data = { - folderId: this.folderId, - name: this.name, - outputType: this.outputType, - variables: this.variables, - signers: this.signers, - viewers: this.viewers, - immediatePublish: this.immediatePublish, - metadata: this.metadata, - templateId: this.templateId, - }; - - const response = await this.agrello.createDocument(data); - $.export("$summary", `Successfully created document with ID ${response.id}`); - return response; - }, -}; diff --git a/components/agrello/actions/get-document/get-document.mjs b/components/agrello/actions/get-document/get-document.mjs index 45f95f00e7b31..918475503069a 100644 --- a/components/agrello/actions/get-document/get-document.mjs +++ b/components/agrello/actions/get-document/get-document.mjs @@ -1,23 +1,32 @@ import agrello from "../../agrello.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "agrello-get-document", name: "Get Document", description: "Get a document in Agrello. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { agrello, + folderId: { + propDefinition: [ + agrello, + "folderId", + ], + }, documentId: { propDefinition: [ agrello, "documentId", + ({ folderId }) => ({ + folderId, + }), ], }, }, async run({ $ }) { const response = await this.agrello.getDocument({ + $, documentId: this.documentId, }); $.export("$summary", `Successfully retrieved document with ID ${this.documentId}`); diff --git a/components/agrello/actions/upload-document/upload-document.mjs b/components/agrello/actions/upload-document/upload-document.mjs deleted file mode 100644 index 07f8b447cc629..0000000000000 --- a/components/agrello/actions/upload-document/upload-document.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import agrello from "../../agrello.app.mjs"; -import { axios } from "@pipedream/platform"; - -export default { - key: "agrello-upload-document", - name: "Upload Document", - description: "Uploads a document to Agrello. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", - version: "0.0.{{ts}}", - type: "action", - props: { - agrello, - folderId: { - propDefinition: [ - agrello, - "folderId", - ], - }, - file: { - propDefinition: [ - agrello, - "file", - ], - }, - }, - async run({ $ }) { - const response = await this.agrello.uploadDocument({ - folderId: this.folderId, - file: this.file, - }); - - $.export("$summary", `Successfully uploaded document to folder ID ${this.folderId}`); - return response; - }, -}; diff --git a/components/agrello/agrello.app.mjs b/components/agrello/agrello.app.mjs index 047150f74713d..a12c7c07fdd1c 100644 --- a/components/agrello/agrello.app.mjs +++ b/components/agrello/agrello.app.mjs @@ -8,177 +8,137 @@ export default { type: "string", label: "Folder ID", description: "The ID of the folder", - async options() { - const folders = await this.listFolders(); - return folders.map((folder) => ({ - label: folder.name, - value: folder.id, - })); + async options({ page }) { + return await this.listFolders({ + params: { + page, + }, + }); }, }, documentId: { type: "string", label: "Document ID", description: "The ID of the document", - async options() { - const documents = await this.listDocuments(); - return documents.map((document) => ({ - label: document.name, - value: document.id, - })); - }, - }, - templateId: { - type: "string", - label: "Template ID", - description: "The ID of the template", - optional: true, - async options() { - const templates = await this.listTemplates(); - return templates.map((template) => ({ - label: template.name, - value: template.id, + async options({ + folderId, page, + }) { + const { content } = await this.listDocuments({ + folderId, + params: { + page, + }, + }); + return content.map(({ + id: value, name: label, + }) => ({ + label, + value, })); }, }, - file: { - type: "string", - label: "File", - description: "The file to upload", - }, - name: { - type: "string", - label: "Document Name", - description: "The name of the document", - }, - outputType: { - type: "string", - label: "Output Type", - description: "The output type of the document", - options: [ - "pdf", - "asice", - "zip", - ], - }, - variables: { - type: "object", - label: "Variables", - description: "The variables for the document", - }, - signers: { - type: "string[]", - label: "Signers", - description: "The signers of the document", - }, - viewers: { - type: "string[]", - label: "Viewers", - description: "The viewers of the document", - }, - immediatePublish: { - type: "boolean", - label: "Immediate Publish", - description: "Whether to publish the document immediately", - }, - metadata: { - type: "object", - label: "Metadata", - description: "The metadata for the document", - }, }, methods: { _baseUrl() { - return "https://api.agrello.io"; + return "https://api.agrello.io/public/v3"; }, - async _makeRequest(opts = {}) { - const { - $ = this, - method = "GET", - path = "/", - headers, - ...otherOpts - } = opts; + _headers(headers = {}) { + return { + ...headers, + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }; + }, + _makeRequest({ + $ = this, path, headers, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - Authorization: `Bearer ${this.$auth.oauth_access_token}`, - }, + headers: this._headers(headers), + ...opts, }); }, async listFolders() { - return this._makeRequest({ - path: "/v3/folders", - }); - }, - async listDocuments() { - return this._makeRequest({ - path: "/v3/documents", + const { content } = await this._makeRequest({ + path: "/folders", }); + + const folders = []; + for (const parent of content) { + folders.push({ + label: `${parent.name}`, + value: parent.id, + }); + folders.push(...await this.getSubFolders(parent.name, parent.id)); + } + + return folders; + }, - async listTemplates() { - return this._makeRequest({ - path: "/v3/templates", + async getSubFolders(parentName, parentId) { + const folders = []; + const { subspaces } = await this._makeRequest({ + path: `/folders/${parentId}/folders`, }); + for (const folder of subspaces) { + const label = `${parentName} - ${folder.name}`; + folders.push({ + label, + value: folder.id, + }); + folders.push(...await this.getSubFolders(label, folder.id)); + } + return folders; }, - async uploadDocument({ - folderId, file, + listDocuments({ + folderId, ...opts }) { - const formData = new FormData(); - formData.append("file", file); return this._makeRequest({ - method: "POST", - path: `/folders/${folderId}/documents`, - data: formData, - headers: { - "Content-Type": "multipart/form-data", - }, + path: `/folders/${folderId}/containers`, + ...opts, }); }, - async getDocument({ documentId }) { + getDocument({ documentId }) { return this._makeRequest({ - path: `/documents/${documentId}`, + path: `/containers/${documentId}`, }); }, - async createDocument({ - folderId, - name, - outputType, - variables, - signers, - viewers, - immediatePublish, - metadata, - templateId, - }) { - const data = { - folderId, - name, - outputType, - variables, - signers, - viewers, - immediatePublish, - metadata, - templateId, - }; + createWebhook(opts = {}) { return this._makeRequest({ method: "POST", - path: "/documents", - data, + path: "/webhooks", + ...opts, }); }, - async emitDocumentSignatureAdded() { - // Implementation to emit event when a signature is added to a document - }, - async emitDocumentSigned() { - // Implementation to emit event when a document is signed by all parties + deleteWebhook(hookId) { + return this._makeRequest({ + method: "DELETE", + path: `/webhooks/${hookId}`, + }); }, - async emitUserAddedDocumentToFolder({ folderId }) { - // Implementation to emit event when a user adds a document to a specific folder + async *paginate({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + let page = 0; + + do { + params.page = page++; + const { content } = await fn({ + params, + ...opts, + }); + for (const d of content) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + hasMore = content.length; + + } while (hasMore); }, }, }; diff --git a/components/agrello/common/utils.mjs b/components/agrello/common/utils.mjs new file mode 100644 index 0000000000000..0cd1a12b6a4ba --- /dev/null +++ b/components/agrello/common/utils.mjs @@ -0,0 +1,31 @@ +export const checkTmp = (filename) => { + if (!filename.startsWith("/tmp")) { + return `/tmp/${filename}`; + } + return filename; +}; + +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/agrello/package.json b/components/agrello/package.json index 319ca1beb0bbe..ad8b43dc433d7 100644 --- a/components/agrello/package.json +++ b/components/agrello/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/agrello", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Agrello Components", "main": "agrello.app.mjs", "keywords": [ @@ -11,5 +11,9 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.1" } } + diff --git a/components/agrello/sources/common/base.mjs b/components/agrello/sources/common/base.mjs new file mode 100644 index 0000000000000..82aa089f5ecef --- /dev/null +++ b/components/agrello/sources/common/base.mjs @@ -0,0 +1,44 @@ +import agrello from "../../agrello.app.mjs"; + +export default { + props: { + agrello, + http: { + type: "$.interface.http", + customResponse: false, + }, + db: "$.service.db", + }, + methods: { + _setHookId(hookId) { + this.db.set("webhookId", hookId); + }, + _getHookId() { + return this.db.get("webhookId"); + }, + }, + hooks: { + async activate() { + const data = await this.agrello.createWebhook({ + data: { + event: this.getEvent(), + url: this.http.endpoint, + }, + }); + + this._setHookId(data.id); + }, + async deactivate() { + const webhookId = this._getHookId(); + await this.agrello.deleteWebhook(webhookId); + }, + }, + async run({ body: { event } }) { + const ts = Date.parse(new Date()); + this.$emit(event, { + id: `${event.containerId}-${ts}`, + summary: this.getSummary(event), + ts: ts, + }); + }, +}; diff --git a/components/agrello/sources/new-document/new-document.mjs b/components/agrello/sources/new-document/new-document.mjs index 738bc42f62c81..d90003afb00f4 100644 --- a/components/agrello/sources/new-document/new-document.mjs +++ b/components/agrello/sources/new-document/new-document.mjs @@ -1,5 +1,6 @@ -import { axios } from "@pipedream/platform"; +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; import agrello from "../../agrello.app.mjs"; +import sampleEmit from "./test-event.mjs"; export default { key: "agrello-new-document", @@ -14,7 +15,7 @@ export default { timer: { type: "$.interface.timer", default: { - intervalSeconds: 60 * 15, // Default to 15 minutes + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, }, }, folderId: { @@ -25,49 +26,53 @@ export default { }, }, methods: { - _getLastDocumentId() { - return this.db.get("lastDocumentId"); + _getLastDate() { + return this.db.get("lastDate") || 0; }, - _setLastDocumentId(id) { - return this.db.set("lastDocumentId", id); + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); }, - async _getDocumentsInFolder(folderId) { - const documents = await this.agrello.listDocuments(); - return documents.filter((doc) => doc.folderId === folderId); + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + + const response = this.agrello.paginate({ + fn: this.agrello.listDocuments, + folderId: this.folderId, + params: { + sort: "createdAt,DESC", + }, + maxResults, + }); + + let responseArray = []; + for await (const item of response) { + if (Date.parse(item.createdAt) <= lastDate) break; + responseArray.push(item); + } + + if (responseArray.length) { + if (maxResults && (responseArray.length > maxResults)) { + responseArray.length = maxResults; + } + this._setLastDate(Date.parse(responseArray[0].createdAt)); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: item.id, + summary: `New Document: ${item.name}`, + ts: Date.parse(item.createdAt), + }); + } }, }, hooks: { async deploy() { - const documents = await this._getDocumentsInFolder(this.folderId); - documents.slice(0, 50).forEach((doc) => this.$emit(doc, { - id: doc.id, - summary: `New Document: ${doc.name}`, - ts: Date.parse(doc.createdAt), - })); - if (documents.length > 0) { - this._setLastDocumentId(documents[0].id); - } - }, - async activate() { - // Add any activation logic here if needed - }, - async deactivate() { - // Add any deactivation logic here if needed + await this.emitEvent(25); }, }, async run() { - const lastDocumentId = this._getLastDocumentId(); - const documents = await this._getDocumentsInFolder(this.folderId); - const newDocuments = documents.filter((doc) => doc.id > lastDocumentId); - - newDocuments.forEach((doc) => this.$emit(doc, { - id: doc.id, - summary: `New Document: ${doc.name}`, - ts: Date.parse(doc.createdAt), - })); - - if (newDocuments.length > 0) { - this._setLastDocumentId(newDocuments[0].id); - } + await this.emitEvent(); }, + sampleEmit, }; diff --git a/components/agrello/sources/new-document/test-event.mjs b/components/agrello/sources/new-document/test-event.mjs new file mode 100644 index 0000000000000..20483cbb724ee --- /dev/null +++ b/components/agrello/sources/new-document/test-event.mjs @@ -0,0 +1,70 @@ +export default { + "id": "string", + "name": "string", + "status": "string", + "outputType": "PDF", + "size": 0, + "createdAt": "2024-09-09T21:28:21.391Z", + "updatedAt": "2024-09-09T21:28:21.391Z", + "parties": [ + { + "id": "string", + "createdAt": "2024-09-09T21:28:21.391Z", + "updatedAt": "2024-09-09T21:28:21.391Z", + "role": "VIEWER", + "identityId": "string", + "username": "string" + } + ], + "invitations": [ + { + "id": "string", + "createdAt": "2024-09-09T21:28:21.391Z", + "email": "string", + "expiresAt": "2024-09-09T21:28:21.391Z", + "role": "VIEWER" + } + ], + "files": [ + { + "id": "string", + "name": "string", + "mimeType": "string", + "size": 0, + "createdAt": "2024-09-09T21:28:21.391Z", + "updatedAt": "2024-09-09T21:28:21.391Z", + "variables": [ + { + "id": "string", + "name": "string", + "type": "TEXT", + "value": "string" + } + ] + } + ], + "signatures": [ + { + "id": "string", + "identityId": "string", + "username": "string", + "certificate": "string", + "certificateHash": "string", + "signature": "string", + "visualSignatureUrl": "string", + "contentHash": "string", + "signingTimestamp": "2024-09-09T21:28:21.391Z", + "type": "BASIC", + "signingMethod": "BARE", + "signatureProvider": "AGRELLO_ID", + "displayName": "string" + } + ], + "folderId": "string", + "workspaceId": "string", + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + } +} \ No newline at end of file diff --git a/components/agrello/sources/new-signature-instant/new-signature-instant.mjs b/components/agrello/sources/new-signature-instant/new-signature-instant.mjs index a2c9486c5ae69..33896240ccd52 100644 --- a/components/agrello/sources/new-signature-instant/new-signature-instant.mjs +++ b/components/agrello/sources/new-signature-instant/new-signature-instant.mjs @@ -1,84 +1,22 @@ -import agrello from "../../agrello.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: "agrello-new-signature-instant", - name: "New Signature Added to Document", - description: "Emit new event when a signature is added to a document. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", - version: "0.0.{{ts}}", + name: "New Signature Added to Document (Instant)", + description: "Emit new event when a signature is added to a container.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - agrello: { - type: "app", - app: "agrello", - }, - http: { - type: "$.interface.http", - customResponse: true, - }, - db: "$.service.db", - }, methods: { - _getWebhookId() { - return this.db.get("webhookId"); - }, - _setWebhookId(id) { - this.db.set("webhookId", id); - }, - }, - hooks: { - async deploy() { - const documents = await this.agrello.listDocuments(); - for (const document of documents) { - const signatures = document.signatures || []; - for (const signature of signatures) { - this.$emit(signature, { - id: signature.id, - summary: `New signature added to document: ${document.name}`, - ts: Date.parse(signature.timestamp), - }); - } - } + ...common.methods, + getEvent() { + return "DOCUMENT_SIGNATURE_ADDED"; }, - async activate() { - const webhookId = await this.agrello.createWebhook({ - url: this.http.endpoint, - event: "document_signature_added", - }); - this._setWebhookId(webhookId); + getSummary(event) { + return `New signature added to container with Id: ${event.containerId}`; }, - async deactivate() { - const webhookId = this._getWebhookId(); - if (webhookId) { - await this.agrello.deleteWebhook(webhookId); - } - }, - }, - async run(event) { - const computedSignature = crypto - .createHmac("sha256", this.agrello.$auth.secret) - .update(event.body) - .digest("base64"); - - if (computedSignature !== event.headers["x-agrello-signature"]) { - this.http.respond({ - status: 401, - body: "Unauthorized", - }); - return; - } - - this.$emit(event.body, { - id: event.body.id, - summary: `New signature added to document ${event.body.documentId}`, - ts: Date.parse(event.body.timestamp), - }); - - this.http.respond({ - status: 200, - body: "OK", - }); }, + sampleEmit, }; diff --git a/components/agrello/sources/new-signature-instant/test-event.mjs b/components/agrello/sources/new-signature-instant/test-event.mjs new file mode 100644 index 0000000000000..63e08339a8846 --- /dev/null +++ b/components/agrello/sources/new-signature-instant/test-event.mjs @@ -0,0 +1,10 @@ +export default { + "containerId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "ownerId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "userId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "username": "email@test.com", + "spaceId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "spaceOwnerId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "workspaceId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "workspaceOwnerId": "068e7102-3565-4591-bf01-71f74e91dd1e" +} \ No newline at end of file diff --git a/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs b/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs index 9683a7f575216..ead58e6e9f71d 100644 --- a/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs +++ b/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs @@ -1,63 +1,22 @@ -import agrello from "../../agrello.app.mjs"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "agrello-new-signed-document-instant", - name: "New Signed Document Instant", - description: "Emit new event when a given document is signed by all parties. [See the documentation](https://api.agrello.io/public/webjars/swagger-ui/index.html)", - version: "0.0.{{ts}}", + name: "New Signed Document (Instant)", + description: "Emit new event when a given document is signed by all parties.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - agrello: { - type: "app", - app: "agrello", + methods: { + ...common.methods, + getEvent() { + return "DOCUMENT_SIGNED"; }, - http: { - type: "$.interface.http", - customResponse: false, + getSummary(event) { + return `Document signed: ${event.name}`; }, - db: "$.service.db", - }, - hooks: { - async deploy() { - const documents = await this.agrello.listDocuments(); - const signedDocuments = documents.filter((doc) => doc.status === "signed"); - for (const doc of signedDocuments.slice(0, 50)) { - this.$emit(doc, { - id: doc.id, - summary: `Document signed: ${doc.name}`, - ts: Date.parse(doc.updatedAt), - }); - } - }, - async activate() { - const webhookId = await this.agrello.createWebhook({ - event: "document.signed", - url: this.http.endpoint, - }); - this.db.set("webhookId", webhookId); - }, - async deactivate() { - const webhookId = this.db.get("webhookId"); - if (webhookId) { - await this.agrello.deleteWebhook({ - id: webhookId, - }); - } - }, - }, - async run(event) { - const { documentId } = event.body; - const document = await this.agrello.getDocument({ - documentId, - }); - if (document.status === "signed") { - this.$emit(document, { - id: document.id, - summary: `Document signed: ${document.name}`, - ts: Date.parse(document.updatedAt), - }); - } }, + sampleEmit, }; diff --git a/components/agrello/sources/new-signed-document-instant/test-event.mjs b/components/agrello/sources/new-signed-document-instant/test-event.mjs new file mode 100644 index 0000000000000..f30c2f5216387 --- /dev/null +++ b/components/agrello/sources/new-signed-document-instant/test-event.mjs @@ -0,0 +1,9 @@ +export default { + "containerId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "userId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "signerCount": 1, + "spaceId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "spaceOwnerId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "workspaceId": "068e7102-3565-4591-bf01-71f74e91dd1e", + "workspaceOwnerId": "068e7102-3565-4591-bf01-71f74e91dd1e" +} \ No newline at end of file From a61dd11e16dcd856bf707db0fa11e8a70a5413ee Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 9 Sep 2024 18:56:53 -0300 Subject: [PATCH 3/5] pnpm update --- pnpm-lock.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b6473fbdb843..2acc65f6a9fa4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -313,7 +313,10 @@ importers: specifiers: {} components/agrello: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.1 + dependencies: + '@pipedream/platform': 3.0.1 components/ahrefs: specifiers: {} From 548a429cd2b0030c019595728043b74cbdcb0ba7 Mon Sep 17 00:00:00 2001 From: Leo Vu Date: Fri, 13 Sep 2024 11:02:57 +0700 Subject: [PATCH 4/5] Fix Summary --- .../new-signed-document-instant/new-signed-document-instant.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs b/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs index ead58e6e9f71d..a53415dccb37d 100644 --- a/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs +++ b/components/agrello/sources/new-signed-document-instant/new-signed-document-instant.mjs @@ -15,7 +15,7 @@ export default { return "DOCUMENT_SIGNED"; }, getSummary(event) { - return `Document signed: ${event.name}`; + return `Document signed: ${event.containerId}`; }, }, sampleEmit, From 54c2ba7668244dccc398ec9f656d8e766d2acc64 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Fri, 13 Sep 2024 12:26:59 -0300 Subject: [PATCH 5/5] Update components/agrello/sources/new-signature-instant/new-signature-instant.mjs Co-authored-by: Leo Vu --- .../sources/new-signature-instant/new-signature-instant.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/agrello/sources/new-signature-instant/new-signature-instant.mjs b/components/agrello/sources/new-signature-instant/new-signature-instant.mjs index 33896240ccd52..43f156fbc87c3 100644 --- a/components/agrello/sources/new-signature-instant/new-signature-instant.mjs +++ b/components/agrello/sources/new-signature-instant/new-signature-instant.mjs @@ -15,7 +15,7 @@ export default { return "DOCUMENT_SIGNATURE_ADDED"; }, getSummary(event) { - return `New signature added to container with Id: ${event.containerId}`; + return `New signature added to container: ${event.containerId}`; }, }, sampleEmit,