Skip to content

Commit 5de4c4a

Browse files
committed
Convert audit_log into camelCase when writing record to firehose
1 parent 2e27d5d commit 5de4c4a

4 files changed

Lines changed: 124 additions & 127 deletions

File tree

src/eligibility_signposting_api/audit_context.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
from dataclasses import asdict
32
from datetime import UTC, datetime
43
from operator import attrgetter
54
from uuid import UUID
@@ -100,7 +99,9 @@ def append_audit_condition(
10099
)
101100

102101
if best_candidate and best_candidate.status and best_candidate.status.name == Status.actionable.name:
103-
audit_redirect_rule = AuditRedirectRule(str(redirect_rule_details[0]), redirect_rule_details[1])
102+
audit_redirect_rule = AuditRedirectRule(
103+
rule_priority=str(redirect_rule_details[0]), rule_name=redirect_rule_details[1]
104+
)
104105

105106
if suggested_actions is None:
106107
audit_actions = None
@@ -142,4 +143,4 @@ def add_response_details(response_id: UUID, last_updated: datetime) -> None:
142143

143144
@staticmethod
144145
def write_to_firehose(service: AuditService) -> None:
145-
service.audit(asdict(g.audit_log))
146+
service.audit(g.audit_log.model_dump(by_alias=True))
Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,65 @@
1-
from dataclasses import dataclass, field
21
from datetime import UTC, datetime
32
from uuid import UUID
43

4+
from pydantic import BaseModel, ConfigDict, Field
5+
from pydantic.alias_generators import to_camel
56

6-
@dataclass
7-
class RequestAuditHeader:
7+
8+
class CamelCaseBaseModel(BaseModel):
9+
model_config = ConfigDict(
10+
alias_generator=to_camel,
11+
populate_by_name=True,
12+
)
13+
14+
15+
class RequestAuditHeader(CamelCaseBaseModel):
816
x_request_id: str | None = None
917
x_correlation_id: str | None = None
1018
nhsd_end_user_organisation_ods: str | None = None
1119
nhsd_application_id: str | None = None
1220

1321

14-
@dataclass
15-
class RequestAuditQueryParams:
22+
class RequestAuditQueryParams(CamelCaseBaseModel):
1623
category: str | None = None
1724
conditions: str | None = None
1825
include_actions: str | None = None
1926

2027

21-
@dataclass
22-
class RequestAuditData:
23-
request_timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))
24-
headers: RequestAuditHeader = field(default_factory=RequestAuditHeader)
25-
query_params: RequestAuditQueryParams = field(default_factory=RequestAuditQueryParams)
28+
class RequestAuditData(CamelCaseBaseModel):
29+
request_timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))
30+
headers: RequestAuditHeader = Field(default_factory=RequestAuditHeader)
31+
query_params: RequestAuditQueryParams = Field(default_factory=RequestAuditQueryParams)
2632
nhs_number: str | None = None
2733

2834

29-
@dataclass
30-
class AuditEligibilityCohorts:
35+
class AuditEligibilityCohorts(CamelCaseBaseModel):
3136
cohort_code: str | None = None
3237
cohort_status: str | None = None
3338

3439

35-
@dataclass
36-
class AuditEligibilityCohortGroups:
40+
class AuditEligibilityCohortGroups(CamelCaseBaseModel):
3741
cohort_code: str | None = None
3842
cohort_text: str | None = None
3943
cohort_status: str | None = None
4044

4145

42-
@dataclass
43-
class AuditFilterRule:
46+
class AuditFilterRule(CamelCaseBaseModel):
4447
rule_priority: str | None = None
4548
rule_name: str | None = None
4649

4750

48-
@dataclass
49-
class AuditSuitabilityRule:
51+
class AuditSuitabilityRule(CamelCaseBaseModel):
5052
rule_priority: str | None = None
5153
rule_name: str | None = None
5254
rule_message: str | None = None
5355

5456

55-
@dataclass
56-
class AuditRedirectRule:
57+
class AuditRedirectRule(CamelCaseBaseModel):
5758
rule_priority: str | None = None
5859
rule_name: str | None = None
5960

6061

61-
@dataclass
62-
class AuditAction:
62+
class AuditAction(CamelCaseBaseModel):
6363
internal_action_code: str | None = None
6464
action_type: str | None = None
6565
action_code: str | None = None
@@ -68,8 +68,7 @@ class AuditAction:
6868
action_url_label: str | None = None
6969

7070

71-
@dataclass
72-
class AuditCondition:
71+
class AuditCondition(CamelCaseBaseModel):
7372
campaign_id: str | None = None
7473
campaign_version: str | None = None
7574
iteration_id: str | None = None
@@ -82,17 +81,15 @@ class AuditCondition:
8281
filter_rules: AuditFilterRule | None = None
8382
suitability_rules: AuditSuitabilityRule | None = None
8483
action_rule: AuditRedirectRule | None = None
85-
actions: list[AuditAction] | None = field(default_factory=list)
84+
actions: list[AuditAction] | None = Field(default_factory=list)
8685

8786

88-
@dataclass
89-
class ResponseAuditData:
87+
class ResponseAuditData(CamelCaseBaseModel):
9088
response_id: UUID | None = None
9189
last_updated: str | None = None
92-
condition: list[AuditCondition] = field(default_factory=list)
90+
condition: list[AuditCondition] = Field(default_factory=list)
9391

9492

95-
@dataclass
96-
class AuditEvent:
97-
request: RequestAuditData = field(default_factory=RequestAuditData)
98-
response: ResponseAuditData = field(default_factory=ResponseAuditData)
93+
class AuditEvent(CamelCaseBaseModel):
94+
request: RequestAuditData = Field(default_factory=RequestAuditData)
95+
response: ResponseAuditData = Field(default_factory=ResponseAuditData)

tests/integration/lambda/test_app_running_as_lambda.py

Lines changed: 90 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -200,48 +200,48 @@ def test_given_nhs_number_in_path_matches_with_nhs_number_in_headers_and_check_i
200200
audit_data = json.loads(s3_client.get_object(Bucket=audit_bucket, Key=latest_key)["Body"].read())
201201

202202
expected_headers = {
203-
"x_request_id": "x_request_id",
204-
"x_correlation_id": "x_correlation_id",
205-
"nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods",
206-
"nhsd_application_id": "nhsd_application_id",
203+
"xRequestId": "x_request_id",
204+
"xCorrelationId": "x_correlation_id",
205+
"nhsdEndUserOrganisationOds": "nhsd_end_user_organisation_ods",
206+
"nhsdApplicationId": "nhsd_application_id",
207207
}
208-
expected_query_params = {"category": None, "conditions": None, "include_actions": "Y"}
209-
210-
assert_that(audit_data["request"]["request_timestamp"], is_not(equal_to("")))
211-
assert_that(audit_data["request"]["headers"], equal_to(expected_headers))
212-
assert_that(audit_data["request"]["nhs_number"], equal_to(persisted_person))
213-
assert_that(audit_data["request"]["query_params"], equal_to(expected_query_params))
208+
expected_query_params = {"category": None, "conditions": None, "includeActions": "Y"}
214209

215210
expected_conditions = [
216211
{
217-
"campaign_id": campaign_config.id,
218-
"campaign_version": campaign_config.version,
219-
"iteration_id": campaign_config.iterations[0].id,
220-
"iteration_version": campaign_config.iterations[0].version,
221-
"condition_name": campaign_config.target,
212+
"campaignId": campaign_config.id,
213+
"campaignVersion": campaign_config.version,
214+
"iterationId": campaign_config.iterations[0].id,
215+
"iterationVersion": campaign_config.iterations[0].version,
216+
"conditionName": campaign_config.target,
222217
"status": "not_actionable",
223-
"status_text": "not_actionable",
224-
"eligibility_cohorts": [{"cohort_code": "cohort_group1", "cohort_status": "not_actionable"}],
225-
"eligibility_cohort_groups": [
218+
"statusText": "not_actionable",
219+
"eligibilityCohorts": [{"cohortCode": "cohort_group1", "cohortStatus": "not_actionable"}],
220+
"eligibilityCohortGroups": [
226221
{
227-
"cohort_code": "cohort_group1",
228-
"cohort_text": "positive_description",
229-
"cohort_status": "not_actionable",
222+
"cohortCode": "cohort_group1",
223+
"cohortText": "positive_description",
224+
"cohortStatus": "not_actionable",
230225
}
231226
],
232-
"filter_rules": None,
233-
"suitability_rules": {
234-
"rule_priority": "10",
235-
"rule_name": "Exclude too young less than 75",
236-
"rule_message": "Exclude too young less than 75",
227+
"filterRules": None,
228+
"suitabilityRules": {
229+
"rulePriority": "10",
230+
"ruleName": "Exclude too young less than 75",
231+
"ruleMessage": "Exclude too young less than 75",
237232
},
238-
"action_rule": None,
233+
"actionRule": None,
239234
"actions": [],
240235
}
241236
]
242237

243-
assert_that(audit_data["response"]["response_id"], is_not(equal_to("")))
244-
assert_that(audit_data["response"]["last_updated"], is_not(equal_to("")))
238+
assert_that(audit_data["request"]["requestTimestamp"], is_not(equal_to("")))
239+
assert_that(audit_data["request"]["headers"], equal_to(expected_headers))
240+
assert_that(audit_data["request"]["nhsNumber"], equal_to(persisted_person))
241+
assert_that(audit_data["request"]["queryParams"], equal_to(expected_query_params))
242+
243+
assert_that(audit_data["response"]["responseId"], is_not(equal_to("")))
244+
assert_that(audit_data["response"]["lastUpdated"], is_not(equal_to("")))
245245
assert_that(audit_data["response"]["condition"], equal_to(expected_conditions))
246246

247247

@@ -303,100 +303,100 @@ def test_given_person_has_unique_status_for_different_conditions_with_audit( #
303303
audit_data = json.loads(s3_client.get_object(Bucket=audit_bucket, Key=latest_key)["Body"].read())
304304

305305
expected_headers = {
306-
"x_request_id": "x_request_id",
307-
"x_correlation_id": "x_correlation_id",
308-
"nhsd_end_user_organisation_ods": "nhsd_end_user_organisation_ods",
309-
"nhsd_application_id": "nhsd_application_id",
306+
"xRequestId": "x_request_id",
307+
"xCorrelationId": "x_correlation_id",
308+
"nhsdEndUserOrganisationOds": "nhsd_end_user_organisation_ods",
309+
"nhsdApplicationId": "nhsd_application_id",
310310
}
311-
expected_query_params = {"category": None, "conditions": None, "include_actions": "Y"}
311+
expected_query_params = {"category": None, "conditions": None, "includeActions": "Y"}
312312

313313
rsv_campaign = multiple_campaign_configs[0]
314314
covid_campaign = multiple_campaign_configs[1]
315315
flu_campaign = multiple_campaign_configs[2]
316316

317317
expected_conditions = [
318318
{
319-
"campaign_id": rsv_campaign.id,
320-
"campaign_version": rsv_campaign.version,
321-
"iteration_id": rsv_campaign.iterations[0].id,
322-
"iteration_version": rsv_campaign.iterations[0].version,
323-
"condition_name": rsv_campaign.target,
319+
"campaignId": rsv_campaign.id,
320+
"campaignVersion": rsv_campaign.version,
321+
"iterationId": rsv_campaign.iterations[0].id,
322+
"iterationVersion": rsv_campaign.iterations[0].version,
323+
"conditionName": rsv_campaign.target,
324324
"status": "not_eligible",
325-
"status_text": "not_eligible",
326-
"eligibility_cohorts": [{"cohort_code": "cohort_group1", "cohort_status": "not_eligible"}],
327-
"eligibility_cohort_groups": [
325+
"statusText": "not_eligible",
326+
"eligibilityCohorts": [{"cohortCode": "cohort_group1", "cohortStatus": "not_eligible"}],
327+
"eligibilityCohortGroups": [
328328
{
329-
"cohort_code": "cohort_group1",
330-
"cohort_text": "negative_desc_1",
331-
"cohort_status": "not_eligible",
329+
"cohortCode": "cohort_group1",
330+
"cohortText": "negative_desc_1",
331+
"cohortStatus": "not_eligible",
332332
}
333333
],
334-
"filter_rules": {"rule_priority": "10", "rule_name": "Exclude too young less than 75"},
335-
"suitability_rules": None,
336-
"action_rule": None,
334+
"filterRules": {"rulePriority": "10", "ruleName": "Exclude too young less than 75"},
335+
"suitabilityRules": None,
336+
"actionRule": None,
337337
"actions": [],
338338
},
339339
{
340-
"campaign_id": covid_campaign.id,
341-
"campaign_version": covid_campaign.version,
342-
"iteration_id": covid_campaign.iterations[0].id,
343-
"iteration_version": covid_campaign.iterations[0].version,
344-
"condition_name": covid_campaign.target,
340+
"campaignId": covid_campaign.id,
341+
"campaignVersion": covid_campaign.version,
342+
"iterationId": covid_campaign.iterations[0].id,
343+
"iterationVersion": covid_campaign.iterations[0].version,
344+
"conditionName": covid_campaign.target,
345345
"status": "not_actionable",
346-
"status_text": "not_actionable",
347-
"eligibility_cohorts": [{"cohort_code": "cohort_group2", "cohort_status": "not_actionable"}],
348-
"eligibility_cohort_groups": [
346+
"statusText": "not_actionable",
347+
"eligibilityCohorts": [{"cohortCode": "cohort_group2", "cohortStatus": "not_actionable"}],
348+
"eligibilityCohortGroups": [
349349
{
350-
"cohort_code": "cohort_group2",
351-
"cohort_text": "positive_desc_2",
352-
"cohort_status": "not_actionable",
350+
"cohortCode": "cohort_group2",
351+
"cohortText": "positive_desc_2",
352+
"cohortStatus": "not_actionable",
353353
}
354354
],
355-
"filter_rules": None,
356-
"suitability_rules": {
357-
"rule_priority": "10",
358-
"rule_name": "Exclude too young less than 75",
359-
"rule_message": "Exclude too young less than 75",
355+
"filterRules": None,
356+
"suitabilityRules": {
357+
"rulePriority": "10",
358+
"ruleName": "Exclude too young less than 75",
359+
"ruleMessage": "Exclude too young less than 75",
360360
},
361-
"action_rule": None,
361+
"actionRule": None,
362362
"actions": [],
363363
},
364364
{
365-
"campaign_id": flu_campaign.id,
366-
"campaign_version": flu_campaign.version,
367-
"iteration_id": flu_campaign.iterations[0].id,
368-
"iteration_version": flu_campaign.iterations[0].version,
369-
"condition_name": flu_campaign.target,
365+
"campaignId": flu_campaign.id,
366+
"campaignVersion": flu_campaign.version,
367+
"iterationId": flu_campaign.iterations[0].id,
368+
"iterationVersion": flu_campaign.iterations[0].version,
369+
"conditionName": flu_campaign.target,
370370
"status": "actionable",
371-
"status_text": "actionable",
372-
"eligibility_cohorts": [{"cohort_code": "cohort_group3", "cohort_status": "actionable"}],
373-
"eligibility_cohort_groups": [
371+
"statusText": "actionable",
372+
"eligibilityCohorts": [{"cohortCode": "cohort_group3", "cohortStatus": "actionable"}],
373+
"eligibilityCohortGroups": [
374374
{
375-
"cohort_code": "cohort_group3",
376-
"cohort_text": "positive_desc_3",
377-
"cohort_status": "actionable",
375+
"cohortCode": "cohort_group3",
376+
"cohortText": "positive_desc_3",
377+
"cohortStatus": "actionable",
378378
}
379379
],
380-
"filter_rules": None,
381-
"suitability_rules": None,
382-
"action_rule": {"rule_priority": "20", "rule_name": "In QE1"},
380+
"filterRules": None,
381+
"suitabilityRules": None,
382+
"actionRule": {"rulePriority": "20", "ruleName": "In QE1"},
383383
"actions": [
384384
{
385-
"internal_action_code": "defaultcomms",
386-
"action_type": "defaultcomms",
387-
"action_code": "action_code",
388-
"action_description": None,
389-
"action_url": None,
390-
"action_url_label": None,
385+
"internalActionCode": "defaultcomms",
386+
"actionType": "defaultcomms",
387+
"actionCode": "action_code",
388+
"actionDescription": None,
389+
"actionUrl": None,
390+
"actionUrlLabel": None,
391391
}
392392
],
393393
},
394394
]
395395

396-
assert_that(audit_data["request"]["request_timestamp"], is_not(equal_to("")))
396+
assert_that(audit_data["request"]["requestTimestamp"], is_not(equal_to("")))
397397
assert_that(audit_data["request"]["headers"], equal_to(expected_headers))
398-
assert_that(audit_data["request"]["nhs_number"], equal_to(persisted_person_all_cohorts))
399-
assert_that(audit_data["request"]["query_params"], equal_to(expected_query_params))
400-
assert_that(audit_data["response"]["response_id"], is_not(equal_to("")))
401-
assert_that(audit_data["response"]["last_updated"], is_not(equal_to("")))
398+
assert_that(audit_data["request"]["nhsNumber"], equal_to(persisted_person_all_cohorts))
399+
assert_that(audit_data["request"]["queryParams"], equal_to(expected_query_params))
400+
assert_that(audit_data["response"]["responseId"], is_not(equal_to("")))
401+
assert_that(audit_data["response"]["lastUpdated"], is_not(equal_to("")))
402402
assert_that(audit_data["response"]["condition"], contains_inanyorder(*expected_conditions))

tests/unit/test_audit_context.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import uuid
2-
from dataclasses import asdict
32
from datetime import UTC, datetime
43
from unittest.mock import Mock
54

@@ -190,4 +189,4 @@ def test_write_to_firehose_calls_audit_service_with_correct_data_from_g(app):
190189
assert g.audit_log.response.response_id == response_id
191190
assert g.audit_log.response.last_updated == last_updated
192191

193-
mock_audit_service.audit.assert_called_once_with(asdict(g.audit_log))
192+
mock_audit_service.audit.assert_called_once_with(g.audit_log.model_dump(by_alias=True))

0 commit comments

Comments
 (0)