From 6e1a345ddb5996ae667f405ccc9e8f26717e1962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dafydd=20Ll=C5=B7r=20Pearson?= Date: Tue, 14 Nov 2023 15:07:49 +0000 Subject: [PATCH] feat: Document download-application endpoint --- api.planx.uk/modules/misc/controller.ts | 39 +++++++++++++++++++++++++ api.planx.uk/modules/misc/docs.yaml | 36 +++++++++++++++++++++++ api.planx.uk/modules/misc/routes.ts | 13 ++++++++- api.planx.uk/server.ts | 20 ------------- 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/api.planx.uk/modules/misc/controller.ts b/api.planx.uk/modules/misc/controller.ts index cc1addd30f..dfe6437827 100644 --- a/api.planx.uk/modules/misc/controller.ts +++ b/api.planx.uk/modules/misc/controller.ts @@ -2,6 +2,9 @@ import { RequestHandler } from "express"; import { getClient } from "../../client"; import { userContext } from "../auth/middleware"; import { ServerError } from "../../errors"; +import { stringify } from "csv-stringify"; +import { z } from "zod"; +import { ValidatedRequestHandler } from "../../shared/middleware/validate"; export const getLoggedInUserDetails: RequestHandler = async ( _req, @@ -33,3 +36,39 @@ export const getLoggedInUserDetails: RequestHandler = async ( export const healthCheck: RequestHandler = (_req, res) => res.json({ hello: "world" }); + +export const downloadApplicationSchema = z.object({ + body: z.object({ + data: z.array( + z.object({ + question: z.string(), + responses: z.any(), + metadata: z.any().optional(), + }), + ), + }), +}); + +export type DownloadApplicationController = ValidatedRequestHandler< + typeof downloadApplicationSchema, + string | Record<"message", string> +>; + +/** + * Allows an applicant to download their application data on the Confirmation page + */ +export const downloadApplicationController: DownloadApplicationController = + async (req, res, next) => { + const { data } = res.locals.parsedReq.body; + + try { + // build a CSV and stream the response + stringify(data, { + columns: ["question", "responses", "metadata"], + header: true, + }).pipe(res); + res.header("Content-type", "text/csv"); + } catch (err) { + next(err); + } + }; diff --git a/api.planx.uk/modules/misc/docs.yaml b/api.planx.uk/modules/misc/docs.yaml index 3d28bd523d..d077513201 100644 --- a/api.planx.uk/modules/misc/docs.yaml +++ b/api.planx.uk/modules/misc/docs.yaml @@ -79,3 +79,39 @@ paths: example: "teamEditor" "401": $ref: "#/components/responses/Unauthorised" + /download-application: + post: + summary: Download application + description: Allows an applicant to download their application data on the Confirmation page + tags: + - misc + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + data: + required: true + type: array + items: + type: object + properties: + question: + type: string + required: true + responses: + type: any + required: true + metadata: + type: any + required: false + responses: + "200": + content: + text/csv: + schema: + type: string + "500": + $ref: "#/components/responses/ErrorMessage" diff --git a/api.planx.uk/modules/misc/routes.ts b/api.planx.uk/modules/misc/routes.ts index 75d202e32e..28fa5d89ce 100644 --- a/api.planx.uk/modules/misc/routes.ts +++ b/api.planx.uk/modules/misc/routes.ts @@ -1,10 +1,21 @@ +import { validate } from "./../../shared/middleware/validate"; import { Router } from "express"; import { useLoginAuth } from "../auth/middleware"; -import { getLoggedInUserDetails, healthCheck } from "./controller"; +import { + downloadApplicationController, + downloadApplicationSchema, + getLoggedInUserDetails, + healthCheck, +} from "./controller"; const router = Router(); router.get("/", healthCheck); router.get("/me", useLoginAuth, getLoggedInUserDetails); +router.post( + "/download-application", + validate(downloadApplicationSchema), + downloadApplicationController, +); export default router; diff --git a/api.planx.uk/server.ts b/api.planx.uk/server.ts index 88e608363a..3ddbb78f43 100644 --- a/api.planx.uk/server.ts +++ b/api.planx.uk/server.ts @@ -306,26 +306,6 @@ app.get("/flows/:flowId/download-schema", async (req, res, next) => { } }); -// allows an applicant to download their application data on the Confirmation page -app.post("/download-application", async (req, res, next) => { - if (!req.body) { - res.send({ - message: "Missing application `data` to download", - }); - } - - try { - // build a CSV and stream the response - stringify(req.body, { - columns: ["question", "responses", "metadata"], - header: true, - }).pipe(res); - res.header("Content-type", "text/csv"); - } catch (err) { - next(err); - } -}); - app.post( "/private-file-upload", multer().single("file"),