"""Model class for push notification device nodes.""" import textwrap from connector_neo4j import get_session from ddtrace import tracer from flask import g from owsresponse import response from users import constants from users.utils import api_utils @tracer.wrap(name='models.devices.create_push_notification_device') def create_push_notification_device( identity_id, push_token, platform_type, device_data, identity_data ): """Create push notification device node in graphdb. Args: identity_id (str): Identity identifier in graph. push_token (str): APNS or FMS push token. This is diff for each app installation. platform_type (str): ios or android. device_data (dict): attributes for device node identity_data (dict): attributes for identity node Returns: dict: the newly created device node from graph. """ session = get_session() undelete_query = """MATCH (i: Identity)- [r:DELETED_HAS_DEVICE]-> (d:Device { pushToken: $push_token, platformType: $platform_type }) WHERE i.id = $identity_id CALL apoc.refactor.setType(r, 'HAS_DEVICE') YIELD input,output RETURN output """ session.run( undelete_query, identity_id=identity_id, push_token=push_token, platform_type=platform_type ) create_query = """MATCH (i: Identity) WHERE i.id = $identity_id MERGE (d:Device { pushToken: $push_token, platformType: $platform_type }) SET d += $device_data, i += $identity_data MERGE (i)-[r:HAS_DEVICE]->(d) SET r.dateCreated = localdatetime() RETURN d as device""" result = session.run( create_query, identity_id=identity_id, push_token=push_token, platform_type=platform_type, device_data=api_utils.to_camel(device_data), identity_data=api_utils.to_camel(identity_data), ) if not result.peek(): return response.create_error_response( code=constants.ERROR_CODE_CREATE_ERROR, message=f'Failed to add Device to user: {identity_id}', ) return response.Response(api_utils.to_snake(dict(result.peek().data()['device']))) @tracer.wrap(name='models.devices.delete_push_notification_device') def delete_push_notification_device(identity_id, device_id, brand=None): """Delete push notification device node in graphdb. Args: identity_id (str): Identity identifier in graph. device_id (str): Device identifier brand (str): app brand. Returns: Response: success response with no message """ session = get_session() delete_query = f"""MATCH (i:Identity)-[r:HAS_DEVICE]->(d:Device) WHERE i.id = $identity_id AND d.deviceId = $device_id {"AND d.brand = $brand" if brand else ""} SET r.dateDeleted = localdatetime() WITH r CALL apoc.refactor.setType(r, 'DELETED_HAS_DEVICE') YIELD input, output RETURN input, output""" session.run(delete_query, identity_id=identity_id, device_id=device_id, brand=brand) return response.Response(status=204) @tracer.wrap(name='models.devices.get_registrations') def get_registrations(device_id, platform_type, brand=None): """Get all device registrations including identity nodes. Args: device_id (str): unique identifier for physical mobile device platform_type (str): ios or android. brand (str): app brand. Returns: array: tuples containing nodes: (device, identity) """ session = get_session() query = textwrap.dedent( f""" MATCH(i:Identity)-[:HAS_DEVICE]-(d:Device) WHERE d.deviceId = $device_id AND d.platformType = $platform_type{" AND d.brand = $brand" if brand else ""} RETURN i,d """ ) result = session.run(query, device_id=device_id, brand=brand, platform_type=platform_type) devices = [ (api_utils.to_snake(dict(each.get('d'))), api_utils.to_snake(dict(each.get('i')))) for each in result ] return response.Response(devices) @tracer.wrap(name='models.devices.get_device_by_push_token') def get_device_by_push_token(identity_id, push_token, platform_type): """Get a device registrations for this platform and push token. Args: identity_id (str): unique identifier for physical mobile device platform_type (str): ios or android. push_token (str): Push token. Returns: dict: device """ g.ows.log.info( f'Getting device registrations for identity_id: {identity_id}, platform: {platform_type} ' f'and push token: {push_token}' ) session = get_session() query = """MATCH(i:Identity)-[:HAS_DEVICE]-(d:Device) WHERE i.id = $identity_id AND d.pushToken = $push_token AND d.platformType = $platform_type RETURN d """ result = session.run( query, push_token=push_token, identity_id=identity_id, platform_type=platform_type ).single() if not result: return response.create_not_found_response('No user device found with this push_token') return response.Response(api_utils.to_snake(dict(result.get('d')))) @tracer.wrap(name='models.devices.get_push_notification_device') def get_push_notification_device(identity_id): """Get all push notification device nodes associated with identity. Args: identity_id (str): Identity identifier in graph. Returns: Response: with a dict of node details. """ session = get_session() get_query = """MATCH (i:Identity)-[:HAS_DEVICE]->(d:Device) WHERE i.id = $identity_id RETURN d as device""" result = session.run(get_query, identity_id=identity_id) devices = [] for each in result: devices.append(api_utils.to_snake(dict(each.get('device')))) return response.Response(devices)