def sendPushNotifications(self):
        success = 0
        error = 0
        now = datetime.utcnow().strftime('%Y/%m/%d %H:%M')
        notifications = PushNotificationModel().find(
            query={
                'sendTime': {
                    "$lt": now
                },
                'progress': ProgressState.ACTIVE
            })
        for notification in notifications:
            users = [
                UserModel().findOne({'_id': p['userId']})
                for p in list(ProfileModel().find(
                    query={
                        'appletId': notification['applet'],
                        'userId': {
                            '$exists': True
                        }
                    }))
            ]
            deviceIds = [
                user['deviceId'] for user in users
                if ('deviceId' in user) and (
                    user.get('timezone', 0) == notification.get('timezone', 0))
            ]
            proxy_dict = {}
            test_api_key = 'AAAAJOyOEz4:APA91bFudM5Cc1Qynqy7QGxDBa-2zrttoRw6ZdvE9PQbfIuAB9SFvPje7DcFMmPuX1IizR1NAa7eHC3qXmE6nmOpgQxXbZ0sNO_n1NITc1sE5NH3d8W9ld-cfN7sXNr6IAOuodtEwQy-'
            push_service = FCMNotification(api_key=test_api_key,
                                           proxy_dict=proxy_dict)
            registration_ids = deviceIds
            message_title = notification['head']
            message_body = notification['content']
            result = push_service.notify_multiple_devices(
                registration_ids=registration_ids,
                message_title=message_title,
                message_body=message_body)
            notification['attempts'] += 1
            notification['progress'] = ProgressState.EMPTY
            if result['failure']:
                notification['progress'] = ProgressState.ERROR
                error += result['failure']
                print(result['results'])

            if result['success']:
                notification['progress'] = ProgressState.SUCCESS
                success += result['success']

            PushNotificationModel().save(notification, validate=False)

        return {'successed': success, 'errors': error}
    def setSchedule(self, applet, schedule, **kwargs):
        thisUser = self.getCurrentUser()
        if not AppletModel().isCoordinator(applet['_id'], thisUser):
            raise AccessException(
                "Only coordinators and managers can update applet schedules.")
        if 'events' in schedule:
            for event in schedule['events']:
                if 'data' in event and 'useNotifications' in event[
                        'data'] and event['data']['useNotifications']:
                    if event['data']['notifications'][0]['start']:
                        sendTime = event['data']['notifications'][0]['start']
                    else:
                        sendTime = '09:00'

                    # in case of sigle event with exact year, month, day
                    if 'year' in event['schedule'] and 'month' in event[
                            'schedule'] and 'dayOfMonth' in event['schedule']:
                        sendTime = (
                            str(event['schedule']['year'][0]) + '/' +
                            ('0' + str(event['schedule']['month'][0] + 1))[-2:]
                            + '/' +
                            ('0' +
                             str(event['schedule']['dayOfMonth'][0]))[-2:] +
                            ' ' + sendTime)
                        existNotification = PushNotificationModel().findOne(
                            query={
                                'applet': applet['_id'],
                                'creator_id': thisUser['_id'],
                                'sendTime': str(sendTime)
                            })
                        if not existNotification:
                            PushNotificationModel().createNotification(
                                applet['_id'], 1, event['data']['title'],
                                event['data']['description'], str(sendTime),
                                thisUser['_id'])

                    # in case of daily event

        appletMeta = applet['meta'] if 'meta' in applet else {'applet': {}}
        if 'applet' not in appletMeta:
            appletMeta['applet'] = {}
        appletMeta['applet']['schedule'] = schedule
        AppletModel().setMetadata(applet, appletMeta)
        thread = threading.Thread(
            target=AppletModel().updateUserCacheAllUsersAllRoles,
            args=(applet, thisUser))
        thread.start()
        return (appletMeta)
    def __send_notification(self, notification, user_ids=None):
        """
        Main bode to send notification
        :params notification: Notification which should be sent to user
        :params notification: dict
        :params user: User to send the notification to.
        :params user: dict
        """
        # notification['dateSend'] = self.user_timezone_time.strftime('%Y/%m/%d')
        message_title = notification['head']
        message_body = notification['content']
        result = self.push_service.notify_multiple_devices(registration_ids=user_ids,
                                                           message_title=message_title,
                                                           message_body=message_body)
        notification['attempts'] += 1
        notification['progress'] = ProgressState.ACTIVE
        if result['failure']:
            notification['progress'] = ProgressState.ERROR
            self.error += result['failure']
            print(result['results'])

        if result['success']:
            notification['progress'] = ProgressState.SUCCESS
            self.success += result['success']

        PushNotificationModel().save(notification, validate=False)
    def get_profiles_by_notifications(self, notifications):
        for notification in notifications:
            if 'notifiedUsers' not in notification:
                notification.update({
                    'notifiedUsers': []
                })
            user_ids = [profile['userId'] for profile in self.get_profiles(notification) if profile]
            users = list(UserModel().get_users_by_ids(user_ids))
            self.set_random_date(notification)
            current_users = self.filter_users_by_timezone(notification, users)

            if current_users:
                notification.get('notifiedUsers')
                notification.update({
                    'notifiedUsers': notification.get('notifiedUsers', []) + [
                        {
                            '_id': user['_id'],
                            'dateSend': (datetime.datetime.strptime(self.current_time, '%Y/%m/%d %H:%M') \
                                + datetime.timedelta(hours=int(user['timezone']))).strftime('%Y/%m/%d')
                        }
                        for user in current_users]
                })
                device_ids = [user['deviceId'] for user in current_users]
                self.__send_notification(notification, device_ids)

            PushNotificationModel().save(notification, validate=False)
    def get_profiles(self, notification):
        if len(notification['users']):
            return list(ProfileModel().get_profiles_by_ids(notification['users']))

        notification_with_applet = list(PushNotificationModel().find(query={
            'applet': notification['applet'],
            'users': {
                '$exists': True,
                '$ne': []
            }
        }))
        notification_with_applet = list(set(user for n in notification_with_applet for user in n['users']))
        profiles = list(ProfileModel().get_profiles_by_applet_id(notification['applet']))
        # exclude existed users from general schedule
        return [profile for profile in profiles if profile['_id'] and profile['_id'] not in notification_with_applet]
    def setSchedule(self, applet, rewrite, deleted, schedule, **kwargs):
        thisUser = self.getCurrentUser()
        if not AppletModel().isCoordinator(applet['_id'], thisUser):
            raise AccessException(
                "Only coordinators and managers can update applet schedules.")

        assigned = {}
        if 'events' in schedule:
            for event in schedule['events']:
                if 'id' in event:
                    event['id'] = ObjectId(event['id'])
                    assigned[event['id']] = True

        if rewrite:
            original = EventsModel().getSchedule(applet['_id'])

            if 'events' in original:
                for event in original['events']:
                    original_id = event.get('id')
                    if original_id not in assigned:
                        PushNotificationModel().delete_notification(
                            original_id)
                        EventsModel().deleteEvent(original_id)
        else:
            if isinstance(deleted, list):
                for event_id in deleted:
                    PushNotificationModel().delete_notification(
                        ObjectId(event_id))
                    EventsModel().deleteEvent(ObjectId(event_id))

        if 'events' in schedule:
            # insert and update events/notifications
            for event in schedule['events']:
                savedEvent = EventsModel().upsertEvent(event, applet['_id'],
                                                       event.get('id', None))

                if 'data' in event and 'useNotifications' in event[
                        'data'] and event['data']['useNotifications']:
                    if 'notifications' in event['data'] and event['data'][
                            'notifications'][0]['start']:
                        # in case of daily/weekly event
                        exist_notification = None

                        if 'id' in event:
                            exist_notification = PushNotificationModel(
                            ).findOne(query={'_id': event['id']})

                        if exist_notification:
                            PushNotificationModel().replaceNotification(
                                applet['_id'], savedEvent, thisUser,
                                exist_notification)
                        else:
                            PushNotificationModel().replaceNotification(
                                applet['_id'], savedEvent, thisUser)
                event['id'] = savedEvent['_id']

        return {
            "applet": {
                "schedule":
                schedule
                if rewrite else EventsModel().getSchedule(applet['_id'])
            }
        }
 def get_notifications_by_type(self, notification_type=1):
     return list(PushNotificationModel().find(
         query={
             'notification_type': notification_type,
         }
     ))