|
12 | 12 |
|
13 | 13 | from controller.aws_apig_event_utils import ( |
14 | 14 | get_path_parameter, |
| 15 | + get_resource_version_header, |
15 | 16 | get_supplier_system_header, |
16 | 17 | ) |
17 | 18 | from controller.aws_apig_response_utils import create_response |
18 | 19 | from controller.constants import E_TAG_HEADER_NAME |
19 | 20 | from controller.fhir_api_exception_handler import fhir_api_exception_handler |
20 | 21 | from models.errors import ( |
21 | 22 | Code, |
22 | | - IdentifierDuplicationError, |
| 23 | + InconsistentIdError, |
23 | 24 | InvalidImmunizationId, |
24 | 25 | InvalidJsonError, |
| 26 | + InvalidResourceVersion, |
25 | 27 | ParameterException, |
26 | 28 | Severity, |
27 | 29 | UnauthorizedError, |
28 | 30 | UnauthorizedVaxError, |
29 | | - ValidationError, |
30 | 31 | create_operation_outcome, |
31 | 32 | ) |
32 | 33 | from models.utils.generic_utils import check_keys_in_sources |
@@ -124,189 +125,31 @@ def create_immunization(self, aws_event: APIGatewayProxyEventV1) -> dict: |
124 | 125 | headers={"Location": f"{self._API_SERVICE_URL}/Immunization/{created_resource_id}", "E-Tag": "1"}, |
125 | 126 | ) |
126 | 127 |
|
127 | | - def update_immunization(self, aws_event): |
128 | | - try: |
129 | | - if aws_event.get("headers"): |
130 | | - imms_id = aws_event["pathParameters"]["id"] |
131 | | - else: |
132 | | - raise UnauthorizedError() |
133 | | - except UnauthorizedError as unauthorized: |
134 | | - return create_response(403, unauthorized.to_operation_outcome()) |
135 | | - |
136 | | - supplier_system = self._identify_supplier_system(aws_event) |
| 128 | + @fhir_api_exception_handler |
| 129 | + def update_immunization(self, aws_event: APIGatewayProxyEventV1) -> dict: |
| 130 | + imms_id = get_path_parameter(aws_event, "id") |
| 131 | + supplier_system = get_supplier_system_header(aws_event) |
| 132 | + resource_version = get_resource_version_header(aws_event) |
137 | 133 |
|
138 | | - # Refactor to raise InvalidImmunizationId when working on VED-747 |
139 | 134 | if not self._is_valid_immunization_id(imms_id): |
140 | | - return create_response( |
141 | | - 400, |
142 | | - json.dumps( |
143 | | - create_operation_outcome( |
144 | | - resource_id=str(uuid.uuid4()), |
145 | | - severity=Severity.error, |
146 | | - code=Code.invalid, |
147 | | - diagnostics="Validation errors: the provided event ID is either missing or not in the expected " |
148 | | - "format.", |
149 | | - ) |
150 | | - ), |
151 | | - ) |
| 135 | + raise InvalidImmunizationId() |
152 | 136 |
|
153 | | - # Validate the body of the request - start |
154 | | - try: |
155 | | - imms = json.loads(aws_event["body"], parse_float=Decimal) |
156 | | - # Validate the imms id in the path params and body of request - start |
157 | | - if imms.get("id") != imms_id: |
158 | | - exp_error = create_operation_outcome( |
159 | | - resource_id=str(uuid.uuid4()), |
160 | | - severity=Severity.error, |
161 | | - code=Code.invariant, |
162 | | - diagnostics=( |
163 | | - f"Validation errors: The provided immunization id:{imms_id} doesn't match with the content of " |
164 | | - "the request body" |
165 | | - ), |
166 | | - ) |
167 | | - return create_response(400, json.dumps(exp_error)) |
168 | | - # Validate the imms id in the path params and body of request - end |
169 | | - except JSONDecodeError as e: |
170 | | - return self._create_bad_request(f"Request's body contains malformed JSON: {e}") |
171 | | - except Exception as e: |
172 | | - return self._create_bad_request(f"Request's body contains string: {e}") |
173 | | - # Validate the body of the request - end |
| 137 | + if not self._is_valid_resource_version(resource_version): |
| 138 | + raise InvalidResourceVersion(resource_version=resource_version) |
174 | 139 |
|
175 | | - # Validate if the imms resource does not exist - start |
176 | 140 | try: |
177 | | - existing_record = self.fhir_service.get_immunization_by_id_all(imms_id, imms) |
178 | | - if not existing_record: |
179 | | - exp_error = create_operation_outcome( |
180 | | - resource_id=str(uuid.uuid4()), |
181 | | - severity=Severity.error, |
182 | | - code=Code.not_found, |
183 | | - diagnostics=( |
184 | | - f"Validation errors: The requested immunization resource with id:{imms_id} was not found." |
185 | | - ), |
186 | | - ) |
187 | | - return create_response(404, json.dumps(exp_error)) |
188 | | - |
189 | | - if "diagnostics" in existing_record: |
190 | | - exp_error = create_operation_outcome( |
191 | | - resource_id=str(uuid.uuid4()), |
192 | | - severity=Severity.error, |
193 | | - code=Code.invariant, |
194 | | - diagnostics=existing_record["diagnostics"], |
195 | | - ) |
196 | | - return create_response(400, json.dumps(exp_error)) |
197 | | - except ValidationError as error: |
198 | | - return create_response(400, error.to_operation_outcome()) |
199 | | - # Validate if the imms resource does not exist - end |
| 141 | + immunization = json.loads(aws_event["body"], parse_float=Decimal) |
| 142 | + except JSONDecodeError as e: |
| 143 | + # Consider moving the start of the message into a const |
| 144 | + raise InvalidJsonError(message=str(f"Request's body contains malformed JSON: {e}")) |
200 | 145 |
|
201 | | - existing_resource_version = int(existing_record["Version"]) |
202 | | - existing_resource_vacc_type = existing_record["VaccineType"] |
| 146 | + if immunization.get("id") != imms_id: |
| 147 | + raise InconsistentIdError(imms_id=imms_id) |
203 | 148 |
|
204 | | - try: |
205 | | - # Validate if the imms resource to be updated is a logically deleted resource - start |
206 | | - if existing_record["DeletedAt"]: |
207 | | - outcome, resource, updated_version = self.fhir_service.reinstate_immunization( |
208 | | - imms_id, |
209 | | - imms, |
210 | | - existing_resource_version, |
211 | | - existing_resource_vacc_type, |
212 | | - supplier_system, |
213 | | - ) |
214 | | - # Validate if the imms resource to be updated is a logically deleted resource-end |
215 | | - else: |
216 | | - # Validate if imms resource version is part of the request - start |
217 | | - if "E-Tag" not in aws_event["headers"]: |
218 | | - exp_error = create_operation_outcome( |
219 | | - resource_id=str(uuid.uuid4()), |
220 | | - severity=Severity.error, |
221 | | - code=Code.invariant, |
222 | | - diagnostics=( |
223 | | - "Validation errors: Immunization resource version not specified in the request headers" |
224 | | - ), |
225 | | - ) |
226 | | - return create_response(400, json.dumps(exp_error)) |
227 | | - # Validate if imms resource version is part of the request - end |
228 | | - |
229 | | - # Validate the imms resource version provided in the request headers - start |
230 | | - try: |
231 | | - resource_version_header = int(aws_event["headers"]["E-Tag"]) |
232 | | - except (TypeError, ValueError): |
233 | | - resource_version = aws_event["headers"]["E-Tag"] |
234 | | - exp_error = create_operation_outcome( |
235 | | - resource_id=str(uuid.uuid4()), |
236 | | - severity=Severity.error, |
237 | | - code=Code.invariant, |
238 | | - diagnostics=( |
239 | | - f"Validation errors: Immunization resource version:{resource_version} in the request " |
240 | | - "headers is invalid." |
241 | | - ), |
242 | | - ) |
243 | | - return create_response(400, json.dumps(exp_error)) |
244 | | - # Validate the imms resource version provided in the request headers - end |
245 | | - |
246 | | - # Validate if resource version has changed since the last retrieve - start |
247 | | - if existing_resource_version > resource_version_header: |
248 | | - exp_error = create_operation_outcome( |
249 | | - resource_id=str(uuid.uuid4()), |
250 | | - severity=Severity.error, |
251 | | - code=Code.invariant, |
252 | | - diagnostics=( |
253 | | - f"Validation errors: The requested immunization resource {imms_id} has changed since the " |
254 | | - "last retrieve." |
255 | | - ), |
256 | | - ) |
257 | | - return create_response(400, json.dumps(exp_error)) |
258 | | - if existing_resource_version < resource_version_header: |
259 | | - exp_error = create_operation_outcome( |
260 | | - resource_id=str(uuid.uuid4()), |
261 | | - severity=Severity.error, |
262 | | - code=Code.invariant, |
263 | | - diagnostics=( |
264 | | - f"Validation errors: The requested immunization resource {imms_id} version is inconsistent " |
265 | | - "with the existing version." |
266 | | - ), |
267 | | - ) |
268 | | - return create_response(400, json.dumps(exp_error)) |
269 | | - # Validate if resource version has changed since the last retrieve - end |
270 | | - |
271 | | - # Check if the record is reinstated record - start |
272 | | - if existing_record["Reinstated"] is True: |
273 | | - outcome, resource, updated_version = self.fhir_service.update_reinstated_immunization( |
274 | | - imms_id, |
275 | | - imms, |
276 | | - existing_resource_version, |
277 | | - existing_resource_vacc_type, |
278 | | - supplier_system, |
279 | | - ) |
280 | | - else: |
281 | | - outcome, resource, updated_version = self.fhir_service.update_immunization( |
282 | | - imms_id, |
283 | | - imms, |
284 | | - existing_resource_version, |
285 | | - existing_resource_vacc_type, |
286 | | - supplier_system, |
287 | | - ) |
288 | | - |
289 | | - # Check if the record is reinstated record - end |
290 | | - |
291 | | - # Check for errors returned on update |
292 | | - if "diagnostics" in resource: |
293 | | - exp_error = create_operation_outcome( |
294 | | - resource_id=str(uuid.uuid4()), |
295 | | - severity=Severity.error, |
296 | | - code=Code.invariant, |
297 | | - diagnostics=resource["diagnostics"], |
298 | | - ) |
299 | | - return create_response(400, json.dumps(exp_error)) |
300 | | - if outcome: |
301 | | - return create_response( |
302 | | - 200, None, {"E-Tag": updated_version} |
303 | | - ) # include e-tag here, is it not included in the response resource |
304 | | - except ValidationError as error: |
305 | | - return create_response(400, error.to_operation_outcome()) |
306 | | - except IdentifierDuplicationError as duplicate: |
307 | | - return create_response(422, duplicate.to_operation_outcome()) |
308 | | - except UnauthorizedVaxError as unauthorized: |
309 | | - return create_response(403, unauthorized.to_operation_outcome()) |
| 149 | + updated_resource_version = self.fhir_service.update_immunization( |
| 150 | + imms_id, immunization, supplier_system, int(resource_version) |
| 151 | + ) |
| 152 | + return create_response(200, None, {E_TAG_HEADER_NAME: updated_resource_version}) |
310 | 153 |
|
311 | 154 | @fhir_api_exception_handler |
312 | 155 | def delete_immunization(self, aws_event: APIGatewayProxyEventV1) -> dict: |
@@ -385,6 +228,10 @@ def _is_valid_immunization_id(self, immunization_id: str) -> bool: |
385 | 228 | """Validates if the given unique Immunization ID is valid.""" |
386 | 229 | return False if not re.match(self._IMMUNIZATION_ID_PATTERN, immunization_id) else True |
387 | 230 |
|
| 231 | + @staticmethod |
| 232 | + def _is_valid_resource_version(resource_version: str) -> bool: |
| 233 | + return resource_version.isdigit() and int(resource_version) > 0 |
| 234 | + |
388 | 235 | def _validate_identifier_system(self, _id: str, _elements: str) -> Optional[dict]: |
389 | 236 | if not _id: |
390 | 237 | return create_operation_outcome( |
|
0 commit comments