Merge lp:~danilo/launchpad/merge-ss-with-filters-urls into lp:launchpad/db-devel
- merge-ss-with-filters-urls
- Merge into db-devel
Status: | Work in progress |
---|---|
Proposed branch: | lp:~danilo/launchpad/merge-ss-with-filters-urls |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
393 lines (+117/-38) 9 files modified
lib/lp/bugs/browser/configure.zcml (+1/-1) lib/lp/bugs/browser/structuralsubscription.py (+1/-4) lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py (+2/-1) lib/lp/bugs/browser/tests/test_structuralsubscription.py (+47/-12) lib/lp/bugs/interfaces/structuralsubscription.py (+9/-6) lib/lp/bugs/model/structuralsubscription.py (+11/-1) lib/lp/bugs/tests/test_structuralsubscriptiontarget.py (+27/-0) lib/lp/registry/stories/person/xx-person-subscriptions.txt (+2/-2) lib/lp/registry/stories/webservice/xx-structuralsubscription.txt (+17/-11) |
To merge this branch: | bzr merge lp:~danilo/launchpad/merge-ss-with-filters-urls |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | code | Approve | |
Review via email: mp+47403@code.launchpad.net |
Commit message
[r=gmb]
Description of the change
= Make StructuralSubsc
In accordance with our higher-level goal of having multiple structural subscription per-target, per-person, we need to have a URL for structural subscriptions that is not limited to one per person.
At the moment, canonical_url for a SS is /<target>
== Pre-implementation notes ==
I discussed with Gary the option of putting all SSs on a top-level StructuralSubsc
== Implementation details ==
I provided a getSubscriptionByID on IStructuralSubs
== Tests ==
bin/test -cvvt structuralsubsc
== Demo and Q/A ==
Check that structural subscriptions appear on appropriate links on QA staging.
= 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/
Gary Poster (gary) wrote : | # |
As you had mentioned at the sprint, after looking deeper in the code, I think we will be productive faster by sticking to one subscription and multiple separate filter records. We will move bug_notificatio
We may return to this model (and the goal of collapsing structural subscriptions and filters) in a later increment, or maybe not. For now, let's hold off on this branch.
Preview Diff
1 | === modified file 'lib/lp/bugs/browser/configure.zcml' | |||
2 | --- lib/lp/bugs/browser/configure.zcml 2011-01-21 08:12:29 +0000 | |||
3 | +++ lib/lp/bugs/browser/configure.zcml 2011-01-31 09:32:26 +0000 | |||
4 | @@ -1195,7 +1195,7 @@ | |||
5 | 1195 | 1195 | ||
6 | 1196 | <browser:url | 1196 | <browser:url |
7 | 1197 | for="lp.bugs.interfaces.structuralsubscription.IStructuralSubscription" | 1197 | for="lp.bugs.interfaces.structuralsubscription.IStructuralSubscription" |
9 | 1198 | path_expression="string:+subscription/${subscriber/name}" | 1198 | path_expression="string:+subscription/${id}" |
10 | 1199 | attribute_to_parent="target"/> | 1199 | attribute_to_parent="target"/> |
11 | 1200 | <browser:navigation | 1200 | <browser:navigation |
12 | 1201 | module="lp.bugs.browser.structuralsubscription" | 1201 | module="lp.bugs.browser.structuralsubscription" |
13 | 1202 | 1202 | ||
14 | === modified file 'lib/lp/bugs/browser/structuralsubscription.py' | |||
15 | --- lib/lp/bugs/browser/structuralsubscription.py 2011-01-21 08:12:29 +0000 | |||
16 | +++ lib/lp/bugs/browser/structuralsubscription.py 2011-01-31 09:32:26 +0000 | |||
17 | @@ -12,7 +12,6 @@ | |||
18 | 12 | 12 | ||
19 | 13 | from operator import attrgetter | 13 | from operator import attrgetter |
20 | 14 | 14 | ||
21 | 15 | from zope.component import getUtility | ||
22 | 16 | from zope.formlib import form | 15 | from zope.formlib import form |
23 | 17 | from zope.schema import ( | 16 | from zope.schema import ( |
24 | 18 | Choice, | 17 | Choice, |
25 | @@ -48,7 +47,6 @@ | |||
26 | 48 | IDistributionSourcePackage, | 47 | IDistributionSourcePackage, |
27 | 49 | ) | 48 | ) |
28 | 50 | from lp.registry.interfaces.milestone import IProjectGroupMilestone | 49 | from lp.registry.interfaces.milestone import IProjectGroupMilestone |
29 | 51 | from lp.registry.interfaces.person import IPersonSet | ||
30 | 52 | from lp.services.propertycache import cachedproperty | 50 | from lp.services.propertycache import cachedproperty |
31 | 53 | 51 | ||
32 | 54 | 52 | ||
33 | @@ -347,8 +345,7 @@ | |||
34 | 347 | @stepthrough('+subscription') | 345 | @stepthrough('+subscription') |
35 | 348 | def traverse_structuralsubscription(self, name): | 346 | def traverse_structuralsubscription(self, name): |
36 | 349 | """Traverses +subscription portions of URLs.""" | 347 | """Traverses +subscription portions of URLs.""" |
39 | 350 | person = getUtility(IPersonSet).getByName(name) | 348 | return self.context.getSubscriptionByID(subscription_id=int(name)) |
38 | 351 | return self.context.getSubscription(person) | ||
40 | 352 | 349 | ||
41 | 353 | 350 | ||
42 | 354 | class StructuralSubscriptionMenuMixin: | 351 | class StructuralSubscriptionMenuMixin: |
43 | 355 | 352 | ||
44 | === modified file 'lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py' | |||
45 | --- lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py 2011-01-21 08:12:29 +0000 | |||
46 | +++ lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py 2011-01-31 09:32:26 +0000 | |||
47 | @@ -61,7 +61,8 @@ | |||
48 | 61 | url = urlparse(canonical_url(self.subscription_filter)) | 61 | url = urlparse(canonical_url(self.subscription_filter)) |
49 | 62 | self.assertThat(url.hostname, StartsWith("bugs.")) | 62 | self.assertThat(url.hostname, StartsWith("bugs.")) |
50 | 63 | self.assertEqual( | 63 | self.assertEqual( |
52 | 64 | "/bar/+subscription/foo/+filter/%d" % ( | 64 | "/bar/+subscription/%d/+filter/%d" % ( |
53 | 65 | self.subscription.id, | ||
54 | 65 | self.subscription_filter.id), | 66 | self.subscription_filter.id), |
55 | 66 | url.path) | 67 | url.path) |
56 | 67 | 68 | ||
57 | 68 | 69 | ||
58 | === modified file 'lib/lp/bugs/browser/tests/test_structuralsubscription.py' | |||
59 | --- lib/lp/bugs/browser/tests/test_structuralsubscription.py 2011-01-21 08:12:29 +0000 | |||
60 | +++ lib/lp/bugs/browser/tests/test_structuralsubscription.py 2011-01-31 09:32:26 +0000 | |||
61 | @@ -61,10 +61,12 @@ | |||
62 | 61 | super(StructuralSubscriptionTraversalTestBase, self).setUp() | 61 | super(StructuralSubscriptionTraversalTestBase, self).setUp() |
63 | 62 | login('foo.bar@canonical.com') | 62 | login('foo.bar@canonical.com') |
64 | 63 | self.eric = self.factory.makePerson(name='eric') | 63 | self.eric = self.factory.makePerson(name='eric') |
65 | 64 | self.michael = self.factory.makePerson(name='michael') | ||
66 | 65 | 64 | ||
67 | 66 | self.setUpTarget() | 65 | self.setUpTarget() |
69 | 67 | self.target.addBugSubscription(self.eric, self.eric) | 66 | self.subscription = self.target.addBugSubscription( |
70 | 67 | self.eric, self.eric) | ||
71 | 68 | # To make sure subscription.id is defined, we commit the transaction. | ||
72 | 69 | transaction.commit() | ||
73 | 68 | 70 | ||
74 | 69 | def setUpTarget(self): | 71 | def setUpTarget(self): |
75 | 70 | self.target = self.factory.makeProduct(name='fooix') | 72 | self.target = self.factory.makeProduct(name='fooix') |
76 | @@ -73,7 +75,7 @@ | |||
77 | 73 | def test_structural_subscription_traversal(self): | 75 | def test_structural_subscription_traversal(self): |
78 | 74 | # Verify that an existing structural subscription can be | 76 | # Verify that an existing structural subscription can be |
79 | 75 | # reached from the target. | 77 | # reached from the target. |
81 | 76 | request = FakeLaunchpadRequest([], ['eric']) | 78 | request = FakeLaunchpadRequest([], [str(self.subscription.id)]) |
82 | 77 | self.assertEqual( | 79 | self.assertEqual( |
83 | 78 | self.target.getSubscription(self.eric), | 80 | self.target.getSubscription(self.eric), |
84 | 79 | self.navigation(self.target, request).publishTraverse( | 81 | self.navigation(self.target, request).publishTraverse( |
85 | @@ -81,17 +83,22 @@ | |||
86 | 81 | 83 | ||
87 | 82 | def test_missing_structural_subscription_traversal(self): | 84 | def test_missing_structural_subscription_traversal(self): |
88 | 83 | # Verify that a NotFound is raised when attempting to reach | 85 | # Verify that a NotFound is raised when attempting to reach |
91 | 84 | # a structural subscription for an person without one. | 86 | # a structural subscription which doesn't exist on the target. |
92 | 85 | request = FakeLaunchpadRequest([], ['michael']) | 87 | request = FakeLaunchpadRequest([], ["0"]) |
93 | 86 | self.assertRaises( | 88 | self.assertRaises( |
94 | 87 | NotFound, | 89 | NotFound, |
95 | 88 | self.navigation(self.target, request).publishTraverse, | 90 | self.navigation(self.target, request).publishTraverse, |
96 | 89 | request, '+subscription') | 91 | request, '+subscription') |
97 | 90 | 92 | ||
99 | 91 | def test_missing_person_structural_subscription_traversal(self): | 93 | def test_other_target_structural_subscription_traversal(self): |
100 | 92 | # Verify that a NotFound is raised when attempting to reach | 94 | # Verify that a NotFound is raised when attempting to reach |
103 | 93 | # a structural subscription for a person that does not exist. | 95 | # a structural subscription for a different target. |
104 | 94 | request = FakeLaunchpadRequest([], ['doesnotexist']) | 96 | other_target = self.factory.makeProduct() |
105 | 97 | other_subscription = other_target.addBugSubscription( | ||
106 | 98 | self.eric, self.eric) | ||
107 | 99 | # To get an ID, we must commit the transaction. | ||
108 | 100 | transaction.commit() | ||
109 | 101 | request = FakeLaunchpadRequest([], [str(other_subscription.id)]) | ||
110 | 95 | self.assertRaises( | 102 | self.assertRaises( |
111 | 96 | NotFound, | 103 | NotFound, |
112 | 97 | self.navigation(self.target, request).publishTraverse, | 104 | self.navigation(self.target, request).publishTraverse, |
113 | @@ -100,9 +107,12 @@ | |||
114 | 100 | def test_structural_subscription_canonical_url(self): | 107 | def test_structural_subscription_canonical_url(self): |
115 | 101 | # Verify that the canonical_url of a structural subscription | 108 | # Verify that the canonical_url of a structural subscription |
116 | 102 | # is correct. | 109 | # is correct. |
117 | 110 | expected_url = ( | ||
118 | 111 | canonical_url(self.target) + '/+subscription/' + | ||
119 | 112 | str(self.subscription.id)) | ||
120 | 103 | self.assertEqual( | 113 | self.assertEqual( |
123 | 104 | canonical_url(self.target.getSubscription(self.eric)), | 114 | expected_url, |
124 | 105 | canonical_url(self.target) + '/+subscription/eric') | 115 | canonical_url(self.target.getSubscription(self.eric))) |
125 | 106 | 116 | ||
126 | 107 | def tearDown(self): | 117 | def tearDown(self): |
127 | 108 | logout() | 118 | logout() |
128 | @@ -364,6 +374,31 @@ | |||
129 | 364 | self.view.target_label) | 374 | self.view.target_label) |
130 | 365 | 375 | ||
131 | 366 | 376 | ||
132 | 377 | class TestStructuralSubscriptionTargetAPI(TestCaseWithFactory): | ||
133 | 378 | |||
134 | 379 | layer = AppServerLayer | ||
135 | 380 | |||
136 | 381 | def setUp(self): | ||
137 | 382 | super(TestStructuralSubscriptionTargetAPI, self).setUp() | ||
138 | 383 | self.owner = self.factory.makePerson(name=u"foo") | ||
139 | 384 | self.subscription_target = self.factory.makeProduct( | ||
140 | 385 | owner=self.owner, name=u"bar") | ||
141 | 386 | with person_logged_in(self.owner): | ||
142 | 387 | self.subscription = self.subscription_target.addBugSubscription( | ||
143 | 388 | self.owner, self.owner) | ||
144 | 389 | transaction.commit() | ||
145 | 390 | self.service = self.factory.makeLaunchpadService(self.owner) | ||
146 | 391 | self.ws_subscription_target = ws_object( | ||
147 | 392 | self.service, self.subscription_target) | ||
148 | 393 | self.ws_subscription = ws_object(self.service, self.subscription) | ||
149 | 394 | |||
150 | 395 | def test_getSubscriptionByID(self): | ||
151 | 396 | self.assertEqual( | ||
152 | 397 | self.ws_subscription, | ||
153 | 398 | self.ws_subscription_target.getSubscriptionByID( | ||
154 | 399 | subscription_id=self.subscription.id)) | ||
155 | 400 | |||
156 | 401 | |||
157 | 367 | class TestStructuralSubscriptionAPI(TestCaseWithFactory): | 402 | class TestStructuralSubscriptionAPI(TestCaseWithFactory): |
158 | 368 | 403 | ||
159 | 369 | layer = AppServerLayer | 404 | layer = AppServerLayer |
160 | @@ -371,10 +406,10 @@ | |||
161 | 371 | def setUp(self): | 406 | def setUp(self): |
162 | 372 | super(TestStructuralSubscriptionAPI, self).setUp() | 407 | super(TestStructuralSubscriptionAPI, self).setUp() |
163 | 373 | self.owner = self.factory.makePerson(name=u"foo") | 408 | self.owner = self.factory.makePerson(name=u"foo") |
165 | 374 | self.structure = self.factory.makeProduct( | 409 | self.subscription_target = self.factory.makeProduct( |
166 | 375 | owner=self.owner, name=u"bar") | 410 | owner=self.owner, name=u"bar") |
167 | 376 | with person_logged_in(self.owner): | 411 | with person_logged_in(self.owner): |
169 | 377 | self.subscription = self.structure.addBugSubscription( | 412 | self.subscription = self.subscription_target.addBugSubscription( |
170 | 378 | self.owner, self.owner) | 413 | self.owner, self.owner) |
171 | 379 | transaction.commit() | 414 | transaction.commit() |
172 | 380 | self.service = self.factory.makeLaunchpadService(self.owner) | 415 | self.service = self.factory.makeLaunchpadService(self.owner) |
173 | 381 | 416 | ||
174 | === modified file 'lib/lp/bugs/interfaces/structuralsubscription.py' | |||
175 | --- lib/lp/bugs/interfaces/structuralsubscription.py 2011-01-21 08:12:29 +0000 | |||
176 | +++ lib/lp/bugs/interfaces/structuralsubscription.py 2011-01-31 09:32:26 +0000 | |||
177 | @@ -15,10 +15,6 @@ | |||
178 | 15 | 'IStructuralSubscriptionTargetHelper', | 15 | 'IStructuralSubscriptionTargetHelper', |
179 | 16 | ] | 16 | ] |
180 | 17 | 17 | ||
181 | 18 | from lazr.enum import ( | ||
182 | 19 | DBEnumeratedType, | ||
183 | 20 | DBItem, | ||
184 | 21 | ) | ||
185 | 22 | from lazr.restful.declarations import ( | 18 | from lazr.restful.declarations import ( |
186 | 23 | call_with, | 19 | call_with, |
187 | 24 | export_as_webservice_entry, | 20 | export_as_webservice_entry, |
188 | @@ -58,7 +54,7 @@ | |||
189 | 58 | class IStructuralSubscriptionPublic(Interface): | 54 | class IStructuralSubscriptionPublic(Interface): |
190 | 59 | """The public parts of a subscription to a Launchpad structure.""" | 55 | """The public parts of a subscription to a Launchpad structure.""" |
191 | 60 | 56 | ||
193 | 61 | id = Int(title=_('ID'), readonly=True, required=True) | 57 | id = exported(Int(title=_('ID'), readonly=True, required=True)) |
194 | 62 | product = Int(title=_('Product'), required=False, readonly=True) | 58 | product = Int(title=_('Product'), required=False, readonly=True) |
195 | 63 | productseries = Int( | 59 | productseries = Int( |
196 | 64 | title=_('Product series'), required=False, readonly=True) | 60 | title=_('Product series'), required=False, readonly=True) |
197 | @@ -151,7 +147,14 @@ | |||
198 | 151 | @operation_returns_entry(IStructuralSubscription) | 147 | @operation_returns_entry(IStructuralSubscription) |
199 | 152 | @export_read_operation() | 148 | @export_read_operation() |
200 | 153 | def getSubscription(person): | 149 | def getSubscription(person): |
202 | 154 | """Return the subscription for `person`, if it exists.""" | 150 | """Return a subscriptions for a `person`.""" |
203 | 151 | |||
204 | 152 | @operation_parameters( | ||
205 | 153 | subscription_id=Int(title=_("Subscription ID"), required=True)) | ||
206 | 154 | @operation_returns_entry(IStructuralSubscription) | ||
207 | 155 | @export_read_operation() | ||
208 | 156 | def getSubscriptionByID(subscription_id): | ||
209 | 157 | """Return a StructuralSubscription with ID `subscription_id`.""" | ||
210 | 155 | 158 | ||
211 | 156 | target_type_display = Attribute("The type of the target, for display.") | 159 | target_type_display = Attribute("The type of the target, for display.") |
212 | 157 | 160 | ||
213 | 158 | 161 | ||
214 | === modified file 'lib/lp/bugs/model/structuralsubscription.py' | |||
215 | --- lib/lp/bugs/model/structuralsubscription.py 2011-01-22 02:59:35 +0000 | |||
216 | +++ lib/lp/bugs/model/structuralsubscription.py 2011-01-31 09:32:26 +0000 | |||
217 | @@ -444,10 +444,16 @@ | |||
218 | 444 | all_subscriptions = self.getSubscriptions(subscriber=person) | 444 | all_subscriptions = self.getSubscriptions(subscriber=person) |
219 | 445 | return all_subscriptions.one() | 445 | return all_subscriptions.one() |
220 | 446 | 446 | ||
221 | 447 | def getSubscriptionByID(self, subscription_id): | ||
222 | 448 | """See `IStructuralSubscriptionTarget`.""" | ||
223 | 449 | subscriptions = self.getSubscriptions( | ||
224 | 450 | subscription_id=subscription_id) | ||
225 | 451 | return subscriptions.one() | ||
226 | 452 | |||
227 | 447 | def getSubscriptions(self, | 453 | def getSubscriptions(self, |
228 | 448 | min_bug_notification_level= | 454 | min_bug_notification_level= |
229 | 449 | BugNotificationLevel.NOTHING, | 455 | BugNotificationLevel.NOTHING, |
231 | 450 | subscriber=None): | 456 | subscriber=None, subscription_id=None): |
232 | 451 | """See `IStructuralSubscriptionTarget`.""" | 457 | """See `IStructuralSubscriptionTarget`.""" |
233 | 452 | from lp.registry.model.person import Person | 458 | from lp.registry.model.person import Person |
234 | 453 | clauses = [ | 459 | clauses = [ |
235 | @@ -463,6 +469,10 @@ | |||
236 | 463 | clauses.append( | 469 | clauses.append( |
237 | 464 | StructuralSubscription.subscriberID==subscriber.id) | 470 | StructuralSubscription.subscriberID==subscriber.id) |
238 | 465 | 471 | ||
239 | 472 | if subscription_id is not None: | ||
240 | 473 | clauses.append( | ||
241 | 474 | StructuralSubscription.id==subscription_id) | ||
242 | 475 | |||
243 | 466 | store = Store.of(self.__helper.pillar) | 476 | store = Store.of(self.__helper.pillar) |
244 | 467 | return store.find( | 477 | return store.find( |
245 | 468 | StructuralSubscription, *clauses).order_by('Person.displayname') | 478 | StructuralSubscription, *clauses).order_by('Person.displayname') |
246 | 469 | 479 | ||
247 | === modified file 'lib/lp/bugs/tests/test_structuralsubscriptiontarget.py' | |||
248 | --- lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2011-01-21 08:12:29 +0000 | |||
249 | +++ lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2011-01-31 09:32:26 +0000 | |||
250 | @@ -171,6 +171,33 @@ | |||
251 | 171 | self.team, self.team_owner), | 171 | self.team, self.team_owner), |
252 | 172 | None) | 172 | None) |
253 | 173 | 173 | ||
254 | 174 | def test_getSubscriptionByID_nothing(self): | ||
255 | 175 | login_person(self.team_owner) | ||
256 | 176 | self.assertIs( | ||
257 | 177 | None, | ||
258 | 178 | self.target.getSubscriptionByID(0)) | ||
259 | 179 | |||
260 | 180 | def test_getSubscriptionByID_success(self): | ||
261 | 181 | login_person(self.team_owner) | ||
262 | 182 | # Create a subscription to return. | ||
263 | 183 | subscription = self.target.addBugSubscription( | ||
264 | 184 | self.team, self.team_owner) | ||
265 | 185 | self.assertEquals( | ||
266 | 186 | subscription, | ||
267 | 187 | self.target.getSubscriptionByID(subscription.id)) | ||
268 | 188 | |||
269 | 189 | def test_getSubscriptionByID_other_target(self): | ||
270 | 190 | # No subscription is returned if one tries to get | ||
271 | 191 | # a subscription from a different target. | ||
272 | 192 | login_person(self.team_owner) | ||
273 | 193 | # Create a subscription on a different target. | ||
274 | 194 | other_target = self.factory.makeProduct() | ||
275 | 195 | subscription = other_target.addBugSubscription( | ||
276 | 196 | self.team, self.team_owner) | ||
277 | 197 | self.assertIs( | ||
278 | 198 | None, | ||
279 | 199 | self.target.getSubscriptionByID(subscription.id)) | ||
280 | 200 | |||
281 | 174 | 201 | ||
282 | 175 | class FilteredStructuralSubscriptionTestBase: | 202 | class FilteredStructuralSubscriptionTestBase: |
283 | 176 | """Tests for filtered structural subscriptions.""" | 203 | """Tests for filtered structural subscriptions.""" |
284 | 177 | 204 | ||
285 | === modified file 'lib/lp/registry/stories/person/xx-person-subscriptions.txt' | |||
286 | --- lib/lp/registry/stories/person/xx-person-subscriptions.txt 2011-01-13 16:28:49 +0000 | |||
287 | +++ lib/lp/registry/stories/person/xx-person-subscriptions.txt 2011-01-31 09:32:26 +0000 | |||
288 | @@ -236,9 +236,9 @@ | |||
289 | 236 | ... "http://launchpad.dev/people/+me/+structural-subscriptions") | 236 | ... "http://launchpad.dev/people/+me/+structural-subscriptions") |
290 | 237 | >>> show_create_links(admin_browser) | 237 | >>> show_create_links(admin_browser) |
291 | 238 | mozilla-firefox in ubuntu | 238 | mozilla-firefox in ubuntu |
293 | 239 | * Create a new filter --> /ubuntu/.../name16/+new-filter | 239 | * Create a new filter --> /ubuntu/.../+new-filter |
294 | 240 | pmount in ubuntu | 240 | pmount in ubuntu |
296 | 241 | * Create a new filter --> /ubuntu/.../name16/+new-filter | 241 | * Create a new filter --> /ubuntu/.../+new-filter |
297 | 242 | 242 | ||
298 | 243 | If the user does not have the necessary rights to create new bug | 243 | If the user does not have the necessary rights to create new bug |
299 | 244 | filters the "Create" link is not shown. | 244 | filters the "Create" link is not shown. |
300 | 245 | 245 | ||
301 | === modified file 'lib/lp/registry/stories/webservice/xx-structuralsubscription.txt' | |||
302 | --- lib/lp/registry/stories/webservice/xx-structuralsubscription.txt 2010-12-21 23:19:35 +0000 | |||
303 | +++ lib/lp/registry/stories/webservice/xx-structuralsubscription.txt 2011-01-31 09:32:26 +0000 | |||
304 | @@ -1,4 +1,5 @@ | |||
306 | 1 | = Structural Subscriptions = | 1 | Structural Subscriptions |
307 | 2 | ======================== | ||
308 | 2 | 3 | ||
309 | 3 | Structural subscriptions can be obtained from any target: a project, | 4 | Structural subscriptions can be obtained from any target: a project, |
310 | 4 | project series, project group, distribution, distribution series or | 5 | project series, project group, distribution, distribution series or |
311 | @@ -37,7 +38,7 @@ | |||
312 | 37 | ... '/fooix', 'addBugSubscription') | 38 | ... '/fooix', 'addBugSubscription') |
313 | 38 | HTTP/1.1 201 Created | 39 | HTTP/1.1 201 Created |
314 | 39 | ... | 40 | ... |
316 | 40 | Location: http://.../fooix/+subscription/eric | 41 | Location: http://.../fooix/+subscription/... |
317 | 41 | ... | 42 | ... |
318 | 42 | 43 | ||
319 | 43 | >>> subscriptions = webservice.named_get( | 44 | >>> subscriptions = webservice.named_get( |
320 | @@ -46,11 +47,12 @@ | |||
321 | 46 | start: 0 | 47 | start: 0 |
322 | 47 | total_size: 1 | 48 | total_size: 1 |
323 | 48 | --- | 49 | --- |
325 | 49 | bug_filters_collection_link: u'.../fooix/+subscription/eric/bug_filters' | 50 | bug_filters_collection_link: u'.../fooix/+subscription/.../bug_filters' |
326 | 50 | date_created: u'...' | 51 | date_created: u'...' |
327 | 51 | date_last_updated: u'...' | 52 | date_last_updated: u'...' |
328 | 53 | id: ... | ||
329 | 52 | resource_type_link: u'http://.../#structural_subscription' | 54 | resource_type_link: u'http://.../#structural_subscription' |
331 | 53 | self_link: u'http://.../fooix/+subscription/eric' | 55 | self_link: u'http://.../fooix/+subscription/...' |
332 | 54 | subscribed_by_link: u'http://.../~eric' | 56 | subscribed_by_link: u'http://.../~eric' |
333 | 55 | subscriber_link: u'http://.../~eric' | 57 | subscriber_link: u'http://.../~eric' |
334 | 56 | target_link: u'http://.../fooix' | 58 | target_link: u'http://.../fooix' |
335 | @@ -61,11 +63,12 @@ | |||
336 | 61 | >>> pprint_entry(eric_webservice.named_get( | 63 | >>> pprint_entry(eric_webservice.named_get( |
337 | 62 | ... '/fooix', 'getSubscription', | 64 | ... '/fooix', 'getSubscription', |
338 | 63 | ... person=webservice.getAbsoluteUrl('/~eric')).jsonBody()) | 65 | ... person=webservice.getAbsoluteUrl('/~eric')).jsonBody()) |
340 | 64 | bug_filters_collection_link: u'.../fooix/+subscription/eric/bug_filters' | 66 | bug_filters_collection_link: u'.../fooix/+subscription/.../bug_filters' |
341 | 65 | date_created: u'...' | 67 | date_created: u'...' |
342 | 66 | date_last_updated: u'...' | 68 | date_last_updated: u'...' |
343 | 69 | id: ... | ||
344 | 67 | resource_type_link: u'http://.../#structural_subscription' | 70 | resource_type_link: u'http://.../#structural_subscription' |
346 | 68 | self_link: u'http://.../fooix/+subscription/eric' | 71 | self_link: u'http://.../fooix/+subscription/...' |
347 | 69 | subscribed_by_link: u'http://.../~eric' | 72 | subscribed_by_link: u'http://.../~eric' |
348 | 70 | subscriber_link: u'http://.../~eric' | 73 | subscriber_link: u'http://.../~eric' |
349 | 71 | target_link: u'http://.../fooix' | 74 | target_link: u'http://.../fooix' |
350 | @@ -96,7 +99,8 @@ | |||
351 | 96 | ... subscriber=webservice.getAbsoluteUrl('/~pythons')) | 99 | ... subscriber=webservice.getAbsoluteUrl('/~pythons')) |
352 | 97 | HTTP/1.1 401 Unauthorized | 100 | HTTP/1.1 401 Unauthorized |
353 | 98 | ... | 101 | ... |
355 | 99 | UserCannotSubscribePerson: eric does not have permission to subscribe pythons. | 102 | UserCannotSubscribePerson: eric does not have permission |
356 | 103 | to subscribe pythons. | ||
357 | 100 | <BLANKLINE> | 104 | <BLANKLINE> |
358 | 101 | 105 | ||
359 | 102 | Oops, Eric isn't a team admin. Eric gets Michael to try, since he is an | 106 | Oops, Eric isn't a team admin. Eric gets Michael to try, since he is an |
360 | @@ -110,7 +114,7 @@ | |||
361 | 110 | ... subscriber=webservice.getAbsoluteUrl('/~pythons')) | 114 | ... subscriber=webservice.getAbsoluteUrl('/~pythons')) |
362 | 111 | HTTP/1.1 201 Created | 115 | HTTP/1.1 201 Created |
363 | 112 | ... | 116 | ... |
365 | 113 | Location: http://.../fooix/+subscription/pythons | 117 | Location: http://.../fooix/+subscription/... |
366 | 114 | ... | 118 | ... |
367 | 115 | 119 | ||
368 | 116 | >>> subscriptions = webservice.named_get( | 120 | >>> subscriptions = webservice.named_get( |
369 | @@ -119,11 +123,12 @@ | |||
370 | 119 | start: 0 | 123 | start: 0 |
371 | 120 | total_size: 1 | 124 | total_size: 1 |
372 | 121 | --- | 125 | --- |
374 | 122 | bug_filters_collection_link: u'.../fooix/+subscription/pythons/bug_filters' | 126 | bug_filters_collection_link: u'.../fooix/+subscription/.../bug_filters' |
375 | 123 | date_created: u'...' | 127 | date_created: u'...' |
376 | 124 | date_last_updated: u'...' | 128 | date_last_updated: u'...' |
377 | 129 | id: ... | ||
378 | 125 | resource_type_link: u'http://.../#structural_subscription' | 130 | resource_type_link: u'http://.../#structural_subscription' |
380 | 126 | self_link: u'http://.../fooix/+subscription/pythons' | 131 | self_link: u'http://.../fooix/+subscription/...' |
381 | 127 | subscribed_by_link: u'http://.../~michael' | 132 | subscribed_by_link: u'http://.../~michael' |
382 | 128 | subscriber_link: u'http://.../~pythons' | 133 | subscriber_link: u'http://.../~pythons' |
383 | 129 | target_link: u'http://.../fooix' | 134 | target_link: u'http://.../fooix' |
384 | @@ -136,7 +141,8 @@ | |||
385 | 136 | ... subscriber=webservice.getAbsoluteUrl('/~pythons')) | 141 | ... subscriber=webservice.getAbsoluteUrl('/~pythons')) |
386 | 137 | HTTP/1.1 401 Unauthorized | 142 | HTTP/1.1 401 Unauthorized |
387 | 138 | ... | 143 | ... |
389 | 139 | UserCannotSubscribePerson: eric does not have permission to unsubscribe pythons. | 144 | UserCannotSubscribePerson: eric does not have permission |
390 | 145 | to unsubscribe pythons. | ||
391 | 140 | <BLANKLINE> | 146 | <BLANKLINE> |
392 | 141 | 147 | ||
393 | 142 | Michael can, though. | 148 | Michael can, though. |
Just one minor change needed, which we discussed on IRC:
[13:57] gmb: ubscriptionTarg etAPI are a bit ambiguous - enough so that a reader would need to find their definition to find out what they are, anyway. I think that self.subscripti on_target and .ws_subscriptio n_target would be better names. What do you think?
danilo: self.structure and self.ws_structure in TestStructuralS
[13:57] danilos:
gmb, agreed!