1010from uuid import uuid4
1111
1212from audit_table import upsert_audit_table
13- from common .aws_s3_utils import move_file
13+ from common .aws_s3_utils import move_file , move_file_to_external_bucket
1414from common .clients import STREAM_NAME , get_s3_client , logger
1515from common .log_decorator import logging_decorator
1616from common .models .errors import UnhandledAuditTableError
1717from constants import (
18+ DPS_DESTINATION_BUCKET_NAME ,
19+ DPS_DESTINATION_PREFIX ,
1820 ERROR_TYPE_TO_STATUS_CODE_MAP ,
21+ EXTENDED_ATTRIBUTES_FILE_PREFIX ,
1922 SOURCE_BUCKET_NAME ,
2023 FileNotProcessedReason ,
2124 FileStatus ,
2225)
23- from file_validation import is_file_in_directory_root , validate_file_key
26+ from file_validation import is_file_in_directory_root , validate_batch_file_key , validate_extended_attributes_file_key
2427from make_and_upload_ack_file import make_and_upload_the_ack_file
2528from models .errors import (
2629 InvalidFileKeyError ,
@@ -53,8 +56,6 @@ def handle_record(record) -> dict:
5356 "error" : str (error ),
5457 }
5558
56- vaccine_type = "unknown"
57- supplier = "unknown"
5859 expiry_timestamp = "unknown"
5960
6061 if bucket_name != SOURCE_BUCKET_NAME :
@@ -72,15 +73,103 @@ def handle_record(record) -> dict:
7273 message_id = "Message id was not created"
7374 created_at_formatted_string = "created_at_time not identified"
7475
76+ message_id = str (uuid4 ())
77+ s3_response = get_s3_client ().get_object (Bucket = bucket_name , Key = file_key )
78+ created_at_formatted_string , expiry_timestamp = get_creation_and_expiry_times (s3_response )
79+
80+ if file_key .startswith (EXTENDED_ATTRIBUTES_FILE_PREFIX ):
81+ return handle_extended_attributes_file (
82+ file_key ,
83+ bucket_name ,
84+ message_id ,
85+ created_at_formatted_string ,
86+ expiry_timestamp ,
87+ )
88+ else :
89+ return handle_batch_file (
90+ file_key ,
91+ bucket_name ,
92+ message_id ,
93+ created_at_formatted_string ,
94+ expiry_timestamp ,
95+ )
96+
97+
98+ def get_file_status_for_error (error : Exception ) -> str :
99+ """Creates a file status based on the type of error that was thrown"""
100+ if isinstance (error , VaccineTypePermissionsError ):
101+ return f"{ FileStatus .NOT_PROCESSED } - { FileNotProcessedReason .UNAUTHORISED } "
102+
103+ return FileStatus .FAILED
104+
105+
106+ def handle_unexpected_bucket_name (bucket_name : str , file_key : str ) -> dict :
107+ """Handles scenario where Lambda was not invoked by the data-sources bucket. Should not occur due to terraform
108+ config and overarching design"""
75109 try :
76- message_id = str (uuid4 ())
77- s3_response = get_s3_client ().get_object (Bucket = bucket_name , Key = file_key )
78- created_at_formatted_string , expiry_timestamp = get_creation_and_expiry_times (s3_response )
110+ if file_key .startswith (EXTENDED_ATTRIBUTES_FILE_PREFIX ):
111+ extended_attribute_identifier = validate_extended_attributes_file_key (file_key )
112+ logger .error (
113+ "Unable to process file %s due to unexpected bucket name %s" ,
114+ file_key ,
115+ bucket_name ,
116+ )
117+ message = f"Failed to process file due to unexpected bucket name { bucket_name } "
118+ return {
119+ "statusCode" : 500 ,
120+ "message" : message ,
121+ "file_key" : file_key ,
122+ "vaccine_supplier_info" : extended_attribute_identifier ,
123+ }
124+ else :
125+ vaccine_type , supplier = validate_batch_file_key (file_key )
126+ logger .error (
127+ "Unable to process file %s due to unexpected bucket name %s" ,
128+ file_key ,
129+ bucket_name ,
130+ )
131+ message = f"Failed to process file due to unexpected bucket name { bucket_name } "
132+
133+ return {
134+ "statusCode" : 500 ,
135+ "message" : message ,
136+ "file_key" : file_key ,
137+ "vaccine_type" : vaccine_type ,
138+ "supplier" : supplier ,
139+ }
79140
80- vaccine_type , supplier = validate_file_key (file_key )
81- permissions = validate_vaccine_type_permissions (vaccine_type = vaccine_type , supplier = supplier )
141+ except Exception as error :
142+ logger .error (
143+ "Unable to process file due to unexpected bucket name %s and file key %s" ,
144+ bucket_name ,
145+ file_key ,
146+ )
147+ message = f"Failed to process file due to unexpected bucket name { bucket_name } and file key { file_key } "
148+
149+ return {
150+ "statusCode" : 500 ,
151+ "message" : message ,
152+ "file_key" : file_key ,
153+ "vaccine_type" : "unknown" ,
154+ "supplier" : "unknown" ,
155+ "error" : str (error ),
156+ }
82157
158+
159+ def handle_batch_file (
160+ file_key : str , bucket_name : str , message_id : str , created_at_formatted_string : str , expiry_timestamp : str
161+ ) -> dict :
162+ """
163+ Processes a single record for batch file.
164+ Returns a dictionary containing information to be included in the logs.
165+ """
166+ vaccine_type = "unknown"
167+ supplier = "unknown"
168+ try :
169+ vaccine_type , supplier = validate_batch_file_key (file_key )
170+ permissions = validate_vaccine_type_permissions (vaccine_type = vaccine_type , supplier = supplier )
83171 queue_name = f"{ supplier } _{ vaccine_type } "
172+
84173 upsert_audit_table (
85174 message_id ,
86175 file_key ,
@@ -97,19 +186,17 @@ def handle_record(record) -> dict:
97186 supplier ,
98187 created_at_formatted_string ,
99188 )
100-
101189 logger .info ("Lambda invocation successful for file '%s'" , file_key )
102190
103- # Return details for logs
104191 return {
105192 "statusCode" : 200 ,
106193 "message" : "Successfully sent to SQS for further processing" ,
107194 "file_key" : file_key ,
108195 "message_id" : message_id ,
109196 "vaccine_type" : vaccine_type ,
110197 "supplier" : supplier ,
198+ "queue_name" : queue_name ,
111199 }
112-
113200 except ( # pylint: disable=broad-exception-caught
114201 VaccineTypePermissionsError ,
115202 InvalidFileKeyError ,
@@ -119,8 +206,8 @@ def handle_record(record) -> dict:
119206 ) as error :
120207 logger .error ("Error processing file '%s': %s" , file_key , str (error ))
121208
122- queue_name = f"{ supplier } _{ vaccine_type } "
123209 file_status = get_file_status_for_error (error )
210+ queue_name = f"{ supplier } _{ vaccine_type } "
124211
125212 upsert_audit_table (
126213 message_id ,
@@ -151,48 +238,61 @@ def handle_record(record) -> dict:
151238 }
152239
153240
154- def get_file_status_for_error (error : Exception ) -> str :
155- """Creates a file status based on the type of error that was thrown"""
156- if isinstance (error , VaccineTypePermissionsError ):
157- return f"{ FileStatus .NOT_PROCESSED } - { FileNotProcessedReason .UNAUTHORISED } "
158-
159- return FileStatus .FAILED
160-
161-
162- def handle_unexpected_bucket_name (bucket_name : str , file_key : str ) -> dict :
163- """Handles scenario where Lambda was not invoked by the data-sources bucket. Should not occur due to terraform
164- config and overarching design"""
241+ def handle_extended_attributes_file (
242+ file_key : str , bucket_name : str , message_id : str , created_at_formatted_string : str , expiry_timestamp : str
243+ ) -> dict :
244+ """
245+ Processes a single record for extended attributes file.
246+ Returns a dictionary containing information to be included in the logs.
247+ """
165248 try :
166- vaccine_type , supplier = validate_file_key (file_key )
167- logger .error (
168- "Unable to process file %s due to unexpected bucket name %s" ,
169- file_key ,
170- bucket_name ,
249+ extended_attribute_identifier = validate_extended_attributes_file_key (file_key )
250+ move_file_to_external_bucket (
251+ bucket_name , file_key , DPS_DESTINATION_BUCKET_NAME , f"{ DPS_DESTINATION_PREFIX } { file_key } "
171252 )
172- message = f"Failed to process file due to unexpected bucket name { bucket_name } "
173253
254+ upsert_audit_table (
255+ message_id ,
256+ file_key ,
257+ created_at_formatted_string ,
258+ expiry_timestamp ,
259+ extended_attribute_identifier ,
260+ FileStatus .PROCESSING ,
261+ )
174262 return {
175- "statusCode" : 500 ,
176- "message" : message ,
263+ "statusCode" : 200 ,
264+ "message" : "Extended Attributes file successfully processed" ,
177265 "file_key" : file_key ,
178- "vaccine_type " : vaccine_type ,
179- "supplier " : supplier ,
266+ "message_id " : message_id ,
267+ "queue_name " : extended_attribute_identifier ,
180268 }
269+ except ( # pylint: disable=broad-exception-caught
270+ VaccineTypePermissionsError ,
271+ InvalidFileKeyError ,
272+ UnhandledAuditTableError ,
273+ UnhandledSqsError ,
274+ Exception ,
275+ ) as error :
276+ logger .error ("Error processing file '%s': %s" , file_key , str (error ))
181277
182- except Exception as error :
183- logger .error (
184- "Unable to process file due to unexpected bucket name %s and file key %s" ,
185- bucket_name ,
278+ file_status = get_file_status_for_error (error )
279+ extended_attribute_identifier = validate_extended_attributes_file_key (file_key )
280+
281+ upsert_audit_table (
282+ message_id ,
186283 file_key ,
284+ created_at_formatted_string ,
285+ expiry_timestamp ,
286+ extended_attribute_identifier ,
287+ file_status ,
288+ error_details = str (error ),
187289 )
188- message = f"Failed to process file due to unexpected bucket name { bucket_name } and file key { file_key } "
189290
190291 return {
191292 "statusCode" : 500 ,
192- "message" : message ,
293+ "message" : f"Failed to process extended attributes file { file_key } from bucket { bucket_name } " ,
193294 "file_key" : file_key ,
194- "vaccine_type" : "unknown" ,
195- "supplier" : "unknown" ,
295+ "message_id" : message_id ,
196296 "error" : str (error ),
197297 }
198298
0 commit comments