"""validation handler.""" import logging as logger from typing import ByteString, Callable, Dict, List, Union from ddex_ingester_common.constants.xmltodict import DDEX_LIST_FIELDS from ddex_ingester_common.helpers.xml_document_helper import ( get_root_element, ) from ddex_ingester_common.schemas.ddex_schema import DDEXSchema from ddex_ingester_common.schemas.s3_schema import S3Schema from rules import ( RuleResult, RULES_PER_INGESTION_SOURCE ) import xmltodict def handler( xml_data: Union[ByteString, str], extended_xml_data: Union[ByteString, str] = '') -> List[RuleResult]: """Script entry point.""" if not xml_data: return [] if isinstance(xml_data, bytes): xml_data = xml_data.decode('utf-8') doc = xmltodict.parse( xml_data, force_list=DDEX_LIST_FIELDS) if extended_xml_data: if isinstance(extended_xml_data, bytes): extended_xml_data = extended_xml_data.decode('utf-8') extended_doc = xmltodict.parse( extended_xml_data, force_list=DDEX_LIST_FIELDS ) doc = combine_ddex_documents(doc, extended_doc) data = DDEXSchema().load(doc) ddex_json = S3Schema().dump(data) rules = RULES_PER_INGESTION_SOURCE.get('AWAL') # Execute validation against received DDEX validation_results = validate(ddex_json, rules) return validation_results def combine_ddex_documents(doc, ext): """Combine extended metadata with DDEX document.""" root = get_root_element(doc) root['Project'] = ext['OrchardMessage']['Project'] """ We want to retain Tracks as a top level object in the DDEX, so remove it from the Product dict after using it to avoid duplication. """ root['Tracks'] = ext['OrchardMessage']['Product']['Tracks'] del ext['OrchardMessage']['Product']['Tracks'] root['Product'] = ext['OrchardMessage']['Product'] if ext['OrchardMessage'].get('OrchardLabelId'): root['Product']['VendorId'] = ext['OrchardMessage']['OrchardLabelId'] if ext['OrchardMessage'].get('OrchardSubaccountId'): root['Product']['SubaccountId'] = ext['OrchardMessage']['OrchardSubaccountId'] # noqa return doc def validate( data: Dict, rules: List[Callable[[Dict], RuleResult]] ) -> List[RuleResult]: """Validate incoming data against a set of rules.""" validation_results = [] for rule in rules: try: logger.info(f'Executing validation rule: {rule.__name__}') validation_results.append(rule(data)) except Exception: msg = f'Exception while executing rule: {rule.__name__}' logger.error(msg) raise return validation_results