diff --git a/.env.example b/.env.example index 52a97abee2..b7f1713f3b 100644 --- a/.env.example +++ b/.env.example @@ -63,7 +63,6 @@ PRODUCTION_PG_URL_FOR_USER_GITHUB_ACTIONS=👻 SHAREDB_PORT=7003 # Integrations (local and pull request environments point to third party staging environments) -BOPS_API_ROOT_DOMAIN=👻 BOPS_API_TOKEN=👻 GOVUK_NOTIFY_API_KEY=👻 @@ -89,26 +88,16 @@ SUPPRESS_LOGS=true ## Lambeth GOV_UK_PAY_TOKEN_LAMBETH=👻 UNIFORM_CLIENT_LAMBETH=👻 -BOPS_SUBMISSION_URL_LAMBETH=https://lambeth.${BOPS_API_ROOT_DOMAIN} ## Southwark GOV_UK_PAY_TOKEN_SOUTHWARK=👻 UNIFORM_CLIENT_SOUTHWARK=👻 -BOPS_SUBMISSION_URL_SOUTHWARK=https://southwark.${BOPS_API_ROOT_DOMAIN} ## Buckinghamshire GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE=👻 UNIFORM_CLIENT_AYLESBURY_VALE=👻 UNIFORM_CLIENT_CHILTERN=👻 UNIFORM_CLIENT_WYCOMBE=👻 -BOPS_SUBMISSION_URL_BUCKINGHAMSHIRE=https://buckinghamshire.${BOPS_API_ROOT_DOMAIN} - -## Camden -BOPS_SUBMISSION_URL_CAMDEN=https://camden.${BOPS_API_ROOT_DOMAIN} - -## Gloucester -BOPS_SUBMISSION_URL_GLOUCESTER=https://gloucester.${BOPS_API_ROOT_DOMAIN} ## End-to-end test team (borrows Lambeth's details) GOV_UK_PAY_TOKEN_E2E=👻 -BOPS_SUBMISSION_URL_E2E=https://lambeth.${BOPS_API_ROOT_DOMAIN} diff --git a/api.planx.uk/.env.test.example b/api.planx.uk/.env.test.example index 99745d4f3a..51ce761586 100644 --- a/api.planx.uk/.env.test.example +++ b/api.planx.uk/.env.test.example @@ -25,7 +25,6 @@ HASURA_GRAPHQL_URL=http://hasura:8080/v1/graphql HASURA_PLANX_API_KEY=👻 # Integrations -BOPS_API_ROOT_DOMAIN=👻 BOPS_API_TOKEN=👻 GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE=👻 @@ -42,18 +41,9 @@ SLACK_WEBHOOK_URL=👻 # Local authority specific integrations ## Lambeth GOV_UK_PAY_TOKEN_LAMBETH=👻 -BOPS_SUBMISSION_URL_LAMBETH=https://lambeth.${BOPS_API_ROOT_DOMAIN} ## Southwark GOV_UK_PAY_TOKEN_SOUTHWARK=👻 -BOPS_SUBMISSION_URL_SOUTHWARK=https://southwark.${BOPS_API_ROOT_DOMAIN} ## Buckinghamshire -GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE=👻 -BOPS_SUBMISSION_URL_BUCKINGHAMSHIRE=https://buckinghamshire.${BOPS_API_ROOT_DOMAIN} - -## Camden -BOPS_SUBMISSION_URL_CAMDEN=https://camden.${BOPS_API_ROOT_DOMAIN} - -## Gloucester -BOPS_SUBMISSION_URL_GLOUCESTER=https://gloucester.${BOPS_API_ROOT_DOMAIN} +GOV_UK_PAY_TOKEN_BUCKINGHAMSHIRE=👻 \ No newline at end of file diff --git a/api.planx.uk/modules/send/bops/bops.test.ts b/api.planx.uk/modules/send/bops/bops.test.ts index b3150a6e2a..4a6d5051c2 100644 --- a/api.planx.uk/modules/send/bops/bops.test.ts +++ b/api.planx.uk/modules/send/bops/bops.test.ts @@ -32,9 +32,9 @@ jest.mock("@opensystemslab/planx-core", () => { }; }); -const submissionURL = process.env.BOPS_SUBMISSION_URL_SOUTHWARK; - describe(`sending an application to BOPS`, () => { + const submissionURL = "https://test.bops-test.com"; + beforeEach(() => { queryMock.mockQuery({ name: "FindApplication", @@ -54,6 +54,38 @@ describe(`sending an application to BOPS`, () => { insertBopsApplication: { id: 22 }, }, }); + + queryMock.mockQuery({ + name: "GetStagingBopsSubmissionURL", + data: { + teams: [ + { + integrations: { + bopsSubmissionURL: submissionURL, + }, + }, + ], + }, + variables: { + slug: "southwark", + }, + }); + + queryMock.mockQuery({ + name: "GetStagingBopsSubmissionURL", + data: { + teams: [ + { + integrations: { + bopsSubmissionURL: null, + }, + }, + ], + }, + variables: { + slug: "unsupported-team", + }, + }); }); it("proxies request and returns hasura id", async () => { @@ -132,6 +164,8 @@ describe(`sending an application to BOPS`, () => { }); describe(`sending an application to BOPS v2`, () => { + const submissionURL = "https://test.bops-test.com"; + beforeEach(() => { queryMock.mockQuery({ name: "FindApplication", @@ -151,6 +185,38 @@ describe(`sending an application to BOPS v2`, () => { insertBopsApplication: { id: 22 }, }, }); + + queryMock.mockQuery({ + name: "GetStagingBopsSubmissionURL", + data: { + teams: [ + { + integrations: { + bopsSubmissionURL: submissionURL, + }, + }, + ], + }, + variables: { + slug: "southwark", + }, + }); + + queryMock.mockQuery({ + name: "GetStagingBopsSubmissionURL", + data: { + teams: [ + { + integrations: { + bopsSubmissionURL: null, + }, + }, + ], + }, + variables: { + slug: "unsupported-team", + }, + }); }); it("successfully proxies request and returns hasura id", async () => { diff --git a/api.planx.uk/modules/send/bops/bops.ts b/api.planx.uk/modules/send/bops/bops.ts index fed2afd51e..22e4568a11 100644 --- a/api.planx.uk/modules/send/bops/bops.ts +++ b/api.planx.uk/modules/send/bops/bops.ts @@ -44,8 +44,11 @@ const sendToBOPS = async (req: Request, res: Response, next: NextFunction) => { // a local or staging API instance should send to the BOPS staging endpoint // production should send to the BOPS production endpoint const localAuthority = req.params.localAuthority; - const bopsSubmissionURLEnvName = `BOPS_SUBMISSION_URL_${localAuthority.toUpperCase()}`; - const bopsSubmissionURL = process.env[bopsSubmissionURLEnvName]; + const env = process.env.NODE_ENV === "production" ? "production" : "staging"; + const bopsSubmissionURL = await $api.team.getBopsSubmissionURL( + localAuthority, + env, + ); const isSupported = Boolean(bopsSubmissionURL); if (!isSupported) { return next( @@ -175,9 +178,21 @@ const sendToBOPSV2 = async ( // a local or staging API instance should send to the BOPS staging endpoint // production should send to the BOPS production endpoint const localAuthority = req.params.localAuthority; - const bopsSubmissionURLEnvName = `BOPS_SUBMISSION_URL_${localAuthority.toUpperCase()}`; - const bopsSubmissionURL = process.env[bopsSubmissionURLEnvName]; + const env = process.env.NODE_ENV === "production" ? "production" : "staging"; + const bopsSubmissionURL = await $api.team.getBopsSubmissionURL( + localAuthority, + env, + ); const isSupported = Boolean(bopsSubmissionURL); + if (!isSupported) { + return next( + new ServerError({ + status: 400, + message: `Back-office Planning System (BOPS) is not enabled for this local authority (${localAuthority})`, + }), + ); + } + if (!isSupported) { return next( new ServerError({ diff --git a/api.planx.uk/server.ts b/api.planx.uk/server.ts index 89d4f6f335..9c0d7b9d61 100644 --- a/api.planx.uk/server.ts +++ b/api.planx.uk/server.ts @@ -76,11 +76,6 @@ app.use(helmet()); assert(process.env.GOVUK_NOTIFY_API_KEY); assert(process.env.HASURA_PLANX_API_KEY); assert(process.env.BOPS_API_TOKEN); -assert(process.env.BOPS_SUBMISSION_URL_LAMBETH); -assert(process.env.BOPS_SUBMISSION_URL_BUCKINGHAMSHIRE); -assert(process.env.BOPS_SUBMISSION_URL_SOUTHWARK); -assert(process.env.BOPS_SUBMISSION_URL_CAMDEN); -assert(process.env.BOPS_SUBMISSION_URL_GLOUCESTER); assert(process.env.UNIFORM_TOKEN_URL); assert(process.env.UNIFORM_SUBMISSION_URL); diff --git a/docker-compose.e2e.yml b/docker-compose.e2e.yml index a3d09eba89..b3ce738817 100644 --- a/docker-compose.e2e.yml +++ b/docker-compose.e2e.yml @@ -29,5 +29,4 @@ services: 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} - BOPS_SUBMISSION_URL_E2E: http://mock-server:8080 \ No newline at end of file + GOV_UK_PAY_TOKEN_E2E: ${GOV_UK_PAY_TOKEN_E2E} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9bbc48cc2a..abc75db0af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -145,21 +145,14 @@ services: # Lambeth GOV_UK_PAY_TOKEN_LAMBETH: ${GOV_UK_PAY_TOKEN_LAMBETH} UNIFORM_CLIENT_LAMBETH: ${UNIFORM_CLIENT_LAMBETH} - BOPS_SUBMISSION_URL_LAMBETH: ${BOPS_SUBMISSION_URL_LAMBETH} # Southwark GOV_UK_PAY_TOKEN_SOUTHWARK: ${GOV_UK_PAY_TOKEN_SOUTHWARK} UNIFORM_CLIENT_SOUTHWARK: ${UNIFORM_CLIENT_SOUTHWARK} - BOPS_SUBMISSION_URL_SOUTHWARK: ${BOPS_SUBMISSION_URL_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} - BOPS_SUBMISSION_URL_BUCKINGHAMSHIRE: ${BOPS_SUBMISSION_URL_BUCKINGHAMSHIRE} - # Camden - BOPS_SUBMISSION_URL_CAMDEN: ${BOPS_SUBMISSION_URL_CAMDEN} - # Gloucester - BOPS_SUBMISSION_URL_GLOUCESTER: ${BOPS_SUBMISSION_URL_GLOUCESTER} sharedb: restart: unless-stopped diff --git a/e2e/tests/api-driven/src/invite-to-pay/helpers.ts b/e2e/tests/api-driven/src/invite-to-pay/helpers.ts index bb906a1656..e736da0b39 100644 --- a/e2e/tests/api-driven/src/invite-to-pay/helpers.ts +++ b/e2e/tests/api-driven/src/invite-to-pay/helpers.ts @@ -14,6 +14,7 @@ import { import { $admin } from "../client"; import { TEST_EMAIL } from "../../../ui-driven/src/globalHelpers"; import { createTeam, createUser } from "../globalHelpers"; +import gql from "graphql-tag"; export async function setUpMocks() { const serverMockFile = readFileSync(`${__dirname}/mocks/server-mocks.yaml`); @@ -159,12 +160,37 @@ export async function cleanup({ } } +const setupMockBopsSubmissionUrl = async (teamId: number) => { + await $admin.client.request( + gql` + mutation SetupTeamIntegrationE2E( + $staging_bops_submission_url: String + $team_id: Int + ) { + insert_team_integrations_one( + object: { + teamId: $team_id + stagingBopsSubmissionUrl: $staging_bops_submission_url + } + ) { + id + } + } + `, + { + teamId, + stagingBopsSubmissionUrl: "http://mock-server:8080", + }, + ); +}; + export const setup = async () => { await setUpMocks(); - const world = { - teamId: await createTeam(), - userId: await createUser(), - }; + const teamId = await createTeam(); + const userId = await createUser(); + await setupMockBopsSubmissionUrl(teamId); + + const world = { teamId, userId }; return world; }; diff --git a/infrastructure/application/Pulumi.production.yaml b/infrastructure/application/Pulumi.production.yaml index 4107b674bd..a0807e1166 100644 --- a/infrastructure/application/Pulumi.production.yaml +++ b/infrastructure/application/Pulumi.production.yaml @@ -3,7 +3,6 @@ config: secure: AAABAE+ZtQZO26XlmfAS7tG1DkwQ+G5OP82Roe4EOuk/tG1bMsI= application:airbrake-project-key: secure: AAABAPIGB+gWevPn0SzWnuSuV1RmdwpLOlWKnu8cM/kxLfslvdCIRcU0n0M0XNJ3jwj4EdFn7/llsL1Kg2XnDA== - application:bops-api-root-domain: bops.services application:bops-api-token: secure: AAABALRtSjQMRjERtkHs6WBOI7MBMw4bFOuHO8qLLPe9Pfg8Nlbp61XalZA1pmXsRt/T+59fGcdqbKA5WRkOZVibhFo= application:cloudflare-zone-id: a9b9933f28e786ec4cfd4bb596f5a519 diff --git a/infrastructure/application/Pulumi.sandbox.yaml b/infrastructure/application/Pulumi.sandbox.yaml index 5ea7dbbf20..d3ac496e30 100644 --- a/infrastructure/application/Pulumi.sandbox.yaml +++ b/infrastructure/application/Pulumi.sandbox.yaml @@ -2,7 +2,6 @@ config: application:airbrake-project-id: "329753" application:airbrake-project-key: secure: AAABAO8NgmVNdkwajWpiKwi+dxGicFACbAQzK66FREUCp+OUbSRyNAb9dSQHq/n9fZb8xWBdvYBCQ9eBr2jqPQ== - application:bops-api-root-domain: bops-staging.services application:bops-api-token: secure: AAABAHLQf7CFOK073geL2TbTYycQCzPYUy3Xi66UniwIrTlOAqve2YBikJXzMJ2xS9v4dGUZMUmwUba0OpTz8KAMXJ8= application:cloudflare-zone-id: 9cdfc35484748e96b0ed2b1d303a694f diff --git a/infrastructure/application/Pulumi.staging.yaml b/infrastructure/application/Pulumi.staging.yaml index cf6881f3b3..704a18bfb8 100644 --- a/infrastructure/application/Pulumi.staging.yaml +++ b/infrastructure/application/Pulumi.staging.yaml @@ -3,7 +3,6 @@ config: secure: AAABABxcp8r3CZAw1kXuXkwPZ8cKRDQyOg4+gVvqzKuCFWb8BEU= application:airbrake-project-key: secure: AAABABujxMHxU8Abj4QpyQTz7bLt3AP2wBFaypVkDZ2khzc6eh6lHLljTEkzpLUncno3gNNDXnrmxzXvqKnQdQ== - application:bops-api-root-domain: bops-staging.services application:bops-api-token: secure: AAABAJx2KnnFeuEmwRB5VyE790TeYxiKmWFuVXVY8Lb7+HDNRYND8Pfd9d61zjwPzi9Jf2ZlT0OH++1MXYafhdQO28Y= application:cloudflare-zone-id: diff --git a/infrastructure/application/index.ts b/infrastructure/application/index.ts index ae7e1d2aed..20d25b2bcb 100644 --- a/infrastructure/application/index.ts +++ b/infrastructure/application/index.ts @@ -322,26 +322,6 @@ export = async () => { }, { name: "SESSION_SECRET", value: config.requireSecret("session-secret") }, { name: "API_URL_EXT", value: `https://api.${DOMAIN}` }, - { - name: "BOPS_SUBMISSION_URL_LAMBETH", - value: pulumi.interpolate`https://lambeth.${config.requireSecret("bops-api-root-domain")}`, - }, - { - name: "BOPS_SUBMISSION_URL_SOUTHWARK", - value: pulumi.interpolate`https://southwark.${config.requireSecret("bops-api-root-domain")}`, - }, - { - name: "BOPS_SUBMISSION_URL_BUCKINGHAMSHIRE", - value: pulumi.interpolate`https://buckinghamshire.${config.requireSecret("bops-api-root-domain")}`, - }, - { - name: "BOPS_SUBMISSION_URL_CAMDEN", - value: pulumi.interpolate`https://camden.${config.requireSecret("bops-api-root-domain")}`, - }, - { - name: "BOPS_SUBMISSION_URL_GLOUCESTER", - value: pulumi.interpolate`https://gloucester.${config.requireSecret("bops-api-root-domain")}`, - }, { name: "BOPS_API_TOKEN", value: config.requireSecret("bops-api-token") }, { name: "JWT_SECRET", value: config.requireSecret("jwt-secret") }, { name: "PORT", value: String(API_PORT) },