Merge lp:~abentley/launchpad/hide-sprint-blueprints into lp:launchpad
- hide-sprint-blueprints
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | j.c.sackett | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 16057 | ||||
Proposed branch: | lp:~abentley/launchpad/hide-sprint-blueprints | ||||
Merge into: | lp:launchpad | ||||
Prerequisite: | lp:~abentley/launchpad/specification-cleanup | ||||
Diff against target: |
1182 lines (+193/-119) 29 files modified
lib/lp/app/browser/root.py (+1/-1) lib/lp/blueprints/browser/specification.py (+4/-4) lib/lp/blueprints/browser/specificationtarget.py (+7/-6) lib/lp/blueprints/browser/sprint.py (+2/-2) lib/lp/blueprints/browser/tests/test_sprint.py (+13/-0) lib/lp/blueprints/doc/specification.txt (+2/-2) lib/lp/blueprints/doc/sprint.txt (+6/-6) lib/lp/blueprints/interfaces/specification.py (+1/-1) lib/lp/blueprints/interfaces/specificationtarget.py (+2/-1) lib/lp/blueprints/model/specification.py (+10/-6) lib/lp/blueprints/model/sprint.py (+14/-7) lib/lp/blueprints/model/tests/test_sprint.py (+47/-14) lib/lp/blueprints/templates/person-specworkload.pt (+1/-1) lib/lp/blueprints/vocabularies/specification.py (+2/-1) lib/lp/registry/browser/person.py (+5/-2) lib/lp/registry/doc/distribution.txt (+8/-8) lib/lp/registry/doc/distroseries.txt (+9/-9) lib/lp/registry/doc/person-account.txt (+1/-1) lib/lp/registry/doc/person.txt (+9/-9) lib/lp/registry/doc/product.txt (+4/-4) lib/lp/registry/doc/productseries.txt (+10/-10) lib/lp/registry/doc/projectgroup.txt (+14/-12) lib/lp/registry/model/distribution.py (+1/-1) lib/lp/registry/model/distroseries.py (+1/-1) lib/lp/registry/model/person.py (+1/-1) lib/lp/registry/model/product.py (+1/-1) lib/lp/registry/model/productseries.py (+1/-1) lib/lp/registry/model/projectgroup.py (+4/-3) lib/lp/testing/factory.py (+12/-4) |
||||
To merge this branch: | bzr merge lp:~abentley/launchpad/hide-sprint-blueprints | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
j.c.sackett (community) | Approve | ||
Review via email: mp+126792@code.launchpad.net |
Commit message
Respect privacy listing specifications for sprints.
Description of the change
= Summary =
Fix bug #1051029: Fix meeting listings with PROPRIETARY specs
== Proposed fix ==
Sprint.
== Pre-implementation notes ==
None
== LOC Rationale ==
Part of private projects
== Implementation details ==
IHasSpecificati
Sprint.
All callers are updated to supply a user. View methods supply self.user, and model methods accept an additional parameter. _all_specifications and _valid_
== Tests ==
Everything
== Demo and Q/A ==
Create a PROPRIETARY blueprint. Link it to a sprint. Go to the sprint page. You should see the blueprint. Log out. It should stop being listed, but the page should not be broken.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
./lib/lp/
408: redefinition of function 'date_next_
^^^ This is an acceptable case of re-definition. It's creating a setter.
Aaron Bentley (abentley) wrote : | # |
> As one minor point, it might be cleaner to set the default argument for user
> in `specifications` to None, rather than passing in None everytime you need
> it. But I don't see that as a blocker to approval--it's just a thought.
I don't think it would be cleaner to set a default, because it would encourage mistakes and sloppy use. The fact is that you need to decide what user to use in all cases. What's worse, mistakes will cause only subtle differences and may go undetected. Deciding to use None is valid, but in most cases you'll be passing in a variable that may or may not have been set to None, like ILaunchBag.user or LaunchpadView.user.
Preview Diff
1 | === modified file 'lib/lp/app/browser/root.py' | |||
2 | --- lib/lp/app/browser/root.py 2012-09-28 14:42:25 +0000 | |||
3 | +++ lib/lp/app/browser/root.py 2012-09-28 14:42:25 +0000 | |||
4 | @@ -130,7 +130,7 @@ | |||
5 | 130 | @property | 130 | @property |
6 | 131 | def blueprint_count(self): | 131 | def blueprint_count(self): |
7 | 132 | """The total blueprint count in all of Launchpad.""" | 132 | """The total blueprint count in all of Launchpad.""" |
9 | 133 | return getUtility(ISpecificationSet).specificationCount() | 133 | return getUtility(ISpecificationSet).specificationCount(self.user) |
10 | 134 | 134 | ||
11 | 135 | @property | 135 | @property |
12 | 136 | def answer_count(self): | 136 | def answer_count(self): |
13 | 137 | 137 | ||
14 | === modified file 'lib/lp/blueprints/browser/specification.py' | |||
15 | --- lib/lp/blueprints/browser/specification.py 2012-09-28 14:42:25 +0000 | |||
16 | +++ lib/lp/blueprints/browser/specification.py 2012-09-28 14:42:25 +0000 | |||
17 | @@ -1036,7 +1036,7 @@ | |||
18 | 1036 | """Override the setup to define own fields.""" | 1036 | """Override the setup to define own fields.""" |
19 | 1037 | if self.context.target is None: | 1037 | if self.context.target is None: |
20 | 1038 | raise AssertionError("No target found for this spec.") | 1038 | raise AssertionError("No target found for this spec.") |
22 | 1039 | specs = sorted(self.context.target.specifications(), | 1039 | specs = sorted(self.context.target.specifications(self.user), |
23 | 1040 | key=attrgetter('name')) | 1040 | key=attrgetter('name')) |
24 | 1041 | terms = [SimpleTerm(spec, spec.name, spec.title) | 1041 | terms = [SimpleTerm(spec, spec.name, spec.title) |
25 | 1042 | for spec in specs if spec != self.context] | 1042 | for spec in specs if spec != self.context] |
26 | @@ -1530,17 +1530,17 @@ | |||
27 | 1530 | @property | 1530 | @property |
28 | 1531 | def latest_specifications(self): | 1531 | def latest_specifications(self): |
29 | 1532 | return self.context.specifications( | 1532 | return self.context.specifications( |
31 | 1533 | sort=SpecificationSort.DATE, quantity=5) | 1533 | self.user, sort=SpecificationSort.DATE, quantity=5) |
32 | 1534 | 1534 | ||
33 | 1535 | @property | 1535 | @property |
34 | 1536 | def latest_completed_specifications(self): | 1536 | def latest_completed_specifications(self): |
35 | 1537 | return self.context.specifications( | 1537 | return self.context.specifications( |
37 | 1538 | sort=SpecificationSort.DATE, quantity=5, | 1538 | self.user, sort=SpecificationSort.DATE, quantity=5, |
38 | 1539 | filter=[SpecificationFilter.COMPLETE]) | 1539 | filter=[SpecificationFilter.COMPLETE]) |
39 | 1540 | 1540 | ||
40 | 1541 | @property | 1541 | @property |
41 | 1542 | def specification_count(self): | 1542 | def specification_count(self): |
43 | 1543 | return self.context.specificationCount() | 1543 | return self.context.specificationCount(self.user) |
44 | 1544 | 1544 | ||
45 | 1545 | @safe_action | 1545 | @safe_action |
46 | 1546 | @action('Find blueprints', name="search") | 1546 | @action('Find blueprints', name="search") |
47 | 1547 | 1547 | ||
48 | === modified file 'lib/lp/blueprints/browser/specificationtarget.py' | |||
49 | --- lib/lp/blueprints/browser/specificationtarget.py 2012-09-28 14:42:25 +0000 | |||
50 | +++ lib/lp/blueprints/browser/specificationtarget.py 2012-09-28 14:42:25 +0000 | |||
51 | @@ -259,11 +259,11 @@ | |||
52 | 259 | 259 | ||
53 | 260 | @cachedproperty | 260 | @cachedproperty |
54 | 261 | def has_any_specifications(self): | 261 | def has_any_specifications(self): |
56 | 262 | return self.context._all_specifications.count() != 0 | 262 | return not self.context._all_specifications.is_empty() |
57 | 263 | 263 | ||
58 | 264 | @cachedproperty | 264 | @cachedproperty |
59 | 265 | def all_specifications(self): | 265 | def all_specifications(self): |
61 | 266 | return shortlist(self.context.all_specifications) | 266 | return shortlist(self.context.all_specifications(self.user)) |
62 | 267 | 267 | ||
63 | 268 | @cachedproperty | 268 | @cachedproperty |
64 | 269 | def searchrequested(self): | 269 | def searchrequested(self): |
65 | @@ -348,7 +348,7 @@ | |||
66 | 348 | and not check_permission('launchpad.View', self.context)): | 348 | and not check_permission('launchpad.View', self.context)): |
67 | 349 | return [] | 349 | return [] |
68 | 350 | filter = self.spec_filter | 350 | filter = self.spec_filter |
70 | 351 | return self.context.specifications(filter=filter) | 351 | return self.context.specifications(self.user, filter=filter) |
71 | 352 | 352 | ||
72 | 353 | @cachedproperty | 353 | @cachedproperty |
73 | 354 | def specs_batched(self): | 354 | def specs_batched(self): |
74 | @@ -364,7 +364,7 @@ | |||
75 | 364 | def documentation(self): | 364 | def documentation(self): |
76 | 365 | filter = [SpecificationFilter.COMPLETE, | 365 | filter = [SpecificationFilter.COMPLETE, |
77 | 366 | SpecificationFilter.INFORMATIONAL] | 366 | SpecificationFilter.INFORMATIONAL] |
79 | 367 | return shortlist(self.context.specifications(filter=filter)) | 367 | return shortlist(self.context.specifications(self.user, filter=filter)) |
80 | 368 | 368 | ||
81 | 369 | @cachedproperty | 369 | @cachedproperty |
82 | 370 | def categories(self): | 370 | def categories(self): |
83 | @@ -405,8 +405,9 @@ | |||
84 | 405 | Only ACCEPTED specifications are returned. This list is used by the | 405 | Only ACCEPTED specifications are returned. This list is used by the |
85 | 406 | +portlet-latestspecs view. | 406 | +portlet-latestspecs view. |
86 | 407 | """ | 407 | """ |
89 | 408 | return self.context.specifications(sort=SpecificationSort.DATE, | 408 | return self.context.specifications(self.user, |
90 | 409 | quantity=quantity, prejoin_people=False) | 409 | sort=SpecificationSort.DATE, quantity=quantity, |
91 | 410 | prejoin_people=False) | ||
92 | 410 | 411 | ||
93 | 411 | 412 | ||
94 | 412 | class SpecificationAssignmentsView(HasSpecificationsView): | 413 | class SpecificationAssignmentsView(HasSpecificationsView): |
95 | 413 | 414 | ||
96 | === modified file 'lib/lp/blueprints/browser/sprint.py' | |||
97 | --- lib/lp/blueprints/browser/sprint.py 2012-01-01 02:58:52 +0000 | |||
98 | +++ lib/lp/blueprints/browser/sprint.py 2012-09-28 14:42:25 +0000 | |||
99 | @@ -216,7 +216,7 @@ | |||
100 | 216 | @cachedproperty | 216 | @cachedproperty |
101 | 217 | def latest_approved(self): | 217 | def latest_approved(self): |
102 | 218 | filter = [SpecificationFilter.ACCEPTED] | 218 | filter = [SpecificationFilter.ACCEPTED] |
104 | 219 | return self.context.specifications(filter=filter, | 219 | return self.context.specifications(self.user, filter=filter, |
105 | 220 | quantity=self.latest_specs_limit, | 220 | quantity=self.latest_specs_limit, |
106 | 221 | sort=SpecificationSort.DATE) | 221 | sort=SpecificationSort.DATE) |
107 | 222 | 222 | ||
108 | @@ -464,7 +464,7 @@ | |||
109 | 464 | 464 | ||
110 | 465 | model_specs = [] | 465 | model_specs = [] |
111 | 466 | for spec in self.context.specifications( | 466 | for spec in self.context.specifications( |
113 | 467 | filter=[SpecificationFilter.ACCEPTED]): | 467 | self.user, filter=[SpecificationFilter.ACCEPTED]): |
114 | 468 | 468 | ||
115 | 469 | # skip sprints with no priority or less than low: | 469 | # skip sprints with no priority or less than low: |
116 | 470 | if spec.priority < SpecificationPriority.UNDEFINED: | 470 | if spec.priority < SpecificationPriority.UNDEFINED: |
117 | 471 | 471 | ||
118 | === modified file 'lib/lp/blueprints/browser/tests/test_sprint.py' | |||
119 | --- lib/lp/blueprints/browser/tests/test_sprint.py 2012-09-28 14:42:25 +0000 | |||
120 | +++ lib/lp/blueprints/browser/tests/test_sprint.py 2012-09-28 14:42:25 +0000 | |||
121 | @@ -8,6 +8,7 @@ | |||
122 | 8 | from storm.locals import Store | 8 | from storm.locals import Store |
123 | 9 | from testtools.matchers import Equals | 9 | from testtools.matchers import Equals |
124 | 10 | 10 | ||
125 | 11 | from lp.app.enums import InformationType | ||
126 | 11 | from lp.testing import BrowserTestCase | 12 | from lp.testing import BrowserTestCase |
127 | 12 | from lp.testing.layers import DatabaseFunctionalLayer | 13 | from lp.testing.layers import DatabaseFunctionalLayer |
128 | 13 | from lp.testing.matchers import BrowsesWithQueryLimit, HasQueryCount | 14 | from lp.testing.matchers import BrowsesWithQueryLimit, HasQueryCount |
129 | @@ -40,3 +41,15 @@ | |||
130 | 40 | with QueryCollector() as recorder: | 41 | with QueryCollector() as recorder: |
131 | 41 | self.getViewBrowser(sprint) | 42 | self.getViewBrowser(sprint) |
132 | 42 | self.assertThat(recorder, HasQueryCount(Equals(30))) | 43 | self.assertThat(recorder, HasQueryCount(Equals(30))) |
133 | 44 | |||
134 | 45 | def test_proprietary_blueprint_listing_query_count(self): | ||
135 | 46 | """Set a maximum number of queries for sprint blueprint lists.""" | ||
136 | 47 | sprint = self.factory.makeSprint() | ||
137 | 48 | for count in range(10): | ||
138 | 49 | blueprint = self.factory.makeSpecification( | ||
139 | 50 | information_type=InformationType.PROPRIETARY) | ||
140 | 51 | link = blueprint.linkSprint(sprint, blueprint.owner) | ||
141 | 52 | link.acceptBy(sprint.owner) | ||
142 | 53 | with QueryCollector() as recorder: | ||
143 | 54 | self.getViewBrowser(sprint) | ||
144 | 55 | self.assertThat(recorder, HasQueryCount(Equals(22))) | ||
145 | 43 | 56 | ||
146 | === modified file 'lib/lp/blueprints/doc/specification.txt' | |||
147 | --- lib/lp/blueprints/doc/specification.txt 2012-09-28 14:42:25 +0000 | |||
148 | +++ lib/lp/blueprints/doc/specification.txt 2012-09-28 14:42:25 +0000 | |||
149 | @@ -222,7 +222,7 @@ | |||
150 | 222 | We can filter for specifications that contain specific text, across all | 222 | We can filter for specifications that contain specific text, across all |
151 | 223 | specifications: | 223 | specifications: |
152 | 224 | 224 | ||
154 | 225 | >>> for spec in specset.specifications(filter=['install']): | 225 | >>> for spec in specset.specifications(None, filter=['install']): |
155 | 226 | ... print spec.name, spec.target.name | 226 | ... print spec.name, spec.target.name |
156 | 227 | cluster-installation kubuntu | 227 | cluster-installation kubuntu |
157 | 228 | extension-manager-upgrades firefox | 228 | extension-manager-upgrades firefox |
158 | @@ -239,7 +239,7 @@ | |||
159 | 239 | >>> unlink_source_packages(upstream_firefox) | 239 | >>> unlink_source_packages(upstream_firefox) |
160 | 240 | >>> upstream_firefox.active = False | 240 | >>> upstream_firefox.active = False |
161 | 241 | >>> flush_database_updates() | 241 | >>> flush_database_updates() |
163 | 242 | >>> for spec in specset.specifications(filter=['install']): | 242 | >>> for spec in specset.specifications(None, filter=['install']): |
164 | 243 | ... print spec.name, spec.target.name | 243 | ... print spec.name, spec.target.name |
165 | 244 | cluster-installation kubuntu | 244 | cluster-installation kubuntu |
166 | 245 | media-integrity-check ubuntu | 245 | media-integrity-check ubuntu |
167 | 246 | 246 | ||
168 | === modified file 'lib/lp/blueprints/doc/sprint.txt' | |||
169 | --- lib/lp/blueprints/doc/sprint.txt 2011-12-30 06:14:56 +0000 | |||
170 | +++ lib/lp/blueprints/doc/sprint.txt 2012-09-28 14:42:25 +0000 | |||
171 | @@ -118,19 +118,19 @@ | |||
172 | 118 | First, there should be no informational specs for ubz: | 118 | First, there should be no informational specs for ubz: |
173 | 119 | 119 | ||
174 | 120 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 120 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
176 | 121 | >>> ubz.specifications(filter=filter).count() | 121 | >>> ubz.specifications(None, filter=filter).count() |
177 | 122 | 1 | 122 | 1 |
178 | 123 | 123 | ||
179 | 124 | There are 0 completed specs for UBZ: | 124 | There are 0 completed specs for UBZ: |
180 | 125 | 125 | ||
181 | 126 | >>> filter = [SpecificationFilter.COMPLETE] | 126 | >>> filter = [SpecificationFilter.COMPLETE] |
183 | 127 | >>> ubz.specifications(filter=filter).count() | 127 | >>> ubz.specifications(None, filter=filter).count() |
184 | 128 | 0 | 128 | 0 |
185 | 129 | 129 | ||
186 | 130 | And there are three incomplete specs: | 130 | And there are three incomplete specs: |
187 | 131 | 131 | ||
188 | 132 | >>> filter = [SpecificationFilter.INCOMPLETE] | 132 | >>> filter = [SpecificationFilter.INCOMPLETE] |
190 | 133 | >>> for spec in ubz.specifications(filter=filter): | 133 | >>> for spec in ubz.specifications(None, filter=filter): |
191 | 134 | ... print spec.name, spec.is_complete | 134 | ... print spec.name, spec.is_complete |
192 | 135 | svg-support False | 135 | svg-support False |
193 | 136 | extension-manager-upgrades False | 136 | extension-manager-upgrades False |
194 | @@ -139,7 +139,7 @@ | |||
195 | 139 | If we ask for all specs, we get them in the order of priority. | 139 | If we ask for all specs, we get them in the order of priority. |
196 | 140 | 140 | ||
197 | 141 | >>> filter = [SpecificationFilter.ALL] | 141 | >>> filter = [SpecificationFilter.ALL] |
199 | 142 | >>> for spec in ubz.specifications(filter=filter): | 142 | >>> for spec in ubz.specifications(None, filter=filter): |
200 | 143 | ... print spec.priority.title, spec.name | 143 | ... print spec.priority.title, spec.name |
201 | 144 | High svg-support | 144 | High svg-support |
202 | 145 | Medium extension-manager-upgrades | 145 | Medium extension-manager-upgrades |
203 | @@ -147,7 +147,7 @@ | |||
204 | 147 | 147 | ||
205 | 148 | And if we ask just for specs, we get them all | 148 | And if we ask just for specs, we get them all |
206 | 149 | 149 | ||
208 | 150 | >>> for spec in ubz.specifications(): | 150 | >>> for spec in ubz.specifications(None): |
209 | 151 | ... print spec.name, spec.is_complete | 151 | ... print spec.name, spec.is_complete |
210 | 152 | svg-support False | 152 | svg-support False |
211 | 153 | extension-manager-upgrades False | 153 | extension-manager-upgrades False |
212 | @@ -167,7 +167,7 @@ | |||
213 | 167 | >>> unlink_source_packages(firefox) | 167 | >>> unlink_source_packages(firefox) |
214 | 168 | >>> firefox.active = False | 168 | >>> firefox.active = False |
215 | 169 | >>> flush_database_updates() | 169 | >>> flush_database_updates() |
217 | 170 | >>> ubz.specifications().count() | 170 | >>> ubz.specifications(None).count() |
218 | 171 | 0 | 171 | 0 |
219 | 172 | 172 | ||
220 | 173 | Reset firefox so we don't mess up later tests. | 173 | Reset firefox so we don't mess up later tests. |
221 | 174 | 174 | ||
222 | === modified file 'lib/lp/blueprints/interfaces/specification.py' | |||
223 | --- lib/lp/blueprints/interfaces/specification.py 2012-09-28 14:42:25 +0000 | |||
224 | +++ lib/lp/blueprints/interfaces/specification.py 2012-09-28 14:42:25 +0000 | |||
225 | @@ -674,7 +674,7 @@ | |||
226 | 674 | 674 | ||
227 | 675 | coming_sprints = Attribute("The next 5 sprints in the system.") | 675 | coming_sprints = Attribute("The next 5 sprints in the system.") |
228 | 676 | 676 | ||
230 | 677 | def specificationCount(): | 677 | def specificationCount(user): |
231 | 678 | """The total number of blueprints in Launchpad""" | 678 | """The total number of blueprints in Launchpad""" |
232 | 679 | 679 | ||
233 | 680 | def getStatusCountsForProductSeries(product_series): | 680 | def getStatusCountsForProductSeries(product_series): |
234 | 681 | 681 | ||
235 | === modified file 'lib/lp/blueprints/interfaces/specificationtarget.py' | |||
236 | --- lib/lp/blueprints/interfaces/specificationtarget.py 2012-09-28 14:42:25 +0000 | |||
237 | +++ lib/lp/blueprints/interfaces/specificationtarget.py 2012-09-28 14:42:25 +0000 | |||
238 | @@ -60,10 +60,11 @@ | |||
239 | 60 | 'have not been accepted for that goal'))), | 60 | 'have not been accepted for that goal'))), |
240 | 61 | exported_as="valid_specifications", as_of="devel") | 61 | exported_as="valid_specifications", as_of="devel") |
241 | 62 | 62 | ||
243 | 63 | def specifications(quantity=None, sort=None, filter=None, | 63 | def specifications(user, quantity=None, sort=None, filter=None, |
244 | 64 | prejoin_people=True): | 64 | prejoin_people=True): |
245 | 65 | """Specifications for this target. | 65 | """Specifications for this target. |
246 | 66 | 66 | ||
247 | 67 | The user specifies which user to use for calculation of visibility. | ||
248 | 67 | The sort is a dbschema which indicates the preferred sort order. The | 68 | The sort is a dbschema which indicates the preferred sort order. The |
249 | 68 | filter is an indicator of the kinds of specs to be returned, and | 69 | filter is an indicator of the kinds of specs to be returned, and |
250 | 69 | appropriate filters depend on the kind of object this method is on. | 70 | appropriate filters depend on the kind of object this method is on. |
251 | 70 | 71 | ||
252 | === modified file 'lib/lp/blueprints/model/specification.py' | |||
253 | --- lib/lp/blueprints/model/specification.py 2012-09-28 14:42:25 +0000 | |||
254 | +++ lib/lp/blueprints/model/specification.py 2012-09-28 14:42:25 +0000 | |||
255 | @@ -109,6 +109,7 @@ | |||
256 | 109 | cachedproperty, | 109 | cachedproperty, |
257 | 110 | get_property_cache, | 110 | get_property_cache, |
258 | 111 | ) | 111 | ) |
259 | 112 | from lp.services.webapp.interfaces import ILaunchBag | ||
260 | 112 | 113 | ||
261 | 113 | 114 | ||
262 | 114 | def recursive_blocked_query(spec): | 115 | def recursive_blocked_query(spec): |
263 | @@ -957,7 +958,7 @@ | |||
264 | 957 | for other classes that have specifications. | 958 | for other classes that have specifications. |
265 | 958 | """ | 959 | """ |
266 | 959 | 960 | ||
268 | 960 | def specifications(self, sort=None, quantity=None, filter=None, | 961 | def specifications(self, user, sort=None, quantity=None, filter=None, |
269 | 961 | prejoin_people=True): | 962 | prejoin_people=True): |
270 | 962 | """See IHasSpecifications.""" | 963 | """See IHasSpecifications.""" |
271 | 963 | # this should be implemented by the actual context class | 964 | # this should be implemented by the actual context class |
272 | @@ -1024,16 +1025,19 @@ | |||
273 | 1024 | @property | 1025 | @property |
274 | 1025 | def _all_specifications(self): | 1026 | def _all_specifications(self): |
275 | 1026 | """See IHasSpecifications.""" | 1027 | """See IHasSpecifications.""" |
277 | 1027 | return self.specifications(filter=[SpecificationFilter.ALL]) | 1028 | user = getUtility(ILaunchBag).user |
278 | 1029 | return self.specifications(user, filter=[SpecificationFilter.ALL]) | ||
279 | 1028 | 1030 | ||
280 | 1029 | @property | 1031 | @property |
281 | 1030 | def _valid_specifications(self): | 1032 | def _valid_specifications(self): |
282 | 1031 | """See IHasSpecifications.""" | 1033 | """See IHasSpecifications.""" |
284 | 1032 | return self.specifications(filter=[SpecificationFilter.VALID]) | 1034 | user = getUtility(ILaunchBag).user |
285 | 1035 | return self.specifications(user, filter=[SpecificationFilter.VALID]) | ||
286 | 1033 | 1036 | ||
288 | 1034 | def specificationCount(self): | 1037 | def specificationCount(self, user): |
289 | 1035 | """See IHasSpecifications.""" | 1038 | """See IHasSpecifications.""" |
291 | 1036 | return self.specifications(filter=[SpecificationFilter.ALL]).count() | 1039 | return self.specifications(user, |
292 | 1040 | filter=[SpecificationFilter.ALL]).count() | ||
293 | 1037 | 1041 | ||
294 | 1038 | 1042 | ||
295 | 1039 | class SpecificationSet(HasSpecificationsMixin): | 1043 | class SpecificationSet(HasSpecificationsMixin): |
296 | @@ -1072,7 +1076,7 @@ | |||
297 | 1072 | """See ISpecificationSet.""" | 1076 | """See ISpecificationSet.""" |
298 | 1073 | return iter(self.all_specifications) | 1077 | return iter(self.all_specifications) |
299 | 1074 | 1078 | ||
301 | 1075 | def specifications(self, sort=None, quantity=None, filter=None, | 1079 | def specifications(self, user, sort=None, quantity=None, filter=None, |
302 | 1076 | prejoin_people=True): | 1080 | prejoin_people=True): |
303 | 1077 | """See IHasSpecifications.""" | 1081 | """See IHasSpecifications.""" |
304 | 1078 | 1082 | ||
305 | 1079 | 1083 | ||
306 | === modified file 'lib/lp/blueprints/model/sprint.py' | |||
307 | --- lib/lp/blueprints/model/sprint.py 2012-09-28 14:42:25 +0000 | |||
308 | +++ lib/lp/blueprints/model/sprint.py 2012-09-28 14:42:25 +0000 | |||
309 | @@ -41,7 +41,10 @@ | |||
310 | 41 | ISprint, | 41 | ISprint, |
311 | 42 | ISprintSet, | 42 | ISprintSet, |
312 | 43 | ) | 43 | ) |
314 | 44 | from lp.blueprints.model.specification import HasSpecificationsMixin | 44 | from lp.blueprints.model.specification import ( |
315 | 45 | get_specification_privacy_filter, | ||
316 | 46 | HasSpecificationsMixin, | ||
317 | 47 | ) | ||
318 | 45 | from lp.blueprints.model.sprintattendance import SprintAttendance | 48 | from lp.blueprints.model.sprintattendance import SprintAttendance |
319 | 46 | from lp.blueprints.model.sprintspecification import SprintSpecification | 49 | from lp.blueprints.model.sprintspecification import SprintSpecification |
320 | 47 | from lp.registry.interfaces.person import ( | 50 | from lp.registry.interfaces.person import ( |
321 | @@ -111,7 +114,7 @@ | |||
322 | 111 | # Only really used in tests. | 114 | # Only really used in tests. |
323 | 112 | return [a.attendee for a in self.attendances] | 115 | return [a.attendee for a in self.attendances] |
324 | 113 | 116 | ||
326 | 114 | def spec_filter_clause(self, filter=None): | 117 | def spec_filter_clause(self, user, filter=None): |
327 | 115 | """Figure out the appropriate query for specifications on a sprint. | 118 | """Figure out the appropriate query for specifications on a sprint. |
328 | 116 | 119 | ||
329 | 117 | We separate out the query generation from the normal | 120 | We separate out the query generation from the normal |
330 | @@ -126,6 +129,7 @@ | |||
331 | 126 | Or(Specification.product == None, | 129 | Or(Specification.product == None, |
332 | 127 | Not(Specification.productID.is_in(Select(Product.id, | 130 | Not(Specification.productID.is_in(Select(Product.id, |
333 | 128 | Product.active == False))))] | 131 | Product.active == False))))] |
334 | 132 | query.append(get_specification_privacy_filter(user)) | ||
335 | 129 | if not filter: | 133 | if not filter: |
336 | 130 | # filter could be None or [] then we decide the default | 134 | # filter could be None or [] then we decide the default |
337 | 131 | # which for a sprint is to show everything approved | 135 | # which for a sprint is to show everything approved |
338 | @@ -169,7 +173,10 @@ | |||
339 | 169 | query.append(fti_search(Specification, constraint)) | 173 | query.append(fti_search(Specification, constraint)) |
340 | 170 | return query | 174 | return query |
341 | 171 | 175 | ||
343 | 172 | def specifications(self, sort=None, quantity=None, filter=None, | 176 | def all_specifications(self, user): |
344 | 177 | return self.specifications(user, filter=[SpecificationFilter.ALL]) | ||
345 | 178 | |||
346 | 179 | def specifications(self, user, sort=None, quantity=None, filter=None, | ||
347 | 173 | prejoin_people=False): | 180 | prejoin_people=False): |
348 | 174 | """See IHasSpecifications.""" | 181 | """See IHasSpecifications.""" |
349 | 175 | # prejoin_people is provided only for interface compatibility and | 182 | # prejoin_people is provided only for interface compatibility and |
350 | @@ -177,7 +184,7 @@ | |||
351 | 177 | assert not prejoin_people | 184 | assert not prejoin_people |
352 | 178 | if filter is None: | 185 | if filter is None: |
353 | 179 | filter = set([SpecificationFilter.ACCEPTED]) | 186 | filter = set([SpecificationFilter.ACCEPTED]) |
355 | 180 | query = self.spec_filter_clause(filter=filter) | 187 | query = self.spec_filter_clause(user, filter=filter) |
356 | 181 | # import here to avoid circular deps | 188 | # import here to avoid circular deps |
357 | 182 | from lp.blueprints.model.specification import Specification | 189 | from lp.blueprints.model.specification import Specification |
358 | 183 | results = Store.of(self).find(Specification, *query) | 190 | results = Store.of(self).find(Specification, *query) |
359 | @@ -200,7 +207,7 @@ | |||
360 | 200 | 207 | ||
361 | 201 | def specificationLinks(self, filter=None): | 208 | def specificationLinks(self, filter=None): |
362 | 202 | """See `ISprint`.""" | 209 | """See `ISprint`.""" |
364 | 203 | query = self.spec_filter_clause(filter=filter) | 210 | query = self.spec_filter_clause(None, filter=filter) |
365 | 204 | result = Store.of(self).find(SprintSpecification, *query) | 211 | result = Store.of(self).find(SprintSpecification, *query) |
366 | 205 | return result | 212 | return result |
367 | 206 | 213 | ||
368 | @@ -227,7 +234,7 @@ | |||
369 | 227 | # queue | 234 | # queue |
370 | 228 | flush_database_updates() | 235 | flush_database_updates() |
371 | 229 | 236 | ||
373 | 230 | return self.specifications( | 237 | return self.specifications(decider, |
374 | 231 | filter=[SpecificationFilter.PROPOSED]).count() | 238 | filter=[SpecificationFilter.PROPOSED]).count() |
375 | 232 | 239 | ||
376 | 233 | def declineSpecificationLinks(self, idlist, decider): | 240 | def declineSpecificationLinks(self, idlist, decider): |
377 | @@ -241,7 +248,7 @@ | |||
378 | 241 | # queue | 248 | # queue |
379 | 242 | flush_database_updates() | 249 | flush_database_updates() |
380 | 243 | 250 | ||
382 | 244 | return self.specifications( | 251 | return self.specifications(decider, |
383 | 245 | filter=[SpecificationFilter.PROPOSED]).count() | 252 | filter=[SpecificationFilter.PROPOSED]).count() |
384 | 246 | 253 | ||
385 | 247 | # attendance | 254 | # attendance |
386 | 248 | 255 | ||
387 | === modified file 'lib/lp/blueprints/model/tests/test_sprint.py' | |||
388 | --- lib/lp/blueprints/model/tests/test_sprint.py 2012-09-28 14:42:25 +0000 | |||
389 | +++ lib/lp/blueprints/model/tests/test_sprint.py 2012-09-28 14:42:25 +0000 | |||
390 | @@ -9,8 +9,10 @@ | |||
391 | 9 | import datetime | 9 | import datetime |
392 | 10 | 10 | ||
393 | 11 | from pytz import utc | 11 | from pytz import utc |
394 | 12 | from zope.component import getUtility | ||
395 | 12 | from zope.security.proxy import removeSecurityProxy | 13 | from zope.security.proxy import removeSecurityProxy |
396 | 13 | 14 | ||
397 | 15 | from lp.app.enums import InformationType | ||
398 | 14 | from lp.blueprints.enums import ( | 16 | from lp.blueprints.enums import ( |
399 | 15 | NewSpecificationDefinitionStatus, | 17 | NewSpecificationDefinitionStatus, |
400 | 16 | SpecificationDefinitionStatus, | 18 | SpecificationDefinitionStatus, |
401 | @@ -18,12 +20,13 @@ | |||
402 | 18 | SpecificationPriority, | 20 | SpecificationPriority, |
403 | 19 | SpecificationSort, | 21 | SpecificationSort, |
404 | 20 | ) | 22 | ) |
405 | 23 | from lp.registry.interfaces.accesspolicy import IAccessPolicySource | ||
406 | 21 | from lp.testing import TestCaseWithFactory | 24 | from lp.testing import TestCaseWithFactory |
407 | 22 | from lp.testing.layers import DatabaseFunctionalLayer | 25 | from lp.testing.layers import DatabaseFunctionalLayer |
408 | 23 | 26 | ||
409 | 24 | 27 | ||
412 | 25 | def list_result(sprint, filter=None): | 28 | def list_result(sprint, filter=None, user=None): |
413 | 26 | result = sprint.specifications(SpecificationSort.DATE, filter=filter) | 29 | result = sprint.specifications(user, SpecificationSort.DATE, filter=filter) |
414 | 27 | return list(result) | 30 | return list(result) |
415 | 28 | 31 | ||
416 | 29 | 32 | ||
417 | @@ -38,11 +41,12 @@ | |||
418 | 38 | def makeSpec(self, sprint=None, date_decided=0, date_created=0, | 41 | def makeSpec(self, sprint=None, date_decided=0, date_created=0, |
419 | 39 | proposed=False, declined=False, title=None, | 42 | proposed=False, declined=False, title=None, |
420 | 40 | status=NewSpecificationDefinitionStatus.NEW, | 43 | status=NewSpecificationDefinitionStatus.NEW, |
422 | 41 | name=None, priority=None): | 44 | name=None, priority=None, information_type=None): |
423 | 42 | if sprint is None: | 45 | if sprint is None: |
424 | 43 | sprint = self.factory.makeSprint() | 46 | sprint = self.factory.makeSprint() |
425 | 44 | blueprint = self.factory.makeSpecification( | 47 | blueprint = self.factory.makeSpecification( |
427 | 45 | title=title, status=status, name=name, priority=priority) | 48 | title=title, status=status, name=name, priority=priority, |
428 | 49 | information_type=information_type) | ||
429 | 46 | link = blueprint.linkSprint(sprint, blueprint.owner) | 50 | link = blueprint.linkSprint(sprint, blueprint.owner) |
430 | 47 | naked_link = removeSecurityProxy(link) | 51 | naked_link = removeSecurityProxy(link) |
431 | 48 | if declined: | 52 | if declined: |
432 | @@ -61,10 +65,11 @@ | |||
433 | 61 | sprint = self.factory.makeSprint() | 65 | sprint = self.factory.makeSprint() |
434 | 62 | for count in range(10): | 66 | for count in range(10): |
435 | 63 | self.makeSpec(sprint) | 67 | self.makeSpec(sprint) |
440 | 64 | self.assertEqual(10, sprint.specifications().count()) | 68 | self.assertEqual(10, sprint.specifications(None).count()) |
441 | 65 | self.assertEqual(10, sprint.specifications(quantity=None).count()) | 69 | result = sprint.specifications(None, quantity=None).count() |
442 | 66 | self.assertEqual(8, sprint.specifications(quantity=8).count()) | 70 | self.assertEqual(10, result) |
443 | 67 | self.assertEqual(10, sprint.specifications(quantity=11).count()) | 71 | self.assertEqual(8, sprint.specifications(None, quantity=8).count()) |
444 | 72 | self.assertEqual(10, sprint.specifications(None, quantity=11).count()) | ||
445 | 68 | 73 | ||
446 | 69 | def test_specifications_date_sort_accepted_decided(self): | 74 | def test_specifications_date_sort_accepted_decided(self): |
447 | 70 | # If only accepted proposals are requested, date-sorting uses | 75 | # If only accepted proposals are requested, date-sorting uses |
448 | @@ -133,9 +138,9 @@ | |||
449 | 133 | blueprint3 = self.makeSpec( | 138 | blueprint3 = self.makeSpec( |
450 | 134 | sprint, priority=SpecificationPriority.LOW, | 139 | sprint, priority=SpecificationPriority.LOW, |
451 | 135 | status=SpecificationDefinitionStatus.OBSOLETE) | 140 | status=SpecificationDefinitionStatus.OBSOLETE) |
453 | 136 | result = sprint.specifications() | 141 | result = sprint.specifications(None) |
454 | 137 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) | 142 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) |
456 | 138 | result = sprint.specifications(sort=SpecificationSort.PRIORITY) | 143 | result = sprint.specifications(None, sort=SpecificationSort.PRIORITY) |
457 | 139 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) | 144 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) |
458 | 140 | 145 | ||
459 | 141 | def test_priority_sort_fallback_status(self): | 146 | def test_priority_sort_fallback_status(self): |
460 | @@ -148,9 +153,9 @@ | |||
461 | 148 | sprint, status=SpecificationDefinitionStatus.APPROVED, name='c') | 153 | sprint, status=SpecificationDefinitionStatus.APPROVED, name='c') |
462 | 149 | blueprint3 = self.makeSpec( | 154 | blueprint3 = self.makeSpec( |
463 | 150 | sprint, status=SpecificationDefinitionStatus.NEW, name='b') | 155 | sprint, status=SpecificationDefinitionStatus.NEW, name='b') |
465 | 151 | result = sprint.specifications() | 156 | result = sprint.specifications(None) |
466 | 152 | self.assertEqual([blueprint2, blueprint3, blueprint1], list(result)) | 157 | self.assertEqual([blueprint2, blueprint3, blueprint1], list(result)) |
468 | 153 | result = sprint.specifications(sort=SpecificationSort.PRIORITY) | 158 | result = sprint.specifications(None, sort=SpecificationSort.PRIORITY) |
469 | 154 | self.assertEqual([blueprint2, blueprint3, blueprint1], list(result)) | 159 | self.assertEqual([blueprint2, blueprint3, blueprint1], list(result)) |
470 | 155 | 160 | ||
471 | 156 | def test_priority_sort_fallback_name(self): | 161 | def test_priority_sort_fallback_name(self): |
472 | @@ -159,9 +164,9 @@ | |||
473 | 159 | sprint = blueprint1.sprints[0] | 164 | sprint = blueprint1.sprints[0] |
474 | 160 | blueprint2 = self.makeSpec(sprint, name='c') | 165 | blueprint2 = self.makeSpec(sprint, name='c') |
475 | 161 | blueprint3 = self.makeSpec(sprint, name='a') | 166 | blueprint3 = self.makeSpec(sprint, name='a') |
477 | 162 | result = sprint.specifications() | 167 | result = sprint.specifications(None) |
478 | 163 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) | 168 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) |
480 | 164 | result = sprint.specifications(sort=SpecificationSort.PRIORITY) | 169 | result = sprint.specifications(None, sort=SpecificationSort.PRIORITY) |
481 | 165 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) | 170 | self.assertEqual([blueprint3, blueprint1, blueprint2], list(result)) |
482 | 166 | 171 | ||
483 | 167 | def test_text_search(self): | 172 | def test_text_search(self): |
484 | @@ -182,6 +187,34 @@ | |||
485 | 182 | result = list_result(sprint, [SpecificationFilter.DECLINED]) | 187 | result = list_result(sprint, [SpecificationFilter.DECLINED]) |
486 | 183 | self.assertEqual([blueprint2], result) | 188 | self.assertEqual([blueprint2], result) |
487 | 184 | 189 | ||
488 | 190 | def test_proprietary_not_listed(self): | ||
489 | 191 | # Proprietary blueprints are not listed for random users | ||
490 | 192 | blueprint1 = self.makeSpec( | ||
491 | 193 | information_type=InformationType.PROPRIETARY) | ||
492 | 194 | self.assertEqual([], list_result(blueprint1.sprints[0])) | ||
493 | 195 | |||
494 | 196 | def test_proprietary_listed_for_artifact_grant(self): | ||
495 | 197 | # Proprietary blueprints are listed for users with an artifact grant. | ||
496 | 198 | blueprint1 = self.makeSpec( | ||
497 | 199 | information_type=InformationType.PROPRIETARY) | ||
498 | 200 | grant = self.factory.makeAccessArtifactGrant( | ||
499 | 201 | concrete_artifact=blueprint1) | ||
500 | 202 | self.assertEqual( | ||
501 | 203 | [blueprint1], | ||
502 | 204 | list_result(blueprint1.sprints[0], user=grant.grantee)) | ||
503 | 205 | |||
504 | 206 | def test_proprietary_listed_for_policy_grant(self): | ||
505 | 207 | # Proprietary blueprints are listed for users with a policy grant. | ||
506 | 208 | blueprint1 = self.makeSpec( | ||
507 | 209 | information_type=InformationType.PROPRIETARY) | ||
508 | 210 | policy_source = getUtility(IAccessPolicySource) | ||
509 | 211 | (policy,) = policy_source.find( | ||
510 | 212 | [(blueprint1.product, InformationType.PROPRIETARY)]) | ||
511 | 213 | grant = self.factory.makeAccessPolicyGrant(policy) | ||
512 | 214 | self.assertEqual( | ||
513 | 215 | [blueprint1], | ||
514 | 216 | list_result(blueprint1.sprints[0], user=grant.grantee)) | ||
515 | 217 | |||
516 | 185 | 218 | ||
517 | 186 | class TestSprintAttendancesSort(TestCaseWithFactory): | 219 | class TestSprintAttendancesSort(TestCaseWithFactory): |
518 | 187 | 220 | ||
519 | 188 | 221 | ||
520 | === modified file 'lib/lp/blueprints/templates/person-specworkload.pt' | |||
521 | --- lib/lp/blueprints/templates/person-specworkload.pt 2011-12-08 22:41:00 +0000 | |||
522 | +++ lib/lp/blueprints/templates/person-specworkload.pt 2012-09-28 14:42:25 +0000 | |||
523 | @@ -44,7 +44,7 @@ | |||
524 | 44 | 44 | ||
525 | 45 | <tal:participants repeat="member members_batch"> | 45 | <tal:participants repeat="member members_batch"> |
526 | 46 | 46 | ||
528 | 47 | <tal:specs define="specifications member/specifications"> | 47 | <tal:specs define="specifications member/@@+specworkload/specifications"> |
529 | 48 | 48 | ||
530 | 49 | <div style="margin-bottom: 1em;" tal:condition="specifications"> | 49 | <div style="margin-bottom: 1em;" tal:condition="specifications"> |
531 | 50 | <p> | 50 | <p> |
532 | 51 | 51 | ||
533 | === modified file 'lib/lp/blueprints/vocabularies/specification.py' | |||
534 | --- lib/lp/blueprints/vocabularies/specification.py 2012-01-01 02:58:52 +0000 | |||
535 | +++ lib/lp/blueprints/vocabularies/specification.py 2012-09-28 14:42:25 +0000 | |||
536 | @@ -39,7 +39,8 @@ | |||
537 | 39 | 39 | ||
538 | 40 | if target is not None: | 40 | if target is not None: |
539 | 41 | for spec in sorted( | 41 | for spec in sorted( |
541 | 42 | target.specifications(), key=attrgetter('title')): | 42 | target.specifications(launchbag.user), |
542 | 43 | key=attrgetter('title')): | ||
543 | 43 | # we will not show the current specification in the | 44 | # we will not show the current specification in the |
544 | 44 | # launchbag | 45 | # launchbag |
545 | 45 | if spec == launchbag.specification: | 46 | if spec == launchbag.specification: |
546 | 46 | 47 | ||
547 | === modified file 'lib/lp/registry/browser/person.py' | |||
548 | --- lib/lp/registry/browser/person.py 2012-09-11 13:25:48 +0000 | |||
549 | +++ lib/lp/registry/browser/person.py 2012-09-28 14:42:25 +0000 | |||
550 | @@ -1303,6 +1303,9 @@ | |||
551 | 1303 | batch_nav = BatchNavigator(members, self.request, size=20) | 1303 | batch_nav = BatchNavigator(members, self.request, size=20) |
552 | 1304 | return batch_nav | 1304 | return batch_nav |
553 | 1305 | 1305 | ||
554 | 1306 | def specifications(self): | ||
555 | 1307 | return self.context.specifications(self.user) | ||
556 | 1308 | |||
557 | 1306 | 1309 | ||
558 | 1307 | class PersonSpecWorkloadTableView(LaunchpadView): | 1310 | class PersonSpecWorkloadTableView(LaunchpadView): |
559 | 1308 | """View to render the specification workload table for a person. | 1311 | """View to render the specification workload table for a person. |
560 | @@ -1331,7 +1334,7 @@ | |||
561 | 1331 | approver, the assignee or the drafter. | 1334 | approver, the assignee or the drafter. |
562 | 1332 | """ | 1335 | """ |
563 | 1333 | return [PersonSpecWorkloadTableView.PersonSpec(spec, self.context) | 1336 | return [PersonSpecWorkloadTableView.PersonSpec(spec, self.context) |
565 | 1334 | for spec in self.context.specifications()] | 1337 | for spec in self.context.specifications(self.user)] |
566 | 1335 | 1338 | ||
567 | 1336 | 1339 | ||
568 | 1337 | class PersonVouchersView(LaunchpadFormView): | 1340 | class PersonVouchersView(LaunchpadFormView): |
569 | @@ -3573,7 +3576,7 @@ | |||
570 | 3573 | else: | 3576 | else: |
571 | 3574 | project['bug_count'] = pillar.searchTasks( | 3577 | project['bug_count'] = pillar.searchTasks( |
572 | 3575 | BugTaskSet().open_bugtask_search).count() | 3578 | BugTaskSet().open_bugtask_search).count() |
574 | 3576 | project['spec_count'] = pillar.specifications().count() | 3579 | project['spec_count'] = pillar.specifications(user).count() |
575 | 3577 | project['question_count'] = pillar.searchQuestions().count() | 3580 | project['question_count'] = pillar.searchQuestions().count() |
576 | 3578 | projects.append(project) | 3581 | projects.append(project) |
577 | 3579 | return projects | 3582 | return projects |
578 | 3580 | 3583 | ||
579 | === modified file 'lib/lp/registry/doc/distribution.txt' | |||
580 | --- lib/lp/registry/doc/distribution.txt 2012-09-28 14:42:25 +0000 | |||
581 | +++ lib/lp/registry/doc/distribution.txt 2012-09-28 14:42:25 +0000 | |||
582 | @@ -490,18 +490,18 @@ | |||
583 | 490 | complete so it will not show up unless we explicitly ask for complete specs: | 490 | complete so it will not show up unless we explicitly ask for complete specs: |
584 | 491 | 491 | ||
585 | 492 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 492 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
587 | 493 | >>> kubuntu.specifications(filter=filter).count() | 493 | >>> kubuntu.specifications(None, filter=filter).count() |
588 | 494 | 0 | 494 | 0 |
589 | 495 | >>> filter = [SpecificationFilter.INFORMATIONAL, | 495 | >>> filter = [SpecificationFilter.INFORMATIONAL, |
590 | 496 | ... SpecificationFilter.COMPLETE] | 496 | ... SpecificationFilter.COMPLETE] |
592 | 497 | >>> kubuntu.specifications(filter=filter).count() | 497 | >>> kubuntu.specifications(None, filter=filter).count() |
593 | 498 | 1 | 498 | 1 |
594 | 499 | 499 | ||
595 | 500 | 500 | ||
596 | 501 | There are 2 completed specs for Kubuntu: | 501 | There are 2 completed specs for Kubuntu: |
597 | 502 | 502 | ||
598 | 503 | >>> filter = [SpecificationFilter.COMPLETE] | 503 | >>> filter = [SpecificationFilter.COMPLETE] |
600 | 504 | >>> for spec in kubuntu.specifications(filter=filter): | 504 | >>> for spec in kubuntu.specifications(None, filter=filter): |
601 | 505 | ... print spec.name, spec.is_complete | 505 | ... print spec.name, spec.is_complete |
602 | 506 | thinclient-local-devices True | 506 | thinclient-local-devices True |
603 | 507 | usplash-on-hibernation True | 507 | usplash-on-hibernation True |
604 | @@ -510,7 +510,7 @@ | |||
605 | 510 | And there are four incomplete specs: | 510 | And there are four incomplete specs: |
606 | 511 | 511 | ||
607 | 512 | >>> filter = [SpecificationFilter.INCOMPLETE] | 512 | >>> filter = [SpecificationFilter.INCOMPLETE] |
609 | 513 | >>> for spec in kubuntu.specifications(filter=filter): | 513 | >>> for spec in kubuntu.specifications(None, filter=filter): |
610 | 514 | ... print spec.name, spec.is_complete | 514 | ... print spec.name, spec.is_complete |
611 | 515 | cluster-installation False | 515 | cluster-installation False |
612 | 516 | revu False | 516 | revu False |
613 | @@ -521,7 +521,7 @@ | |||
614 | 521 | If we ask for all specs, we get them in the order of priority. | 521 | If we ask for all specs, we get them in the order of priority. |
615 | 522 | 522 | ||
616 | 523 | >>> filter = [SpecificationFilter.ALL] | 523 | >>> filter = [SpecificationFilter.ALL] |
618 | 524 | >>> for spec in kubuntu.specifications(filter=filter): | 524 | >>> for spec in kubuntu.specifications(None, filter=filter): |
619 | 525 | ... print spec.priority.title, spec.name | 525 | ... print spec.priority.title, spec.name |
620 | 526 | Essential cluster-installation | 526 | Essential cluster-installation |
621 | 527 | High revu | 527 | High revu |
622 | @@ -533,7 +533,7 @@ | |||
623 | 533 | 533 | ||
624 | 534 | And if we ask just for specs, we get the incomplete ones. | 534 | And if we ask just for specs, we get the incomplete ones. |
625 | 535 | 535 | ||
627 | 536 | >>> for spec in kubuntu.specifications(): | 536 | >>> for spec in kubuntu.specifications(None): |
628 | 537 | ... print spec.name, spec.is_complete | 537 | ... print spec.name, spec.is_complete |
629 | 538 | cluster-installation False | 538 | cluster-installation False |
630 | 539 | revu False | 539 | revu False |
631 | @@ -542,7 +542,7 @@ | |||
632 | 542 | 542 | ||
633 | 543 | We can filter for specifications that contain specific text: | 543 | We can filter for specifications that contain specific text: |
634 | 544 | 544 | ||
636 | 545 | >>> for spec in kubuntu.specifications(filter=['package']): | 545 | >>> for spec in kubuntu.specifications(None, filter=['package']): |
637 | 546 | ... print spec.name | 546 | ... print spec.name |
638 | 547 | revu | 547 | revu |
639 | 548 | 548 | ||
640 | @@ -550,7 +550,7 @@ | |||
641 | 550 | 550 | ||
642 | 551 | >>> from lp.blueprints.enums import SpecificationDefinitionStatus | 551 | >>> from lp.blueprints.enums import SpecificationDefinitionStatus |
643 | 552 | >>> login('mark@example.com') | 552 | >>> login('mark@example.com') |
645 | 553 | >>> for spec in kubuntu.specifications(): | 553 | >>> for spec in kubuntu.specifications(None): |
646 | 554 | ... # Do this here, otherwise, the change will be flush before | 554 | ... # Do this here, otherwise, the change will be flush before |
647 | 555 | ... # updateLifecycleStatus() acts and an IntegrityError will be | 555 | ... # updateLifecycleStatus() acts and an IntegrityError will be |
648 | 556 | ... # raised. | 556 | ... # raised. |
649 | 557 | 557 | ||
650 | === modified file 'lib/lp/registry/doc/distroseries.txt' | |||
651 | --- lib/lp/registry/doc/distroseries.txt 2012-09-27 02:53:00 +0000 | |||
652 | +++ lib/lp/registry/doc/distroseries.txt 2012-09-28 14:42:25 +0000 | |||
653 | @@ -850,14 +850,14 @@ | |||
654 | 850 | First, there should be one informational specs for krunch: | 850 | First, there should be one informational specs for krunch: |
655 | 851 | 851 | ||
656 | 852 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 852 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
658 | 853 | >>> krunch.specifications(filter=filter).count() | 853 | >>> krunch.specifications(None, filter=filter).count() |
659 | 854 | 1 | 854 | 1 |
660 | 855 | 855 | ||
661 | 856 | 856 | ||
662 | 857 | There are 2 completed specs for Krunch: | 857 | There are 2 completed specs for Krunch: |
663 | 858 | 858 | ||
664 | 859 | >>> filter = [SpecificationFilter.COMPLETE] | 859 | >>> filter = [SpecificationFilter.COMPLETE] |
666 | 860 | >>> for spec in kubuntu.specifications(filter=filter): | 860 | >>> for spec in kubuntu.specifications(None, filter=filter): |
667 | 861 | ... print spec.name, spec.is_complete | 861 | ... print spec.name, spec.is_complete |
668 | 862 | thinclient-local-devices True | 862 | thinclient-local-devices True |
669 | 863 | usplash-on-hibernation True | 863 | usplash-on-hibernation True |
670 | @@ -866,7 +866,7 @@ | |||
671 | 866 | And there are 2 incomplete specs: | 866 | And there are 2 incomplete specs: |
672 | 867 | 867 | ||
673 | 868 | >>> filter = [SpecificationFilter.INCOMPLETE] | 868 | >>> filter = [SpecificationFilter.INCOMPLETE] |
675 | 869 | >>> for spec in krunch.specifications(filter=filter): | 869 | >>> for spec in krunch.specifications(None, filter=filter): |
676 | 870 | ... print spec.name, spec.is_complete | 870 | ... print spec.name, spec.is_complete |
677 | 871 | cluster-installation False | 871 | cluster-installation False |
678 | 872 | revu False | 872 | revu False |
679 | @@ -875,7 +875,7 @@ | |||
680 | 875 | If we ask for all specs, we get them in the order of priority. | 875 | If we ask for all specs, we get them in the order of priority. |
681 | 876 | 876 | ||
682 | 877 | >>> filter = [SpecificationFilter.ALL] | 877 | >>> filter = [SpecificationFilter.ALL] |
684 | 878 | >>> for spec in krunch.specifications(filter=filter): | 878 | >>> for spec in krunch.specifications(None, filter=filter): |
685 | 879 | ... print spec.priority.title, spec.name | 879 | ... print spec.priority.title, spec.name |
686 | 880 | Essential cluster-installation | 880 | Essential cluster-installation |
687 | 881 | High revu | 881 | High revu |
688 | @@ -888,7 +888,7 @@ | |||
689 | 888 | With a distroseries, we can ask for ACCEPTED, PROPOSED and DECLINED specs: | 888 | With a distroseries, we can ask for ACCEPTED, PROPOSED and DECLINED specs: |
690 | 889 | 889 | ||
691 | 890 | >>> filter=[SpecificationFilter.ACCEPTED] | 890 | >>> filter=[SpecificationFilter.ACCEPTED] |
693 | 891 | >>> for spec in krunch.specifications(filter=filter): | 891 | >>> for spec in krunch.specifications(None, filter=filter): |
694 | 892 | ... print spec.name, spec.goalstatus.title | 892 | ... print spec.name, spec.goalstatus.title |
695 | 893 | cluster-installation Accepted | 893 | cluster-installation Accepted |
696 | 894 | revu Accepted | 894 | revu Accepted |
697 | @@ -896,12 +896,12 @@ | |||
698 | 896 | usplash-on-hibernation Accepted | 896 | usplash-on-hibernation Accepted |
699 | 897 | 897 | ||
700 | 898 | >>> filter=[SpecificationFilter.PROPOSED] | 898 | >>> filter=[SpecificationFilter.PROPOSED] |
702 | 899 | >>> for spec in krunch.specifications(filter=filter): | 899 | >>> for spec in krunch.specifications(None, filter=filter): |
703 | 900 | ... print spec.name, spec.goalstatus.title | 900 | ... print spec.name, spec.goalstatus.title |
704 | 901 | kde-desktopfile-langpacks Proposed | 901 | kde-desktopfile-langpacks Proposed |
705 | 902 | 902 | ||
706 | 903 | >>> filter=[SpecificationFilter.DECLINED] | 903 | >>> filter=[SpecificationFilter.DECLINED] |
708 | 904 | >>> for spec in krunch.specifications(filter=filter): | 904 | >>> for spec in krunch.specifications(None, filter=filter): |
709 | 905 | ... print spec.name, spec.goalstatus.title | 905 | ... print spec.name, spec.goalstatus.title |
710 | 906 | krunch-desktop-plan Declined | 906 | krunch-desktop-plan Declined |
711 | 907 | 907 | ||
712 | @@ -909,7 +909,7 @@ | |||
713 | 909 | And if we ask just for specs, we get BOTH the incomplete and the complete | 909 | And if we ask just for specs, we get BOTH the incomplete and the complete |
714 | 910 | ones that have been accepted. | 910 | ones that have been accepted. |
715 | 911 | 911 | ||
717 | 912 | >>> for spec in krunch.specifications(): | 912 | >>> for spec in krunch.specifications(None): |
718 | 913 | ... print spec.name, spec.is_complete, spec.goalstatus.title | 913 | ... print spec.name, spec.is_complete, spec.goalstatus.title |
719 | 914 | cluster-installation False Accepted | 914 | cluster-installation False Accepted |
720 | 915 | revu False Accepted | 915 | revu False Accepted |
721 | @@ -918,7 +918,7 @@ | |||
722 | 918 | 918 | ||
723 | 919 | We can filter for specifications that contain specific text: | 919 | We can filter for specifications that contain specific text: |
724 | 920 | 920 | ||
726 | 921 | >>> for spec in krunch.specifications(filter=['usb']): | 921 | >>> for spec in krunch.specifications(None, filter=['usb']): |
727 | 922 | ... print spec.name | 922 | ... print spec.name |
728 | 923 | thinclient-local-devices | 923 | thinclient-local-devices |
729 | 924 | 924 | ||
730 | 925 | 925 | ||
731 | === modified file 'lib/lp/registry/doc/person-account.txt' | |||
732 | --- lib/lp/registry/doc/person-account.txt 2012-09-07 18:06:37 +0000 | |||
733 | +++ lib/lp/registry/doc/person-account.txt 2012-09-28 14:42:25 +0000 | |||
734 | @@ -70,7 +70,7 @@ | |||
735 | 70 | >>> personset = getUtility(IPersonSet) | 70 | >>> personset = getUtility(IPersonSet) |
736 | 71 | >>> foobar_preferredemail = emailset.getByEmail('foo.bar@canonical.com') | 71 | >>> foobar_preferredemail = emailset.getByEmail('foo.bar@canonical.com') |
737 | 72 | >>> foobar = personset.get(foobar_preferredemail.personID) | 72 | >>> foobar = personset.get(foobar_preferredemail.personID) |
739 | 73 | >>> foobar.specifications().count() > 0 | 73 | >>> foobar.specifications(None).count() > 0 |
740 | 74 | True | 74 | True |
741 | 75 | 75 | ||
742 | 76 | >>> from lp.blueprints.model.specification import Specification | 76 | >>> from lp.blueprints.model.specification import Specification |
743 | 77 | 77 | ||
744 | === modified file 'lib/lp/registry/doc/person.txt' | |||
745 | --- lib/lp/registry/doc/person.txt 2012-09-26 07:45:31 +0000 | |||
746 | +++ lib/lp/registry/doc/person.txt 2012-09-28 14:42:25 +0000 | |||
747 | @@ -1146,7 +1146,7 @@ | |||
748 | 1146 | him: | 1146 | him: |
749 | 1147 | 1147 | ||
750 | 1148 | >>> from lp.blueprints.enums import SpecificationFilter | 1148 | >>> from lp.blueprints.enums import SpecificationFilter |
752 | 1149 | >>> carlos.specifications(filter=[ | 1149 | >>> carlos.specifications(None, filter=[ |
753 | 1150 | ... SpecificationFilter.ASSIGNEE, | 1150 | ... SpecificationFilter.ASSIGNEE, |
754 | 1151 | ... SpecificationFilter.COMPLETE]).count() | 1151 | ... SpecificationFilter.COMPLETE]).count() |
755 | 1152 | 0 | 1152 | 0 |
756 | @@ -1154,7 +1154,7 @@ | |||
757 | 1154 | Next, Carlos has two incomplete specs *related* to him: | 1154 | Next, Carlos has two incomplete specs *related* to him: |
758 | 1155 | 1155 | ||
759 | 1156 | >>> filter = [] | 1156 | >>> filter = [] |
761 | 1157 | >>> for spec in carlos.specifications(filter=filter): | 1157 | >>> for spec in carlos.specifications(None, filter=filter): |
762 | 1158 | ... print spec.name, spec.is_complete, spec.informational | 1158 | ... print spec.name, spec.is_complete, spec.informational |
763 | 1159 | svg-support False False | 1159 | svg-support False False |
764 | 1160 | extension-manager-upgrades False True | 1160 | extension-manager-upgrades False True |
765 | @@ -1177,39 +1177,39 @@ | |||
766 | 1177 | 1177 | ||
767 | 1178 | >>> mark = getUtility(IPersonSet).getByName('mark') | 1178 | >>> mark = getUtility(IPersonSet).getByName('mark') |
768 | 1179 | >>> filter = [SpecificationFilter.APPROVER] | 1179 | >>> filter = [SpecificationFilter.APPROVER] |
770 | 1180 | >>> for spec in mark.specifications(filter=filter): | 1180 | >>> for spec in mark.specifications(None, filter=filter): |
771 | 1181 | ... print spec.name | 1181 | ... print spec.name |
772 | 1182 | extension-manager-upgrades | 1182 | extension-manager-upgrades |
773 | 1183 | 1183 | ||
774 | 1184 | But has registered 5 of them: | 1184 | But has registered 5 of them: |
775 | 1185 | 1185 | ||
776 | 1186 | >>> filter = [SpecificationFilter.CREATOR] | 1186 | >>> filter = [SpecificationFilter.CREATOR] |
778 | 1187 | >>> print foobar.specifications(filter=filter).count() | 1187 | >>> print foobar.specifications(None, filter=filter).count() |
779 | 1188 | 5 | 1188 | 5 |
780 | 1189 | 1189 | ||
781 | 1190 | Now Celso, on the other hand, has 2 specs related to him: | 1190 | Now Celso, on the other hand, has 2 specs related to him: |
782 | 1191 | 1191 | ||
783 | 1192 | >>> cprov = personset.getByName('cprov') | 1192 | >>> cprov = personset.getByName('cprov') |
785 | 1193 | >>> cprov.specifications().count() | 1193 | >>> cprov.specifications(None).count() |
786 | 1194 | 2 | 1194 | 2 |
787 | 1195 | 1195 | ||
788 | 1196 | On one of those, he is the approver: | 1196 | On one of those, he is the approver: |
789 | 1197 | 1197 | ||
790 | 1198 | >>> filter = [SpecificationFilter.APPROVER] | 1198 | >>> filter = [SpecificationFilter.APPROVER] |
792 | 1199 | >>> for spec in cprov.specifications(filter=filter): | 1199 | >>> for spec in cprov.specifications(None, filter=filter): |
793 | 1200 | ... print spec.name | 1200 | ... print spec.name |
794 | 1201 | svg-support | 1201 | svg-support |
795 | 1202 | 1202 | ||
796 | 1203 | And on another one, he is the drafter | 1203 | And on another one, he is the drafter |
797 | 1204 | 1204 | ||
798 | 1205 | >>> filter = [SpecificationFilter.DRAFTER] | 1205 | >>> filter = [SpecificationFilter.DRAFTER] |
800 | 1206 | >>> for spec in cprov.specifications(filter=filter): | 1206 | >>> for spec in cprov.specifications(None, filter=filter): |
801 | 1207 | ... print spec.name | 1207 | ... print spec.name |
802 | 1208 | e4x | 1208 | e4x |
803 | 1209 | 1209 | ||
804 | 1210 | We can filter for specifications that contain specific text: | 1210 | We can filter for specifications that contain specific text: |
805 | 1211 | 1211 | ||
807 | 1212 | >>> for spec in cprov.specifications(filter=['svg']): | 1212 | >>> for spec in cprov.specifications(None, filter=['svg']): |
808 | 1213 | ... print spec.name | 1213 | ... print spec.name |
809 | 1214 | svg-support | 1214 | svg-support |
810 | 1215 | 1215 | ||
811 | @@ -1225,7 +1225,7 @@ | |||
812 | 1225 | >>> unlink_source_packages(firefox) | 1225 | >>> unlink_source_packages(firefox) |
813 | 1226 | >>> firefox.active = False | 1226 | >>> firefox.active = False |
814 | 1227 | >>> flush_database_updates() | 1227 | >>> flush_database_updates() |
816 | 1228 | >>> cprov.specifications(filter=['svg']).count() | 1228 | >>> cprov.specifications(None, filter=['svg']).count() |
817 | 1229 | 0 | 1229 | 0 |
818 | 1230 | 1230 | ||
819 | 1231 | Reset firefox so we don't mess up later tests. | 1231 | Reset firefox so we don't mess up later tests. |
820 | 1232 | 1232 | ||
821 | === modified file 'lib/lp/registry/doc/product.txt' | |||
822 | --- lib/lp/registry/doc/product.txt 2012-09-25 16:30:05 +0000 | |||
823 | +++ lib/lp/registry/doc/product.txt 2012-09-28 14:42:25 +0000 | |||
824 | @@ -384,7 +384,7 @@ | |||
825 | 384 | First, there should be only one informational spec for firefox: | 384 | First, there should be only one informational spec for firefox: |
826 | 385 | 385 | ||
827 | 386 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 386 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
829 | 387 | >>> for spec in firefox.specifications(filter=filter): | 387 | >>> for spec in firefox.specifications(None, filter=filter): |
830 | 388 | ... print spec.name | 388 | ... print spec.name |
831 | 389 | extension-manager-upgrades | 389 | extension-manager-upgrades |
832 | 390 | 390 | ||
833 | @@ -392,19 +392,19 @@ | |||
834 | 392 | There are no completed specs for firefox: | 392 | There are no completed specs for firefox: |
835 | 393 | 393 | ||
836 | 394 | >>> filter = [SpecificationFilter.COMPLETE] | 394 | >>> filter = [SpecificationFilter.COMPLETE] |
838 | 395 | >>> for spec in firefox.specifications(filter=filter): | 395 | >>> for spec in firefox.specifications(None, filter=filter): |
839 | 396 | ... print spec.name | 396 | ... print spec.name |
840 | 397 | 397 | ||
841 | 398 | 398 | ||
842 | 399 | And there are five incomplete specs: | 399 | And there are five incomplete specs: |
843 | 400 | 400 | ||
844 | 401 | >>> filter = [SpecificationFilter.INCOMPLETE] | 401 | >>> filter = [SpecificationFilter.INCOMPLETE] |
846 | 402 | >>> firefox.specifications(filter=filter).count() | 402 | >>> firefox.specifications(None, filter=filter).count() |
847 | 403 | 5 | 403 | 5 |
848 | 404 | 404 | ||
849 | 405 | We can filter for specifications that contain specific text: | 405 | We can filter for specifications that contain specific text: |
850 | 406 | 406 | ||
852 | 407 | >>> for spec in firefox.specifications(filter=['new']): | 407 | >>> for spec in firefox.specifications(None, filter=['new']): |
853 | 408 | ... print spec.name | 408 | ... print spec.name |
854 | 409 | canvas | 409 | canvas |
855 | 410 | e4x | 410 | e4x |
856 | 411 | 411 | ||
857 | === modified file 'lib/lp/registry/doc/productseries.txt' | |||
858 | --- lib/lp/registry/doc/productseries.txt 2012-04-10 14:01:17 +0000 | |||
859 | +++ lib/lp/registry/doc/productseries.txt 2012-09-28 14:42:25 +0000 | |||
860 | @@ -229,7 +229,7 @@ | |||
861 | 229 | If we ask for ALL specs we should see them both. | 229 | If we ask for ALL specs we should see them both. |
862 | 230 | 230 | ||
863 | 231 | >>> filter = [SpecificationFilter.ALL] | 231 | >>> filter = [SpecificationFilter.ALL] |
865 | 232 | >>> for s in onezero.specifications(filter=filter): | 232 | >>> for s in onezero.specifications(None, filter=filter): |
866 | 233 | ... print s.name | 233 | ... print s.name |
867 | 234 | a | 234 | a |
868 | 235 | b | 235 | b |
869 | @@ -238,23 +238,23 @@ | |||
870 | 238 | specs: | 238 | specs: |
871 | 239 | 239 | ||
872 | 240 | >>> filter=[SpecificationFilter.ACCEPTED] | 240 | >>> filter=[SpecificationFilter.ACCEPTED] |
874 | 241 | >>> for spec in onezero.specifications(filter=filter): | 241 | >>> for spec in onezero.specifications(None, filter=filter): |
875 | 242 | ... print spec.name, spec.goalstatus.title | 242 | ... print spec.name, spec.goalstatus.title |
876 | 243 | a Accepted | 243 | a Accepted |
877 | 244 | 244 | ||
878 | 245 | >>> filter=[SpecificationFilter.PROPOSED] | 245 | >>> filter=[SpecificationFilter.PROPOSED] |
880 | 246 | >>> onezero.specifications(filter=filter).count() | 246 | >>> onezero.specifications(None, filter=filter).count() |
881 | 247 | 0 | 247 | 0 |
882 | 248 | 248 | ||
883 | 249 | >>> filter=[SpecificationFilter.DECLINED] | 249 | >>> filter=[SpecificationFilter.DECLINED] |
885 | 250 | >>> onezero.specifications(filter=filter).count() | 250 | >>> onezero.specifications(None, filter=filter).count() |
886 | 251 | 1 | 251 | 1 |
887 | 252 | 252 | ||
888 | 253 | We should see one informational spec if we ask just for that, the | 253 | We should see one informational spec if we ask just for that, the |
889 | 254 | accepted one. | 254 | accepted one. |
890 | 255 | 255 | ||
891 | 256 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 256 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
893 | 257 | >>> for s in onezero.specifications(filter=filter): | 257 | >>> for s in onezero.specifications(None, filter=filter): |
894 | 258 | ... print s.name | 258 | ... print s.name |
895 | 259 | a | 259 | a |
896 | 260 | 260 | ||
897 | @@ -262,21 +262,21 @@ | |||
898 | 262 | 262 | ||
899 | 263 | >>> filter = [ | 263 | >>> filter = [ |
900 | 264 | ... SpecificationFilter.INFORMATIONAL, SpecificationFilter.DECLINED] | 264 | ... SpecificationFilter.INFORMATIONAL, SpecificationFilter.DECLINED] |
902 | 265 | >>> for s in onezero.specifications(filter=filter): | 265 | >>> for s in onezero.specifications(None, filter=filter): |
903 | 266 | ... print s.name | 266 | ... print s.name |
904 | 267 | b | 267 | b |
905 | 268 | 268 | ||
906 | 269 | There are is one completed, accepted spec for 1.0: | 269 | There are is one completed, accepted spec for 1.0: |
907 | 270 | 270 | ||
908 | 271 | >>> filter = [SpecificationFilter.COMPLETE] | 271 | >>> filter = [SpecificationFilter.COMPLETE] |
910 | 272 | >>> for spec in onezero.specifications(filter=filter): | 272 | >>> for spec in onezero.specifications(None, filter=filter): |
911 | 273 | ... print spec.name, spec.is_complete, spec.goalstatus.title | 273 | ... print spec.name, spec.is_complete, spec.goalstatus.title |
912 | 274 | a True Accepted | 274 | a True Accepted |
913 | 275 | 275 | ||
914 | 276 | There is one completed, declined spec: | 276 | There is one completed, declined spec: |
915 | 277 | 277 | ||
916 | 278 | >>> filter = [SpecificationFilter.COMPLETE, SpecificationFilter.DECLINED] | 278 | >>> filter = [SpecificationFilter.COMPLETE, SpecificationFilter.DECLINED] |
918 | 279 | >>> for spec in onezero.specifications(filter=filter): | 279 | >>> for spec in onezero.specifications(None, filter=filter): |
919 | 280 | ... print spec.name, spec.is_complete, spec.goalstatus.title | 280 | ... print spec.name, spec.is_complete, spec.goalstatus.title |
920 | 281 | b True Declined | 281 | b True Declined |
921 | 282 | 282 | ||
922 | @@ -291,7 +291,7 @@ | |||
923 | 291 | And if we ask just for specs, we get BOTH the incomplete and the | 291 | And if we ask just for specs, we get BOTH the incomplete and the |
924 | 292 | complete ones that have been accepted. | 292 | complete ones that have been accepted. |
925 | 293 | 293 | ||
927 | 294 | >>> for spec in onezero.specifications(): | 294 | >>> for spec in onezero.specifications(None): |
928 | 295 | ... print spec.name, spec.is_complete, spec.goalstatus.title | 295 | ... print spec.name, spec.is_complete, spec.goalstatus.title |
929 | 296 | a True Accepted | 296 | a True Accepted |
930 | 297 | b False Accepted | 297 | b False Accepted |
931 | @@ -299,7 +299,7 @@ | |||
932 | 299 | We can search for text in specifications (in this case there are no | 299 | We can search for text in specifications (in this case there are no |
933 | 300 | matches): | 300 | matches): |
934 | 301 | 301 | ||
936 | 302 | >>> print len(list(onezero.specifications(filter=['new']))) | 302 | >>> print len(list(onezero.specifications(None, filter=['new']))) |
937 | 303 | 0 | 303 | 0 |
938 | 304 | 304 | ||
939 | 305 | 305 | ||
940 | 306 | 306 | ||
941 | === modified file 'lib/lp/registry/doc/projectgroup.txt' | |||
942 | --- lib/lp/registry/doc/projectgroup.txt 2012-09-28 14:42:25 +0000 | |||
943 | +++ lib/lp/registry/doc/projectgroup.txt 2012-09-28 14:42:25 +0000 | |||
944 | @@ -150,7 +150,7 @@ | |||
945 | 150 | First, there should be only one informational spec for mozilla: | 150 | First, there should be only one informational spec for mozilla: |
946 | 151 | 151 | ||
947 | 152 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 152 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
949 | 153 | >>> for spec in mozilla.specifications(filter=filter): | 153 | >>> for spec in mozilla.specifications(None, filter=filter): |
950 | 154 | ... print spec.name | 154 | ... print spec.name |
951 | 155 | extension-manager-upgrades | 155 | extension-manager-upgrades |
952 | 156 | 156 | ||
953 | @@ -158,19 +158,19 @@ | |||
954 | 158 | There are no completed specs for mozilla: | 158 | There are no completed specs for mozilla: |
955 | 159 | 159 | ||
956 | 160 | >>> filter = [SpecificationFilter.COMPLETE] | 160 | >>> filter = [SpecificationFilter.COMPLETE] |
958 | 161 | >>> for spec in mozilla.specifications(filter=filter): | 161 | >>> for spec in mozilla.specifications(None, filter=filter): |
959 | 162 | ... print spec.name | 162 | ... print spec.name |
960 | 163 | 163 | ||
961 | 164 | 164 | ||
962 | 165 | And there are five incomplete specs: | 165 | And there are five incomplete specs: |
963 | 166 | 166 | ||
964 | 167 | >>> filter = [SpecificationFilter.INCOMPLETE] | 167 | >>> filter = [SpecificationFilter.INCOMPLETE] |
966 | 168 | >>> mozilla.specifications(filter=filter).count() | 168 | >>> mozilla.specifications(None, filter=filter).count() |
967 | 169 | 5 | 169 | 5 |
968 | 170 | 170 | ||
969 | 171 | We can filter for specifications that contain specific text: | 171 | We can filter for specifications that contain specific text: |
970 | 172 | 172 | ||
972 | 173 | >>> for spec in mozilla.specifications(filter=['install']): | 173 | >>> for spec in mozilla.specifications(None, filter=['install']): |
973 | 174 | ... print spec.name | 174 | ... print spec.name |
974 | 175 | extension-manager-upgrades | 175 | extension-manager-upgrades |
975 | 176 | 176 | ||
976 | @@ -178,7 +178,7 @@ | |||
977 | 178 | Inactive products are excluded from the listings. | 178 | Inactive products are excluded from the listings. |
978 | 179 | 179 | ||
979 | 180 | >>> filter = [SpecificationFilter.INCOMPLETE] | 180 | >>> filter = [SpecificationFilter.INCOMPLETE] |
981 | 181 | >>> mozilla.specifications(filter=filter).count() | 181 | >>> mozilla.specifications(None, filter=filter).count() |
982 | 182 | 5 | 182 | 5 |
983 | 183 | 183 | ||
984 | 184 | >>> from lp.registry.interfaces.product import IProductSet | 184 | >>> from lp.registry.interfaces.product import IProductSet |
985 | @@ -190,7 +190,7 @@ | |||
986 | 190 | >>> firefox.active = False | 190 | >>> firefox.active = False |
987 | 191 | >>> flush_database_updates() | 191 | >>> flush_database_updates() |
988 | 192 | >>> filter = [SpecificationFilter.INCOMPLETE] | 192 | >>> filter = [SpecificationFilter.INCOMPLETE] |
990 | 193 | >>> mozilla.specifications(filter=filter).count() | 193 | >>> mozilla.specifications(None, filter=filter).count() |
991 | 194 | 0 | 194 | 0 |
992 | 195 | 195 | ||
993 | 196 | Reset firefox so we don't mess up later tests. | 196 | Reset firefox so we don't mess up later tests. |
994 | @@ -248,7 +248,8 @@ | |||
995 | 248 | mozilla_1_0_series._all_specifications. | 248 | mozilla_1_0_series._all_specifications. |
996 | 249 | 249 | ||
997 | 250 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 250 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
999 | 251 | >>> extension_manager_upgrades = mozilla.specifications(filter=filter)[0] | 251 | >>> extension_manager_upgrades = mozilla.specifications( |
1000 | 252 | ... None, filter=filter)[0] | ||
1001 | 252 | >>> series_1_0 = firefox.getSeries('1.0') | 253 | >>> series_1_0 = firefox.getSeries('1.0') |
1002 | 253 | >>> extension_manager_upgrades.proposeGoal(series_1_0, no_priv) | 254 | >>> extension_manager_upgrades.proposeGoal(series_1_0, no_priv) |
1003 | 254 | >>> for spec in mozilla_series_1_0._all_specifications: | 255 | >>> for spec in mozilla_series_1_0._all_specifications: |
1004 | @@ -264,7 +265,7 @@ | |||
1005 | 264 | Filtered lists of project series related specifications are generated | 265 | Filtered lists of project series related specifications are generated |
1006 | 265 | the same way as for project related specifications. | 266 | the same way as for project related specifications. |
1007 | 266 | 267 | ||
1009 | 267 | >>> for spec in mozilla_series_1_0.specifications(filter=filter): | 268 | >>> for spec in mozilla_series_1_0.specifications(None, filter=filter): |
1010 | 268 | ... print spec.name | 269 | ... print spec.name |
1011 | 269 | extension-manager-upgrades | 270 | extension-manager-upgrades |
1012 | 270 | 271 | ||
1013 | @@ -277,7 +278,7 @@ | |||
1014 | 277 | project itself. | 278 | project itself. |
1015 | 278 | 279 | ||
1016 | 279 | >>> filter = [SpecificationFilter.INCOMPLETE] | 280 | >>> filter = [SpecificationFilter.INCOMPLETE] |
1018 | 280 | >>> for spec in mozilla_series_1_0.specifications(filter=filter): | 281 | >>> for spec in mozilla_series_1_0.specifications(None, filter=filter): |
1019 | 281 | ... print spec.name | 282 | ... print spec.name |
1020 | 282 | svg-support | 283 | svg-support |
1021 | 283 | canvas | 284 | canvas |
1022 | @@ -287,21 +288,22 @@ | |||
1023 | 287 | 288 | ||
1024 | 288 | Searching for text is also possible. | 289 | Searching for text is also possible. |
1025 | 289 | 290 | ||
1027 | 290 | >>> for spec in mozilla_series_1_0.specifications(filter=['install']): | 291 | >>> for spec in mozilla_series_1_0.specifications( |
1028 | 292 | ... None, filter=['install']): | ||
1029 | 291 | ... print spec.name | 293 | ... print spec.name |
1030 | 292 | extension-manager-upgrades | 294 | extension-manager-upgrades |
1031 | 293 | 295 | ||
1032 | 294 | Inactive products are excluded from the series listings. | 296 | Inactive products are excluded from the series listings. |
1033 | 295 | 297 | ||
1034 | 296 | >>> filter = [SpecificationFilter.INCOMPLETE] | 298 | >>> filter = [SpecificationFilter.INCOMPLETE] |
1036 | 297 | >>> specs = mozilla_series_1_0.specifications(filter=filter) | 299 | >>> specs = mozilla_series_1_0.specifications(None, filter=filter) |
1037 | 298 | >>> print specs.count() | 300 | >>> print specs.count() |
1038 | 299 | 5 | 301 | 5 |
1039 | 300 | 302 | ||
1040 | 301 | >>> firefox = getUtility(IProductSet).getByName('firefox') | 303 | >>> firefox = getUtility(IProductSet).getByName('firefox') |
1041 | 302 | >>> firefox.active = False | 304 | >>> firefox.active = False |
1042 | 303 | >>> filter = [SpecificationFilter.INCOMPLETE] | 305 | >>> filter = [SpecificationFilter.INCOMPLETE] |
1044 | 304 | >>> mozilla_series_1_0.specifications(filter=filter).count() | 306 | >>> mozilla_series_1_0.specifications(None, filter=filter).count() |
1045 | 305 | 0 | 307 | 0 |
1046 | 306 | 308 | ||
1047 | 307 | Reset firefox so we don't mess up later tests. | 309 | Reset firefox so we don't mess up later tests. |
1048 | 308 | 310 | ||
1049 | === modified file 'lib/lp/registry/model/distribution.py' | |||
1050 | --- lib/lp/registry/model/distribution.py 2012-09-28 14:42:25 +0000 | |||
1051 | +++ lib/lp/registry/model/distribution.py 2012-09-28 14:42:25 +0000 | |||
1052 | @@ -878,7 +878,7 @@ | |||
1053 | 878 | return getUtility(IDistributionSet).getCurrentSourceReleases( | 878 | return getUtility(IDistributionSet).getCurrentSourceReleases( |
1054 | 879 | {self: source_package_names}) | 879 | {self: source_package_names}) |
1055 | 880 | 880 | ||
1057 | 881 | def specifications(self, sort=None, quantity=None, filter=None, | 881 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1058 | 882 | prejoin_people=True): | 882 | prejoin_people=True): |
1059 | 883 | """See `IHasSpecifications`. | 883 | """See `IHasSpecifications`. |
1060 | 884 | 884 | ||
1061 | 885 | 885 | ||
1062 | === modified file 'lib/lp/registry/model/distroseries.py' | |||
1063 | --- lib/lp/registry/model/distroseries.py 2012-09-28 14:42:25 +0000 | |||
1064 | +++ lib/lp/registry/model/distroseries.py 2012-09-28 14:42:25 +0000 | |||
1065 | @@ -777,7 +777,7 @@ | |||
1066 | 777 | """See `IHasBugs`.""" | 777 | """See `IHasBugs`.""" |
1067 | 778 | return self.distribution.official_bug_tags | 778 | return self.distribution.official_bug_tags |
1068 | 779 | 779 | ||
1070 | 780 | def specifications(self, sort=None, quantity=None, filter=None, | 780 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1071 | 781 | prejoin_people=True): | 781 | prejoin_people=True): |
1072 | 782 | """See IHasSpecifications. | 782 | """See IHasSpecifications. |
1073 | 783 | 783 | ||
1074 | 784 | 784 | ||
1075 | === modified file 'lib/lp/registry/model/person.py' | |||
1076 | --- lib/lp/registry/model/person.py 2012-09-28 14:42:25 +0000 | |||
1077 | +++ lib/lp/registry/model/person.py 2012-09-28 14:42:25 +0000 | |||
1078 | @@ -821,7 +821,7 @@ | |||
1079 | 821 | """See `IPerson`.""" | 821 | """See `IPerson`.""" |
1080 | 822 | return "%s (%s)" % (self.displayname, self.name) | 822 | return "%s (%s)" % (self.displayname, self.name) |
1081 | 823 | 823 | ||
1083 | 824 | def specifications(self, sort=None, quantity=None, filter=None, | 824 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1084 | 825 | prejoin_people=True): | 825 | prejoin_people=True): |
1085 | 826 | """See `IHasSpecifications`.""" | 826 | """See `IHasSpecifications`.""" |
1086 | 827 | 827 | ||
1087 | 828 | 828 | ||
1088 | === modified file 'lib/lp/registry/model/product.py' | |||
1089 | --- lib/lp/registry/model/product.py 2012-09-28 14:42:25 +0000 | |||
1090 | +++ lib/lp/registry/model/product.py 2012-09-28 14:42:25 +0000 | |||
1091 | @@ -1303,7 +1303,7 @@ | |||
1092 | 1303 | # automatically shared. | 1303 | # automatically shared. |
1093 | 1304 | return True | 1304 | return True |
1094 | 1305 | 1305 | ||
1096 | 1306 | def specifications(self, sort=None, quantity=None, filter=None, | 1306 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1097 | 1307 | prejoin_people=True): | 1307 | prejoin_people=True): |
1098 | 1308 | """See `IHasSpecifications`.""" | 1308 | """See `IHasSpecifications`.""" |
1099 | 1309 | 1309 | ||
1100 | 1310 | 1310 | ||
1101 | === modified file 'lib/lp/registry/model/productseries.py' | |||
1102 | --- lib/lp/registry/model/productseries.py 2012-09-28 14:42:25 +0000 | |||
1103 | +++ lib/lp/registry/model/productseries.py 2012-09-28 14:42:25 +0000 | |||
1104 | @@ -301,7 +301,7 @@ | |||
1105 | 301 | """See `IProductSeries`.""" | 301 | """See `IProductSeries`.""" |
1106 | 302 | return self == self.product.development_focus | 302 | return self == self.product.development_focus |
1107 | 303 | 303 | ||
1109 | 304 | def specifications(self, sort=None, quantity=None, filter=None, | 304 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1110 | 305 | prejoin_people=True): | 305 | prejoin_people=True): |
1111 | 306 | """See IHasSpecifications. | 306 | """See IHasSpecifications. |
1112 | 307 | 307 | ||
1113 | 308 | 308 | ||
1114 | === modified file 'lib/lp/registry/model/projectgroup.py' | |||
1115 | --- lib/lp/registry/model/projectgroup.py 2012-09-28 14:42:25 +0000 | |||
1116 | +++ lib/lp/registry/model/projectgroup.py 2012-09-28 14:42:25 +0000 | |||
1117 | @@ -231,7 +231,7 @@ | |||
1118 | 231 | """ % sqlvalues(self, SprintSpecificationStatus.ACCEPTED) | 231 | """ % sqlvalues(self, SprintSpecificationStatus.ACCEPTED) |
1119 | 232 | return query, ['Product', 'Specification', 'SprintSpecification'] | 232 | return query, ['Product', 'Specification', 'SprintSpecification'] |
1120 | 233 | 233 | ||
1122 | 234 | def specifications(self, sort=None, quantity=None, filter=None, | 234 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1123 | 235 | series=None, prejoin_people=True): | 235 | series=None, prejoin_people=True): |
1124 | 236 | """See `IHasSpecifications`.""" | 236 | """See `IHasSpecifications`.""" |
1125 | 237 | 237 | ||
1126 | @@ -631,10 +631,11 @@ | |||
1127 | 631 | self.project = project | 631 | self.project = project |
1128 | 632 | self.name = name | 632 | self.name = name |
1129 | 633 | 633 | ||
1131 | 634 | def specifications(self, sort=None, quantity=None, filter=None, | 634 | def specifications(self, user, sort=None, quantity=None, filter=None, |
1132 | 635 | prejoin_people=True): | 635 | prejoin_people=True): |
1133 | 636 | return self.project.specifications( | 636 | return self.project.specifications( |
1135 | 637 | sort, quantity, filter, self.name, prejoin_people=prejoin_people) | 637 | user, sort, quantity, filter, self.name, |
1136 | 638 | prejoin_people=prejoin_people) | ||
1137 | 638 | 639 | ||
1138 | 639 | @property | 640 | @property |
1139 | 640 | def title(self): | 641 | def title(self): |
1140 | 641 | 642 | ||
1141 | === modified file 'lib/lp/testing/factory.py' | |||
1142 | --- lib/lp/testing/factory.py 2012-09-28 06:25:44 +0000 | |||
1143 | +++ lib/lp/testing/factory.py 2012-09-28 14:42:25 +0000 | |||
1144 | @@ -2091,8 +2091,16 @@ | |||
1145 | 2091 | :param product: The product to make the blueprint on. If one is | 2091 | :param product: The product to make the blueprint on. If one is |
1146 | 2092 | not specified, an arbitrary product is created. | 2092 | not specified, an arbitrary product is created. |
1147 | 2093 | """ | 2093 | """ |
1148 | 2094 | proprietary = (information_type not in PUBLIC_INFORMATION_TYPES and | ||
1149 | 2095 | information_type is not None) | ||
1150 | 2094 | if distribution is None and product is None: | 2096 | if distribution is None and product is None: |
1152 | 2095 | product = self.makeProduct() | 2097 | if proprietary: |
1153 | 2098 | specification_sharing_policy = ( | ||
1154 | 2099 | SpecificationSharingPolicy.EMBARGOED_OR_PROPRIETARY) | ||
1155 | 2100 | else: | ||
1156 | 2101 | specification_sharing_policy = None | ||
1157 | 2102 | product = self.makeProduct( | ||
1158 | 2103 | specification_sharing_policy=specification_sharing_policy) | ||
1159 | 2096 | if name is None: | 2104 | if name is None: |
1160 | 2097 | name = self.getUniqueString('name') | 2105 | name = self.getUniqueString('name') |
1161 | 2098 | if summary is None: | 2106 | if summary is None: |
1162 | @@ -2125,7 +2133,7 @@ | |||
1163 | 2125 | priority=priority) | 2133 | priority=priority) |
1164 | 2126 | naked_spec = removeSecurityProxy(spec) | 2134 | naked_spec = removeSecurityProxy(spec) |
1165 | 2127 | if information_type is not None: | 2135 | if information_type is not None: |
1167 | 2128 | if information_type not in PUBLIC_INFORMATION_TYPES: | 2136 | if proprietary: |
1168 | 2129 | naked_spec.target._ensurePolicies([information_type]) | 2137 | naked_spec.target._ensurePolicies([information_type]) |
1169 | 2130 | naked_spec.transitionToInformationType( | 2138 | naked_spec.transitionToInformationType( |
1170 | 2131 | information_type, spec.target.owner) | 2139 | information_type, spec.target.owner) |
1171 | @@ -4340,9 +4348,9 @@ | |||
1172 | 4340 | return link | 4348 | return link |
1173 | 4341 | 4349 | ||
1174 | 4342 | def makeAccessArtifactGrant(self, artifact=None, grantee=None, | 4350 | def makeAccessArtifactGrant(self, artifact=None, grantee=None, |
1176 | 4343 | grantor=None): | 4351 | grantor=None, concrete_artifact=None): |
1177 | 4344 | if artifact is None: | 4352 | if artifact is None: |
1179 | 4345 | artifact = self.makeAccessArtifact() | 4353 | artifact = self.makeAccessArtifact(concrete_artifact) |
1180 | 4346 | if grantee is None: | 4354 | if grantee is None: |
1181 | 4347 | grantee = self.makePerson() | 4355 | grantee = self.makePerson() |
1182 | 4348 | if grantor is None: | 4356 | if grantor is None: |
This looks alright.
As one minor point, it might be cleaner to set the default argument for user in `specifications` to None, rather than passing in None everytime you need it. But I don't see that as a blocker to approval--it's just a thought.