Merge lp:~allenap/launchpad/structural-subscriptions-with-filters-4 into lp:launchpad/db-devel
- structural-subscriptions-with-filters-4
- Merge into db-devel
Status: | Merged |
---|---|
Approved by: | Aaron Bentley |
Approved revision: | no longer in the source branch. |
Merged at revision: | 9866 |
Proposed branch: | lp:~allenap/launchpad/structural-subscriptions-with-filters-4 |
Merge into: | lp:launchpad/db-devel |
Prerequisite: | lp:~allenap/launchpad/structural-subscriptions-with-filters-3 |
Diff against target: |
545 lines (+300/-26) 10 files modified
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+6/-3) lib/lp/bugs/configure.zcml (+12/-0) lib/lp/bugs/interfaces/bugsubscriptionfilter.py (+81/-0) lib/lp/bugs/model/bugsubscriptionfilter.py (+10/-0) lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py (+104/-0) lib/lp/bugs/security.py (+12/-0) lib/lp/registry/interfaces/structuralsubscription.py (+12/-1) lib/lp/registry/model/structuralsubscription.py (+14/-0) lib/lp/registry/tests/test_structuralsubscription.py (+41/-0) lib/lp/registry/tests/test_structuralsubscriptiontarget.py (+8/-22) |
To merge this branch: | bzr merge lp:~allenap/launchpad/structural-subscriptions-with-filters-4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Aaron Bentley (community) | Approve | ||
Review via email: mp+37467@code.launchpad.net |
Commit message
Description of the change
This branch:
- Adds an IBugSubscriptio
- A security adapter for it,
- A bug_filters property and a newBugFilter() method to IStructuralSubs
- Uses the convenience API introduced in the prerequisite branch to simplify testing.
Gavin Panella (allenap) wrote : | # |
> There are a few naming issues:
> Some classes use destroySelf, others use delete. We should pick one project-
> wide, and stick to it.
I don't know which one to choose! destroySelf() is an SQLObject-ism so
I steered away from that, if only to avoid confusion.
> I think that IBugSubscriptio
> is not a good distinction, because methods that are not mutators should be on
> the same interface as its attributes so that they have the same permissions.
>
> Perhaps IBugSubscription and IBugSubscriptio
I couldn't think of a better solution to this, but I think something
like this might make sense:
IBugSubscript
--> IBugSubscriptio
IBugSubscript
--> IBugSubscriptio
IBugSubsc
I've already sent this branch off, so I'll change it in the follow-up.
Thank you for the review :)
Gavin Panella (allenap) wrote : | # |
Ach, Zope complains if I try to combine things in "odd" ways, so I'm
going to stick with Attributes and Methods. They're only referenced in
the same file and in one configure.zcml so anyone who has a better
approach can change them with ease.
Aaron Bentley (abentley) wrote : | # |
Alright.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py' |
2 | --- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-09-29 09:28:17 +0000 |
3 | +++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-10-05 09:31:09 +0000 |
4 | @@ -40,6 +40,7 @@ |
5 | ) |
6 | from lp.bugs.interfaces.bugbranch import IBugBranch |
7 | from lp.bugs.interfaces.bugnomination import IBugNomination |
8 | +from lp.bugs.interfaces.bugsubscriptionfilter import IBugSubscriptionFilter |
9 | from lp.bugs.interfaces.bugtarget import ( |
10 | IBugTarget, |
11 | IHasBugs, |
12 | @@ -111,9 +112,7 @@ |
13 | ISourcePackagePublishingHistory, |
14 | ISourcePackagePublishingHistoryPublic, |
15 | ) |
16 | -from lp.soyuz.interfaces.queue import ( |
17 | - IPackageUpload, |
18 | - ) |
19 | +from lp.soyuz.interfaces.queue import IPackageUpload |
20 | from lp.soyuz.interfaces.sourcepackagerelease import ISourcePackageRelease |
21 | from lp.translations.interfaces.pofile import IPOFile |
22 | from lp.translations.interfaces.potemplate import ( |
23 | @@ -397,13 +396,17 @@ |
24 | patch_reference_property(IPackageUpload, 'archive', IArchive) |
25 | |
26 | # IStructuralSubscription |
27 | +patch_collection_property( |
28 | + IStructuralSubscription, 'bug_filters', IBugSubscriptionFilter) |
29 | patch_reference_property( |
30 | IStructuralSubscription, 'target', IStructuralSubscriptionTarget) |
31 | |
32 | +# IStructuralSubscriptionTarget |
33 | patch_reference_property( |
34 | IStructuralSubscriptionTarget, 'parent_subscription_target', |
35 | IStructuralSubscriptionTarget) |
36 | |
37 | +# ISourcePackageRelease |
38 | patch_reference_property( |
39 | ISourcePackageRelease, 'source_package_recipe_build', |
40 | ISourcePackageRecipeBuild) |
41 | |
42 | === modified file 'lib/lp/bugs/configure.zcml' |
43 | --- lib/lp/bugs/configure.zcml 2010-09-30 05:47:44 +0000 |
44 | +++ lib/lp/bugs/configure.zcml 2010-10-05 09:31:09 +0000 |
45 | @@ -609,6 +609,18 @@ |
46 | permission="zope.Public" |
47 | set_schema="lp.bugs.interfaces.bugsubscription.IBugSubscription"/> |
48 | </class> |
49 | + |
50 | + <!-- BugSubscriptionFilter --> |
51 | + <class |
52 | + class=".model.bugsubscriptionfilter.BugSubscriptionFilter"> |
53 | + <allow |
54 | + interface=".interfaces.bugsubscriptionfilter.IBugSubscriptionFilterAttributes"/> |
55 | + <require |
56 | + permission="launchpad.Edit" |
57 | + interface=".interfaces.bugsubscriptionfilter.IBugSubscriptionFilterMethods" |
58 | + set_schema=".interfaces.bugsubscriptionfilter.IBugSubscriptionFilterAttributes" /> |
59 | + </class> |
60 | + |
61 | <facet |
62 | facet="bugs"> |
63 | |
64 | |
65 | === added file 'lib/lp/bugs/interfaces/bugsubscriptionfilter.py' |
66 | --- lib/lp/bugs/interfaces/bugsubscriptionfilter.py 1970-01-01 00:00:00 +0000 |
67 | +++ lib/lp/bugs/interfaces/bugsubscriptionfilter.py 2010-10-05 09:31:09 +0000 |
68 | @@ -0,0 +1,81 @@ |
69 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
70 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
71 | + |
72 | +"""Bug subscription filter interfaces.""" |
73 | + |
74 | +__metaclass__ = type |
75 | +__all__ = [ |
76 | + "IBugSubscriptionFilter", |
77 | + ] |
78 | + |
79 | + |
80 | +from lazr.restful.fields import Reference |
81 | +from zope.interface import Interface |
82 | +from zope.schema import ( |
83 | + Bool, |
84 | + Choice, |
85 | + FrozenSet, |
86 | + Text, |
87 | + ) |
88 | + |
89 | +from canonical.launchpad import _ |
90 | +from lp.bugs.interfaces.bugtask import ( |
91 | + BugTaskImportance, |
92 | + BugTaskStatus, |
93 | + ) |
94 | +from lp.registry.interfaces.structuralsubscription import ( |
95 | + IStructuralSubscription, |
96 | + ) |
97 | +from lp.services.fields import SearchTag |
98 | + |
99 | + |
100 | +class IBugSubscriptionFilterAttributes(Interface): |
101 | + """Attributes of `IBugSubscriptionFilter`.""" |
102 | + |
103 | + structural_subscription = Reference( |
104 | + IStructuralSubscription, |
105 | + title=_("Structural subscription"), |
106 | + required=True, readonly=True) |
107 | + |
108 | + find_all_tags = Bool( |
109 | + title=_("All given tags must be found, or any."), |
110 | + required=True, default=False) |
111 | + include_any_tags = Bool( |
112 | + title=_("Include any tags."), |
113 | + required=True, default=False) |
114 | + exclude_any_tags = Bool( |
115 | + title=_("Exclude all tags."), |
116 | + required=True, default=False) |
117 | + |
118 | + description = Text( |
119 | + title=_("Description of this filter."), |
120 | + required=False) |
121 | + |
122 | + statuses = FrozenSet( |
123 | + title=_("The statuses to filter on."), |
124 | + required=True, default=frozenset(), |
125 | + value_type=Choice( |
126 | + title=_('Status'), vocabulary=BugTaskStatus)) |
127 | + |
128 | + importances = FrozenSet( |
129 | + title=_("The importances to filter on."), |
130 | + required=True, default=frozenset(), |
131 | + value_type=Choice( |
132 | + title=_('Importance'), vocabulary=BugTaskImportance)) |
133 | + |
134 | + tags = FrozenSet( |
135 | + title=_("The tags to filter on."), |
136 | + required=True, default=frozenset(), |
137 | + value_type=SearchTag()) |
138 | + |
139 | + |
140 | +class IBugSubscriptionFilterMethods(Interface): |
141 | + """Methods of `IBugSubscriptionFilter`.""" |
142 | + |
143 | + def delete(): |
144 | + """Delete this bug subscription filter.""" |
145 | + |
146 | + |
147 | +class IBugSubscriptionFilter( |
148 | + IBugSubscriptionFilterAttributes, IBugSubscriptionFilterMethods): |
149 | + """A bug subscription filter.""" |
150 | |
151 | === modified file 'lib/lp/bugs/model/bugsubscriptionfilter.py' |
152 | --- lib/lp/bugs/model/bugsubscriptionfilter.py 2010-10-05 09:31:08 +0000 |
153 | +++ lib/lp/bugs/model/bugsubscriptionfilter.py 2010-10-05 09:31:09 +0000 |
154 | @@ -13,11 +13,14 @@ |
155 | Bool, |
156 | Int, |
157 | Reference, |
158 | + Store, |
159 | Unicode, |
160 | ) |
161 | +from zope.interface import implements |
162 | |
163 | from canonical.launchpad import searchbuilder |
164 | from canonical.launchpad.interfaces.lpstorm import IStore |
165 | +from lp.bugs.interfaces.bugsubscriptionfilter import IBugSubscriptionFilter |
166 | from lp.bugs.model.bugsubscriptionfilterimportance import ( |
167 | BugSubscriptionFilterImportance, |
168 | ) |
169 | @@ -30,6 +33,8 @@ |
170 | class BugSubscriptionFilter(Storm): |
171 | """A filter to specialize a *structural* subscription.""" |
172 | |
173 | + implements(IBugSubscriptionFilter) |
174 | + |
175 | __storm_table__ = "BugSubscriptionFilter" |
176 | |
177 | id = Int(primary=True) |
178 | @@ -178,3 +183,8 @@ |
179 | tags = property( |
180 | _get_tags, _set_tags, doc=( |
181 | "A frozenset of tags filtered on.")) |
182 | + |
183 | + def delete(self): |
184 | + """See `IBugSubscriptionFilter`.""" |
185 | + self.importances = self.statuses = self.tags = () |
186 | + Store.of(self).remove(self) |
187 | |
188 | === modified file 'lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py' |
189 | --- lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py 2010-10-05 09:31:08 +0000 |
190 | +++ lib/lp/bugs/model/tests/test_bugsubscriptionfilter.py 2010-10-05 09:31:09 +0000 |
191 | @@ -5,6 +5,10 @@ |
192 | |
193 | __metaclass__ = type |
194 | |
195 | +from storm.store import Store |
196 | +from zope.security.interfaces import Unauthorized |
197 | +from zope.security.proxy import ProxyFactory |
198 | + |
199 | from canonical.launchpad import searchbuilder |
200 | from canonical.launchpad.interfaces.lpstorm import IStore |
201 | from canonical.testing import DatabaseFunctionalLayer |
202 | @@ -14,7 +18,9 @@ |
203 | ) |
204 | from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter |
205 | from lp.testing import ( |
206 | + anonymous_logged_in, |
207 | login_person, |
208 | + person_logged_in, |
209 | TestCaseWithFactory, |
210 | ) |
211 | |
212 | @@ -70,6 +76,24 @@ |
213 | self.assertIs(None, bug_subscription_filter.other_parameters) |
214 | self.assertIs(None, bug_subscription_filter.description) |
215 | |
216 | + def test_delete(self): |
217 | + """`BugSubscriptionFilter` objects can be deleted. |
218 | + |
219 | + Child objects - like `BugSubscriptionFilterTags` - will also be |
220 | + deleted. |
221 | + """ |
222 | + bug_subscription_filter = BugSubscriptionFilter() |
223 | + bug_subscription_filter.structural_subscription = self.subscription |
224 | + bug_subscription_filter.importances = [BugTaskImportance.LOW] |
225 | + bug_subscription_filter.statuses = [BugTaskStatus.NEW] |
226 | + bug_subscription_filter.tags = [u"foo"] |
227 | + IStore(bug_subscription_filter).flush() |
228 | + self.assertIsNot(None, Store.of(bug_subscription_filter)) |
229 | + # Delete. |
230 | + bug_subscription_filter.delete() |
231 | + IStore(bug_subscription_filter).flush() |
232 | + self.assertIs(None, Store.of(bug_subscription_filter)) |
233 | + |
234 | def test_statuses(self): |
235 | # The statuses property is a frozenset of the statuses that are |
236 | # filtered upon. |
237 | @@ -196,3 +220,83 @@ |
238 | bug_subscription_filter.tags = searchbuilder.any(u"baz") |
239 | self.assertEqual(frozenset((u"baz",)), bug_subscription_filter.tags) |
240 | self.assertFalse(bug_subscription_filter.find_all_tags) |
241 | + |
242 | + |
243 | +class TestBugSubscriptionFilterPermissions(TestCaseWithFactory): |
244 | + |
245 | + layer = DatabaseFunctionalLayer |
246 | + |
247 | + def setUp(self): |
248 | + super(TestBugSubscriptionFilterPermissions, self).setUp() |
249 | + self.target = self.factory.makeProduct() |
250 | + self.subscriber = self.target.owner |
251 | + with person_logged_in(self.subscriber): |
252 | + self.subscription = self.target.addBugSubscription( |
253 | + self.subscriber, self.subscriber) |
254 | + |
255 | + def test_read_to_all(self): |
256 | + """`BugSubscriptionFilter`s can be read by anyone.""" |
257 | + bug_subscription_filter = BugSubscriptionFilter() |
258 | + bug_subscription_filter.structural_subscription = self.subscription |
259 | + bug_subscription_filter = ProxyFactory(bug_subscription_filter) |
260 | + with person_logged_in(self.subscriber): |
261 | + bug_subscription_filter.find_all_tags |
262 | + with person_logged_in(self.factory.makePerson()): |
263 | + bug_subscription_filter.find_all_tags |
264 | + with anonymous_logged_in(): |
265 | + bug_subscription_filter.find_all_tags |
266 | + |
267 | + def test_write_to_subscribers(self): |
268 | + """`BugSubscriptionFilter`s can only be modifed by subscribers.""" |
269 | + bug_subscription_filter = BugSubscriptionFilter() |
270 | + bug_subscription_filter.structural_subscription = self.subscription |
271 | + bug_subscription_filter = ProxyFactory(bug_subscription_filter) |
272 | + # The subscriber can edit the filter. |
273 | + with person_logged_in(self.subscriber): |
274 | + bug_subscription_filter.find_all_tags = True |
275 | + # Any other person is denied rights to edit the filter. |
276 | + with person_logged_in(self.factory.makePerson()): |
277 | + self.assertRaises( |
278 | + Unauthorized, setattr, bug_subscription_filter, |
279 | + "find_all_tags", True) |
280 | + # Anonymous users are also denied. |
281 | + with anonymous_logged_in(): |
282 | + self.assertRaises( |
283 | + Unauthorized, setattr, bug_subscription_filter, |
284 | + "find_all_tags", True) |
285 | + |
286 | + def test_delete_by_subscribers(self): |
287 | + """`BugSubscriptionFilter`s can only be deleted by subscribers.""" |
288 | + bug_subscription_filter = BugSubscriptionFilter() |
289 | + bug_subscription_filter.structural_subscription = self.subscription |
290 | + bug_subscription_filter = ProxyFactory(bug_subscription_filter) |
291 | + # Anonymous users are denied rights to delete the filter. |
292 | + with anonymous_logged_in(): |
293 | + self.assertRaises( |
294 | + Unauthorized, getattr, bug_subscription_filter, "delete") |
295 | + # Any other person is also denied. |
296 | + with person_logged_in(self.factory.makePerson()): |
297 | + self.assertRaises( |
298 | + Unauthorized, getattr, bug_subscription_filter, "delete") |
299 | + # The subscriber can delete the filter. |
300 | + with person_logged_in(self.subscriber): |
301 | + bug_subscription_filter.delete() |
302 | + |
303 | + def test_write_to_any_user_when_no_subscription(self): |
304 | + """ |
305 | + `BugSubscriptionFilter`s can be modifed by any logged-in user when |
306 | + there is no related subscription. |
307 | + """ |
308 | + bug_subscription_filter = BugSubscriptionFilter() |
309 | + bug_subscription_filter = ProxyFactory(bug_subscription_filter) |
310 | + # The subscriber can edit the filter. |
311 | + with person_logged_in(self.subscriber): |
312 | + bug_subscription_filter.find_all_tags = True |
313 | + # Any other person can edit the filter. |
314 | + with person_logged_in(self.factory.makePerson()): |
315 | + bug_subscription_filter.find_all_tags = True |
316 | + # Anonymous users are denied rights to edit the filter. |
317 | + with anonymous_logged_in(): |
318 | + self.assertRaises( |
319 | + Unauthorized, setattr, bug_subscription_filter, |
320 | + "find_all_tags", True) |
321 | |
322 | === modified file 'lib/lp/bugs/security.py' |
323 | --- lib/lp/bugs/security.py 2010-09-10 16:21:21 +0000 |
324 | +++ lib/lp/bugs/security.py 2010-10-05 09:31:09 +0000 |
325 | @@ -17,6 +17,7 @@ |
326 | from lp.bugs.interfaces.bugbranch import IBugBranch |
327 | from lp.bugs.interfaces.bugnomination import IBugNomination |
328 | from lp.bugs.interfaces.bugsubscription import IBugSubscription |
329 | +from lp.bugs.interfaces.bugsubscriptionfilter import IBugSubscriptionFilter |
330 | from lp.bugs.interfaces.bugtracker import IBugTracker |
331 | from lp.bugs.interfaces.bugwatch import IBugWatch |
332 | |
333 | @@ -171,3 +172,14 @@ |
334 | return ( |
335 | user.in_admin or |
336 | user.in_launchpad_developers) |
337 | + |
338 | + |
339 | +class EditBugSubscriptionFilter(AuthorizationBase): |
340 | + """Bug subscription filters may only be modified by the subscriber.""" |
341 | + permission = 'launchpad.Edit' |
342 | + usedfor = IBugSubscriptionFilter |
343 | + |
344 | + def checkAuthenticated(self, user): |
345 | + return ( |
346 | + self.obj.structural_subscription is None or |
347 | + user.inTeam(self.obj.structural_subscription.subscriber)) |
348 | |
349 | === modified file 'lib/lp/registry/interfaces/structuralsubscription.py' |
350 | --- lib/lp/registry/interfaces/structuralsubscription.py 2010-10-05 09:31:08 +0000 |
351 | +++ lib/lp/registry/interfaces/structuralsubscription.py 2010-10-05 09:31:09 +0000 |
352 | @@ -32,7 +32,10 @@ |
353 | operation_returns_entry, |
354 | REQUEST_USER, |
355 | ) |
356 | -from lazr.restful.fields import Reference |
357 | +from lazr.restful.fields import ( |
358 | + CollectionField, |
359 | + Reference, |
360 | + ) |
361 | from zope.interface import ( |
362 | Attribute, |
363 | Interface, |
364 | @@ -126,6 +129,14 @@ |
365 | required=True, readonly=True, |
366 | title=_("The structure to which this subscription belongs."))) |
367 | |
368 | + bug_filters = CollectionField( |
369 | + title=_('List of bug filters that narrow this subscription.'), |
370 | + readonly=True, required=False, |
371 | + value_type=Reference(schema=Interface)) |
372 | + |
373 | + def newBugFilter(): |
374 | + """Returns a new `BugSubscriptionFilter` for this subscription.""" |
375 | + |
376 | |
377 | class IStructuralSubscriptionTargetRead(Interface): |
378 | """A Launchpad Structure allowing users to subscribe to it. |
379 | |
380 | === modified file 'lib/lp/registry/model/structuralsubscription.py' |
381 | --- lib/lp/registry/model/structuralsubscription.py 2010-10-05 09:31:08 +0000 |
382 | +++ lib/lp/registry/model/structuralsubscription.py 2010-10-05 09:31:09 +0000 |
383 | @@ -26,6 +26,7 @@ |
384 | SQLBase, |
385 | ) |
386 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
387 | +from canonical.launchpad.interfaces.lpstorm import IStore |
388 | from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter |
389 | from lp.bugs.model.bugsubscriptionfilterimportance import ( |
390 | BugSubscriptionFilterImportance, |
391 | @@ -135,6 +136,19 @@ |
392 | else: |
393 | raise AssertionError('StructuralSubscription has no target.') |
394 | |
395 | + @property |
396 | + def bug_filters(self): |
397 | + """See `IStructuralSubscription`.""" |
398 | + return IStore(BugSubscriptionFilter).find( |
399 | + BugSubscriptionFilter, |
400 | + BugSubscriptionFilter.structural_subscription == self) |
401 | + |
402 | + def newBugFilter(self): |
403 | + """See `IStructuralSubscription`.""" |
404 | + bug_filter = BugSubscriptionFilter() |
405 | + bug_filter.structural_subscription = self |
406 | + return bug_filter |
407 | + |
408 | |
409 | class DistroSeriesTargetHelper: |
410 | """A helper for `IDistroSeries`s.""" |
411 | |
412 | === added file 'lib/lp/registry/tests/test_structuralsubscription.py' |
413 | --- lib/lp/registry/tests/test_structuralsubscription.py 1970-01-01 00:00:00 +0000 |
414 | +++ lib/lp/registry/tests/test_structuralsubscription.py 2010-10-05 09:31:09 +0000 |
415 | @@ -0,0 +1,41 @@ |
416 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
417 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
418 | + |
419 | +"""Tests for `StructuralSubscription`.""" |
420 | + |
421 | +__metaclass__ = type |
422 | + |
423 | +from canonical.testing.layers import LaunchpadZopelessLayer |
424 | +from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter |
425 | +from lp.testing import TestCaseWithFactory |
426 | + |
427 | + |
428 | +class TestStructuralSubscription(TestCaseWithFactory): |
429 | + |
430 | + layer = LaunchpadZopelessLayer |
431 | + |
432 | + def test_bug_filters_empty(self): |
433 | + # StructuralSubscription.filters returns the BugSubscriptionFilter |
434 | + # records associated with this subscription. It's empty to begin with. |
435 | + product = self.factory.makeProduct() |
436 | + subscription = product.addSubscription(product.owner, product.owner) |
437 | + self.assertEqual([], list(subscription.bug_filters)) |
438 | + |
439 | + def test_bug_filters(self): |
440 | + # StructuralSubscription.filters returns the BugSubscriptionFilter |
441 | + # records associated with this subscription. |
442 | + product = self.factory.makeProduct() |
443 | + subscription = product.addSubscription(product.owner, product.owner) |
444 | + subscription_filter = BugSubscriptionFilter() |
445 | + subscription_filter.structural_subscription = subscription |
446 | + self.assertEqual([subscription_filter], list(subscription.bug_filters)) |
447 | + |
448 | + def test_newBugFilter(self): |
449 | + # Structural_Subscription.newBugFilter() creates a new subscription |
450 | + # filter linked to the subscription. |
451 | + product = self.factory.makeProduct() |
452 | + subscription = product.addSubscription(product.owner, product.owner) |
453 | + subscription_filter = subscription.newBugFilter() |
454 | + self.assertEqual( |
455 | + subscription, subscription_filter.structural_subscription) |
456 | + self.assertEqual([subscription_filter], list(subscription.bug_filters)) |
457 | |
458 | === modified file 'lib/lp/registry/tests/test_structuralsubscriptiontarget.py' |
459 | --- lib/lp/registry/tests/test_structuralsubscriptiontarget.py 2010-10-05 09:31:08 +0000 |
460 | +++ lib/lp/registry/tests/test_structuralsubscriptiontarget.py 2010-10-05 09:31:09 +0000 |
461 | @@ -33,12 +33,6 @@ |
462 | BugTaskStatus, |
463 | ) |
464 | from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilter |
465 | -from lp.bugs.model.bugsubscriptionfilterimportance import ( |
466 | - BugSubscriptionFilterImportance, |
467 | - ) |
468 | -from lp.bugs.model.bugsubscriptionfilterstatus import ( |
469 | - BugSubscriptionFilterStatus, |
470 | - ) |
471 | from lp.bugs.tests.test_bugtarget import bugtarget_filebug |
472 | from lp.registry.enum import BugNotificationLevel |
473 | from lp.registry.errors import ( |
474 | @@ -208,9 +202,7 @@ |
475 | # Filter the subscription to bugs in the CONFIRMED state. |
476 | subscription_filter = BugSubscriptionFilter() |
477 | subscription_filter.structural_subscription = subscription |
478 | - subscription_filter_status = BugSubscriptionFilterStatus() |
479 | - subscription_filter_status.filter = subscription_filter |
480 | - subscription_filter_status.status = BugTaskStatus.CONFIRMED |
481 | + subscription_filter.statuses = [BugTaskStatus.CONFIRMED] |
482 | |
483 | # With the filter the subscription is not found. |
484 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
485 | @@ -218,7 +210,7 @@ |
486 | self.assertEqual([], list(subscriptions_for_bug)) |
487 | |
488 | # If the filter is adjusted, the subscription is found again. |
489 | - subscription_filter_status.status = bugtask.status |
490 | + subscription_filter.statuses = [bugtask.status] |
491 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
492 | bugtask.bug, BugNotificationLevel.NOTHING) |
493 | self.assertEqual([subscription], list(subscriptions_for_bug)) |
494 | @@ -242,9 +234,7 @@ |
495 | # Filter the subscription to bugs in the CRITICAL state. |
496 | subscription_filter = BugSubscriptionFilter() |
497 | subscription_filter.structural_subscription = subscription |
498 | - subscription_filter_importance = BugSubscriptionFilterImportance() |
499 | - subscription_filter_importance.filter = subscription_filter |
500 | - subscription_filter_importance.importance = BugTaskImportance.CRITICAL |
501 | + subscription_filter.importances = [BugTaskImportance.CRITICAL] |
502 | |
503 | # With the filter the subscription is not found. |
504 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
505 | @@ -252,7 +242,7 @@ |
506 | self.assertEqual([], list(subscriptions_for_bug)) |
507 | |
508 | # If the filter is adjusted, the subscription is found again. |
509 | - subscription_filter_importance.importance = bugtask.importance |
510 | + subscription_filter.importances = [bugtask.importance] |
511 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
512 | bugtask.bug, BugNotificationLevel.NOTHING) |
513 | self.assertEqual([subscription], list(subscriptions_for_bug)) |
514 | @@ -271,12 +261,8 @@ |
515 | # Filter the subscription to bugs in the CRITICAL state. |
516 | subscription_filter = BugSubscriptionFilter() |
517 | subscription_filter.structural_subscription = subscription |
518 | - subscription_filter_status = BugSubscriptionFilterStatus() |
519 | - subscription_filter_status.filter = subscription_filter |
520 | - subscription_filter_status.status = BugTaskStatus.CONFIRMED |
521 | - subscription_filter_importance = BugSubscriptionFilterImportance() |
522 | - subscription_filter_importance.filter = subscription_filter |
523 | - subscription_filter_importance.importance = BugTaskImportance.CRITICAL |
524 | + subscription_filter.statuses = [BugTaskStatus.CONFIRMED] |
525 | + subscription_filter.importances = [BugTaskImportance.CRITICAL] |
526 | |
527 | # With the filter the subscription is not found. |
528 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
529 | @@ -285,14 +271,14 @@ |
530 | |
531 | # If the filter is adjusted to match status but not importance, the |
532 | # subscription is still not found. |
533 | - subscription_filter_status.status = bugtask.status |
534 | + subscription_filter.statuses = [bugtask.status] |
535 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
536 | bugtask.bug, BugNotificationLevel.NOTHING) |
537 | self.assertEqual([], list(subscriptions_for_bug)) |
538 | |
539 | # If the filter is adjusted to also match importance, the subscription |
540 | # is found again. |
541 | - subscription_filter_importance.importance = bugtask.importance |
542 | + subscription_filter.importances = [bugtask.importance] |
543 | subscriptions_for_bug = self.target.getSubscriptionsForBug( |
544 | bugtask.bug, BugNotificationLevel.NOTHING) |
545 | self.assertEqual([subscription], list(subscriptions_for_bug)) |
There are a few naming issues:
Some classes use destroySelf, others use delete. We should pick one project-wide, and stick to it.
I think that IBugSubscriptio nFilterMethods vs IBugSubscriptio nFilterAttribut es is not a good distinction, because methods that are not mutators should be on the same interface as its attributes so that they have the same permissions.
Perhaps IBugSubscription and IBugSubscriptio nMutator?
If you really want to keep IBugSubscriptio nFilterMethods and IBugSubscriptio nFilterAttribut es, I can live with that.