"""Dynamodb table {env}-product_localization model.""" from datetime import datetime from oto import response from pynamodb import attributes from pynamodb.exceptions import PynamoDBConnectionError from pynamodb.models import Model from product import config from product.connectors.sentry import sentry_client from product.constants import error class AdditionalData(attributes.MapAttribute): """Complex Map attribute for data column of Localization model.""" product_name = attributes.UnicodeAttribute(attr_name='product_name') # @todo to find some way to make this null=False only for Film type or # add these attributes only for film. short_synopsis = attributes.UnicodeAttribute( null=True, attr_name='short_synopsis') long_synopsis = attributes.UnicodeAttribute( null=True, attr_name='long_synopsis') def serialize(self, values): """Override serialize from MapAttribute class. Override the fn so as we can can skip attributes with Null values from saving. Else they get saved in DB as null Args: values (dict): of all values as it is, non-serialized. Returns: dict: dict of serializable key-value obj """ return_value = {} for k in values: v = values[k] attr_class = attributes._get_class_for_serialize(v) attr_key = attributes._get_key_for_serialize(v) if attr_class is None or v is None: continue return_value[k] = {attr_key: attr_class.serialize(v)} return return_value class ProductLocalization(Model): """Localization table model.""" class Meta: """Metadata for the table itself.""" table_name = '{env}-product_localization'.format( env=config.ENVIRONMENT) if config.DYNAMODB_HOST: host = config.DYNAMODB_HOST product_id = attributes.UnicodeAttribute(null=None, hash_key=True) language_id = attributes.UnicodeAttribute(null=None, range_key=True) data = AdditionalData(null={}) last_updated = attributes.UTCDateTimeAttribute( null=datetime.now(), default=datetime.now()) def to_dict(self): """To render a json/serializable object for GET/POST response. Returns: dict: json representation of model object """ basic = {'language_id': self.language_id} basic.update(self.data.as_dict()) return basic def get_localization_data(product_id): """Get localization data from DB lookup for this product_id. Args: product_id (int): primary key product_id. Returns: Response: A Response obj with message = List of model object representation """ return_list = [] try: # @todo to handle pagination if too many results - MOV-2248 for localize_data in ProductLocalization.query(str(product_id)): return_list.append(localize_data.to_dict()) except PynamoDBConnectionError as e: sentry_client.captureException() return response.create_fatal_response(message=e.msg) if len(return_list) < 1: return response.create_not_found_response( 'No localization data found for product id={}'.format( product_id)) return_obj = { 'product_id': product_id, 'items': return_list, 'pagination': { 'type': 'standard', 'offset': 0, 'limit': -1, 'total_records': len(return_list)}} return response.Response(message=return_obj) def create_update(product_id, language_id, data): """Create/Update localization data in DB lookup with data provided. Args: product_id (int): primary key product_id. language_id (int): secondary key language_id. data (dict): additional translations for fields. Returns: Response: A Response obj with message = List of model object representation """ if data is None or data == {}: return response.create_error_response( error.ERROR_CODE_INVALID_DATA, 'No data sent for save for product id={}'.format(product_id)) add_data = AdditionalData(**data) formatted_data = { 'product_id': str(product_id), 'language_id': str(language_id), } localization_obj = ProductLocalization(**formatted_data) localization_obj.data = add_data try: localization_obj.save() return response.Response(message=localization_obj.to_dict()) except ValueError as e: sentry_client.captureException() return response.create_error_response( error.ERROR_CODE_INVALID_DATA, message=str(e)) except PynamoDBConnectionError as e: sentry_client.captureException() return response.create_fatal_response(message=e.msg) def delete(product_id, language_id): """Create/Update localization data in DB lookup with data provided. Args: product_id (int): primary key product_id. language_id (int): secondary key language_id. data (dict): additional translations for fields. Returns: Response: A Response obj with message = List of model object representation """ delete_count = 0 try: for localize_data in ProductLocalization.query( str(product_id), ProductLocalization.language_id == str(language_id) ): localize_data.delete() delete_count += 1 except PynamoDBConnectionError as e: sentry_client.captureException() return response.create_fatal_response(message=e.msg) if delete_count < 1: return response.create_not_found_response( 'No localization data deleted for product_id={} ' 'language_id={}'.format(product_id, language_id)) return response.Response( message='{} product was successfully deleted.'.format(delete_count))