def new(object, action): """ Sends notifications for a new object, saves it as `first_unread_object` or in `unread_objects` (depending on the type's mode) and increments the unread count. Must be called whenever a new object is created or moved to the scope of a SubscriptionType (e.g. when a topic is moved to another forum). :param object: The added object. :param action: The action which lead to the creation of the object. It is used to select the SubscriptionTypes that need to be considered and the action's :meth:`notify` method is called. """ #XXX: if `object` is removed before the task is run, subscriptions are # marked as notified though the user didn't receive a notification if isinstance(action, basestring): action = SubscriptionAction.by_name(action) #: store ids of Subscription objects for which we need to notify subscriptions = [] for t in SubscriptionType.by_action(action): subjects = t.get_subjects(object) if not subjects: continue subject_ids = [getattr(s, 'id', s) for s in subjects] base_cond = (Subscription.type_name == t.name) if t.subject_type is not None: base_cond &= Subscription.subject_id.in_(subject_ids) if t.mode == 'sequent': #: increment unread count where there already are unread objects cond = base_cond & (Subscription.count > 0) q = db.update(Subscription.__table__, cond, {'count': Subscription.count + 1}) db.session.execute(q) db.session.commit() #: then set the first unread object and notify the user #: where there were no new objects since the last visit cond = base_cond & (Subscription.count == 0) for s in Subscription.query.filter(cond): subscriptions.append(s.id) s.first_unread_object_id = object.id s.count = 1 db.session.commit() if t.mode == 'multiple': for s in Subscription.query.filter(base_cond): subscriptions.append(s.id) s.unread_object_ids.add(object.id) s.count = len(s.unread_object_ids) db.session.commit() from inyoka.core import tasks tasks.send_notifications(object, action.name, subscriptions)
def send_notifications(object, action_name, subscriptions): action = SubscriptionAction.by_name(action_name) if action is None: raise ValueError('no action found with %r' % action_name) notifications = defaultdict(lambda: defaultdict(list)) for s in subscriptions: try: s = Subscription.query.get(s) except NoResultFound: raise ValueError('no subscription found with id %r' % s) notifications[s.user][s.type.name].append(s.subject) for user in notifications: action.notify(user, object, notifications[user])