예제 #1
0
    async def create_notification(self, request):
        request: CreateNotificationRequest = convert_request(
            CreateNotificationRequest,
            await request.json(),
        )

        try:
            conditions = dataclasses.asdict(
                deserialize.deserialize(ConditionClause, request.conditions))
        except deserialize.exceptions.DeserializeException as error:
            return json_response(reason=f'wrong condition clause {error}',
                                 status=400)

        current_datetime = utc_now()

        if request.scheduled_at is None:
            scheduled_at = current_datetime
        else:
            scheduled_at = request.scheduled_at

        if current_datetime > scheduled_at:
            return json_response(
                reason=f'scheduled_at should later than current time',
                status=400)

        notification = await create_notification(
            title=request.title,
            body=request.body,
            scheduled_at=scheduled_at,
            deep_link=request.deep_link,
            image_url=request.image_url,
            icon_url=request.icon_url,
            conditions=conditions,
        )
        return json_response(result=notification_model_to_dict(notification))
예제 #2
0
    async def get_notifications(self, request):
        query_params: FetchNotificationsRequest = convert_request(
            FetchNotificationsRequest,
            dict(request.rel_url.query),
        )
        available_order_by_fields = {
            'created_at',
            '-created_at',
            'modified_at',
            '-modified_at',
            'scheduled_at',
            '-scheduled_at',
        }

        total, notifications = await find_notifications_by_status(
            status=query_params.status,
            start=query_params.start,
            size=query_params.size,
            order_bys=list(
                available_order_by_fields.intersection(
                    query_params.order_bys)),
        )

        return json_response(
            result={
                'total':
                total,
                'notifications': [
                    notification_model_to_dict(notification)
                    for notification in notifications
                ]
            })
예제 #3
0
def device_notification_log_model_to_dict(row: DeviceNotificationLog):
    device_notification_log_dict = {
        'id': row.id,
        'notification': notification_model_to_dict(row.notification),
        'created_at': row.created_at,
    }
    return device_notification_log_dict
예제 #4
0
def device_notification_event_model_to_dict(row: DeviceNotificationEvent):
    device_notification_event_dict = {
        'id': row.id,
        'notification': notification_model_to_dict(row.notification),
        'event': row.event,
        'created_at': row.created_at,
    }
    return device_notification_event_dict
예제 #5
0
    async def get_notification(self, request):
        notification_uuid = request.match_info['notification_uuid']
        notification = await find_notification_by_id(uuid=notification_uuid)

        if notification is None:
            return json_response(
                reason=f'notification not found {notification_uuid}',
                status=404)

        return json_response(result=notification_model_to_dict(notification))
예제 #6
0
    async def launch_notification(self, request):
        notification_uuid = request.match_info['notification_uuid']
        notification = await find_notification_by_id(uuid=notification_uuid)

        if notification is None:
            return json_response(
                reason=f'notification not found {notification_uuid}',
                status=404)

        notification = await change_notification_status(
            target_notification=notification,
            status=NotificationStatus.QUEUED,
        )
        conditions = deserialize.deserialize(ConditionClause,
                                             notification.conditions)

        tasks = [{
            'task': NotificationTask.LAUNCH_NOTIFICATION,
            'kwargs': {
                'notification': {
                    'id': notification.id,
                    'uuid': str(notification.uuid),
                    'title': notification.title,
                    'body': notification.body,
                    'image_url': notification.image_url,
                    'icon_url': notification.icon_url,
                    'deep_link': notification.deep_link,
                },
                'conditions': dataclasses.asdict(conditions),
            },
        }]
        try:
            await self.notification_task_queue.apply_tasks(tasks=[
                TaskIn(
                    task=task,
                    queue_name='NOTIFICATION_JOB_QUEUE',
                    scheduled_at=int(notification.scheduled_at.timestamp()),
                ) for task in tasks
            ], )
        except Exception as e:  # rollback if queue pushing failed
            logger.warning(f'rollback because of queue pushing failed {e}')
            notification = await change_notification_status(
                target_notification=notification,
                status=NotificationStatus.ERROR,
            )

        return json_response(result=notification_model_to_dict(notification))
예제 #7
0
    async def update_notification_status(self, request):
        notification_uuid = request.match_info['notification_uuid']
        notification = await find_notification_by_id(uuid=notification_uuid)

        if notification is None:
            return json_response(
                reason=f'notification not found {notification_uuid}',
                status=404)

        request_body: UpdateNotificationStatusRequest = convert_request(
            UpdateNotificationStatusRequest,
            await request.json(),
        )
        notification = await change_notification_status(
            target_notification=notification,
            status=request_body.status,
        )
        return json_response(result=notification_model_to_dict(notification))
예제 #8
0
    async def launch_notification(self, request):
        notification_uuid = request.match_info['notification_uuid']
        notification = await find_notification_by_id(uuid=notification_uuid)

        if notification is None:
            return json_response(
                reason=f'notification not found {notification_uuid}',
                status=404)

        notification = await change_notification_status(
            target_notification=notification,
            status=NotificationStatus.LAUNCHED,
        )

        conditions = deserialize.deserialize(ConditionClause,
                                             notification.conditions)
        device_total = await get_device_total_by_conditions(
            conditions=conditions)
        notification_job_capacity = math.ceil(device_total /
                                              self.NOTIFICATION_WORKER_COUNT)

        try:
            tasks = []
            with await self.redis_pool as redis_conn:
                current_datetime = utc_now()
                scheduled_at_utc = datetime_to_utc_datetime(
                    notification.scheduled_at)

                priority = NotificationPriority.IMMEDIATE
                if scheduled_at_utc > current_datetime:
                    priority = NotificationPriority.SCHEDULED

                for job_index in range(self.NOTIFICATION_WORKER_COUNT):
                    job: NotificationJob = deserialize.deserialize(
                        NotificationJob, {
                            'notification': {
                                'id': notification.id,
                                'uuid': str(notification.uuid),
                                'title': notification.title,
                                'body': notification.body,
                                'image_url': notification.image_url,
                                'icon_url': notification.icon_url,
                                'deep_link': notification.deep_link,
                                'conditions': object_to_dict(conditions),
                                'devices': {
                                    'start':
                                    job_index * notification_job_capacity,
                                    'size': notification_job_capacity,
                                }
                            },
                            'scheduled_at': scheduled_at_utc.isoformat()
                        })
                    tasks.append(
                        publish_notification_job(
                            redis_conn=redis_conn,
                            job=object_to_dict(job),
                            priority=priority,
                        ))
                await asyncio.gather(*tasks)
        except Exception as e:  # rollback if queue pushing failed
            logger.warning(f'rollback because of queue pushing failed {e}')
            notification = await change_notification_status(
                target_notification=notification,
                status=NotificationStatus.ERROR,
            )

        return json_response(result=notification_model_to_dict(notification))