Exemple #1
0
def send_call_message(device, unique_key, phonenumber, caller_id, attempt):
    """
    Function to send the call push notification.

    Args:
        device (Device): A Device object.
        unique_key (string): String with the unique_key.
        phonenumber (string): Phonenumber that is calling.
        caller_id (string): ID of the caller.
        attempt (int): The amount of attempts made.
    """
    data = {
        'unique_key': unique_key,
        'phonenumber': phonenumber,
        'caller_id': caller_id,
        'attempt': attempt,
    }
    if device.app.platform == APNS_PLATFORM:
        send_apns_message(device, device.app, TYPE_CALL, data)
    elif device.app.platform == GCM_PLATFORM:
        send_gcm_message(device, device.app, TYPE_CALL, data)
    elif device.app.platform == ANDROID_PLATFORM:
        send_fcm_message(device, device.app, TYPE_CALL, data)
    else:
        log_middleware_information(
            '{0} | Trying to sent \'call\' notification to unknown platform:{1} device:{2}',
            OrderedDict([
                ('unique_key', unique_key),
                ('platform', device.app.platform),
                ('token', device.token),
            ]),
            logging.WARNING,
            device=device,
        )
Exemple #2
0
    def post(self, request):
        """
        Handle the post request of this view.

        Args:
            request (Request): Containing the post data.

        Returns:
            json: Status key with OK value.
        """
        serialized_data = self._serialize_request(request)
        unique_key = serialized_data['unique_key']
        message_start_time = serialized_data['message_start_time']
        available = serialized_data['available']

        cache_key = 'call_{0}'.format(unique_key)

        redis_cache = RedisClusterCache()

        # Check if key exists to avoid endpoint probing spam.
        if not redis_cache.exists(cache_key):
            return Response('', status=HTTP_404_NOT_FOUND)

        # Wait loop for asterisk sets the device platform as placeholder
        # for the available flag.
        platform = redis_cache.get(cache_key)

        redis_cache.set(cache_key, available)

        roundtrip = time.time() - float(message_start_time)

        log_middleware_information(
            '{0} | Device responded. Message start-time: {1} sec, round trip-time: {2} sec',
            OrderedDict([
                ('unique_key', unique_key),
                ('starttime',
                 datetime.datetime.fromtimestamp(message_start_time)),
                ('roundtrip', roundtrip),
            ]),
            logging.INFO,
        )

        # Threaded task to log information to the database.
        log_to_db(platform, roundtrip, available)

        # If device responded too late return 404 request (call) not found.
        if (roundtrip > (settings.APP_PUSH_ROUNDTRIP_WAIT / 1000)):
            return Response('', status=HTTP_404_NOT_FOUND)

        return Response('', status=HTTP_202_ACCEPTED)
Exemple #3
0
    def _serialize_data(self, data, serializer_class=None):
        """
        Function to serialize data with the serializer given in the
        serializer_class attribute. Also validates the data and responds with
        a HTTP_400_BAD_REQUEST when validation failed. Due to being an open
        api we do not want to give away the required fields and their
        requirements.

        Args:
            data(dict): Dictonary with that data that need to be serialized.
            serializer_class(Serializer): Class to use for serialization.

        Returns:
            dict: Dictionary with the validated data.

        Raises:
            NotImplementedError: When serializer_class attribute is not set.
            ParseError: When validation fails but because it's an open API we
                do not want to give away what failed. ParseError returns a
                HTTP_400_BAD_REQUEST.
        """
        if serializer_class is None:
            if self.serializer_class is None:
                raise NotImplementedError(
                    'serializer_class Attribute should be set')
        else:
            self.serializer_class = serializer_class

        serializer = self.serializer_class(data=data)
        if not serializer.is_valid(raise_exception=False):
            # Log errors.
            log_middleware_information(
                'BAD REQUEST! Serialization failed with following errors:\n\n{0}\n\nData:\n\n{1}',
                OrderedDict([
                    ('serializer_errors', serializer.errors),
                    ('data', data),
                ]),
                logging.INFO,
            )
            # This raises a bad request response.
            raise ParseError(detail=None)

        return serializer.validated_data
    def _check_status_code(self, status_code):
        """
        Function for checking the status code.

        Args:
            status_code(int): That status code of a response.
        """
        if status_code == 200:
            return
        elif status_code == 401:
            raise AuthenticationFailed(detail=None)
        elif status_code == 403:
            raise PermissionDenied(detail=None)
        else:
            # Temporarily unavailable.
            log_middleware_information(
                'Unsupported VG response code {0}',
                OrderedDict([
                    ('status_code', status_code),
                ]),
                logging.WARNING,
            )
            raise UnavailableException(detail=None)
Exemple #5
0
    def post(self, request):
        """
        Function to log the reason for a device.
        """
        serialized_data = self._serialize_request(request)

        reason = serialized_data['reason']
        unique_key = serialized_data['unique_key']
        sip_user_id = serialized_data['sip_user_id']

        try:
            # Check if there is a registered device for given sip_user_id.
            device = get_object_or_404(Device, sip_user_id=sip_user_id)
        except Http404:
            log_middleware_information(
                '{0} | Failed to find a device for SIP_user_ID : {1}',
                OrderedDict([
                    ('unique_key', unique_key),
                    (LOG_SIP_USER_ID, sip_user_id),
                ]),
                logging.WARNING,
            )
            raise

        log_middleware_information(
            '{0} | {1} Device not available because: {2} on {3}',
            OrderedDict([
                ('unique_key', unique_key),
                ('platform', device.app.platform.upper()),
                ('reason', reason),
                ('timestamp', datetime.datetime.fromtimestamp(
                    time.time()).strftime('%H:%M:%S.%f')),
            ]),
            logging.INFO,
            device=device,
        )
        return Response(status=HTTP_200_OK)
Exemple #6
0
def send_text_message(device, app, message):
    """
    Function to send a push notification with a message.

    Args:
        device (Device): A Device object.
        message (string): The message that needs to be send to the device.
    """
    if app.platform == APNS_PLATFORM:
        send_apns_message(device, app, TYPE_MESSAGE, {'message': message})
    elif app.platform == GCM_PLATFORM:
        send_gcm_message(device, app, TYPE_MESSAGE, {'message': message})
    elif app.platform == ANDROID_PLATFORM:
        send_fcm_message(device, app, TYPE_MESSAGE, {'message': message})
    else:
        log_middleware_information(
            'Trying to sent \'message\' notification to unknown platform:{0} device:{1}',
            OrderedDict([
                ('platform', device.app.platform),
                ('token', device.token),
            ]),
            logging.WARNING,
            device=device,
        )
Exemple #7
0
def get_apns2_connection(app, device, unique_key):
    """
    Get the active APNSv2 connection.

    This returns a reference to the global connection object,
    and initializes it if the connection was not yet made.

    Args:
        app (App): App requesting the connection.
        device (Device): Device requesting the connection.
        unique_key (str): Unique key used for logging.

    Returns:
        APNsClient.
    """
    global apns2_connection_pool
    if app.app_id not in apns2_connection_pool:
        full_cert_path = os.path.join(settings.CERT_DIR, app.push_key)
        apns2_connection = APNsClient(full_cert_path,
                                      use_sandbox=settings.APNS_IS_SANDBOX)
        log_middleware_information(
            '{0} | Opened new connection to APNSv2 for app_id: {1}',
            OrderedDict([
                ('token', unique_key),
                ('app_id', app.app_id),
            ]),
            logging.INFO,
            device=device,
        )
        apns2_connection_pool.update({app.app_id: apns2_connection})
    else:
        # Test the existing connection, will throw an exception if this fails.
        apns2_connection = apns2_connection_pool[app.app_id]
        apns2_connection.connect()

    return apns2_connection
Exemple #8
0
    def delete(self, request, platform):
        """
        Function for deleting a Device.
        """
        serialized_data = self._serialize_request(
            request, serializer_class=DeleteDeviceSerializer)

        token = serialized_data['token']
        sip_user_id = serialized_data['sip_user_id']
        app_id = serialized_data['app']

        try:
            device = get_object_or_404(
                Device,
                sip_user_id=sip_user_id,
                token=token,
                app__app_id=app_id,
                app__platform=platform,
            )
            device.delete()
        except Http404:
            log_middleware_information(
                'Could not unregister device {0} for SIP_USER_ID {1}',
                OrderedDict([
                    ('token', token),
                    (LOG_SIP_USER_ID, sip_user_id),
                ]),
                logging.WARNING,
            )
            raise
        except Exception:
            log_middleware_information(
                'EXCEPTION WHILE UNREGISTERING DEVICE {0} FOR SIP_USER_ID : {1}',
                OrderedDict([
                    ('token', token),
                    (LOG_SIP_USER_ID, sip_user_id),
                ]),
                logging.CRITICAL,
            )
            raise
        log_middleware_information(
            'Unregistered device {0} for SIP_USER_ID {1}',
            OrderedDict([
                ('token', token),
                (LOG_SIP_USER_ID, sip_user_id),
            ]),
            logging.INFO,
            device=device,
        )
        return Response('', status=HTTP_200_OK)
Exemple #9
0
def send_gcm_message(device, app, message_type, data=None):
    """
    Send a Google Cloud Messaging message.
    """
    token_list = [device.token]
    unique_key = device.token

    key = '%d-cycle.key' % int(time())
    if message_type == TYPE_CALL:
        unique_key = data['unique_key']
        message = get_call_push_payload(
            unique_key,
            data['phonenumber'],
            data['caller_id'],
            data['attempt'],
        )
    elif message_type == TYPE_MESSAGE:
        message = get_message_push_payload(data['message'])
    else:
        log_middleware_information(
            '{0} | Trying to sent message of unknown type: {1}',
            OrderedDict([
                ('unique_key', unique_key),
                ('message_type', message_type),
            ]),
            logging.WARNING,
            device=device,
        )

    gcm = GCM(app.push_key)

    try:
        start_time = time()
        response = gcm.json_request(
            registration_ids=token_list,
            data=message,
            collapse_key=key,
            priority='high',
        )

        success = response.get('success')
        canonical = response.get('canonical')
        errors = response.get('errors')

        if success:
            for reg_id, msg_id in success.items():
                log_middleware_information(
                    '{0} | GCM \'{1}\' message sent at time:{2} to {3}',
                    OrderedDict([
                        ('unique_key', unique_key),
                        ('message_type', message_type),
                        ('sent_time',
                         datetime.datetime.fromtimestamp(start_time).strftime(
                             '%H:%M:%S.%f')),
                        ('registration_id', reg_id),
                    ]),
                    logging.INFO,
                    device=device,
                )

        if canonical:
            for reg_id, new_reg_id in canonical.items():
                log_middleware_information(
                    '{0} | Should replace device token {1} with {2} in database',
                    OrderedDict([
                        ('unique_key', unique_key),
                        ('registration_id', reg_id),
                        ('new_registration_id', new_reg_id),
                    ]),
                    logging.WARNING,
                    device=device,
                )

        if errors:
            for err_code, reg_id in errors.items():
                log_middleware_information(
                    '{0} | Should remove {1} because {2}',
                    OrderedDict([
                        ('unique_key', unique_key),
                        ('registration_id', reg_id),
                        ('error_code', err_code),
                    ]),
                    logging.WARNING,
                    device=device,
                )

    except GCMAuthenticationException:
        # Stop and fix your settings.
        log_middleware_information(
            '{0} | Our Google API key was rejected!!!',
            OrderedDict([
                ('unique_key', unique_key),
            ]),
            logging.ERROR,
            device=device,
        )
    except ValueError:
        # Probably your extra options, such as time_to_live,
        # are invalid. Read error message for more info.
        log_middleware_information(
            '{0} | Invalid message/option or invalid GCM response',
            OrderedDict([
                ('unique_key', unique_key),
            ]),
            logging.ERROR,
            device=device,
        )
    except Exception:
        log_middleware_information(
            '{0} | Error sending GCM message',
            OrderedDict([
                ('unique_key', unique_key),
            ]),
            logging.CRITICAL,
            device=device,
        )
Exemple #10
0
def send_fcm_message(device, app, message_type, data=None):
    """
    Function for sending a push message using firebase.
    """
    registration_id = device.token
    unique_key = device.token
    if message_type == TYPE_CALL:
        unique_key = data['unique_key']
        message = get_call_push_payload(
            unique_key,
            data['phonenumber'],
            data['caller_id'],
            data['attempt'],
        )
    elif message_type == TYPE_MESSAGE:
        message = get_message_push_payload(data['message'])
    else:
        log_middleware_information(
            '{0} | Trying to sent message of unknown type: {1}',
            OrderedDict([
                ('unique_key', unique_key),
                ('message_type', message_type),
            ]),
            logging.WARNING,
            device=device,
        )

    push_service = FCMNotification(api_key=app.push_key)

    try:
        start_time = time()
        result = push_service.notify_single_device(
            registration_id=registration_id, data_message=message)
    except AuthenticationError:
        log_middleware_information(
            '{0} | Our Google API key was rejected!!!',
            OrderedDict([
                ('unique_key', unique_key),
            ]),
            logging.ERROR,
            device=device,
        )
    except InternalPackageError:
        log_middleware_information(
            '{0} | Bad api request made by package.',
            OrderedDict([
                ('unique_key', unique_key),
            ]),
            logging.ERROR,
            device=device,
        )
    except FCMServerError:
        log_middleware_information(
            '{0} | FCM Server error.',
            OrderedDict([
                ('unique_key', unique_key),
            ]),
            logging.ERROR,
            device=device,
        )
    else:
        if result.get('success'):
            log_middleware_information(
                '{0} | FCM \'{1}\' message sent at time:{2} to {3}',
                OrderedDict([
                    ('unique_key', unique_key),
                    ('message_type', message_type),
                    ('sent_time', datetime.datetime.fromtimestamp(
                        start_time).strftime('%H:%M:%S.%f')),
                    ('registration_id', registration_id),
                ]),
                logging.INFO,
                device=device,
            )

        if result.get('failure'):
            log_middleware_information(
                '{0} | Should remove {1} because {2}',
                OrderedDict([
                    ('unique_key', unique_key),
                    ('registration_id', registration_id),
                    ('results', result['results']),
                ]),
                logging.WARNING,
                device=device,
            )

            if (len(result['results']) > 0 and 'error' in result['results'][0]
                    and result['results'][0]['error'] == 'NotRegistered'):
                log_middleware_information(
                    '{0} | Removed {1}',
                    OrderedDict([
                        ('unique_key', unique_key),
                        ('device', device),
                    ]),
                    logging.INFO,
                )
                # Remove the unique key from the cache so we can sent
                # NAK to asterisk.
                redis_cache = RedisClusterCache()
                if redis_cache.exists(unique_key):
                    redis_cache.set(unique_key, "Removed")
                device.delete()

        if result.get('canonical_ids'):
            log_middleware_information(
                '{0} | Should replace device token {1}',
                OrderedDict([
                    ('unique_key', unique_key),
                    ('registration_id', registration_id),
                ]),
                logging.WARNING,
                device=device,
            )
Exemple #11
0
def send_apns_message(device, app, message_type, data=None):
    """
    Send an Apple Push Notification message via the new v2 API.
    """
    unique_key = device.token

    if message_type == TYPE_CALL:
        unique_key = data['unique_key']
        message = Payload(custom=get_call_push_payload(
            unique_key,
            data['phonenumber'],
            data['caller_id'],
            data['attempt'],
        ))
    elif message_type == TYPE_MESSAGE:
        message = Payload(custom=get_message_push_payload(data['message']))
    else:
        log_middleware_information(
            '{0} | TRYING TO SENT MESSAGE OF UNKNOWN TYPE: {1}',
            OrderedDict([
                ('unique_key', unique_key),
                ('message_type', message_type),
            ]),
            logging.WARNING,
            device=device,
        )

        # Unknown message type: ignore this message.
        return

    # Get the APNSv2 connection. There is one global connection.
    client = get_apns2_connection(app, device, unique_key)

    try:
        log_middleware_information(
            '{0} | Sending APNSv2 \'{1}\' message at time:{2} to {3}',
            OrderedDict([
                ('unique_key', unique_key),
                ('message_type', message_type),
                ('message_time', datetime.datetime.fromtimestamp(
                    time()).strftime('%H:%M:%S.%f')),
                ('token', device.token),
            ]),
            logging.INFO,
            device=device,
        )

        start_time = time()
        try:
            client.send_notification(device.token, message)
        finally:
            elapsed_time = time() - start_time
            log_middleware_information(
                '{0} | Sending message to APNSv2 took {1:.2f}s',
                OrderedDict([
                    ('unique_key', unique_key),
                    ('conn_time', elapsed_time),
                ]),
                logging.INFO,
                device=device,
            )

    except (DeviceTokenNotForTopic, BadDeviceToken, Unregistered) as ex:
        # According to APNs protocol the token reported here
        # is garbage (invalid or empty), stop using and remove it.
        log_middleware_information(
            '{0} | Sending APNSv2 message failed for device: {1}, reason: {2}',
            OrderedDict([
                ('unique_key', unique_key),
                ('token', device.token),
                ('error_msg', type(ex).__name__),
            ]),
            logging.WARNING,
            device=device,
        )
    except APNsException as ex:
        # Failures not related to devices.
        log_middleware_information(
            '{0} | Error sending APNSv2 message. \'{1}\'',
            OrderedDict([
                ('unique_key', unique_key),
                ('error_msg', type(ex).__name__),
            ]),
            logging.WARNING,
            device=device,
        )
    except Exception:
        log_middleware_information(
            '{0} | Error sending APNSv2 message',
            OrderedDict(unique_key=unique_key, ),
            logging.CRITICAL,
            device=device,
        )
Exemple #12
0
    def post(self, request, platform):
        """
        Function to create or update a Device.
        """
        serialized_data = self._serialize_request(request)

        token = serialized_data['token']
        sip_user_id = serialized_data['sip_user_id']
        app_id = serialized_data['app']
        remote_logging_id = serialized_data.get('remote_logging_id')

        app = get_object_or_404(App, app_id=app_id, platform=platform)

        device, created = Device.objects.update_or_create(
            sip_user_id=sip_user_id,
            defaults={
                'app_id': app.id,
                'token': token,
                'remote_logging_id': remote_logging_id,
            })

        # Track status.
        status = 'OK'

        # Update token.
        if device.token != token:
            if not created:
                task_notify_old_token(device, device.app)
                status += ' updated and send notify to old token'
            else:
                status += ' and updated token'
            device.token = token

        # Update remote_logging_id.
        if device.remote_logging_id != remote_logging_id:
            device.remote_logging_id = remote_logging_id
            status += ', updated the remote_logging_id'

        # Update fields.
        device.name = serialized_data.get('name', None)
        device.os_version = serialized_data.get('os_version', None)
        device.client_version = serialized_data.get('client_version', None)
        device.last_seen = timezone.now()
        device.sandbox = serialized_data['sandbox']

        device.app = app

        device.save()

        status_code = HTTP_200_OK
        if created:
            status_code = HTTP_201_CREATED

        log_middleware_information(
            '{0} {1} device:{2} registered for SIP_USER_ID: {3}. Status: {4}.',
            OrderedDict([
                ('app_id', app_id),
                ('platform', device.app.platform.upper()),
                ('device_token', device.token),
                (LOG_SIP_USER_ID, sip_user_id),
                ('status', status),
            ]),
            logging.INFO,
            device=device,
        )
        return Response('', status=status_code)
Exemple #13
0
    def post(self, request):
        """
        Handle post requests on this view.

        Args:
            request (Request): Containing the post data.

        Returns:
            string: With status=ACK or status=NAK based on succes or failure.

        Raises:
            Http404: When an app_id is provided that does not exist.
        """
        redis_cache = RedisClusterCache()
        serialized_data = self._serialize_request(request)

        sip_user_id = serialized_data['sip_user_id']
        caller_id = serialized_data['caller_id']
        phonenumber = serialized_data['phonenumber']
        call_id = serialized_data['call_id']

        if not call_id:
            # Generate unique_key for reference on incoming call answer.
            unique_key = random.getrandbits(128)
            unique_key = '%032x' % unique_key
        else:
            unique_key = call_id

        try:
            # Check if there is a registered device for given sip_user_id.
            device = get_object_or_404(Device, sip_user_id=sip_user_id)
        except Http404:
            log_middleware_information(
                '{0} | Failed to find a device for SIP_user_ID : {1} sending NAK',
                OrderedDict([
                    ('unique_key', unique_key),
                    (LOG_SIP_USER_ID, sip_user_id),
                ]),
                logging.WARNING,
            )

            # Push data to Redis for when a sip user id couldn't be found.
            redis_cache.client.rpush(
                VIALER_MIDDLEWARE_INCOMING_CALL_FAILED_TOTAL_KEY, {
                    OS_KEY: 'Middleware',
                    ACTION_KEY: 'Received',
                    FAILED_REASON_KEY: 'failed no sip_user_id',
                })

            # Log to the metrics file.
            metrics_data = {
                OS_KEY: 'Middleware',
                ACTION_KEY: 'Received',
                FAILED_REASON_KEY: 'failed no sip_user_id',
                'unique_key': unique_key,
            }
            log_data_to_metrics_log(metrics_data, sip_user_id)
        except Exception:
            log_middleware_information(
                '{0} | EXCEPTION WHILE FINDING DEVICE FOR SIP_USER_ID : {1}',
                OrderedDict([
                    ('unique_key', unique_key),
                    (LOG_SIP_USER_ID, sip_user_id),
                ]),
                logging.CRITICAL,
            )
        else:
            log_middleware_information(
                '{0} | Incoming call for SIP:{1} FROM:\'{2}/{3}\'',
                OrderedDict([
                    ('unique_key', unique_key),
                    (LOG_SIP_USER_ID, sip_user_id),
                    (LOG_CALL_FROM, phonenumber),
                    (LOG_CALLER_ID, caller_id),
                ]),
                logging.INFO,
                device=device,
            )

            # Push data to Redis for when a incoming call is received.
            redis_cache.client.rpush(
                VIALER_MIDDLEWARE_INCOMING_CALL_SUCCESS_TOTAL_KEY, {
                    OS_KEY: 'Middleware',
                    ACTION_KEY: 'Received',
                })

            # Log to the metrics file.
            metrics_data = {
                OS_KEY: 'Middleware',
                ACTION_KEY: 'Received',
                'unique_key': unique_key,
            }
            log_data_to_metrics_log(metrics_data, sip_user_id)

            attempt = 1
            # Send push message to wake up app.
            task_incoming_call_notify(
                device,
                unique_key,
                phonenumber,
                caller_id,
                attempt,
            )

            # Time related settings.
            wait_interval = settings.APP_PUSH_ROUNDTRIP_WAIT / 1000
            wait_until = time.time() + wait_interval
            resend_interval = settings.APP_PUSH_RESEND_INTERVAL / 1000
            next_resend_time = time.time() + resend_interval

            # Determine max possible attempts. Avoid sending a push
            # close to the end of the loop.
            max_attemps = int(wait_interval / resend_interval) - 1

            cache_key = 'call_{0}'.format(unique_key)
            # Create cache entry with device platform as placeholder for the
            # available flag. Done for logging purposes.
            redis_cache.set(cache_key, device.app.platform)

            log_middleware_information(
                '{0} | {1} Starting \'wait for it\' loop until {2} ({3}msec)',
                OrderedDict([
                    ('unique_key', unique_key),
                    ('platform', device.app.platform.upper()),
                    ('wait_until', datetime.datetime.fromtimestamp(
                        wait_until).strftime('%H:%M:%S.%f')),
                    ('roundtrip', settings.APP_PUSH_ROUNDTRIP_WAIT),
                ]),
                logging.INFO,
                device=device,
            )

            # We have to wait till the app responds and sets the cache value.
            while time.time() < wait_until:
                available = redis_cache.get(cache_key)
                # Get on an empty key returns None so we need to check for
                # True and False.
                if available == 'True':
                    log_middleware_information(
                        '{0} | {1} Device checked in on time, sending ACK on {2}',
                        OrderedDict([
                            ('unique_key', unique_key),
                            ('platform', device.app.platform.upper()),
                            ('ack_time',
                             datetime.datetime.fromtimestamp(
                                 time.time()).strftime('%H:%M:%S.%f')),
                        ]),
                        logging.INFO,
                        device=device,
                    )

                    # Push data to Redis for when a device successful
                    # responded to the middleware.
                    redis_cache.client.rpush(
                        VIALER_MIDDLEWARE_PUSH_NOTIFICATION_SUCCESS_TOTAL_KEY,
                        {
                            OS_KEY: device.app.platform,
                            DIRECTION_KEY: VIALER_MIDDLEWARE_INCOMING_VALUE,
                        })

                    # Log to the metrics file.
                    metrics_data = {
                        OS_KEY: device.app.platform,
                        CALL_SETUP_SUCCESSFUL_KEY: 'true',
                    }
                    log_data_to_metrics_log(metrics_data, sip_user_id)

                    # Success status for asterisk.
                    return Response('status=ACK')
                elif available == 'False':
                    log_middleware_information(
                        '{0} | {1} Device not available, sending NAK on {2}',
                        OrderedDict([
                            ('unique_key', unique_key),
                            ('platform', device.app.platform.upper()),
                            ('nak_time',
                             datetime.datetime.fromtimestamp(
                                 time.time()).strftime('%H:%M:%S.%f')),
                        ]),
                        logging.INFO,
                        device=device,
                    )

                    # Push data to Redis for when a device responded as not
                    # available to the middleware.
                    redis_cache.client.rpush(
                        VIALER_MIDDLEWARE_PUSH_NOTIFICATION_FAILED_TOTAL_KEY, {
                            OS_KEY: device.app.platform,
                            DIRECTION_KEY: VIALER_MIDDLEWARE_INCOMING_VALUE,
                            FAILED_REASON_KEY: 'Device not available',
                        })

                    # Log to the metrics file.
                    metrics_data = {
                        OS_KEY: device.app.platform,
                        CALL_SETUP_SUCCESSFUL_KEY: 'false',
                        FAILED_REASON_KEY: 'Device not available',
                    }
                    log_data_to_metrics_log(metrics_data, sip_user_id)

                    # App is not available.
                    return Response('status=NAK')
                elif available == 'Removed':
                    log_middleware_information(
                        '{0} | {1} Device has no valid push token, sending NAK on {2}',
                        OrderedDict([
                            ('unique_key', unique_key),
                            ('platform', device.app.platform.upper()),
                            ('nak_time',
                             datetime.datetime.fromtimestamp(
                                 time.time()).strftime('%H:%M:%S.%f')),
                        ]),
                        logging.INFO,
                        device=device,
                    )

                    return Response('status=NAK')
                else:
                    # Try to resend the push message every X seconds or
                    # after exceeding the max_attempts.
                    if time.time(
                    ) > next_resend_time and attempt < max_attemps:
                        attempt += 1
                        next_resend_time = time.time() + resend_interval
                        task_incoming_call_notify(
                            device,
                            unique_key,
                            phonenumber,
                            caller_id,
                            attempt,
                        )

                    time.sleep(.01)  # wait 10 ms

            log_middleware_information(
                '{0} | {1} Device did NOT check in on time, sending NAK on {2}',
                OrderedDict([
                    ('unique_key', unique_key),
                    ('platform', device.app.platform.upper()),
                    ('nak_time', datetime.datetime.fromtimestamp(
                        time.time()).strftime('%H:%M:%S.%f')),
                ]),
                logging.INFO,
                device=device,
            )

            # Push data to Redis for when a device has not responded to the middleware.
            redis_cache.client.rpush(
                VIALER_MIDDLEWARE_PUSH_NOTIFICATION_FAILED_TOTAL_KEY, {
                    OS_KEY: device.app.platform,
                    DIRECTION_KEY: VIALER_MIDDLEWARE_INCOMING_VALUE,
                    FAILED_REASON_KEY: 'Unable to get response from phone',
                })

            # Log to the metrics file.
            metrics_data = {
                OS_KEY: device.app.platform,
                CALL_SETUP_SUCCESSFUL_KEY: 'false',
                FAILED_REASON_KEY: 'Device did not respond in time',
            }
            log_data_to_metrics_log(metrics_data, sip_user_id)

        # Failed status for asterisk.
        return Response('status=NAK')
    def authenticate(self, request):
        """
        Function for authentication against VoIPGRID api.
        """
        if settings.TESTING:
            return (AnonymousUser, None)

        # Get auth headers.
        auth = get_authorization_header(request)

        if not auth:
            # Raises 'Authentication credentials were not provided'.
            raise NotAuthenticated(detail=None)

        # Serialize data to check for sip_user_id.
        serializer = SipUserIdSerializer(data=request.data)
        if not serializer.is_valid(raise_exception=False):
            log_middleware_information(
                'BAD REQUEST! Authentication failed due to invalid sip_user_id in data:\n\n{0}',
                OrderedDict([
                    ('data', request.data),
                ]),
                logging.INFO,
            )
            # This raises a bad request response.
            raise ParseError(detail=None)

        # Get sip_user_id.
        sip_user_id = serializer.validated_data['sip_user_id']

        # Created new headers with old auth data.
        headers = {'Authorization': auth}

        # Get user profile.
        response = requests.get(settings.VG_API_USER_URL, headers=headers)
        # Check status code.
        self._check_status_code(response.status_code)

        # Parse to json.
        json_response = response.json()

        # Get app account reference on systemuser.
        app_account_url = json_response['app_account']

        if not app_account_url:
            # Has no app account and thus no access to api.
            log_middleware_information(
                'No app account for systemuser {0} - {1}',
                OrderedDict([
                    ('id', json_response['id']),
                    (LOG_EMAIL, json_response['email']),
                ]),
                logging.INFO,
                device=Device.objects.get(sip_user_id=sip_user_id),
            )
            raise PermissionDenied(detail=None)

        # Get url for app account.
        app_account_api_url = settings.VG_API_BASE_URL + app_account_url

        # Get app account.
        response = requests.get(app_account_api_url, headers=headers)
        # Check status code.
        self._check_status_code(response.status_code)
        # Get account id.
        account_id = response.json()['account_id']

        # Compare account id to sip user id the request is meant for.
        if str(sip_user_id) != str(account_id):
            # Raise permissions denied.
            raise PermissionDenied(detail=None)

        # All good.
        return (AnonymousUser, None)