From 6ab395c66d3228160c0f7080320eec0817203a1b Mon Sep 17 00:00:00 2001 From: Dakota Dutko Date: Thu, 5 Sep 2024 13:56:51 -0400 Subject: [PATCH] Updates the change request functions to automatically close the corresponding zendesk ticket (#2546) --- app/lib/zendesk.server.ts | 29 ++++++++++- .../circulars._archive._index/route.tsx | 19 ++++--- app/routes/circulars/circulars.lib.ts | 1 + app/routes/circulars/circulars.server.ts | 49 ++++++++++--------- 4 files changed, 68 insertions(+), 30 deletions(-) diff --git a/app/lib/zendesk.server.ts b/app/lib/zendesk.server.ts index 65fb2d1bd..490c88778 100644 --- a/app/lib/zendesk.server.ts +++ b/app/lib/zendesk.server.ts @@ -43,6 +43,33 @@ export async function postZendeskRequest(request: ZendeskRequest) { if (!response.ok) { console.error(response) - throw new Error(`Reqeust failed with status ${response.status}`) + throw new Error(`Request failed with status ${response.status}`) + } + return await response.json() +} + +export async function closeZendeskTicket(ticketId: number) { + const response = await fetch( + `https://nasa-gcn.zendesk.com/api/v2/tickets/${ticketId}.json`, + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + ...getBasicAuthHeaders( + `${getEnvOrDie('ZENDESK_TOKEN_EMAIL')}/token`, + getEnvOrDie('ZENDESK_TOKEN') + ), + }, + body: JSON.stringify({ + ticket: { + status: 'solved', + }, + }), + } + ) + + if (!response.ok) { + console.error(response) + throw new Error(`Request failed with status ${response.status}`) } } diff --git a/app/routes/circulars._archive._index/route.tsx b/app/routes/circulars._archive._index/route.tsx index 76a55d40e..a40c79753 100644 --- a/app/routes/circulars._archive._index/route.tsx +++ b/app/routes/circulars._archive._index/route.tsx @@ -110,22 +110,27 @@ export async function action({ request }: ActionFunctionArgs) { if (!createdOnDate || !createdOn) throw new Response(null, { status: 400 }) + + const { + request: { id: zendeskTicketId }, + } = await postZendeskRequest({ + requester: { name: user.name, email: user.email }, + subject: `Change Request for Circular ${circularId}`, + comment: { + body: `${user.name} has requested an edit. Review at ${origin}/circulars`, + }, + }) + await createChangeRequest( { circularId: parseFloat(circularId), ...props, submitter, createdOn, + zendeskTicketId, }, user ) - await postZendeskRequest({ - requester: { name: user.name, email: user.email }, - subject: `Change Request for Circular ${circularId}`, - comment: { - body: `${user.name} has requested an edit. Review at ${origin}/circulars`, - }, - }) newCircular = null break case 'edit': diff --git a/app/routes/circulars/circulars.lib.ts b/app/routes/circulars/circulars.lib.ts index 77d8d2c64..a23c9a10e 100644 --- a/app/routes/circulars/circulars.lib.ts +++ b/app/routes/circulars/circulars.lib.ts @@ -39,6 +39,7 @@ export interface CircularChangeRequest extends CircularMetadata { format: CircularFormat submitter: string createdOn: number + zendeskTicketId: number } export interface CircularChangeRequestKeys { diff --git a/app/routes/circulars/circulars.server.ts b/app/routes/circulars/circulars.server.ts index 363c957a8..e855838de 100644 --- a/app/routes/circulars/circulars.server.ts +++ b/app/routes/circulars/circulars.server.ts @@ -33,6 +33,7 @@ import type { } from './circulars.lib' import { sendEmail } from '~/lib/email.server' import { feature, origin } from '~/lib/env.server' +import { closeZendeskTicket } from '~/lib/zendesk.server' // A type with certain keys required. type Require = Omit & Required> @@ -387,7 +388,7 @@ export async function createChangeRequest( | 'editedOn' | 'submitter' | 'createdOn' - > & { submitter?: string; createdOn?: number }, + > & { submitter?: string; createdOn?: number; zendeskTicketId: number }, user?: User ) { validateCircular(item) @@ -462,10 +463,9 @@ export async function deleteChangeRequest( { status: 403 } ) - const requestorEmail = (await getChangeRequest(circularId, requestorSub)) - .requestorEmail + const changeRequest = await getChangeRequest(circularId, requestorSub) + const requestorEmail = changeRequest.requestorEmail await deleteChangeRequestRaw(circularId, requestorSub) - await sendEmail({ to: [requestorEmail], fromName: 'GCN Circulars', @@ -527,27 +527,32 @@ export async function approveChangeRequest( const circular = await get(circularId) const autoincrementVersion = await getDynamoDBVersionAutoIncrement(circularId) - await autoincrementVersion.put({ - ...circular, - body: changeRequest.body, - subject: changeRequest.subject, - editedBy: `${formatAuthor(user)} on behalf of ${changeRequest.requestor}`, - editedOn: Date.now(), - format: changeRequest.format, - submitter: changeRequest.submitter, - createdOn: changeRequest.createdOn ?? circular.createdOn, // This is temporary while there are some requests without this property - }) + const promises = [ + autoincrementVersion.put({ + ...circular, + body: changeRequest.body, + subject: changeRequest.subject, + editedBy: `${formatAuthor(user)} on behalf of ${changeRequest.requestor}`, + editedOn: Date.now(), + format: changeRequest.format, + submitter: changeRequest.submitter, + createdOn: changeRequest.createdOn ?? circular.createdOn, // This is temporary while there are some requests without this property + }), + deleteChangeRequestRaw(circularId, requestorSub), + sendEmail({ + to: [changeRequest.requestorEmail], + fromName: 'GCN Circulars', + subject: 'GCN Circulars Change Request: Approved', + body: dedent`Your change request has been approved for GCN Circular ${changeRequest.circularId}. - await deleteChangeRequestRaw(circularId, requestorSub) + View the Circular at ${origin}/circulars/${changeRequest.circularId}`, + }), + ] - await sendEmail({ - to: [changeRequest.requestorEmail], - fromName: 'GCN Circulars', - subject: 'GCN Circulars Change Request: Approved', - body: dedent`Your change request has been approved for GCN Circular ${changeRequest.circularId}. + if (changeRequest.zendeskTicketId) + promises.push(closeZendeskTicket(changeRequest.zendeskTicketId)) - View the Circular at ${origin}/circulars/${changeRequest.circularId}`, - }) + await Promise.all(promises) } /**