Skip to content

Commit 7db75d2

Browse files
authored
Merge branch 'master' into VED-350-Dose-Unit-Code-Validation
2 parents a4204e8 + dade8a7 commit 7db75d2

24 files changed

+578
-250
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
if: github.ref == 'refs/heads/master'
99
steps:
1010
- name: Checkout
11-
uses: actions/checkout@v4
11+
uses: actions/checkout@v5
1212
with:
1313
fetch-depth: 0 # This causes all history to be fetched, which is required for calculate-version to function
1414

.github/workflows/deploy-template.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
run: aws sts get-caller-identity
2525

2626
- name: Checkout
27-
uses: actions/checkout@v4
27+
uses: actions/checkout@v5
2828
with:
2929
fetch-depth: 1
3030

@@ -53,7 +53,7 @@ jobs:
5353
name: int
5454
steps:
5555
- name: Checkout
56-
uses: actions/checkout@v4
56+
uses: actions/checkout@v5
5757

5858
- uses: aws-actions/configure-aws-credentials@v4
5959
with:
@@ -85,7 +85,7 @@ jobs:
8585
contents: read
8686
steps:
8787
- name: Checkout
88-
uses: actions/checkout@v4
88+
uses: actions/checkout@v5
8989

9090
- uses: aws-actions/configure-aws-credentials@v4
9191
with:

.github/workflows/sonarcloud.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
runs-on: ubuntu-latest
1818

1919
steps:
20-
- uses: actions/checkout@v4
20+
- uses: actions/checkout@v5
2121
with:
2222
fetch-depth: 0
2323

backend/poetry.lock

Lines changed: 184 additions & 176 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/fhir_batch_repository.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import boto3
44
import time
55
import simplejson as json
6+
from clients import logger
67
from dataclasses import dataclass
78
import botocore.exceptions
89
from boto3.dynamodb.conditions import Key, Attr
@@ -34,7 +35,7 @@ def _query_identifier(table, index, pk, identifier, is_present):
3435
return queryresponse
3536

3637
if retries > 6:
37-
print(f"{identifier}: Crossed {retries} retries")
38+
logger.info(f"{identifier}: Crossed {retries} retries")
3839

3940
retries += 1
4041
# Delay time in milliseconds

backend/src/fhir_controller.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from aws_lambda_typing.events import APIGatewayProxyEventV1
1111
from fhir.resources.R4B.immunization import Immunization
1212
from boto3 import client as boto3_client
13+
from clients import logger
1314

1415
from authorization import Authorization, UnknownPermission
1516
from fhir_repository import ImmunizationRepository, create_table
@@ -625,7 +626,7 @@ def check_vaccine_type_permissions(self, aws_event):
625626
if len(supplier_system) == 0:
626627
raise UnauthorizedSystemError()
627628
imms_vax_type_perms = get_supplier_permissions(supplier_system)
628-
print(f" update imms = {imms_vax_type_perms}")
629+
logger.info(f" update imms = {imms_vax_type_perms}")
629630
if len(imms_vax_type_perms) == 0:
630631
raise UnauthorizedVaxError()
631632
# Return the values needed for later use

backend/src/fhir_repository.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from urllib import response
2+
from responses import logger
13
import simplejson as json
24
import os
35
import time
@@ -397,20 +399,46 @@ def find_immunizations(self, patient_identifier: str, vaccine_types: list):
397399
condition = Key("PatientPK").eq(_make_patient_pk(patient_identifier))
398400
is_not_deleted = Attr("DeletedAt").not_exists() | Attr("DeletedAt").eq("reinstated")
399401

400-
response = self.table.query(
401-
IndexName="PatientGSI",
402-
KeyConditionExpression=condition,
403-
FilterExpression=is_not_deleted,
404-
)
402+
raw_items = self.get_all_items(condition, is_not_deleted)
405403

406-
if "Items" in response:
404+
if raw_items:
407405
# Filter the response to contain only the requested vaccine types
408-
items = [x for x in response["Items"] if x["PatientSK"].split("#")[0] in vaccine_types]
406+
items = [x for x in raw_items if x["PatientSK"].split("#")[0] in vaccine_types]
409407

410408
# Return a list of the FHIR immunization resource JSON items
411-
return [json.loads(item["Resource"]) for item in items]
409+
final_resources = [json.loads(item["Resource"]) for item in items]
410+
411+
return final_resources
412412
else:
413-
raise UnhandledResponseError(message=f"Unhandled error. Query failed", response=response)
413+
logger.warning("no items matched patient_identifier filter!")
414+
return []
415+
416+
def get_all_items(self, condition, is_not_deleted):
417+
"""Query DynamoDB and paginate through all results."""
418+
all_items = []
419+
last_evaluated_key = None
420+
421+
while True:
422+
query_args = {
423+
"IndexName": "PatientGSI",
424+
"KeyConditionExpression": condition,
425+
"FilterExpression": is_not_deleted,
426+
}
427+
if last_evaluated_key:
428+
query_args["ExclusiveStartKey"] = last_evaluated_key
429+
430+
response = self.table.query(**query_args)
431+
if "Items" not in response:
432+
raise UnhandledResponseError(message="No Items in DynamoDB response", response=response)
433+
434+
items = response.get("Items", [])
435+
all_items.extend(items)
436+
437+
last_evaluated_key = response.get("LastEvaluatedKey")
438+
if not last_evaluated_key:
439+
break
440+
441+
return all_items
414442

415443
@staticmethod
416444
def _handle_dynamo_response(response):

backend/src/log_structure.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,47 @@
66

77
from log_firehose import FirehoseLogger
88

9+
from models.utils.validation_utils import get_vaccine_type
10+
911
logging.basicConfig()
1012
logger = logging.getLogger()
1113
logger.setLevel("INFO")
1214

1315

1416
firehose_logger = FirehoseLogger()
1517

18+
def _log_data_from_body(event) -> dict:
19+
log_data = {}
20+
if event.get("body") is None:
21+
return log_data
22+
try:
23+
imms = json.loads(event["body"])
24+
except json.decoder.JSONDecodeError:
25+
return log_data
26+
try:
27+
vaccine_type = get_vaccine_type(imms)
28+
log_data["vaccine_type"] = vaccine_type
29+
except Exception:
30+
pass
31+
try:
32+
local_id = imms["identifier"][0]["value"] + "^" + imms["identifier"][0]["system"]
33+
log_data["local_id"] = local_id
34+
except Exception:
35+
pass
36+
return log_data
37+
1638

1739
def function_info(func):
1840
"""This decorator prints the execution information for the decorated function."""
1941

2042
@wraps(func)
2143
def wrapper(*args, **kwargs):
2244
event = args[0] if args else {}
23-
print(f"Event: {event}")
45+
logger.info(f"Event: {event}")
2446
headers = event.get("headers", {})
2547
correlation_id = headers.get("X-Correlation-ID", "X-Correlation-ID not passed")
2648
request_id = headers.get("X-Request-ID", "X-Request-ID not passed")
49+
supplier_system = headers.get("SupplierSystem", "SupplierSystem not passed")
2750
actual_path = event.get("path", "Unknown")
2851
resource_path = event.get("requestContext", {}).get("resourcePath", "Unknown")
2952
logger.info(f"Starting {func.__name__} with X-Correlation-ID: {correlation_id} and X-Request-ID: {request_id}")
@@ -32,6 +55,7 @@ def wrapper(*args, **kwargs):
3255
"date_time": str(datetime.now()),
3356
"X-Correlation-ID": correlation_id,
3457
"X-Request-ID": request_id,
58+
"supplier": supplier_system,
3559
"actual_path": actual_path,
3660
"resource_path": resource_path,
3761
}
@@ -40,9 +64,10 @@ def wrapper(*args, **kwargs):
4064
start = time.time()
4165
try:
4266
result = func(*args, **kwargs)
43-
print(f"Result:{result}")
67+
logger.info(f"Result:{result}")
4468
end = time.time()
4569
log_data["time_taken"] = f"{round(end - start, 5)}s"
70+
log_data.update(_log_data_from_body(event))
4671
status = "500"
4772
status_code = "Exception"
4873
diagnostics = str()
@@ -56,7 +81,7 @@ def wrapper(*args, **kwargs):
5681
record = result_headers["Location"]
5782
if result.get("body"):
5883
ops_outcome = json.loads(result["body"])
59-
print(f"ops_outcome: {ops_outcome}")
84+
logger.info(f"ops_outcome: {ops_outcome}")
6085
if ops_outcome.get("issue"):
6186
outcome_body = ops_outcome["issue"][0]
6287
status_code = outcome_body["code"]
@@ -78,6 +103,7 @@ def wrapper(*args, **kwargs):
78103
log_data["error"] = str(e)
79104
end = time.time()
80105
log_data["time_taken"] = f"{round(end - start, 5)}s"
106+
log_data.update(_log_data_from_body(event))
81107
logger.exception(json.dumps(log_data))
82108
firehose_log["event"] = log_data
83109
firehose_logger.send_log(firehose_log)

backend/src/models/utils/permission_checker.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from enum import StrEnum
2+
from clients import logger
23

34
class ApiOperationCode(StrEnum):
45
CREATE = "c"
@@ -22,7 +23,7 @@ def _expand_permissions(permissions: list[str]) -> dict[str, list[ApiOperationCo
2223

2324
def validate_permissions(permissions: list[str], operation: ApiOperationCode, vaccine_types: list[str]):
2425
expanded_permissions = _expand_permissions(permissions)
25-
print(f"operation: {operation}, expanded_permissions: {expanded_permissions}, vaccine_types: {vaccine_types}")
26+
logger.info(f"operation: {operation}, expanded_permissions: {expanded_permissions}, vaccine_types: {vaccine_types}")
2627
return all(
2728
operation in expanded_permissions.get(vaccine_type.lower(), [])
2829
for vaccine_type in vaccine_types

backend/src/parameter_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Optional
77
from urllib.parse import parse_qs, urlencode, quote
88

9-
from clients import redis_client
9+
from clients import redis_client, logger
1010
from models.errors import ParameterException
1111
from models.constants import Constants
1212

0 commit comments

Comments
 (0)