Merge lp:~cprov/launchpad/bug-422965-archive-permission-api into lp:launchpad

Proposed by Celso Providelo
Status: Merged
Merged at revision: not available
Proposed branch: lp:~cprov/launchpad/bug-422965-archive-permission-api
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~cprov/launchpad/bug-422965-archive-permission-api
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+12006@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Celso Providelo (cprov) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

= Summary =

This branch fixes https://bugs.edge.launchpad.net/bugs/422965.

Now the methods for reading and adjusting archive permissions are restricted to IArchive lp.Edit permission (owners) instead of the *special* IArchivePermissionSet (only tech board)

- From now own ubuntu-drivers will be able to allow new uploaders in ubuntu primary archive and PPA owners will be able to do the same for their PPAs.

== Tests ==

./bin/test -vv -t xx-archive.txt

== Demo and Q/A ==

Create a PPA if the user you are logged in doesn't have one, otherwise adjust the parameters of the code snipped below

1. Reading permissions:
{{{
    user = lp.people['no-priv']
    ppa = lp.me.getPPAByName(name='ppa')
    print 'Permission for %s in %s' % (
        user.display_name, ppa.displayname)
    for perm in ppa.getPermissionsForPerson(person=user):
        print perm.permission
}}}

2. Setting permission:
{{{
    user = lp.people['no-priv']
    ppa = lp.me.getPPAByName(name='ppa')
    ppa.newComponentUploader(person=user, component_name='main')
}}}

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/soyuz/stories/webservice/xx-archive.txt
  lib/lp/soyuz/interfaces/archive.py
  lib/lp/soyuz/configure.zcml
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkqykjkACgkQ7KBXuXyZSjB0xQCgkLYFyzzQ87e23tJDuY7AmJDw
RlkAn1yplbsf24s82ziAtkXXhvfsziCW
=R4q7
-----END PGP SIGNATURE-----

== Pylint notices ==

lib/lp/soyuz/interfaces/archive.py
    39: [F0401] Unable to import 'lazr.enum' (No module named enum)
    52: [F0401] Unable to import 'lazr.restful.declarations' (No module named restful)
    58: [F0401] Unable to import 'lazr.restful.fields' (No module named restful)

Revision history for this message
Paul Hummer (rockstar) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/configure.zcml'
2--- lib/lp/soyuz/configure.zcml 2009-09-03 15:04:13 +0000
3+++ lib/lp/soyuz/configure.zcml 2009-09-04 18:18:39 +0000
4@@ -394,6 +394,7 @@
5 interface="lp.soyuz.interfaces.archive.IArchiveAppend"/>
6 <require
7 permission="launchpad.Edit"
8+ interface="lp.soyuz.interfaces.archive.IArchiveEdit"
9 set_attributes="description displayname"/>
10 <require
11 permission="launchpad.Commercial"
12@@ -465,16 +466,16 @@
13 packagesetsForUploader
14 packagesetsForSource
15 packagesetsForSourceUploader
16- isSourceUploadAllowed"/>
17- <require
18- permission="launchpad.Edit"
19- attributes="
20+ isSourceUploadAllowed
21 newPackageUploader
22 newComponentUploader
23 newQueueAdmin
24 deletePackageUploader
25 deleteComponentUploader
26- deleteQueueAdmin
27+ deleteQueueAdmin"/>
28+ <require
29+ permission="launchpad.Edit"
30+ attributes="
31 newPackagesetUploader
32 deletePackagesetUploader"/>
33 </securedutility>
34
35=== modified file 'lib/lp/soyuz/interfaces/archive.py'
36--- lib/lp/soyuz/interfaces/archive.py 2009-09-02 21:28:11 +0000
37+++ lib/lp/soyuz/interfaces/archive.py 2009-09-17 17:24:04 +0000
38@@ -16,6 +16,7 @@
39 'DistroSeriesNotFound',
40 'IArchive',
41 'IArchiveAppend',
42+ 'IArchiveEdit',
43 'IArchiveView',
44 'IArchiveEditDependenciesForm',
45 'IArchivePublic',
46@@ -336,68 +337,6 @@
47 :return: A list of `IArchivePermission` records.
48 """
49
50- @operation_parameters(person=Reference(schema=IPerson))
51- # Really IArchivePermission, set below to avoid circular import.
52- @operation_returns_collection_of(Interface)
53- @export_read_operation()
54- def getPermissionsForPerson(person):
55- """Return the `IArchivePermission` records applicable to the person.
56-
57- :param person: An `IPerson`
58- :return: A list of `IArchivePermission` records.
59- """
60-
61- @operation_parameters(
62- source_package_name=TextLine(
63- title=_("Source Package Name"), required=True))
64- # Really IArchivePermission, set below to avoid circular import.
65- @operation_returns_collection_of(Interface)
66- @export_read_operation()
67- def getUploadersForPackage(source_package_name):
68- """Return `IArchivePermission` records for the package's uploaders.
69-
70- :param source_package_name: An `ISourcePackageName` or textual name
71- for the source package.
72- :return: A list of `IArchivePermission` records.
73- """
74-
75- @operation_parameters(
76- component_name=TextLine(title=_("Component Name"), required=False))
77- # Really IArchivePermission, set below to avoid circular import.
78- @operation_returns_collection_of(Interface)
79- @export_read_operation()
80- def getUploadersForComponent(component_name=None):
81- """Return `IArchivePermission` records for the component's uploaders.
82-
83- :param component_name: An `IComponent` or textual name for the
84- component.
85- :return: A list of `IArchivePermission` records.
86- """
87-
88- @operation_parameters(
89- component_name=TextLine(title=_("Component Name"), required=True))
90- # Really IArchivePermission, set below to avoid circular import.
91- @operation_returns_collection_of(Interface)
92- @export_read_operation()
93- def getQueueAdminsForComponent(component_name):
94- """Return `IArchivePermission` records for authorised queue admins.
95-
96- :param component_name: An `IComponent` or textual name for the
97- component.
98- :return: A list of `IArchivePermission` records.
99- """
100-
101- @operation_parameters(person=Reference(schema=IPerson))
102- # Really IArchivePermission, set below to avoid circular import.
103- @operation_returns_collection_of(Interface)
104- @export_read_operation()
105- def getComponentsForQueueAdmin(person):
106- """Return `IArchivePermission` for the person's queue admin components
107-
108- :param person: An `IPerson`
109- :return: A list of `IArchivePermission` records.
110- """
111-
112 def canUpload(person, component_or_package=None):
113 """Check to see if person is allowed to upload to component.
114
115@@ -423,103 +362,6 @@
116 queue for items with 'component'.
117 """
118
119- # The following three factory methods are not in the
120- # IArchiveEditRestricted interface because the rights to use them
121- # does not depend on edit permissions to the archive. The code they
122- # contain does all the necessary security checking and is well
123- # tested in xx-archive.txt and archivepermissions.txt.
124-
125- @operation_parameters(
126- person=Reference(schema=IPerson),
127- source_package_name=TextLine(
128- title=_("Source Package Name"), required=True))
129- # Really IArchivePermission, set below to avoid circular import.
130- @export_factory_operation(Interface, [])
131- def newPackageUploader(person, source_package_name):
132- """Add permisson for a person to upload a package to this archive.
133-
134- :param person: An `IPerson` whom should be given permission.
135- :param source_package_name: An `ISourcePackageName` or textual package
136- name.
137- :return: An `IArchivePermission` which is the newly-created
138- permission.
139- """
140-
141- @operation_parameters(
142- person=Reference(schema=IPerson),
143- component_name=TextLine(
144- title=_("Component Name"), required=True))
145- # Really IArchivePermission, set below to avoid circular import.
146- @export_factory_operation(Interface, [])
147- def newComponentUploader(person, component_name):
148- """Add permission for a person to upload to a component.
149-
150- :param person: An `IPerson` whom should be given permission.
151- :param component: An `IComponent` or textual component name.
152- :return: An `IArchivePermission` which is the newly-created
153- permission.
154- :raises InvalidComponent: if this archive is a PPA and the component
155- is not 'main'.
156- """
157-
158- @operation_parameters(
159- person=Reference(schema=IPerson),
160- component_name=TextLine(
161- title=_("Component Name"), required=True))
162- # Really IArchivePermission, set below to avoid circular import.
163- @export_factory_operation(Interface, [])
164- def newQueueAdmin(person, component_name):
165- """Add permission for a person to administer a distroseries queue.
166-
167- The supplied person will gain permission to administer the
168- distroseries queue for packages in the supplied component.
169-
170- :param person: An `IPerson` whom should be given permission.
171- :param component: An `IComponent` or textual component name.
172- :return: An `IArchivePermission` which is the newly-created
173- permission.
174- """
175-
176- @operation_parameters(
177- person=Reference(schema=IPerson),
178- source_package_name=TextLine(
179- title=_("Source Package Name"), required=True))
180- @export_write_operation()
181- def deletePackageUploader(person, source_package_name):
182- """Revoke permission for the person to upload the package.
183-
184- :param person: An `IPerson` whose permission should be revoked.
185- :param source_package_name: An `ISourcePackageName` or textual package
186- name.
187- """
188-
189- @operation_parameters(
190- person=Reference(schema=IPerson),
191- component_name=TextLine(
192- title=_("Component Name"), required=True))
193- @export_write_operation()
194- def deleteComponentUploader(person, component_name):
195- """Revoke permission for the person to upload to the component.
196-
197- :param person: An `IPerson` whose permission should be revoked.
198- :param component: An `IComponent` or textual component name.
199- """
200-
201- @operation_parameters(
202- person=Reference(schema=IPerson),
203- component_name=TextLine(
204- title=_("Component Name"), required=True))
205- @export_write_operation()
206- def deleteQueueAdmin(person, component_name):
207- """Revoke permission for the person to administer distroseries queues.
208-
209- The supplied person will lose permission to administer the
210- distroseries queue for packages in the supplied component.
211-
212- :param person: An `IPerson` whose permission should be revoked.
213- :param component: An `IComponent` or textual component name.
214- """
215-
216 def getFileByName(filename):
217 """Return the corresponding `ILibraryFileAlias` in this context.
218
219@@ -926,6 +768,68 @@
220 could not be found.
221 """
222
223+ @operation_parameters(person=Reference(schema=IPerson))
224+ # Really IArchivePermission, set below to avoid circular import.
225+ @operation_returns_collection_of(Interface)
226+ @export_read_operation()
227+ def getPermissionsForPerson(person):
228+ """Return the `IArchivePermission` records applicable to the person.
229+
230+ :param person: An `IPerson`
231+ :return: A list of `IArchivePermission` records.
232+ """
233+
234+ @operation_parameters(
235+ source_package_name=TextLine(
236+ title=_("Source Package Name"), required=True))
237+ # Really IArchivePermission, set below to avoid circular import.
238+ @operation_returns_collection_of(Interface)
239+ @export_read_operation()
240+ def getUploadersForPackage(source_package_name):
241+ """Return `IArchivePermission` records for the package's uploaders.
242+
243+ :param source_package_name: An `ISourcePackageName` or textual name
244+ for the source package.
245+ :return: A list of `IArchivePermission` records.
246+ """
247+
248+ @operation_parameters(
249+ component_name=TextLine(title=_("Component Name"), required=False))
250+ # Really IArchivePermission, set below to avoid circular import.
251+ @operation_returns_collection_of(Interface)
252+ @export_read_operation()
253+ def getUploadersForComponent(component_name=None):
254+ """Return `IArchivePermission` records for the component's uploaders.
255+
256+ :param component_name: An `IComponent` or textual name for the
257+ component.
258+ :return: A list of `IArchivePermission` records.
259+ """
260+
261+ @operation_parameters(
262+ component_name=TextLine(title=_("Component Name"), required=True))
263+ # Really IArchivePermission, set below to avoid circular import.
264+ @operation_returns_collection_of(Interface)
265+ @export_read_operation()
266+ def getQueueAdminsForComponent(component_name):
267+ """Return `IArchivePermission` records for authorised queue admins.
268+
269+ :param component_name: An `IComponent` or textual name for the
270+ component.
271+ :return: A list of `IArchivePermission` records.
272+ """
273+
274+ @operation_parameters(person=Reference(schema=IPerson))
275+ # Really IArchivePermission, set below to avoid circular import.
276+ @operation_returns_collection_of(Interface)
277+ @export_read_operation()
278+ def getComponentsForQueueAdmin(person):
279+ """Return `IArchivePermission` for the person's queue admin components
280+
281+ :param person: An `IPerson`
282+ :return: A list of `IArchivePermission` records.
283+ """
284+
285
286 class IArchiveAppend(Interface):
287 """Archive interface for operations restricted by append privilege."""
288@@ -1043,7 +947,102 @@
289 """
290
291
292-class IArchive(IArchivePublic, IArchiveAppend, IArchiveView):
293+class IArchiveEdit(Interface):
294+ """Archive interface for operations restricted by edit privilege."""
295+
296+ @operation_parameters(
297+ person=Reference(schema=IPerson),
298+ source_package_name=TextLine(
299+ title=_("Source Package Name"), required=True))
300+ # Really IArchivePermission, set below to avoid circular import.
301+ @export_factory_operation(Interface, [])
302+ def newPackageUploader(person, source_package_name):
303+ """Add permisson for a person to upload a package to this archive.
304+
305+ :param person: An `IPerson` whom should be given permission.
306+ :param source_package_name: An `ISourcePackageName` or textual package
307+ name.
308+ :return: An `IArchivePermission` which is the newly-created
309+ permission.
310+ """
311+
312+ @operation_parameters(
313+ person=Reference(schema=IPerson),
314+ component_name=TextLine(
315+ title=_("Component Name"), required=True))
316+ # Really IArchivePermission, set below to avoid circular import.
317+ @export_factory_operation(Interface, [])
318+ def newComponentUploader(person, component_name):
319+ """Add permission for a person to upload to a component.
320+
321+ :param person: An `IPerson` whom should be given permission.
322+ :param component: An `IComponent` or textual component name.
323+ :return: An `IArchivePermission` which is the newly-created
324+ permission.
325+ :raises InvalidComponent: if this archive is a PPA and the component
326+ is not 'main'.
327+ """
328+
329+ @operation_parameters(
330+ person=Reference(schema=IPerson),
331+ component_name=TextLine(
332+ title=_("Component Name"), required=True))
333+ # Really IArchivePermission, set below to avoid circular import.
334+ @export_factory_operation(Interface, [])
335+ def newQueueAdmin(person, component_name):
336+ """Add permission for a person to administer a distroseries queue.
337+
338+ The supplied person will gain permission to administer the
339+ distroseries queue for packages in the supplied component.
340+
341+ :param person: An `IPerson` whom should be given permission.
342+ :param component: An `IComponent` or textual component name.
343+ :return: An `IArchivePermission` which is the newly-created
344+ permission.
345+ """
346+
347+ @operation_parameters(
348+ person=Reference(schema=IPerson),
349+ source_package_name=TextLine(
350+ title=_("Source Package Name"), required=True))
351+ @export_write_operation()
352+ def deletePackageUploader(person, source_package_name):
353+ """Revoke permission for the person to upload the package.
354+
355+ :param person: An `IPerson` whose permission should be revoked.
356+ :param source_package_name: An `ISourcePackageName` or textual package
357+ name.
358+ """
359+
360+ @operation_parameters(
361+ person=Reference(schema=IPerson),
362+ component_name=TextLine(
363+ title=_("Component Name"), required=True))
364+ @export_write_operation()
365+ def deleteComponentUploader(person, component_name):
366+ """Revoke permission for the person to upload to the component.
367+
368+ :param person: An `IPerson` whose permission should be revoked.
369+ :param component: An `IComponent` or textual component name.
370+ """
371+
372+ @operation_parameters(
373+ person=Reference(schema=IPerson),
374+ component_name=TextLine(
375+ title=_("Component Name"), required=True))
376+ @export_write_operation()
377+ def deleteQueueAdmin(person, component_name):
378+ """Revoke permission for the person to administer distroseries queues.
379+
380+ The supplied person will lose permission to administer the
381+ distroseries queue for packages in the supplied component.
382+
383+ :param person: An `IPerson` whose permission should be revoked.
384+ :param component: An `IComponent` or textual component name.
385+ """
386+
387+
388+class IArchive(IArchivePublic, IArchiveAppend, IArchiveEdit, IArchiveView):
389 """Main Archive interface."""
390 export_as_webservice_entry()
391
392
393=== modified file 'lib/lp/soyuz/stories/webservice/xx-archive.txt'
394--- lib/lp/soyuz/stories/webservice/xx-archive.txt 2009-09-04 07:29:56 +0000
395+++ lib/lp/soyuz/stories/webservice/xx-archive.txt 2009-09-04 18:18:39 +0000
396@@ -76,9 +76,9 @@
397
398 The archive has the following attributes:
399
400- >>> main_archive = webservice.get(
401+ >>> ubuntu_main_archive = webservice.get(
402 ... ubuntutest['main_archive_link']).jsonBody()
403- >>> pprint_entry(main_archive)
404+ >>> pprint_entry(ubuntu_main_archive)
405 dependencies_collection_link: u'http://.../ubuntutest/+archive/primary/dependencies'
406 description: None
407 displayname: u'Primary Archive for Ubuntu Test'
408@@ -186,10 +186,10 @@
409 Permission collections can be retrieved with custom operations on the
410 archive.
411
412-getPermissionsForPerson returns all the permissions that a user has.
413+`getPermissionsForPerson` returns all the permissions that a user has.
414
415- >>> ubuntu_team = webservice.get("/~ubuntu-team").jsonBody()
416- >>> permissions = webservice.named_get(
417+ >>> ubuntu_team = user_webservice.get("/~ubuntu-team").jsonBody()
418+ >>> permissions = user_webservice.named_get(
419 ... ubuntutest['main_archive_link'], 'getPermissionsForPerson',
420 ... person=ubuntu_team['self_link']).jsonBody()
421
422@@ -211,11 +211,11 @@
423 Archive Upload Rights ...~ubuntu-team main None
424 Archive Upload Rights ...~ubuntu-team universe None
425
426-getUploadersForPackage returns all the permissions where someone can
427+`getUploadersForPackage` returns all the permissions where someone can
428 upload a particular package.
429
430 >>> def show_mozilla_permissions():
431- ... permissions = webservice.named_get(
432+ ... permissions = user_webservice.named_get(
433 ... ubuntu['main_archive_link'], 'getUploadersForPackage',
434 ... source_package_name='mozilla-firefox').jsonBody()
435 ... show_permission_entries(permissions)
436@@ -225,17 +225,35 @@
437
438 Passing a bad package name results in an error:
439
440- >>> print webservice.named_get(
441+ >>> print user_webservice.named_get(
442 ... ubuntu['main_archive_link'], 'getUploadersForPackage',
443 ... source_package_name="badpackage")
444 HTTP/1.1 400 Bad Request
445 ...
446
447-newPackageUploader() is a factory function that adds a new permission for
448-a person to upload a package.
449+Colin is a valid member of the team who owns the ubuntu primary archive.
450+
451+ >>> from canonical.launchpad.testing.pages import webservice_for_person
452+ >>> from canonical.launchpad.webapp.interfaces import OAuthPermission
453+ >>> from lp.registry.interfaces.distribution import IDistributionSet
454+
455+ >>> login(ANONYMOUS)
456+ >>> cjwatson = getUtility(IPersonSet).getByName('kamion')
457+ >>> ubuntu_db = getUtility(IDistributionSet).getByName('ubuntu')
458+ >>> cjwatson.inTeam(ubuntu_db.main_archive.owner)
459+ True
460+
461+ >>> logout()
462+
463+ >>> cjwatson_webservice = webservice_for_person(
464+ ... cjwatson, permission=OAuthPermission.WRITE_PUBLIC)
465+
466+
467+`newPackageUploader` is a factory function that adds a new permission
468+for a person to upload a package.
469
470 >>> name12 = webservice.get("/~name12").jsonBody()
471- >>> response = webservice.named_post(
472+ >>> response = cjwatson_webservice.named_post(
473 ... ubuntu['main_archive_link'], 'newPackageUploader', {},
474 ... person=name12['self_link'],
475 ... source_package_name='mozilla-firefox')
476@@ -243,7 +261,7 @@
477 HTTP/1.1 201 Created
478 ...
479
480- >>> new_permission = webservice.get(
481+ >>> new_permission = user_webservice.get(
482 ... response.getHeader('Location')).jsonBody()
483 >>> print new_permission['self_link']
484 http://.../ubuntu/+archive/primary/+upload/name12?type=packagename&item=mozilla-firefox
485@@ -254,7 +272,7 @@
486
487 deletePackageUploader() removes that permission:
488
489- >>> print webservice.named_post(
490+ >>> print cjwatson_webservice.named_post(
491 ... ubuntu['main_archive_link'], 'deletePackageUploader', {},
492 ... person=name12['self_link'],
493 ... source_package_name='mozilla-firefox')
494@@ -270,7 +288,7 @@
495 upload to a particular component:
496
497 >>> def show_component_permissions(component=None):
498- ... permissions = webservice.named_get(
499+ ... permissions = user_webservice.named_get(
500 ... ubuntu['main_archive_link'], 'getUploadersForComponent',
501 ... component_name=component).jsonBody()
502 ... show_permission_entries(permissions)
503@@ -280,7 +298,7 @@
504
505 Passing a bad component name results in an error:
506
507- >>> print webservice.named_get(
508+ >>> print cjwatson_webservice.named_get(
509 ... ubuntu['main_archive_link'], 'getUploadersForComponent',
510 ... component_name="badcomponent")
511 HTTP/1.1 400 Bad Request
512@@ -296,7 +314,7 @@
513 newComponentUploader adds a new permission for a person to upload to a
514 component.
515
516- >>> response = webservice.named_post(
517+ >>> response = cjwatson_webservice.named_post(
518 ... ubuntu['main_archive_link'], 'newComponentUploader', {},
519 ... person=name12['self_link'],
520 ... component_name='restricted')
521@@ -304,7 +322,7 @@
522 HTTP/1.1 201 Created
523 ...
524
525- >>> new_permission = webservice.get(
526+ >>> new_permission = user_webservice.get(
527 ... response.getHeader('Location')).jsonBody()
528 >>> print new_permission['self_link']
529 http://.../ubuntu/+archive/primary/+upload/name12?type=component&item=restricted
530@@ -315,10 +333,52 @@
531 Archive Upload Rights ...~ubuntu-team restricted None
532 Archive Upload Rights ...~ubuntu-team universe None
533
534+deleteComponentUploader() removes that permission:
535+
536+ >>> print cjwatson_webservice.named_post(
537+ ... ubuntu['main_archive_link'], 'deleteComponentUploader', {},
538+ ... person=name12['self_link'],
539+ ... component_name='restricted')
540+ HTTP/1.1 200 Ok
541+ ...
542+
543+And we can see that it's gone:
544+
545+ >>> show_component_permissions()
546+ Archive Upload Rights ...~ubuntu-team main None
547+ Archive Upload Rights ...~ubuntu-team restricted None
548+ Archive Upload Rights ...~ubuntu-team universe None
549+
550+Only the archive owners can add or remove component-uploaders.
551+
552+ >>> no_priv = webservice.get("/~no-priv").jsonBody()
553+
554+ >>> print user_webservice.named_post(
555+ ... cprov_archive['self_link'], 'newComponentUploader', {},
556+ ... person=no_priv['self_link'], component_name='main')
557+ HTTP/1.1 401 Unauthorized
558+ ...
559+
560+ >>> cprov_webservice = webservice_for_person(
561+ ... cprov, permission=OAuthPermission.WRITE_PUBLIC)
562+
563+ >>> print cprov_webservice.named_post(
564+ ... cprov_archive['self_link'], 'newComponentUploader', {},
565+ ... person=no_priv['self_link'], component_name='main')
566+ HTTP/1.1 201 Created
567+ ...
568+
569+ >>> print cprov_webservice.named_post(
570+ ... cprov_archive['self_link'], 'deleteComponentUploader', {},
571+ ... person=no_priv['self_link'],
572+ ... component_name='main')
573+ HTTP/1.1 200 Ok
574+ ...
575+
576 If you add a new permission for someone to upload to a PPA, you must specify
577 the 'main' component, or an error is returned:
578
579- >>> response = webservice.named_post(
580+ >>> response = cprov_webservice.named_post(
581 ... cprov_archive['self_link'], 'newComponentUploader', {},
582 ... person=name12['self_link'], component_name='restricted')
583 >>> print response
584@@ -327,29 +387,6 @@
585 InvalidComponent: Component for PPAs should be 'main'
586 <BLANKLINE>
587
588- >>> response = webservice.named_post(
589- ... cprov_archive['self_link'], 'newComponentUploader', {},
590- ... person=name12['self_link'], component_name='main')
591- >>> print response
592- HTTP/1.1 201 Created
593- ...
594-
595-deleteComponentUploader() removes that permission:
596-
597- >>> print webservice.named_post(
598- ... ubuntu['main_archive_link'], 'deleteComponentUploader', {},
599- ... person=name12['self_link'],
600- ... component_name='restricted')
601- HTTP/1.1 200 Ok
602- ...
603-
604-And we can see that it's gone:
605-
606- >>> show_component_permissions()
607- Archive Upload Rights ...~ubuntu-team main None
608- Archive Upload Rights ...~ubuntu-team restricted None
609- Archive Upload Rights ...~ubuntu-team universe None
610-
611 getQueueAdminsForComponent returns all the permissions where someone
612 can administer distroseries queues in a particular component.
613
614@@ -497,18 +534,9 @@
615 For testing purpose we will create some publications.
616
617 >>> login('foo.bar@canonical.com')
618-
619- >>> from lp.registry.interfaces.distribution import (
620- ... IDistributionSet)
621-
622- >>> ubuntu_distro = getUtility(IDistributionSet).getByName('ubuntu')
623-
624- >>> main_archive = ubuntu_distro.main_archive
625-
626- >>> from lp.soyuz.tests.test_publishing import (
627- ... SoyuzTestPublisher)
628+ >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
629 >>> test_publisher = SoyuzTestPublisher()
630- >>> hoary = ubuntu_distro.getSeries('hoary')
631+ >>> hoary = ubuntu_db.getSeries('hoary')
632 >>> test_publisher.addFakeChroots(hoary)
633 >>> ignore = test_publisher.setUpDefaultDistroSeries(hoary)
634
635@@ -516,27 +544,22 @@
636 ubuntu primary archive.
637
638 >>> ignore = test_publisher.getPubSource(
639- ... sourcename="package1", version="1.0", archive=main_archive)
640-
641- >>> ignore = test_publisher.getPubSource(
642- ... sourcename="package1", version="1.1", archive=main_archive)
643-
644- >>> ignore = test_publisher.getPubSource(
645- ... sourcename="package2", version="1.0", archive=main_archive)
646+ ... sourcename="package1", version="1.0",
647+ ... archive=ubuntu_db.main_archive)
648+
649+ >>> ignore = test_publisher.getPubSource(
650+ ... sourcename="package1", version="1.1",
651+ ... archive=ubuntu_db.main_archive)
652+
653+ >>> ignore = test_publisher.getPubSource(
654+ ... sourcename="package2", version="1.0",
655+ ... archive=ubuntu_db.main_archive)
656
657 A test publication in Celso's PPA.
658
659- >>> cprov = getUtility(IPersonSet).getByName('cprov')
660-
661 >>> ignore = test_publisher.getPubSource(
662 ... sourcename="package3", version="1.0", archive=cprov.archive)
663
664-Colin is a valid member of the team who owns the ubuntu primary archive.
665-
666- >>> cjwatson = getUtility(IPersonSet).getByName('kamion')
667- >>> cjwatson.inTeam(main_archive.owner)
668- True
669-
670 Setup done, let's log out and continue with the tests.
671
672 >>> logout()
673@@ -557,13 +580,7 @@
674 When accessed via Colin's key that can perform writes, the API will
675 respond positively.
676
677- >>> from canonical.launchpad.testing.pages import webservice_for_person
678- >>> from canonical.launchpad.webapp.interfaces import OAuthPermission
679-
680- >>> admin_webservice = webservice_for_person(
681- ... cjwatson, permission=OAuthPermission.WRITE_PUBLIC)
682-
683- >>> print admin_webservice.named_post(
684+ >>> print cjwatson_webservice.named_post(
685 ... ubuntu['main_archive_link'], 'syncSource', {},
686 ... source_name='package3', version='1.0',
687 ... from_archive=cprov_archive['self_link'], to_pocket='release',
688@@ -575,7 +592,7 @@
689 PPA. The 'admin_write' key created for Colin isn't allowed to modify
690 Celso's PPA.
691
692- >>> print admin_webservice.named_post(
693+ >>> print cjwatson_webservice.named_post(
694 ... cprov_archive['self_link'], 'syncSource', {},
695 ... source_name='package1', version='1.0',
696 ... from_archive=ubuntu['main_archive_link'], to_pocket='release',
697@@ -639,7 +656,8 @@
698 # It can be successfully synchronised to Celso's PPA.
699 >>> login('foo.bar@canonical.com')
700 >>> allowed_source = test_publisher.getPubSource(
701- ... sourcename="allowed", version="1.0", archive=main_archive)
702+ ... sourcename="allowed", version="1.0",
703+ ... archive=ubuntu_db.main_archive)
704 >>> ignore = test_publisher.getPubBinaries(pub_source=allowed_source)
705 >>> logout()
706
707@@ -664,7 +682,7 @@
708 ... source_name="allowed").jsonBody()['total_size']
709 0
710
711-Keys with not enough permissions in Celso's PPA context are not
712+Keys with insufficient permissions on Celso's PPA context are not
713 allowed to call the method at all.
714
715 >>> print user_webservice.named_post(
716@@ -675,7 +693,7 @@
717 HTTP/1.1 401 Unauthorized
718 ...
719
720- >>> print admin_webservice.named_post(
721+ >>> print cjwatson_webservice.named_post(
722 ... cprov_archive['self_link'], 'syncSources', {},
723 ... source_names=['package1', 'package2'],
724 ... from_archive=ubuntu['main_archive_link'], to_pocket='release',
725@@ -899,9 +917,8 @@
726 >>> from lp.soyuz.interfaces.component import IComponentSet
727 >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
728 >>> login('foo.bar@canonical.com')
729- >>> cprov_ppa_db = getUtility(IPersonSet).getByName('cprov').archive
730- >>> dep = cprov_ppa_db.addArchiveDependency(
731- ... cprov_ppa_db.distribution.main_archive,
732+ >>> dep = cprov.archive.addArchiveDependency(
733+ ... cprov.archive.distribution.main_archive,
734 ... PackagePublishingPocket.RELEASE,
735 ... component=getUtility(IComponentSet)['universe'])
736 >>> logout()