Merge lp:~allenap/launchpad/wire-up-filter-subs-bug-655567-devel into lp:launchpad
- wire-up-filter-subs-bug-655567-devel
- Merge into devel
Proposed by
Gavin Panella
Status: | Merged |
---|---|
Approved by: | Gavin Panella |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11721 |
Proposed branch: | lp:~allenap/launchpad/wire-up-filter-subs-bug-655567-devel |
Merge into: | lp:launchpad |
Diff against target: |
881 lines (+239/-250) 12 files modified
database/schema/security.cfg (+7/-0) lib/lp/bugs/configure.zcml (+1/-0) lib/lp/bugs/interfaces/bug.py (+8/-2) lib/lp/bugs/model/bug.py (+61/-36) lib/lp/bugs/model/tests/test_bug.py (+91/-9) lib/lp/registry/doc/structural-subscriptions.txt (+0/-55) lib/lp/registry/interfaces/person.py (+0/-11) lib/lp/registry/interfaces/structuralsubscription.py (+2/-2) lib/lp/registry/model/person.py (+0/-53) lib/lp/registry/model/structuralsubscription.py (+5/-19) lib/lp/registry/tests/test_structuralsubscriptiontarget.py (+63/-62) utilities/format-new-and-modified-imports (+1/-1) |
To merge this branch: | bzr merge lp:~allenap/launchpad/wire-up-filter-subs-bug-655567-devel |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Abel Deuring (community) | code | Approve | |
Review via email: mp+38562@code.launchpad.net |
Commit message
Merge wire-up-
Description of the change
Merge lp:~allenap/launchpad/wire-up-filter-subs-bug-655567 into devel. It's already in db-devel.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'database/schema/security.cfg' | |||
2 | --- database/schema/security.cfg 2010-10-07 22:46:08 +0000 | |||
3 | +++ database/schema/security.cfg 2010-10-15 16:17:07 +0000 | |||
4 | @@ -549,6 +549,7 @@ | |||
5 | 549 | public.bugsubscriptionfilterstatus = SELECT | 549 | public.bugsubscriptionfilterstatus = SELECT |
6 | 550 | public.bugsubscriptionfilterimportance = SELECT | 550 | public.bugsubscriptionfilterimportance = SELECT |
7 | 551 | public.bugsubscriptionfiltertag = SELECT | 551 | public.bugsubscriptionfiltertag = SELECT |
8 | 552 | public.bugtag = SELECT | ||
9 | 552 | public.bugtask = SELECT, INSERT, UPDATE | 553 | public.bugtask = SELECT, INSERT, UPDATE |
10 | 553 | public.bugtracker = SELECT, INSERT | 554 | public.bugtracker = SELECT, INSERT |
11 | 554 | public.bugtrackercomponent = SELECT, INSERT, UPDATE, DELETE | 555 | public.bugtrackercomponent = SELECT, INSERT, UPDATE, DELETE |
12 | @@ -638,6 +639,7 @@ | |||
13 | 638 | public.bugsubscriptionfiltertag = SELECT | 639 | public.bugsubscriptionfiltertag = SELECT |
14 | 639 | public.bugnotification = SELECT, INSERT | 640 | public.bugnotification = SELECT, INSERT |
15 | 640 | public.bugnotificationrecipient = SELECT, INSERT | 641 | public.bugnotificationrecipient = SELECT, INSERT |
16 | 642 | public.bugtag = SELECT | ||
17 | 641 | public.structuralsubscription = SELECT | 643 | public.structuralsubscription = SELECT |
18 | 642 | public.message = SELECT, INSERT | 644 | public.message = SELECT, INSERT |
19 | 643 | public.messagechunk = SELECT, INSERT | 645 | public.messagechunk = SELECT, INSERT |
20 | @@ -833,6 +835,7 @@ | |||
21 | 833 | public.bugnotification = SELECT, INSERT | 835 | public.bugnotification = SELECT, INSERT |
22 | 834 | public.bugnotificationrecipient = SELECT, INSERT | 836 | public.bugnotificationrecipient = SELECT, INSERT |
23 | 835 | public.bugnomination = SELECT | 837 | public.bugnomination = SELECT |
24 | 838 | public.bugtag = SELECT | ||
25 | 836 | public.bugtask = SELECT, UPDATE | 839 | public.bugtask = SELECT, UPDATE |
26 | 837 | public.product = SELECT | 840 | public.product = SELECT |
27 | 838 | public.project = SELECT | 841 | public.project = SELECT |
28 | @@ -1194,6 +1197,7 @@ | |||
29 | 1194 | public.bugnotification = SELECT, INSERT | 1197 | public.bugnotification = SELECT, INSERT |
30 | 1195 | public.bugnotificationrecipient = SELECT, INSERT | 1198 | public.bugnotificationrecipient = SELECT, INSERT |
31 | 1196 | public.bugnomination = SELECT | 1199 | public.bugnomination = SELECT |
32 | 1200 | public.bugtag = SELECT | ||
33 | 1197 | public.bugtask = SELECT, UPDATE | 1201 | public.bugtask = SELECT, UPDATE |
34 | 1198 | public.product = SELECT, UPDATE | 1202 | public.product = SELECT, UPDATE |
35 | 1199 | public.project = SELECT, UPDATE | 1203 | public.project = SELECT, UPDATE |
36 | @@ -1300,6 +1304,7 @@ | |||
37 | 1300 | public.bugnotification = SELECT, INSERT | 1304 | public.bugnotification = SELECT, INSERT |
38 | 1301 | public.bugnotificationrecipient = SELECT, INSERT | 1305 | public.bugnotificationrecipient = SELECT, INSERT |
39 | 1302 | public.bugnomination = SELECT | 1306 | public.bugnomination = SELECT |
40 | 1307 | public.bugtag = SELECT | ||
41 | 1303 | public.bugtask = SELECT, UPDATE | 1308 | public.bugtask = SELECT, UPDATE |
42 | 1304 | public.product = SELECT, UPDATE | 1309 | public.product = SELECT, UPDATE |
43 | 1305 | public.project = SELECT, UPDATE | 1310 | public.project = SELECT, UPDATE |
44 | @@ -1855,6 +1860,7 @@ | |||
45 | 1855 | public.bug = SELECT, INSERT, UPDATE | 1860 | public.bug = SELECT, INSERT, UPDATE |
46 | 1856 | public.bugjob = SELECT, INSERT | 1861 | public.bugjob = SELECT, INSERT |
47 | 1857 | public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE | 1862 | public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE |
48 | 1863 | public.bugtag = SELECT | ||
49 | 1858 | public.bugtask = SELECT, INSERT, UPDATE | 1864 | public.bugtask = SELECT, INSERT, UPDATE |
50 | 1859 | public.accountpassword = SELECT, INSERT | 1865 | public.accountpassword = SELECT, INSERT |
51 | 1860 | public.teamparticipation = SELECT, INSERT | 1866 | public.teamparticipation = SELECT, INSERT |
52 | @@ -1917,6 +1923,7 @@ | |||
53 | 1917 | public.bugaffectsperson = SELECT | 1923 | public.bugaffectsperson = SELECT |
54 | 1918 | public.bugnotification = SELECT, DELETE | 1924 | public.bugnotification = SELECT, DELETE |
55 | 1919 | public.bugnotificationrecipientarchive = SELECT | 1925 | public.bugnotificationrecipientarchive = SELECT |
56 | 1926 | public.bugtag = SELECT | ||
57 | 1920 | public.bugwatch = SELECT, UPDATE | 1927 | public.bugwatch = SELECT, UPDATE |
58 | 1921 | public.bugwatchactivity = SELECT, DELETE | 1928 | public.bugwatchactivity = SELECT, DELETE |
59 | 1922 | public.codeimportresult = SELECT, DELETE | 1929 | public.codeimportresult = SELECT, DELETE |
60 | 1923 | 1930 | ||
61 | === modified file 'lib/lp/bugs/configure.zcml' | |||
62 | --- lib/lp/bugs/configure.zcml 2010-10-06 18:53:53 +0000 | |||
63 | +++ lib/lp/bugs/configure.zcml 2010-10-15 16:17:07 +0000 | |||
64 | @@ -706,6 +706,7 @@ | |||
65 | 706 | getSubscribersForPerson | 706 | getSubscribersForPerson |
66 | 707 | indexed_messages | 707 | indexed_messages |
67 | 708 | getAlsoNotifiedSubscribers | 708 | getAlsoNotifiedSubscribers |
68 | 709 | getStructuralSubscribers | ||
69 | 709 | getBugWatch | 710 | getBugWatch |
70 | 710 | canBeNominatedFor | 711 | canBeNominatedFor |
71 | 711 | getNominationFor | 712 | getNominationFor |
72 | 712 | 713 | ||
73 | === modified file 'lib/lp/bugs/interfaces/bug.py' | |||
74 | --- lib/lp/bugs/interfaces/bug.py 2010-10-12 14:56:31 +0000 | |||
75 | +++ lib/lp/bugs/interfaces/bug.py 2010-10-15 16:17:07 +0000 | |||
76 | @@ -493,6 +493,12 @@ | |||
77 | 493 | from duplicates. | 493 | from duplicates. |
78 | 494 | """ | 494 | """ |
79 | 495 | 495 | ||
80 | 496 | def getStructuralSubscribers(recipients=None, level=None): | ||
81 | 497 | """Return `IPerson`s subscribed to this bug's targets. | ||
82 | 498 | |||
83 | 499 | This takes into account bug subscription filters. | ||
84 | 500 | """ | ||
85 | 501 | |||
86 | 496 | def getSubscriptionsFromDuplicates(): | 502 | def getSubscriptionsFromDuplicates(): |
87 | 497 | """Return IBugSubscriptions subscribed from dupes of this bug.""" | 503 | """Return IBugSubscriptions subscribed from dupes of this bug.""" |
88 | 498 | 504 | ||
89 | @@ -501,9 +507,9 @@ | |||
90 | 501 | 507 | ||
91 | 502 | def getSubscribersForPerson(person): | 508 | def getSubscribersForPerson(person): |
92 | 503 | """Find the persons or teams by which person is subscribed. | 509 | """Find the persons or teams by which person is subscribed. |
94 | 504 | 510 | ||
95 | 505 | This call should be quite cheap to make and performs a single query. | 511 | This call should be quite cheap to make and performs a single query. |
97 | 506 | 512 | ||
98 | 507 | :return: An IResultSet. | 513 | :return: An IResultSet. |
99 | 508 | """ | 514 | """ |
100 | 509 | 515 | ||
101 | 510 | 516 | ||
102 | === modified file 'lib/lp/bugs/model/bug.py' | |||
103 | --- lib/lp/bugs/model/bug.py 2010-10-14 11:05:05 +0000 | |||
104 | +++ lib/lp/bugs/model/bug.py 2010-10-15 16:17:07 +0000 | |||
105 | @@ -51,7 +51,6 @@ | |||
106 | 51 | In, | 51 | In, |
107 | 52 | LeftJoin, | 52 | LeftJoin, |
108 | 53 | Max, | 53 | Max, |
109 | 54 | Min, | ||
110 | 55 | Not, | 54 | Not, |
111 | 56 | Or, | 55 | Or, |
112 | 57 | Select, | 56 | Select, |
113 | @@ -156,14 +155,13 @@ | |||
114 | 156 | from lp.bugs.model.bugnomination import BugNomination | 155 | from lp.bugs.model.bugnomination import BugNomination |
115 | 157 | from lp.bugs.model.bugnotification import BugNotification | 156 | from lp.bugs.model.bugnotification import BugNotification |
116 | 158 | from lp.bugs.model.bugsubscription import BugSubscription | 157 | from lp.bugs.model.bugsubscription import BugSubscription |
117 | 158 | from lp.bugs.model.bugtarget import OfficialBugTag | ||
118 | 159 | from lp.bugs.model.bugtask import ( | 159 | from lp.bugs.model.bugtask import ( |
119 | 160 | BugTask, | 160 | BugTask, |
120 | 161 | bugtask_sort_key, | 161 | bugtask_sort_key, |
121 | 162 | BugTaskSet, | ||
122 | 163 | get_bug_privacy_filter, | 162 | get_bug_privacy_filter, |
123 | 164 | NullBugTask, | 163 | NullBugTask, |
124 | 165 | ) | 164 | ) |
125 | 166 | from lp.bugs.model.bugtarget import OfficialBugTag | ||
126 | 167 | from lp.bugs.model.bugwatch import BugWatch | 165 | from lp.bugs.model.bugwatch import BugWatch |
127 | 168 | from lp.hardwaredb.interfaces.hwdb import IHWSubmissionBugSet | 166 | from lp.hardwaredb.interfaces.hwdb import IHWSubmissionBugSet |
128 | 169 | from lp.registry.enum import BugNotificationLevel | 167 | from lp.registry.enum import BugNotificationLevel |
129 | @@ -172,10 +170,7 @@ | |||
130 | 172 | IDistributionSourcePackage, | 170 | IDistributionSourcePackage, |
131 | 173 | ) | 171 | ) |
132 | 174 | from lp.registry.interfaces.distroseries import IDistroSeries | 172 | from lp.registry.interfaces.distroseries import IDistroSeries |
137 | 175 | from lp.registry.interfaces.person import ( | 173 | from lp.registry.interfaces.person import validate_public_person |
134 | 176 | IPersonSet, | ||
135 | 177 | validate_public_person, | ||
136 | 178 | ) | ||
138 | 179 | from lp.registry.interfaces.product import IProduct | 174 | from lp.registry.interfaces.product import IProduct |
139 | 180 | from lp.registry.interfaces.productseries import IProductSeries | 175 | from lp.registry.interfaces.productseries import IProductSeries |
140 | 181 | from lp.registry.interfaces.series import SeriesStatus | 176 | from lp.registry.interfaces.series import SeriesStatus |
141 | @@ -458,11 +453,9 @@ | |||
142 | 458 | store = Store.of(self) | 453 | store = Store.of(self) |
143 | 459 | message_by_id = {} | 454 | message_by_id = {} |
144 | 460 | if include_parents: | 455 | if include_parents: |
147 | 461 | def to_messages(rows): | 456 | to_messages = lambda rows: [row[0] for row in rows] |
146 | 462 | return [row[0] for row in rows] | ||
148 | 463 | else: | 457 | else: |
151 | 464 | def to_messages(rows): | 458 | to_messages = lambda rows: rows |
150 | 465 | return rows | ||
152 | 466 | def eager_load_owners(messages): | 459 | def eager_load_owners(messages): |
153 | 467 | # Because we may have multiple owners, we spend less time in storm | 460 | # Because we may have multiple owners, we spend less time in storm |
154 | 468 | # with very large bugs by not joining and instead querying a second | 461 | # with very large bugs by not joining and instead querying a second |
155 | @@ -976,31 +969,12 @@ | |||
156 | 976 | 969 | ||
157 | 977 | also_notified_subscribers = set() | 970 | also_notified_subscribers = set() |
158 | 978 | 971 | ||
159 | 979 | structural_subscription_targets = set() | ||
160 | 980 | |||
161 | 981 | for bugtask in self.bugtasks: | 972 | for bugtask in self.bugtasks: |
162 | 982 | if bugtask.assignee: | 973 | if bugtask.assignee: |
163 | 983 | also_notified_subscribers.add(bugtask.assignee) | 974 | also_notified_subscribers.add(bugtask.assignee) |
164 | 984 | if recipients is not None: | 975 | if recipients is not None: |
165 | 985 | recipients.addAssignee(bugtask.assignee) | 976 | recipients.addAssignee(bugtask.assignee) |
166 | 986 | 977 | ||
167 | 987 | if IStructuralSubscriptionTarget.providedBy(bugtask.target): | ||
168 | 988 | structural_subscription_targets.add(bugtask.target) | ||
169 | 989 | if bugtask.target.parent_subscription_target is not None: | ||
170 | 990 | structural_subscription_targets.add( | ||
171 | 991 | bugtask.target.parent_subscription_target) | ||
172 | 992 | |||
173 | 993 | if ISourcePackage.providedBy(bugtask.target): | ||
174 | 994 | # Distribution series bug tasks with a package have the | ||
175 | 995 | # source package set as their target, so we add the | ||
176 | 996 | # distroseries explicitly to the set of subscription | ||
177 | 997 | # targets. | ||
178 | 998 | structural_subscription_targets.add( | ||
179 | 999 | bugtask.distroseries) | ||
180 | 1000 | |||
181 | 1001 | if bugtask.milestone is not None: | ||
182 | 1002 | structural_subscription_targets.add(bugtask.milestone) | ||
183 | 1003 | |||
184 | 1004 | # If the target's bug supervisor isn't set, | 978 | # If the target's bug supervisor isn't set, |
185 | 1005 | # we add the owner as a subscriber. | 979 | # we add the owner as a subscriber. |
186 | 1006 | pillar = bugtask.pillar | 980 | pillar = bugtask.pillar |
187 | @@ -1009,22 +983,73 @@ | |||
188 | 1009 | if recipients is not None: | 983 | if recipients is not None: |
189 | 1010 | recipients.addRegistrant(pillar.owner, pillar) | 984 | recipients.addRegistrant(pillar.owner, pillar) |
190 | 1011 | 985 | ||
197 | 1012 | person_set = getUtility(IPersonSet) | 986 | # Structural subscribers. |
198 | 1013 | target_subscribers = person_set.getSubscribersForTargets( | 987 | also_notified_subscribers.update( |
199 | 1014 | structural_subscription_targets, recipients=recipients, | 988 | self.getStructuralSubscribers( |
200 | 1015 | level=level) | 989 | recipients=recipients, level=level)) |
195 | 1016 | |||
196 | 1017 | also_notified_subscribers.update(target_subscribers) | ||
201 | 1018 | 990 | ||
202 | 1019 | # Direct subscriptions always take precedence over indirect | 991 | # Direct subscriptions always take precedence over indirect |
203 | 1020 | # subscriptions. | 992 | # subscriptions. |
204 | 1021 | direct_subscribers = set(self.getDirectSubscribers()) | 993 | direct_subscribers = set(self.getDirectSubscribers()) |
205 | 994 | |||
206 | 1022 | # Remove security proxy for the sort key, but return | 995 | # Remove security proxy for the sort key, but return |
207 | 1023 | # the regular proxied object. | 996 | # the regular proxied object. |
208 | 1024 | return sorted( | 997 | return sorted( |
209 | 1025 | (also_notified_subscribers - direct_subscribers), | 998 | (also_notified_subscribers - direct_subscribers), |
210 | 1026 | key=lambda x: removeSecurityProxy(x).displayname) | 999 | key=lambda x: removeSecurityProxy(x).displayname) |
211 | 1027 | 1000 | ||
212 | 1001 | def getStructuralSubscribers(self, recipients=None, level=None): | ||
213 | 1002 | """See `IBug`. """ | ||
214 | 1003 | query_arguments = [] | ||
215 | 1004 | for bugtask in self.bugtasks: | ||
216 | 1005 | if IStructuralSubscriptionTarget.providedBy(bugtask.target): | ||
217 | 1006 | query_arguments.append((bugtask.target, bugtask)) | ||
218 | 1007 | if bugtask.target.parent_subscription_target is not None: | ||
219 | 1008 | query_arguments.append( | ||
220 | 1009 | (bugtask.target.parent_subscription_target, bugtask)) | ||
221 | 1010 | if ISourcePackage.providedBy(bugtask.target): | ||
222 | 1011 | # Distribution series bug tasks with a package have the source | ||
223 | 1012 | # package set as their target, so we add the distroseries | ||
224 | 1013 | # explicitly to the set of subscription targets. | ||
225 | 1014 | query_arguments.append((bugtask.distroseries, bugtask)) | ||
226 | 1015 | if bugtask.milestone is not None: | ||
227 | 1016 | query_arguments.append((bugtask.milestone, bugtask)) | ||
228 | 1017 | |||
229 | 1018 | if len(query_arguments) == 0: | ||
230 | 1019 | return EmptyResultSet() | ||
231 | 1020 | |||
232 | 1021 | if level is None: | ||
233 | 1022 | # If level is not specified, default to NOTHING so that all | ||
234 | 1023 | # subscriptions are found. XXX: Perhaps this should go in | ||
235 | 1024 | # getSubscriptionsForBugTask()? | ||
236 | 1025 | level = BugNotificationLevel.NOTHING | ||
237 | 1026 | |||
238 | 1027 | # Build the query. | ||
239 | 1028 | union = lambda left, right: left.union(right) | ||
240 | 1029 | queries = ( | ||
241 | 1030 | target.getSubscriptionsForBugTask(bugtask, level) | ||
242 | 1031 | for target, bugtask in query_arguments) | ||
243 | 1032 | subscriptions = reduce(union, queries) | ||
244 | 1033 | |||
245 | 1034 | # Pull all the subscriptions in. | ||
246 | 1035 | subscriptions = list(subscriptions) | ||
247 | 1036 | |||
248 | 1037 | # Prepare a query for the subscribers. | ||
249 | 1038 | subscribers = Store.of(self).find( | ||
250 | 1039 | Person, Person.id.is_in( | ||
251 | 1040 | subscription.subscriberID | ||
252 | 1041 | for subscription in subscriptions)) | ||
253 | 1042 | |||
254 | 1043 | if recipients is not None: | ||
255 | 1044 | # We need to process subscriptions, so pull all the subscribes | ||
256 | 1045 | # into the cache, then update recipients with the subscriptions. | ||
257 | 1046 | subscribers = list(subscribers) | ||
258 | 1047 | for subscription in subscriptions: | ||
259 | 1048 | recipients.addStructuralSubscriber( | ||
260 | 1049 | subscription.subscriber, subscription.target) | ||
261 | 1050 | |||
262 | 1051 | return subscribers | ||
263 | 1052 | |||
264 | 1028 | def getBugNotificationRecipients(self, duplicateof=None, old_bug=None, | 1053 | def getBugNotificationRecipients(self, duplicateof=None, old_bug=None, |
265 | 1029 | level=None, | 1054 | level=None, |
266 | 1030 | include_master_dupe_subscribers=False): | 1055 | include_master_dupe_subscribers=False): |
267 | 1031 | 1056 | ||
268 | === renamed file 'lib/lp/bugs/tests/test_bug.py' => 'lib/lp/bugs/model/tests/test_bug.py' | |||
269 | --- lib/lp/bugs/tests/test_bug.py 2010-10-14 13:47:47 +0000 | |||
270 | +++ lib/lp/bugs/model/tests/test_bug.py 2010-10-15 16:17:07 +0000 | |||
271 | @@ -5,7 +5,10 @@ | |||
272 | 5 | 5 | ||
273 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
274 | 7 | 7 | ||
275 | 8 | from storm.store import ResultSet | ||
276 | 9 | |||
277 | 8 | from canonical.testing.layers import DatabaseFunctionalLayer | 10 | from canonical.testing.layers import DatabaseFunctionalLayer |
278 | 11 | from lp.bugs.mail.bugnotificationrecipients import BugNotificationRecipients | ||
279 | 9 | from lp.registry.enum import BugNotificationLevel | 12 | from lp.registry.enum import BugNotificationLevel |
280 | 10 | from lp.registry.interfaces.person import PersonVisibility | 13 | from lp.registry.interfaces.person import PersonVisibility |
281 | 11 | from lp.registry.model.structuralsubscription import StructuralSubscription | 14 | from lp.registry.model.structuralsubscription import StructuralSubscription |
282 | @@ -14,6 +17,7 @@ | |||
283 | 14 | person_logged_in, | 17 | person_logged_in, |
284 | 15 | TestCaseWithFactory, | 18 | TestCaseWithFactory, |
285 | 16 | ) | 19 | ) |
286 | 20 | from lp.testing.matchers import StartsWith | ||
287 | 17 | 21 | ||
288 | 18 | 22 | ||
289 | 19 | class TestBug(TestCaseWithFactory): | 23 | class TestBug(TestCaseWithFactory): |
290 | @@ -36,7 +40,7 @@ | |||
291 | 36 | bug = self.factory.makeBug() | 40 | bug = self.factory.makeBug() |
292 | 37 | person = self.factory.makePerson() | 41 | person = self.factory.makePerson() |
293 | 38 | team1 = self.factory.makeTeam(members=[person]) | 42 | team1 = self.factory.makeTeam(members=[person]) |
295 | 39 | team2 = self.factory.makeTeam(members=[person]) | 43 | self.factory.makeTeam(members=[person]) |
296 | 40 | with person_logged_in(person): | 44 | with person_logged_in(person): |
297 | 41 | bug.subscribe(team1, person) | 45 | bug.subscribe(team1, person) |
298 | 42 | self.assertEqual([team1], list(bug.getSubscribersForPerson(person))) | 46 | self.assertEqual([team1], list(bug.getSubscribersForPerson(person))) |
299 | @@ -157,8 +161,7 @@ | |||
300 | 157 | subscriber = self.factory.makePerson() | 161 | subscriber = self.factory.makePerson() |
301 | 158 | subscribers.append(subscriber) | 162 | subscribers.append(subscriber) |
302 | 159 | with person_logged_in(subscriber): | 163 | with person_logged_in(subscriber): |
305 | 160 | subscription = bug.subscribe( | 164 | bug.subscribe(subscriber, subscriber, level=level) |
304 | 161 | subscriber, subscriber, level=level) | ||
306 | 162 | direct_subscribers = bug.getDirectSubscribers(level=level) | 165 | direct_subscribers = bug.getDirectSubscribers(level=level) |
307 | 163 | 166 | ||
308 | 164 | # All the previous subscribers will be included because | 167 | # All the previous subscribers will be included because |
309 | @@ -181,8 +184,7 @@ | |||
310 | 181 | subscriber = self.factory.makePerson() | 184 | subscriber = self.factory.makePerson() |
311 | 182 | subscribers.append(subscriber) | 185 | subscribers.append(subscriber) |
312 | 183 | with person_logged_in(subscriber): | 186 | with person_logged_in(subscriber): |
315 | 184 | subscription = bug.subscribe( | 187 | bug.subscribe(subscriber, subscriber, level=level) |
314 | 185 | subscriber, subscriber, level=level) | ||
316 | 186 | 188 | ||
317 | 187 | # All the subscribers should be returned by | 189 | # All the subscribers should be returned by |
318 | 188 | # getDirectSubscribers() because it defaults to returning | 190 | # getDirectSubscribers() because it defaults to returning |
319 | @@ -211,8 +213,7 @@ | |||
320 | 211 | subscriber = self.factory.makePerson() | 213 | subscriber = self.factory.makePerson() |
321 | 212 | subscribers.append(subscriber) | 214 | subscribers.append(subscriber) |
322 | 213 | with person_logged_in(subscriber): | 215 | with person_logged_in(subscriber): |
325 | 214 | subscription = duplicate_bug.subscribe( | 216 | duplicate_bug.subscribe(subscriber, subscriber, level=level) |
324 | 215 | subscriber, subscriber, level=level) | ||
326 | 216 | duplicate_subscribers = ( | 217 | duplicate_subscribers = ( |
327 | 217 | bug.getSubscribersFromDuplicates(level=level)) | 218 | bug.getSubscribersFromDuplicates(level=level)) |
328 | 218 | # All the previous subscribers will be included because | 219 | # All the previous subscribers will be included because |
329 | @@ -237,11 +238,92 @@ | |||
330 | 237 | duplicate_bug.owner, duplicate_bug.owner) | 238 | duplicate_bug.owner, duplicate_bug.owner) |
331 | 238 | subscriber = self.factory.makePerson() | 239 | subscriber = self.factory.makePerson() |
332 | 239 | with person_logged_in(subscriber): | 240 | with person_logged_in(subscriber): |
334 | 240 | direct_subscription = bug.subscribe( | 241 | bug.subscribe( |
335 | 241 | subscriber, subscriber, level=BugNotificationLevel.NOTHING) | 242 | subscriber, subscriber, level=BugNotificationLevel.NOTHING) |
337 | 242 | dupe_subscription = duplicate_bug.subscribe( | 243 | duplicate_bug.subscribe( |
338 | 243 | subscriber, subscriber, level=BugNotificationLevel.METADATA) | 244 | subscriber, subscriber, level=BugNotificationLevel.METADATA) |
339 | 244 | duplicate_subscribers = bug.getSubscribersFromDuplicates() | 245 | duplicate_subscribers = bug.getSubscribersFromDuplicates() |
340 | 245 | self.assertTrue( | 246 | self.assertTrue( |
341 | 246 | subscriber not in duplicate_subscribers, | 247 | subscriber not in duplicate_subscribers, |
342 | 247 | "Subscriber should not be in duplicate_subscribers.") | 248 | "Subscriber should not be in duplicate_subscribers.") |
343 | 249 | |||
344 | 250 | |||
345 | 251 | class TestBugStructuralSubscribers(TestCaseWithFactory): | ||
346 | 252 | |||
347 | 253 | layer = DatabaseFunctionalLayer | ||
348 | 254 | |||
349 | 255 | def test_getStructuralSubscribers_no_subscribers(self): | ||
350 | 256 | # If there are no subscribers for any of the bug's targets then no | ||
351 | 257 | # subscribers will be returned by getStructuralSubscribers(). | ||
352 | 258 | product = self.factory.makeProduct() | ||
353 | 259 | bug = self.factory.makeBug(product=product) | ||
354 | 260 | subscribers = bug.getStructuralSubscribers() | ||
355 | 261 | self.assertIsInstance(subscribers, ResultSet) | ||
356 | 262 | self.assertEqual([], list(subscribers)) | ||
357 | 263 | |||
358 | 264 | def test_getStructuralSubscribers_single_target(self): | ||
359 | 265 | # Subscribers for any of the bug's targets are returned. | ||
360 | 266 | subscriber = self.factory.makePerson() | ||
361 | 267 | login_person(subscriber) | ||
362 | 268 | product = self.factory.makeProduct() | ||
363 | 269 | product.addBugSubscription(subscriber, subscriber) | ||
364 | 270 | bug = self.factory.makeBug(product=product) | ||
365 | 271 | self.assertEqual([subscriber], list(bug.getStructuralSubscribers())) | ||
366 | 272 | |||
367 | 273 | def test_getStructuralSubscribers_multiple_targets(self): | ||
368 | 274 | # Subscribers for any of the bug's targets are returned. | ||
369 | 275 | actor = self.factory.makePerson() | ||
370 | 276 | login_person(actor) | ||
371 | 277 | |||
372 | 278 | subscriber1 = self.factory.makePerson() | ||
373 | 279 | subscriber2 = self.factory.makePerson() | ||
374 | 280 | |||
375 | 281 | product1 = self.factory.makeProduct(owner=actor) | ||
376 | 282 | product1.addBugSubscription(subscriber1, subscriber1) | ||
377 | 283 | product2 = self.factory.makeProduct(owner=actor) | ||
378 | 284 | product2.addBugSubscription(subscriber2, subscriber2) | ||
379 | 285 | |||
380 | 286 | bug = self.factory.makeBug(product=product1) | ||
381 | 287 | bug.addTask(actor, product2) | ||
382 | 288 | |||
383 | 289 | subscribers = bug.getStructuralSubscribers() | ||
384 | 290 | self.assertIsInstance(subscribers, ResultSet) | ||
385 | 291 | self.assertEqual(set([subscriber1, subscriber2]), set(subscribers)) | ||
386 | 292 | |||
387 | 293 | def test_getStructuralSubscribers_recipients(self): | ||
388 | 294 | # If provided, getStructuralSubscribers() calls the appropriate | ||
389 | 295 | # methods on a BugNotificationRecipients object. | ||
390 | 296 | subscriber = self.factory.makePerson() | ||
391 | 297 | login_person(subscriber) | ||
392 | 298 | product = self.factory.makeProduct() | ||
393 | 299 | product.addBugSubscription(subscriber, subscriber) | ||
394 | 300 | bug = self.factory.makeBug(product=product) | ||
395 | 301 | recipients = BugNotificationRecipients() | ||
396 | 302 | subscribers = bug.getStructuralSubscribers(recipients=recipients) | ||
397 | 303 | # The return value is a list only when populating recipients. | ||
398 | 304 | self.assertIsInstance(subscribers, list) | ||
399 | 305 | self.assertEqual([subscriber], recipients.getRecipients()) | ||
400 | 306 | reason, header = recipients.getReason(subscriber) | ||
401 | 307 | self.assertThat( | ||
402 | 308 | reason, StartsWith( | ||
403 | 309 | u"You received this bug notification because " | ||
404 | 310 | u"you are subscribed to ")) | ||
405 | 311 | self.assertThat(header, StartsWith(u"Subscriber ")) | ||
406 | 312 | |||
407 | 313 | def test_getStructuralSubscribers_level(self): | ||
408 | 314 | # getStructuralSubscribers() respects the given level. | ||
409 | 315 | subscriber = self.factory.makePerson() | ||
410 | 316 | login_person(subscriber) | ||
411 | 317 | product = self.factory.makeProduct() | ||
412 | 318 | subscription = product.addBugSubscription(subscriber, subscriber) | ||
413 | 319 | subscription.bug_notification_level = BugNotificationLevel.METADATA | ||
414 | 320 | bug = self.factory.makeBug(product=product) | ||
415 | 321 | self.assertEqual( | ||
416 | 322 | [subscriber], list( | ||
417 | 323 | bug.getStructuralSubscribers( | ||
418 | 324 | level=BugNotificationLevel.METADATA))) | ||
419 | 325 | subscription.bug_notification_level = BugNotificationLevel.METADATA | ||
420 | 326 | self.assertEqual( | ||
421 | 327 | [], list( | ||
422 | 328 | bug.getStructuralSubscribers( | ||
423 | 329 | level=BugNotificationLevel.COMMENTS))) | ||
424 | 248 | 330 | ||
425 | === modified file 'lib/lp/registry/doc/structural-subscriptions.txt' | |||
426 | --- lib/lp/registry/doc/structural-subscriptions.txt 2010-10-06 18:53:53 +0000 | |||
427 | +++ lib/lp/registry/doc/structural-subscriptions.txt 2010-10-15 16:17:07 +0000 | |||
428 | @@ -198,61 +198,6 @@ | |||
429 | 198 | name16 | 198 | name16 |
430 | 199 | 199 | ||
431 | 200 | 200 | ||
432 | 201 | Retrieving structural subscribers of targets | ||
433 | 202 | ============================================ | ||
434 | 203 | |||
435 | 204 | Subscribers of one or more targets are retrieved by | ||
436 | 205 | PersonSet.getSubscribersForTargets. | ||
437 | 206 | |||
438 | 207 | XXX Abel Deuring 2008-07-11 We must remove the security proxy, because | ||
439 | 208 | PersonSet.getSubscribersForTargets() accesses the private attribute | ||
440 | 209 | firefox._targets_args. This attribute should be renamed. Bug #247525. | ||
441 | 210 | |||
442 | 211 | >>> from zope.security.proxy import removeSecurityProxy | ||
443 | 212 | >>> firefox_no_proxy = removeSecurityProxy(firefox) | ||
444 | 213 | >>> from lp.registry.interfaces.person import IPersonSet | ||
445 | 214 | >>> person_set = getUtility(IPersonSet) | ||
446 | 215 | >>> firefox_subscribers = person_set.getSubscribersForTargets( | ||
447 | 216 | ... [firefox_no_proxy]) | ||
448 | 217 | >>> print_bug_subscribers(firefox_subscribers) | ||
449 | 218 | name12 | ||
450 | 219 | |||
451 | 220 | If PersonSet.getSubscribersForTargets() is passed a | ||
452 | 221 | BugNotificationLevel in its `level` parameter, only structural | ||
453 | 222 | subscribers with that notification level or higher will be returned. | ||
454 | 223 | The subscription level of ff_sub, the only structural subscription | ||
455 | 224 | to firefox, is NOTHING, hence we get an empty list if we pass any | ||
456 | 225 | larger bug notification level. | ||
457 | 226 | |||
458 | 227 | >>> firefox_subscribers = person_set.getSubscribersForTargets( | ||
459 | 228 | ... [firefox_no_proxy], level=BugNotificationLevel.LIFECYCLE) | ||
460 | 229 | >>> print len(firefox_subscribers) | ||
461 | 230 | 0 | ||
462 | 231 | |||
463 | 232 | If the bug notification level of ff_sub is increased, the subscription | ||
464 | 233 | is included in the result of PersonSet.getSubscribersForTarget(). | ||
465 | 234 | |||
466 | 235 | >>> ff_sub.level = BugNotificationLevel.LIFECYCLE | ||
467 | 236 | >>> firefox_subscribers = person_set.getSubscribersForTargets( | ||
468 | 237 | ... [firefox_no_proxy]) | ||
469 | 238 | >>> print_bug_subscribers(firefox_subscribers) | ||
470 | 239 | name12 | ||
471 | 240 | >>> ff_sub.level = BugNotificationLevel.METADATA | ||
472 | 241 | >>> firefox_subscribers = person_set.getSubscribersForTargets( | ||
473 | 242 | ... [firefox_no_proxy]) | ||
474 | 243 | >>> print_bug_subscribers(firefox_subscribers) | ||
475 | 244 | name12 | ||
476 | 245 | |||
477 | 246 | More than one target can be passed to PersonSet.getSubscribersForTargets(). | ||
478 | 247 | |||
479 | 248 | >>> ubuntu_no_proxy = removeSecurityProxy(ubuntu) | ||
480 | 249 | >>> ubuntu_or_firefox_subscribers = person_set.getSubscribersForTargets( | ||
481 | 250 | ... [firefox_no_proxy, ubuntu_no_proxy]) | ||
482 | 251 | >>> print_bug_subscribers(ubuntu_or_firefox_subscribers) | ||
483 | 252 | name12 | ||
484 | 253 | name16 | ||
485 | 254 | |||
486 | 255 | |||
487 | 256 | Target type display | 201 | Target type display |
488 | 257 | =================== | 202 | =================== |
489 | 258 | 203 | ||
490 | 259 | 204 | ||
491 | === modified file 'lib/lp/registry/interfaces/person.py' | |||
492 | --- lib/lp/registry/interfaces/person.py 2010-09-29 20:05:17 +0000 | |||
493 | +++ lib/lp/registry/interfaces/person.py 2010-10-15 16:17:07 +0000 | |||
494 | @@ -2006,17 +2006,6 @@ | |||
495 | 2006 | specified product are returned. | 2006 | specified product are returned. |
496 | 2007 | """ | 2007 | """ |
497 | 2008 | 2008 | ||
498 | 2009 | def getSubscribersForTargets(targets, recipients=None): | ||
499 | 2010 | """Return the set of subscribers for `targets`. | ||
500 | 2011 | |||
501 | 2012 | :param targets: The sequence of targets for which to get the | ||
502 | 2013 | subscribers. | ||
503 | 2014 | :param recipients: An optional instance of | ||
504 | 2015 | `BugNotificationRecipients`. | ||
505 | 2016 | If present, all found subscribers will be | ||
506 | 2017 | added to it. | ||
507 | 2018 | """ | ||
508 | 2019 | |||
509 | 2020 | def updatePersonalStandings(): | 2009 | def updatePersonalStandings(): |
510 | 2021 | """Update the personal standings of some people. | 2010 | """Update the personal standings of some people. |
511 | 2022 | 2011 | ||
512 | 2023 | 2012 | ||
513 | === modified file 'lib/lp/registry/interfaces/structuralsubscription.py' | |||
514 | --- lib/lp/registry/interfaces/structuralsubscription.py 2010-10-05 09:23:22 +0000 | |||
515 | +++ lib/lp/registry/interfaces/structuralsubscription.py 2010-10-15 16:17:07 +0000 | |||
516 | @@ -200,8 +200,8 @@ | |||
517 | 200 | def userHasBugSubscriptions(user): | 200 | def userHasBugSubscriptions(user): |
518 | 201 | """Is `user` subscribed, directly or via a team, to bug mail?""" | 201 | """Is `user` subscribed, directly or via a team, to bug mail?""" |
519 | 202 | 202 | ||
522 | 203 | def getSubscriptionsForBug(bug, level): | 203 | def getSubscriptionsForBugTask(bug, level): |
523 | 204 | """Return subscriptions for a given `IBug` at `level`.""" | 204 | """Return subscriptions for a given `IBugTask` at `level`.""" |
524 | 205 | 205 | ||
525 | 206 | 206 | ||
526 | 207 | class IStructuralSubscriptionTargetWrite(Interface): | 207 | class IStructuralSubscriptionTargetWrite(Interface): |
527 | 208 | 208 | ||
528 | === modified file 'lib/lp/registry/model/person.py' | |||
529 | --- lib/lp/registry/model/person.py 2010-09-29 14:38:30 +0000 | |||
530 | +++ lib/lp/registry/model/person.py 2010-10-15 16:17:07 +0000 | |||
531 | @@ -4060,59 +4060,6 @@ | |||
532 | 4060 | Person.id in (%s) | 4060 | Person.id in (%s) |
533 | 4061 | ''' % branch_clause) | 4061 | ''' % branch_clause) |
534 | 4062 | 4062 | ||
535 | 4063 | def getSubscribersForTargets(self, targets, recipients=None, level=None): | ||
536 | 4064 | """See `IPersonSet`. """ | ||
537 | 4065 | if len(targets) == 0: | ||
538 | 4066 | return set() | ||
539 | 4067 | target_criteria = [] | ||
540 | 4068 | for target in targets: | ||
541 | 4069 | # target_args is a mapping from query arguments | ||
542 | 4070 | # to query values. | ||
543 | 4071 | target_args = target._target_args | ||
544 | 4072 | target_criteria_clauses = [] | ||
545 | 4073 | for key, value in target_args.items(): | ||
546 | 4074 | if value is not None: | ||
547 | 4075 | target_criteria_clauses.append( | ||
548 | 4076 | '%s = %s' % (key, quote(value))) | ||
549 | 4077 | else: | ||
550 | 4078 | target_criteria_clauses.append( | ||
551 | 4079 | '%s IS NULL' % key) | ||
552 | 4080 | if level is not None: | ||
553 | 4081 | target_criteria_clauses.append('bug_notification_level >= %s' | ||
554 | 4082 | % quote(level.value)) | ||
555 | 4083 | |||
556 | 4084 | target_criteria.append( | ||
557 | 4085 | '(%s)' % ' AND '.join(target_criteria_clauses)) | ||
558 | 4086 | |||
559 | 4087 | # Build a UNION query, since using OR slows down the query a lot. | ||
560 | 4088 | subscriptions = StructuralSubscription.select(target_criteria[0]) | ||
561 | 4089 | for target_criterion in target_criteria[1:]: | ||
562 | 4090 | subscriptions = subscriptions.union( | ||
563 | 4091 | StructuralSubscription.select(target_criterion)) | ||
564 | 4092 | |||
565 | 4093 | # Listify the result, since we want to loop over it multiple times. | ||
566 | 4094 | subscriptions = list(subscriptions) | ||
567 | 4095 | |||
568 | 4096 | # We can't use prejoins in UNION queries, so populate the cache | ||
569 | 4097 | # by getting all the subscribers. | ||
570 | 4098 | subscriber_ids = [ | ||
571 | 4099 | subscription.subscriberID for subscription in subscriptions] | ||
572 | 4100 | if len(subscriber_ids) > 0: | ||
573 | 4101 | # Pull in ValidPersonCache records in addition to Person | ||
574 | 4102 | # records to warm up the cache. | ||
575 | 4103 | list(IStore(Person).find( | ||
576 | 4104 | (Person, ValidPersonCache), | ||
577 | 4105 | In(Person.id, subscriber_ids), | ||
578 | 4106 | ValidPersonCache.id == Person.id)) | ||
579 | 4107 | |||
580 | 4108 | subscribers = set() | ||
581 | 4109 | for subscription in subscriptions: | ||
582 | 4110 | subscribers.add(subscription.subscriber) | ||
583 | 4111 | if recipients is not None: | ||
584 | 4112 | recipients.addStructuralSubscriber( | ||
585 | 4113 | subscription.subscriber, subscription.target) | ||
586 | 4114 | return subscribers | ||
587 | 4115 | |||
588 | 4116 | def updatePersonalStandings(self): | 4063 | def updatePersonalStandings(self): |
589 | 4117 | """See `IPersonSet`.""" | 4064 | """See `IPersonSet`.""" |
590 | 4118 | cur = cursor() | 4065 | cur = cursor() |
591 | 4119 | 4066 | ||
592 | === modified file 'lib/lp/registry/model/structuralsubscription.py' | |||
593 | --- lib/lp/registry/model/structuralsubscription.py 2010-10-05 16:52:02 +0000 | |||
594 | +++ lib/lp/registry/model/structuralsubscription.py 2010-10-15 16:17:07 +0000 | |||
595 | @@ -484,21 +484,8 @@ | |||
596 | 484 | return True | 484 | return True |
597 | 485 | return False | 485 | return False |
598 | 486 | 486 | ||
600 | 487 | def getSubscriptionsForBug(self, bug, level): | 487 | def getSubscriptionsForBugTask(self, bugtask, level): |
601 | 488 | """See `IStructuralSubscriptionTarget`.""" | 488 | """See `IStructuralSubscriptionTarget`.""" |
602 | 489 | if IProjectGroup.providedBy(self): | ||
603 | 490 | targets = set(self.products) | ||
604 | 491 | elif IMilestone.providedBy(self): | ||
605 | 492 | targets = [self.series_target] | ||
606 | 493 | else: | ||
607 | 494 | targets = [self] | ||
608 | 495 | |||
609 | 496 | bugtasks = [ | ||
610 | 497 | bugtask for bugtask in bug.bugtasks | ||
611 | 498 | if bugtask.target in targets] | ||
612 | 499 | |||
613 | 500 | assert len(bugtasks) != 0, repr(self) | ||
614 | 501 | |||
615 | 502 | origin = [ | 489 | origin = [ |
616 | 503 | StructuralSubscription, | 490 | StructuralSubscription, |
617 | 504 | LeftJoin( | 491 | LeftJoin( |
618 | @@ -515,7 +502,7 @@ | |||
619 | 515 | BugSubscriptionFilter.id)), | 502 | BugSubscriptionFilter.id)), |
620 | 516 | ] | 503 | ] |
621 | 517 | 504 | ||
623 | 518 | if len(bug.tags) == 0: | 505 | if len(bugtask.bug.tags) == 0: |
624 | 519 | tag_conditions = [ | 506 | tag_conditions = [ |
625 | 520 | BugSubscriptionFilter.include_any_tags == False, | 507 | BugSubscriptionFilter.include_any_tags == False, |
626 | 521 | ] | 508 | ] |
627 | @@ -534,13 +521,12 @@ | |||
628 | 534 | # There's no status filter, or there is a status filter | 521 | # There's no status filter, or there is a status filter |
629 | 535 | # and and it matches. | 522 | # and and it matches. |
630 | 536 | Or(BugSubscriptionFilterStatus.id == None, | 523 | Or(BugSubscriptionFilterStatus.id == None, |
633 | 537 | BugSubscriptionFilterStatus.status.is_in( | 524 | BugSubscriptionFilterStatus.status == bugtask.status), |
632 | 538 | bugtask.status for bugtask in bugtasks)), | ||
634 | 539 | # There's no importance filter, or there is an importance | 525 | # There's no importance filter, or there is an importance |
635 | 540 | # filter and it matches. | 526 | # filter and it matches. |
636 | 541 | Or(BugSubscriptionFilterImportance.id == None, | 527 | Or(BugSubscriptionFilterImportance.id == None, |
639 | 542 | BugSubscriptionFilterImportance.importance.is_in( | 528 | BugSubscriptionFilterImportance.importance == ( |
640 | 543 | bugtask.importance for bugtask in bugtasks)), | 529 | bugtask.importance)), |
641 | 544 | # Any number of conditions relating to tags. | 530 | # Any number of conditions relating to tags. |
642 | 545 | *tag_conditions)), | 531 | *tag_conditions)), |
643 | 546 | ] | 532 | ] |
644 | 547 | 533 | ||
645 | === modified file 'lib/lp/registry/tests/test_structuralsubscriptiontarget.py' | |||
646 | --- lib/lp/registry/tests/test_structuralsubscriptiontarget.py 2010-10-06 18:53:53 +0000 | |||
647 | +++ lib/lp/registry/tests/test_structuralsubscriptiontarget.py 2010-10-15 16:17:07 +0000 | |||
648 | @@ -173,19 +173,20 @@ | |||
649 | 173 | def makeBugTask(self): | 173 | def makeBugTask(self): |
650 | 174 | return self.factory.makeBugTask(target=self.target) | 174 | return self.factory.makeBugTask(target=self.target) |
651 | 175 | 175 | ||
653 | 176 | def test_getSubscriptionsForBug(self): | 176 | def test_getSubscriptionsForBugTask(self): |
654 | 177 | # If no one has a filtered subscription for the given bug, the result | 177 | # If no one has a filtered subscription for the given bug, the result |
656 | 178 | # of getSubscriptionsForBug() is the same as for getSubscriptions(). | 178 | # of getSubscriptionsForBugTask() is the same as for |
657 | 179 | # getSubscriptions(). | ||
658 | 179 | bugtask = self.makeBugTask() | 180 | bugtask = self.makeBugTask() |
659 | 180 | subscriptions = self.target.getSubscriptions( | 181 | subscriptions = self.target.getSubscriptions( |
660 | 181 | min_bug_notification_level=BugNotificationLevel.NOTHING) | 182 | min_bug_notification_level=BugNotificationLevel.NOTHING) |
664 | 182 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 183 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
665 | 183 | bugtask.bug, BugNotificationLevel.NOTHING) | 184 | bugtask, BugNotificationLevel.NOTHING) |
666 | 184 | self.assertEqual(list(subscriptions), list(subscriptions_for_bug)) | 185 | self.assertEqual(list(subscriptions), list(subscriptions_for_bugtask)) |
667 | 185 | 186 | ||
669 | 186 | def test_getSubscriptionsForBug_with_filter_on_status(self): | 187 | def test_getSubscriptionsForBugTask_with_filter_on_status(self): |
670 | 187 | # If a status filter exists for a subscription, the result of | 188 | # If a status filter exists for a subscription, the result of |
672 | 188 | # getSubscriptionsForBug() may be a subset of getSubscriptions(). | 189 | # getSubscriptionsForBugTask() may be a subset of getSubscriptions(). |
673 | 189 | bugtask = self.makeBugTask() | 190 | bugtask = self.makeBugTask() |
674 | 190 | 191 | ||
675 | 191 | # Create a new subscription on self.target. | 192 | # Create a new subscription on self.target. |
676 | @@ -195,9 +196,9 @@ | |||
677 | 195 | subscription.bug_notification_level = BugNotificationLevel.COMMENTS | 196 | subscription.bug_notification_level = BugNotificationLevel.COMMENTS |
678 | 196 | 197 | ||
679 | 197 | # Without any filters the subscription is found. | 198 | # Without any filters the subscription is found. |
683 | 198 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 199 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
684 | 199 | bugtask.bug, BugNotificationLevel.NOTHING) | 200 | bugtask, BugNotificationLevel.NOTHING) |
685 | 200 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 201 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
686 | 201 | 202 | ||
687 | 202 | # Filter the subscription to bugs in the CONFIRMED state. | 203 | # Filter the subscription to bugs in the CONFIRMED state. |
688 | 203 | subscription_filter = BugSubscriptionFilter() | 204 | subscription_filter = BugSubscriptionFilter() |
689 | @@ -205,19 +206,19 @@ | |||
690 | 205 | subscription_filter.statuses = [BugTaskStatus.CONFIRMED] | 206 | subscription_filter.statuses = [BugTaskStatus.CONFIRMED] |
691 | 206 | 207 | ||
692 | 207 | # With the filter the subscription is not found. | 208 | # With the filter the subscription is not found. |
696 | 208 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 209 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
697 | 209 | bugtask.bug, BugNotificationLevel.NOTHING) | 210 | bugtask, BugNotificationLevel.NOTHING) |
698 | 210 | self.assertEqual([], list(subscriptions_for_bug)) | 211 | self.assertEqual([], list(subscriptions_for_bugtask)) |
699 | 211 | 212 | ||
700 | 212 | # If the filter is adjusted, the subscription is found again. | 213 | # If the filter is adjusted, the subscription is found again. |
701 | 213 | subscription_filter.statuses = [bugtask.status] | 214 | subscription_filter.statuses = [bugtask.status] |
705 | 214 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 215 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
706 | 215 | bugtask.bug, BugNotificationLevel.NOTHING) | 216 | bugtask, BugNotificationLevel.NOTHING) |
707 | 216 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 217 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
708 | 217 | 218 | ||
710 | 218 | def test_getSubscriptionsForBug_with_filter_on_importance(self): | 219 | def test_getSubscriptionsForBugTask_with_filter_on_importance(self): |
711 | 219 | # If an importance filter exists for a subscription, the result of | 220 | # If an importance filter exists for a subscription, the result of |
713 | 220 | # getSubscriptionsForBug() may be a subset of getSubscriptions(). | 221 | # getSubscriptionsForBugTask() may be a subset of getSubscriptions(). |
714 | 221 | bugtask = self.makeBugTask() | 222 | bugtask = self.makeBugTask() |
715 | 222 | 223 | ||
716 | 223 | # Create a new subscription on self.target. | 224 | # Create a new subscription on self.target. |
717 | @@ -227,9 +228,9 @@ | |||
718 | 227 | subscription.bug_notification_level = BugNotificationLevel.COMMENTS | 228 | subscription.bug_notification_level = BugNotificationLevel.COMMENTS |
719 | 228 | 229 | ||
720 | 229 | # Without any filters the subscription is found. | 230 | # Without any filters the subscription is found. |
724 | 230 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 231 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
725 | 231 | bugtask.bug, BugNotificationLevel.NOTHING) | 232 | bugtask, BugNotificationLevel.NOTHING) |
726 | 232 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 233 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
727 | 233 | 234 | ||
728 | 234 | # Filter the subscription to bugs in the CRITICAL state. | 235 | # Filter the subscription to bugs in the CRITICAL state. |
729 | 235 | subscription_filter = BugSubscriptionFilter() | 236 | subscription_filter = BugSubscriptionFilter() |
730 | @@ -237,19 +238,19 @@ | |||
731 | 237 | subscription_filter.importances = [BugTaskImportance.CRITICAL] | 238 | subscription_filter.importances = [BugTaskImportance.CRITICAL] |
732 | 238 | 239 | ||
733 | 239 | # With the filter the subscription is not found. | 240 | # With the filter the subscription is not found. |
737 | 240 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 241 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
738 | 241 | bugtask.bug, BugNotificationLevel.NOTHING) | 242 | bugtask, BugNotificationLevel.NOTHING) |
739 | 242 | self.assertEqual([], list(subscriptions_for_bug)) | 243 | self.assertEqual([], list(subscriptions_for_bugtask)) |
740 | 243 | 244 | ||
741 | 244 | # If the filter is adjusted, the subscription is found again. | 245 | # If the filter is adjusted, the subscription is found again. |
742 | 245 | subscription_filter.importances = [bugtask.importance] | 246 | subscription_filter.importances = [bugtask.importance] |
746 | 246 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 247 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
747 | 247 | bugtask.bug, BugNotificationLevel.NOTHING) | 248 | bugtask, BugNotificationLevel.NOTHING) |
748 | 248 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 249 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
749 | 249 | 250 | ||
751 | 250 | def test_getSubscriptionsForBug_with_filter_on_level(self): | 251 | def test_getSubscriptionsForBugTask_with_filter_on_level(self): |
752 | 251 | # All structural subscriptions have a level for bug notifications | 252 | # All structural subscriptions have a level for bug notifications |
754 | 252 | # which getSubscriptionsForBug() observes. | 253 | # which getSubscriptionsForBugTask() observes. |
755 | 253 | bugtask = self.makeBugTask() | 254 | bugtask = self.makeBugTask() |
756 | 254 | 255 | ||
757 | 255 | # Create a new METADATA level subscription on self.target. | 256 | # Create a new METADATA level subscription on self.target. |
758 | @@ -259,19 +260,19 @@ | |||
759 | 259 | subscription.bug_notification_level = BugNotificationLevel.METADATA | 260 | subscription.bug_notification_level = BugNotificationLevel.METADATA |
760 | 260 | 261 | ||
761 | 261 | # The subscription is found when looking for NOTHING or above. | 262 | # The subscription is found when looking for NOTHING or above. |
765 | 262 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 263 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
766 | 263 | bugtask.bug, BugNotificationLevel.NOTHING) | 264 | bugtask, BugNotificationLevel.NOTHING) |
767 | 264 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 265 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
768 | 265 | # The subscription is found when looking for METADATA or above. | 266 | # The subscription is found when looking for METADATA or above. |
772 | 266 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 267 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
773 | 267 | bugtask.bug, BugNotificationLevel.METADATA) | 268 | bugtask, BugNotificationLevel.METADATA) |
774 | 268 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 269 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
775 | 269 | # The subscription is not found when looking for COMMENTS or above. | 270 | # The subscription is not found when looking for COMMENTS or above. |
779 | 270 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 271 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
780 | 271 | bugtask.bug, BugNotificationLevel.COMMENTS) | 272 | bugtask, BugNotificationLevel.COMMENTS) |
781 | 272 | self.assertEqual([], list(subscriptions_for_bug)) | 273 | self.assertEqual([], list(subscriptions_for_bugtask)) |
782 | 273 | 274 | ||
784 | 274 | def test_getSubscriptionsForBug_with_filter_include_any_tags(self): | 275 | def test_getSubscriptionsForBugTask_with_filter_include_any_tags(self): |
785 | 275 | # If a subscription filter has include_any_tags, a bug with one or | 276 | # If a subscription filter has include_any_tags, a bug with one or |
786 | 276 | # more tags is matched. | 277 | # more tags is matched. |
787 | 277 | bugtask = self.makeBugTask() | 278 | bugtask = self.makeBugTask() |
788 | @@ -285,17 +286,17 @@ | |||
789 | 285 | subscription_filter.include_any_tags = True | 286 | subscription_filter.include_any_tags = True |
790 | 286 | 287 | ||
791 | 287 | # Without any tags the subscription is not found. | 288 | # Without any tags the subscription is not found. |
795 | 288 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 289 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
796 | 289 | bugtask.bug, BugNotificationLevel.NOTHING) | 290 | bugtask, BugNotificationLevel.NOTHING) |
797 | 290 | self.assertEqual([], list(subscriptions_for_bug)) | 291 | self.assertEqual([], list(subscriptions_for_bugtask)) |
798 | 291 | 292 | ||
799 | 292 | # With any tag the subscription is found. | 293 | # With any tag the subscription is found. |
800 | 293 | bugtask.bug.tags = ["foo"] | 294 | bugtask.bug.tags = ["foo"] |
804 | 294 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 295 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
805 | 295 | bugtask.bug, BugNotificationLevel.NOTHING) | 296 | bugtask, BugNotificationLevel.NOTHING) |
806 | 296 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 297 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
807 | 297 | 298 | ||
809 | 298 | def test_getSubscriptionsForBug_with_filter_exclude_any_tags(self): | 299 | def test_getSubscriptionsForBugTask_with_filter_exclude_any_tags(self): |
810 | 299 | # If a subscription filter has exclude_any_tags, only bugs with no | 300 | # If a subscription filter has exclude_any_tags, only bugs with no |
811 | 300 | # tags are matched. | 301 | # tags are matched. |
812 | 301 | bugtask = self.makeBugTask() | 302 | bugtask = self.makeBugTask() |
813 | @@ -309,17 +310,17 @@ | |||
814 | 309 | subscription_filter.exclude_any_tags = True | 310 | subscription_filter.exclude_any_tags = True |
815 | 310 | 311 | ||
816 | 311 | # Without any tags the subscription is found. | 312 | # Without any tags the subscription is found. |
820 | 312 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 313 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
821 | 313 | bugtask.bug, BugNotificationLevel.NOTHING) | 314 | bugtask, BugNotificationLevel.NOTHING) |
822 | 314 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 315 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
823 | 315 | 316 | ||
824 | 316 | # With any tag the subscription is not found. | 317 | # With any tag the subscription is not found. |
825 | 317 | bugtask.bug.tags = ["foo"] | 318 | bugtask.bug.tags = ["foo"] |
829 | 318 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 319 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
830 | 319 | bugtask.bug, BugNotificationLevel.NOTHING) | 320 | bugtask, BugNotificationLevel.NOTHING) |
831 | 320 | self.assertEqual([], list(subscriptions_for_bug)) | 321 | self.assertEqual([], list(subscriptions_for_bugtask)) |
832 | 321 | 322 | ||
834 | 322 | def test_getSubscriptionsForBug_with_multiple_filters(self): | 323 | def test_getSubscriptionsForBugTask_with_multiple_filters(self): |
835 | 323 | # If multiple filters exist for a subscription, all filters must | 324 | # If multiple filters exist for a subscription, all filters must |
836 | 324 | # match. | 325 | # match. |
837 | 325 | bugtask = self.makeBugTask() | 326 | bugtask = self.makeBugTask() |
838 | @@ -337,23 +338,23 @@ | |||
839 | 337 | subscription_filter.importances = [BugTaskImportance.CRITICAL] | 338 | subscription_filter.importances = [BugTaskImportance.CRITICAL] |
840 | 338 | 339 | ||
841 | 339 | # With the filter the subscription is not found. | 340 | # With the filter the subscription is not found. |
845 | 340 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 341 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
846 | 341 | bugtask.bug, BugNotificationLevel.NOTHING) | 342 | bugtask, BugNotificationLevel.NOTHING) |
847 | 342 | self.assertEqual([], list(subscriptions_for_bug)) | 343 | self.assertEqual([], list(subscriptions_for_bugtask)) |
848 | 343 | 344 | ||
849 | 344 | # If the filter is adjusted to match status but not importance, the | 345 | # If the filter is adjusted to match status but not importance, the |
850 | 345 | # subscription is still not found. | 346 | # subscription is still not found. |
851 | 346 | subscription_filter.statuses = [bugtask.status] | 347 | subscription_filter.statuses = [bugtask.status] |
855 | 347 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 348 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
856 | 348 | bugtask.bug, BugNotificationLevel.NOTHING) | 349 | bugtask, BugNotificationLevel.NOTHING) |
857 | 349 | self.assertEqual([], list(subscriptions_for_bug)) | 350 | self.assertEqual([], list(subscriptions_for_bugtask)) |
858 | 350 | 351 | ||
859 | 351 | # If the filter is adjusted to also match importance, the subscription | 352 | # If the filter is adjusted to also match importance, the subscription |
860 | 352 | # is found again. | 353 | # is found again. |
861 | 353 | subscription_filter.importances = [bugtask.importance] | 354 | subscription_filter.importances = [bugtask.importance] |
865 | 354 | subscriptions_for_bug = self.target.getSubscriptionsForBug( | 355 | subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
866 | 355 | bugtask.bug, BugNotificationLevel.NOTHING) | 356 | bugtask, BugNotificationLevel.NOTHING) |
867 | 356 | self.assertEqual([subscription], list(subscriptions_for_bug)) | 357 | self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
868 | 357 | 358 | ||
869 | 358 | 359 | ||
870 | 359 | class TestStructuralSubscriptionForDistro( | 360 | class TestStructuralSubscriptionForDistro( |
871 | 360 | 361 | ||
872 | === modified file 'utilities/format-new-and-modified-imports' | |||
873 | --- utilities/format-new-and-modified-imports 2010-09-28 09:50:49 +0000 | |||
874 | +++ utilities/format-new-and-modified-imports 2010-10-15 16:17:07 +0000 | |||
875 | @@ -9,5 +9,5 @@ | |||
876 | 9 | # | 9 | # |
877 | 10 | 10 | ||
878 | 11 | bzr status --short "$@" | \ | 11 | bzr status --short "$@" | \ |
880 | 12 | awk '/^.[MN] .*[.]py$/ { print $2 }' | \ | 12 | awk '/^.[MN] .*[.]py$/ { print $NF }' | \ |
881 | 13 | xargs -r "$(dirname "$0")/format-imports" | 13 | xargs -r "$(dirname "$0")/format-imports" |
(18:18:58) allenap: adeuring: It's already reviewed and landed in db-devel, so I just need a +1 to land on devel.
(18:20:00) adeuring: allenap: so, rs=me
(18:20:10) allenap: adeuring: Thanks.