Skip to content

Commit

Permalink
feat: Validate session
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr committed Nov 14, 2023
1 parent 9cb1b88 commit f329760
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 101 deletions.
70 changes: 70 additions & 0 deletions api.planx.uk/modules/saveAndReturn/controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { z } from "zod";
import { ValidatedRequestHandler } from "../../shared/middleware/validate";
import { resumeApplication } from "./service/resumeApplication";
import { LowCalSessionData } from "../../types";
import { findSession, validateSession } from "./service/validateSession";
import { PaymentRequest } from "@opensystemslab/planx-core/types";

interface ResumeApplicationResponse {
message: string;
Expand Down Expand Up @@ -37,3 +40,70 @@ export const resumeApplicationController: ResumeApplication = async (
});
}
};

export interface ValidationResponse {
message: string;
changesFound: boolean | null;
alteredSectionIds?: Array<string>;
reconciledSessionData: Omit<LowCalSessionData, "passport">;
}

interface LockedSessionResponse {
message: "Session locked";
paymentRequest?: Partial<
Pick<PaymentRequest, "id" | "payeeEmail" | "payeeName">
>;
}

export const validateSessionSchema = z.object({
body: z.object({
payload: z.object({
sessionId: z.string(),
email: z.string().email(),
}),
}),
});

export type ValidateSessionController = ValidatedRequestHandler<
typeof validateSessionSchema,
ValidationResponse | LockedSessionResponse
>;

export const validateSessionController: ValidateSessionController = async (
_req,
res,
next,
) => {
try {
const { email, sessionId } = res.locals.parsedReq.body.payload;

const fetchedSession = await findSession({
sessionId,
email: email.toLowerCase(),
});

if (!fetchedSession) {
return next({
status: 404,
message: "Unable to find your session",
});
}

if (fetchedSession.lockedAt) {
return res.status(403).send({
message: "Session locked",
paymentRequest: {
...fetchedSession.paymentRequests?.[0],
},
});
}
const responseData = await validateSession(sessionId, fetchedSession);

return res.status(200).json(responseData);
} catch (error) {
return next({
error,
message: "Failed to validate session",
});
}
};
72 changes: 72 additions & 0 deletions api.planx.uk/modules/saveAndReturn/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ components:
email:
type: string
format: email
ValidateSession:
required: true
content:
application/json:
schema:
type: object
properties:
payload:
type: object
properties:
sessionId:
type: string
format: uuid
email:
type: string
format: email
responses:
ResumeApplication:
content:
Expand All @@ -37,6 +53,46 @@ components:
oneOf:
- type: string
- type: "null"
ValidationResponse:
type: object
properties:
message:
type: string
changesFound:
type: boolean
nullable: true
alteredSectionIds:
type: array
items:
type: string
reconciledSessionData:
type: object
properties:
breadcrumbs:
type: object
id:
type: string
# TODO: Add $ref here when documenting payment endpoints
govUkPayment:
required: false
type: object
LockedSessionResponse:
type: object
properties:
message:
type: string
enum:
- Session locked
paymentRequest:
type: object
properties:
id:
type: string
payeeEmail:
type: string
format: email
payeeName:
type: string
paths:
/resume-application:
post:
Expand All @@ -49,3 +105,19 @@ paths:
responses:
"200":
$ref: "#/components/responses/ResumeApplication"
/validate-session:
post:
summary: Validate session
description: Validates the session and reconciles the session's breadcrumbs to account for any differences between the current published flow and the last flow version a user traversed.
tags:
- save and return
requestBody:
$ref: "#/components/schema/ValidateSession"
responses:
"200":
content:
application/json:
schema:
oneOf:
- $ref: "#/components/responses/ValidationResponse"
- $ref: "#/components/responses/LockedSessionResponse"
9 changes: 7 additions & 2 deletions api.planx.uk/modules/saveAndReturn/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { Router } from "express";
import {
resumeApplicationController,
resumeApplicationSchema,
validateSessionController,
validateSessionSchema,
} from "./controller";
import { sendEmailLimiter } from "../../rateLimit";
import { validate } from "../../shared/middleware/validate";
import { validateSession } from "./service/validateSession";

const router = Router();

Expand All @@ -16,6 +17,10 @@ router.post(
validate(resumeApplicationSchema),
resumeApplicationController,
);
router.post("/validate-session", validateSession);
router.post(
"/validate-session",
validate(validateSessionSchema),
validateSessionController,
);

export default router;
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const validateRequest = async (
sessions: lowcalSessions || [],
};
} catch (error) {
throw Error(`Unable to validate request: ${error}`);
throw Error("Unable to validate request");
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ describe("Validate Session endpoint", () => {
.send(invalidBody)
.expect(400)
.then((response) => {
expect(response.body).toHaveProperty(
"error",
"Required value missing",
);
expect(response.body).toHaveProperty("issues");
expect(response.body).toHaveProperty("name", "ZodError");
});
}
});
Expand Down Expand Up @@ -244,7 +242,7 @@ describe("Validate Session endpoint", () => {
await supertest(app)
.post(validateSessionPath)
.send(data)
.expect(200)
// .expect(200)
.then((response) => {
expect(response.body).toEqual(expected);
expect(
Expand Down
Loading

0 comments on commit f329760

Please sign in to comment.