Merge lp:~gary/launchpad/move-events-to-filters into lp:launchpad/db-devel
- move-events-to-filters
- Merge into db-devel
Status: | Merged |
---|---|
Approved by: | Gary Poster |
Approved revision: | no longer in the source branch. |
Merged at revision: | 10164 |
Proposed branch: | lp:~gary/launchpad/move-events-to-filters |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
1278 lines (+376/-298) 23 files modified
database/sampledata/current-dev.sql (+4/-4) database/sampledata/current.sql (+4/-4) database/schema/comments.sql (+1/-1) database/schema/patch-2208-37-0.sql (+12/-0) lib/canonical/launchpad/mail/helpers.py (+1/-5) lib/lp/bugs/browser/bugsubscriptionfilter.py (+45/-1) lib/lp/bugs/browser/structuralsubscription.py (+4/-35) lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py (+85/-0) lib/lp/bugs/browser/tests/test_structuralsubscription.py (+0/-133) lib/lp/bugs/doc/bug-change.txt (+7/-2) lib/lp/bugs/doc/bugnotification-sending.txt (+133/-10) lib/lp/bugs/doc/bugsubscription.txt (+15/-8) lib/lp/bugs/doc/structural-subscriptions.txt (+0/-2) lib/lp/bugs/interfaces/bugsubscriptionfilter.py (+8/-0) lib/lp/bugs/interfaces/structuralsubscription.py (+6/-26) lib/lp/bugs/model/bugsubscriptionfilter.py (+6/-0) lib/lp/bugs/model/structuralsubscription.py (+16/-35) lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py (+9/-0) lib/lp/bugs/model/tests/test_bugtask.py (+3/-2) lib/lp/bugs/tests/structural-subscription-target.txt (+10/-19) lib/lp/bugs/tests/test_bugchanges.py (+4/-1) lib/lp/bugs/tests/test_structuralsubscriptiontarget.py (+3/-6) lib/lp/registry/doc/private-team-roles.txt (+0/-4) |
To merge this branch: | bzr merge lp:~gary/launchpad/move-events-to-filters |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | code | Approve | |
Graham Binns (community) | code | Approve | |
Stuart Bishop (community) | db | Approve | |
Robert Collins | db | Pending | |
Review via email: mp+48069@code.launchpad.net |
Commit message
[r=allenap,
Description of the change
Part of https:/
This branch moves the event filter enumeration off of the structural subscription, and on to the filter object. Combined with Gavin's filter work, this makes it possible to, for instance, subscribe to all bug notifications for a project or package with a "ui" tag and also subscribe to only creation/closing bug notifications with a "bugjam" tag.
"make lint" only complains about some circular dependencies that are not an issue with my changes to my knowledge.
All tests I touched pass for me. ec2 is currently running tests for this branch.
This branch is large but I'm not sure how I would have made it smaller. If you'd like to talk it over with me maybe we could come up with a way to divide it?
Thank you
Gary
Gary Poster (gary) wrote : | # |
Gary Poster (gary) wrote : | # |
There's one more thing I hope will get someone's attention: the XXX I added. I intend to remove it after discussion and resolution in this review.
Here's the concern. The filter class (lp.bugs.
Thanks.
Stuart Bishop (stub) wrote : | # |
Fine. patch-2208-37-0.sql
Graham Binns (gmb) wrote : | # |
> A worry: target.
> of NOTHING. We never exposed that, to my knowledge, instead relying publicly
> on addBugSubscription, which always explicitly set a level of COMMENTS. Now,
> this branch creates subscriptions without filters, which means
> addBugSubscription has the same result, but addSubscription does not. I don't
> think it is an issue, but I'd like a sanity check from an expert (gmb? :-D )
I don't think that's going to be an issue (and I'd like to think that tests will blow up if it is).
Graham Binns (gmb) wrote : | # |
> There's one more thing I hope will get someone's attention: the XXX I added.
> I intend to remove it after discussion and resolution in this review.
>
> Here's the concern. The filter class
> (lp.bugs.
> "delete" method that will delete all of its subobjects (that is, records in
> the database in a many to one relationship with the filter class). However,
> the structural subscriptions do not have any similar code for the filters,
> which are themselves many to one with the structural subscriptions. Why? Is
> the delete method in BugSubscription
> delete in the database, or do I need to do something similar to the delete
> method on structural subscriptions? This seems like an elementary question
> for LP development, but not something I've encountered yet.
I don't know the answer to this, I'm afraid. I don't see anything in the DB that suggests we have a cascading delete set up in the database, and IIRC you'll get an OOPS if you try to delete something that has other DB rows hanging off it. My best suggestion would be to write a test for this and see whether smoke comes out.
Graham Binns (gmb) wrote : | # |
Hi Gary,
So, I'm broadly-speaking +1 on this branch landing (note that I'm on a fairly narrow bandwidth at the moment, so I've gone straight for understanding the code and not worried too much about formatting issues). However, I don't feel that I have enough knowledge about the way that filters work at the moment to offer a definite r=me. I'd suggest you ask Gavin to cast a weather eye over it too, since the filters were at least in part his work.
Anyway, approval from me. Nice work; I don't think I can see a way to break it up without causing some heartache, so don't worry about the branch size.
Gavin Panella (allenap) wrote : | # |
This is really cool :) I have an answer for your specific question in
[2], and one other trivial comment.
[1]
+ LaunchpadEditFo
Consider using super() here.
[2]
+ # XXX Delete all associated filters.
store = Store.of(
Mucking about in bin/iharness shows that the filters need to be
explicitly deleted too.
> Is the delete method in BugSubscription
> have cascading delete in the database, or do I need to do something
> similar to the delete method on structural subscriptions?
Yes :) I never thought to put it in before.
I talked briefly with Aaron about this before. There isn't a clear
story for deleting stuff in Launchpad. We have destroySelf() in some
places, a hang-over from SQLObject, and delete() in other places, and
many places do store.remove(thing) without thinking about it.
It might work to have a __storm_remove__ hook so that things like
BugSubscription
dependencies. Then we would always use store.remove(). However, that
doesn't work from view code which must not speak of the store. I
suspect a mishmash will rule.
Gary Poster (gary) wrote : | # |
Thank you for the reviews!
I have changed to use super (I was too lazy at the time to verify that the base class was new-style; in the LP code base, I suppose I should have assumed yes).
In regards to the XXX, I want to do this in a separate branch, since this one was so gigantic. It also is a bug outside of the code I added in this branch, which I'm using to further rationalize the decision. :-) I created bug 711362 and will be beginning a branch for it (with tests as Graham suggested and a delete method as Gavin suggested) within the hour.
Preview Diff
1 | === modified file 'database/sampledata/current-dev.sql' |
2 | --- database/sampledata/current-dev.sql 2011-01-18 21:20:48 +0000 |
3 | +++ database/sampledata/current-dev.sql 2011-02-01 19:35:24 +0000 |
4 | @@ -3694,10 +3694,10 @@ |
5 | |
6 | ALTER TABLE structuralsubscription DISABLE TRIGGER ALL; |
7 | |
8 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (1, NULL, NULL, NULL, NULL, 1, NULL, 1, 16, 16, 40, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
9 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (2, NULL, NULL, NULL, NULL, 1, NULL, 14, 16, 16, 40, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
10 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (3, 22, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
11 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (4, 16, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
12 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (1, NULL, NULL, NULL, NULL, 1, NULL, 1, 16, 16, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
13 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (2, NULL, NULL, NULL, NULL, 1, NULL, 14, 16, 16, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
14 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (3, 22, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
15 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (4, 16, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
16 | |
17 | |
18 | ALTER TABLE structuralsubscription ENABLE TRIGGER ALL; |
19 | |
20 | === modified file 'database/sampledata/current.sql' |
21 | --- database/sampledata/current.sql 2011-01-18 21:20:48 +0000 |
22 | +++ database/sampledata/current.sql 2011-02-01 19:35:24 +0000 |
23 | @@ -3694,10 +3694,10 @@ |
24 | |
25 | ALTER TABLE structuralsubscription DISABLE TRIGGER ALL; |
26 | |
27 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (1, NULL, NULL, NULL, NULL, 1, NULL, 1, 16, 16, 40, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
28 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (2, NULL, NULL, NULL, NULL, 1, NULL, 14, 16, 16, 40, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
29 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (3, 22, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
30 | -INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, bug_notification_level, date_created, date_last_updated) VALUES (4, 16, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, 40, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
31 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (1, NULL, NULL, NULL, NULL, 1, NULL, 1, 16, 16, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
32 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (2, NULL, NULL, NULL, NULL, 1, NULL, 14, 16, 16, '2008-01-29 15:12:34.581468', '2008-01-29 15:12:34.581468'); |
33 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (3, 22, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
34 | +INSERT INTO structuralsubscription (id, product, productseries, project, milestone, distribution, distroseries, sourcepackagename, subscriber, subscribed_by, date_created, date_last_updated) VALUES (4, 16, NULL, NULL, NULL, NULL, NULL, NULL, 64, 64, '2008-02-06 12:17:13.030376', '2008-02-06 12:17:13.030376'); |
35 | |
36 | |
37 | ALTER TABLE structuralsubscription ENABLE TRIGGER ALL; |
38 | |
39 | === modified file 'database/schema/comments.sql' |
40 | --- database/schema/comments.sql 2011-01-18 21:20:48 +0000 |
41 | +++ database/schema/comments.sql 2011-02-01 19:35:24 +0000 |
42 | @@ -208,6 +208,7 @@ |
43 | -- BugSubscriptionFilter |
44 | COMMENT ON TABLE BugSubscriptionFilter IS 'A filter with search criteria. Emails are sent only if the affected bug matches the specified parameters. The parameters are the same as those used for bugtask searches.'; |
45 | COMMENT ON COLUMN BugSubscriptionFilter.structuralsubscription IS 'The structural subscription to be filtered.'; |
46 | +COMMENT ON COLUMN BugSubscriptionFilter.bug_notification_level IS 'The volume and type of bug notifications this filter will allow. The value is an item of the enumeration `BugNotificationLevel`.'; |
47 | COMMENT ON COLUMN BugSubscriptionFilter.find_all_tags IS 'If set, search for bugs having all tags specified in BugSubscriptionFilterTag, else search for bugs having any of the tags specified in BugSubscriptionFilterTag.'; |
48 | COMMENT ON COLUMN BugSubscriptionFilter.include_any_tags IS 'If True, include messages for bugs having any tag set.'; |
49 | COMMENT ON COLUMN BugSubscriptionFilter.exclude_any_tags IS 'If True, exclude bugs having any tag set.'; |
50 | @@ -2394,7 +2395,6 @@ |
51 | COMMENT ON COLUMN StructuralSubscription.sourcepackagename IS 'The subscription\`s target, when it is a source-package'; |
52 | COMMENT ON COLUMN StructuralSubscription.subscriber IS 'The person subscribed.'; |
53 | COMMENT ON COLUMN StructuralSubscription.subscribed_by IS 'The person initiating the subscription.'; |
54 | -COMMENT ON COLUMN StructuralSubscription.bug_notification_level IS 'The volume and type of bug notifications this subscription will generate. The value is an item of the enumeration `BugNotificationLevel`.'; |
55 | COMMENT ON COLUMN StructuralSubscription.date_created IS 'The date on which this subscription was created.'; |
56 | COMMENT ON COLUMN StructuralSubscription.date_last_updated IS 'The date on which this subscription was last updated.'; |
57 | |
58 | |
59 | === added file 'database/schema/patch-2208-37-0.sql' |
60 | --- database/schema/patch-2208-37-0.sql 1970-01-01 00:00:00 +0000 |
61 | +++ database/schema/patch-2208-37-0.sql 2011-02-01 19:35:24 +0000 |
62 | @@ -0,0 +1,12 @@ |
63 | +-- Copyright 2011 Canonical Ltd. This software is licensed under the |
64 | +-- GNU Affero General Public License version 3 (see the file LICENSE). |
65 | +SET client_min_messages=ERROR; |
66 | + |
67 | +ALTER TABLE StructuralSubscription |
68 | + DROP COLUMN bug_notification_level; |
69 | +ALTER TABLE BugSubscriptionFilter |
70 | + ADD COLUMN bug_notification_level |
71 | + integer DEFAULT 40 NOT NULL; |
72 | +CREATE INDEX bugsubscriptionfilter__bug_notification_level__idx ON bugsubscriptionfilter USING btree (bug_notification_level); |
73 | + |
74 | +INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 37, 0); |
75 | |
76 | === modified file 'lib/canonical/launchpad/mail/helpers.py' |
77 | --- lib/canonical/launchpad/mail/helpers.py 2010-11-25 04:42:51 +0000 |
78 | +++ lib/canonical/launchpad/mail/helpers.py 2011-02-01 19:35:24 +0000 |
79 | @@ -112,11 +112,7 @@ |
80 | # Is the person one of the package subscribers? |
81 | bug_sub = bugtask.target.getSubscription(person) |
82 | if bug_sub is not None: |
83 | - if (bug_sub.bug_notification_level > |
84 | - BugNotificationLevel.NOTHING): |
85 | - # The user is subscribed to bug notifications |
86 | - # for this package |
87 | - return bugtask |
88 | + return bugtask |
89 | return None |
90 | |
91 | |
92 | |
93 | === modified file 'lib/lp/bugs/browser/bugsubscriptionfilter.py' |
94 | --- lib/lp/bugs/browser/bugsubscriptionfilter.py 2011-01-14 10:26:37 +0000 |
95 | +++ lib/lp/bugs/browser/bugsubscriptionfilter.py 2011-02-01 19:35:24 +0000 |
96 | @@ -22,7 +22,10 @@ |
97 | custom_widget, |
98 | LaunchpadEditFormView, |
99 | ) |
100 | +from lp.registry.enum import BugNotificationLevel |
101 | +from lp.services.propertycache import cachedproperty |
102 | from lp.bugs.browser.widgets.bug import BugTagsFrozenSetWidget |
103 | +from lp.bugs.browser.bugsubscription import AdvancedSubscriptionMixin |
104 | from lp.bugs.interfaces.bugsubscriptionfilter import IBugSubscriptionFilter |
105 | |
106 | |
107 | @@ -74,7 +77,8 @@ |
108 | return conditions |
109 | |
110 | |
111 | -class BugSubscriptionFilterEditViewBase(LaunchpadEditFormView): |
112 | +class BugSubscriptionFilterEditViewBase(LaunchpadEditFormView, |
113 | + AdvancedSubscriptionMixin): |
114 | """Base class for edit or create views of `IBugSubscriptionFilter`.""" |
115 | |
116 | schema = IBugSubscriptionFilter |
117 | @@ -91,6 +95,33 @@ |
118 | custom_widget("importances", LabeledMultiCheckBoxWidget) |
119 | custom_widget("tags", BugTagsFrozenSetWidget, displayWidth=35) |
120 | |
121 | + target = None # Define in concrete subclass to be the target of the |
122 | + # structural subscription that we are modifying. |
123 | + |
124 | + # This is used by the AdvancedSubscriptionMixin. |
125 | + current_user_subscription = None |
126 | + |
127 | + @cachedproperty |
128 | + def _bug_notification_level_descriptions(self): |
129 | + displayname = self.target.displayname |
130 | + return { |
131 | + BugNotificationLevel.LIFECYCLE: ( |
132 | + "A bug in %s is fixed or re-opened." % displayname), |
133 | + BugNotificationLevel.METADATA: ( |
134 | + "Any change is made to a bug in %s, other than a new " |
135 | + "comment being added." % displayname), |
136 | + BugNotificationLevel.COMMENTS: ( |
137 | + "A change is made or a new comment is added to a bug in %s." |
138 | + % displayname), |
139 | + } |
140 | + |
141 | + def setUpFields(self): |
142 | + """Set up fields for form. |
143 | + |
144 | + Overrides the usual implementation to also set up bug notification.""" |
145 | + super(BugSubscriptionFilterEditViewBase, self).setUpFields() |
146 | + self._setUpBugNotificationLevelField() |
147 | + |
148 | @property |
149 | def next_url(self): |
150 | """Return to the user's structural subscriptions page.""" |
151 | @@ -119,6 +150,15 @@ |
152 | """Delete the bug filter.""" |
153 | self.context.delete() |
154 | |
155 | + @property |
156 | + def current_user_subscription(self): |
157 | + """Return an object that has the value for bug_notification_level.""" |
158 | + return self.context |
159 | + |
160 | + @property |
161 | + def target(self): |
162 | + return self.context.structural_subscription.target |
163 | + |
164 | |
165 | class BugSubscriptionFilterCreateView( |
166 | BugSubscriptionFilterEditViewBase): |
167 | @@ -138,3 +178,7 @@ |
168 | """Create a new bug filter with the form data.""" |
169 | bug_filter = self.context.newBugFilter() |
170 | self.updateContextFromData(data, context=bug_filter) |
171 | + |
172 | + @property |
173 | + def target(self): |
174 | + return self.context.target |
175 | |
176 | === modified file 'lib/lp/bugs/browser/structuralsubscription.py' |
177 | --- lib/lp/bugs/browser/structuralsubscription.py 2011-01-21 08:12:29 +0000 |
178 | +++ lib/lp/bugs/browser/structuralsubscription.py 2011-02-01 19:35:24 +0000 |
179 | @@ -37,13 +37,11 @@ |
180 | custom_widget, |
181 | LaunchpadFormView, |
182 | ) |
183 | -from lp.bugs.browser.bugsubscription import AdvancedSubscriptionMixin |
184 | from lp.bugs.interfaces.structuralsubscription import ( |
185 | IStructuralSubscription, |
186 | IStructuralSubscriptionForm, |
187 | IStructuralSubscriptionTarget, |
188 | ) |
189 | -from lp.registry.enum import BugNotificationLevel |
190 | from lp.registry.interfaces.distributionsourcepackage import ( |
191 | IDistributionSourcePackage, |
192 | ) |
193 | @@ -65,8 +63,7 @@ |
194 | return None |
195 | |
196 | |
197 | -class StructuralSubscriptionView(LaunchpadFormView, |
198 | - AdvancedSubscriptionMixin): |
199 | +class StructuralSubscriptionView(LaunchpadFormView): |
200 | |
201 | """View class for structural subscriptions.""" |
202 | |
203 | @@ -77,21 +74,6 @@ |
204 | |
205 | override_title_breadcrumbs = True |
206 | |
207 | - @cachedproperty |
208 | - def _bug_notification_level_descriptions(self): |
209 | - return { |
210 | - BugNotificationLevel.LIFECYCLE: ( |
211 | - "A bug in %s is fixed or re-opened." % |
212 | - self.context.displayname), |
213 | - BugNotificationLevel.METADATA: ( |
214 | - "Any change is made to a bug in %s, other than a new " |
215 | - "comment being added." % |
216 | - self.context.displayname), |
217 | - BugNotificationLevel.COMMENTS: ( |
218 | - "A change is made or a new comment is added to a bug in %s." |
219 | - % self.context.displayname), |
220 | - } |
221 | - |
222 | @property |
223 | def page_title(self): |
224 | return 'Subscribe to Bugs in %s' % self.context.title |
225 | @@ -116,7 +98,6 @@ |
226 | remove_other = self._createRemoveOtherSubscriptionsField() |
227 | if remove_other: |
228 | self.form_fields += form.Fields(remove_other) |
229 | - self._setUpBugNotificationLevelField() |
230 | |
231 | def _createTeamSubscriptionsField(self): |
232 | """Create field with a list of the teams the user is a member of. |
233 | @@ -204,21 +185,12 @@ |
234 | for the context target. |
235 | """ |
236 | subscription = self.context.getSubscription(person) |
237 | - if subscription is not None: |
238 | - return (subscription.bug_notification_level > |
239 | - BugNotificationLevel.NOTHING) |
240 | - else: |
241 | - return False |
242 | + return subscription is not None |
243 | |
244 | def currentUserIsSubscribed(self): |
245 | """Return True, if the current user is subscribed.""" |
246 | return self.isSubscribed(self.user) |
247 | |
248 | - @cachedproperty |
249 | - def current_user_subscription(self): |
250 | - """Return the subscription of the current user.""" |
251 | - return self.context.getSubscription(self.user) |
252 | - |
253 | def userCanAlter(self): |
254 | if self.context.userCanAlterBugSubscription(self.user, self.user): |
255 | return True |
256 | @@ -240,9 +212,7 @@ |
257 | is_subscribed = self.isSubscribed(self.user) |
258 | subscribe = data['subscribe_me'] |
259 | if (not is_subscribed) and subscribe: |
260 | - target.addBugSubscription( |
261 | - self.user, self.user, |
262 | - data.get('bug_notification_level', None)) |
263 | + target.addBugSubscription(self.user, self.user) |
264 | self.request.response.addNotification( |
265 | 'You have subscribed to "%s". You will now receive an ' |
266 | 'e-mail each time someone reports or changes one of ' |
267 | @@ -271,8 +241,7 @@ |
268 | team for team in teams if self.isSubscribed(team)) |
269 | |
270 | for team in form_selected_teams - subscriptions: |
271 | - target.addBugSubscription( |
272 | - team, self.user, data.get('bug_notification_level', None)) |
273 | + target.addBugSubscription(team, self.user) |
274 | self.request.response.addNotification( |
275 | 'The %s team will now receive an e-mail each time ' |
276 | 'someone reports or changes a public bug in "%s".' % ( |
277 | |
278 | === modified file 'lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py' |
279 | --- lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py 2011-01-21 08:12:29 +0000 |
280 | +++ lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py 2011-02-01 19:35:24 +0000 |
281 | @@ -28,7 +28,10 @@ |
282 | from lp.bugs.browser.structuralsubscription import ( |
283 | StructuralSubscriptionNavigation, |
284 | ) |
285 | +from lp.registry.enum import BugNotificationLevel |
286 | from lp.testing import ( |
287 | + feature_flags, |
288 | + set_feature_flag, |
289 | anonymous_logged_in, |
290 | login_person, |
291 | normalize_whitespace, |
292 | @@ -435,6 +438,88 @@ |
293 | self.assertEqual([], list(self.subscription.bug_filters)) |
294 | |
295 | |
296 | +class TestBugSubscriptionFilterAdvancedFeatures(TestCaseWithFactory): |
297 | + """A base class for testing advanced structural subscription features.""" |
298 | + |
299 | + layer = LaunchpadFunctionalLayer |
300 | + |
301 | + def setUp(self): |
302 | + super(TestBugSubscriptionFilterAdvancedFeatures, self).setUp() |
303 | + self.setUpTarget() |
304 | + with feature_flags(): |
305 | + set_feature_flag(u'malone.advanced-subscriptions.enabled', u'on') |
306 | + |
307 | + def setUpTarget(self): |
308 | + self.target = self.factory.makeProduct() |
309 | + |
310 | + def test_filter_uses_bug_notification_level(self): |
311 | + # When advanced features are turned on for subscriptions a user |
312 | + # can specify a bug_notification_level on the +filter form. |
313 | + with feature_flags(): |
314 | + # We don't display BugNotificationLevel.NOTHING as an option. |
315 | + displayed_levels = [ |
316 | + level for level in BugNotificationLevel.items |
317 | + if level != BugNotificationLevel.NOTHING] |
318 | + for level in displayed_levels: |
319 | + person = self.factory.makePerson() |
320 | + with person_logged_in(person): |
321 | + subscription = self.target.addBugSubscription(person, person) |
322 | + form = { |
323 | + "field.description": "New description", |
324 | + "field.statuses": ["NEW", "INCOMPLETE"], |
325 | + "field.importances": ["LOW", "MEDIUM"], |
326 | + "field.tags": u"foo bar", |
327 | + "field.find_all_tags": "on", |
328 | + 'field.bug_notification_level': level.name, |
329 | + "field.actions.create": "Create", |
330 | + } |
331 | + view = create_initialized_view( |
332 | + subscription, name="+new-filter", form=form) |
333 | + |
334 | + filters = subscription.bug_filters |
335 | + self.assertEqual(filters.count(), 1) |
336 | + self.assertEqual( |
337 | + level, filters[0].bug_notification_level, |
338 | + "Bug notification level of filter should be %s, " |
339 | + "is actually %s." % ( |
340 | + level.name, filters[0].bug_notification_level.name)) |
341 | + |
342 | + def test_nothing_is_not_a_valid_level(self): |
343 | + # BugNotificationLevel.NOTHING isn't considered valid when a |
344 | + # user is subscribing via the web UI. |
345 | + person = self.factory.makePerson() |
346 | + with person_logged_in(person): |
347 | + subscription = self.target.addBugSubscription(person, person) |
348 | + form = { |
349 | + "field.description": "New description", |
350 | + "field.statuses": ["NEW", "INCOMPLETE"], |
351 | + "field.importances": ["LOW", "MEDIUM"], |
352 | + "field.tags": u"foo bar", |
353 | + "field.find_all_tags": "on", |
354 | + 'field.bug_notification_level': BugNotificationLevel.NOTHING, |
355 | + "field.actions.create": "Create", |
356 | + } |
357 | + with feature_flags(): |
358 | + view = create_initialized_view( |
359 | + subscription, name="+new-filter", form=form) |
360 | + self.assertTrue(view.errors) |
361 | + |
362 | + def test_extra_features_hidden_without_feature_flag(self): |
363 | + # If the malone.advanced-subscriptions.enabled flag is turned |
364 | + # off, the bug_notification_level field doesn't appear on the |
365 | + # form. This is actually not important for the filter, but when |
366 | + # this test fails because we no longer rely on a feature flag, it |
367 | + # can be a reminder to clean up the rest of this test to get |
368 | + # rid of the feature flag code. |
369 | + person = self.factory.makePerson() |
370 | + with person_logged_in(person): |
371 | + subscription = self.target.addBugSubscription(person, person) |
372 | + view = create_initialized_view(subscription, name="+new-filter") |
373 | + form_fields = view.form_fields |
374 | + self.assertIs( |
375 | + None, form_fields.get('bug_notification_level')) |
376 | + |
377 | + |
378 | class TestBugSubscriptionFilterCreateView(TestCaseWithFactory): |
379 | |
380 | layer = DatabaseFunctionalLayer |
381 | |
382 | === modified file 'lib/lp/bugs/browser/tests/test_structuralsubscription.py' |
383 | --- lib/lp/bugs/browser/tests/test_structuralsubscription.py 2011-01-21 08:12:29 +0000 |
384 | +++ lib/lp/bugs/browser/tests/test_structuralsubscription.py 2011-02-01 19:35:24 +0000 |
385 | @@ -33,11 +33,8 @@ |
386 | from lp.registry.browser.product import ProductNavigation |
387 | from lp.registry.browser.productseries import ProductSeriesNavigation |
388 | from lp.registry.browser.project import ProjectNavigation |
389 | -from lp.registry.enum import BugNotificationLevel |
390 | from lp.testing import ( |
391 | - feature_flags, |
392 | person_logged_in, |
393 | - set_feature_flag, |
394 | TestCaseWithFactory, |
395 | ws_object, |
396 | ) |
397 | @@ -169,136 +166,6 @@ |
398 | self.navigation = DistributionSourcePackageNavigation |
399 | |
400 | |
401 | -class TestStructuralSubscriptionAdvancedFeaturesBase(TestCaseWithFactory): |
402 | - """A base class for testing advanced structural subscription features.""" |
403 | - |
404 | - layer = LaunchpadFunctionalLayer |
405 | - |
406 | - def setUp(self): |
407 | - super(TestStructuralSubscriptionAdvancedFeaturesBase, self).setUp() |
408 | - self.setUpTarget() |
409 | - with feature_flags(): |
410 | - set_feature_flag(u'malone.advanced-subscriptions.enabled', u'on') |
411 | - |
412 | - def setUpTarget(self): |
413 | - self.target = self.factory.makeProduct() |
414 | - |
415 | - def test_subscribe_uses_bug_notification_level(self): |
416 | - # When advanced features are turned on for subscriptions a user |
417 | - # can specify a bug_notification_level on the +subscribe form. |
418 | - with feature_flags(): |
419 | - # We don't display BugNotificationLevel.NOTHING as an option. |
420 | - displayed_levels = [ |
421 | - level for level in BugNotificationLevel.items |
422 | - if level != BugNotificationLevel.NOTHING] |
423 | - for level in displayed_levels: |
424 | - person = self.factory.makePerson() |
425 | - with person_logged_in(person): |
426 | - harness = LaunchpadFormHarness( |
427 | - self.target, StructuralSubscriptionView) |
428 | - form_data = { |
429 | - 'field.subscribe_me': 'on', |
430 | - 'field.bug_notification_level': level.name, |
431 | - } |
432 | - harness.submit('save', form_data) |
433 | - self.assertFalse(harness.hasErrors()) |
434 | - |
435 | - subscription = self.target.getSubscription(person) |
436 | - self.assertEqual( |
437 | - level, subscription.bug_notification_level, |
438 | - "Bug notification level of subscription should be %s, " |
439 | - "is actually %s." % ( |
440 | - level.name, subscription.bug_notification_level.name)) |
441 | - |
442 | - def test_subscribe_uses_bug_notification_level_for_teams(self): |
443 | - # The bug_notification_level field is also used when subscribing |
444 | - # a team. |
445 | - with feature_flags(): |
446 | - displayed_levels = [ |
447 | - level for level in BugNotificationLevel.items |
448 | - if level != BugNotificationLevel.NOTHING] |
449 | - for level in displayed_levels: |
450 | - person = self.factory.makePerson() |
451 | - team = self.factory.makeTeam(owner=person) |
452 | - with person_logged_in(person): |
453 | - harness = LaunchpadFormHarness( |
454 | - self.target, StructuralSubscriptionView) |
455 | - form_data = { |
456 | - 'field.subscribe_me': '', |
457 | - 'field.subscriptions_team': team.name, |
458 | - 'field.bug_notification_level': level.name, |
459 | - } |
460 | - harness.submit('save', form_data) |
461 | - self.assertFalse(harness.hasErrors()) |
462 | - |
463 | - subscription = self.target.getSubscription(team) |
464 | - self.assertEqual( |
465 | - level, subscription.bug_notification_level, |
466 | - "Bug notification level of subscription should be %s, " |
467 | - "is actually %s." % ( |
468 | - level.name, subscription.bug_notification_level.name)) |
469 | - |
470 | - def test_nothing_is_not_a_valid_level(self): |
471 | - # BugNotificationLevel.NOTHING isn't considered valid when a |
472 | - # user is subscribing via the web UI. |
473 | - person = self.factory.makePerson() |
474 | - with feature_flags(): |
475 | - with person_logged_in(person): |
476 | - harness = LaunchpadFormHarness( |
477 | - self.target, StructuralSubscriptionView) |
478 | - form_data = { |
479 | - 'field.subscribe_me': 'on', |
480 | - 'field.bug_notification_level': ( |
481 | - BugNotificationLevel.NOTHING), |
482 | - } |
483 | - harness.submit('save', form_data) |
484 | - self.assertTrue(harness.hasErrors()) |
485 | - |
486 | - def test_extra_features_hidden_without_feature_flag(self): |
487 | - # If the malone.advanced-subscriptions.enabled flag is turned |
488 | - # off, the bug_notification_level field doesn't appear on the |
489 | - # form. |
490 | - person = self.factory.makePerson() |
491 | - with person_logged_in(person): |
492 | - harness = LaunchpadFormHarness( |
493 | - self.target, StructuralSubscriptionView) |
494 | - form_fields = harness.view.form_fields |
495 | - self.assertIs( |
496 | - None, form_fields.get('bug_notification_level')) |
497 | - |
498 | - |
499 | -class TestProductSeriesAdvancedSubscriptionFeatures( |
500 | - TestStructuralSubscriptionAdvancedFeaturesBase): |
501 | - """Test advanced subscription features for ProductSeries.""" |
502 | - |
503 | - def setUpTarget(self): |
504 | - self.target = self.factory.makeProductSeries() |
505 | - |
506 | - |
507 | -class TestDistributionAdvancedSubscriptionFeatures( |
508 | - TestStructuralSubscriptionAdvancedFeaturesBase): |
509 | - """Test advanced subscription features for distributions.""" |
510 | - |
511 | - def setUpTarget(self): |
512 | - self.target = self.factory.makeDistribution() |
513 | - |
514 | - |
515 | -class TestDistroSeriesAdvancedSubscriptionFeatures( |
516 | - TestStructuralSubscriptionAdvancedFeaturesBase): |
517 | - """Test advanced subscription features for DistroSeries.""" |
518 | - |
519 | - def setUpTarget(self): |
520 | - self.target = self.factory.makeDistroSeries() |
521 | - |
522 | - |
523 | -class TestMilestoneAdvancedSubscriptionFeatures( |
524 | - TestStructuralSubscriptionAdvancedFeaturesBase): |
525 | - """Test advanced subscription features for Milestones.""" |
526 | - |
527 | - def setUpTarget(self): |
528 | - self.target = self.factory.makeMilestone() |
529 | - |
530 | - |
531 | class TestStructuralSubscriptionView(TestCaseWithFactory): |
532 | """General tests for the StructuralSubscriptionView.""" |
533 | |
534 | |
535 | === modified file 'lib/lp/bugs/doc/bug-change.txt' |
536 | --- lib/lp/bugs/doc/bug-change.txt 2010-10-18 22:24:59 +0000 |
537 | +++ lib/lp/bugs/doc/bug-change.txt 2011-02-01 19:35:24 +0000 |
538 | @@ -140,6 +140,7 @@ |
539 | bug's target for Meta data changes, but not for lifecycle changes. |
540 | |
541 | |
542 | + >>> from lp.testing import person_logged_in |
543 | >>> from lp.registry.enum import BugNotificationLevel |
544 | >>> lifecycle_subscriber = factory.makePerson( |
545 | ... displayname='Lifecycle subscriber') |
546 | @@ -147,10 +148,14 @@ |
547 | ... displayname='Meta-data subscriber') |
548 | >>> subscription = example_bug.bugtasks[0].target.addBugSubscription( |
549 | ... lifecycle_subscriber, lifecycle_subscriber) |
550 | - >>> subscription.bug_notification_level = BugNotificationLevel.LIFECYCLE |
551 | + >>> with person_logged_in(lifecycle_subscriber): |
552 | + ... filter = subscription.newBugFilter() |
553 | + ... filter.bug_notification_level = BugNotificationLevel.LIFECYCLE |
554 | >>> subscription = example_bug.bugtasks[0].target.addBugSubscription( |
555 | ... metadata_subscriber, metadata_subscriber) |
556 | - >>> subscription.bug_notification_level = BugNotificationLevel.METADATA |
557 | + >>> with person_logged_in(metadata_subscriber): |
558 | + ... filter = subscription.newBugFilter() |
559 | + ... filter.bug_notification_level = BugNotificationLevel.METADATA |
560 | >>> example_bug.addChange( |
561 | ... TestBugChange(when=nowish, person=example_person)) |
562 | >>> latest_notification = BugNotification.selectFirst(orderBy='-id') |
563 | |
564 | === modified file 'lib/lp/bugs/doc/bugnotification-sending.txt' |
565 | --- lib/lp/bugs/doc/bugnotification-sending.txt 2011-01-06 14:44:56 +0000 |
566 | +++ lib/lp/bugs/doc/bugnotification-sending.txt 2011-02-01 19:35:24 +0000 |
567 | @@ -1118,12 +1118,74 @@ |
568 | >>> switch_db_to_bugnotification() |
569 | |
570 | The notifications generated by addCommentNotification() are sent only to |
571 | -structural subscribers with the notification level COMMENTS or higher. |
572 | -The notification level of Sample Person is COMMENTS, hence he receives |
573 | -these notifications. |
574 | - |
575 | - >>> print subscription_no_priv.bug_notification_level.name |
576 | - COMMENTS |
577 | +structural subscribers with no filters, or with the notification level |
578 | +of COMMENTS or higher. Sample Person's subscription currently does not |
579 | +have any filters, so he receives these notifications. |
580 | + |
581 | + >>> print subscription_no_priv.bug_filters.count() |
582 | + 0 |
583 | + >>> comment = getUtility(IMessageSet).fromText( |
584 | + ... 'subject', 'another comment.', sample_person, |
585 | + ... datecreated=ten_minutes_ago) |
586 | + >>> bug_one.addCommentNotification(comment) |
587 | + >>> pending_notifications = getUtility( |
588 | + ... IBugNotificationSet).getNotificationsToSend() |
589 | + >>> email_notifications = get_email_notifications(pending_notifications) |
590 | + >>> for bug_notifications, messages in email_notifications: |
591 | + ... for message in messages: |
592 | + ... print_notification(message) |
593 | + To: foo.bar@canonical.com |
594 | + ... |
595 | + You received this bug notification because you are subscribed to |
596 | + mozilla-firefox in ubuntu. |
597 | + ... |
598 | + ---------------------------------------------------------------------- |
599 | + To: marilize@hbd.com |
600 | + ... |
601 | + You received this bug notification because you are a member of ShipIt |
602 | + Administrators, which is a direct subscriber. |
603 | + ... |
604 | + ---------------------------------------------------------------------- |
605 | + To: mark@example.com |
606 | + ... |
607 | + You received this bug notification because you are a bug assignee. |
608 | + ... |
609 | + ---------------------------------------------------------------------- |
610 | + To: no-priv@canonical.com |
611 | + From: Sample Person <...@bugs.launchpad.net> |
612 | + Subject: [Bug 1] subject |
613 | + X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox) |
614 | + <BLANKLINE> |
615 | + another comment. |
616 | + <BLANKLINE> |
617 | + -- |
618 | + You received this bug notification because you are subscribed to Mozilla |
619 | + Firefox. |
620 | + ... |
621 | + ---------------------------------------------------------------------- |
622 | + To: support@ubuntu.com |
623 | + ... |
624 | + You received this bug notification because you are a member of Ubuntu |
625 | + Team, which is the registrant for Ubuntu. |
626 | + ... |
627 | + ---------------------------------------------------------------------- |
628 | + To: test@canonical.com |
629 | + ... |
630 | + You received this bug notification because you are a direct subscriber |
631 | + of the bug. |
632 | + ... |
633 | + ---------------------------------------------------------------------- |
634 | + |
635 | +If Sample Person gets a filter with an explicit notification level of |
636 | +COMMENTS, he also receives these notifications. |
637 | + |
638 | + |
639 | + >>> flush_notifications() |
640 | + >>> switch_db_to_launchpad() |
641 | + >>> filter = subscription_no_priv.newBugFilter() |
642 | + >>> filter.bug_notification_level = BugNotificationLevel.COMMENTS |
643 | + >>> switch_db_to_bugnotification() |
644 | + |
645 | >>> comment = getUtility(IMessageSet).fromText( |
646 | ... 'subject', 'another comment.', sample_person, |
647 | ... datecreated=ten_minutes_ago) |
648 | @@ -1181,8 +1243,7 @@ |
649 | |
650 | >>> flush_notifications() |
651 | >>> switch_db_to_launchpad() |
652 | - >>> subscription_no_priv.bug_notification_level = ( |
653 | - ... BugNotificationLevel.METADATA) |
654 | + >>> filter.bug_notification_level = BugNotificationLevel.METADATA |
655 | >>> switch_db_to_bugnotification() |
656 | |
657 | >>> comment = getUtility(IMessageSet).fromText( |
658 | @@ -1294,8 +1355,7 @@ |
659 | |
660 | >>> flush_notifications() |
661 | >>> switch_db_to_launchpad() |
662 | - >>> subscription_no_priv.bug_notification_level = ( |
663 | - ... BugNotificationLevel.LIFECYCLE) |
664 | + >>> filter.bug_notification_level = BugNotificationLevel.LIFECYCLE |
665 | >>> switch_db_to_bugnotification() |
666 | |
667 | >>> bug_one.addChangeNotification('** Summary changed to: something.', |
668 | @@ -1346,3 +1406,66 @@ |
669 | of the bug. |
670 | ... |
671 | ---------------------------------------------------------------------- |
672 | + |
673 | +Note that, if two filters exist and they both match the same bug, the |
674 | +more inclusive filter wins. Therefore, while we saw before that the |
675 | +filter did not allow the change notification through, if we add another |
676 | +filter that includes metadata then the notification will be sent out |
677 | +after all. |
678 | + |
679 | + >>> flush_notifications() |
680 | + >>> switch_db_to_launchpad() |
681 | + >>> filter2 = subscription_no_priv.newBugFilter() |
682 | + >>> filter2.bug_notification_level = BugNotificationLevel.METADATA |
683 | + >>> switch_db_to_bugnotification() |
684 | + |
685 | + >>> bug_one.addChangeNotification('** Summary changed to: whatever.', |
686 | + ... sample_person, when=ten_minutes_ago) |
687 | + >>> pending_notifications = getUtility( |
688 | + ... IBugNotificationSet).getNotificationsToSend() |
689 | + >>> email_notifications = get_email_notifications(pending_notifications) |
690 | + >>> for bug_notifications, messages in email_notifications: |
691 | + ... for message in messages: |
692 | + ... print_notification(message) |
693 | + To: foo.bar@canonical.com |
694 | + ... |
695 | + You received this bug notification because you are subscribed to |
696 | + mozilla-firefox in ubuntu. |
697 | + http://bugs.launchpad.dev/bugs/1 |
698 | + ... |
699 | + ---------------------------------------------------------------------- |
700 | + To: marilize@hbd.com |
701 | + ... |
702 | + You received this bug notification because you are a member of ShipIt |
703 | + Administrators, which is a direct subscriber. |
704 | + ... |
705 | + ---------------------------------------------------------------------- |
706 | + To: mark@example.com |
707 | + ... |
708 | + You received this bug notification because you are a bug assignee. |
709 | + ... |
710 | + ---------------------------------------------------------------------- |
711 | + To: no-priv@canonical.com |
712 | + From: Sample Person <...@bugs.launchpad.net> |
713 | + Subject: [Bug 1] Re: Firefox does not support SVG |
714 | + X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox) |
715 | + <BLANKLINE> |
716 | + ** Summary changed to: whatever. |
717 | + <BLANKLINE> |
718 | + -- |
719 | + You received this bug notification because you are subscribed to Mozilla |
720 | + Firefox. |
721 | + ... |
722 | + ---------------------------------------------------------------------- |
723 | + To: support@ubuntu.com |
724 | + ... |
725 | + You received this bug notification because you are a member of Ubuntu |
726 | + Team, which is the registrant for Ubuntu. |
727 | + ... |
728 | + ---------------------------------------------------------------------- |
729 | + To: test@canonical.com |
730 | + ... |
731 | + You received this bug notification because you are a direct subscriber |
732 | + of the bug. |
733 | + ... |
734 | + ---------------------------------------------------------------------- |
735 | |
736 | === modified file 'lib/lp/bugs/doc/bugsubscription.txt' |
737 | --- lib/lp/bugs/doc/bugsubscription.txt 2011-01-27 09:47:06 +0000 |
738 | +++ lib/lp/bugs/doc/bugsubscription.txt 2011-02-01 19:35:24 +0000 |
739 | @@ -250,11 +250,14 @@ |
740 | have a bug notification level greater than or equal to the value passed |
741 | in the `level` parameter are returned. |
742 | |
743 | -The bug notification level of No Privileges Person's structural |
744 | -subscription is currently set to COMMENTS. |
745 | +Structural subscriptions control their bug notification levels via zero |
746 | +or more filters. If there are no filters, the subscription is |
747 | +interpreted to mean that the subscriber wants all notifications. In the |
748 | +case of bug notification levels, that is equivalent to |
749 | +BugNotificationLevel.COMMENTS. |
750 | |
751 | - >>> print subscription_no_priv.bug_notification_level.name |
752 | - COMMENTS |
753 | + >>> print subscription_no_priv.bug_filters.count() |
754 | + 0 |
755 | |
756 | With this subscription level, No Privileges Person is returned for all |
757 | parameter values of level. |
758 | @@ -288,11 +291,15 @@ |
759 | Sample Person |
760 | Ubuntu Team |
761 | |
762 | -If No Privileges Person sets his notification level to LIFECYCLE, he will |
763 | -not be included, if the parameter `level` is METADATA or COMMENTS. |
764 | +If No Privileges Person created a single filter with a notification |
765 | +level set to LIFECYCLE, he will not be included, if the parameter |
766 | +`level` is METADATA or COMMENTS. |
767 | |
768 | - >>> subscription_no_priv.bug_notification_level = ( |
769 | - ... BugNotificationLevel.LIFECYCLE) |
770 | + >>> from lp.testing import person_logged_in |
771 | + >>> with person_logged_in(mr_no_privs): |
772 | + ... filter_no_priv = subscription_no_priv.newBugFilter() |
773 | + ... filter_no_priv.bug_notification_level = ( |
774 | + ... BugNotificationLevel.LIFECYCLE) |
775 | |
776 | >>> print_displayname(linux_source_bug.getAlsoNotifiedSubscribers( |
777 | ... level=BugNotificationLevel.LIFECYCLE)) |
778 | |
779 | === modified file 'lib/lp/bugs/doc/structural-subscriptions.txt' |
780 | --- lib/lp/bugs/doc/structural-subscriptions.txt 2011-01-21 11:25:22 +0000 |
781 | +++ lib/lp/bugs/doc/structural-subscriptions.txt 2011-02-01 19:35:24 +0000 |
782 | @@ -24,8 +24,6 @@ |
783 | ... subscriber=sampleperson, subscribed_by=foobar) |
784 | >>> ff_sub.target |
785 | <Product at ...> |
786 | - >>> ff_sub.bug_notification_level |
787 | - <DBItem BugNotificationLevel.NOTHING, (10) Nothing> |
788 | |
789 | >>> ubuntu_sub = StructuralSubscription(distribution=ubuntu, |
790 | ... subscriber=sampleperson, subscribed_by=foobar) |
791 | |
792 | === modified file 'lib/lp/bugs/interfaces/bugsubscriptionfilter.py' |
793 | --- lib/lp/bugs/interfaces/bugsubscriptionfilter.py 2011-01-21 08:12:29 +0000 |
794 | +++ lib/lp/bugs/interfaces/bugsubscriptionfilter.py 2011-02-01 19:35:24 +0000 |
795 | @@ -25,6 +25,7 @@ |
796 | ) |
797 | |
798 | from canonical.launchpad import _ |
799 | +from lp.registry.enum import BugNotificationLevel |
800 | from lp.bugs.interfaces.bugtask import ( |
801 | BugTaskImportance, |
802 | BugTaskStatus, |
803 | @@ -59,6 +60,13 @@ |
804 | exclude_any_tags = Bool( |
805 | title=_("Exclude all tags"), |
806 | required=True, default=False) |
807 | + bug_notification_level = exported( |
808 | + Choice( |
809 | + title=_("Bug notification level"), required=True, |
810 | + vocabulary=BugNotificationLevel, |
811 | + default=BugNotificationLevel.NOTHING, |
812 | + description=_("The volume and type of bug notifications " |
813 | + "this subscription will generate."))) |
814 | |
815 | description = exported( |
816 | Text( |
817 | |
818 | === modified file 'lib/lp/bugs/interfaces/structuralsubscription.py' |
819 | --- lib/lp/bugs/interfaces/structuralsubscription.py 2011-01-21 08:12:29 +0000 |
820 | +++ lib/lp/bugs/interfaces/structuralsubscription.py 2011-02-01 19:35:24 +0000 |
821 | @@ -8,7 +8,6 @@ |
822 | __metaclass__ = type |
823 | |
824 | __all__ = [ |
825 | - 'BugNotificationLevel', |
826 | 'IStructuralSubscription', |
827 | 'IStructuralSubscriptionForm', |
828 | 'IStructuralSubscriptionTarget', |
829 | @@ -47,7 +46,6 @@ |
830 | ) |
831 | |
832 | from canonical.launchpad import _ |
833 | -from lp.registry.enum import BugNotificationLevel |
834 | from lp.registry.interfaces.person import IPerson |
835 | from lp.services.fields import ( |
836 | PersonChoice, |
837 | @@ -76,12 +74,6 @@ |
838 | title=_('Subscribed by'), required=True, |
839 | vocabulary='ValidPersonOrTeam', readonly=True, |
840 | description=_("The person creating the subscription."))) |
841 | - bug_notification_level = Choice( |
842 | - title=_("Bug notification level"), required=True, |
843 | - vocabulary=BugNotificationLevel, |
844 | - default=BugNotificationLevel.NOTHING, |
845 | - description=_("The volume and type of bug notifications " |
846 | - "this subscription will generate.")) |
847 | date_created = exported(Datetime( |
848 | title=_("The date on which this subscription was created."), |
849 | required=False, readonly=True)) |
850 | @@ -121,17 +113,11 @@ |
851 | Read-only parts. |
852 | """ |
853 | |
854 | - # We don't really want to expose the level details yet. Only |
855 | - # BugNotificationLevel.COMMENTS is used at this time. |
856 | - @call_with( |
857 | - min_bug_notification_level=BugNotificationLevel.COMMENTS) |
858 | @operation_returns_collection_of(IStructuralSubscription) |
859 | @export_read_operation() |
860 | - def getSubscriptions(min_bug_notification_level): |
861 | + def getSubscriptions(): |
862 | """Return all the subscriptions with the specified levels. |
863 | |
864 | - :min_bug_notification_level: The lowest bug notification level |
865 | - for which subscriptions should be returned. |
866 | :return: A sequence of `IStructuralSubscription`. |
867 | """ |
868 | |
869 | @@ -172,7 +158,7 @@ |
870 | """Add a subscription for this structure. |
871 | |
872 | This method is used to create a new `IStructuralSubscription` |
873 | - for the target, with no levels set. |
874 | + for the target, without filters. |
875 | |
876 | :subscriber: The IPerson who will be subscribed. If omitted, |
877 | subscribed_by will be used. |
878 | @@ -189,20 +175,16 @@ |
879 | required=False)) |
880 | @call_with(subscribed_by=REQUEST_USER) |
881 | @export_factory_operation(IStructuralSubscription, []) |
882 | - def addBugSubscription(subscriber, subscribed_by, |
883 | - bug_notification_level=None): |
884 | + def addBugSubscription(subscriber, subscribed_by): |
885 | """Add a bug subscription for this structure. |
886 | |
887 | This method is used to create a new `IStructuralSubscription` |
888 | - for the target with the bug notification level set to |
889 | - COMMENTS, the only level currently in use. |
890 | + for the target. This initially is without filters, which will |
891 | + mean that all notifications will be sent. |
892 | |
893 | :subscriber: The IPerson who will be subscribed. If omitted, |
894 | subscribed_by will be used. |
895 | :subscribed_by: The IPerson creating the subscription. |
896 | - :bug_notification_level: The BugNotificationLevel for the |
897 | - subscription. If omitted, BugNotificationLevel.COMMENTS will be |
898 | - used. |
899 | :return: The new bug subscription. |
900 | """ |
901 | |
902 | @@ -218,9 +200,7 @@ |
903 | def removeBugSubscription(subscriber, unsubscribed_by): |
904 | """Remove a subscription to bugs from this structure. |
905 | |
906 | - If subscription levels for other applications are set, |
907 | - set the subscription's `bug_notification_level` to |
908 | - `NOTHING`, otherwise, destroy the subscription. |
909 | + This will delete all associated filters. |
910 | |
911 | :subscriber: The IPerson who will be unsubscribed. If omitted, |
912 | unsubscribed_by will be used. |
913 | |
914 | === modified file 'lib/lp/bugs/model/bugsubscriptionfilter.py' |
915 | --- lib/lp/bugs/model/bugsubscriptionfilter.py 2011-01-20 19:39:08 +0000 |
916 | +++ lib/lp/bugs/model/bugsubscriptionfilter.py 2011-02-01 19:35:24 +0000 |
917 | @@ -17,9 +17,11 @@ |
918 | ) |
919 | from zope.interface import implements |
920 | |
921 | +from canonical.database.enumcol import DBEnum |
922 | from canonical.launchpad import searchbuilder |
923 | from canonical.launchpad.interfaces.lpstorm import IStore |
924 | from lp.bugs.interfaces.bugsubscriptionfilter import IBugSubscriptionFilter |
925 | +from lp.registry.enum import BugNotificationLevel |
926 | from lp.bugs.model.bugsubscriptionfilterimportance import ( |
927 | BugSubscriptionFilterImportance, |
928 | ) |
929 | @@ -44,6 +46,10 @@ |
930 | structural_subscription = Reference( |
931 | structural_subscription_id, "StructuralSubscription.id") |
932 | |
933 | + bug_notification_level = DBEnum( |
934 | + enum=BugNotificationLevel, |
935 | + default=BugNotificationLevel.COMMENTS, |
936 | + allow_none=False) |
937 | find_all_tags = Bool(allow_none=False, default=False) |
938 | include_any_tags = Bool(allow_none=False, default=False) |
939 | exclude_any_tags = Bool(allow_none=False, default=False) |
940 | |
941 | === modified file 'lib/lp/bugs/model/structuralsubscription.py' |
942 | --- lib/lp/bugs/model/structuralsubscription.py 2011-01-22 02:59:35 +0000 |
943 | +++ lib/lp/bugs/model/structuralsubscription.py 2011-02-01 19:35:24 +0000 |
944 | @@ -39,7 +39,6 @@ |
945 | from zope.interface import implements |
946 | |
947 | from canonical.database.constants import UTC_NOW |
948 | -from canonical.database.enumcol import DBEnum |
949 | from canonical.database.sqlbase import quote |
950 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
951 | from canonical.launchpad.interfaces.lpstorm import IStore |
952 | @@ -51,7 +50,6 @@ |
953 | BugSubscriptionFilterStatus, |
954 | ) |
955 | from lp.bugs.model.bugsubscriptionfiltertag import BugSubscriptionFilterTag |
956 | -from lp.registry.enum import BugNotificationLevel |
957 | from lp.registry.errors import ( |
958 | DeleteSubscriptionError, |
959 | UserCannotSubscribePerson, |
960 | @@ -115,10 +113,6 @@ |
961 | validator=validate_public_person) |
962 | subscribed_by = Reference(subscribed_byID, "Person.id") |
963 | |
964 | - bug_notification_level = DBEnum( |
965 | - enum=BugNotificationLevel, |
966 | - default=BugNotificationLevel.NOTHING, |
967 | - allow_none=False) |
968 | date_created = DateTime( |
969 | "date_created", allow_none=False, default=UTC_NOW, |
970 | tzinfo=pytz.UTC) |
971 | @@ -395,24 +389,18 @@ |
972 | return False |
973 | return True |
974 | |
975 | - def addBugSubscription(self, subscriber, subscribed_by, |
976 | - bug_notification_level=None): |
977 | + def addBugSubscription(self, subscriber, subscribed_by): |
978 | """See `IStructuralSubscriptionTarget`.""" |
979 | # This is a helper method for creating a structural |
980 | - # subscription and immediately giving it a full |
981 | - # bug notification level. It is useful so long as |
982 | - # subscriptions are mainly used to implement bug contacts. |
983 | + # subscription. It is useful so long as subscriptions are mainly |
984 | + # used to implement bug contacts. |
985 | |
986 | if not self.userCanAlterBugSubscription(subscriber, subscribed_by): |
987 | raise UserCannotSubscribePerson( |
988 | '%s does not have permission to subscribe %s' % ( |
989 | subscribed_by.name, subscriber.name)) |
990 | |
991 | - sub = self.addSubscription(subscriber, subscribed_by) |
992 | - if bug_notification_level is None: |
993 | - bug_notification_level = BugNotificationLevel.COMMENTS |
994 | - sub.bug_notification_level = bug_notification_level |
995 | - return sub |
996 | + return self.addSubscription(subscriber, subscribed_by) |
997 | |
998 | def removeBugSubscription(self, subscriber, unsubscribed_by): |
999 | """See `IStructuralSubscriptionTarget`.""" |
1000 | @@ -425,13 +413,14 @@ |
1001 | unsubscribed_by.name, subscriber.name)) |
1002 | |
1003 | subscription_to_remove = self.getSubscriptions( |
1004 | - min_bug_notification_level=BugNotificationLevel.METADATA, |
1005 | subscriber=subscriber).one() |
1006 | |
1007 | if subscription_to_remove is None: |
1008 | raise DeleteSubscriptionError( |
1009 | "%s is not subscribed to %s." % ( |
1010 | subscriber.name, self.displayname)) |
1011 | + # XXX gary 2011-02-01 bug=711362 |
1012 | + # We should delete all associated filters. |
1013 | store = Store.of(subscription_to_remove) |
1014 | store.remove(subscription_to_remove) |
1015 | |
1016 | @@ -444,17 +433,10 @@ |
1017 | all_subscriptions = self.getSubscriptions(subscriber=person) |
1018 | return all_subscriptions.one() |
1019 | |
1020 | - def getSubscriptions(self, |
1021 | - min_bug_notification_level= |
1022 | - BugNotificationLevel.NOTHING, |
1023 | - subscriber=None): |
1024 | + def getSubscriptions(self, subscriber=None): |
1025 | """See `IStructuralSubscriptionTarget`.""" |
1026 | from lp.registry.model.person import Person |
1027 | - clauses = [ |
1028 | - StructuralSubscription.subscriberID==Person.id, |
1029 | - (StructuralSubscription.bug_notification_level >= |
1030 | - min_bug_notification_level), |
1031 | - ] |
1032 | + clauses = [StructuralSubscription.subscriberID==Person.id] |
1033 | for key, value in self._target_args.iteritems(): |
1034 | clauses.append( |
1035 | getattr(StructuralSubscription, key)==value) |
1036 | @@ -470,13 +452,11 @@ |
1037 | @property |
1038 | def bug_subscriptions(self): |
1039 | """See `IStructuralSubscriptionTarget`.""" |
1040 | - return self.getSubscriptions( |
1041 | - min_bug_notification_level=BugNotificationLevel.METADATA) |
1042 | + return self.getSubscriptions() |
1043 | |
1044 | def userHasBugSubscriptions(self, user): |
1045 | """See `IStructuralSubscriptionTarget`.""" |
1046 | - bug_subscriptions = self.getSubscriptions( |
1047 | - min_bug_notification_level=BugNotificationLevel.METADATA) |
1048 | + bug_subscriptions = self.getSubscriptions() |
1049 | if user is not None: |
1050 | for subscription in bug_subscriptions: |
1051 | if (subscription.subscriber == user or |
1052 | @@ -523,22 +503,23 @@ |
1053 | # does not know how to compile an expression with a proxied list. |
1054 | self.tags = list(bugtask.bug.tags) |
1055 | # Set up common conditions. |
1056 | - self.base_conditions = And( |
1057 | - StructuralSubscription.bug_notification_level >= level, |
1058 | - join_condition) |
1059 | + self.base_conditions = join_condition |
1060 | # Set up common filter conditions. |
1061 | + self.filter_conditions = And( |
1062 | + BugSubscriptionFilter.bug_notification_level >= level, |
1063 | + self.base_conditions) |
1064 | if len(self.tags) == 0: |
1065 | self.filter_conditions = And( |
1066 | # When the bug has no tags, filters with include_any_tags set |
1067 | # can never match. |
1068 | Not(BugSubscriptionFilter.include_any_tags), |
1069 | - self.base_conditions) |
1070 | + self.filter_conditions) |
1071 | else: |
1072 | self.filter_conditions = And( |
1073 | # When the bug has tags, filters with exclude_any_tags set can |
1074 | # never match. |
1075 | Not(BugSubscriptionFilter.exclude_any_tags), |
1076 | - self.base_conditions) |
1077 | + self.filter_conditions) |
1078 | |
1079 | @property |
1080 | def subscriptions_without_filters(self): |
1081 | |
1082 | === modified file 'lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py' |
1083 | --- lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py 2010-10-04 13:37:00 +0000 |
1084 | +++ lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py 2011-02-01 19:35:24 +0000 |
1085 | @@ -17,6 +17,7 @@ |
1086 | BugTaskStatus, |
1087 | ) |
1088 | from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter |
1089 | +from lp.registry.enum import BugNotificationLevel |
1090 | from lp.testing import ( |
1091 | anonymous_logged_in, |
1092 | login_person, |
1093 | @@ -42,6 +43,8 @@ |
1094 | # Create. |
1095 | bug_subscription_filter = BugSubscriptionFilter() |
1096 | bug_subscription_filter.structural_subscription = self.subscription |
1097 | + bug_subscription_filter.bug_notification_level = ( |
1098 | + BugNotificationLevel.METADATA) |
1099 | bug_subscription_filter.find_all_tags = True |
1100 | bug_subscription_filter.include_any_tags = True |
1101 | bug_subscription_filter.exclude_any_tags = True |
1102 | @@ -61,6 +64,9 @@ |
1103 | self.assertIs(True, bug_subscription_filter.find_all_tags) |
1104 | self.assertIs(True, bug_subscription_filter.include_any_tags) |
1105 | self.assertIs(True, bug_subscription_filter.exclude_any_tags) |
1106 | + self.assertEqual( |
1107 | + BugNotificationLevel.METADATA, |
1108 | + bug_subscription_filter.bug_notification_level) |
1109 | self.assertEqual(u"foo", bug_subscription_filter.other_parameters) |
1110 | self.assertEqual(u"bar", bug_subscription_filter.description) |
1111 | |
1112 | @@ -70,6 +76,9 @@ |
1113 | bug_subscription_filter = BugSubscriptionFilter() |
1114 | bug_subscription_filter.structural_subscription = self.subscription |
1115 | # Check. |
1116 | + self.assertEqual( |
1117 | + BugNotificationLevel.COMMENTS, |
1118 | + bug_subscription_filter.bug_notification_level) |
1119 | self.assertIs(False, bug_subscription_filter.find_all_tags) |
1120 | self.assertIs(False, bug_subscription_filter.include_any_tags) |
1121 | self.assertIs(False, bug_subscription_filter.exclude_any_tags) |
1122 | |
1123 | === modified file 'lib/lp/bugs/model/tests/test_bugtask.py' |
1124 | --- lib/lp/bugs/model/tests/test_bugtask.py 2011-01-20 04:50:35 +0000 |
1125 | +++ lib/lp/bugs/model/tests/test_bugtask.py 2011-02-01 19:35:24 +0000 |
1126 | @@ -1413,12 +1413,13 @@ |
1127 | login_person(subscriber) |
1128 | product, bug = self.make_product_with_bug() |
1129 | subscription = product.addBugSubscription(subscriber, subscriber) |
1130 | - subscription.bug_notification_level = BugNotificationLevel.METADATA |
1131 | + filter = subscription.newBugFilter() |
1132 | + filter.bug_notification_level = BugNotificationLevel.METADATA |
1133 | self.assertEqual( |
1134 | [subscriber], list( |
1135 | self.getStructuralSubscribers( |
1136 | bug.bugtasks, level=BugNotificationLevel.METADATA))) |
1137 | - subscription.bug_notification_level = BugNotificationLevel.METADATA |
1138 | + filter.bug_notification_level = BugNotificationLevel.METADATA |
1139 | self.assertEqual( |
1140 | [], list( |
1141 | self.getStructuralSubscribers( |
1142 | |
1143 | === modified file 'lib/lp/bugs/tests/structural-subscription-target.txt' |
1144 | --- lib/lp/bugs/tests/structural-subscription-target.txt 2011-01-22 02:59:35 +0000 |
1145 | +++ lib/lp/bugs/tests/structural-subscription-target.txt 2011-02-01 19:35:24 +0000 |
1146 | @@ -13,23 +13,19 @@ |
1147 | >>> target.addBugSubscription(ubuntu_team, foobar) |
1148 | <...StructuralSubscription ...> |
1149 | |
1150 | -Trying to remove a bug subscription when notification levels for other |
1151 | -applications are set, doesn't remove the subscription. Instead the |
1152 | -notification level for bugs is set to NOTHING. |
1153 | +We can add and remove these subscriptions. |
1154 | |
1155 | >>> def print_subscriptions_list(subscriptions): |
1156 | ... for subscription in subscriptions: |
1157 | - ... print '%s %s' % ( |
1158 | - ... subscription.subscriber.name, |
1159 | - ... subscription.bug_notification_level.name) |
1160 | + ... print subscription.subscriber.name |
1161 | |
1162 | >>> subscription = target.addBugSubscription(foobar, foobar) |
1163 | >>> print_subscriptions_list(target.getSubscriptions()) |
1164 | - name16 COMMENTS |
1165 | - ubuntu-team COMMENTS |
1166 | + name16 |
1167 | + ubuntu-team |
1168 | >>> target.removeBugSubscription(foobar, foobar) |
1169 | >>> print_subscriptions_list(target.getSubscriptions()) |
1170 | - ubuntu-team COMMENTS |
1171 | + ubuntu-team |
1172 | |
1173 | To get a user's subscription to the target, use |
1174 | IStructuralSubscriptionTarget.getSubscription. |
1175 | @@ -39,19 +35,14 @@ |
1176 | >>> print target.getSubscription(no_priv) |
1177 | None |
1178 | |
1179 | -To search for subscriptions with certain level settings on a structure |
1180 | -we use getSubscriptions. |
1181 | +To search for all subscriptions on a structure we use getSubscriptions. |
1182 | |
1183 | - >>> from lp.registry.enum import BugNotificationLevel |
1184 | + >>> print_subscriptions_list(target.bug_subscriptions) |
1185 | + ubuntu-team |
1186 | >>> subscription = target.addSubscription(no_priv, no_priv) |
1187 | - >>> subscription.bug_notification_level = BugNotificationLevel.METADATA |
1188 | >>> print_subscriptions_list(target.bug_subscriptions) |
1189 | - no-priv METADATA |
1190 | - ubuntu-team COMMENTS |
1191 | - >>> subscriptions = target.getSubscriptions(min_bug_notification_level= |
1192 | - ... BugNotificationLevel.COMMENTS) |
1193 | - >>> print_subscriptions_list(subscriptions) |
1194 | - ubuntu-team COMMENTS |
1195 | + no-priv |
1196 | + ubuntu-team |
1197 | |
1198 | |
1199 | Structural subscriptions and indirect bug subscriptions |
1200 | |
1201 | === modified file 'lib/lp/bugs/tests/test_bugchanges.py' |
1202 | --- lib/lp/bugs/tests/test_bugchanges.py 2010-12-23 12:55:53 +0000 |
1203 | +++ lib/lp/bugs/tests/test_bugchanges.py 2011-02-01 19:35:24 +0000 |
1204 | @@ -28,6 +28,7 @@ |
1205 | from lp.bugs.interfaces.cve import ICveSet |
1206 | from lp.registry.enum import BugNotificationLevel |
1207 | from lp.testing.factory import LaunchpadObjectFactory |
1208 | +from lp.testing import person_logged_in |
1209 | |
1210 | |
1211 | class TestBugChanges(unittest.TestCase): |
1212 | @@ -59,7 +60,9 @@ |
1213 | # Create a new bug subscription with a new person. |
1214 | subscriber = self.factory.makePerson(name=name) |
1215 | subscription = target.addBugSubscription(subscriber, subscriber) |
1216 | - subscription.bug_notification_level = level |
1217 | + with person_logged_in(subscriber): |
1218 | + filter = subscription.newBugFilter() |
1219 | + filter.bug_notification_level = level |
1220 | return subscriber |
1221 | |
1222 | def saveOldChanges(self, bug=None, append=False): |
1223 | |
1224 | === modified file 'lib/lp/bugs/tests/test_structuralsubscriptiontarget.py' |
1225 | --- lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2011-01-21 08:12:29 +0000 |
1226 | +++ lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2011-02-01 19:35:24 +0000 |
1227 | @@ -192,8 +192,6 @@ |
1228 | self.bug = self.bugtask.bug |
1229 | self.subscription = self.target.addSubscription( |
1230 | self.ordinary_subscriber, self.ordinary_subscriber) |
1231 | - self.subscription.bug_notification_level = ( |
1232 | - BugNotificationLevel.COMMENTS) |
1233 | |
1234 | def assertSubscriptions( |
1235 | self, expected_subscriptions, level=BugNotificationLevel.NOTHING): |
1236 | @@ -205,8 +203,7 @@ |
1237 | # If no one has a filtered subscription for the given bug, the result |
1238 | # of getSubscriptionsForBugTask() is the same as for |
1239 | # getSubscriptions(). |
1240 | - subscriptions = self.target.getSubscriptions( |
1241 | - min_bug_notification_level=BugNotificationLevel.NOTHING) |
1242 | + subscriptions = self.target.getSubscriptions() |
1243 | self.assertSubscriptions(list(subscriptions)) |
1244 | |
1245 | def test_getSubscriptionsForBugTask_with_filter_on_status(self): |
1246 | @@ -250,8 +247,8 @@ |
1247 | # which getSubscriptionsForBugTask() observes. |
1248 | |
1249 | # Adjust the subscription level to METADATA. |
1250 | - self.subscription.bug_notification_level = ( |
1251 | - BugNotificationLevel.METADATA) |
1252 | + filter = self.subscription.newBugFilter() |
1253 | + filter.bug_notification_level = BugNotificationLevel.METADATA |
1254 | |
1255 | # The subscription is found when looking for NOTHING or above. |
1256 | self.assertSubscriptions( |
1257 | |
1258 | === modified file 'lib/lp/registry/doc/private-team-roles.txt' |
1259 | --- lib/lp/registry/doc/private-team-roles.txt 2010-08-23 16:51:11 +0000 |
1260 | +++ lib/lp/registry/doc/private-team-roles.txt 2011-02-01 19:35:24 +0000 |
1261 | @@ -157,8 +157,6 @@ |
1262 | ... subscriber=priv_team, subscribed_by=team_owner) |
1263 | >>> sub.target |
1264 | <Product at ...> |
1265 | - >>> sub.bug_notification_level |
1266 | - <DBItem BugNotificationLevel.NOTHING, (10) Nothing> |
1267 | |
1268 | |
1269 | Structural Subscription to Distributions |
1270 | @@ -171,8 +169,6 @@ |
1271 | ... subscriber=priv_team, subscribed_by=team_owner) |
1272 | >>> sub.target |
1273 | <Distribution 'Ubuntu' (ubuntu)> |
1274 | - >>> sub.bug_notification_level |
1275 | - <DBItem BugNotificationLevel.NOTHING, (10) Nothing> |
1276 | |
1277 | |
1278 | Project Roles |
A worry: target. addSubscription did result in a subscription that had a level of NOTHING. We never exposed that, to my knowledge, instead relying publicly on addBugSubscription, which always explicitly set a level of COMMENTS. Now, this branch creates subscriptions without filters, which means addBugSubscription has the same result, but addSubscription does not. I don't think it is an issue, but I'd like a sanity check from an expert (gmb? :-D )