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
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2009-09-03 15:04:13 +0000
+++ lib/lp/soyuz/configure.zcml 2009-09-04 18:18:39 +0000
@@ -394,6 +394,7 @@
394 interface="lp.soyuz.interfaces.archive.IArchiveAppend"/>394 interface="lp.soyuz.interfaces.archive.IArchiveAppend"/>
395 <require395 <require
396 permission="launchpad.Edit"396 permission="launchpad.Edit"
397 interface="lp.soyuz.interfaces.archive.IArchiveEdit"
397 set_attributes="description displayname"/>398 set_attributes="description displayname"/>
398 <require399 <require
399 permission="launchpad.Commercial"400 permission="launchpad.Commercial"
@@ -465,16 +466,16 @@
465 packagesetsForUploader466 packagesetsForUploader
466 packagesetsForSource467 packagesetsForSource
467 packagesetsForSourceUploader468 packagesetsForSourceUploader
468 isSourceUploadAllowed"/>469 isSourceUploadAllowed
469 <require
470 permission="launchpad.Edit"
471 attributes="
472 newPackageUploader470 newPackageUploader
473 newComponentUploader471 newComponentUploader
474 newQueueAdmin472 newQueueAdmin
475 deletePackageUploader473 deletePackageUploader
476 deleteComponentUploader474 deleteComponentUploader
477 deleteQueueAdmin475 deleteQueueAdmin"/>
476 <require
477 permission="launchpad.Edit"
478 attributes="
478 newPackagesetUploader479 newPackagesetUploader
479 deletePackagesetUploader"/>480 deletePackagesetUploader"/>
480 </securedutility>481 </securedutility>
481482
=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py 2009-09-02 21:28:11 +0000
+++ lib/lp/soyuz/interfaces/archive.py 2009-09-17 17:24:04 +0000
@@ -16,6 +16,7 @@
16 'DistroSeriesNotFound',16 'DistroSeriesNotFound',
17 'IArchive',17 'IArchive',
18 'IArchiveAppend',18 'IArchiveAppend',
19 'IArchiveEdit',
19 'IArchiveView',20 'IArchiveView',
20 'IArchiveEditDependenciesForm',21 'IArchiveEditDependenciesForm',
21 'IArchivePublic',22 'IArchivePublic',
@@ -336,68 +337,6 @@
336 :return: A list of `IArchivePermission` records.337 :return: A list of `IArchivePermission` records.
337 """338 """
338339
339 @operation_parameters(person=Reference(schema=IPerson))
340 # Really IArchivePermission, set below to avoid circular import.
341 @operation_returns_collection_of(Interface)
342 @export_read_operation()
343 def getPermissionsForPerson(person):
344 """Return the `IArchivePermission` records applicable to the person.
345
346 :param person: An `IPerson`
347 :return: A list of `IArchivePermission` records.
348 """
349
350 @operation_parameters(
351 source_package_name=TextLine(
352 title=_("Source Package Name"), required=True))
353 # Really IArchivePermission, set below to avoid circular import.
354 @operation_returns_collection_of(Interface)
355 @export_read_operation()
356 def getUploadersForPackage(source_package_name):
357 """Return `IArchivePermission` records for the package's uploaders.
358
359 :param source_package_name: An `ISourcePackageName` or textual name
360 for the source package.
361 :return: A list of `IArchivePermission` records.
362 """
363
364 @operation_parameters(
365 component_name=TextLine(title=_("Component Name"), required=False))
366 # Really IArchivePermission, set below to avoid circular import.
367 @operation_returns_collection_of(Interface)
368 @export_read_operation()
369 def getUploadersForComponent(component_name=None):
370 """Return `IArchivePermission` records for the component's uploaders.
371
372 :param component_name: An `IComponent` or textual name for the
373 component.
374 :return: A list of `IArchivePermission` records.
375 """
376
377 @operation_parameters(
378 component_name=TextLine(title=_("Component Name"), required=True))
379 # Really IArchivePermission, set below to avoid circular import.
380 @operation_returns_collection_of(Interface)
381 @export_read_operation()
382 def getQueueAdminsForComponent(component_name):
383 """Return `IArchivePermission` records for authorised queue admins.
384
385 :param component_name: An `IComponent` or textual name for the
386 component.
387 :return: A list of `IArchivePermission` records.
388 """
389
390 @operation_parameters(person=Reference(schema=IPerson))
391 # Really IArchivePermission, set below to avoid circular import.
392 @operation_returns_collection_of(Interface)
393 @export_read_operation()
394 def getComponentsForQueueAdmin(person):
395 """Return `IArchivePermission` for the person's queue admin components
396
397 :param person: An `IPerson`
398 :return: A list of `IArchivePermission` records.
399 """
400
401 def canUpload(person, component_or_package=None):340 def canUpload(person, component_or_package=None):
402 """Check to see if person is allowed to upload to component.341 """Check to see if person is allowed to upload to component.
403342
@@ -423,103 +362,6 @@
423 queue for items with 'component'.362 queue for items with 'component'.
424 """363 """
425364
426 # The following three factory methods are not in the
427 # IArchiveEditRestricted interface because the rights to use them
428 # does not depend on edit permissions to the archive. The code they
429 # contain does all the necessary security checking and is well
430 # tested in xx-archive.txt and archivepermissions.txt.
431
432 @operation_parameters(
433 person=Reference(schema=IPerson),
434 source_package_name=TextLine(
435 title=_("Source Package Name"), required=True))
436 # Really IArchivePermission, set below to avoid circular import.
437 @export_factory_operation(Interface, [])
438 def newPackageUploader(person, source_package_name):
439 """Add permisson for a person to upload a package to this archive.
440
441 :param person: An `IPerson` whom should be given permission.
442 :param source_package_name: An `ISourcePackageName` or textual package
443 name.
444 :return: An `IArchivePermission` which is the newly-created
445 permission.
446 """
447
448 @operation_parameters(
449 person=Reference(schema=IPerson),
450 component_name=TextLine(
451 title=_("Component Name"), required=True))
452 # Really IArchivePermission, set below to avoid circular import.
453 @export_factory_operation(Interface, [])
454 def newComponentUploader(person, component_name):
455 """Add permission for a person to upload to a component.
456
457 :param person: An `IPerson` whom should be given permission.
458 :param component: An `IComponent` or textual component name.
459 :return: An `IArchivePermission` which is the newly-created
460 permission.
461 :raises InvalidComponent: if this archive is a PPA and the component
462 is not 'main'.
463 """
464
465 @operation_parameters(
466 person=Reference(schema=IPerson),
467 component_name=TextLine(
468 title=_("Component Name"), required=True))
469 # Really IArchivePermission, set below to avoid circular import.
470 @export_factory_operation(Interface, [])
471 def newQueueAdmin(person, component_name):
472 """Add permission for a person to administer a distroseries queue.
473
474 The supplied person will gain permission to administer the
475 distroseries queue for packages in the supplied component.
476
477 :param person: An `IPerson` whom should be given permission.
478 :param component: An `IComponent` or textual component name.
479 :return: An `IArchivePermission` which is the newly-created
480 permission.
481 """
482
483 @operation_parameters(
484 person=Reference(schema=IPerson),
485 source_package_name=TextLine(
486 title=_("Source Package Name"), required=True))
487 @export_write_operation()
488 def deletePackageUploader(person, source_package_name):
489 """Revoke permission for the person to upload the package.
490
491 :param person: An `IPerson` whose permission should be revoked.
492 :param source_package_name: An `ISourcePackageName` or textual package
493 name.
494 """
495
496 @operation_parameters(
497 person=Reference(schema=IPerson),
498 component_name=TextLine(
499 title=_("Component Name"), required=True))
500 @export_write_operation()
501 def deleteComponentUploader(person, component_name):
502 """Revoke permission for the person to upload to the component.
503
504 :param person: An `IPerson` whose permission should be revoked.
505 :param component: An `IComponent` or textual component name.
506 """
507
508 @operation_parameters(
509 person=Reference(schema=IPerson),
510 component_name=TextLine(
511 title=_("Component Name"), required=True))
512 @export_write_operation()
513 def deleteQueueAdmin(person, component_name):
514 """Revoke permission for the person to administer distroseries queues.
515
516 The supplied person will lose permission to administer the
517 distroseries queue for packages in the supplied component.
518
519 :param person: An `IPerson` whose permission should be revoked.
520 :param component: An `IComponent` or textual component name.
521 """
522
523 def getFileByName(filename):365 def getFileByName(filename):
524 """Return the corresponding `ILibraryFileAlias` in this context.366 """Return the corresponding `ILibraryFileAlias` in this context.
525367
@@ -926,6 +768,68 @@
926 could not be found.768 could not be found.
927 """769 """
928770
771 @operation_parameters(person=Reference(schema=IPerson))
772 # Really IArchivePermission, set below to avoid circular import.
773 @operation_returns_collection_of(Interface)
774 @export_read_operation()
775 def getPermissionsForPerson(person):
776 """Return the `IArchivePermission` records applicable to the person.
777
778 :param person: An `IPerson`
779 :return: A list of `IArchivePermission` records.
780 """
781
782 @operation_parameters(
783 source_package_name=TextLine(
784 title=_("Source Package Name"), required=True))
785 # Really IArchivePermission, set below to avoid circular import.
786 @operation_returns_collection_of(Interface)
787 @export_read_operation()
788 def getUploadersForPackage(source_package_name):
789 """Return `IArchivePermission` records for the package's uploaders.
790
791 :param source_package_name: An `ISourcePackageName` or textual name
792 for the source package.
793 :return: A list of `IArchivePermission` records.
794 """
795
796 @operation_parameters(
797 component_name=TextLine(title=_("Component Name"), required=False))
798 # Really IArchivePermission, set below to avoid circular import.
799 @operation_returns_collection_of(Interface)
800 @export_read_operation()
801 def getUploadersForComponent(component_name=None):
802 """Return `IArchivePermission` records for the component's uploaders.
803
804 :param component_name: An `IComponent` or textual name for the
805 component.
806 :return: A list of `IArchivePermission` records.
807 """
808
809 @operation_parameters(
810 component_name=TextLine(title=_("Component Name"), required=True))
811 # Really IArchivePermission, set below to avoid circular import.
812 @operation_returns_collection_of(Interface)
813 @export_read_operation()
814 def getQueueAdminsForComponent(component_name):
815 """Return `IArchivePermission` records for authorised queue admins.
816
817 :param component_name: An `IComponent` or textual name for the
818 component.
819 :return: A list of `IArchivePermission` records.
820 """
821
822 @operation_parameters(person=Reference(schema=IPerson))
823 # Really IArchivePermission, set below to avoid circular import.
824 @operation_returns_collection_of(Interface)
825 @export_read_operation()
826 def getComponentsForQueueAdmin(person):
827 """Return `IArchivePermission` for the person's queue admin components
828
829 :param person: An `IPerson`
830 :return: A list of `IArchivePermission` records.
831 """
832
929833
930class IArchiveAppend(Interface):834class IArchiveAppend(Interface):
931 """Archive interface for operations restricted by append privilege."""835 """Archive interface for operations restricted by append privilege."""
@@ -1043,7 +947,102 @@
1043 """947 """
1044948
1045949
1046class IArchive(IArchivePublic, IArchiveAppend, IArchiveView):950class IArchiveEdit(Interface):
951 """Archive interface for operations restricted by edit privilege."""
952
953 @operation_parameters(
954 person=Reference(schema=IPerson),
955 source_package_name=TextLine(
956 title=_("Source Package Name"), required=True))
957 # Really IArchivePermission, set below to avoid circular import.
958 @export_factory_operation(Interface, [])
959 def newPackageUploader(person, source_package_name):
960 """Add permisson for a person to upload a package to this archive.
961
962 :param person: An `IPerson` whom should be given permission.
963 :param source_package_name: An `ISourcePackageName` or textual package
964 name.
965 :return: An `IArchivePermission` which is the newly-created
966 permission.
967 """
968
969 @operation_parameters(
970 person=Reference(schema=IPerson),
971 component_name=TextLine(
972 title=_("Component Name"), required=True))
973 # Really IArchivePermission, set below to avoid circular import.
974 @export_factory_operation(Interface, [])
975 def newComponentUploader(person, component_name):
976 """Add permission for a person to upload to a component.
977
978 :param person: An `IPerson` whom should be given permission.
979 :param component: An `IComponent` or textual component name.
980 :return: An `IArchivePermission` which is the newly-created
981 permission.
982 :raises InvalidComponent: if this archive is a PPA and the component
983 is not 'main'.
984 """
985
986 @operation_parameters(
987 person=Reference(schema=IPerson),
988 component_name=TextLine(
989 title=_("Component Name"), required=True))
990 # Really IArchivePermission, set below to avoid circular import.
991 @export_factory_operation(Interface, [])
992 def newQueueAdmin(person, component_name):
993 """Add permission for a person to administer a distroseries queue.
994
995 The supplied person will gain permission to administer the
996 distroseries queue for packages in the supplied component.
997
998 :param person: An `IPerson` whom should be given permission.
999 :param component: An `IComponent` or textual component name.
1000 :return: An `IArchivePermission` which is the newly-created
1001 permission.
1002 """
1003
1004 @operation_parameters(
1005 person=Reference(schema=IPerson),
1006 source_package_name=TextLine(
1007 title=_("Source Package Name"), required=True))
1008 @export_write_operation()
1009 def deletePackageUploader(person, source_package_name):
1010 """Revoke permission for the person to upload the package.
1011
1012 :param person: An `IPerson` whose permission should be revoked.
1013 :param source_package_name: An `ISourcePackageName` or textual package
1014 name.
1015 """
1016
1017 @operation_parameters(
1018 person=Reference(schema=IPerson),
1019 component_name=TextLine(
1020 title=_("Component Name"), required=True))
1021 @export_write_operation()
1022 def deleteComponentUploader(person, component_name):
1023 """Revoke permission for the person to upload to the component.
1024
1025 :param person: An `IPerson` whose permission should be revoked.
1026 :param component: An `IComponent` or textual component name.
1027 """
1028
1029 @operation_parameters(
1030 person=Reference(schema=IPerson),
1031 component_name=TextLine(
1032 title=_("Component Name"), required=True))
1033 @export_write_operation()
1034 def deleteQueueAdmin(person, component_name):
1035 """Revoke permission for the person to administer distroseries queues.
1036
1037 The supplied person will lose permission to administer the
1038 distroseries queue for packages in the supplied component.
1039
1040 :param person: An `IPerson` whose permission should be revoked.
1041 :param component: An `IComponent` or textual component name.
1042 """
1043
1044
1045class IArchive(IArchivePublic, IArchiveAppend, IArchiveEdit, IArchiveView):
1047 """Main Archive interface."""1046 """Main Archive interface."""
1048 export_as_webservice_entry()1047 export_as_webservice_entry()
10491048
10501049
=== modified file 'lib/lp/soyuz/stories/webservice/xx-archive.txt'
--- lib/lp/soyuz/stories/webservice/xx-archive.txt 2009-09-04 07:29:56 +0000
+++ lib/lp/soyuz/stories/webservice/xx-archive.txt 2009-09-04 18:18:39 +0000
@@ -76,9 +76,9 @@
7676
77The archive has the following attributes:77The archive has the following attributes:
7878
79 >>> main_archive = webservice.get(79 >>> ubuntu_main_archive = webservice.get(
80 ... ubuntutest['main_archive_link']).jsonBody()80 ... ubuntutest['main_archive_link']).jsonBody()
81 >>> pprint_entry(main_archive)81 >>> pprint_entry(ubuntu_main_archive)
82 dependencies_collection_link: u'http://.../ubuntutest/+archive/primary/dependencies'82 dependencies_collection_link: u'http://.../ubuntutest/+archive/primary/dependencies'
83 description: None83 description: None
84 displayname: u'Primary Archive for Ubuntu Test'84 displayname: u'Primary Archive for Ubuntu Test'
@@ -186,10 +186,10 @@
186Permission collections can be retrieved with custom operations on the186Permission collections can be retrieved with custom operations on the
187archive.187archive.
188188
189getPermissionsForPerson returns all the permissions that a user has.189`getPermissionsForPerson` returns all the permissions that a user has.
190190
191 >>> ubuntu_team = webservice.get("/~ubuntu-team").jsonBody()191 >>> ubuntu_team = user_webservice.get("/~ubuntu-team").jsonBody()
192 >>> permissions = webservice.named_get(192 >>> permissions = user_webservice.named_get(
193 ... ubuntutest['main_archive_link'], 'getPermissionsForPerson',193 ... ubuntutest['main_archive_link'], 'getPermissionsForPerson',
194 ... person=ubuntu_team['self_link']).jsonBody()194 ... person=ubuntu_team['self_link']).jsonBody()
195195
@@ -211,11 +211,11 @@
211 Archive Upload Rights ...~ubuntu-team main None211 Archive Upload Rights ...~ubuntu-team main None
212 Archive Upload Rights ...~ubuntu-team universe None212 Archive Upload Rights ...~ubuntu-team universe None
213213
214getUploadersForPackage returns all the permissions where someone can214`getUploadersForPackage` returns all the permissions where someone can
215upload a particular package.215upload a particular package.
216216
217 >>> def show_mozilla_permissions():217 >>> def show_mozilla_permissions():
218 ... permissions = webservice.named_get(218 ... permissions = user_webservice.named_get(
219 ... ubuntu['main_archive_link'], 'getUploadersForPackage',219 ... ubuntu['main_archive_link'], 'getUploadersForPackage',
220 ... source_package_name='mozilla-firefox').jsonBody()220 ... source_package_name='mozilla-firefox').jsonBody()
221 ... show_permission_entries(permissions)221 ... show_permission_entries(permissions)
@@ -225,17 +225,35 @@
225225
226Passing a bad package name results in an error:226Passing a bad package name results in an error:
227227
228 >>> print webservice.named_get(228 >>> print user_webservice.named_get(
229 ... ubuntu['main_archive_link'], 'getUploadersForPackage',229 ... ubuntu['main_archive_link'], 'getUploadersForPackage',
230 ... source_package_name="badpackage")230 ... source_package_name="badpackage")
231 HTTP/1.1 400 Bad Request231 HTTP/1.1 400 Bad Request
232 ...232 ...
233233
234newPackageUploader() is a factory function that adds a new permission for234Colin is a valid member of the team who owns the ubuntu primary archive.
235a person to upload a package.235
236 >>> from canonical.launchpad.testing.pages import webservice_for_person
237 >>> from canonical.launchpad.webapp.interfaces import OAuthPermission
238 >>> from lp.registry.interfaces.distribution import IDistributionSet
239
240 >>> login(ANONYMOUS)
241 >>> cjwatson = getUtility(IPersonSet).getByName('kamion')
242 >>> ubuntu_db = getUtility(IDistributionSet).getByName('ubuntu')
243 >>> cjwatson.inTeam(ubuntu_db.main_archive.owner)
244 True
245
246 >>> logout()
247
248 >>> cjwatson_webservice = webservice_for_person(
249 ... cjwatson, permission=OAuthPermission.WRITE_PUBLIC)
250
251
252`newPackageUploader` is a factory function that adds a new permission
253for a person to upload a package.
236254
237 >>> name12 = webservice.get("/~name12").jsonBody()255 >>> name12 = webservice.get("/~name12").jsonBody()
238 >>> response = webservice.named_post(256 >>> response = cjwatson_webservice.named_post(
239 ... ubuntu['main_archive_link'], 'newPackageUploader', {},257 ... ubuntu['main_archive_link'], 'newPackageUploader', {},
240 ... person=name12['self_link'],258 ... person=name12['self_link'],
241 ... source_package_name='mozilla-firefox')259 ... source_package_name='mozilla-firefox')
@@ -243,7 +261,7 @@
243 HTTP/1.1 201 Created261 HTTP/1.1 201 Created
244 ...262 ...
245263
246 >>> new_permission = webservice.get(264 >>> new_permission = user_webservice.get(
247 ... response.getHeader('Location')).jsonBody()265 ... response.getHeader('Location')).jsonBody()
248 >>> print new_permission['self_link']266 >>> print new_permission['self_link']
249 http://.../ubuntu/+archive/primary/+upload/name12?type=packagename&item=mozilla-firefox267 http://.../ubuntu/+archive/primary/+upload/name12?type=packagename&item=mozilla-firefox
@@ -254,7 +272,7 @@
254272
255deletePackageUploader() removes that permission:273deletePackageUploader() removes that permission:
256274
257 >>> print webservice.named_post(275 >>> print cjwatson_webservice.named_post(
258 ... ubuntu['main_archive_link'], 'deletePackageUploader', {},276 ... ubuntu['main_archive_link'], 'deletePackageUploader', {},
259 ... person=name12['self_link'],277 ... person=name12['self_link'],
260 ... source_package_name='mozilla-firefox')278 ... source_package_name='mozilla-firefox')
@@ -270,7 +288,7 @@
270upload to a particular component:288upload to a particular component:
271289
272 >>> def show_component_permissions(component=None):290 >>> def show_component_permissions(component=None):
273 ... permissions = webservice.named_get(291 ... permissions = user_webservice.named_get(
274 ... ubuntu['main_archive_link'], 'getUploadersForComponent',292 ... ubuntu['main_archive_link'], 'getUploadersForComponent',
275 ... component_name=component).jsonBody()293 ... component_name=component).jsonBody()
276 ... show_permission_entries(permissions)294 ... show_permission_entries(permissions)
@@ -280,7 +298,7 @@
280298
281Passing a bad component name results in an error:299Passing a bad component name results in an error:
282300
283 >>> print webservice.named_get(301 >>> print cjwatson_webservice.named_get(
284 ... ubuntu['main_archive_link'], 'getUploadersForComponent',302 ... ubuntu['main_archive_link'], 'getUploadersForComponent',
285 ... component_name="badcomponent")303 ... component_name="badcomponent")
286 HTTP/1.1 400 Bad Request304 HTTP/1.1 400 Bad Request
@@ -296,7 +314,7 @@
296newComponentUploader adds a new permission for a person to upload to a314newComponentUploader adds a new permission for a person to upload to a
297component.315component.
298316
299 >>> response = webservice.named_post(317 >>> response = cjwatson_webservice.named_post(
300 ... ubuntu['main_archive_link'], 'newComponentUploader', {},318 ... ubuntu['main_archive_link'], 'newComponentUploader', {},
301 ... person=name12['self_link'],319 ... person=name12['self_link'],
302 ... component_name='restricted')320 ... component_name='restricted')
@@ -304,7 +322,7 @@
304 HTTP/1.1 201 Created322 HTTP/1.1 201 Created
305 ...323 ...
306324
307 >>> new_permission = webservice.get(325 >>> new_permission = user_webservice.get(
308 ... response.getHeader('Location')).jsonBody()326 ... response.getHeader('Location')).jsonBody()
309 >>> print new_permission['self_link']327 >>> print new_permission['self_link']
310 http://.../ubuntu/+archive/primary/+upload/name12?type=component&item=restricted328 http://.../ubuntu/+archive/primary/+upload/name12?type=component&item=restricted
@@ -315,10 +333,52 @@
315 Archive Upload Rights ...~ubuntu-team restricted None333 Archive Upload Rights ...~ubuntu-team restricted None
316 Archive Upload Rights ...~ubuntu-team universe None334 Archive Upload Rights ...~ubuntu-team universe None
317335
336deleteComponentUploader() removes that permission:
337
338 >>> print cjwatson_webservice.named_post(
339 ... ubuntu['main_archive_link'], 'deleteComponentUploader', {},
340 ... person=name12['self_link'],
341 ... component_name='restricted')
342 HTTP/1.1 200 Ok
343 ...
344
345And we can see that it's gone:
346
347 >>> show_component_permissions()
348 Archive Upload Rights ...~ubuntu-team main None
349 Archive Upload Rights ...~ubuntu-team restricted None
350 Archive Upload Rights ...~ubuntu-team universe None
351
352Only the archive owners can add or remove component-uploaders.
353
354 >>> no_priv = webservice.get("/~no-priv").jsonBody()
355
356 >>> print user_webservice.named_post(
357 ... cprov_archive['self_link'], 'newComponentUploader', {},
358 ... person=no_priv['self_link'], component_name='main')
359 HTTP/1.1 401 Unauthorized
360 ...
361
362 >>> cprov_webservice = webservice_for_person(
363 ... cprov, permission=OAuthPermission.WRITE_PUBLIC)
364
365 >>> print cprov_webservice.named_post(
366 ... cprov_archive['self_link'], 'newComponentUploader', {},
367 ... person=no_priv['self_link'], component_name='main')
368 HTTP/1.1 201 Created
369 ...
370
371 >>> print cprov_webservice.named_post(
372 ... cprov_archive['self_link'], 'deleteComponentUploader', {},
373 ... person=no_priv['self_link'],
374 ... component_name='main')
375 HTTP/1.1 200 Ok
376 ...
377
318If you add a new permission for someone to upload to a PPA, you must specify378If you add a new permission for someone to upload to a PPA, you must specify
319the 'main' component, or an error is returned:379the 'main' component, or an error is returned:
320380
321 >>> response = webservice.named_post(381 >>> response = cprov_webservice.named_post(
322 ... cprov_archive['self_link'], 'newComponentUploader', {},382 ... cprov_archive['self_link'], 'newComponentUploader', {},
323 ... person=name12['self_link'], component_name='restricted')383 ... person=name12['self_link'], component_name='restricted')
324 >>> print response384 >>> print response
@@ -327,29 +387,6 @@
327 InvalidComponent: Component for PPAs should be 'main'387 InvalidComponent: Component for PPAs should be 'main'
328 <BLANKLINE>388 <BLANKLINE>
329389
330 >>> response = webservice.named_post(
331 ... cprov_archive['self_link'], 'newComponentUploader', {},
332 ... person=name12['self_link'], component_name='main')
333 >>> print response
334 HTTP/1.1 201 Created
335 ...
336
337deleteComponentUploader() removes that permission:
338
339 >>> print webservice.named_post(
340 ... ubuntu['main_archive_link'], 'deleteComponentUploader', {},
341 ... person=name12['self_link'],
342 ... component_name='restricted')
343 HTTP/1.1 200 Ok
344 ...
345
346And we can see that it's gone:
347
348 >>> show_component_permissions()
349 Archive Upload Rights ...~ubuntu-team main None
350 Archive Upload Rights ...~ubuntu-team restricted None
351 Archive Upload Rights ...~ubuntu-team universe None
352
353getQueueAdminsForComponent returns all the permissions where someone390getQueueAdminsForComponent returns all the permissions where someone
354can administer distroseries queues in a particular component.391can administer distroseries queues in a particular component.
355392
@@ -497,18 +534,9 @@
497For testing purpose we will create some publications.534For testing purpose we will create some publications.
498535
499 >>> login('foo.bar@canonical.com')536 >>> login('foo.bar@canonical.com')
500537 >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
501 >>> from lp.registry.interfaces.distribution import (
502 ... IDistributionSet)
503
504 >>> ubuntu_distro = getUtility(IDistributionSet).getByName('ubuntu')
505
506 >>> main_archive = ubuntu_distro.main_archive
507
508 >>> from lp.soyuz.tests.test_publishing import (
509 ... SoyuzTestPublisher)
510 >>> test_publisher = SoyuzTestPublisher()538 >>> test_publisher = SoyuzTestPublisher()
511 >>> hoary = ubuntu_distro.getSeries('hoary')539 >>> hoary = ubuntu_db.getSeries('hoary')
512 >>> test_publisher.addFakeChroots(hoary)540 >>> test_publisher.addFakeChroots(hoary)
513 >>> ignore = test_publisher.setUpDefaultDistroSeries(hoary)541 >>> ignore = test_publisher.setUpDefaultDistroSeries(hoary)
514542
@@ -516,27 +544,22 @@
516ubuntu primary archive.544ubuntu primary archive.
517545
518 >>> ignore = test_publisher.getPubSource(546 >>> ignore = test_publisher.getPubSource(
519 ... sourcename="package1", version="1.0", archive=main_archive)547 ... sourcename="package1", version="1.0",
520548 ... archive=ubuntu_db.main_archive)
521 >>> ignore = test_publisher.getPubSource(549
522 ... sourcename="package1", version="1.1", archive=main_archive)550 >>> ignore = test_publisher.getPubSource(
523551 ... sourcename="package1", version="1.1",
524 >>> ignore = test_publisher.getPubSource(552 ... archive=ubuntu_db.main_archive)
525 ... sourcename="package2", version="1.0", archive=main_archive)553
554 >>> ignore = test_publisher.getPubSource(
555 ... sourcename="package2", version="1.0",
556 ... archive=ubuntu_db.main_archive)
526557
527A test publication in Celso's PPA.558A test publication in Celso's PPA.
528559
529 >>> cprov = getUtility(IPersonSet).getByName('cprov')
530
531 >>> ignore = test_publisher.getPubSource(560 >>> ignore = test_publisher.getPubSource(
532 ... sourcename="package3", version="1.0", archive=cprov.archive)561 ... sourcename="package3", version="1.0", archive=cprov.archive)
533562
534Colin is a valid member of the team who owns the ubuntu primary archive.
535
536 >>> cjwatson = getUtility(IPersonSet).getByName('kamion')
537 >>> cjwatson.inTeam(main_archive.owner)
538 True
539
540Setup done, let's log out and continue with the tests.563Setup done, let's log out and continue with the tests.
541564
542 >>> logout()565 >>> logout()
@@ -557,13 +580,7 @@
557When accessed via Colin's key that can perform writes, the API will580When accessed via Colin's key that can perform writes, the API will
558respond positively.581respond positively.
559582
560 >>> from canonical.launchpad.testing.pages import webservice_for_person583 >>> print cjwatson_webservice.named_post(
561 >>> from canonical.launchpad.webapp.interfaces import OAuthPermission
562
563 >>> admin_webservice = webservice_for_person(
564 ... cjwatson, permission=OAuthPermission.WRITE_PUBLIC)
565
566 >>> print admin_webservice.named_post(
567 ... ubuntu['main_archive_link'], 'syncSource', {},584 ... ubuntu['main_archive_link'], 'syncSource', {},
568 ... source_name='package3', version='1.0',585 ... source_name='package3', version='1.0',
569 ... from_archive=cprov_archive['self_link'], to_pocket='release',586 ... from_archive=cprov_archive['self_link'], to_pocket='release',
@@ -575,7 +592,7 @@
575PPA. The 'admin_write' key created for Colin isn't allowed to modify592PPA. The 'admin_write' key created for Colin isn't allowed to modify
576Celso's PPA.593Celso's PPA.
577594
578 >>> print admin_webservice.named_post(595 >>> print cjwatson_webservice.named_post(
579 ... cprov_archive['self_link'], 'syncSource', {},596 ... cprov_archive['self_link'], 'syncSource', {},
580 ... source_name='package1', version='1.0',597 ... source_name='package1', version='1.0',
581 ... from_archive=ubuntu['main_archive_link'], to_pocket='release',598 ... from_archive=ubuntu['main_archive_link'], to_pocket='release',
@@ -639,7 +656,8 @@
639 # It can be successfully synchronised to Celso's PPA.656 # It can be successfully synchronised to Celso's PPA.
640 >>> login('foo.bar@canonical.com')657 >>> login('foo.bar@canonical.com')
641 >>> allowed_source = test_publisher.getPubSource(658 >>> allowed_source = test_publisher.getPubSource(
642 ... sourcename="allowed", version="1.0", archive=main_archive)659 ... sourcename="allowed", version="1.0",
660 ... archive=ubuntu_db.main_archive)
643 >>> ignore = test_publisher.getPubBinaries(pub_source=allowed_source)661 >>> ignore = test_publisher.getPubBinaries(pub_source=allowed_source)
644 >>> logout()662 >>> logout()
645663
@@ -664,7 +682,7 @@
664 ... source_name="allowed").jsonBody()['total_size']682 ... source_name="allowed").jsonBody()['total_size']
665 0683 0
666684
667Keys with not enough permissions in Celso's PPA context are not685Keys with insufficient permissions on Celso's PPA context are not
668allowed to call the method at all.686allowed to call the method at all.
669687
670 >>> print user_webservice.named_post(688 >>> print user_webservice.named_post(
@@ -675,7 +693,7 @@
675 HTTP/1.1 401 Unauthorized693 HTTP/1.1 401 Unauthorized
676 ...694 ...
677695
678 >>> print admin_webservice.named_post(696 >>> print cjwatson_webservice.named_post(
679 ... cprov_archive['self_link'], 'syncSources', {},697 ... cprov_archive['self_link'], 'syncSources', {},
680 ... source_names=['package1', 'package2'],698 ... source_names=['package1', 'package2'],
681 ... from_archive=ubuntu['main_archive_link'], to_pocket='release',699 ... from_archive=ubuntu['main_archive_link'], to_pocket='release',
@@ -899,9 +917,8 @@
899 >>> from lp.soyuz.interfaces.component import IComponentSet917 >>> from lp.soyuz.interfaces.component import IComponentSet
900 >>> from lp.registry.interfaces.pocket import PackagePublishingPocket918 >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
901 >>> login('foo.bar@canonical.com')919 >>> login('foo.bar@canonical.com')
902 >>> cprov_ppa_db = getUtility(IPersonSet).getByName('cprov').archive920 >>> dep = cprov.archive.addArchiveDependency(
903 >>> dep = cprov_ppa_db.addArchiveDependency(921 ... cprov.archive.distribution.main_archive,
904 ... cprov_ppa_db.distribution.main_archive,
905 ... PackagePublishingPocket.RELEASE,922 ... PackagePublishingPocket.RELEASE,
906 ... component=getUtility(IComponentSet)['universe'])923 ... component=getUtility(IComponentSet)['universe'])
907 >>> logout()924 >>> logout()