Skip to content

Commit 7718325

Browse files
authored
Merge pull request #345 from NHSDigital/release/2024-10-07
Release/2024-10-07
2 parents a06bd64 + 922c6cd commit 7718325

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1275
-471
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 2024-10-07
4+
- [PI-505] Create EPR Product
5+
- [PI-538] Increase rate limiting
6+
- Dependabot: pre-commit
7+
38
## 2024-10-02
49
- [PI-497] Read a CPM Product
510
- [PI-543] Remove snapshot from etl

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2024.10.02
1+
2024.10.07

changelog/2024-10-07.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- [PI-505] Create EPR Product
2+
- [PI-538] Increase rate limiting
3+
- Dependabot: pre-commit

docs/public_swagger/swagger.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,52 @@ paths:
480480
application/fhir+json:
481481
schema:
482482
$ref: "#/components/schemas/OperationOutcome"
483+
/ProductTeam/{product_team_id}/Product/Epr:
484+
post:
485+
operationId: createproductforeprendpoint
486+
summary: createCpmProductForEpr endpoint for APIGEE integration
487+
parameters:
488+
- name: product_team_id
489+
in: path
490+
required: true
491+
description: logical identifier
492+
schema:
493+
type: string
494+
- in: header
495+
name: version
496+
schema:
497+
$ref: "#/components/schemas/Version"
498+
- in: header
499+
name: x-request-id
500+
schema:
501+
$ref: "#/components/schemas/RequestId"
502+
- in: header
503+
name: x-correlation-id
504+
schema:
505+
$ref: "#/components/schemas/CorrelationId"
506+
requestBody:
507+
required: true
508+
content:
509+
application/json:
510+
schema:
511+
type: object
512+
properties:
513+
product_name:
514+
type: string
515+
description: Name of the product
516+
responses:
517+
"201":
518+
description: Create operation successful
519+
content:
520+
application/fhir+json:
521+
schema:
522+
$ref: "#/components/schemas/OperationOutcome"
523+
"4XX":
524+
description: "Client Error"
525+
content:
526+
application/fhir+json:
527+
schema:
528+
$ref: "#/components/schemas/OperationOutcome"
483529
/searchSdsDevice:
484530
get:
485531
operationId: searchsdsdevice

infrastructure/swagger/04_apigee.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ x-nhsd-apim:
1414
type: apikey
1515
header: apikey
1616
secret: cpm-1 # NB: this is the *name* of the secret, not the value
17+
ratelimiting:
18+
proxy:
19+
timeunit: "minute"
20+
limit: 2000

infrastructure/swagger/05_paths.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,42 @@ paths:
226226
- ${authoriser_name}: []
227227
- app-level0: []
228228

229+
/ProductTeam/{product_team_id}/Product/Epr:
230+
post:
231+
operationId: createproductforeprendpoint
232+
summary: createCpmProductForEpr endpoint for APIGEE integration
233+
parameters:
234+
- name: product_team_id
235+
in: path
236+
required: true
237+
description: logical identifier
238+
schema:
239+
type: string
240+
- *RequestHeaderVersion
241+
- *RequestHeaderRequestId
242+
- *RequestHeaderCorrelationId
243+
requestBody:
244+
required: true
245+
content:
246+
application/json:
247+
schema:
248+
type: object
249+
properties:
250+
product_name:
251+
type: string
252+
description: Name of the product
253+
responses:
254+
"201":
255+
<<: *Response201
256+
"4XX":
257+
<<: *Response4XX
258+
x-amazon-apigateway-integration:
259+
<<: *ApiGatewayIntegration
260+
uri: ${method_createCpmProductForEpr}
261+
security:
262+
- ${authoriser_name}: []
263+
- app-level0: []
264+
229265
/Device:
230266
post:
231267
responses:

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "connecting-party-manager"
3-
version = "2024.10.02"
3+
version = "2024.10.07"
44
description = "Repository for the Connecting Party Manager API and related services"
55
authors = ["NHS England"]
66
license = "LICENSE.md"
@@ -29,7 +29,7 @@ attrs = "^24.2.0"
2929
locust = "^2.29.1"
3030

3131
[tool.poetry.group.dev.dependencies]
32-
pre-commit = "^3.4.0"
32+
pre-commit = "^4.0.0"
3333
black = "^24.1.1"
3434
flake8 = "^7.0.0"
3535
behave = "^1.2.6"

src/api/createCpmProduct/index.py

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
1-
from types import ModuleType
2-
3-
from api_utils.versioning.constants import VERSIONING_STEP_ARGS
4-
from api_utils.versioning.steps import (
5-
get_largest_possible_version,
6-
get_steps_for_requested_version,
7-
versioning_steps,
8-
)
9-
from domain.logging.step_decorators import logging_step_decorators
10-
from domain.response.steps import response_steps
1+
from api_utils.api_step_chain import execute_step_chain_with_location
112
from event.aws.client import dynamodb_client
123
from event.environment import BaseEnvironment
134
from event.logging.logger import setup_logger
14-
from event.step_chain import StepChain
155

166
from .src.v1.steps import steps as v1_steps
177

@@ -29,51 +19,8 @@ class Environment(BaseEnvironment):
2919

3020
def handler(event: dict, context=None):
3121
setup_logger(service_name=__file__)
32-
return execute_step_chain(
22+
return execute_step_chain_with_location(
3323
event=event,
3424
cache=cache,
3525
versioned_steps=versioned_steps,
3626
)
37-
38-
39-
STEP_DECORATORS = [*logging_step_decorators]
40-
41-
42-
def lower_case_keys(_dict: dict[str, str]):
43-
return {k.lower(): v for k, v in _dict.items()}
44-
45-
46-
def execute_step_chain(
47-
event: dict, cache: dict, versioned_steps: dict[str, ModuleType]
48-
):
49-
event["headers"] = lower_case_keys(event.get("headers", {}))
50-
51-
version_chain = StepChain(
52-
step_chain=versioning_steps, step_decorators=STEP_DECORATORS
53-
)
54-
version_chain.run(
55-
init={
56-
VERSIONING_STEP_ARGS.EVENT: event,
57-
VERSIONING_STEP_ARGS.VERSIONED_STEPS: versioned_steps,
58-
}
59-
)
60-
61-
version = None
62-
location = None
63-
if isinstance(version_chain.result, Exception):
64-
result = version_chain.result
65-
else:
66-
version = version_chain.data[get_largest_possible_version]
67-
steps = version_chain.data[get_steps_for_requested_version]
68-
api_chain = StepChain(step_chain=steps, step_decorators=STEP_DECORATORS)
69-
api_chain.run(cache=cache, init=event)
70-
if isinstance(api_chain.result, Exception):
71-
result = api_chain.result
72-
else:
73-
result, location = api_chain.result
74-
75-
response_chain = StepChain(
76-
step_chain=response_steps, step_decorators=STEP_DECORATORS
77-
)
78-
response_chain.run(init=(result, version, location))
79-
return response_chain.result
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
["dynamodb:Query", "dynamodb:PutItem"]
1+
["dynamodb:Query", "dynamodb:PutItem", "dynamodb:GetItem"]
Lines changed: 2 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,3 @@
1-
from http import HTTPStatus
1+
from domain.common_steps.create_product import after_steps, before_steps
22

3-
from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent
4-
from domain.core.cpm_product import CpmProduct
5-
from domain.core.cpm_system_id import ProductId
6-
from domain.core.product_team.v3 import ProductTeam
7-
from domain.repository.cpm_product_repository.v3 import CpmProductRepository
8-
from domain.repository.product_team_repository.v2 import ProductTeamRepository
9-
from domain.request_models.v1 import (
10-
CreateCpmProductIncomingParams,
11-
ProductTeamPathParams,
12-
)
13-
from domain.response.validation_errors import (
14-
InboundValidationError,
15-
mark_json_decode_errors_as_inbound,
16-
mark_validation_errors_as_inbound,
17-
)
18-
from event.step_chain import StepChain
19-
from pydantic import ValidationError
20-
21-
22-
@mark_validation_errors_as_inbound
23-
def parse_path_params(data, cache) -> ProductTeamPathParams:
24-
event = APIGatewayProxyEvent(data[StepChain.INIT])
25-
return ProductTeamPathParams(**event.path_parameters)
26-
27-
28-
@mark_json_decode_errors_as_inbound
29-
def parse_event_body(data, cache) -> dict:
30-
event = APIGatewayProxyEvent(data[StepChain.INIT])
31-
return event.json_body if event.body else {}
32-
33-
34-
def parse_incoming_cpm_product(data, cache) -> CreateCpmProductIncomingParams:
35-
json_body = data[parse_event_body]
36-
try:
37-
incoming_product = CreateCpmProductIncomingParams(**json_body)
38-
return incoming_product
39-
except ValidationError as exc:
40-
raise InboundValidationError(errors=exc.raw_errors, model=exc.model)
41-
42-
43-
def read_product_team(data, cache) -> ProductTeam:
44-
path_params: ProductTeamPathParams = data[parse_path_params]
45-
46-
product_team_repo = ProductTeamRepository(
47-
table_name=cache["DYNAMODB_TABLE"], dynamodb_client=cache["DYNAMODB_CLIENT"]
48-
)
49-
return product_team_repo.read(id=path_params.product_team_id)
50-
51-
52-
def generate_cpm_product_id(data, cache) -> str:
53-
generated_product_id = ProductId.create()
54-
return generated_product_id.id
55-
56-
57-
@mark_validation_errors_as_inbound
58-
def create_cpm_product(data, cache) -> CpmProduct:
59-
incoming_product = data[parse_incoming_cpm_product]
60-
product_team: ProductTeam = data[read_product_team]
61-
product_id = data[generate_cpm_product_id]
62-
product = product_team.create_cpm_product(
63-
product_id=product_id, name=incoming_product.product_name
64-
)
65-
return product
66-
67-
68-
def save_cpm_product(data, cache) -> dict:
69-
cpm_product = data[create_cpm_product]
70-
cpm_product_repo = CpmProductRepository(
71-
table_name=cache["DYNAMODB_TABLE"], dynamodb_client=cache["DYNAMODB_CLIENT"]
72-
)
73-
return cpm_product_repo.write(entity=cpm_product)
74-
75-
76-
def set_http_status(data, cache) -> tuple[HTTPStatus, str]:
77-
product: CpmProduct = data[create_cpm_product]
78-
return HTTPStatus.CREATED, str(product.id)
79-
80-
81-
steps = [
82-
parse_path_params,
83-
parse_event_body,
84-
parse_incoming_cpm_product,
85-
read_product_team,
86-
generate_cpm_product_id,
87-
create_cpm_product,
88-
save_cpm_product,
89-
set_http_status,
90-
]
3+
steps = [*before_steps, *after_steps]

0 commit comments

Comments
 (0)