Skip to content

Commit

Permalink
fix: don't link to locked or sanitised sessions in resume emails (#2713)
Browse files Browse the repository at this point in the history
  • Loading branch information
jessicamcinchak authored Jan 31, 2024
1 parent a5deb4e commit 9d933e0
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe("buildContentFromSessions function", () => {
},
},
id: "123",
created_at: "2022-05-01T01:02:03.865452+00:00",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
Expand All @@ -56,7 +56,7 @@ describe("buildContentFromSessions function", () => {
const result = `Service: Apply for a lawful development certificate
Address: 1 High Street
Project type: New office premises
Expiry Date: 29 May 2022
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=123`;
expect(
await buildContentFromSessions(
Expand All @@ -80,7 +80,7 @@ describe("buildContentFromSessions function", () => {
},
},
id: "123",
created_at: "2022-05-01T01:02:03.865452+00:00",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
Expand All @@ -97,7 +97,7 @@ describe("buildContentFromSessions function", () => {
},
},
id: "456",
created_at: "2022-05-01T01:02:03.865452+00:00",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
Expand All @@ -114,7 +114,7 @@ describe("buildContentFromSessions function", () => {
},
},
id: "789",
created_at: "2022-05-01T01:02:03.865452+00:00",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
Expand All @@ -123,15 +123,15 @@ describe("buildContentFromSessions function", () => {
const result = `Service: Apply for a lawful development certificate
Address: 1 High Street
Project type: New office premises
Expiry Date: 29 May 2022
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=123\n\nService: Apply for a lawful development certificate
Address: 2 High Street
Project type: New office premises
Expiry Date: 29 May 2022
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=456\n\nService: Apply for a lawful development certificate
Address: 3 High Street
Project type: New office premises
Expiry Date: 29 May 2022
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=789`;
expect(
await buildContentFromSessions(
Expand All @@ -141,6 +141,56 @@ describe("buildContentFromSessions function", () => {
).toEqual(result);
});

it("should filter out expired sessions", async () => {
const sessions: PartialDeep<LowCalSession>[] = [
{
data: {
passport: {
data: {
_address: {
single_line_address: "1 High Street",
},
"proposal.projectType": ["new.office"],
},
},
},
id: "123",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
},
{
data: {
passport: {
data: {
_address: {
single_line_address: "2 High Street",
},
"proposal.projectType": ["new.office"],
},
},
},
id: "456",
created_at: "2022-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
},
];
const result = `Service: Apply for a lawful development certificate
Address: 1 High Street
Project type: New office premises
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=123`;
expect(
await buildContentFromSessions(
sessions as LowCalSession[],
{ slug: "team" } as Team,
),
).toEqual(result);
});

it("should handle an empty address field", async () => {
const sessions: PartialDeep<LowCalSession>[] = [
{
Expand All @@ -153,7 +203,7 @@ describe("buildContentFromSessions function", () => {
},
},
id: "123",
created_at: "2022-05-01T01:02:03.865452+00:00",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
Expand All @@ -163,7 +213,7 @@ describe("buildContentFromSessions function", () => {
const result = `Service: Apply for a lawful development certificate
Address: Address not submitted
Project type: New office premises
Expiry Date: 29 May 2022
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=123`;
expect(
await buildContentFromSessions(
Expand All @@ -187,7 +237,7 @@ describe("buildContentFromSessions function", () => {
},
},
id: "123",
created_at: "2022-05-01T01:02:03.865452+00:00",
created_at: "2026-05-01T01:02:03.865452+00:00",
flow: {
slug: "apply-for-a-lawful-development-certificate",
},
Expand All @@ -197,7 +247,7 @@ describe("buildContentFromSessions function", () => {
const result = `Service: Apply for a lawful development certificate
Address: 1 High Street
Project type: Project type not submitted
Expiry Date: 29 May 2022
Expiry Date: 29 May 2026
Link: example.com/team/apply-for-a-lawful-development-certificate/preview?sessionId=123`;
expect(
await buildContentFromSessions(
Expand Down
27 changes: 20 additions & 7 deletions api.planx.uk/modules/saveAndReturn/service/resumeApplication.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { gql } from "graphql-request";
import { LowCalSession, Team } from "../../../types";
import { convertSlugToName, getResumeLink, calculateExpiryDate } from "./utils";
import { sendEmail } from "../../../lib/notify";
import type { SiteAddress } from "@opensystemslab/planx-core/types";
import { differenceInDays } from "date-fns";
import { gql } from "graphql-request";
import { $api, $public } from "../../../client";
import { sendEmail } from "../../../lib/notify";
import { LowCalSession, Team } from "../../../types";
import {
DAYS_UNTIL_EXPIRY,
calculateExpiryDate,
convertSlugToName,
getResumeLink,
} from "./utils";

/**
* Send a "Resume" email to an applicant which list all open applications for a given council (team)
Expand Down Expand Up @@ -46,7 +52,9 @@ const validateRequest = async (
where: {
email: { _eq: $email }
deleted_at: { _is_null: true }
locked_at: { _is_null: true }
submitted_at: { _is_null: true }
sanitised_at: { _is_null: true }
flow: { team: { slug: { _eq: $teamSlug } } }
}
order_by: { flow: { slug: asc }, created_at: asc }
Expand Down Expand Up @@ -113,15 +121,20 @@ const buildContentFromSessions = async (
const resumeLink = getResumeLink(session, team, session.flow.slug);
const expiryDate = calculateExpiryDate(session.created_at);

return `Service: ${service}
// Filter out any sessions that are expired (safety net for failed sanitation)
const today = new Date();
const sessionAge = differenceInDays(today, new Date(session.created_at));

if (sessionAge < DAYS_UNTIL_EXPIRY)
return `Service: ${service}
Address: ${addressLine || "Address not submitted"}
Project type: ${projectType || "Project type not submitted"}
Expiry Date: ${expiryDate}
Link: ${resumeLink}`;
};

const content = await Promise.all(sessions.map(contentBuilder));
return content.join("\n\n");
return content.filter(Boolean).join("\n\n");
};

export { resumeApplication, buildContentFromSessions };
export { buildContentFromSessions, resumeApplication };
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,12 @@ export const getExpiredSessionIds = async (): Promise<string[]> => {
query GetExpiredSessionIds($retentionPeriod: timestamptz) {
lowcal_sessions(
where: {
submitted_at: { _lt: $retentionPeriod }
sanitised_at: { _is_null: true }
_or: [
{ deleted_at: { _lt: $retentionPeriod } }
{ submitted_at: { _lt: $retentionPeriod } }
{ locked_at: { _lt: $retentionPeriod } }
]
}
) {
id
Expand Down Expand Up @@ -123,6 +127,7 @@ export const sanitiseLowcalSessions: Operation = async () => {
_or: [
{ deleted_at: { _lt: $retentionPeriod } }
{ submitted_at: { _lt: $retentionPeriod } }
{ locked_at: { _lt: $retentionPeriod } }
]
}
) {
Expand Down

0 comments on commit 9d933e0

Please sign in to comment.