~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/bugs/model/structuralsubscription.py

[r=jtv][bug=874250] Load preferredemail when calculating bug
 subscribers of any kind via BugSubscriptionInfo.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 
4
4
__metaclass__ = type
5
5
__all__ = [
 
6
    'get_structural_subscribers',
 
7
    'get_structural_subscription_targets',
 
8
    'get_structural_subscriptions',
6
9
    'get_structural_subscriptions_for_bug',
7
10
    'get_structural_subscriptions_for_target',
8
 
    'get_structural_subscribers',
9
 
    'get_structural_subscription_targets',
10
11
    'StructuralSubscription',
11
12
    'StructuralSubscriptionTargetMixin',
12
13
    ]
478
479
    def getSubscriptions(self, subscriber=None):
479
480
        """See `IStructuralSubscriptionTarget`."""
480
481
        from lp.registry.model.person import Person
481
 
        clauses = [StructuralSubscription.subscriberID==Person.id]
 
482
        clauses = [StructuralSubscription.subscriberID == Person.id]
482
483
        for key, value in self._target_args.iteritems():
483
484
            clauses.append(
484
 
                getattr(StructuralSubscription, key)==value)
 
485
                getattr(StructuralSubscription, key) == value)
485
486
 
486
487
        if subscriber is not None:
487
488
            clauses.append(
488
 
                StructuralSubscription.subscriberID==subscriber.id)
 
489
                StructuralSubscription.subscriberID == subscriber.id)
489
490
 
490
491
        store = Store.of(self.__helper.pillar)
491
492
        return store.find(
588
589
        *conditions)
589
590
 
590
591
 
591
 
def get_structural_subscribers(
592
 
    bug_or_bugtask, recipients, level, direct_subscribers=None):
593
 
    """Return subscribers for bug or bugtask at level.
594
 
 
595
 
    :param bug: a bug.
596
 
    :param recipients: a BugNotificationRecipients object or None.
597
 
                       Populates if given.
598
 
    :param level: a level from lp.bugs.enum.BugNotificationLevel.
599
 
    :param direct_subscribers: a collection of Person objects who are
600
 
                               directly subscribed to the bug.
601
 
 
602
 
    Excludes structural subscriptions for people who are directly subscribed
603
 
    to the bug."""
604
 
    if IBug.providedBy(bug_or_bugtask):
605
 
        bug = bug_or_bugtask
606
 
        bugtasks = bug.bugtasks
607
 
    elif IBugTask.providedBy(bug_or_bugtask):
608
 
        bug = bug_or_bugtask.bug
609
 
        bugtasks = [bug_or_bugtask]
610
 
    else:
611
 
        raise ValueError('First argument must be bug or bugtask')
 
592
def query_structural_subscriptions(
 
593
    what, bug, bugtasks, level, exclude=None):
 
594
    """Query into structural subscriptions for a given bug.
 
595
 
 
596
    :param what: The fields to fetch. Choose from `Person`,
 
597
        `StructuralSubscription`, `BugSubscriptionFilter`, or a combo.
 
598
    :param bug: An `IBug`
 
599
    :param bugtasks: An iterable of `IBugTask`.
 
600
    :param level: A level from `BugNotificationLevel`. Filters below this
 
601
        level will be excluded.
 
602
    :param exclude: `Person`s to exclude (e.g. direct subscribers).
 
603
    """
 
604
    from lp.registry.model.person import Person  # Circular.
612
605
    filter_id_query = (
613
606
        _get_structural_subscription_filter_id_query(
614
 
            bug, bugtasks, level, direct_subscribers))
 
607
            bug, bugtasks, level, exclude))
615
608
    if not filter_id_query:
616
609
        return EmptyResultSet()
617
 
    # This is here because of a circular import.
618
 
    from lp.registry.model.person import Person
619
610
    source = IStore(StructuralSubscription).using(
620
611
        StructuralSubscription,
621
612
        Join(BugSubscriptionFilter,
622
613
             BugSubscriptionFilter.structural_subscription_id ==
623
614
             StructuralSubscription.id),
624
615
        Join(Person,
625
 
             Person.id == StructuralSubscription.subscriberID),
626
 
        )
 
616
             Person.id == StructuralSubscription.subscriberID))
 
617
    conditions = In(
 
618
        BugSubscriptionFilter.id, filter_id_query)
 
619
    return source.find(what, conditions)
 
620
 
 
621
 
 
622
def get_bug_and_bugtasks(bug_or_bugtask):
 
623
    """Return a bug and a list of bugtasks given a bug or a bugtask.
 
624
 
 
625
    :param bug_or_bugtask: An `IBug` or `IBugTask`.
 
626
    :raises ValueError: If `bug_or_bugtask` does not provide `IBug` or
 
627
        `IBugTask`.
 
628
    """
 
629
    if IBug.providedBy(bug_or_bugtask):
 
630
        return bug_or_bugtask, bug_or_bugtask.bugtasks
 
631
    elif IBugTask.providedBy(bug_or_bugtask):
 
632
        return bug_or_bugtask.bug, [bug_or_bugtask]
 
633
    else:
 
634
        raise ValueError(
 
635
            "Expected bug or bugtask, got %r" % (bug_or_bugtask,))
 
636
 
 
637
 
 
638
def get_structural_subscriptions(bug_or_bugtask, level, exclude=None):
 
639
    """Return subscriptions for bug or bugtask at level.
 
640
 
 
641
    :param bug_or_bugtask: An `IBug` or `IBugTask`.
 
642
    :param level: A level from `BugNotificationLevel`. Filters below this
 
643
        level will be excluded.
 
644
    :param exclude: `Person`s to exclude (e.g. direct subscribers).
 
645
    """
 
646
    from lp.registry.model.person import Person  # Circular.
 
647
    bug, bugtasks = get_bug_and_bugtasks(bug_or_bugtask)
 
648
    subscriptions = query_structural_subscriptions(
 
649
        StructuralSubscription, bug, bugtasks, level, exclude)
 
650
    # Return only the first subscription and filter per subscriber.
 
651
    subscriptions.config(distinct=(Person.id,))
 
652
    subscriptions.order_by(
 
653
        Person.id, StructuralSubscription.id,
 
654
        BugSubscriptionFilter.id)
 
655
    return subscriptions
 
656
 
 
657
 
 
658
def get_structural_subscribers(
 
659
    bug_or_bugtask, recipients, level, exclude=None):
 
660
    """Return subscribers for bug or bugtask at level.
 
661
 
 
662
    :param bug_or_bugtask: An `IBug` or `IBugTask`.
 
663
    :param recipients: A `BugNotificationRecipients` object or
 
664
        `None`, which will be populated if provided.
 
665
    :param level: A level from `BugNotificationLevel`. Filters below this
 
666
        level will be excluded.
 
667
    :param exclude: `Person`s to exclude (e.g. direct subscribers).
 
668
    """
 
669
    from lp.registry.model.person import Person  # Circular.
 
670
    bug, bugtasks = get_bug_and_bugtasks(bug_or_bugtask)
627
671
    if recipients is None:
628
 
        return source.find(
629
 
            Person,
630
 
            In(BugSubscriptionFilter.id,
631
 
               filter_id_query)).config(distinct=True).order_by()
 
672
        subscribers = query_structural_subscriptions(
 
673
            Person, bug, bugtasks, level, exclude)
 
674
        subscribers.config(distinct=True)
 
675
        return subscribers.order_by()
632
676
    else:
 
677
        results = query_structural_subscriptions(
 
678
            (Person, StructuralSubscription, BugSubscriptionFilter),
 
679
            bug, bugtasks, level, exclude)
633
680
        subscribers = []
634
 
        query_results = source.find(
635
 
            (Person, StructuralSubscription, BugSubscriptionFilter),
636
 
            In(BugSubscriptionFilter.id, filter_id_query))
637
 
        for person, subscription, filter in query_results:
638
 
            # Set up results.
 
681
        for person, subscription, filter in results:
639
682
            if person not in recipients:
640
683
                subscribers.append(person)
641
684
                recipients.addStructuralSubscriber(
839
882
            group_by=(BugSubscriptionFilter.id,),
840
883
            having=Count(
841
884
                SQL('CASE WHEN BugSubscriptionFilterTag.include '
842
 
                    'THEN BugSubscriptionFilterTag.tag END'))==0)
 
885
                    'THEN BugSubscriptionFilterTag.tag END')) == 0)
843
886
    else:
844
887
        # The bug has some tags.  This will require a bit of fancy
845
888
        # footwork. First, though, we will simply want to leave out