Merge lp:~jelmer/launchpad/refactor-permissions into lp:launchpad

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: 10869
Proposed branch: lp:~jelmer/launchpad/refactor-permissions
Merge into: lp:launchpad
Diff against target: 1138 lines (+356/-318)
19 files modified
lib/canonical/launchpad/security.py (+7/-8)
lib/lp/archiveuploader/nascentupload.py (+2/-3)
lib/lp/archiveuploader/permission.py (+0/-246)
lib/lp/archiveuploader/tests/nascentupload-packageset.txt (+2/-2)
lib/lp/archiveuploader/tests/test_permission.py (+12/-14)
lib/lp/bugs/model/bugnomination.py (+1/-1)
lib/lp/code/model/recipebuilder.py (+2/-3)
lib/lp/code/model/sourcepackagerecipe.py (+3/-4)
lib/lp/code/model/tests/test_sourcepackagerecipe.py (+2/-3)
lib/lp/code/tests/test_branch.py (+4/-5)
lib/lp/soyuz/browser/archive.py (+2/-1)
lib/lp/soyuz/doc/archive.txt (+11/-11)
lib/lp/soyuz/doc/archivepermission.txt (+1/-1)
lib/lp/soyuz/doc/nascentupload.txt (+2/-3)
lib/lp/soyuz/interfaces/archive.py (+136/-1)
lib/lp/soyuz/model/archive.py (+94/-5)
lib/lp/soyuz/model/archivepermission.py (+2/-2)
lib/lp/soyuz/model/binarypackagebuildbehavior.py (+2/-3)
lib/lp/soyuz/tests/test_archive.py (+71/-2)
To merge this branch: bzr merge lp:~jelmer/launchpad/refactor-permissions
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+23216@code.launchpad.net

Commit message

Move archive permission checking functions onto Archive.

Description of the change

This move some of the permission checking functions for archives on the Archive method and removes a couple of duplicate functions in the process.

This is in preparation of exposing these methods over the web API, as requested by james_w.

To post a comment you must log in.
Brad Crittenden (bac) wrote :

Hi Jelmer this refactoring looks good. In test_archive.py please end all comments with punctuation.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/security.py'
2--- lib/canonical/launchpad/security.py 2010-04-26 15:02:03 +0000
3+++ lib/canonical/launchpad/security.py 2010-05-11 14:12:39 +0000
4@@ -12,8 +12,6 @@
5 from zope.component import getAdapter, getUtility
6
7 from canonical.launchpad.interfaces.account import IAccount
8-from lp.archiveuploader.permission import (
9- can_upload_to_archive, check_upload_to_archive)
10 from canonical.launchpad.interfaces.emailaddress import IEmailAddress
11 from lp.registry.interfaces.announcement import IAnnouncement
12 from lp.soyuz.interfaces.archive import IArchive
13@@ -1475,9 +1473,9 @@
14 # user to retry build if so.
15 # strict_component is True because the source package already exists,
16 # otherwise, how can they give it back?
17- check_perms = check_upload_to_archive(
18+ check_perms = self.obj.archive.checkUpload(
19 user.person, self.obj.distroseries,
20- self.obj.sourcepackagerelease.sourcepackagename, self.obj.archive,
21+ self.obj.sourcepackagerelease.sourcepackagename,
22 self.obj.current_component, self.obj.pocket,
23 strict_component=True)
24 return check_perms == None
25@@ -1718,7 +1716,8 @@
26 # one combination that allows us to upload the corresponding source
27 # package.
28 for ssp in ssp_list:
29- if can_upload_to_archive(person_role.person, ssp):
30+ archive = ssp.sourcepackage.get_default_archive()
31+ if archive.canUploadSuiteSourcePackage(person_role.person, ssp):
32 return True
33 return False
34
35@@ -2047,7 +2046,7 @@
36 return True
37
38 # Uploaders can view private PPAs.
39- if self.obj.is_ppa and self.obj.canUpload(user.person):
40+ if self.obj.is_ppa and self.obj.checkArchivePermission(user.person):
41 return True
42
43 return False
44@@ -2062,7 +2061,7 @@
45
46 No one can upload to disabled archives.
47
48- PPA upload rights are managed via `IArchive.canUpload`;
49+ PPA upload rights are managed via `IArchive.checkArchivePermission`;
50
51 Appending to PRIMARY, PARTNER or COPY archives is restricted to owners.
52
53@@ -2079,7 +2078,7 @@
54 if user.inTeam(self.obj.owner):
55 return True
56
57- if self.obj.is_ppa and self.obj.canUpload(user.person):
58+ if self.obj.is_ppa and self.obj.checkArchivePermission(user.person):
59 return True
60
61 celebrities = getUtility(ILaunchpadCelebrities)
62
63=== modified file 'lib/lp/archiveuploader/nascentupload.py'
64--- lib/lp/archiveuploader/nascentupload.py 2010-02-26 16:52:46 +0000
65+++ lib/lp/archiveuploader/nascentupload.py 2010-05-11 14:12:39 +0000
66@@ -28,7 +28,6 @@
67 from lp.archiveuploader.nascentuploadfile import (
68 UploadError, UploadWarning, CustomUploadFile, SourceUploadFile,
69 BaseBinaryUploadFile)
70-from lp.archiveuploader.permission import check_upload_to_archive
71 from lp.archiveuploader.utils import determine_source_file_type
72 from lp.registry.interfaces.pocket import PackagePublishingPocket
73 from lp.registry.interfaces.sourcepackage import SourcePackageFileType
74@@ -489,8 +488,8 @@
75 source_name = getUtility(
76 ISourcePackageNameSet).queryByName(self.changes.dsc.package)
77
78- rejection_reason = check_upload_to_archive(
79- uploader, self.policy.distroseries, source_name, archive,
80+ rejection_reason = archive.checkUpload(
81+ uploader, self.policy.distroseries, source_name,
82 self.changes.dsc.component, self.policy.pocket, not self.is_new)
83
84 if rejection_reason is not None:
85
86=== removed file 'lib/lp/archiveuploader/permission.py'
87--- lib/lp/archiveuploader/permission.py 2010-02-02 14:01:02 +0000
88+++ lib/lp/archiveuploader/permission.py 1970-01-01 00:00:00 +0000
89@@ -1,246 +0,0 @@
90-# Copyright 2009 Canonical Ltd. This software is licensed under the
91-# GNU Affero General Public License version 3 (see the file LICENSE).
92-
93-"""Permissions for uploading a package to an archive."""
94-
95-__metaclass__ = type
96-__all__ = [
97- 'CannotUploadToArchive',
98- 'CannotUploadToPPA',
99- 'can_upload_to_archive',
100- 'check_upload_to_archive',
101- 'check_upload_to_pocket',
102- 'components_valid_for',
103- 'verify_upload',
104- ]
105-
106-from zope.component import getUtility
107-
108-from lp.registry.interfaces.pocket import PackagePublishingPocket
109-from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
110-from lp.soyuz.interfaces.archive import ArchivePurpose
111-
112-
113-class CannotUploadToArchive(Exception):
114- """A reason for not being able to upload to an archive."""
115-
116- _fmt = '%(person)s has no upload rights to %(archive)s.'
117-
118- def __init__(self, **args):
119- """Construct a `CannotUploadToArchive`."""
120- Exception.__init__(self, self._fmt % args)
121-
122-
123-class CannotUploadToPocket(Exception):
124- """Returned when a pocket is closed for uploads."""
125-
126- def __init__(self, distroseries, pocket):
127- Exception.__init__(self,
128- "Not permitted to upload to the %s pocket in a series in the "
129- "'%s' state." % (pocket.name, distroseries.status.name))
130-
131-
132-class CannotUploadToPPA(CannotUploadToArchive):
133- """Raised when a person cannot upload to a PPA."""
134-
135- _fmt = 'Signer has no upload rights to this PPA.'
136-
137-
138-class NoRightsForArchive(CannotUploadToArchive):
139- """Raised when a person has absolutely no upload rights to an archive."""
140-
141- _fmt = (
142- "The signer of this package has no upload rights to this "
143- "distribution's primary archive. Did you mean to upload to "
144- "a PPA?")
145-
146-
147-class InsufficientUploadRights(CannotUploadToArchive):
148- """Raised when a person has insufficient upload rights."""
149- _fmt = (
150- "The signer of this package is lacking the upload rights for "
151- "the source package, component or package set in question.")
152-
153-
154-class NoRightsForComponent(CannotUploadToArchive):
155- """Raised when a person tries to upload to a component without permission.
156- """
157-
158- _fmt = (
159- "Signer is not permitted to upload to the component '%(component)s'.")
160-
161- def __init__(self, component):
162- CannotUploadToArchive.__init__(self, component=component.name)
163-
164-
165-class InvalidPocketForPPA(CannotUploadToArchive):
166- """PPAs only support some pockets."""
167-
168- _fmt = "PPA uploads must be for the RELEASE pocket."
169-
170-
171-class InvalidPocketForPartnerArchive(CannotUploadToArchive):
172- """Partner archives only support some pockets."""
173-
174- _fmt = "Partner uploads must be for the RELEASE or PROPOSED pocket."
175-
176-
177-class ArchiveDisabled(CannotUploadToArchive):
178- """Uploading to a disabled archive is not allowed."""
179-
180- _fmt = ("%(archive_name)s is disabled.")
181-
182- def __init__(self, archive_name):
183- CannotUploadToArchive.__init__(self, archive_name=archive_name)
184-
185-
186-def components_valid_for(archive, person):
187- """Return the components that 'person' can upload to 'archive'.
188-
189- :param archive: The `IArchive` than 'person' wishes to upload to.
190- :param person: An `IPerson` wishing to upload to an archive.
191- :return: A `set` of `IComponent`s that 'person' can upload to.
192- """
193- permission_set = getUtility(IArchivePermissionSet)
194- permissions = permission_set.componentsForUploader(archive, person)
195- return set(permission.component for permission in permissions)
196-
197-
198-def can_upload_to_archive(person, suitesourcepackage, archive=None):
199- """Check if 'person' upload 'suitesourcepackage' to 'archive'.
200-
201- :param person: An `IPerson` who might be uploading.
202- :param suitesourcepackage: An `ISuiteSourcePackage` to be uploaded.
203- :param archive: The `IArchive` to upload to. If not provided, defaults
204- to the default archive for the source package. (See
205- `ISourcePackage.get_default_archive`).
206- :return: True if they can, False if they cannot.
207- """
208- sourcepackage = suitesourcepackage.sourcepackage
209- if archive is None:
210- archive = sourcepackage.get_default_archive()
211- pocket = suitesourcepackage.pocket
212- distroseries = sourcepackage.distroseries
213- sourcepackagename = sourcepackage.sourcepackagename
214- component = sourcepackage.latest_published_component
215- # strict_component is True because the source package already exists
216- # (otherwise we couldn't have a suitesourcepackage object) and
217- # nascentupload passes True as a matter of policy when the package exists.
218- reason = check_upload_to_archive(
219- person, distroseries, sourcepackagename, archive, component, pocket,
220- strict_component=True)
221- return reason is None
222-
223-
224-def check_upload_to_pocket(archive, distroseries, pocket):
225- """Check if uploading to a particular pocket in an archive is possible.
226-
227- :param archive: A `IArchive`
228- :param distroseries: A `IDistroSeries`
229- :param pocket: A `PackagePublishingPocket`
230- """
231- if archive.purpose == ArchivePurpose.PARTNER:
232- if pocket not in (
233- PackagePublishingPocket.RELEASE,
234- PackagePublishingPocket.PROPOSED):
235- return InvalidPocketForPartnerArchive()
236- elif archive.is_ppa:
237- if pocket != PackagePublishingPocket.RELEASE:
238- return InvalidPocketForPPA()
239- else:
240- # Uploads to the partner archive are allowed in any distroseries
241- # state.
242- # XXX julian 2005-05-29 bug=117557:
243- # This is a greasy hack until bug #117557 is fixed.
244- if not distroseries.canUploadToPocket(pocket):
245- return CannotUploadToPocket(distroseries, pocket)
246-
247-
248-def check_upload_to_archive(person, distroseries, sourcepackagename, archive,
249- component, pocket, strict_component=True):
250- """Check if 'person' upload 'suitesourcepackage' to 'archive'.
251-
252- :param person: An `IPerson` who might be uploading.
253- :param distroseries: The `IDistroSeries` being uploaded to.
254- :param sourcepackagename: The `ISourcePackageName` being uploaded.
255- :param archive: The `IArchive` to upload to. If not provided, defaults
256- to the default archive for the source package. (See
257- `ISourcePackage.get_default_archive`).
258- :param component: The `Component` being uploaded to.
259- :param pocket: The `PackagePublishingPocket` of 'distroseries' being
260- uploaded to.
261- :return: The reason for not being able to upload, None otherwise.
262- """
263- reason = check_upload_to_pocket(archive, distroseries, pocket)
264- if reason is not None:
265- return reason
266- return verify_upload(
267- person, sourcepackagename, archive, component, distroseries,
268- strict_component)
269-
270-
271-def packagesets_valid_for(archive, person):
272- """Return the package sets that 'person' can upload to 'archive'.
273-
274- :param archive: The `IArchive` than 'person' wishes to upload to.
275- :param person: An `IPerson` wishing to upload to an archive.
276- :return: A `set` of `IPackageset`s that 'person' can upload to.
277- """
278- permission_set = getUtility(IArchivePermissionSet)
279- permissions = permission_set.packagesetsForUploader(archive, person)
280- return set(permission.packageset for permission in permissions)
281-
282-
283-def verify_upload(person, sourcepackagename, archive, component,
284- distroseries, strict_component=True):
285- """Can 'person' upload 'sourcepackagename' to 'archive'?
286-
287- :param person: The `IPerson` trying to upload to the package. Referred to
288- as 'the signer' in upload code.
289- :param sourcepackagename: The source package being uploaded. None if the
290- package is new.
291- :param archive: The `IArchive` being uploaded to.
292- :param component: The `IComponent` that the source package belongs to.
293- :param distroseries: The upload's target distro series.
294- :param strict_component: True if access to the specific component for the
295- package is needed to upload to it. If False, then access to any
296- package will do.
297- :return: CannotUploadToArchive if 'person' cannot upload to the archive,
298- None otherwise.
299- """
300- if not archive.enabled:
301- return ArchiveDisabled(archive.displayname)
302-
303- # For PPAs...
304- if archive.is_ppa:
305- if not archive.canUpload(person):
306- return CannotUploadToPPA()
307- else:
308- return None
309-
310- # For any other archive...
311- ap_set = getUtility(IArchivePermissionSet)
312-
313- if sourcepackagename is not None:
314- # Check whether user may upload because he holds a permission for
315- # - the given source package directly
316- # - a package set in the correct distro series that includes the
317- # given source package
318- source_allowed = archive.canUpload(person, sourcepackagename)
319- set_allowed = ap_set.isSourceUploadAllowed(
320- archive, sourcepackagename, person, distroseries)
321- if source_allowed or set_allowed:
322- return None
323-
324- if not components_valid_for(archive, person):
325- if not packagesets_valid_for(archive, person):
326- return NoRightsForArchive()
327- else:
328- return InsufficientUploadRights()
329-
330- if (component is not None
331- and strict_component
332- and not archive.canUpload(person, component)):
333- return NoRightsForComponent(component)
334-
335- return None
336
337=== modified file 'lib/lp/archiveuploader/tests/nascentupload-packageset.txt'
338--- lib/lp/archiveuploader/tests/nascentupload-packageset.txt 2009-10-02 15:00:09 +0000
339+++ lib/lp/archiveuploader/tests/nascentupload-packageset.txt 2010-05-11 14:12:39 +0000
340@@ -39,8 +39,8 @@
341 >>> bar_failed.is_rejected
342 True
343 >>> print bar_failed.rejection_message
344- The signer of this package has no upload rights to this distribution's
345- primary archive. Did you mean to upload to a PPA?
346+ The signer of this package is lacking the upload rights for the source
347+ package, component or package set in question.
348
349
350 We can grant selective, package set based upload permissions to the user
351
352=== modified file 'lib/lp/archiveuploader/tests/test_permission.py'
353--- lib/lp/archiveuploader/tests/test_permission.py 2010-02-08 10:56:18 +0000
354+++ lib/lp/archiveuploader/tests/test_permission.py 2010-05-11 14:12:39 +0000
355@@ -12,8 +12,6 @@
356
357 from canonical.testing import DatabaseFunctionalLayer
358
359-from lp.archiveuploader.permission import (
360- check_upload_to_archive, components_valid_for)
361 from lp.registry.interfaces.series import SeriesStatus
362 from lp.registry.interfaces.pocket import PackagePublishingPocket
363 from lp.soyuz.interfaces.archive import ArchivePurpose
364@@ -29,21 +27,22 @@
365 # By default, a person cannot upload to any component of an archive.
366 archive = self.factory.makeArchive()
367 person = self.factory.makePerson()
368- self.assertEqual(set(), components_valid_for(archive, person))
369+ self.assertEqual(set(),
370+ set(archive.getComponentsForUploader(person)))
371
372 def test_components_for_person_with_permissions(self):
373 # If a person has been explicitly granted upload permissions to a
374 # particular component, then those components are included in
375- # components_valid_for.
376+ # IArchive.getComponentsForUploader.
377 archive = self.factory.makeArchive()
378 component = self.factory.makeComponent()
379 person = self.factory.makePerson()
380 # Only admins or techboard members can add permissions normally. That
381 # restriction isn't relevant to this test.
382 ap_set = removeSecurityProxy(getUtility(IArchivePermissionSet))
383- ap_set.newComponentUploader(archive, person, component)
384- self.assertEqual(
385- set([component]), components_valid_for(archive, person))
386+ ap = ap_set.newComponentUploader(archive, person, component)
387+ self.assertEqual(set([ap]),
388+ set(archive.getComponentsForUploader(person)))
389
390
391 class TestPermission(TestCaseWithFactory):
392@@ -67,8 +66,8 @@
393 pocket = PackagePublishingPocket.RELEASE
394 self.assertIs(
395 None,
396- check_upload_to_archive(
397- person, distroseries, spn, archive, component, pocket,
398+ archive.checkUpload(
399+ person, distroseries, spn, component, pocket,
400 strict_component))
401
402 def assertCannotUpload(self, reason, person, spn, archive, component,
403@@ -87,8 +86,8 @@
404 if distroseries is None:
405 distroseries = self.factory.makeDistroSeries()
406 pocket = PackagePublishingPocket.RELEASE
407- exception = check_upload_to_archive(
408- person, distroseries, spn, archive, component, pocket)
409+ exception = archive.checkUpload(
410+ person, distroseries, spn, component, pocket)
411 self.assertEqual(reason, str(exception))
412
413 def test_random_person_cannot_upload_to_ppa(self):
414@@ -137,9 +136,8 @@
415 archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
416 spn = self.factory.makeSourcePackageName()
417 self.assertCannotUpload(
418- ("The signer of this package has no upload rights to this "
419- "distribution's primary archive. Did you mean to upload to "
420- "a PPA?"),
421+ ("The signer of this package is lacking the upload rights for "
422+ "the source package, component or package set in question."),
423 person, spn, archive, None)
424
425 def test_package_specific_rights(self):
426
427=== modified file 'lib/lp/bugs/model/bugnomination.py'
428--- lib/lp/bugs/model/bugnomination.py 2009-08-26 09:31:57 +0000
429+++ lib/lp/bugs/model/bugnomination.py 2010-05-11 14:12:39 +0000
430@@ -144,7 +144,7 @@
431 upload_component.component
432 for upload_component in distribution.uploaders)
433 for packagename_or_component in bug_packagenames_and_components:
434- if distribution.main_archive.canUpload(
435+ if distribution.main_archive.checkArchivePermission(
436 person, packagename_or_component):
437 return True
438
439
440=== modified file 'lib/lp/code/model/recipebuilder.py'
441--- lib/lp/code/model/recipebuilder.py 2010-04-29 14:54:05 +0000
442+++ lib/lp/code/model/recipebuilder.py 2010-05-11 14:12:39 +0000
443@@ -15,7 +15,6 @@
444
445 from canonical.config import config
446
447-from lp.archiveuploader.permission import check_upload_to_pocket
448 from lp.buildmaster.interfaces.buildfarmjobbehavior import (
449 IBuildFarmJobBehavior)
450 from lp.buildmaster.interfaces.builder import CannotBuild
451@@ -158,8 +157,8 @@
452
453 # This should already have been checked earlier, but just check again
454 # here in case of programmer errors.
455- reason = check_upload_to_pocket(
456- build.archive, build.distroseries, build.pocket)
457+ reason = build.archive.checkUploadToPocket(
458+ build.distroseries, build.pocket)
459 assert reason is None, (
460 "%s (%s) can not be built for pocket %s: invalid pocket due "
461 "to the series status of %s." %
462
463=== modified file 'lib/lp/code/model/sourcepackagerecipe.py'
464--- lib/lp/code/model/sourcepackagerecipe.py 2010-04-30 12:33:16 +0000
465+++ lib/lp/code/model/sourcepackagerecipe.py 2010-05-11 14:12:39 +0000
466@@ -22,7 +22,6 @@
467 from canonical.database.datetimecol import UtcDateTimeCol
468 from canonical.launchpad.interfaces.lpstorm import IMasterStore
469
470-from lp.archiveuploader.permission import check_upload_to_archive
471 from lp.code.interfaces.sourcepackagerecipe import (
472 ISourcePackageRecipe, ISourcePackageRecipeSource,
473 ISourcePackageRecipeData)
474@@ -153,9 +152,9 @@
475 if archive.purpose != ArchivePurpose.PPA:
476 raise NonPPABuildRequest
477 component = getUtility(IComponentSet)["multiverse"]
478- reject_reason = check_upload_to_archive(
479- requester, distroseries, self.sourcepackagename,
480- archive, component, pocket)
481+ reject_reason = archive.checkUpload(
482+ requester, self.distroseries, self.sourcepackagename,
483+ component, pocket)
484 if reject_reason is not None:
485 raise reject_reason
486
487
488=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
489--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-04-30 12:33:16 +0000
490+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-05-11 14:12:39 +0000
491@@ -24,8 +24,8 @@
492 from canonical.testing.layers import DatabaseFunctionalLayer, AppServerLayer
493
494 from canonical.launchpad.webapp.authorization import check_permission
495-from lp.archiveuploader.permission import (
496- ArchiveDisabled, CannotUploadToArchive, InvalidPocketForPPA)
497+from lp.soyuz.interfaces.archive import (
498+ ArchiveDisabled, ArchivePurpose, CannotUploadToArchive, InvalidPocketForPPA)
499 from lp.buildmaster.interfaces.buildqueue import IBuildQueue
500 from lp.buildmaster.model.buildqueue import BuildQueue
501 from lp.code.interfaces.sourcepackagerecipe import (
502@@ -40,7 +40,6 @@
503 from lp.registry.interfaces.pocket import PackagePublishingPocket
504 from lp.services.job.interfaces.job import (
505 IJob, JobStatus)
506-from lp.soyuz.interfaces.archive import ArchivePurpose
507 from lp.testing import (
508 ANONYMOUS, launchpadlib_for, login, login_person, person_logged_in,
509 TestCaseWithFactory, ws_object)
510
511=== modified file 'lib/lp/code/tests/test_branch.py'
512--- lib/lp/code/tests/test_branch.py 2010-03-18 17:49:21 +0000
513+++ lib/lp/code/tests/test_branch.py 2010-05-11 14:12:39 +0000
514@@ -12,7 +12,6 @@
515 from canonical.launchpad.webapp.authorization import check_permission
516 from canonical.testing import DatabaseFunctionalLayer
517
518-from lp.archiveuploader.permission import verify_upload
519 from lp.code.enums import (
520 BranchSubscriptionDiffSize, BranchSubscriptionNotificationLevel,
521 CodeReviewNotificationLevel)
522@@ -277,8 +276,8 @@
523 distroseries = archive.distribution.currentseries
524 self.assertIs(
525 None,
526- verify_upload(
527- person, spn, archive, component, distroseries,
528+ archive.verifyUpload(
529+ person, spn, component, distroseries,
530 strict_component))
531
532 def assertCannotUpload(
533@@ -295,8 +294,8 @@
534 """
535 if distroseries is None:
536 distroseries = archive.distribution.currentseries
537- exception = verify_upload(
538- person, spn, archive, component, distroseries)
539+ exception = archive.verifyUpload(
540+ person, spn, component, distroseries)
541 self.assertEqual(reason, str(exception))
542
543 def test_package_upload_permissions_grant_branch_edit(self):
544
545=== modified file 'lib/lp/soyuz/browser/archive.py'
546--- lib/lp/soyuz/browser/archive.py 2010-04-30 03:10:17 +0000
547+++ lib/lp/soyuz/browser/archive.py 2010-05-11 14:12:39 +0000
548@@ -1236,7 +1236,8 @@
549 # XXX cprov 2009-07-17 bug=385503: copies cannot be properly traced
550 # that's why we explicitly don't allow them do be done via the UI
551 # in main archives, only PPAs.
552- return self.context.is_ppa and self.context.canUpload(self.user)
553+ return (self.context.is_ppa and
554+ self.context.checkArchivePermission(self.user))
555
556 def createDestinationArchiveField(self):
557 """Create the 'destination_archive' field."""
558
559=== modified file 'lib/lp/soyuz/doc/archive.txt'
560--- lib/lp/soyuz/doc/archive.txt 2010-05-06 10:05:49 +0000
561+++ lib/lp/soyuz/doc/archive.txt 2010-05-11 14:12:39 +0000
562@@ -276,7 +276,7 @@
563
564 Uploads to copy archives are not allowed.
565
566- >>> rebuild_archive.canUpload(cprov)
567+ >>> rebuild_archive.checkArchivePermission(cprov)
568 Traceback (most recent call last):
569 ...
570 AssertionError: Uploads to copy archives are not allowed.
571@@ -2106,7 +2106,7 @@
572
573 == Archive Permission Checking ==
574
575-IArchive has two public methods, canUpload() and canAdministerQueue()
576+IArchive has two public methods, checkArchivePermission() and canAdministerQueue()
577 that check a user's permission to upload and/or administer a
578 distroseries upload queue respectively. See archivepermission.txt
579 for more details.
580@@ -2114,40 +2114,40 @@
581 >>> ubuntu_team = getUtility(IPersonSet).getByName('ubuntu-team')
582 >>> carlos = getUtility(IPersonSet).getByName('carlos')
583
584- >>> ubuntu.main_archive.canUpload(carlos, main_component)
585+ >>> ubuntu.main_archive.checkArchivePermission(carlos, main_component)
586 False
587
588 >>> ubuntu.main_archive.canAdministerQueue(carlos, main_component)
589 False
590
591- >>> ubuntu.main_archive.canUpload(ubuntu_team, main_component)
592+ >>> ubuntu.main_archive.checkArchivePermission(ubuntu_team, main_component)
593 True
594
595 >>> ubuntu.main_archive.canAdministerQueue(ubuntu_team, main_component)
596 True
597
598-canUpload() can also check someone's permission to upload a specific
599+checkArchivePermission() can also check someone's permission to upload a specific
600 source package. Carlos, who does not have permission to upload to any
601 Ubuntu components, has permission to upload "mozilla-firefox".
602
603 >>> from canonical.launchpad.interfaces import ISourcePackageNameSet
604 >>> mozilla = getUtility(
605 ... ISourcePackageNameSet).queryByName("mozilla-firefox")
606- >>> ubuntu.main_archive.canUpload(carlos, mozilla)
607+ >>> ubuntu.main_archive.checkArchivePermission(carlos, mozilla)
608 True
609
610 Cprov does not have permission, however.
611
612- >>> ubuntu.main_archive.canUpload(cprov, mozilla)
613+ >>> ubuntu.main_archive.checkArchivePermission(cprov, mozilla)
614 False
615
616-canUpload() also works in the same way for PPAs. By default, it allows
617+checkArchivePermission() also works in the same way for PPAs. By default, it allows
618 anyone in the PPA owning team to upload.
619
620- >>> cprov_archive.canUpload(cprov)
621+ >>> cprov_archive.checkArchivePermission(cprov)
622 True
623
624- >>> cprov_archive.canUpload(carlos)
625+ >>> cprov_archive.checkArchivePermission(carlos)
626 False
627
628 We can also create an ArchivePermission entry for carlos to be able to upload
629@@ -2159,7 +2159,7 @@
630
631 Carlos can now upload to Joe's PPA:
632
633- >>> joes_ppa.canUpload(carlos)
634+ >>> joes_ppa.checkArchivePermission(carlos)
635 True
636
637 Note that when creating a new permission, trying to specify a component other
638
639=== modified file 'lib/lp/soyuz/doc/archivepermission.txt'
640--- lib/lp/soyuz/doc/archivepermission.txt 2010-03-08 17:06:41 +0000
641+++ lib/lp/soyuz/doc/archivepermission.txt 2010-05-11 14:12:39 +0000
642@@ -108,7 +108,7 @@
643 ... ubuntu)
644 Traceback (most recent call last):
645 ...
646- AssertionError: 'item' is not an IComponent, IPackageset or an
647+ AssertionError: 'item' ... is not an IComponent, IPackageset or an
648 ISourcePackageName
649
650 IArchivePermissionSet also has some helpers to make it very easy to
651
652=== modified file 'lib/lp/soyuz/doc/nascentupload.txt'
653--- lib/lp/soyuz/doc/nascentupload.txt 2010-03-11 16:09:29 +0000
654+++ lib/lp/soyuz/doc/nascentupload.txt 2010-05-11 14:12:39 +0000
655@@ -879,9 +879,8 @@
656 >>> bar_failed.is_rejected
657 True
658 >>> print bar_failed.rejection_message
659- The signer of this package has no upload rights to this distribution's
660- primary archive. Did you mean to upload to a PPA?
661-
662+ The signer of this package is lacking the upload rights for the source
663+ package, component or package set in question.
664
665 Even in a rejected upload using 'insecure' policy, the DSC signing key
666 and the changesfile sigining key are stored in NascentUpload instance
667
668=== modified file 'lib/lp/soyuz/interfaces/archive.py'
669--- lib/lp/soyuz/interfaces/archive.py 2010-03-26 17:30:33 +0000
670+++ lib/lp/soyuz/interfaces/archive.py 2010-05-11 14:12:39 +0000
671@@ -11,12 +11,15 @@
672 'ALLOW_RELEASE_BUILDS',
673 'AlreadySubscribed',
674 'ArchiveDependencyError',
675+ 'ArchiveDisabled',
676 'ArchiveNotPrivate',
677 'ArchivePurpose',
678 'ArchiveStatus',
679 'CannotCopy',
680 'CannotSwitchPrivacy',
681 'ComponentNotFound',
682+ 'CannotUploadToPPA',
683+ 'CannotUploadToPocket',
684 'DistroSeriesNotFound',
685 'IArchive',
686 'IArchiveAppend',
687@@ -26,10 +29,15 @@
688 'IArchivePublic',
689 'IArchiveSet',
690 'IDistributionArchive',
691+ 'InsufficientUploadRights',
692 'InvalidComponent',
693+ 'InvalidPocketForPartnerArchive',
694+ 'InvalidPocketForPPA',
695 'IPPA',
696 'IPPAActivateForm',
697 'MAIN_ARCHIVE_PURPOSES',
698+ 'NoRightsForArchive',
699+ 'NoRightsForComponent',
700 'NoSuchPPA',
701 'NoTokensForTeams',
702 'PocketNotFound',
703@@ -133,6 +141,79 @@
704 webservice_error(400) # Bad request.
705
706
707+class CannotUploadToArchive(Exception):
708+ """A reason for not being able to upload to an archive."""
709+
710+ _fmt = '%(person)s has no upload rights to %(archive)s.'
711+
712+ def __init__(self, **args):
713+ """Construct a `CannotUploadToArchive`."""
714+ Exception.__init__(self, self._fmt % args)
715+
716+
717+class InvalidPocketForPartnerArchive(CannotUploadToArchive):
718+ """Partner archives only support some pockets."""
719+
720+ _fmt = "Partner uploads must be for the RELEASE or PROPOSED pocket."
721+
722+
723+class CannotUploadToPocket(Exception):
724+ """Returned when a pocket is closed for uploads."""
725+
726+ def __init__(self, distroseries, pocket):
727+ Exception.__init__(self,
728+ "Not permitted to upload to the %s pocket in a series in the "
729+ "'%s' state." % (pocket.name, distroseries.status.name))
730+
731+
732+class CannotUploadToPPA(CannotUploadToArchive):
733+ """Raised when a person cannot upload to a PPA."""
734+
735+ _fmt = 'Signer has no upload rights to this PPA.'
736+
737+
738+class NoRightsForArchive(CannotUploadToArchive):
739+ """Raised when a person has absolutely no upload rights to an archive."""
740+
741+ _fmt = (
742+ "The signer of this package has no upload rights to this "
743+ "distribution's primary archive. Did you mean to upload to "
744+ "a PPA?")
745+
746+
747+class InsufficientUploadRights(CannotUploadToArchive):
748+ """Raised when a person has insufficient upload rights."""
749+ _fmt = (
750+ "The signer of this package is lacking the upload rights for "
751+ "the source package, component or package set in question.")
752+
753+
754+class NoRightsForComponent(CannotUploadToArchive):
755+ """Raised when a person tries to upload to a component without permission.
756+ """
757+
758+ _fmt = (
759+ "Signer is not permitted to upload to the component '%(component)s'.")
760+
761+ def __init__(self, component):
762+ CannotUploadToArchive.__init__(self, component=component.name)
763+
764+
765+class InvalidPocketForPPA(CannotUploadToArchive):
766+ """PPAs only support some pockets."""
767+
768+ _fmt = "PPA uploads must be for the RELEASE pocket."
769+
770+
771+class ArchiveDisabled(CannotUploadToArchive):
772+ """Uploading to a disabled archive is not allowed."""
773+
774+ _fmt = ("%(archive_name)s is disabled.")
775+
776+ def __init__(self, archive_name):
777+ CannotUploadToArchive.__init__(self, archive_name=archive_name)
778+
779+
780 class IArchivePublic(IHasOwner, IPrivacy):
781 """An Archive interface for publicly available operations."""
782 id = Attribute("The archive ID.")
783@@ -380,7 +461,7 @@
784 :return: A list of `IArchivePermission` records.
785 """
786
787- def canUpload(person, component_or_package=None):
788+ def checkArchivePermission(person, component_or_package=None):
789 """Check to see if person is allowed to upload to component.
790
791 :param person: An `IPerson` whom should be checked for authentication.
792@@ -395,6 +476,53 @@
793
794 """
795
796+ def canUploadSuiteSourcePackage(person, suitesourcepackage):
797+ """Check if 'person' upload 'suitesourcepackage' to 'archive'.
798+
799+ :param person: An `IPerson` who might be uploading.
800+ :param suitesourcepackage: An `ISuiteSourcePackage` to be uploaded.
801+ :return: True if they can, False if they cannot.
802+ """
803+
804+ def checkUploadToPocket(distroseries, pocket):
805+ """Check if uploading to a particular pocket in an archive is possible.
806+
807+ :param distroseries: A `IDistroSeries`
808+ :param pocket: A `PackagePublishingPocket`
809+ :return: Reason why uploading is not possible or None
810+ """
811+
812+ def checkUpload(person, distroseries, sourcepackagename, component,
813+ pocket, strict_component=True):
814+ """Check if 'person' upload 'suitesourcepackage' to 'archive'.
815+
816+ :param person: An `IPerson` who might be uploading.
817+ :param distroseries: The `IDistroSeries` being uploaded to.
818+ :param sourcepackagename: The `ISourcePackageName` being uploaded.
819+ :param component: The `Component` being uploaded to.
820+ :param pocket: The `PackagePublishingPocket` of 'distroseries' being
821+ uploaded to.
822+ :return: The reason for not being able to upload, None otherwise.
823+ """
824+
825+ def verifyUpload(person, sourcepackagename, component,
826+ distroseries, strict_component=True):
827+ """Can 'person' upload 'sourcepackagename' to this archive ?
828+
829+ :param person: The `IPerson` trying to upload to the package. Referred to
830+ as 'the signer' in upload code.
831+ :param sourcepackagename: The source package being uploaded. None if the
832+ package is new.
833+ :param archive: The `IArchive` being uploaded to.
834+ :param component: The `IComponent` that the source package belongs to.
835+ :param distroseries: The upload's target distro series.
836+ :param strict_component: True if access to the specific component for the
837+ package is needed to upload to it. If False, then access to any
838+ package will do.
839+ :return: CannotUploadToArchive if 'person' cannot upload to the archive,
840+ None otherwise.
841+ """
842+
843 def canAdministerQueue(person, component):
844 """Check to see if person is allowed to administer queue items.
845
846@@ -564,6 +692,13 @@
847 'person' is allowed to upload to.
848 """
849
850+ def getComponentsForUploader(person):
851+ """Return the components that 'person' can upload to this archive.
852+
853+ :param person: An `IPerson` wishing to upload to an archive.
854+ :return: A `set` of `IComponent`s that 'person' can upload to.
855+ """
856+
857 @operation_parameters(
858 sourcepackagename=TextLine(
859 title=_("Source package name"), required=True),
860
861=== modified file 'lib/lp/soyuz/model/archive.py'
862--- lib/lp/soyuz/model/archive.py 2010-05-06 10:05:49 +0000
863+++ lib/lp/soyuz/model/archive.py 2010-05-11 14:12:39 +0000
864@@ -58,11 +58,14 @@
865 from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
866 from lp.registry.model.teammembership import TeamParticipation
867 from lp.soyuz.interfaces.archive import (
868- AlreadySubscribed, ArchiveDependencyError, ArchiveNotPrivate,
869- ArchivePurpose, ArchiveStatus, CannotCopy, CannotSwitchPrivacy,
870+ AlreadySubscribed, ArchiveDependencyError, ArchiveDisabled,
871+ ArchiveNotPrivate, ArchivePurpose, ArchiveStatus, CannotCopy,
872+ CannotSwitchPrivacy, CannotUploadToPPA, CannotUploadToPocket,
873 DistroSeriesNotFound, IArchive, IArchiveSet, IDistributionArchive,
874- InvalidComponent, IPPA, MAIN_ARCHIVE_PURPOSES, NoSuchPPA,
875- NoTokensForTeams, PocketNotFound, VersionRequiresName,
876+ InsufficientUploadRights, InvalidPocketForPPA,
877+ InvalidPocketForPartnerArchive, InvalidComponent, IPPA,
878+ MAIN_ARCHIVE_PURPOSES, NoRightsForArchive, NoRightsForComponent,
879+ NoSuchPPA, NoTokensForTeams, PocketNotFound, VersionRequiresName,
880 default_name_by_purpose)
881 from lp.soyuz.interfaces.archiveauthtoken import IArchiveAuthTokenSet
882 from lp.soyuz.interfaces.archivearch import IArchiveArchSet
883@@ -954,7 +957,7 @@
884 source_ids,
885 archive=self)
886
887- def canUpload(self, user, component_or_package=None):
888+ def checkArchivePermission(self, user, component_or_package=None):
889 """See `IArchive`."""
890 assert not self.is_copy, "Uploads to copy archives are not allowed."
891 # PPA access is immediately granted if the user is in the PPA
892@@ -977,6 +980,87 @@
893 return self._authenticate(
894 user, component_or_package, ArchivePermissionType.UPLOAD)
895
896+ def canUploadSuiteSourcePackage(self, person, suitesourcepackage):
897+ """See `IArchive`."""
898+ sourcepackage = suitesourcepackage.sourcepackage
899+ pocket = suitesourcepackage.pocket
900+ distroseries = sourcepackage.distroseries
901+ sourcepackagename = sourcepackage.sourcepackagename
902+ component = sourcepackage.latest_published_component
903+ # strict_component is True because the source package already exists
904+ # (otherwise we couldn't have a suitesourcepackage object) and
905+ # nascentupload passes True as a matter of policy when the package exists.
906+ reason = self.checkUpload(
907+ person, distroseries, sourcepackagename, component, pocket,
908+ strict_component=True)
909+ return reason is None
910+
911+ def checkUploadToPocket(self, distroseries, pocket):
912+ """See `IArchive`."""
913+ if self.purpose == ArchivePurpose.PARTNER:
914+ if pocket not in (
915+ PackagePublishingPocket.RELEASE,
916+ PackagePublishingPocket.PROPOSED):
917+ return InvalidPocketForPartnerArchive()
918+ elif self.is_ppa:
919+ if pocket != PackagePublishingPocket.RELEASE:
920+ return InvalidPocketForPPA()
921+ else:
922+ # Uploads to the partner archive are allowed in any distroseries
923+ # state.
924+ # XXX julian 2005-05-29 bug=117557:
925+ # This is a greasy hack until bug #117557 is fixed.
926+ if not distroseries.canUploadToPocket(pocket):
927+ return CannotUploadToPocket(distroseries, pocket)
928+
929+ def checkUpload(self, person, distroseries, sourcepackagename, component,
930+ pocket, strict_component=True):
931+ """See `IArchive`."""
932+ reason = self.checkUploadToPocket(distroseries, pocket)
933+ if reason is not None:
934+ return reason
935+ return self.verifyUpload(
936+ person, sourcepackagename, component, distroseries,
937+ strict_component)
938+
939+ def verifyUpload(self, person, sourcepackagename, component,
940+ distroseries, strict_component=True):
941+ """See `IArchive`."""
942+ if not self.enabled:
943+ return ArchiveDisabled(self.displayname)
944+
945+ # For PPAs...
946+ if self.is_ppa:
947+ if not self.checkArchivePermission(person):
948+ return CannotUploadToPPA()
949+ else:
950+ return None
951+
952+ if sourcepackagename is not None:
953+ # Check whether user may upload because they hold a permission for
954+ # - the given source package directly
955+ # - a package set in the correct distro series that includes the
956+ # given source package
957+ source_allowed = self.checkArchivePermission(person,
958+ sourcepackagename)
959+ set_allowed = self.isSourceUploadAllowed(
960+ sourcepackagename, person, distroseries)
961+ if source_allowed or set_allowed:
962+ return None
963+
964+ if not self.getComponentsForUploader(person):
965+ if not self.getPackagesetsForUploader(person):
966+ return NoRightsForArchive()
967+ else:
968+ return InsufficientUploadRights()
969+
970+ if (component is not None
971+ and strict_component
972+ and not self.checkArchivePermission(person, component)):
973+ return NoRightsForComponent(component)
974+
975+ return None
976+
977 def canAdministerQueue(self, user, component):
978 """See `IArchive`."""
979 return self._authenticate(
980@@ -1050,6 +1134,11 @@
981 return permission_set.deletePackagesetUploader(
982 self, person, packageset, explicit)
983
984+ def getComponentsForUploader(self, person):
985+ """See `IArchive`."""
986+ permission_set = getUtility(IArchivePermissionSet)
987+ return permission_set.componentsForUploader(self, person)
988+
989 def getPackagesetsForUploader(self, person):
990 """See `IArchive`."""
991 permission_set = getUtility(IArchivePermissionSet)
992
993=== modified file 'lib/lp/soyuz/model/archivepermission.py'
994--- lib/lp/soyuz/model/archivepermission.py 2010-03-08 17:06:41 +0000
995+++ lib/lp/soyuz/model/archivepermission.py 2010-05-11 14:12:39 +0000
996@@ -151,8 +151,8 @@
997 prejoins.append("packageset")
998 else:
999 raise AssertionError(
1000- "'item' is not an IComponent, IPackageset or an "
1001- "ISourcePackageName")
1002+ "'item' %r is not an IComponent, IPackageset or an "
1003+ "ISourcePackageName" % item)
1004
1005 query = " AND ".join(clauses)
1006 auth = ArchivePermission.select(
1007
1008=== modified file 'lib/lp/soyuz/model/binarypackagebuildbehavior.py'
1009--- lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-04-12 05:52:01 +0000
1010+++ lib/lp/soyuz/model/binarypackagebuildbehavior.py 2010-05-11 14:12:39 +0000
1011@@ -15,7 +15,6 @@
1012
1013 from canonical.launchpad.webapp import urlappend
1014
1015-from lp.archiveuploader.permission import check_upload_to_pocket
1016 from lp.buildmaster.interfaces.buildfarmjobbehavior import (
1017 IBuildFarmJobBehavior)
1018 from lp.buildmaster.model.buildfarmjobbehavior import (
1019@@ -123,8 +122,8 @@
1020
1021 # This should already have been checked earlier, but just check again
1022 # here in case of programmer errors.
1023- reason = check_upload_to_pocket(
1024- build.archive, build.distroseries, build.pocket)
1025+ reason = build.archive.checkUploadToPocket(build.distroseries,
1026+ build.pocket)
1027 assert reason is None, (
1028 "%s (%s) can not be built for pocket %s: invalid pocket due "
1029 "to the series status of %s." %
1030
1031=== modified file 'lib/lp/soyuz/tests/test_archive.py'
1032--- lib/lp/soyuz/tests/test_archive.py 2010-05-03 07:48:54 +0000
1033+++ lib/lp/soyuz/tests/test_archive.py 2010-05-11 14:12:39 +0000
1034@@ -18,13 +18,16 @@
1035 from lp.buildmaster.interfaces.buildbase import BuildStatus
1036 from lp.registry.interfaces.distribution import IDistributionSet
1037 from lp.registry.interfaces.person import IPersonSet
1038+from lp.registry.interfaces.pocket import PackagePublishingPocket
1039 from lp.services.job.interfaces.job import JobStatus
1040+from lp.soyuz.interfaces.archive import (IArchiveSet, ArchivePurpose,
1041+ ArchiveStatus, CannotSwitchPrivacy, InvalidPocketForPartnerArchive,
1042+ InvalidPocketForPPA)
1043 from lp.services.worlddata.interfaces.country import ICountrySet
1044-from lp.soyuz.interfaces.archive import (
1045- IArchiveSet, ArchivePurpose, ArchiveStatus, CannotSwitchPrivacy)
1046 from lp.soyuz.interfaces.archivearch import IArchiveArchSet
1047 from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
1048 from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat
1049+from lp.soyuz.interfaces.component import IComponentSet
1050 from lp.soyuz.interfaces.processor import IProcessorFamilySet
1051 from lp.soyuz.interfaces.publishing import PackagePublishingStatus
1052 from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
1053@@ -345,6 +348,7 @@
1054 self.failUnlessEqual(
1055 self.sourcepackagereleases[0], result[0])
1056
1057+
1058 class TestCorrespondingDebugArchive(TestCaseWithFactory):
1059
1060 layer = LaunchpadZopelessLayer
1061@@ -520,6 +524,7 @@
1062 self.archive.disable()
1063 self.assertRaises(AssertionError, self.archive.disable)
1064
1065+
1066 class TestCollectLatestPublishedSources(TestCaseWithFactory):
1067 """Ensure that the private helper method works as expected."""
1068
1069@@ -566,6 +571,70 @@
1070 self.assertEqual('0.5.11~ppa1', pubs[0].source_package_version)
1071
1072
1073+class TestArchiveCanUpload(TestCaseWithFactory):
1074+ """Test the various methods that verify whether uploads are allowed to
1075+ happen."""
1076+
1077+ layer = LaunchpadZopelessLayer
1078+
1079+ def test_checkArchivePermission_by_PPA_owner(self):
1080+ # Uploading to a PPA should be allowed for a user that is the owner
1081+ owner = self.factory.makePerson(name="somebody")
1082+ archive = self.factory.makeArchive(owner=owner)
1083+ self.assertEquals(True, archive.checkArchivePermission(owner))
1084+ someone_unrelated = self.factory.makePerson(name="somebody-unrelated")
1085+ self.assertEquals(False,
1086+ archive.checkArchivePermission(someone_unrelated))
1087+
1088+ def test_checkArchivePermission_distro_archive(self):
1089+ # Regular users can not upload to ubuntu
1090+ ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
1091+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY,
1092+ distribution=ubuntu)
1093+ main = getUtility(IComponentSet)["main"]
1094+ # A regular user doesn't have access
1095+ somebody = self.factory.makePerson(name="somebody")
1096+ self.assertEquals(False,
1097+ archive.checkArchivePermission(somebody, main))
1098+ # An ubuntu core developer does have access
1099+ kamion = getUtility(IPersonSet).getByName('kamion')
1100+ self.assertEquals(True, archive.checkArchivePermission(kamion, main))
1101+
1102+ def test_checkArchivePermission_ppa(self):
1103+ ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
1104+ owner = self.factory.makePerson(name="eigenaar")
1105+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PPA,
1106+ distribution=ubuntu,
1107+ owner=owner)
1108+ somebody = self.factory.makePerson(name="somebody")
1109+ # The owner has access
1110+ self.assertEquals(True, archive.checkArchivePermission(owner))
1111+ # Somebody unrelated does not
1112+ self.assertEquals(False, archive.checkArchivePermission(somebody))
1113+
1114+ def test_checkUpload_partner_invalid_pocket(self):
1115+ # Partner archives only have release and proposed pockets
1116+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PARTNER)
1117+ self.assertIsInstance(archive.checkUpload(self.factory.makePerson(),
1118+ self.factory.makeDistroSeries(),
1119+ self.factory.makeSourcePackageName(),
1120+ self.factory.makeComponent(),
1121+ PackagePublishingPocket.UPDATES),
1122+ InvalidPocketForPartnerArchive)
1123+
1124+ def test_checkUpload_ppa_invalid_pocket(self):
1125+ # PPA archives only have release pockets
1126+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
1127+ self.assertIsInstance(archive.checkUpload(self.factory.makePerson(),
1128+ self.factory.makeDistroSeries(),
1129+ self.factory.makeSourcePackageName(),
1130+ self.factory.makeComponent(),
1131+ PackagePublishingPocket.PROPOSED),
1132+ InvalidPocketForPPA)
1133+
1134+ # XXX: JRV 20100511: IArchive.canUploadSuiteSourcePackage needs tests
1135+
1136+
1137 class TestUpdatePackageDownloadCount(TestCaseWithFactory):
1138 """Ensure that updatePackageDownloadCount works as expected."""
1139