From 32e2f3b960b9608ae28a88f17c8794c05f10c75a Mon Sep 17 00:00:00 2001 From: ayeshalshukri1-nhs <112615598+ayeshalshukri1-nhs@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:20:55 +0100 Subject: [PATCH 1/3] WIP: empty strings and remove http url. --- src/eligibility_signposting_api/views/eligibility.py | 4 ++-- .../views/response_model/eligibility.py | 7 ++++--- tests/fixtures/builders/model/eligibility.py | 2 +- tests/unit/views/test_eligibility.py | 12 ++++++------ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/eligibility_signposting_api/views/eligibility.py b/src/eligibility_signposting_api/views/eligibility.py index 310c4e1eb..1ab59bbdf 100644 --- a/src/eligibility_signposting_api/views/eligibility.py +++ b/src/eligibility_signposting_api/views/eligibility.py @@ -140,8 +140,8 @@ def build_actions(condition: Condition) -> list[eligibility.Action] | None: description=eligibility.Description(action.action_description) if action.action_description is not None else None, - urlLink=eligibility.HttpUrl(action.url_link) if action.url_link is not None else None, - urlLabel=eligibility.UrlLabel(action.url_label) if action.url_label is not None else None, + urlLink=eligibility.UrlLink(action.url_link), + urlLabel=eligibility.UrlLabel(action.url_label), ) for action in condition.actions ] diff --git a/src/eligibility_signposting_api/views/response_model/eligibility.py b/src/eligibility_signposting_api/views/response_model/eligibility.py index 58af90904..c4d48b338 100644 --- a/src/eligibility_signposting_api/views/response_model/eligibility.py +++ b/src/eligibility_signposting_api/views/response_model/eligibility.py @@ -16,6 +16,7 @@ CohortCode = NewType("CohortCode", str) CohortText = NewType("CohortText", str) UrlLabel = NewType("UrlLabel", str) +UrlLink = NewType("UrlLink", str) class Status(StrEnum): @@ -49,9 +50,9 @@ class SuitabilityRule(BaseModel): class Action(BaseModel): action_type: ActionType = Field(..., alias="actionType") action_code: ActionCode = Field(..., alias="actionCode") - description: Description | None - url_link: HttpUrl | None = Field(..., alias="urlLink") - url_label: UrlLabel | None = Field(..., alias="urlLabel") + description: Description = Field(default="") + url_link: UrlLink = Field(default="", alias="urlLink" ) + url_label: UrlLabel = Field(default="", alias="urlLabel") model_config = {"populate_by_name": True} diff --git a/tests/fixtures/builders/model/eligibility.py b/tests/fixtures/builders/model/eligibility.py index aef3b0eaf..d86a8be03 100644 --- a/tests/fixtures/builders/model/eligibility.py +++ b/tests/fixtures/builders/model/eligibility.py @@ -10,7 +10,7 @@ class SuggestedActionFactory(DataclassFactory[eligibility.SuggestedAction]): - url_link = UrlLink(HttpUrl("https://test-example.com")) + url_link = UrlLink("https://test-example.com") class ConditionFactory(DataclassFactory[eligibility.Condition]): diff --git a/tests/unit/views/test_eligibility.py b/tests/unit/views/test_eligibility.py index c0b4c3fa7..be091da53 100644 --- a/tests/unit/views/test_eligibility.py +++ b/tests/unit/views/test_eligibility.py @@ -398,7 +398,7 @@ def test_no_suitability_rules_for_actionable(): action_type=ActionType("TYPE_A"), action_code=ActionCode("CODE123"), action_description=ActionDescription("Some description"), - url_link=UrlLink(HttpUrl("https://example.com")), + url_link=UrlLink("https://example.com"), url_label=UrlLabel("Learn more"), ) ], @@ -407,7 +407,7 @@ def test_no_suitability_rules_for_actionable(): actionType=eligibility.ActionType("TYPE_A"), actionCode=eligibility.ActionCode("CODE123"), description=eligibility.Description("Some description"), - urlLink=eligibility.HttpUrl("https://example.com"), + urlLink=eligibility.UrlLink("https://example.com"), urlLabel=eligibility.UrlLabel("Learn more"), ) ], @@ -426,9 +426,9 @@ def test_no_suitability_rules_for_actionable(): eligibility.Action( actionType=eligibility.ActionType("TYPE_B"), actionCode=eligibility.ActionCode("CODE123"), - description=None, - urlLink=None, - urlLabel=None, + description="", + urlLink="", + urlLabel="", ) ], ), @@ -654,7 +654,7 @@ def test_build_response_include_values_that_are_not_null(client: FlaskClient): actionType=eligibility.ActionType("TYPE_A"), actionCode=eligibility.ActionCode("CODE123"), description=eligibility.Description("Contact GP"), - urlLink=eligibility.HttpUrl(HttpUrl("https://example.dummy/")), + urlLink=eligibility.UrlLink("https://example.dummy/"), urlLabel=eligibility.UrlLabel("GP contact"), ) ], From 5677a0bbce221ca0964be72755142073b0e5836a Mon Sep 17 00:00:00 2001 From: ayeshalshukri1-nhs <112615598+ayeshalshukri1-nhs@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:24:46 +0100 Subject: [PATCH 2/3] WIP --- src/eligibility_signposting_api/views/eligibility.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/eligibility_signposting_api/views/eligibility.py b/src/eligibility_signposting_api/views/eligibility.py index 1ab59bbdf..7a873e0e2 100644 --- a/src/eligibility_signposting_api/views/eligibility.py +++ b/src/eligibility_signposting_api/views/eligibility.py @@ -137,9 +137,7 @@ def build_actions(condition: Condition) -> list[eligibility.Action] | None: eligibility.Action( actionType=eligibility.ActionType(action.action_type), actionCode=eligibility.ActionCode(action.action_code), - description=eligibility.Description(action.action_description) - if action.action_description is not None - else None, + description=eligibility.Description(action.action_description), urlLink=eligibility.UrlLink(action.url_link), urlLabel=eligibility.UrlLabel(action.url_label), ) From 47decfe1c671e4c9d8c85efc57a83ea4a1ee3c6e Mon Sep 17 00:00:00 2001 From: Shweta <216860557+shweta-nhs@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:49:12 +0100 Subject: [PATCH 3/3] Sets url and description to empty when unavailable --- .../views/eligibility.py | 6 ++-- .../views/response_model/eligibility.py | 8 ++--- tests/fixtures/builders/model/eligibility.py | 1 - .../in_process/test_eligibility_endpoint.py | 30 +++++++++++++++++-- tests/unit/views/test_eligibility.py | 13 ++++---- 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/eligibility_signposting_api/views/eligibility.py b/src/eligibility_signposting_api/views/eligibility.py index 7a873e0e2..17432ce50 100644 --- a/src/eligibility_signposting_api/views/eligibility.py +++ b/src/eligibility_signposting_api/views/eligibility.py @@ -137,9 +137,9 @@ def build_actions(condition: Condition) -> list[eligibility.Action] | None: eligibility.Action( actionType=eligibility.ActionType(action.action_type), actionCode=eligibility.ActionCode(action.action_code), - description=eligibility.Description(action.action_description), - urlLink=eligibility.UrlLink(action.url_link), - urlLabel=eligibility.UrlLabel(action.url_label), + description=eligibility.Description(action.action_description or ""), + urlLabel=eligibility.UrlLabel(action.url_label or ""), + urlLink=eligibility.UrlLink(str(action.url_link)) if action.url_link else eligibility.UrlLink(""), ) for action in condition.actions ] diff --git a/src/eligibility_signposting_api/views/response_model/eligibility.py b/src/eligibility_signposting_api/views/response_model/eligibility.py index c4d48b338..20c5b64d9 100644 --- a/src/eligibility_signposting_api/views/response_model/eligibility.py +++ b/src/eligibility_signposting_api/views/response_model/eligibility.py @@ -2,7 +2,7 @@ from enum import StrEnum from typing import NewType -from pydantic import UUID4, BaseModel, Field, HttpUrl, field_serializer +from pydantic import UUID4, BaseModel, Field, field_serializer from pydantic_core.core_schema import SerializationInfo LastUpdated = NewType("LastUpdated", datetime) @@ -50,9 +50,9 @@ class SuitabilityRule(BaseModel): class Action(BaseModel): action_type: ActionType = Field(..., alias="actionType") action_code: ActionCode = Field(..., alias="actionCode") - description: Description = Field(default="") - url_link: UrlLink = Field(default="", alias="urlLink" ) - url_label: UrlLabel = Field(default="", alias="urlLabel") + description: Description = Field(default=Description("")) + url_link: UrlLink = Field(default=UrlLink(""), alias="urlLink") + url_label: UrlLabel = Field(default=UrlLabel(""), alias="urlLabel") model_config = {"populate_by_name": True} diff --git a/tests/fixtures/builders/model/eligibility.py b/tests/fixtures/builders/model/eligibility.py index d86a8be03..a1fd81f7d 100644 --- a/tests/fixtures/builders/model/eligibility.py +++ b/tests/fixtures/builders/model/eligibility.py @@ -3,7 +3,6 @@ from polyfactory import Use from polyfactory.factories import DataclassFactory -from pydantic import HttpUrl from eligibility_signposting_api.model import eligibility from eligibility_signposting_api.model.eligibility import UrlLink diff --git a/tests/integration/in_process/test_eligibility_endpoint.py b/tests/integration/in_process/test_eligibility_endpoint.py index 833b0b758..0a97e474d 100644 --- a/tests/integration/in_process/test_eligibility_endpoint.py +++ b/tests/integration/in_process/test_eligibility_endpoint.py @@ -218,7 +218,15 @@ def test_actionable( "cohortText": "positive_description", } ], - "actions": [{"actionType": "defaultcomms", "actionCode": "action_code"}], + "actions": [ + { + "actionCode": "action_code", + "actionType": "defaultcomms", + "description": "", + "urlLabel": "", + "urlLink": "", + } + ], "suitabilityRules": [], "statusText": "Status.actionable", } @@ -355,7 +363,15 @@ def test_actionable_when_only_magic_cohort_is_present( "cohortText": "magic positive description", } ], - "actions": [{"actionType": "defaultcomms", "actionCode": "action_code"}], + "actions": [ + { + "actionCode": "action_code", + "actionType": "defaultcomms", + "description": "", + "urlLabel": "", + "urlLink": "", + } + ], "suitabilityRules": [], "statusText": "Status.actionable", } @@ -511,7 +527,15 @@ def test_actionable( "condition": "FLU", "status": "Actionable", "eligibilityCohorts": [], - "actions": [{"actionCode": "action_code", "actionType": "defaultcomms"}], + "actions": [ + { + "actionCode": "action_code", + "actionType": "defaultcomms", + "description": "", + "urlLabel": "", + "urlLink": "", + } + ], "suitabilityRules": [], "statusText": "Status.actionable", } diff --git a/tests/unit/views/test_eligibility.py b/tests/unit/views/test_eligibility.py index be091da53..ec8d7e2ed 100644 --- a/tests/unit/views/test_eligibility.py +++ b/tests/unit/views/test_eligibility.py @@ -11,7 +11,6 @@ from flask import Flask, Request from flask.testing import FlaskClient from hamcrest import assert_that, contains_exactly, has_entries, has_length, is_, none -from pydantic import HttpUrl from wireup.integration.flask import get_app_container from eligibility_signposting_api.audit.audit_service import AuditService @@ -601,9 +600,9 @@ def test_excludes_nulls_via_build_response(client: FlaskClient): eligibility.Action( actionType=eligibility.ActionType("TYPE_A"), actionCode=eligibility.ActionCode("CODE123"), - description=None, # Should be excluded - urlLink=None, # Should be excluded - urlLabel=None, # Should be excluded + description=eligibility.Description(""), # Should be an empty string + urlLink=eligibility.UrlLink(""), # Should be an empty string + urlLabel=eligibility.UrlLabel(""), # Should be an empty string ) ], ) @@ -633,9 +632,9 @@ def test_excludes_nulls_via_build_response(client: FlaskClient): assert action["actionType"] == "TYPE_A" assert action["actionCode"] == "CODE123" - assert "description" not in action - assert "urlLink" not in action - assert "urlLabel" not in action + assert action["description"] == "" + assert action["urlLink"] == "" + assert action["urlLabel"] == "" def test_build_response_include_values_that_are_not_null(client: FlaskClient):