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

Fix: [AEA-4403] - use epsat to talk proxygen api #3152

Merged
merged 23 commits into from
Feb 7, 2025
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
6 changes: 6 additions & 0 deletions .gitallowed
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ super\(\"1\.2

# snapshots are fine
^[a-f0-9]{40}:?packages\/tool\/site\/client\/tests\/pages\/__snapshots__\/.*snap
^packages\/tool\/site\/client\/tests\/pages\/__snapshots__\/.*snap

# CONFIG.sessionKey is fine
CONFIG.sessionKey

# files that no longer exist or have been moved
^[a-f0-9]{40}:.*sds-api\/spine-directory-service\/sds\/lookup\/tests\/data\/my_real_server_schema\.json
Expand Down Expand Up @@ -338,6 +342,8 @@ super\(\"1\.2
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/app\.ts:65
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/app\.ts:87
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/app\.ts:227
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/app\.ts:54
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/app\.ts:76
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/routes\/api\/send\.ts:150
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/routes\/auth\/refresh\.ts:12
^[a-f0-9]{40}:packages\/tool\/site\/server\/src\/routes\/sign\/downloadSignatures\.ts:29
Expand Down
1 change: 1 addition & 0 deletions .github/scripts/deploy_api.sh
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ echo "Removing dummy paths before publishing spec"
jq 'del(."paths"."/FHIR/R4/$process-message")' "$SPEC_PATH" > temp.json && mv temp.json "${SPEC_PATH}"
jq 'del(."paths"."/FHIR/R4//FHIR/R4/Task")' "$SPEC_PATH" > temp.json && mv temp.json "${SPEC_PATH}"
jq 'del(."paths"."/FHIR/R4/$validate")' "$SPEC_PATH" > temp.json && mv temp.json "${SPEC_PATH}"
jq 'del(."paths"."/FHIR/R4/$convert")' "$SPEC_PATH" > temp.json && mv temp.json "${SPEC_PATH}"

if [[ "${APIGEE_ENVIRONMENT}" == "int" ]]; then
echo
Expand Down
16 changes: 16 additions & 0 deletions packages/specification/fhir-prescribing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,22 @@ paths:
$ref: examples/spec/errors/example-a-validation-error-missing-field/Response-FhirError.json
security:
- nhs-cis2-aal3: []
/FHIR/R4/$convert :
post:
operationId: convert
summary: dummy operation for path
description: |
this is a dummy method so things go to the backend correctly
parameters:
- $ref: "#/components/parameters/BearerAuthorization"
- $ref: "#/components/parameters/RoleId"
- $ref: "#/components/parameters/RequestID"
- $ref: "#/components/parameters/CorrelationID"
responses:
"200":
description: "Dummy response"
security:
- nhs-cis2-aal3: []

components:
securitySchemes:
Expand Down
3 changes: 0 additions & 3 deletions packages/tool/azure/azure-release-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,12 @@ extends:
proxy_path: sandbox
- environment: internal-qa
depends_on:
- internal_dev
- qa_manual_approval
- environment: sandbox
proxy_path: sandbox
depends_on:
- internal_qa
- ptl_manual_approval
- environment: int
proxy_path: live
depends_on:
- internal_qa
- ptl_manual_approval
13 changes: 0 additions & 13 deletions packages/tool/e2e-tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ export async function getElement(

export async function sendPrescriptionUserJourney(driver: ThenableWebDriver): Promise<string> {
await loginViaSimulatedAuthSmartcardUser(driver)
await setMockSigningConfig(driver)
await createPrescription(driver)
await loadPredefinedExamplePrescription(driver)
await sendPrescription(driver)
Expand All @@ -101,7 +100,6 @@ export async function sendPrescriptionUserJourney(driver: ThenableWebDriver): Pr

export async function sendBulkPrescriptionUserJourney(driver: ThenableWebDriver, fileInfo: FileUploadInfo, successfulResultCountExpected: number): Promise<void> {
await loginViaSimulatedAuthSmartcardUser(driver)
await setMockSigningConfig(driver)
await createPrescription(driver)
await loadTestData(driver, fileInfo)
await sendPrescription(driver)
Expand All @@ -123,7 +121,6 @@ export async function prescriptionIntoCanceledState(driver: ThenableWebDriver, f

export async function sendPrescriptionSingleMessageUserJourney(driver: ThenableWebDriver, fileUploadInfo: FileUploadInfo): Promise<string> {
await loginViaSimulatedAuthSmartcardUser(driver)
await setMockSigningConfig(driver)
await createPrescription(driver)
await loadTestData(driver, fileUploadInfo)
await sendPrescription(driver)
Expand Down Expand Up @@ -354,16 +351,6 @@ export async function sendPrescription(driver: ThenableWebDriver): Promise<void>
finaliseWebAction(driver, "SENDING PRESCRIPTION...")
}

export async function setMockSigningConfig(driver: ThenableWebDriver): Promise<void> {
await (await getElement(driver, configLink)).click()
await driver.wait(until.elementLocated(configPageTitle))
await waitForPageToRender()

await (await getElement(driver, By.name("useSigningMock"))).click()
await (await getElement(driver, configButton)).click()
await (await getElement(driver, backButton)).click()
}

export async function checkApiResult(driver: ThenableWebDriver, fhirOnly?: boolean): Promise<void> {
await driver.wait(until.elementsLocated(fhirRequestExpander), apiTimeout)
if (!fhirOnly) {
Expand Down
2 changes: 0 additions & 2 deletions packages/tool/e2e-tests/prescribe/editPrescription.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
loadPredefinedExamplePrescription,
loginViaSimulatedAuthSmartcardUser,
sendPrescription,
setMockSigningConfig,
tenTimesDefaultWaitTimeout,
viewPrescriptionUserJourney,
waitForPageToRender
Expand All @@ -29,7 +28,6 @@ async function editPrescriptionOrganisationUserJourney(
newOrganisation: string
): Promise<void> {
await loginViaSimulatedAuthSmartcardUser(driver)
await setMockSigningConfig(driver)
await createPrescription(driver)
await loadPredefinedExamplePrescription(driver)
await editPrescriptionOrganisation(driver, newOrganisation)
Expand Down
4 changes: 2 additions & 2 deletions packages/tool/site/client/src/components/pageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from "react"
import {useContext} from "react"
import {Header, Images} from "nhsuk-react-components"
import {AppContext} from "../index"
import {isInternalDev, isInternalDevSandbox, isQa, isSandbox} from "../services/environment"
import {isSandbox} from "../services/environment"
import SessionTimer from "./sessionTimer"
import styled from "styled-components"

Expand All @@ -22,7 +22,7 @@ export const PageHeader: React.FC<PageHeaderProps> = ({loggedIn}) => {
<Header transactional>
<Header.Container>
<Header.Logo href={baseUrl} />
{loggedIn && (isInternalDev(environment) || isInternalDevSandbox(environment) || isQa(environment)) ? (
{loggedIn ? (
<Header.ServiceName href={`${baseUrl}config`}>
<div className="inline-flex">
EPSAT - Electronic Prescription Service API Tool
Expand Down
78 changes: 62 additions & 16 deletions packages/tool/site/client/src/pages/configPage.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import * as React from "react"
import {useContext, useState} from "react"
import {useContext, useState, useEffect} from "react"
import {Label, Button, Fieldset, Form, Checkboxes, TextInput} from "nhsuk-react-components"
import {AppContext} from "../index"
import ButtonList from "../components/common/buttonList"
import {Field, Formik} from "formik"
import {axiosInstance} from "../requests/axiosInstance"
import BackButton from "../components/common/backButton"
import SuccessOrFail from "../components/common/successOrFail"
import { isInternalDev, isInternalDevSandbox, isQa } from "../services/environment"

interface ConfigFormValues {
useSigningMock: boolean
useProxygen: boolean
epsPrNumber: string
signingPrNumber: string
}
Expand All @@ -18,10 +20,40 @@ interface ConfigResponse {
success: boolean
}

interface ConfigDetails {
useSigningMock: boolean,
epsPrNumber: string,
signingPrNumber: string,
useProxygen: boolean
}

const ConfigPage: React.FC = () => {
const {baseUrl} = useContext(AppContext)
const {baseUrl, environment} = useContext(AppContext)
const [configUpdateSuccess, setConfigUpdateSuccess] = useState(undefined)
const initialValues = {useSigningMock: false, epsPrNumber: "", signingPrNumber: ""}
const [configValues, setConfigValues] = useState({useSigningMock: false, epsPrNumber: "", signingPrNumber: "", useProxygen: false})
const initialValues = {
useSigningMock: configValues.useSigningMock,
epsPrNumber: configValues.epsPrNumber,
signingPrNumber: configValues.signingPrNumber,
useProxygen: configValues.useProxygen
}
const isDevOrQa = isInternalDev(environment) || isInternalDevSandbox(environment) || isQa(environment)


useEffect(() => {
axiosInstance.get(`${baseUrl}getconfig`)
.then(response => {
if (response.status === 200) {
const configDetails = response.data
if (configDetails.hasOwnProperty("useSigningMock") &&
configDetails.hasOwnProperty("epsPrNumber") &&
configDetails.hasOwnProperty("signingPrNumber") &&
configDetails.hasOwnProperty("useProxygen")) {
setConfigValues(response.data)
}
}
})
}, [])

if (configUpdateSuccess !== undefined) {
return <>
Expand All @@ -32,31 +64,45 @@ const ConfigPage: React.FC = () => {
</>
}


return (
<>
<Label isPageHeading>Config</Label>
<Formik<ConfigFormValues>
initialValues={initialValues}
onSubmit={values => updateConfig(baseUrl, values, setConfigUpdateSuccess)}
>
enableReinitialize={true}>
{formik =>
<Form onSubmit={formik.handleSubmit} onReset={formik.handleReset}>
<Label bold>EPS</Label>
<Fieldset>
<Field
id="epsPrNumber"
name="epsPrNumber"
as={TextInput}
width={30}
label="EPS PR Number"
/>
<Label bold>Signing</Label>
<Checkboxes id="useSigningMockCheckboxes">
<Field id="useSigningMock" name="useSigningMock" type="checkbox" as={Checkboxes.Box}>
Use Signing Mock
{isDevOrQa &&
<Field
id="epsPrNumber"
name="epsPrNumber"
as={TextInput}
width={30}
label="EPS PR Number"
/>
}
<Label bold>Use Proxygen</Label>
<Checkboxes id="useProxygen">
<Field id="useProxygen" name="useProxygen" type="checkbox" as={Checkboxes.Box}>
Use Proxygen deployed APIs
</Field>
</Checkboxes>
{!formik.values.useSigningMock &&
{isDevOrQa &&
<Label bold>Signing</Label>
}

{isDevOrQa &&
<Checkboxes id="useSigningMockCheckboxes">
<Field id="useSigningMock" name="useSigningMock" type="checkbox" as={Checkboxes.Box}>
Use Signing Mock
</Field>
</Checkboxes>
}
{!formik.values.useSigningMock && isDevOrQa &&
<Field
id="signingPrNumber"
name="signingPrNumber"
Expand Down
14 changes: 13 additions & 1 deletion packages/tool/site/client/src/pages/loginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useState} from "react"
import React, {useContext, useEffect, useState} from "react"
import {Button, Label} from "nhsuk-react-components"
import {AppContext} from "../index"
import {axiosInstance} from "../requests/axiosInstance"
Expand All @@ -10,6 +10,12 @@ const LoginPage: React.FC<{separateAuth?: string}> = ({separateAuth}) => {
const {baseUrl, environment} = useContext(AppContext)

const [mockAuthSelected, setMockAuthSelected] = useState(false)

useEffect(() => {
if (isInternalDev(environment)) {
setDefaultDevConfig(baseUrl)
}
}, [])

if (isInt(environment)) {
makeLoginRequest(baseUrl, separateAuth ? "user-separate" : "user-combined")
Expand Down Expand Up @@ -55,4 +61,10 @@ const makeLoginRequest = async (baseUrl: string, authLevel: string) => {
redirect(`${response.data.redirectUri}`)
}

async function setDefaultDevConfig(
baseUrl: string
): Promise<void> {
const defaultDevConfig = {useSigningMock: true, epsPrNumber: "", signingPrNumber: "", useProxygen: false}
await axiosInstance.post(`${baseUrl}config`, defaultDevConfig)
}
export default LoginPage
17 changes: 15 additions & 2 deletions packages/tool/site/client/src/requests/axiosInstance.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import axios from "axios"
import axios, {InternalAxiosRequestConfig} from "axios"
import {v4 as uuidv4} from "uuid"

export const axiosInstance = axios.create({
const axiosInstance = axios.create({
validateStatus: () => true
})

axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
config.headers["x-correlation-id"] = uuidv4()
return config
},
(error) => {
return Promise.reject(Error(error))
}
)

export {axiosInstance}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Header renders when logged in 1`] = `
"<header class="nhsuk-header nhsuk-header__transactional" role="banner">
<div class="nhsuk-width-container nhsuk-header__container">
<div class="nhsuk-header__logo nhsuk-header__transactional--logo"><a class="nhsuk-header__link" aria-label="NHS homepage" href="/"><svg class="nhsuk-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 16" height="40" width="100" aria-labelledby="nhsuk-logo_title">
<title id="nhsuk-logo_title">NHS Logo</title>
<path class="nhsuk-logo__background" d="M0 0h40v16H0z" fill="#005eb8"></path>
<path class="nhsuk-logo__text" fill="#fff" d="M3.9 1.5h4.4l2.6 9h.1l1.8-9h3.3l-2.8 13H9l-2.7-9h-.1l-1.8 9H1.1M17.3 1.5h3.6l-1 4.9h4L25 1.5h3.5l-2.7 13h-3.5l1.1-5.6h-4.1l-1.2 5.6h-3.4M37.7 4.4c-.7-.3-1.6-.6-2.9-.6-1.4 0-2.5.2-2.5 1.3 0 1.8 5.1 1.2 5.1 5.1 0 3.6-3.3 4.5-6.4 4.5-1.3 0-2.9-.3-4-.7l.8-2.7c.7.4 2.1.7 3.2.7s2.8-.2 2.8-1.5c0-2.1-5.1-1.3-5.1-5 0-3.4 2.9-4.4 5.8-4.4 1.6 0 3.1.2 4 .6"></path>
</svg></a></div>
<div class="nhsuk-header__transactional-service-name"><a class="nhsuk-header__transactional-service-name--link" href="/config">
<div class="inline-flex">EPSAT - Electronic Prescription Service API Tool<figure class="nhsuk-image"><img class="nhsuk-image__img sc-jtQUzJ fSmwEJ" srcset="/static/Cogs_SVG_White.svg" sizes="50px"></figure>
</div>
</a></div>
</div>
<div class="nhsuk-navigation-container">
<nav class="nhsuk-navigation" id="header-navigation" role="navigation">
<ul class="nhsuk-header__navigation-list nhsuk-header__navigation-list--left-aligned">
<li class="nhsuk-header__navigation-item"><a class="nhsuk-header__navigation-link" href="/">Home</a></li>
<li class="nhsuk-header__navigation-item"><a class="nhsuk-header__navigation-link" href="/my-prescriptions">My Prescriptions</a></li>
<li class="nhsuk-header__navigation-item"><a class="nhsuk-header__navigation-link" href="/logout">Logout</a></li>
</ul>
</nav>
</div>
</header>"
`;

exports[`Header renders when not logged in 1`] = `
"<header class="nhsuk-header nhsuk-header__transactional" role="banner">
<div class="nhsuk-width-container nhsuk-header__container">
<div class="nhsuk-header__logo nhsuk-header__transactional--logo"><a class="nhsuk-header__link" aria-label="NHS homepage" href="/"><svg class="nhsuk-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 16" height="40" width="100" aria-labelledby="nhsuk-logo_title">
<title id="nhsuk-logo_title">NHS Logo</title>
<path class="nhsuk-logo__background" d="M0 0h40v16H0z" fill="#005eb8"></path>
<path class="nhsuk-logo__text" fill="#fff" d="M3.9 1.5h4.4l2.6 9h.1l1.8-9h3.3l-2.8 13H9l-2.7-9h-.1l-1.8 9H1.1M17.3 1.5h3.6l-1 4.9h4L25 1.5h3.5l-2.7 13h-3.5l1.1-5.6h-4.1l-1.2 5.6h-3.4M37.7 4.4c-.7-.3-1.6-.6-2.9-.6-1.4 0-2.5.2-2.5 1.3 0 1.8 5.1 1.2 5.1 5.1 0 3.6-3.3 4.5-6.4 4.5-1.3 0-2.9-.3-4-.7l.8-2.7c.7.4 2.1.7 3.2.7s2.8-.2 2.8-1.5c0-2.1-5.1-1.3-5.1-5 0-3.4 2.9-4.4 5.8-4.4 1.6 0 3.1.2 4 .6"></path>
</svg></a></div>
<div class="nhsuk-header__transactional-service-name"><a class="nhsuk-header__transactional-service-name--link" href="/">EPSAT - Electronic Prescription Service API Tool</a></div>
</div>
</header>"
`;
32 changes: 32 additions & 0 deletions packages/tool/site/client/tests/components/pageHeader.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {render} from "@testing-library/react"
import {screen} from "@testing-library/dom"
import pretty from "pretty"
import * as React from "react"
import {PageHeader} from "../../src/components/pageHeader"
import {expect} from "@jest/globals"
import {MemoryRouter} from "react-router-dom"

test("Header renders when logged in", async () => {
const {container} = render(
<MemoryRouter>
<PageHeader loggedIn={true}/>
</MemoryRouter>
)

expect(screen.getByText("My Prescriptions")).toBeTruthy()

expect(pretty(container.innerHTML)).toMatchSnapshot()
})

test("Header renders when not logged in", async () => {
const {container} = render(
<MemoryRouter>
<PageHeader loggedIn={false}/>
</MemoryRouter>
)

expect(screen.queryByText("My Prescriptions")).toBeNull()

expect(pretty(container.innerHTML)).toMatchSnapshot()
})

Loading