diff --git a/components/freshdesk/actions/add-note-to-ticket/add-note-to-ticket.mjs b/components/freshdesk/actions/add-note-to-ticket/add-note-to-ticket.mjs new file mode 100644 index 0000000000000..f8fa1cc684abd --- /dev/null +++ b/components/freshdesk/actions/add-note-to-ticket/add-note-to-ticket.mjs @@ -0,0 +1,104 @@ +import freshdesk from "../../freshdesk.app.mjs"; +import { ConfigurationError } from "@pipedream/platform"; + +export default { + key: "freshdesk-add-note-to-ticket", + name: "Add Note to Ticket", + description: "Add a note or conversation to an existing ticket. [See the documentation](https://developers.freshdesk.com/api/#add_note_to_a_ticket).", + version: "0.0.1", + type: "action", + props: { + freshdesk, + ticketId: { + propDefinition: [ + freshdesk, + "ticketId", + ], + }, + body: { + type: "string", + label: "Note Body", + description: "Content of the note in HTML format", + }, + private: { + type: "boolean", + label: "Private Note", + description: "Set to true if the note is private (internal)", + default: false, + }, + incoming: { + type: "boolean", + label: "Incoming", + description: "Set to true if the note should be marked as incoming (false for outgoing)", + default: false, + optional: true, + }, + user_id: { + propDefinition: [ + freshdesk, + "agentId", + ], + label: "User ID", + description: "ID of the user creating the note (defaults to the API user)", + optional: true, + }, + notify_emails: { + type: "string[]", + label: "Notify Emails", + description: "Array of email addresses to notify about this note", + optional: true, + }, + }, + async run({ $ }) { + const { + freshdesk, + ticketId, + body, + private: isPrivate, + incoming, + user_id, + notify_emails, + } = this; + + if (!body || !body.trim()) { + throw new ConfigurationError("Note body cannot be empty"); + } + + const ticketName = await freshdesk.getTicketName(ticketId) || "Unknown Ticket"; + + const data = { + body, + private: isPrivate, + }; + + if (incoming !== undefined) { + data.incoming = incoming; + } + + if (user_id) { + const userId = Number(user_id); + if (isNaN(userId)) { + throw new ConfigurationError("User ID must be a valid number"); + } + data.user_id = userId; + } + + if (notify_emails && notify_emails.length > 0) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + const invalidEmails = notify_emails.filter((email) => !emailRegex.test(email)); + if (invalidEmails.length > 0) { + throw new ConfigurationError(`Invalid email addresses: ${invalidEmails.join(", ")}`); + } + data.notify_emails = notify_emails; + } + + const response = await freshdesk.addNoteToTicket({ + $, + ticketId: Number(ticketId), + data, + }); + + $.export("$summary", `Note added to ticket "${ticketName}" (ID: ${ticketId})`); + return response; + }, +}; diff --git a/components/freshdesk/actions/update-ticket/update-ticket.mjs b/components/freshdesk/actions/update-ticket/update-ticket.mjs index f1dd5c8c1e7df..2822463ce2aea 100644 --- a/components/freshdesk/actions/update-ticket/update-ticket.mjs +++ b/components/freshdesk/actions/update-ticket/update-ticket.mjs @@ -100,7 +100,7 @@ export default { const data = removeNullEntries(fields); - const ticketName = await freshdesk.getTicketName(ticketId); + const ticketName = await freshdesk.getTicketName(ticketId) || "Unknown Ticket"; if (!Object.keys(data).length) { throw new Error("Please provide at least one field to update."); diff --git a/components/freshdesk/freshdesk.app.mjs b/components/freshdesk/freshdesk.app.mjs index fe405b1c37151..8d856e11b80b1 100644 --- a/components/freshdesk/freshdesk.app.mjs +++ b/components/freshdesk/freshdesk.app.mjs @@ -251,10 +251,17 @@ export default { }); }, async getTicketName(ticketId) { - const ticket = await this.getTicket({ - ticketId, - }); - return ticket.subject; + try { + const ticket = await this.getTicket({ + ticketId, + }); + return ticket.subject; + } catch (error) { + if (error.response?.status === 404) { + return null; + } + throw error; + } }, parseIfJSONString(input) { if (typeof input === "string") { @@ -266,5 +273,28 @@ export default { } return input; }, + /** + * Add a note to a Freshdesk ticket + * @param {Object} options - The options object + * @param {number} options.ticketId - The ID of the ticket to add the note to + * @param {Object} options.data - The note data object + * @param {string} options.data.body - Content of the note in HTML format + * @param {boolean} [options.data.private=false] - Whether the note is private + * @param {boolean} [options.data.incoming] - Whether the note is incoming + * @param {number} [options.data.user_id] - ID of the user creating the note + * @param {string[]} [options.data.notify_emails] - Array of email addresses to notify + * @param {...*} args - Additional arguments passed to _makeRequest + * @returns {Promise} The API response containing the created note + */ + async addNoteToTicket({ + ticketId, data, ...args + }) { + return this._makeRequest({ + url: `/tickets/${ticketId}/notes`, + method: "post", + data, + ...args, + }); + }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b38fc416d13e0..c93473523dcfd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9840,8 +9840,7 @@ importers: components/paypro: {} - components/payrexx: - specifiers: {} + components/payrexx: {} components/paystack: dependencies: @@ -15877,14 +15876,6 @@ importers: specifier: ^6.0.0 version: 6.2.0 - modelcontextprotocol/node_modules2/@modelcontextprotocol/sdk/dist/cjs: {} - - modelcontextprotocol/node_modules2/@modelcontextprotocol/sdk/dist/esm: {} - - modelcontextprotocol/node_modules2/zod-to-json-schema/dist/cjs: {} - - modelcontextprotocol/node_modules2/zod-to-json-schema/dist/esm: {} - packages/ai: dependencies: '@pipedream/sdk':