Merge lp:~sinzui/launchpad/delete-packaging-link into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 15987
Proposed branch: lp:~sinzui/launchpad/delete-packaging-link
Merge into: lp:launchpad
Diff against target: 642 lines (+86/-199)
11 files modified
lib/lp/registry/browser/tests/test_sourcepackage_views.py (+28/-31)
lib/lp/registry/doc/sourcepackage.txt (+0/-64)
lib/lp/registry/interfaces/packaging.py (+2/-3)
lib/lp/registry/model/packaging.py (+7/-6)
lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt (+2/-2)
lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt (+2/-1)
lib/lp/registry/tests/test_packaging.py (+9/-20)
lib/lp/registry/tests/test_sourcepackage.py (+16/-59)
lib/lp/testing/factory.py (+6/-1)
lib/lp/translations/browser/tests/test_sharing_details.py (+12/-11)
lib/lp/translations/tests/test_translationpackagingjob.py (+2/-1)
To merge this branch: bzr merge lp:~sinzui/launchpad/delete-packaging-link
Reviewer Review Type Date Requested Status
Richard Harding (community) Approve
Review via email: mp+124809@code.launchpad.net

Commit message

Allow the Ubuntu community to manage their upstream packaging links.

Description of the change

Launchpad's zcml states that anyone can unlink a package from a series.
The rule is used on the distribution and source package pages, and on
the project's package pages. When translation message sharing was added,
a condition was added to the code that will raise a forbidden error if
the user attempts to unlink a package from a series that is sharing
translations.

There is no role or action that a user can do that definitely qualify a
user to manage packaging. We know that project users are more likely to
create bogus packaging links and that users create more packaging links
then are deleted.

The Packaging.userCanDelete() restrictions are naive. The rules assume
that shared messages are more important then the true links to the
upstream project. The ubuntu community cannot fix bogus data created by
project maintainers who do not understand packaging. Ubuntu encourages
projects to link to them by making it easy to create the link, and the
community gardens the packaging links. The restrictive code is solving a
problem that never existed, and introduces a new problem that distro
communities cannot manage their data.

The broken rules and tests favoured the package or productseries owner,
but these properties recored registrants, not people with
responsibility. In fact, most of these Packaging permission checks are
asking if the user is ~sinzui or ~jelmer because we created most of the
packaging links :(

--------------------------------------------------------------------

RULES

    Pre-implementation: jcsackett
    * Either remove Packaging.userCanDelete() or simplify it to verify
      if the user has launchpad experience.

QA

    * Visit https://qastaging.launchpad.net/ubuntu/q-series/+source/tweak
    * Verify there is a delete and edit icon next to the upstream series
    * Open each action and verify the pages loads without error
    * Visit https://translations.qastaging.launchpad.net/ubuntu/precise/+source/tweak/+sharing-details
    * Verify the edit and delete icons are show next to the package
    * Open each and verify the pages loads without error

LINT

    lib/lp/registry/interfaces/packaging.py
    lib/lp/registry/model/packaging.py
    lib/lp/translations/browser/tests/test_sharing_details.py

TEST

    ./bin/test -vvc -t packaging lp.translations.browser.tests.test_sharing

IMPLEMENTATION

I updated Packaging.userCanDelete() to check if the user is not
probationary, which is the experience test we use elsewhere when we do
not want novices creating bogus data. I updated the tests that care
about sharing and packaging to make it clear probationary users cannot
change collection packaging data.
    lib/lp/registry/interfaces/packaging.py
    lib/lp/registry/model/packaging.py
    lib/lp/translations/browser/tests/test_sharing_details.py

To post a comment you must log in.
Revision history for this message
Richard Harding (rharding) wrote :

Thanks for clearing up in irc that the karma changes are needed to get the user to not be probationary. For devs not totally aware of the distinction a comment to that effect would be helpful. Thanks for the change.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/tests/test_sourcepackage_views.py'
2--- lib/lp/registry/browser/tests/test_sourcepackage_views.py 2012-01-01 02:58:52 +0000
3+++ lib/lp/registry/browser/tests/test_sourcepackage_views.py 2012-09-19 18:22:24 +0000
4@@ -213,17 +213,14 @@
5
6 layer = DatabaseFunctionalLayer
7
8- def makeSourcePackageOverviewMenu(self, with_packaging, for_other_user):
9+ def makeSourcePackageOverviewMenu(self, with_packaging, karma=None):
10 sourcepackage = self.factory.makeSourcePackage()
11- owner = self.factory.makePerson()
12+ registrant = self.factory.makePerson()
13 if with_packaging:
14 self.factory.makePackagingLink(
15 sourcepackagename=sourcepackage.sourcepackagename,
16- distroseries=sourcepackage.distroseries, owner=owner)
17- if for_other_user:
18- user = self.factory.makePerson()
19- else:
20- user = owner
21+ distroseries=sourcepackage.distroseries, owner=registrant)
22+ user = self.factory.makePerson(karma=karma)
23 with person_logged_in(user):
24 menu = SourcePackageOverviewMenu(sourcepackage)
25 return menu, user
26@@ -231,62 +228,62 @@
27 def test_edit_packaging_link__enabled_without_packaging(self):
28 # If no packging exists, the edit_packaging link is always
29 # enabled.
30- menu, user = self.makeSourcePackageOverviewMenu(False, False)
31+ menu, user = self.makeSourcePackageOverviewMenu(False, None)
32 with person_logged_in(user):
33 self.assertTrue(menu.edit_packaging().enabled)
34
35 def test_set_upstrem_link__enabled_without_packaging(self):
36 # If no packging exists, the set_upstream link is always
37 # enabled.
38- menu, user = self.makeSourcePackageOverviewMenu(False, False)
39+ menu, user = self.makeSourcePackageOverviewMenu(False, None)
40 with person_logged_in(user):
41 self.assertTrue(menu.set_upstream().enabled)
42
43 def test_remove_packaging_link__enabled_without_packaging(self):
44 # If no packging exists, the remove_packaging link is always
45 # enabled.
46- menu, user = self.makeSourcePackageOverviewMenu(False, False)
47+ menu, user = self.makeSourcePackageOverviewMenu(False, None)
48 with person_logged_in(user):
49 self.assertTrue(menu.remove_packaging().enabled)
50
51- def test_edit_packaging_link__enabled_with_packaging_for_owner(self):
52+ def test_edit_packaging_link__enabled_with_packaging_non_probation(self):
53 # If a packging exists, the edit_packaging link is enabled
54- # for the packaging owner.
55- menu, user = self.makeSourcePackageOverviewMenu(True, False)
56+ # for the non-probationary users.
57+ menu, user = self.makeSourcePackageOverviewMenu(True, 100)
58 with person_logged_in(user):
59 self.assertTrue(menu.edit_packaging().enabled)
60
61- def test_set_upstrem_link__enabled_with_packaging_for_owner(self):
62+ def test_set_upstrem_link__enabled_with_packaging_non_probation(self):
63 # If a packging exists, the set_upstream link is enabled
64- # for the packaging owner.
65- menu, user = self.makeSourcePackageOverviewMenu(True, False)
66+ # for the non-probationary users.
67+ menu, user = self.makeSourcePackageOverviewMenu(True, 100)
68 with person_logged_in(user):
69 self.assertTrue(menu.set_upstream().enabled)
70
71- def test_remove_packaging_link__enabled_with_packaging_for_owner(self):
72+ def test_remove_packaging_link__enabled_with_packaging_non_probation(self):
73 # If a packging exists, the remove_packaging link is enabled
74- # for the packaging owner.
75- menu, user = self.makeSourcePackageOverviewMenu(True, False)
76+ # for the non-probationary users.
77+ menu, user = self.makeSourcePackageOverviewMenu(True, 100)
78 with person_logged_in(user):
79 self.assertTrue(menu.remove_packaging().enabled)
80
81- def test_edit_packaging_link__enabled_with_packaging_for_others(self):
82- # If a packging exists, the edit_packaging link is enabled
83- # for the packaging owner.
84- menu, user = self.makeSourcePackageOverviewMenu(True, True)
85+ def test_edit_packaging_link__enabled_with_packaging_probation(self):
86+ # If a packging exists, the edit_packaging link is not enabled
87+ # for probationary users.
88+ menu, user = self.makeSourcePackageOverviewMenu(True, None)
89 with person_logged_in(user):
90 self.assertFalse(menu.edit_packaging().enabled)
91
92- def test_set_upstrem_link__enabled_with_packaging_for_others(self):
93- # If a packging exists, the set_upstream link is enabled
94- # for the packaging owner.
95- menu, user = self.makeSourcePackageOverviewMenu(True, True)
96+ def test_set_upstrem_link__enabled_with_packaging_probation(self):
97+ # If a packging exists, the set_upstream link is not enabled
98+ # for probationary users.
99+ menu, user = self.makeSourcePackageOverviewMenu(True, None)
100 with person_logged_in(user):
101 self.assertFalse(menu.set_upstream().enabled)
102
103- def test_remove_packaging_link__enabled_with_packaging_for_others(self):
104- # If a packging exists, the remove_packaging link is enabled
105- # for the packaging owner.
106- menu, user = self.makeSourcePackageOverviewMenu(True, True)
107+ def test_remove_packaging_link__enabled_with_packaging_probation(self):
108+ # If a packging exists, the remove_packaging link is not enabled
109+ # for probationary users.
110+ menu, user = self.makeSourcePackageOverviewMenu(True, None)
111 with person_logged_in(user):
112 self.assertFalse(menu.remove_packaging().enabled)
113
114=== modified file 'lib/lp/registry/doc/sourcepackage.txt'
115--- lib/lp/registry/doc/sourcepackage.txt 2012-08-07 02:31:56 +0000
116+++ lib/lp/registry/doc/sourcepackage.txt 2012-09-19 18:22:24 +0000
117@@ -273,18 +273,12 @@
118 First, let's get some useful objects from the db.
119
120 >>> from lp.registry.model.sourcepackagename import SourcePackageName
121- >>> evolution = SourcePackageName.byName('evolution')
122- >>> a52dec = SourcePackageName.byName('a52dec')
123- >>> netapplet = SourcePackageName.byName('netapplet')
124 >>> firefox = SourcePackageName.byName('mozilla-firefox')
125 >>> pmount = SourcePackageName.byName('pmount')
126
127 >>> from lp.registry.model.distroseries import DistroSeries
128 >>> warty = DistroSeries.get(1)
129 >>> hoary = DistroSeries.get(3)
130- >>> sarge = DistroSeries.get(7)
131- >>> sid = DistroSeries.get(8)
132- >>> g2k5 = DistroSeries.get(9)
133
134 Now let's make sure that we can see a productseries for a source
135 package.
136@@ -294,62 +288,6 @@
137 >>> print sp.productseries.name
138 1.0
139
140-A source package's product series is None when it does not have a
141-Packaging entry. Historical packaging does not affect the state of the
142-productseries attribute.
143-
144- >>> from lp.registry.model.packaging import PackagingUtil
145- >>> hoary_a52dec = SourcePackage(sourcepackagename=a52dec,
146- ... distroseries=hoary)
147- >>> PackagingUtil().packagingEntryExists(
148- ... productseries=hoary_a52dec.productseries,
149- ... sourcepackagename=a52dec,
150- ... distroseries=hoary)
151- False
152-
153- >>> print hoary_a52dec.productseries
154- None
155-
156-Once a Packaging entry is created to link a distro series source package name
157-to a product series, the source package does have a product series.
158-
159- >>> from lp.registry.interfaces.packaging import PackagingType
160-
161- >>> user = factory.makePerson()
162- >>> a52dec_series = factory.makeProductSeries(name='ratty')
163- >>> packaging = PackagingUtil().createPackaging(
164- ... productseries=a52dec_series,
165- ... sourcepackagename=a52dec,
166- ... distroseries=hoary,
167- ... packaging=PackagingType.PRIME,
168- ... owner=user)
169-
170- >>> PackagingUtil().packagingEntryExists(
171- ... productseries=a52dec_series,
172- ... sourcepackagename=a52dec,
173- ... distroseries=hoary)
174- True
175-
176- >>> print hoary_a52dec.productseries.name
177- ratty
178-
179-Packaging entries can be deleted using PackagingUtil.deletePackaging. That
180-also removes the source package product series.
181-
182- >>> from lp.testing import person_logged_in
183- >>> with person_logged_in(user):
184- ... PackagingUtil().deletePackaging(
185- ... productseries=a52dec_series,
186- ... sourcepackagename=a52dec,
187- ... distroseries=hoary)
188- >>> PackagingUtil().packagingEntryExists(
189- ... productseries=a52dec_series,
190- ... sourcepackagename=a52dec,
191- ... distroseries=hoary)
192- False
193-
194- >>> print hoary_a52dec.productseries
195- None
196
197 Linkified changelogs are available through SourcePackageReleaseView: XXX
198 julian 2007-09-17 This is duplicating the page test. Instead it should
199@@ -537,5 +475,3 @@
200
201 >>> verifyObject(IHasTranslationImports, warty_firefox)
202 True
203-
204-
205
206=== modified file 'lib/lp/registry/interfaces/packaging.py'
207--- lib/lp/registry/interfaces/packaging.py 2011-12-24 16:54:44 +0000
208+++ lib/lp/registry/interfaces/packaging.py 2012-09-19 18:22:24 +0000
209@@ -98,9 +98,8 @@
210 """True, if the current user is allowed to delete this packaging,
211 else False.
212
213- People who created the packaging can delete it, as well as
214- people with upload rights for a source package, distribution
215- owners, members of the registry team and LP admin team.
216+ Non-probationary users can delete packaging links that they believe
217+ connect Ubuntu to bogus data.
218 """
219
220
221
222=== modified file 'lib/lp/registry/model/packaging.py'
223--- lib/lp/registry/model/packaging.py 2011-12-30 06:14:56 +0000
224+++ lib/lp/registry/model/packaging.py 2012-09-19 18:22:24 +0000
225@@ -74,12 +74,13 @@
226 if user is None:
227 return False
228 admin = getUtility(ILaunchpadCelebrities).admin
229- registry_experts = (
230- getUtility(ILaunchpadCelebrities).registry_experts)
231- return (
232- user.inTeam(self.owner) or
233- user.canAccess(self.sourcepackage, 'setBranch') or
234- user.inTeam(registry_experts) or user.inTeam(admin))
235+ registry_experts = (getUtility(ILaunchpadCelebrities).registry_experts)
236+ if (not user.is_probationary
237+ or user.inTeam(self.productseries.product.owner)
238+ or user.canAccess(self.sourcepackage, 'setBranch')
239+ or user.inTeam(registry_experts) or user.inTeam(admin)):
240+ return True
241+ return False
242
243 def destroySelf(self):
244 if not self.userCanDelete():
245
246=== modified file 'lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt'
247--- lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt 2010-03-03 00:40:03 +0000
248+++ lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging-concurrent-deletion.txt 2012-09-19 18:22:24 +0000
249@@ -7,10 +7,10 @@
250
251 The No Privilege User may open the same page in two browser tabs.
252
253- >>> first_browser = setupBrowser(auth='Basic no-priv@canonical.com:test')
254+ >>> first_browser = setupBrowser(auth='Basic test@canonical.com:test')
255 >>> first_browser.open('http://launchpad.dev/ubuntu/+source/alsa-utils')
256
257- >>> second_browser = setupBrowser(auth='Basic no-priv@canonical.com:test')
258+ >>> second_browser = setupBrowser(auth='Basic test@canonical.com:test')
259 >>> second_browser.open('http://launchpad.dev/ubuntu/+source/alsa-utils')
260
261 Then the user click the "Delete Link" button in the first tab. The
262
263=== modified file 'lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt'
264--- lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt 2012-06-14 10:34:55 +0000
265+++ lib/lp/registry/stories/packaging/xx-distributionsourcepackage-packaging.txt 2012-09-19 18:22:24 +0000
266@@ -20,7 +20,7 @@
267 >>> print extract_text(find_tag_by_id(content, 'packages_list'))
268 The Hoary Hedgehog Release (active development) Set upstream link
269 1.0.9a-4ubuntu1 release (main) 2005-09-15
270- The Warty Warthog Release (current stable release) alsa-utils trunk series
271+ The Warty Warthog Release (current stable release) alsa-utils trunk series
272 1.0.8-1ubuntu1 release (main) 2005-09-15
273 1.0.9a-4 release (main) 2005-09-16
274
275@@ -31,6 +31,7 @@
276 A button is displayed to authenticated users to delete existing
277 packaging links.
278
279+ >>> user_browser = setupBrowser(auth='Basic test@canonical.com:test')
280 >>> user_browser.open('http://launchpad.dev/ubuntu/+source/alsa-utils')
281 >>> link = user_browser.getLink(
282 ... url='/ubuntu/warty/+source/alsa-utils/+remove-packaging')
283
284=== modified file 'lib/lp/registry/tests/test_packaging.py'
285--- lib/lp/registry/tests/test_packaging.py 2012-06-29 08:40:05 +0000
286+++ lib/lp/registry/tests/test_packaging.py 2012-09-19 18:22:24 +0000
287@@ -51,7 +51,8 @@
288 def test_destroySelf_notifies(self):
289 """destroySelf creates a notification."""
290 packaging = self.factory.makePackagingLink()
291- with person_logged_in(packaging.owner):
292+ user = self.factory.makePerson(karma=200)
293+ with person_logged_in(user):
294 with EventRecorder() as recorder:
295 removeSecurityProxy(packaging).destroySelf()
296 (event,) = recorder.events
297@@ -67,7 +68,7 @@
298 packaging.productseries, packaging.sourcepackagename,
299 packaging.distroseries)
300
301- def test_destroySelf__not_allowed_for_arbitrary_user(self):
302+ def test_destroySelf__not_allowed_for_probationary_user(self):
303 """Arbitrary users cannot delete a packaging."""
304 packaging = self.factory.makePackagingLink()
305 packaging_util = getUtility(IPackagingUtil)
306@@ -77,14 +78,15 @@
307 packaging.productseries, packaging.sourcepackagename,
308 packaging.distroseries)
309
310- def test_destroySelf__allowed_for_packaging_owner(self):
311- """A packaging owner can delete a packaging."""
312+ def test_destroySelf__allowed_for_non_probationary_user(self):
313+ """An experienced user can delete a packaging."""
314 packaging = self.factory.makePackagingLink()
315 sourcepackagename = packaging.sourcepackagename
316 distroseries = packaging.distroseries
317 productseries = packaging.productseries
318 packaging_util = getUtility(IPackagingUtil)
319- with person_logged_in(packaging.owner):
320+ user = self.factory.makePerson(karma=200)
321+ with person_logged_in(user):
322 packaging_util.deletePackaging(
323 packaging.productseries, packaging.sourcepackagename,
324 packaging.distroseries)
325@@ -92,20 +94,6 @@
326 packaging_util.packagingEntryExists(
327 sourcepackagename, distroseries, productseries))
328
329- def test_destroySelf__allowed_for_distro_owner(self):
330- """A distribution owner can delete a packaging link."""
331- packaging = self.factory.makePackagingLink()
332- sourcepackagename = packaging.sourcepackagename
333- distroseries = packaging.distroseries
334- productseries = packaging.productseries
335- packaging_util = getUtility(IPackagingUtil)
336- with person_logged_in(distroseries.distribution.owner):
337- packaging_util.deletePackaging(
338- productseries, sourcepackagename, distroseries)
339- self.assertFalse(
340- packaging_util.packagingEntryExists(
341- sourcepackagename, distroseries, productseries))
342-
343 def test_destroySelf__allowed_for_uploader(self):
344 """A person with upload rights for the sourcepackage can
345 delete a packaging link.
346@@ -287,7 +275,8 @@
347 """Deleting a Packaging creates a notification."""
348 packaging_util = getUtility(IPackagingUtil)
349 packaging = self.factory.makePackagingLink()
350- with person_logged_in(packaging.owner):
351+ user = self.factory.makePerson(karma=200)
352+ with person_logged_in(user):
353 with EventRecorder() as recorder:
354 packaging_util.deletePackaging(
355 packaging.productseries, packaging.sourcepackagename,
356
357=== modified file 'lib/lp/registry/tests/test_sourcepackage.py'
358--- lib/lp/registry/tests/test_sourcepackage.py 2012-06-28 01:14:33 +0000
359+++ lib/lp/registry/tests/test_sourcepackage.py 2012-09-19 18:22:24 +0000
360@@ -14,7 +14,6 @@
361 from zope.component import getUtility
362 from zope.interface.verify import verifyObject
363 from zope.security.checker import canAccess
364-from zope.security.interfaces import Unauthorized
365 from zope.security.management import checkPermission
366 from zope.security.proxy import removeSecurityProxy
367
368@@ -283,10 +282,11 @@
369
370 def test_deletePackaging(self):
371 """Ensure deletePackaging completely removes packaging."""
372+ user = self.factory.makePerson(karma=200)
373 packaging = self.factory.makePackagingLink()
374 packaging_id = packaging.id
375 store = Store.of(packaging)
376- with person_logged_in(packaging.owner):
377+ with person_logged_in(user):
378 packaging.sourcepackage.deletePackaging()
379 result = store.find(Packaging, Packaging.id == packaging_id)
380 self.assertIs(None, result.one())
381@@ -305,11 +305,12 @@
382 sourcepackage = self.factory.makeSourcePackage()
383 productseries = self.factory.makeProductSeries()
384 other_series = self.factory.makeProductSeries()
385- owner = self.factory.makePerson()
386+ user = self.factory.makePerson(karma=200)
387+ registrant = self.factory.makePerson()
388 with EventRecorder() as recorder:
389- with person_logged_in(owner):
390- sourcepackage.setPackaging(productseries, owner=owner)
391- sourcepackage.setPackaging(other_series, owner=owner)
392+ with person_logged_in(user):
393+ sourcepackage.setPackaging(productseries, owner=registrant)
394+ sourcepackage.setPackaging(other_series, owner=registrant)
395 packaging = sourcepackage.direct_packaging
396 self.assertEqual(packaging.productseries, other_series)
397 # The first call of setPackaging() created an ObjectCreatedEvent;
398@@ -321,21 +322,6 @@
399 self.assertIsInstance(event2, ObjectDeletedEvent)
400 self.assertIsInstance(event3, ObjectCreatedEvent)
401
402- def test_setPackaging__change_existing_entry_different_users(self):
403- """An ordinary user cannot change a Packaging defined by
404- somebody else.
405- """
406- sourcepackage = self.factory.makeSourcePackage()
407- productseries = self.factory.makeProductSeries()
408- other_series = self.factory.makeProductSeries()
409- owner = self.factory.makePerson()
410- other_user = self.factory.makePerson()
411- sourcepackage.setPackaging(productseries, owner=owner)
412- with person_logged_in(other_user):
413- self.assertRaises(
414- Unauthorized, sourcepackage.setPackaging,
415- other_series, owner=other_user)
416-
417 def test_setPackagingReturnSharingDetailPermissions__ordinary_user(self):
418 """An ordinary user can create a packaging link but he cannot
419 set the series' branch or translation syncronisation settings,
420@@ -343,7 +329,7 @@
421 """
422 sourcepackage = self.factory.makeSourcePackage()
423 productseries = self.factory.makeProductSeries()
424- packaging_owner = self.factory.makePerson()
425+ packaging_owner = self.factory.makePerson(karma=100)
426 with person_logged_in(packaging_owner):
427 permissions = (
428 sourcepackage.setPackagingReturnSharingDetailPermissions(
429@@ -370,19 +356,20 @@
430 synchronisation settings, or the translation usage settings of the
431 product.
432 """
433+ user = self.factory.makePerson(karma=100)
434 packaging = self.factory.makePackagingLink()
435 sourcepackage = packaging.sourcepackage
436 productseries = packaging.productseries
437- with person_logged_in(packaging.owner):
438+ with person_logged_in(user):
439 permissions = sourcepackage.getSharingDetailPermissions()
440 self.assertEqual(productseries, sourcepackage.productseries)
441 self.assertFalse(
442- packaging.owner.canWrite(productseries, 'branch'))
443+ user.canWrite(productseries, 'branch'))
444 self.assertFalse(
445- packaging.owner.canWrite(
446+ user.canWrite(
447 productseries, 'translations_autoimport_mode'))
448 self.assertFalse(
449- packaging.owner.canWrite(
450+ user.canWrite(
451 productseries.product, 'translations_usage'))
452 expected = {
453 'user_can_change_product_series': True,
454@@ -397,37 +384,6 @@
455 return self.factory.makeProductSeries(
456 owner=self.factory.makePerson())
457
458- def test_getSharingDetailPermissions__series_owner(self):
459- """A product series owner can create a packaging link, and he can
460- set the series' branch or translation syncronisation settings,
461- but he cannot set the translation usage settings of the product.
462- """
463- productseries = self.makeDistinctOwnerProductSeries()
464- series_owner = productseries.owner
465- # Ensure productseries owner is distinct from product owner.
466- productseries = self.factory.makeProductSeries(
467- owner=series_owner)
468- with person_logged_in(series_owner):
469- packaging = self.factory.makePackagingLink(
470- productseries=productseries, owner=series_owner)
471- sourcepackage = packaging.sourcepackage
472- permissions = sourcepackage.getSharingDetailPermissions()
473- self.assertEqual(productseries, sourcepackage.productseries)
474- self.assertTrue(series_owner.canWrite(productseries, 'branch'))
475- self.assertTrue(
476- series_owner.canWrite(
477- productseries, 'translations_autoimport_mode'))
478- self.assertFalse(
479- series_owner.canWrite(
480- productseries.product, 'translations_usage'))
481- expected = {
482- 'user_can_change_product_series': True,
483- 'user_can_change_branch': True,
484- 'user_can_change_translation_usage': False,
485- 'user_can_change_translations_autoimport_mode': True,
486- }
487- self.assertEqual(expected, permissions)
488-
489 def test_getSharingDetailPermissions__product_owner(self):
490 """A product owner can create a packaging link, and he can set the
491 series' branch and the translation syncronisation settings, and the
492@@ -463,7 +419,7 @@
493 Afterward, random people cannot change product series.
494 """
495 sourcepackage = self.factory.makeSourcePackage()
496- person1 = self.factory.makePerson()
497+ person1 = self.factory.makePerson(karma=100)
498 person2 = self.factory.makePerson()
499
500 def can_change_product_series():
501@@ -553,10 +509,11 @@
502
503 def test_deletePackaging(self):
504 """Deleting a packaging should work."""
505+ user = self.factory.makePerson(karma=200)
506 packaging = self.factory.makePackagingLink()
507 sourcepackage = packaging.sourcepackage
508 transaction.commit()
509- self.wsObject(sourcepackage, user=packaging.owner).deletePackaging()
510+ self.wsObject(sourcepackage, user=user).deletePackaging()
511 transaction.commit()
512 self.assertIs(None, sourcepackage.direct_packaging)
513
514
515=== modified file 'lib/lp/testing/factory.py'
516--- lib/lp/testing/factory.py 2012-09-14 18:23:50 +0000
517+++ lib/lp/testing/factory.py 2012-09-19 18:22:24 +0000
518@@ -214,6 +214,7 @@
519 from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
520 from lp.registry.interfaces.ssh import ISSHKeySet
521 from lp.registry.model.commercialsubscription import CommercialSubscription
522+from lp.registry.model.karma import KarmaTotalCache
523 from lp.registry.model.milestone import Milestone
524 from lp.registry.model.suitesourcepackage import SuiteSourcePackage
525 from lp.services.config import config
526@@ -607,7 +608,7 @@
527 self, email=None, name=None, displayname=None, account_status=None,
528 email_address_status=None, hide_email_addresses=False,
529 time_zone=None, latitude=None, longitude=None, description=None,
530- selfgenerated_bugnotifications=False, member_of=()):
531+ selfgenerated_bugnotifications=False, member_of=(), karma=None):
532 """Create and return a new, arbitrary Person.
533
534 :param email: The email address for the new person.
535@@ -668,6 +669,10 @@
536 with person_logged_in(team.teamowner):
537 team.addMember(person, team.teamowner)
538
539+ if karma is not None:
540+ with dbuser('karma'):
541+ # Give the user karma to make the user non-probationary.
542+ KarmaTotalCache(person=person.id, karma_total=karma)
543 # Ensure updated ValidPersonCache
544 flush_database_updates()
545 return person
546
547=== modified file 'lib/lp/translations/browser/tests/test_sharing_details.py'
548--- lib/lp/translations/browser/tests/test_sharing_details.py 2012-08-06 06:09:19 +0000
549+++ lib/lp/translations/browser/tests/test_sharing_details.py 2012-09-19 18:22:24 +0000
550@@ -5,7 +5,6 @@
551
552
553 import re
554-
555 from lazr.restful.interfaces import IJSONRequestCache
556 from soupmatchers import (
557 HTMLContains,
558@@ -101,7 +100,9 @@
559 sourcepackage=self.sourcepackage, name='ubuntu-only')
560 self.shared_template_ubuntu_side = self.factory.makePOTemplate(
561 sourcepackage=self.sourcepackage, name='shared-template')
562- self.productseries = self.factory.makeProductSeries()
563+ self.privileged_user = self.factory.makePerson(karma=200)
564+ product = self.factory.makeProduct(owner=self.privileged_user)
565+ self.productseries = self.factory.makeProductSeries(product=product)
566 self.shared_template_upstream_side = self.factory.makePOTemplate(
567 productseries=self.productseries, name='shared-template')
568 self.upstream_only_template = self.factory.makePOTemplate(
569@@ -566,8 +567,8 @@
570 self.assertEqual(
571 expected, self.view.set_packaging_link.escapedtext)
572
573- def test_set_packaging_link__with_packaging_any_user(self):
574- # If packaging is configured, arbitrary users do no see
575+ def test_set_packaging_link__with_packaging_probationary_user(self):
576+ # If packaging is configured, probationary users do no see
577 # the "set packaging" link.
578 self.configureSharing()
579 expected = self._getExpectedPackagingLink(
580@@ -588,7 +589,7 @@
581 expected = self._getExpectedPackagingLink(
582 id='set-packaging', url='+edit-packaging', icon='add',
583 text='Set upstream link', visible=True)
584- with person_logged_in(self.sourcepackage.packaging.owner):
585+ with person_logged_in(self.privileged_user):
586 view = SourcePackageTranslationSharingDetailsView(
587 self.sourcepackage, LaunchpadTestRequest())
588 view.initialize()
589@@ -617,8 +618,8 @@
590 self.assertEqual(
591 expected, self.view.change_packaging_link.escapedtext)
592
593- def test_change_packaging_link__with_packaging_any_user(self):
594- # If packaging is configured, arbitrary users do no see
595+ def test_change_packaging_link__with_packaging_probationary_user(self):
596+ # If packaging is configured, probationary users do no see
597 # the "change packaging" link.
598 self.configureSharing()
599 expected = self._getExpectedPackagingLink(
600@@ -639,7 +640,7 @@
601 expected = self._getExpectedPackagingLink(
602 id='change-packaging', url='+edit-packaging', icon='edit',
603 text='Change upstream link', visible=True)
604- with person_logged_in(self.sourcepackage.packaging.owner):
605+ with person_logged_in(self.privileged_user):
606 view = SourcePackageTranslationSharingDetailsView(
607 self.sourcepackage, LaunchpadTestRequest())
608 view.initialize()
609@@ -668,8 +669,8 @@
610 self.assertEqual(
611 expected, self.view.remove_packaging_link.escapedtext)
612
613- def test_remove_packaging_link__with_packaging_any_user(self):
614- # If packaging is configured, arbitrary users do no see
615+ def test_remove_packaging_link__with_packaging_probationary_user(self):
616+ # If packaging is configured, probationary users do no see
617 # the "remove packaging" link.
618 self.configureSharing()
619 expected = self._getExpectedPackagingLink(
620@@ -690,7 +691,7 @@
621 expected = self._getExpectedPackagingLink(
622 id='remove-packaging', url='+remove-packaging', icon='remove',
623 text='Remove upstream link', visible=True)
624- with person_logged_in(self.sourcepackage.packaging.owner):
625+ with person_logged_in(self.privileged_user):
626 view = SourcePackageTranslationSharingDetailsView(
627 self.sourcepackage, LaunchpadTestRequest())
628 view.initialize()
629
630=== modified file 'lib/lp/translations/tests/test_translationpackagingjob.py'
631--- lib/lp/translations/tests/test_translationpackagingjob.py 2012-04-24 18:41:35 +0000
632+++ lib/lp/translations/tests/test_translationpackagingjob.py 2012-09-19 18:22:24 +0000
633@@ -288,7 +288,8 @@
634 packaging.productseries, packaging.sourcepackage,
635 TranslationSplitJob)
636 self.assertEqual([], finder.find())
637- with person_logged_in(packaging.owner):
638+ user = self.factory.makePerson(karma=200)
639+ with person_logged_in(user):
640 getUtility(IPackagingUtil).deletePackaging(
641 packaging.productseries, packaging.sourcepackagename,
642 packaging.distroseries)