Skip to content
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 2025-02-21
- [PI-754] Search Product
- Dependabot: datamodel-code-generator

## 2025-02-20
- [PI-790] Remove EPR from swagger

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2025.02.20
2025.02.21
2 changes: 2 additions & 0 deletions changelog/2025-02-21.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [PI-754] Search Product
- Dependabot: datamodel-code-generator
89 changes: 69 additions & 20 deletions infrastructure/swagger/05_paths.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ x-definitions:
tags:
- name: Core Product ID Endpoints
description: Create, Read and Delete Product IDs

- name: Options
description: These exist for CORS
paths:
/_status:
get:
Expand Down Expand Up @@ -44,6 +45,8 @@ paths:
options:
operationId: createproductteamcors
summary: Create a Product Team resource (OPTIONS)
tags:
- Options
responses:
"400":
$ref: "#/components/responses/BadRequest"
Expand Down Expand Up @@ -161,6 +164,8 @@ paths:
options:
operationId: createproductcors
summary: Create a Product resource (OPTIONS)
tags:
- Options
parameters:
- $ref: "#/components/parameters/ProductTeamId"
responses:
Expand Down Expand Up @@ -228,25 +233,69 @@ paths:
security:
- ${authoriser_name}: []
- app-level0: []
# get:
# operationId: searchCpmProduct
# summary: Retrieve all Products associated with a Product Team (GET)
# parameters:
# - $ref: "#/components/parameters/ProductTeamId"
# - $ref: "#/components/parameters/HeaderVersion"
# - $ref: "#/components/parameters/HeaderRequestId"
# - $ref: "#/components/parameters/HeaderCorrelationId"
# responses:
# "200":
# $ref: "#/components/responses/ProductSearch"
# "404":
# $ref: "#/components/responses/NotFound"
# x-amazon-apigateway-integration:
# <<: *ApiGatewayIntegration
# uri: ${method_searchCpmProduct}
# security:
# - ${authoriser_name}: []
# - app-level0: []

/Product:
options:
operationId: searchproductcors
summary: Search Products (OPTIONS)
tags:
- Options
responses:
"400":
$ref: "#/components/responses/BadRequest"
"200":
description: "200 response"
headers:
Access-Control-Allow-Origin:
schema:
type: "string"
Access-Control-Allow-Methods:
schema:
type: "string"
Access-Control-Allow-Headers:
schema:
type: "string"
content:
application/json:
schema:
$ref: "#/components/schemas/Empty"
x-amazon-apigateway-integration:
responses:
default:
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
method.response.header.Access-Control-Allow-Headers: "'apikey,authorization,content-type,version'"
method.response.header.Access-Control-Allow-Origin: "'*'"
requestTemplates:
application/json: '{"statusCode": 200}'
passthroughBehavior: "never"
type: "mock"
security:
- ${authoriser_name}: []
- app-level0: []
get:
operationId: searchProduct
summary: Retrieve all Products associated with a Product Team or Organisation (GET)
tags:
- Core Product ID Endpoints
parameters:
- $ref: "#/components/parameters/ProductTeamIdQuery"
- $ref: "#/components/parameters/OrganisationCodeQuery"
- $ref: "#/components/parameters/HeaderVersion"
- $ref: "#/components/parameters/HeaderRequestId"
- $ref: "#/components/parameters/HeaderCorrelationId"
responses:
"200":
$ref: "#/components/responses/ProductSearch"
"400":
$ref: "#/components/responses/SearchProductBadRequest"
x-amazon-apigateway-integration:
<<: *ApiGatewayIntegration
uri: ${method_searchProduct}
security:
- ${authoriser_name}: []
- app-level0: []

/ProductTeam/{product_team_id}/Product/{product_id}:
get:
Expand Down
75 changes: 75 additions & 0 deletions infrastructure/swagger/07_components--schemas--domain.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,78 @@ components:
example:
code: "RESOURCE_DELETED"
message: "P.XYZ-123 has been deleted."
ProductSearchResponse:
type: object
properties:
results:
type: array
items:
type: object
properties:
org_code:
type: string
product_teams:
type: array
items:
type: object
properties:
product_team_id:
type: string
products:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
product_team_id:
type: string
ods_code:
type: string
status:
type: string
keys:
type: array
items:
type: object
properties:
key_type:
type: string
key_value:
type: string
created_on:
type: string
updated_on:
type: string
nullable: true
deleted_on:
type: string
nullable: true
example:
results:
- org_code: "xyzzy"
product_teams:
- product_team_id: "1234"
products:
- id: "P.123"
product_team_id: "1234"
name: "My Great Product 1"
ods_code: "F5H1R"
status: "active"
created_on: "2024-10-15T10:00:00Z"
updated_on: "null"
deleted_on: "null"
keys: []
- product_team_id: "5678"
products:
- id: "P.xyz"
product_team_id: "5678"
name: "My Great Product 3"
ods_code: "F5H1R"
status: "active"
created_on: "2024-10-15T10:00:00Z"
updated_on: "null"
deleted_on: "null"
keys: []
25 changes: 25 additions & 0 deletions infrastructure/swagger/12_components--responses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@ components:
message: "Duplicate 'Interaction ID' provided: value '<INTERACTION ID>' occurs <N> times in the questionnaire response."
- code: "VALIDATION_ERROR"
message: "SubCpmProductPathParams.environment: value is not a valid enumeration member; permitted: 'dev', 'qa', 'ref', 'int', 'prod'"
SearchProductBadRequest:
description: searchProduct Bad request
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
ValidationError:
value:
errors:
- code: "VALIDATION_ERROR"
message: "SearchProductQueryParams.__root__: Please provide exactly one valid query parameter: {'product_team_id', 'organisation_code'}."
- code: "VALIDATION_ERROR"
message: "SearchSDSDeviceQueryParams.foo: extra fields not permitted"
headers:
Access-Control-Allow-Origin:
schema:
type: string
example: "*"
UnprocessableContent:
description: Unprocessable Content
content:
Expand Down Expand Up @@ -125,3 +144,9 @@ components:
application/json:
schema:
$ref: "#/components/schemas/CPMProductDeleteResponse"
ProductSearch:
description: Search Product operation successful
content:
application/json:
schema:
$ref: "#/components/schemas/ProductSearchResponse"
16 changes: 16 additions & 0 deletions infrastructure/swagger/13_components--parameters--query.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
---
components:
parameters:
ProductTeamIdQuery:
name: product_team_id
in: query
required: false
description: The ID of the product team to filter results by.
schema:
type: string
OrganisationCodeQuery:
name: organisation_code
in: query
required: false
description: The organisation code to filter results by.
schema:
type: string
2 changes: 1 addition & 1 deletion infrastructure/terraform/per_workspace/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ module "lambdas" {
}
}
environment_variables = {
DYNAMODB_TABLE = contains(["createProductTeam", "readProductTeam", "deleteProductTeam", "createCpmProduct", "readCpmProduct", "searchCpmProduct", "deleteCpmProduct"], each.key) ? module.cpmtable.dynamodb_table_name : module.eprtable.dynamodb_table_name
DYNAMODB_TABLE = contains(["createProductTeam", "readProductTeam", "deleteProductTeam", "createCpmProduct", "readCpmProduct", "searchProduct", "deleteCpmProduct"], each.key) ? module.cpmtable.dynamodb_table_name : module.eprtable.dynamodb_table_name
}
attach_policy_statements = length((fileset("${path.module}/../../../src/api/${each.key}/policies", "*.json"))) > 0
policy_statements = {
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "connecting-party-manager"
version = "2025.02.20"
version = "2025.02.21"
description = "Repository for the Connecting Party Manager API and related services"
authors = ["NHS England"]
license = "LICENSE.md"
Expand Down Expand Up @@ -41,7 +41,7 @@ hypothesis = "^6.87.3"
aws-lambda-powertools = { extras = ["aws-sdk"], version = "^2.26.0" }
parse = "^1.19.1"
pytest-mock = "^3.12.0"
datamodel-code-generator = "^0.26.0"
datamodel-code-generator = "^0.28.1"
pyyaml = "^6.0.1"
proxygen-cli = "^2.1.14"
moto = "^5.0.1"
Expand Down
5 changes: 4 additions & 1 deletion src/api/deleteProductTeam/src/v1/steps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from http import HTTPStatus

from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent
from domain.core.enum import Status
from domain.core.error import ConflictError
from domain.core.product_team import ProductTeam
from domain.repository.cpm_product_repository import CpmProductRepository
Expand Down Expand Up @@ -29,7 +30,9 @@ def read_products(data, cache):
product_repo = CpmProductRepository(
table_name=cache["DYNAMODB_TABLE"], dynamodb_client=cache["DYNAMODB_CLIENT"]
)
cpm_products = product_repo.search(product_team_id=product_team.id)
cpm_products = product_repo.search_by_product_team(
product_team_id=product_team.id, status=Status.ACTIVE
)

if cpm_products:
product_ids = [str(product.id) for product in cpm_products]
Expand Down
27 changes: 27 additions & 0 deletions src/api/searchProduct/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from api_utils.api_step_chain import execute_step_chain
from event.aws.client import dynamodb_client
from event.environment import BaseEnvironment
from event.logging.logger import setup_logger

from .src.v1.steps import steps as v1_steps


class Environment(BaseEnvironment):
DYNAMODB_TABLE: str


versioned_steps = {"1": v1_steps}
cache = {
**Environment.build().dict(),
"DYNAMODB_CLIENT": dynamodb_client(),
}


def handler(event: dict, context=None):
setup_logger(service_name=__file__)

return execute_step_chain(
event=event,
cache=cache,
versioned_steps=versioned_steps,
)
4 changes: 4 additions & 0 deletions src/api/searchProduct/make/make.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from builder.lambda_build import build

if __name__ == "__main__":
build(__file__)
1 change: 1 addition & 0 deletions src/api/searchProduct/policies/dynamodb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["dynamodb:Query"]
1 change: 1 addition & 0 deletions src/api/searchProduct/policies/kms.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["kms:Decrypt"]
Loading
Loading