Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production deploy #2895

Merged
merged 8 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,15 @@ SUPPRESS_LOGS=true

# Local authority specific integrations
## Lambeth
GOV_UK_PAY_TOKEN_LAMBETH=👻
UNIFORM_CLIENT_LAMBETH=👻

## Southwark
GOV_UK_PAY_TOKEN_SOUTHWARK=👻
UNIFORM_CLIENT_SOUTHWARK=👻

## Buckinghamshire
GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE=👻
UNIFORM_CLIENT_AYLESBURY_VALE=👻
UNIFORM_CLIENT_CHILTERN=👻
UNIFORM_CLIENT_WYCOMBE=👻

## Camden
GOV_UK_PAY_TOKEN_CAMDEN=👻

## Gloucester
GOV_UK_PAY_TOKEN_GLOUCESTER=👻

## Medway
GOV_UK_PAY_TOKEN_MEDWAY=👻

## End-to-end test team (borrows Lambeth's details)
GOV_UK_PAY_TOKEN_E2E=👻
GOV_UK_PAY_SECRET_E2E=👻
21 changes: 1 addition & 20 deletions api.planx.uk/.env.test.example
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,4 @@ UNIFORM_SUBMISSION_URL=👻

SLACK_WEBHOOK_URL=👻

ORDNANCE_SURVEY_API_KEY=👻

# Local authority specific integrations
## Lambeth
GOV_UK_PAY_TOKEN_LAMBETH=👻

## Southwark
GOV_UK_PAY_TOKEN_SOUTHWARK=👻

## Buckinghamshire
GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE=👻

## Camden
GOV_UK_PAY_TOKEN_CAMDEN=👻

## Gloucester
GOV_UK_PAY_TOKEN_GLOUCESTER=👻

## Medway
GOV_UK_PAY_TOKEN_MEDWAY=👻
ORDNANCE_SURVEY_API_KEY=👻
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const baseSchema: PlanningConstraintsBaseSchema = {
category: "Heritage and conservation",
},
locallyListed: {
active: true,
active: false,
neg: "is not, or is not within, a Locally Listed Building",
pos: "is, or is within, a Locally Listed Building",
"digital-land-datasets": ["locally-listed-building"],
Expand Down
3 changes: 3 additions & 0 deletions api.planx.uk/modules/pay/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const makePaymentViaProxy: PaymentProxyController = async (
),
},
req,
res,
)(req, res, next);
};

Expand Down Expand Up @@ -101,6 +102,7 @@ export const makeInviteToPayPaymentViaProxy: PaymentRequestProxyController = (
}),
},
req,
res,
)(req, res, next);
};

Expand Down Expand Up @@ -151,6 +153,7 @@ export function fetchPaymentViaProxyWithCallback(
}),
},
req,
res,
)(req, res, next);
};
}
Expand Down
5 changes: 5 additions & 0 deletions api.planx.uk/modules/pay/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ jest.mock("@opensystemslab/planx-core", () => {
session: {
findDetails: jest.fn().mockImplementation(() => ({ lockedAt: null })),
},
team: {
getIntegrations: jest
.fn()
.mockImplementation(() => ({ govPayToken: "abc123" })),
},
})),
};
});
Expand Down
17 changes: 12 additions & 5 deletions api.planx.uk/modules/pay/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@ import { ServerError } from "../../errors";

/**
* Confirm that this local authority (aka team) has a pay token
* TODO: Check this against a DB value instead of env vars?
*/
export const isTeamUsingGovPay: RequestHandler = (req, _res, next) => {
const isSupported =
process.env[`GOV_UK_PAY_TOKEN_${req.params.localAuthority.toUpperCase()}`];
export const isTeamUsingGovPay: RequestHandler = async (req, res, next) => {
const env =
process.env.APP_ENVIRONMENT === "production" ? "production" : "staging";

if (!isSupported) {
const { govPayToken } = await $api.team.getIntegrations({
env,
slug: req.params.localAuthority,
encryptionKey: process.env.ENCRYPTION_KEY!,
});

if (!govPayToken) {
return next({
status: 400,
message: `GOV.UK Pay is not enabled for this local authority (${req.params.localAuthority})`,
});
}

res.locals.govPayToken = govPayToken;

next();
};

Expand Down
14 changes: 7 additions & 7 deletions api.planx.uk/modules/pay/proxy.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Request } from "express";
import { Response, Request } from "express";
import { fixRequestBody, Options } from "http-proxy-middleware";
import { useProxy } from "../../shared/middleware/proxy";

export const usePayProxy = (options: Partial<Options>, req: Request) => {
export const usePayProxy = (
options: Partial<Options>,
req: Request,
res: Response,
) => {
return useProxy({
target: "https://publicapi.payments.service.gov.uk/v1/payments",
onProxyReq: fixRequestBody,
headers: {
...(req.headers as NodeJS.Dict<string | string[]>),
"content-type": "application/json",
Authorization: `Bearer ${
process.env[
`GOV_UK_PAY_TOKEN_${req.params.localAuthority}`.toUpperCase()
]
}`,
Authorization: `Bearer ${res.locals.govPayToken}`,
},
...options,
});
Expand Down
42 changes: 42 additions & 0 deletions api.planx.uk/modules/pay/service/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { GovUKPayment } from "@opensystemslab/planx-core/types";
import { isTestPayment } from "./utils";

describe("isTestPayment() helper function", () => {
const OLD_ENV = process.env;

beforeEach(() => {
process.env = { ...OLD_ENV };
});

afterAll(() => {
process.env = OLD_ENV;
});

test("sandbox payments", () => {
const result = isTestPayment({
payment_provider: "sandbox",
} as GovUKPayment);
expect(result).toBe(true);
});

test("other payment providers", () => {
const result = isTestPayment({ payment_provider: "Visa" } as GovUKPayment);
expect(result).toBe(false);
});

test("stripe payments (staging)", () => {
process.env.APP_ENVIRONMENT = "staging";
const result = isTestPayment({
payment_provider: "stripe",
} as GovUKPayment);
expect(result).toBe(true);
});

test("stripe payments (production)", () => {
process.env.APP_ENVIRONMENT = "production";
const result = isTestPayment({
payment_provider: "stripe",
} as GovUKPayment);
expect(result).toBe(false);
});
});
46 changes: 33 additions & 13 deletions api.planx.uk/modules/pay/service/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,42 @@ export const addGovPayPaymentIdToPaymentRequest = async (
}
};

/**
* Identify if a payment is using dummy card details for testing
* Docs: https://docs.payments.service.gov.uk/testing_govuk_pay/#mock-card-numbers-and-email-addresses
*/
export const isTestPayment = ({
payment_provider: paymentProvider,
}: GovUKPayment) => {
// Payment using "sandbox" account
const isSandbox = paymentProvider === "sandbox";
const isProduction = process.env.APP_ENVIRONMENT === "production";

// Payment using Stripe in non-production environment
// Stripe test accounts do not have a specific test code
const isStripeTest = paymentProvider === "stripe" && !isProduction;

return isSandbox || isStripeTest;
};

/**
* Notify #planx-notifications so we can monitor for subsequent submissions
*/
export async function postPaymentNotificationToSlack(
req: Request,
govUkResponse: GovUKPayment,
label = "",
) {
// if it's a prod payment, notify #planx-notifications so we can monitor for subsequent submissions
if (govUkResponse?.payment_provider !== "sandbox") {
const slack = SlackNotify(process.env.SLACK_WEBHOOK_URL!);
const getStatus = (state: GovUKPayment["state"]) =>
state.status + (state.message ? ` (${state.message})` : "");
const payMessage = `:coin: New GOV Pay payment ${label} *${
govUkResponse.payment_id
}* with status *${getStatus(govUkResponse.state)}* [${
req.params.localAuthority
}]`;
await slack.send(payMessage);
console.log("Payment notification posted to Slack");
}
if (isTestPayment(govUkResponse)) return;

const slack = SlackNotify(process.env.SLACK_WEBHOOK_URL!);
const getStatus = (state: GovUKPayment["state"]) =>
state.status + (state.message ? ` (${state.message})` : "");
const payMessage = `:coin: New GOV Pay payment ${label} *${
govUkResponse.payment_id
}* with status *${getStatus(govUkResponse.state)}* [${
req.params.localAuthority
}]`;
await slack.send(payMessage);
console.log("Payment notification posted to Slack");
}
5 changes: 0 additions & 5 deletions api.planx.uk/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,6 @@ assert(process.env.BOPS_API_TOKEN);
assert(process.env.UNIFORM_TOKEN_URL);
assert(process.env.UNIFORM_SUBMISSION_URL);

// Camden, Medway & Gloucester have sandbox pay only, so skip assertion as this will fail in production
["BUCKINGHAMSHIRE", "LAMBETH", "SOUTHWARK"].forEach((authority) => {
assert(process.env[`GOV_UK_PAY_TOKEN_${authority}`]);
});

// needed for storing original URL to redirect to in login flow
app.use(
cookieSession({
Expand Down
54 changes: 0 additions & 54 deletions api.planx.uk/tests/serverErrorHandler.test.js

This file was deleted.

2 changes: 1 addition & 1 deletion doc/how-to/how-to-generate-a-secret.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# How to generating a secret
# How to generate a secret

## Process
1. Generate a new secret using a random password generator, such as 1Password
Expand Down
2 changes: 2 additions & 0 deletions doc/how-to/how-to-grant-metabase-permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ When adding a new view, you will need to grant the `metabase_read_only` role `SE
```sql
GRANT SELECT ON public.YOUR_NEW_VIEW TO metabase_read_only;
```

⚠️ Please note - when views are dropped and re-created, associated privileges are revoked. Be sure to re-grant `SELECT` permissions when updating views via Hasura migrations.
3 changes: 1 addition & 2 deletions docker-compose.e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,4 @@ services:
environment:
UNIFORM_SUBMISSION_URL: http://mock-server:8080
UNIFORM_TOKEN_URL: http://mock-server:8080
UNIFORM_CLIENT_E2E: e2e:123
GOV_UK_PAY_TOKEN_E2E: ${GOV_UK_PAY_TOKEN_E2E}
UNIFORM_CLIENT_E2E: e2e:123
9 changes: 0 additions & 9 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,22 +145,13 @@ services:
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
# Local authority config
# Lambeth
GOV_UK_PAY_TOKEN_LAMBETH: ${GOV_UK_PAY_TOKEN_LAMBETH}
UNIFORM_CLIENT_LAMBETH: ${UNIFORM_CLIENT_LAMBETH}
# Southwark
GOV_UK_PAY_TOKEN_SOUTHWARK: ${GOV_UK_PAY_TOKEN_SOUTHWARK}
UNIFORM_CLIENT_SOUTHWARK: ${UNIFORM_CLIENT_SOUTHWARK}
# Buckinghamshire
GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE: ${GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE}
UNIFORM_CLIENT_AYLESBURY_VALE: ${UNIFORM_CLIENT_AYLESBURY_VALE}
UNIFORM_CLIENT_CHILTERN: ${UNIFORM_CLIENT_CHILTERN}
UNIFORM_CLIENT_WYCOMBE: ${UNIFORM_CLIENT_WYCOMBE}
#Camden
GOV_UK_PAY_TOKEN_CAMDEN: ${GOV_UK_PAY_TOKEN_CAMDEN}
# Medway
GOV_UK_PAY_TOKEN_MEDWAY: ${GOV_UK_PAY_TOKEN_MEDWAY}
# Gloucester
GOV_UK_PAY_TOKEN_GLOUCESTER: ${GOV_UK_PAY_TOKEN_GLOUCESTER}

sharedb:
restart: unless-stopped
Expand Down
Loading
Loading