Merge lp:~danilo/launchpad/bug-720826-links into lp:launchpad/db-devel

Proposed by Данило Шеган
Status: Merged
Approved by: Данило Шеган
Approved revision: no longer in the source branch.
Merged at revision: 10265
Proposed branch: lp:~danilo/launchpad/bug-720826-links
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~danilo/launchpad/bug-720826-emails
Diff against target: 153 lines (+39/-6)
5 files modified
lib/lp/bugs/configure.zcml (+4/-0)
lib/lp/bugs/doc/bugnotification-sending.txt (+9/-3)
lib/lp/bugs/mail/bugnotificationrecipients.py (+11/-0)
lib/lp/bugs/model/bugnotification.py (+11/-0)
lib/lp/bugs/model/structuralsubscription.py (+4/-3)
To merge this branch: bzr merge lp:~danilo/launchpad/bug-720826-links
Reviewer Review Type Date Requested Status
Gary Poster (community) Approve
Review via email: mp+52226@code.launchpad.net

Commit message

[r=gary][bug=720826] Populate BugNotificationFilter table with links between BugNotifications and BugSubscriptionFilters to finally close off 720826.

Description of the change

= Bug 720826 =

This finally ties everything up together: we start adding links to
subscription filters that have caused a certain BugNotification to
go off.

Previously, framework for this was provided, and if these links were
there, appropriate email headers and content was added to outgoing
emails.

== Proposed fix ==

 * Extend BugNotificationRecipients to allow holding relevant filters
   along with recipients and reasons they are getting emails
 * Find out what those filters are and add them to the `recipients`
   in structuralsubscription._get_structural_subscribers
 * In BugNotificationSet.addNotification(), we insert appropriate
   linking rows for all the filters present in `recipients`.

== Implementation details ==

BugNotificationRecipients is a structure that is passed around. IMHO, it is somewhat nasty that `recipients` is passed around and updated as a side-effect in a few methods which are called get*, but because it already is, I am abusing it to pass the subscription filters list as well (especially since I can easily calculate them at the same time all the other recipients stuff is calculated).

I am only providing the integration test in bugnotification-sending.txt.

== Tests ==

bin/test -cvvt bugnotification-sending.txt

== Demo and Q/A ==

Add a few subscription filters, and run "cronscripts/send-bug-notifications.py -vvv" and watch for the X-Launchpad-Subscription-Filter and "Matching filters" line.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/model/bugnotification.py
  lib/lp/bugs/mail/bugnotificationrecipients.py
  lib/lp/bugs/model/tests/test_bugtask.py
  lib/lp/bugs/doc/bugnotification-sending.txt
  lib/lp/bugs/model/bug.py
  lib/lp/bugs/tests/test_structuralsubscriptiontarget.py
  lib/lp/bugs/model/structuralsubscription.py
  lib/lp/bugs/model/bugtask.py

./lib/lp/bugs/model/bugnotification.py
     132: E202 whitespace before ']'
./lib/lp/bugs/doc/bugnotification-sending.txt
     433: want has trailing whitespace.
     451: want has trailing whitespace.

To post a comment you must log in.
Revision history for this message
Gary Poster (gary) wrote :

Let's remove the distinct=True in the structural subscription code, as we discussed on IRC. It might have made some sense when we were not getting a result per filter, but does not now.

I asked for a test showing multiple filters and you said they existed in unit tests. I'm mostly OK with that as being sufficient here. :-)

Yay, thank you!

review: Approve
Revision history for this message
Данило Шеган (danilo) wrote :

Yep, unit tests are available in "bin/test -cvvt test_header_multiple -t test_body_multiple".

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/configure.zcml'
2--- lib/lp/bugs/configure.zcml 2011-03-02 23:08:54 +0000
3+++ lib/lp/bugs/configure.zcml 2011-03-05 17:49:56 +0000
4@@ -1056,6 +1056,10 @@
5 class="lp.bugs.mail.bugnotificationrecipients.BugNotificationRecipients">
6 <allow
7 interface="canonical.launchpad.interfaces.launchpad.INotificationRecipientSet"/>
8+ <!-- BugNotificationRecipients provides the following
9+ attributes/methods in addition. -->
10+ <allow
11+ attributes="subscription_filters addFilter"/>
12 </class>
13 <securedutility
14 provides="lp.bugs.interfaces.bugnotification.IBugNotificationSet"
15
16=== modified file 'lib/lp/bugs/doc/bugnotification-sending.txt'
17--- lib/lp/bugs/doc/bugnotification-sending.txt 2011-02-22 10:44:48 +0000
18+++ lib/lp/bugs/doc/bugnotification-sending.txt 2011-03-05 17:49:56 +0000
19@@ -21,8 +21,10 @@
20
21 >>> def print_notification_headers(email_notification):
22 ... for header in ['To', 'From', 'Subject',
23- ... 'X-Launchpad-Message-Rationale']:
24- ... print "%s: %s" % (header, email_notification[header])
25+ ... 'X-Launchpad-Message-Rationale',
26+ ... 'X-Launchpad-Subscription-Filter']:
27+ ... if email_notification[header]:
28+ ... print "%s: %s" % (header, email_notification[header])
29
30 >>> def print_notification(email_notification):
31 ... print_notification_headers(email_notification)
32@@ -676,7 +678,6 @@
33 been set properly.
34
35 >>> from lp.bugs.model.bugnotification import BugNotification
36- >>> from lp.bugs.enum import BugNotificationStatus
37 >>> for notification in BugNotification.select(orderBy='id')[-8:]:
38 ... if notification.is_comment:
39 ... identifier = 'comment'
40@@ -1247,6 +1248,7 @@
41 >>> with lp_dbuser():
42 ... filter = subscription_no_priv.newBugFilter()
43 ... filter.bug_notification_level = BugNotificationLevel.COMMENTS
44+ ... filter.description = u"Allow-comments filter"
45
46 >>> comment = getUtility(IMessageSet).fromText(
47 ... 'subject', 'another comment.', sample_person,
48@@ -1279,12 +1281,14 @@
49 From: Sample Person <...@bugs.launchpad.net>
50 Subject: [Bug 1] subject
51 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)
52+ X-Launchpad-Subscription-Filter: Allow-comments filter
53 <BLANKLINE>
54 another comment.
55 <BLANKLINE>
56 --
57 You received this bug notification because you are subscribed to Mozilla
58 Firefox.
59+ Matching filters: Allow-comments filter
60 ...
61 ----------------------------------------------------------------------
62 To: support@ubuntu.com
63@@ -1390,6 +1394,7 @@
64 From: Sample Person <...@bugs.launchpad.net>
65 Subject: [Bug 1] subject
66 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)
67+ X-Launchpad-Subscription-Filter: Allow-comments filter
68 <BLANKLINE>
69 no comment for no-priv.
70 <BLANKLINE>
71@@ -1400,6 +1405,7 @@
72 --
73 You received this bug notification because you are subscribed to Mozilla
74 Firefox.
75+ Matching filters: Allow-comments filter
76 ...
77 ----------------------------------------------------------------------
78 To: support@ubuntu.com
79
80=== modified file 'lib/lp/bugs/mail/bugnotificationrecipients.py'
81--- lib/lp/bugs/mail/bugnotificationrecipients.py 2011-03-02 14:07:23 +0000
82+++ lib/lp/bugs/mail/bugnotificationrecipients.py 2011-03-05 17:49:56 +0000
83@@ -58,6 +58,7 @@
84 """
85 NotificationRecipientSet.__init__(self)
86 self.duplicateof = duplicateof
87+ self.subscription_filters = set()
88
89 def _addReason(self, person, reason, header):
90 """Adds a reason (text and header) for a person.
91@@ -127,3 +128,13 @@
92 else:
93 text = "are the registrant for %s" % upstream.displayname
94 self._addReason(person, text, reason)
95+
96+ def update(self, recipient_set):
97+ """See `INotificationRecipientSet`."""
98+ super(BugNotificationRecipients, self).update(recipient_set)
99+ self.subscription_filters.update(
100+ recipient_set.subscription_filters)
101+
102+ def addFilter(self, subscription_filter):
103+ if subscription_filter is not None:
104+ self.subscription_filters.add(subscription_filter)
105
106=== modified file 'lib/lp/bugs/model/bugnotification.py'
107--- lib/lp/bugs/model/bugnotification.py 2011-02-25 16:19:58 +0000
108+++ lib/lp/bugs/model/bugnotification.py 2011-03-05 17:49:56 +0000
109@@ -150,12 +150,23 @@
110 reason_body, reason_header = recipients.getReason(recipient)
111 sql_values.append('(%s, %s, %s, %s)' % sqlvalues(
112 bug_notification, recipient, reason_header, reason_body))
113+
114 # We add all the recipients in a single SQL statement to make
115 # this a bit more efficient for bugs with many subscribers.
116 store.execute("""
117 INSERT INTO BugNotificationRecipient
118 (bug_notification, person, reason_header, reason_body)
119 VALUES %s;""" % ', '.join(sql_values))
120+
121+ if len(recipients.subscription_filters) > 0:
122+ filter_link_sql = [
123+ "(%s, %s)" % sqlvalues(bug_notification, filter.id)
124+ for filter in recipients.subscription_filters]
125+ store.execute("""
126+ INSERT INTO BugNotificationFilter
127+ (bug_notification, bug_subscription_filter)
128+ VALUES %s;""" % ", ".join(filter_link_sql))
129+
130 return bug_notification
131
132
133
134=== modified file 'lib/lp/bugs/model/structuralsubscription.py'
135--- lib/lp/bugs/model/structuralsubscription.py 2011-03-04 02:29:09 +0000
136+++ lib/lp/bugs/model/structuralsubscription.py 2011-03-05 17:49:56 +0000
137@@ -585,14 +585,15 @@
138 else:
139 subscribers = []
140 query_results = source.find(
141- (Person, StructuralSubscription),
142- *constraints).config(distinct=True)
143- for person, subscription in query_results:
144+ (Person, StructuralSubscription, BugSubscriptionFilter),
145+ *constraints)
146+ for person, subscription, filter in query_results:
147 # Set up results.
148 if person not in recipients:
149 subscribers.append(person)
150 recipients.addStructuralSubscriber(
151 person, subscription.target)
152+ recipients.addFilter(filter)
153 return subscribers
154
155

Subscribers

People subscribed via source and target branches

to status/vote changes: