-
Notifications
You must be signed in to change notification settings - Fork 1
[PRMP-1465] Post User Restriction #1131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
SWhyteAnswer
wants to merge
23
commits into
main
Choose a base branch
from
PRMP-1465
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
b5af10f
[PRMP-1464] introduce model, mock data, start implementing hcw api se…
steph-torres-nhs 2ca5d16
[PRMP-1464] implement get practitioner using hcw api
steph-torres-nhs 386ad9f
[PRMP-1464] remove comment
steph-torres-nhs dfe3a71
[PRMP-1464] add headers
steph-torres-nhs 646d908
[PRMP-1464] remove comment
steph-torres-nhs eb9416c
[PRMP-1444] cread user restrictions model
steph-torres-nhs ce7292e
[PRMP-1444] adjust ods code attribute
steph-torres-nhs ea03142
[PRMP-1444] update model
steph-torres-nhs ae7b929
[PRMP-1444] address pr comments
steph-torres-nhs 3f63d8a
[PRMP-1444] change status to is active
steph-torres-nhs 5f9e3d1
[PRMP-1444] ensure model aligns with table
steph-torres-nhs d0d7c40
[PRMP-1465] changes
SWhyteAnswer 3b82540
[PRMP-1465] changes
SWhyteAnswer aac606f
[PRMP-1464] tests
SWhyteAnswer 5b97c65
[PRMP-1465] changes
SWhyteAnswer 57cab4e
[PRMP-1465] edit comment
SWhyteAnswer 5af470e
[PRMP-1465] corrected db env
SWhyteAnswer 736b579
[PRMP-1465] new func for parse bod
SWhyteAnswer 0fb099b
[PRMP-1465] removing json check
SWhyteAnswer 295439d
[PRMP-1465] new util for ods/creator
SWhyteAnswer da3905c
[PRMP-1465] ods to cust
SWhyteAnswer e2edc22
[PRMP-1465] custom exception
SWhyteAnswer bc8fbc4
[PRMP-1465] response model
SWhyteAnswer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| import json | ||
|
|
||
| from pydantic import ValidationError | ||
| from services.post_user_restriction_service import PostUserRestrictionService | ||
| from utils.audit_logging_setup import LoggingService | ||
| from utils.decorators.ensure_env_var import ensure_environment_variables | ||
| from utils.decorators.handle_lambda_exceptions import handle_lambda_exceptions | ||
| from utils.decorators.override_error_check import override_error_check | ||
| from utils.decorators.set_audit_arg import set_request_context_for_logging | ||
| from utils.exceptions import HealthcareWorkerAPIException, HealthcareWorkerPractitionerModelException, OdsErrorException, UserRestrictionException | ||
| from utils.lambda_response import ApiGatewayResponse | ||
| from utils.ods_utils import extract_creator_and_ods_code_from_request_context | ||
|
|
||
| logger = LoggingService(__name__) | ||
|
|
||
|
|
||
| def parse_body(body: str | None) -> tuple[tuple[str, str] | None, object]: | ||
| if not body: | ||
| logger.error("Missing request body") | ||
| return None, ApiGatewayResponse( | ||
| 400, "Missing request body", "POST" | ||
| ).create_api_gateway_response() | ||
|
|
||
| payload = json.loads(body) | ||
|
|
||
| smart_card_id = payload.get("smart_card_id") | ||
| nhs_number = payload.get("nhs_number") | ||
| if not smart_card_id or not nhs_number: | ||
| logger.error("Missing required fields") | ||
| return None, ApiGatewayResponse( | ||
| 400, "Missing required fields", "POST" | ||
| ).create_api_gateway_response() | ||
|
|
||
| return (smart_card_id, nhs_number), None | ||
|
|
||
|
|
||
| @set_request_context_for_logging | ||
| @override_error_check | ||
| @ensure_environment_variables( | ||
| names=[ | ||
| "RESTRICTIONS_TABLE_NAME", | ||
| "HEALTHCARE_WORKER_API_URL", | ||
| ] | ||
| ) | ||
| @handle_lambda_exceptions | ||
| def lambda_handler(event, context): | ||
| logger.info("Starting create user restriction process") | ||
|
|
||
| parsed, error = parse_body(event.get("body")) | ||
| if error: | ||
| return error | ||
| smart_card_id, nhs_number = parsed | ||
|
|
||
| try: | ||
| creator, ods_code = extract_creator_and_ods_code_from_request_context() | ||
| except OdsErrorException: | ||
| logger.error("Missing user context") | ||
| return ApiGatewayResponse( | ||
| 400, "Missing user context", "POST" | ||
| ).create_api_gateway_response() | ||
|
|
||
| service = PostUserRestrictionService() | ||
| try: | ||
| response = service.create_restriction( | ||
| smart_card_id=smart_card_id, | ||
| nhs_number=nhs_number, | ||
| custodian=ods_code, | ||
| creator=creator, | ||
| ) | ||
| # Translate service validation errors into a 400 response. | ||
| except UserRestrictionException as exc: | ||
| logger.error(exc) | ||
| return ApiGatewayResponse( | ||
| 400, str(exc), "POST" | ||
| ).create_api_gateway_response() | ||
| except HealthcareWorkerAPIException as exc: | ||
| logger.error(exc) | ||
| return ApiGatewayResponse( | ||
| exc.status_code, exc.message, "POST" | ||
| ).create_api_gateway_response() | ||
| except HealthcareWorkerPractitionerModelException as exc: | ||
| logger.error(exc) | ||
| return ApiGatewayResponse( | ||
| 400, "Unable to process restricted user information", "POST" | ||
| ).create_api_gateway_response() | ||
| except ValidationError as exc: | ||
| logger.error(exc) | ||
| return ApiGatewayResponse( | ||
| 400, "Invalid request body", "POST" | ||
| ).create_api_gateway_response() | ||
|
|
||
| # Successful create returns the full restriction payload. | ||
| response_body = json.dumps(response.model_dump(by_alias=True)) | ||
|
|
||
| return ApiGatewayResponse( | ||
| 201, response_body, "POST" | ||
| ).create_api_gateway_response() |
Empty file.
34 changes: 34 additions & 0 deletions
34
lambdas/models/user_restrictions/user_restriction_response.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| from datetime import datetime, timezone | ||
|
|
||
| from pydantic import BaseModel, ConfigDict, Field | ||
| from pydantic.alias_generators import to_pascal | ||
|
|
||
|
|
||
| class UserRestrictionResponse(BaseModel): | ||
| model_config = ConfigDict( | ||
| validate_by_alias=True, | ||
| validate_by_name=True, | ||
| alias_generator=to_pascal, | ||
| populate_by_name=True, | ||
| ) | ||
|
|
||
| id: str = Field(alias="ID") | ||
| nhs_number: str = Field(alias="NHSNumber") | ||
| patient_name: str | None = None | ||
| restricted_smartcard_id: str | ||
| restricted_user_name: str | ||
| created: str | ||
|
|
||
| @classmethod | ||
| def from_restriction(cls, restriction, restricted_user_name: str) -> "UserRestrictionResponse": | ||
| created_iso = datetime.fromtimestamp( | ||
| restriction.created, tz=timezone.utc | ||
| ).strftime("%Y-%m-%dT%H:%M:%SZ") | ||
|
|
||
| return cls( | ||
| id=restriction.id, | ||
| nhs_number=restriction.nhs_number, | ||
| restricted_smartcard_id=restriction.restricted_user, | ||
| restricted_user_name=restricted_user_name, | ||
| created=created_iso, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import os | ||
|
|
||
| from models.user_restrictions.user_restriction_response import UserRestrictionResponse | ||
| from models.user_restrictions.user_restrictions import UserRestriction, UserRestrictionsFields | ||
| from services.base.dynamo_service import DynamoDBService | ||
| from services.user_restrictions.healthcare_worker_service import HealthCareWorkerApiService | ||
| from utils.audit_logging_setup import LoggingService | ||
| from utils.exceptions import UserRestrictionException | ||
|
|
||
| logger = LoggingService(__name__) | ||
|
|
||
|
|
||
| class PostUserRestrictionService: | ||
| def __init__(self): | ||
| self.table_name = os.getenv("RESTRICTIONS_TABLE_NAME") | ||
| self.db_service = DynamoDBService() | ||
| self.healthcare_service = HealthCareWorkerApiService() | ||
|
|
||
| def create_restriction( | ||
| self, | ||
| smart_card_id: str, | ||
| nhs_number: str, | ||
| custodian: str, | ||
| creator: str, | ||
| ) -> UserRestrictionResponse: | ||
| if smart_card_id == creator: | ||
| raise UserRestrictionException("You cannot create a restriction for yourself") | ||
|
|
||
| practitioner = self.healthcare_service.get_practitioner(smart_card_id) | ||
| restricted_user_name = f"{practitioner.first_name} {practitioner.last_name}" | ||
|
|
||
| # Build the domain model that will be persisted to DB. | ||
| restriction = UserRestriction( | ||
| restricted_user=smart_card_id, | ||
| nhs_number=nhs_number, | ||
| custodian=custodian, | ||
| creator=creator, | ||
| ) | ||
|
|
||
| # Persist the new restriction in the configured table. | ||
| self.db_service.create_item( | ||
| table_name=self.table_name, | ||
| item=restriction.model_dump(by_alias=True, exclude_none=True), | ||
| key_name=UserRestrictionsFields.ID.value, | ||
| ) | ||
|
|
||
| logger.info("Created user restriction") | ||
| return UserRestrictionResponse.from_restriction(restriction, restricted_user_name) | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
believe we are returning this the the frontend, may need to change what is returned from this function