def test_subscriptiontype(self): eq_(SubscriptionType.by_name(u'__test_comments'), CommentsSubscriptionType) eq_(SubscriptionType.by_object_type(TestSubscriptionComment), [CommentsSubscriptionType]) eq_(SubscriptionType.by_subject_type(TestSubscriptionCategory), [CategorySubscriptionType]) eq_(sorted(SubscriptionType.by_action(NewEntrySubscriptionAction)), sorted([CategorySubscriptionType, BlogSubscriptionType, TagSubscriptionType])) eq_(SubscriptionType.by_action(u'__test_new_comment'), [CommentsSubscriptionType])
def accessed(user, **kwargs): """ Mark subscriptions as read. This means to remove objects from the `unread_objects` or unset `first_unread_object` (depending on the type's mode) and decrement the unread count. Must be called whenever an object is accessed. :param object: Mark all subscriptions with this object as read. :param subject: Mark all subscriptions with this subject as read. """ # enforce usage of keywords object = kwargs.pop('object', None) subject = kwargs.pop('subject', None) assert not kwargs, 'Invalid Arguments %r' % kwargs.keys() if object is not None: for t in SubscriptionType.by_object_type(type(object)): subjects = t.get_subjects(object) if not subjects: continue subject_ids = [getattr(s, 'id', s) for s in subjects] cond = ((Subscription.type_name == t.name) & (Subscription.user == user)) if t.subject_type is not None: cond &= Subscription.subject_id.in_(subject_ids) subscriptions = Subscription.query.filter(cond).all() for s in subscriptions: if t.mode == 'sequent': s.first_unread_object_id = None s.count = 0 elif t.mode == 'multiple': try: s.unread_object_ids.remove(object.id) except KeyError: pass else: s.count -= 1 db.session.commit() if subject is not None: for t in SubscriptionType.by_subject_type(type(subject)): try: s = Subscription.query.filter_by(type_name=t.name, subject_id=subject.id, user=user).one() except db.NoResultFound: continue s.count = 0 if t.mode == 'sequent': s.first_unread_object_id = None elif t.mode == 'multiple': s.unread_object_ids = [] db.session.commit()
def test_subscriptiontype(self): eq_(SubscriptionType.by_name(u'__test_comments'), CommentsSubscriptionType) eq_(SubscriptionType.by_object_type(TestSubscriptionComment), [CommentsSubscriptionType]) eq_(SubscriptionType.by_subject_type(TestSubscriptionCategory), [CategorySubscriptionType]) eq_( sorted(SubscriptionType.by_action(NewEntrySubscriptionAction)), sorted([ CategorySubscriptionType, BlogSubscriptionType, TagSubscriptionType ])) eq_(SubscriptionType.by_action(u'__test_new_comment'), [CommentsSubscriptionType])
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 subscribe(user, type_, subject=None): """ Safely subscribe a user to a subject. Returns False if the Subscription already exists, else True. :param user: A user object or a user id. :param type_: The subscription type to be used. May be a subclass of :class:`SubscriptionType` or a name of a subscription type. :param subject: The subject to be used (id or instance). May be None if the type has not ``subject_type``. """ if isinstance(type_, basestring): type_ = SubscriptionType.by_name(type_) subject_type = type_ and type_.subject_type or type(None) if not isinstance(subject, subject_type): raise ValueError('subject (%r) does not match the subject_type ' '(%r) of given SubscriptionType' % (subject, subject_type)) subject_id = None if subject is None else subject.id args = { 'user': user, 'type_name': type_.name, 'subject_id': subject_id, } if Subscription.query.filter_by(**args).count(): return False Subscription(**args) db.session.commit() return True
def unsubscribe(user_or_subscription, type_=None, subject=None): """ Safely unsubscribe a user from a subject. Returns False if the Subscription did not exist, else True. :param user_or_subscription: A user object or a user id. May also be a Subscription object, in this case the other parameters must not be given. :param type_: The subscription type to be used. May be a subclass of :class:`SubscriptionType` or a name of a subscription type. :param subject: The subject to be used (id or instance). May be None if the type has not ``subject_type``. """ if isinstance(user_or_subscription, Subscription): assert type_ is None and subject is None db.session.delete(user_or_subscription) db.session.commit() return True else: user = user_or_subscription if isinstance(type_, basestring): type_ = SubscriptionType.by_name(type_) s = Subscription.query.filter_by(user=user, type_name=type_.name, subject_id=getattr( subject, 'id', subject)).all() if not len(s): return False if len(s) > 1: raise ValueError('Duplicate found!') db.session.delete(s[0]) db.session.commit() return True
def type(self): return SubscriptionType.by_name(self.type_name)