def send(cls, message, category=None, icon=None, priority=NORMAL,
             expiration=0, dismissable=True, groupable=True, username=None,
             group=None, db=None):
        # TODO: if group is not None, query all users of the specified group
        # and create a notification instance for each member of the group
        if not isinstance(message, basestring):
            message = json.dumps(message)

        instance = cls(notification_id=cls.generate_unique_id(),
                       message=message,
                       created_at=utcnow(),
                       category=category,
                       icon=icon,
                       priority=priority,
                       expires_at=cls.calc_expiry(expiration),
                       dismissable=dismissable,
                       groupable=groupable,
                       read_at=None,
                       username=username,
                       db=db)
        instance.save()
        # when notification is sent, invoke subscribers of on_send with
        # notification instance as their only argument
        for callback in cls.on_send_callbacks:
            callback(instance)

        return instance
    def send(cls,
             message,
             category=None,
             icon=None,
             priority=NORMAL,
             expiration=0,
             dismissable=True,
             groupable=True,
             username=None,
             group=None,
             db=None):
        """ Creates a notification and a notification target

        Short description of variables:
            message:        text of the notification (may be json)
            category:       category of the notification
            icon:           unimplemented
            priority:       unimplemented
            dismissable:    whether the notification can be dismissed
            groupable:      whether notifications may be stacked
            username:       username target should be created for
            group:          group name to target - special group "guest" for
                            anonymous users

        Notification targetting:
            Targets are created for the notification once. First option is
            username, second is group, and if none are provided, special group
            "all" is used.
        """
        if not isinstance(message, basestring):
            message = json.dumps(message)
        notification_id = cls.generate_unique_id()
        instance = cls(notification_id=notification_id,
                       message=message,
                       created_at=utcnow(),
                       category=category,
                       icon=icon,
                       priority=priority,
                       expires_at=cls.calc_expiry(expiration),
                       dismissable=dismissable,
                       groupable=groupable,
                       read_at=None,
                       username=username,
                       db=db)
        instance.save()
        NotificationTarget.create(
            notification_id,
            target=username or group or 'all',
            target_type='user' if username else 'group',
            db=db,
        )
        # when notification is sent, invoke subscribers of on_send with
        # notification instance as their only argument
        for callback in cls.on_send_callbacks:
            callback(instance)

        return instance
def notification_cleanup(db, default_expiry):
    logging.debug("Notification cleanup started.")
    now = utcnow()
    auto_expires_at = now - datetime.timedelta(seconds=default_expiry)
    q = db.Delete('notifications', where='dismissable = true')
    q.where += ('((expires_at IS NULL AND created_at <= %(auto_expires_at)s) '
                'OR expires_at <= %(now)s)')
    rowcount = db.execute(q, dict(now=now, auto_expires_at=auto_expires_at))
    logging.debug("Notification cleanup deleted: {} "
                  "notifications.".format(rowcount))
    def mark_read(self, read_at=None):
        read_at = utcnow() if read_at is None else read_at
        if not self.is_read:
            if self.is_shared:
                # shared notifications store the datetime of reading in the
                # user's session
                self._mark_shared_read(read_at)
            else:
                # only personal notifications can be marked as read in the db
                self._mark_private_read(read_at)

        return self
    def mark_read(self, read_at=None):
        read_at = utcnow() if read_at is None else read_at
        if not self.is_read:
            if self.is_shared:
                # shared notifications store the datetime of reading in the
                # user's session
                self._mark_shared_read(read_at)
            else:
                # only personal notifications can be marked as read in the db
                self._mark_private_read(read_at)

        return self
    def send(cls, message, category=None, icon=None, priority=NORMAL,
             expiration=0, dismissable=True, groupable=True, username=None,
             group=None, db=None):
        """ Creates a notification and a notification target

        Short description of variables:
            message:        text of the notification (may be json)
            category:       category of the notification
            icon:           unimplemented
            priority:       unimplemented
            dismissable:    whether the notification can be dismissed
            groupable:      whether notifications may be stacked
            username:       username target should be created for
            group:          group name to target - special group "guest" for
                            anonymous users

        Notification targetting:
            Targets are created for the notification once. First option is
            username, second is group, and if none are provided, special group
            "all" is used.
        """
        if not isinstance(message, basestring):
            message = json.dumps(message)
        notification_id = cls.generate_unique_id()
        instance = cls(notification_id=notification_id,
                       message=message,
                       created_at=utcnow(),
                       category=category,
                       icon=icon,
                       priority=priority,
                       expires_at=cls.calc_expiry(expiration),
                       dismissable=dismissable,
                       groupable=groupable,
                       read_at=None,
                       username=username,
                       db=db)
        instance.save()
        NotificationTarget.create(
            notification_id,
            target=username or group or 'all',
            target_type='user' if username else 'group',
            db=db,
        )
        # when notification is sent, invoke subscribers of on_send with
        # notification instance as their only argument
        for callback in cls.on_send_callbacks:
            callback(instance)

        return instance
def ago(dt, days_only=False):
    # It may appear as if there's quite a bit of redundancy here, but it all
    # boils down to the need to mark translations using ngettext. We can't be
    # too 'progammatic' about this because various languages have different
    # numeber of plural forms and different rules about plural calculations.
    # Because of this, we sacrifice DRY for tranlsator-friendly strings.
    diff = utcnow().date() - dt
    divdays = functools.partial(divround, diff.days)
    period = divdays(365)
    if period:
        return ngettext("{number} year ago",
                        "{number} years ago",
                        period).format(number=period)
    period = divdays(30)
    if period:
        return ngettext("{number} month ago",
                        "{number} months ago",
                        period).format(number=period)
    period = divdays(7)
    if period:
        return ngettext("{number} week ago",
                        "{number} weeks ago",
                        period).format(number=period)
    if diff.days > 1:
        return ngettext("{number} day ago",
                        "{number} days ago",
                        diff.days).format(number=diff.days)
    if diff.days == 1:
        return _('Yesterday')
    if days_only:
        return _('Today')

    divsecs = functools.partial(divround, diff.seconds)
    period = divsecs(3600)
    if period:
        return ngettext("{number} hour ago",
                        "{number} hours ago",
                        period).format(number=period)
    period = divsecs(60)
    if period:
        return ngettext("{number} minute ago",
                        "{number} minutes ago",
                        period).format(number=period)
    if diff.seconds > 5:
        return ngettext("{number} second ago",
                        "{number} seconds ago",
                        diff.seconds).format(number=diff.seconds)
    return _('just now')
def notification_cleanup(db, default_expiry):
    logging.debug("Notification cleanup started.")
    now = utcnow()
    auto_expires_at = now - datetime.timedelta(seconds=default_expiry)
    where = '''notifications.dismissable = true AND (
                (notifications.expires_at IS NULL AND
                 notifications.created_at <= %(auto_expires_at)s) OR
                 notifications.expires_at <= %(now)s)'''
    query = db.Delete('notifications', where=where)
    target_query = db.Delete('notification_targets USING notifications',
                             where=where)
    target_query.where += ('notification_targets.notification_id = '
                           'notifications.notification_id')
    db.execute(target_query, dict(now=now, auto_expires_at=auto_expires_at))
    rows = db.execute(query, dict(now=now, auto_expires_at=auto_expires_at))
    logging.debug("{} expired notifications deleted.".format(rows))
 def __add_auto_fields(self, meta, relpath):
     # add auto-generated values to metadata before writing into db
     meta['path'] = relpath
     meta['updated'] = utcnow()
     (success, dir_fso) = self.fsal.get_fso(relpath)
     # TODO: should we raise in this case?
     meta['size'] = dir_fso.size if success else 0
     meta['content_type'] = metadata.determine_content_type(meta)
     # if cover or thumb images do not exist, avoid later filesystem lookups
     # by not writing the default paths into the storage
     for key in ('cover', 'thumb'):
         filename = meta.get(key)
         if filename:
             file_path = os.path.join(relpath, filename)
             if not self.fsal.exists(file_path):
                 meta.pop(key, None)
    def calc_expiry(expiration):
        if expiration == 0:
            return None

        return utcnow() + datetime.timedelta(seconds=expiration)
 def has_expired(self):
     return self.expires_at is not None and self.expires_at < utcnow()
def mark_read(notifications):
    now = utcnow()
    for notification in notifications:
        if notification.dismissable:
            notification.mark_read(now)
 def has_expired(self):
     return self.expires_at is not None and self.expires_at < utcnow()
    def calc_expiry(expiration):
        if expiration == 0:
            return None

        return utcnow() + datetime.timedelta(seconds=expiration)
Example #15
0
def mark_read(notifications):
    now = utcnow()
    for notification in notifications:
        if notification.dismissable:
            notification.mark_read(now)