Skip to content

Commit

Permalink
feat: Add payment exemption status to Slack notifications (#2251)
Browse files Browse the repository at this point in the history
* refactor: Move webhook routes from server to module

* refactor: Update sendSlackNotification to modular structure

* test: Add email-submission tests

* refactor: Rename and restructure folders, simplify service

* feat: Add exemption status to notification

* docs: Add Swagger docs

* fix: Don't use fee to calculate exemption statuses
  • Loading branch information
DafyddLlyr authored Oct 2, 2023
1 parent d6eb95d commit 8fb8e06
Show file tree
Hide file tree
Showing 21 changed files with 740 additions and 320 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import supertest from "supertest";
import app from "../server";
import { createScheduledEvent } from "../hasura/metadata";
import app from "../../../server";
import { createScheduledEvent } from "../../../hasura/metadata";

const { post } = supertest(app);

jest.mock("../hasura/metadata");
jest.mock("../../../hasura/metadata");
const mockedCreateScheduledEvent = createScheduledEvent as jest.MockedFunction<
typeof createScheduledEvent
>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { addDays } from "date-fns";
import { Request, Response, NextFunction } from "express";

import { createScheduledEvent } from "../hasura/metadata";
import { createScheduledEvent } from "../../../hasura/metadata";
import {
DAYS_UNTIL_EXPIRY,
REMINDER_DAYS_FROM_EXPIRY,
} from "../saveAndReturn/utils";
} from "../../../saveAndReturn/utils";

/**
* Create "reminder" events for a lowcal_session record
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import supertest from "supertest";
import app from "../server";
import { createScheduledEvent } from "../hasura/metadata";
import app from "../../../server";
import { createScheduledEvent } from "../../../hasura/metadata";

const { post } = supertest(app);

jest.mock("../hasura/metadata");
jest.mock("../../../hasura/metadata");
const mockedCreateScheduledEvent = createScheduledEvent as jest.MockedFunction<
typeof createScheduledEvent
>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { addDays } from "date-fns";
import { Request, Response, NextFunction } from "express";

import { createScheduledEvent } from "../hasura/metadata";
import { createScheduledEvent } from "../../../hasura/metadata";
import {
DAYS_UNTIL_EXPIRY,
REMINDER_DAYS_FROM_EXPIRY,
} from "../saveAndReturn/utils";
} from "../../../saveAndReturn/utils";

/**
* Create two "invitation" events for a payments_request record: one for the nominee and one for the agent
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import supertest from "supertest";
import app from "../../server";
import app from "../../../../server";
import * as operations from "./operations";

const mockSend = jest.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Request, Response, NextFunction } from "express";

import { getOperations, operationHandler } from "./operations";
import { OperationResult } from "./types";
import { getFormattedEnvironment } from "../../helpers";
import { getFormattedEnvironment } from "../../../../helpers";

/**
* Called by Hasura cron job `sanitise_application_data` on a nightly basis
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { runSQL } from "../../hasura/schema";
import { queryMock } from "../../tests/graphqlQueryMock";
import { runSQL } from "../../../../hasura/schema";
import { queryMock } from "../../../../tests/graphqlQueryMock";
import {
mockIds,
mockSanitiseBOPSApplicationsMutation,
Expand All @@ -25,11 +25,11 @@ import {
deleteHasuraScheduledEventsForSubmittedSessions,
} from "./operations";

jest.mock("../../hasura/schema");
jest.mock("../../../../hasura/schema");
const mockRunSQL = runSQL as jest.MockedFunction<typeof runSQL>;

const mockFindSession = jest.fn();
jest.mock("../../client", () => {
jest.mock("../../../../client", () => {
return {
$admin: {
session: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { gql } from "graphql-request";
import { subMonths } from "date-fns";

import { Operation, OperationResult } from "./types";
import { adminGraphQLClient } from "../../hasura";
import { runSQL } from "../../hasura/schema";
import { getFilesForSession } from "../../session/files";
import { deleteFilesByURL } from "../../s3/deleteFile";
import { adminGraphQLClient } from "../../../../hasura";
import { runSQL } from "../../../../hasura/schema";
import { getFilesForSession } from "../../../../session/files";
import { deleteFilesByURL } from "../../../../s3/deleteFile";

const RETENTION_PERIOD_MONTHS = 6;
export const getRetentionPeriod = () =>
Expand Down
31 changes: 31 additions & 0 deletions api.planx.uk/modules/webhooks/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ServerError } from "../../errors";
import { sendSlackNotification } from "./sendNotification/service";
import { SendSlackNotification } from "./sendNotification/types";

export const sendSlackNotificationController: SendSlackNotification = async (
req,
res,
next,
) => {
const isProduction = process.env.APP_ENVIRONMENT === "production";
if (!isProduction) {
return res.status(200).send({
message: `Staging application submitted, skipping Slack notification`,
});
}

const eventData = req.body.event.data.new;
const eventType = req.query.type;

try {
const data = await sendSlackNotification(eventData, eventType);
return res.status(200).send({ message: "Posted to Slack", data });
} catch (error) {
return next(
new ServerError({
message: `Failed to send ${eventType} Slack notification`,
cause: error,
}),
);
}
};
135 changes: 135 additions & 0 deletions api.planx.uk/modules/webhooks/docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
openapi: 3.1.0
info:
title: Plan✕ API
version: 0.1.0
tags:
- name: webhooks
description: Webhooks for event management
components:
schemas:
Payload:
type: object
properties:
sessionId:
type: string
required:
- sessionId
BopsSubmissionSchema:
type: object
properties:
body:
type: object
properties:
event:
type: object
properties:
data:
type: object
properties:
new:
type: object
properties:
payload:
$ref: "#/components/schemas/Payload"
bops_id:
type: string
destination_url:
type: string
required:
- body
UniformSubmissionSchema:
type: object
properties:
body:
type: object
properties:
event:
type: object
properties:
data:
type: object
properties:
new:
type: object
properties:
payload:
$ref: "#/components/schemas/Payload"
submission_reference:
type: string
response:
type: object
properties:
organisation:
type: string
required:
- body
EmailSubmissionSchema:
type: object
properties:
body:
type: object
properties:
event:
type: object
properties:
data:
type: object
properties:
new:
type: object
properties:
session_id:
type: string
team_slug:
type: string
request:
type: object
properties:
personalisation:
type: object
properties:
serviceName:
type: string
required:
- body
SendSlackNotificationSchema:
oneOf:
- $ref: "#/components/schemas/BopsSubmissionSchema"
- $ref: "#/components/schemas/UniformSubmissionSchema"
- $ref: "#/components/schemas/EmailSubmissionSchema"
responses:
SlackNotificationSuccessMessage:
content:
application/json:
schema:
type: object
properties:
data:
type: string
required: false
description: The generated Slack message
message:
type: string
required: true
paths:
/webhooks/hasura/sendSlackNotification:
post:
tags: ["webhooks"]
summary: Send Slack notification
description: Endpoint to trigger a Slack notification following a submission event
parameters:
- in: query
name: type
type: string
enum: ["bops-submission", "uniform-submission", "email-submission"]
required: true
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/SendSlackNotificationSchema"
responses:
"200":
$ref: "#/components/responses/SlackNotificationSuccessMessage"
"500":
$ref: "#/components/responses/ErrorMessage"
40 changes: 40 additions & 0 deletions api.planx.uk/modules/webhooks/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Router } from "express";
import { useHasuraAuth } from "../auth/middleware";
import { createPaymentSendEvents } from "../../inviteToPay/createPaymentSendEvents";
import { sanitiseApplicationData } from "./_old/sanitiseApplicationData";
import {
createExpiryEvent,
createReminderEvent,
} from "./_old/lowcalSessionEvents";
import {
createPaymentExpiryEvents,
createPaymentInvitationEvents,
createPaymentReminderEvents,
} from "./_old/paymentRequestEvents";
import { validate } from "../../shared/middleware/validate";
import { sendSlackNotificationController } from "./controller";
import { sendSlackNotificationSchema } from "./sendNotification/schema";

const router = Router();

router.use("/hasura", useHasuraAuth);
router.post("/hasura/create-reminder-event", createReminderEvent);
router.post("/hasura/create-expiry-event", createExpiryEvent);
router.post(
"/hasura/create-payment-invitation-events",
createPaymentInvitationEvents,
);
router.post(
"/hasura/create-payment-reminder-events",
createPaymentReminderEvents,
);
router.post("/hasura/create-payment-expiry-events", createPaymentExpiryEvents);
router.post("/hasura/create-payment-send-events", createPaymentSendEvents);
router.post(
"/hasura/send-slack-notification",
validate(sendSlackNotificationSchema),
sendSlackNotificationController,
);
router.post("/hasura/sanitise-application-data", sanitiseApplicationData);

export default router;
Loading

0 comments on commit 8fb8e06

Please sign in to comment.