diff --git a/components/freshdesk/actions/update-ticket/update-ticket.mjs b/components/freshdesk/actions/update-ticket/update-ticket.mjs index f1dd5c8c1e7df..641b0e3d8d047 100644 --- a/components/freshdesk/actions/update-ticket/update-ticket.mjs +++ b/components/freshdesk/actions/update-ticket/update-ticket.mjs @@ -5,7 +5,7 @@ export default { key: "freshdesk-update-ticket", name: "Update a Ticket", description: "Update status, priority, subject, description, agent, group, etc. [See the documentation](https://developers.freshdesk.com/api/#update_ticket).", - version: "0.0.1", + version: "0.0.2", type: "action", props: { freshdesk, @@ -71,6 +71,19 @@ export default { description: "Used when creating a contact with phone but no email.", optional: true, }, + internalNote: { + type: "boolean", + label: "Internal note (private)", + description: "If enabled, the comment will be added as an internal note (not visible to requester).", + optional: true, + default: false, + }, + noteBody: { + type: "string", + label: "Note Body", + description: "The content of the internal note to add.", + optional: true, + }, type: { type: "string", label: "Type", @@ -95,6 +108,8 @@ export default { const { freshdesk, ticketId, + internalNote, + noteBody, ...fields } = this; @@ -102,21 +117,35 @@ export default { const ticketName = await freshdesk.getTicketName(ticketId); + if (internalNote && noteBody) { + const response = await freshdesk._makeRequest({ + $, + method: "POST", + url: `/tickets/${ticketId}/notes`, + data: { + body: noteBody, + private: true, + }, + }); + + $.export("$summary", `Internal note added to ticket "${ticketName}" (ID: ${ticketId})`); + return response; + } + if (!Object.keys(data).length) { throw new Error("Please provide at least one field to update."); } - + if (data.custom_fields) freshdesk.parseIfJSONString(data.custom_fields); - + const response = await freshdesk._makeRequest({ $, method: "PUT", url: `/tickets/${ticketId}`, data, }); - + $.export("$summary", `Ticket "${ticketName}" (ID: ${this.ticketId}) updated successfully`); return response; }, -}; - +} \ No newline at end of file diff --git a/components/gorgias_oauth/actions/create-ticket-message/create-ticket-message.mjs b/components/gorgias_oauth/actions/create-ticket-message/create-ticket-message.mjs index faaa171588977..b8dfb3ec7cf17 100644 --- a/components/gorgias_oauth/actions/create-ticket-message/create-ticket-message.mjs +++ b/components/gorgias_oauth/actions/create-ticket-message/create-ticket-message.mjs @@ -7,7 +7,7 @@ export default { key: "gorgias_oauth-create-ticket-message", name: "Create Ticket Message", description: "Create a message for a ticket in the Gorgias system. [See the documentation](https://developers.gorgias.com/reference/create-ticket-message)", - version: "0.0.2", + version: "0.0.3", type: "action", props: { gorgiasOauth, @@ -67,6 +67,15 @@ export default { label: "Message", description: "Message of the ticket. Accepts HTML", }, + channel: { + propDefinition: [ + gorgiasOauth, + "channel", + ], + optional: false, + default: "email", + reloadProps: true, + }, via: { propDefinition: [ gorgiasOauth, @@ -101,10 +110,11 @@ export default { }, }, additionalProps(props) { - props.toUser.hidden = this.fromAgent; - props.fromCustomer.hidden = this.fromAgent; - props.toCustomer.hidden = !this.fromAgent; - props.fromUser.hidden = !this.fromAgent; + const isInternalNote = this.channel === "internal-note"; + props.toUser.hidden = this.fromAgent || isInternalNote; + props.fromCustomer.hidden = this.fromAgent || isInternalNote; + props.toCustomer.hidden = !this.fromAgent || isInternalNote; + props.fromUser.hidden = !this.fromAgent || isInternalNote; return {}; }, methods: { @@ -147,6 +157,8 @@ export default { throw new ConfigurationError("Must enter both Attachment URL and Attachment File Name"); } + const isInternalNote = this.channel === "internal-note"; + let contentType, size; if (this.attachmentUrl) { ({ @@ -162,55 +174,64 @@ export default { ? this.toCustomer : this.toUser; - if (!fromId) { - throw new ConfigurationError(`"${this.fromAgent - ? "From User" - : "From Customer"}" is required when "From Agent" is set to \`${this.fromAgent}\``); - } - if (!toId) { - throw new ConfigurationError(`"${this.fromAgent - ? "To Customer" - : "To User"}" is required when "From Agent" is set to \`${this.fromAgent}\``); + // For internal notes, we don't need from/to validation + if (!isInternalNote) { + if (!fromId) { + throw new ConfigurationError(`"${this.fromAgent + ? "From User" + : "From Customer"}" is required when "From Agent" is set to \`${this.fromAgent}\``); + } + if (!toId) { + throw new ConfigurationError(`"${this.fromAgent + ? "To Customer" + : "To User"}" is required when "From Agent" is set to \`${this.fromAgent}\``); + } } - const response = await this.gorgiasOauth.createMessage({ - $, - ticketId: this.ticketId, - data: { - channel: "email", - source: { - from: { - address: await this.getEmail($, fromId, "from"), - }, - to: [ - { - address: await this.getEmail($, toId, "to"), - }, - ], + const messageData = { + channel: this.channel, + body_html: this.message, + via: this.via, + subject: this.subject, + from_agent: this.fromAgent, + sent_datetime: this.sentDatetime, + attachments: this.attachmentUrl && [ + { + url: this.attachmentUrl, + name: this.attachmentName, + content_type: contentType, + size, }, - body_html: this.message, - via: this.via, - subject: this.subject, - from_agent: this.fromAgent, - sent_datetime: this.sentDatetime, - attachments: this.attachmentUrl && [ + ], + }; + + // Only add source, sender, and receiver for non-internal notes + if (!isInternalNote) { + messageData.source = { + from: { + address: await this.getEmail($, fromId, "from"), + }, + to: [ { - url: this.attachmentUrl, - name: this.attachmentName, - content_type: contentType, - size, + address: await this.getEmail($, toId, "to"), }, ], - sender: { - id: fromId, - }, - receiver: { - id: toId, - }, - }, + }; + messageData.sender = { + id: fromId, + }; + messageData.receiver = { + id: toId, + }; + } + + const response = await this.gorgiasOauth.createMessage({ + $, + ticketId: this.ticketId, + data: messageData, }); - $.export("$summary", `Succesfully created ticket message with ID: ${response.id}`); + $.export("$summary", `Successfully created ${isInternalNote ? "internal note" : "ticket message"} with ID: ${response.id}`); return response; }, diff --git a/components/gorgias_oauth/package.json b/components/gorgias_oauth/package.json index ad3a6cef51a8a..52da9ee2878d8 100644 --- a/components/gorgias_oauth/package.json +++ b/components/gorgias_oauth/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/gorgias_oauth", - "version": "0.5.1", + "version": "0.5.2", "description": "Pipedream Gorgias OAuth Components", "main": "gorgias_oauth.app.mjs", "keywords": [ diff --git a/components/gorgias_oauth/sources/internal-note-created/internal-note-created.mjs b/components/gorgias_oauth/sources/internal-note-created/internal-note-created.mjs new file mode 100644 index 0000000000000..f57db8557be8c --- /dev/null +++ b/components/gorgias_oauth/sources/internal-note-created/internal-note-created.mjs @@ -0,0 +1,51 @@ +import constants from "../../common/constants.mjs"; +import base from "../common/base.mjs"; +import eventTypes from "../common/event-types.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...base, + key: "gorgias_oauth-internal-note-created", + name: "New Internal Note", + description: "Emit new event when an internal note is created on a ticket. [See the documentation](https://developers.gorgias.com/reference/the-event-object)", + version: "0.0.1", + type: "source", + props: { + ...base.props, + ticketId: { + propDefinition: [ + base.props.gorgias_oauth, + "ticketId", + ], + optional: true, + }, + sender: { + type: "string", + label: "Sender Email", + description: "Email address of the sender", + optional: true, + }, + }, + hooks: { + ...base.hooks, + deploy() {}, + }, + methods: { + ...base.methods, + getEventType() { + return eventTypes.TICKET_MESSAGE_CREATED; + }, + isRelevant(message) { + return message.channel === "internal-note" + && (!this.ticketId || message.ticket_id === this.ticketId) + && (!this.sender || message.sender.email === this.sender); + }, + async processEvent(event) { + const { message } = event; + if (this.isRelevant(message)) { + this.emitEvent(message); + } + }, + }, + sampleEmit, +}; \ No newline at end of file diff --git a/components/gorgias_oauth/sources/internal-note-created/test-event.mjs b/components/gorgias_oauth/sources/internal-note-created/test-event.mjs new file mode 100644 index 0000000000000..b6c243f2b4cf3 --- /dev/null +++ b/components/gorgias_oauth/sources/internal-note-created/test-event.mjs @@ -0,0 +1,43 @@ +export default { + id: 123456789, + created_datetime: "2024-01-15T10:30:00Z", + updated_datetime: "2024-01-15T10:30:00Z", + ticket_id: 98765, + channel: "internal-note", + via: "internal-note", + source: { + type: "internal-note", + from: { + address: "agent@company.com", + name: "Support Agent" + }, + to: [] + }, + sender: { + id: 456, + email: "agent@company.com", + name: "Support Agent" + }, + receiver: null, + body_html: "
This is an internal note about the customer's issue.
", + body_text: "This is an internal note about the customer's issue.", + subject: "Internal Note", + from_agent: true, + sent_datetime: "2024-01-15T10:30:00Z", + attachments: [], + public: false, + stripped_html: "This is an internal note about the customer's issue.
", + stripped_text: "This is an internal note about the customer's issue.", + stripped_signature: "", + message_id: "internal-note-123456789", + actions: [], + rule_id: null, + external_id: null, + tags: [], + integration_id: null, + last_sending_error: null, + opened_datetime: null, + clicked_datetime: null, + failed_datetime: null, + errors: [] +}; \ No newline at end of file