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 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)