Skip to content

Commit

Permalink
feat: Download flow schema
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr committed Nov 13, 2023
1 parent 1c58cec commit a984c15
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 47 deletions.
17 changes: 17 additions & 0 deletions api.planx.uk/modules/flows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,20 @@ paths:
$ref: "#/components/responses/ValidateAndDiff"
"500":
$ref: "#/components/responses/ErrorMessage"
/flows/{flowId}/download-schema:
post:
summary: Download flow schema
description: Download a CSV file representing the flow's schema
tags: ["flows"]
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/flowId"
responses:
"200":
content:
text/csv:
schema:
type: string
"500":
$ref: "#/components/responses/ErrorMessage"
41 changes: 41 additions & 0 deletions api.planx.uk/modules/flows/downloadSchema/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { z } from "zod";
import { ValidatedRequestHandler } from "../../../shared/middleware/validate";
import { stringify } from "csv-stringify";
import { getFlowSchema } from "./service";
import { ServerError } from "../../../errors";

interface DownloadFlowSchemaResponse {
message: string;
alteredNodes: Node[] | null;
description?: string;
}

export const downloadFlowSchema = z.object({
params: z.object({
flowId: z.string(),
}),
});

export type DownloadFlowSchemaController = ValidatedRequestHandler<
typeof downloadFlowSchema,
DownloadFlowSchemaResponse
>;

export const downloadFlowSchemaController: DownloadFlowSchemaController =
async (_res, res, next) => {
try {
const { flowId } = res.locals.parsedReq.params;
const flowSchema = await getFlowSchema(flowId);

// Build a CSV and stream it
stringify(flowSchema, { header: true }).pipe(res);
res.header("Content-type", "text/csv");
res.attachment(`${flowId}.csv`);
} catch (error) {
return next(
new ServerError({
message: `Failed to download flow schema: ${error}`,
}),
);
}
};
35 changes: 35 additions & 0 deletions api.planx.uk/modules/flows/downloadSchema/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { $public } from "../../../client";
import { gql } from "graphql-request";

interface FlowSchema {
node: string;
type: string;
text: string;
planx_variable: string;
}

export const getFlowSchema = async (flowId: string) => {
const { flowSchema } = await $public.client.request<{
flowSchema: FlowSchema[];
}>(
gql`
query ($flow_id: String!) {
flowSchema: get_flow_schema(args: { published_flow_id: $flow_id }) {
node
type
text
planx_variable
}
}
`,
{ flow_id: flowId },
);

if (!flowSchema.length) {
throw Error(
"Can't find a schema for this flow. Make sure it's published or try a different flow id.",
);
}

return flowSchema;
};
5 changes: 4 additions & 1 deletion api.planx.uk/modules/flows/publish/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Node } from "@opensystemslab/planx-core/types";
import { ValidatedRequestHandler } from "../../../shared/middleware/validate";
import { z } from "zod";
import { publishFlow } from "./service";
import { ServerError } from "../../../errors";

interface PublishFlowResponse {
message: string;
Expand Down Expand Up @@ -37,6 +38,8 @@ export const publishFlowController: PublishFlowController = async (
message: alteredNodes ? "Changes published" : "No new changes to publish",
});
} catch (error) {
return next(error);
return next(
new ServerError({ message: `Failed to publish flow: ${error}` }),
);
}
};
54 changes: 9 additions & 45 deletions api.planx.uk/modules/flows/routes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Router } from "express";
import { usePlatformAdminAuth, useTeamEditorAuth } from "../auth/middleware";
import { publishFlowController } from "./publish/controller";
import { $public } from "../../client";
import { gql } from "graphql-request";
import { stringify } from "csv-stringify";
import { copyFlowController, copyFlowSchema } from "./copyFlow/controller";
import { validate } from "../../shared/middleware/validate";
import {
Expand All @@ -20,6 +17,10 @@ import {
validateAndDiffSchema,
} from "./validate/controller";
import { publishFlowSchema } from "./publish/controller";
import {
downloadFlowSchema,
downloadFlowSchemaController,
} from "./downloadSchema/controller";
const router = Router();

router.post(
Expand Down Expand Up @@ -64,47 +65,10 @@ router.post(
validateAndDiffFlowController,
);

interface FlowSchema {
node: string;
type: string;
text: string;
planx_variable: string;
}

router.get("/:flowId/download-schema", async (req, res, next) => {
try {
const { flowSchema } = await $public.client.request<{
flowSchema: FlowSchema[];
}>(
gql`
query ($flow_id: String!) {
flowSchema: get_flow_schema(args: { published_flow_id: $flow_id }) {
node
type
text
planx_variable
}
}
`,
{ flow_id: req.params.flowId },
);

if (!flowSchema.length) {
next({
status: 404,
message:
"Can't find a schema for this flow. Make sure it's published or try a different flow id.",
});
} else {
// build a CSV and stream it
stringify(flowSchema, { header: true }).pipe(res);

res.header("Content-type", "text/csv");
res.attachment(`${req.params.flowId}.csv`);
}
} catch (err) {
next(err);
}
});
router.get(
"/:flowId/download-schema",
validate(downloadFlowSchema),
downloadFlowSchemaController,
);

export default router;
7 changes: 6 additions & 1 deletion api.planx.uk/modules/flows/validate/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Node } from "@opensystemslab/planx-core/types";
import { ValidatedRequestHandler } from "../../../shared/middleware/validate";
import { z } from "zod";
import { validateAndDiffFlow } from "./service";
import { ServerError } from "../../../errors";

interface ValidateAndDiffResponse {
message: string;
Expand All @@ -27,6 +28,10 @@ export const validateAndDiffFlowController: ValidateAndDiffFlowController =
const result = await validateAndDiffFlow(flowId);
return res.json(result);
} catch (error) {
return next(error);
return next(
new ServerError({
message: `Failed to validate and diff flow: ${error}`,
}),
);
}
};

0 comments on commit a984c15

Please sign in to comment.