Merge lp:~adeuring/launchpad/product-lp-limitedview-2 into lp:launchpad

Proposed by Abel Deuring
Status: Merged
Approved by: Abel Deuring
Approved revision: no longer in the source branch.
Merged at revision: 16257
Proposed branch: lp:~adeuring/launchpad/product-lp-limitedview-2
Merge into: lp:launchpad
Diff against target: 290 lines (+109/-55)
4 files modified
lib/lp/bugs/browser/tests/test_bug_views.py (+23/-0)
lib/lp/registry/configure.zcml (+31/-1)
lib/lp/registry/interfaces/product.py (+41/-41)
lib/lp/registry/tests/test_product.py (+14/-13)
To merge this branch: bzr merge lp:~adeuring/launchpad/product-lp-limitedview-2
Reviewer Review Type Date Requested Status
j.c.sackett (community) Approve
Review via email: mp+133481@code.launchpad.net

Commit message

Require the permission launchpad.LimitedView for IProduct attributes needed to render a bug page.

Description of the change

This branch changes the permision required to access a number
of IProduct attributes from launchpad.View to
launchpad.LimitedView.

The changes are necessary to let a user with an artifact grant on
a bug of a private product view the main bug page. This is tested in
test_bugtask_view_user_with_grant_on_bug_for_private_product().

For some attributes, this means that an attribute definition
is moved from the interface class IProductView to IProductLimitedView.

Other attributes are defined in classes which IProductView inherited from.
If these classes defined just the attributes required to let the test pass
(IHasLogo and IHasOnwer) or if the attributes do not provide any data that
might be considered "really confidential", those of ILaunchpadUsage,
these classes are inherited by IProductLimitedView.

Permissions for IBugTarget and IStructuralSubscriptionTarget are now
defined attribute by attribute.

These changes are not sufficient to let a user with a grant on a bug
view bug pages: LP's traversal machinery still return a 404 error
because it checks if the current user has the permission lp.View for
the bug's target. I'll fix this in another branch.

tests:

./bin/test bugs -vvt test_bugtask_view_user_with_grant_on_bug_for_private_product
./bin/test registry -vvt lp.registry.tests.test_product.TestProduct.test_access
./bin/test registry -vvt lp.registry.tests.test_product.TestProduct.test_.et_permissions

no lint

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

Abel--

This looks ok, just one nitpick you can address before landing.

#16: It seems odd to have a test with no assertions--I believe this may throw
off some test machinery. At a minimum, probably worth testing that the bug
does show in contents:

    contents = view.render()
    self.assertTrue(bug.title in contents)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/browser/tests/test_bug_views.py'
--- lib/lp/bugs/browser/tests/test_bug_views.py 2012-11-11 23:39:34 +0000
+++ lib/lp/bugs/browser/tests/test_bug_views.py 2012-11-12 11:53:43 +0000
@@ -28,6 +28,7 @@
28from zope.security.proxy import removeSecurityProxy28from zope.security.proxy import removeSecurityProxy
2929
30from lp.app.enums import InformationType30from lp.app.enums import InformationType
31from lp.app.interfaces.services import IService
31from lp.bugs.adapters.bugchange import BugAttachmentChange32from lp.bugs.adapters.bugchange import BugAttachmentChange
32from lp.registry.enums import BugSharingPolicy33from lp.registry.enums import BugSharingPolicy
33from lp.registry.interfaces.accesspolicy import (34from lp.registry.interfaces.accesspolicy import (
@@ -499,6 +500,28 @@
499 self.assertEqual(500 self.assertEqual(
500 u'Private', soup.find('label', text="Private"))501 u'Private', soup.find('label', text="Private"))
501502
503 def test_bugtask_view_user_with_grant_on_bug_for_private_product(self):
504 # The regular bug view is properly rendered even if the user
505 # does not have permissions to view every detail of a product.
506 owner = self.factory.makePerson()
507 product = self.factory.makeProduct(
508 owner=owner,
509 information_type=InformationType.PROPRIETARY)
510 user = self.factory.makePerson()
511 with person_logged_in(owner):
512 bug = self.factory.makeBug(
513 target=product, information_type=InformationType.PROPRIETARY)
514 getUtility(IService, 'sharing').ensureAccessGrants(
515 [user], owner, bugs=[bug])
516 launchbag = getUtility(IOpenLaunchBag)
517 launchbag.add(bug)
518 launchbag.add(bug.default_bugtask)
519 with person_logged_in(user):
520 view = create_initialized_view(
521 bug.default_bugtask, name=u'+index', principal=user)
522 contents = view.render()
523 self.assertTrue(bug.title in contents)
524
502525
503class TestBugTextViewPrivateTeams(TestCaseWithFactory):526class TestBugTextViewPrivateTeams(TestCaseWithFactory):
504 """ Test for rendering BugTextView with private team artifacts.527 """ Test for rendering BugTextView with private team artifacts.
505528
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2012-11-11 23:39:34 +0000
+++ lib/lp/registry/configure.zcml 2012-11-12 11:53:43 +0000
@@ -1356,6 +1356,25 @@
1356 set_schema="lp.registry.interfaces.product.IProductModerateRestricted"1356 set_schema="lp.registry.interfaces.product.IProductModerateRestricted"
1357 set_attributes="active"/>1357 set_attributes="active"/>
13581358
1359 <!-- IBugTarget -->
1360
1361 <require
1362 permission="launchpad.LimitedView"
1363 attributes="
1364 bugtargetdisplayname"/>
1365
1366 <require
1367 permission="launchpad.View"
1368 attributes="
1369 bug_reported_acknowledgement
1370 bug_reporting_guidelines
1371 bugtargetname
1372 createBug
1373 enable_bugfiling_duplicate_search
1374 getBugTaskWeightFunction
1375 pillar
1376 searchTasks"/>
1377
1359 <!-- IHasAliases -->1378 <!-- IHasAliases -->
13601379
1361 <require1380 <require
@@ -1391,8 +1410,19 @@
1391 <!-- IStructuralSubscriptionTarget -->1410 <!-- IStructuralSubscriptionTarget -->
13921411
1393 <require1412 <require
1413 permission="launchpad.LimitedView"
1414 attributes="
1415 parent_subscription_target" />
1416 <require
1394 permission="launchpad.View"1417 permission="launchpad.View"
1395 interface="lp.bugs.interfaces.structuralsubscription.IStructuralSubscriptionTargetRead" />1418 attributes="
1419 bug_subscriptions
1420 getSubscription
1421 getSubscriptions
1422 target_type_display
1423 userCanAlterBugSubscription
1424 userCanAlterSubscription
1425 userHasBugSubscriptions" />
1396 <require1426 <require
1397 permission="launchpad.AnyAllowedPerson"1427 permission="launchpad.AnyAllowedPerson"
1398 interface="lp.bugs.interfaces.structuralsubscription.IStructuralSubscriptionTargetWrite" />1428 interface="lp.bugs.interfaces.structuralsubscription.IStructuralSubscriptionTargetWrite" />
13991429
=== modified file 'lib/lp/registry/interfaces/product.py'
--- lib/lp/registry/interfaces/product.py 2012-11-11 23:39:34 +0000
+++ lib/lp/registry/interfaces/product.py 2012-11-12 11:53:43 +0000
@@ -428,11 +428,27 @@
428 """True if the given user has access to this product."""428 """True if the given user has access to this product."""
429429
430430
431class IProductLimitedView(Interface):431class IProductLimitedView(IHasLogo, IHasOwner, ILaunchpadUsage):
432 """Attributes that must be visible for person with artifact grants432 """Attributes that must be visible for person with artifact grants
433 on bugs, branches or specifications for the product.433 on bugs, branches or specifications for the product.
434 """434 """
435435
436 displayname = exported(
437 TextLine(
438 title=_('Display Name'),
439 description=_("""The name of the project as it would appear in a
440 paragraph.""")),
441 exported_as='display_name')
442
443 logo = exported(
444 LogoImageUpload(
445 title=_("Logo"), required=False,
446 default_image_resource='/@@/product-logo',
447 description=_(
448 "An image of exactly 64x64 pixels that will be displayed in "
449 "the heading of all pages related to this project. It should "
450 "be no bigger than 50kb in size.")))
451
436 name = exported(452 name = exported(
437 ProductNameField(453 ProductNameField(
438 title=_('Name'),454 title=_('Name'),
@@ -442,16 +458,14 @@
442 "letters, numbers, dots, hyphens or pluses. "458 "letters, numbers, dots, hyphens or pluses. "
443 "Keep this name short; it is used in URLs as shown above.")))459 "Keep this name short; it is used in URLs as shown above.")))
444460
445461 owner = exported(
446class IProductView(462 PersonChoice(
447 IBugTarget, ICanGetMilestonesDirectly, IHasAppointedDriver, IHasBranches,463 title=_('Maintainer'),
448 IHasDrivers, IHasExternalBugTracker, IHasIcon,464 required=True,
449 IHasLogo, IHasMergeProposals, IHasMilestones, IHasExpirableBugs,465 vocabulary='ValidPillarOwner',
450 IHasMugshot, IHasOwner, IHasSprints, IHasTranslationImports,466 description=_("The restricted team, moderated team, or person "
451 ITranslationPolicy, IKarmaContext, ILaunchpadUsage, IMakesAnnouncements,467 "who maintains the project information in "
452 IOfficialBugTagTargetPublic, IHasOOPSReferences,468 "Launchpad.")))
453 ISpecificationTarget, IHasRecipes, IHasCodeImports, IServiceUsage):
454 """Public IProduct properties."""
455469
456 project = exported(470 project = exported(
457 ReferenceChoice(471 ReferenceChoice(
@@ -469,14 +483,21 @@
469 'and security policy will apply to this project.')),483 'and security policy will apply to this project.')),
470 exported_as='project_group')484 exported_as='project_group')
471485
472 owner = exported(486 title = exported(
473 PersonChoice(487 Title(
474 title=_('Maintainer'),488 title=_('Title'),
475 required=True,489 description=_("The project title. Should be just a few words.")))
476 vocabulary='ValidPillarOwner',490
477 description=_("The restricted team, moderated team, or person "491
478 "who maintains the project information in "492class IProductView(
479 "Launchpad.")))493 ICanGetMilestonesDirectly, IHasAppointedDriver, IHasBranches,
494 IHasDrivers, IHasExternalBugTracker, IHasIcon,
495 IHasMergeProposals, IHasMilestones, IHasExpirableBugs,
496 IHasMugshot, IHasSprints, IHasTranslationImports,
497 ITranslationPolicy, IKarmaContext, IMakesAnnouncements,
498 IOfficialBugTagTargetPublic, IHasOOPSReferences,
499 ISpecificationTarget, IHasRecipes, IHasCodeImports, IServiceUsage):
500 """Public IProduct properties."""
480501
481 registrant = exported(502 registrant = exported(
482 PublicPersonChoice(503 PublicPersonChoice(
@@ -503,18 +524,6 @@
503 "required because there might be a project driver and also a "524 "required because there might be a project driver and also a "
504 "driver appointed in the overarching project group.")525 "driver appointed in the overarching project group.")
505526
506 displayname = exported(
507 TextLine(
508 title=_('Display Name'),
509 description=_("""The name of the project as it would appear in a
510 paragraph.""")),
511 exported_as='display_name')
512
513 title = exported(
514 Title(
515 title=_('Title'),
516 description=_("The project title. Should be just a few words.")))
517
518 summary = exported(527 summary = exported(
519 Summary(528 Summary(
520 title=_('Summary'),529 title=_('Summary'),
@@ -614,15 +623,6 @@
614 "will be displayed next to the project name everywhere in "623 "will be displayed next to the project name everywhere in "
615 "Launchpad that we refer to the project and link to it.")))624 "Launchpad that we refer to the project and link to it.")))
616625
617 logo = exported(
618 LogoImageUpload(
619 title=_("Logo"), required=False,
620 default_image_resource='/@@/product-logo',
621 description=_(
622 "An image of exactly 64x64 pixels that will be displayed in "
623 "the heading of all pages related to this project. It should "
624 "be no bigger than 50kb in size.")))
625
626 mugshot = exported(626 mugshot = exported(
627 MugshotImageUpload(627 MugshotImageUpload(
628 title=_("Brand"), required=False,628 title=_("Brand"), required=False,
@@ -917,7 +917,7 @@
917917
918918
919class IProduct(919class IProduct(
920 IHasBugSupervisor, IProductEditRestricted,920 IBugTarget, IHasBugSupervisor, IProductEditRestricted,
921 IProductModerateRestricted, IProductDriverRestricted, IProductView,921 IProductModerateRestricted, IProductDriverRestricted, IProductView,
922 IProductLimitedView, IProductPublic, IQuestionTarget, IRootContext,922 IProductLimitedView, IProductPublic, IQuestionTarget, IRootContext,
923 IStructuralSubscriptionTarget, IInformationType, IPillar):923 IStructuralSubscriptionTarget, IInformationType, IPillar):
924924
=== modified file 'lib/lp/registry/tests/test_product.py'
--- lib/lp/registry/tests/test_product.py 2012-11-11 23:39:34 +0000
+++ lib/lp/registry/tests/test_product.py 2012-11-12 11:53:43 +0000
@@ -551,7 +551,11 @@
551 CheckerPublic: set((551 CheckerPublic: set((
552 'active', 'id', 'information_type', 'pillar_category', 'private',552 'active', 'id', 'information_type', 'pillar_category', 'private',
553 'userCanView',)),553 'userCanView',)),
554 'launchpad.LimitedView': set(('name', )),554 'launchpad.LimitedView': set((
555 'bugtargetdisplayname', 'displayname', 'enable_bug_expiration',
556 'logo', 'name', 'official_answers', 'official_anything',
557 'official_blueprints', 'official_codehosting', 'official_malone',
558 'owner', 'parent_subscription_target', 'project', 'title', )),
555 'launchpad.View': set((559 'launchpad.View': set((
556 '_getOfficialTagClause', '_all_specifications',560 '_getOfficialTagClause', '_all_specifications',
557 '_valid_specifications', 'active_or_packaged_series',561 '_valid_specifications', 'active_or_packaged_series',
@@ -561,16 +565,15 @@
561 'blueprints_usage', 'branch_sharing_policy',565 'blueprints_usage', 'branch_sharing_policy',
562 'bug_reported_acknowledgement', 'bug_reporting_guidelines',566 'bug_reported_acknowledgement', 'bug_reporting_guidelines',
563 'bug_sharing_policy', 'bug_subscriptions', 'bug_supervisor',567 'bug_sharing_policy', 'bug_subscriptions', 'bug_supervisor',
564 'bug_tracking_usage', 'bugtargetdisplayname', 'bugtargetname',568 'bug_tracking_usage', 'bugtargetname',
565 'bugtracker', 'canUserAlterAnswerContact',569 'bugtracker', 'canUserAlterAnswerContact', 'codehosting_usage',
566 'codehosting_usage',
567 'coming_sprints', 'commercial_subscription',570 'coming_sprints', 'commercial_subscription',
568 'commercial_subscription_is_due', 'createBug',571 'commercial_subscription_is_due', 'createBug',
569 'createCustomLanguageCode', 'custom_language_codes',572 'createCustomLanguageCode', 'custom_language_codes',
570 'date_next_suggest_packaging', 'datecreated', 'description',573 'date_next_suggest_packaging', 'datecreated', 'description',
571 'development_focus', 'development_focusID',574 'development_focus', 'development_focusID',
572 'direct_answer_contacts', 'displayname', 'distrosourcepackages',575 'direct_answer_contacts', 'distrosourcepackages',
573 'downloadurl', 'driver', 'drivers', 'enable_bug_expiration',576 'downloadurl', 'driver', 'drivers',
574 'enable_bugfiling_duplicate_search', 'findReferencedOOPS',577 'enable_bugfiling_duplicate_search', 'findReferencedOOPS',
575 'findSimilarFAQs', 'findSimilarQuestions', 'freshmeatproject',578 'findSimilarFAQs', 'findSimilarQuestions', 'freshmeatproject',
576 'getAllowedBugInformationTypes',579 'getAllowedBugInformationTypes',
@@ -594,15 +597,13 @@
594 'has_custom_language_codes', 'has_milestones', 'homepage_content',597 'has_custom_language_codes', 'has_milestones', 'homepage_content',
595 'homepageurl', 'icon', 'invitesTranslationEdits',598 'homepageurl', 'icon', 'invitesTranslationEdits',
596 'invitesTranslationSuggestions',599 'invitesTranslationSuggestions',
597 'license_info', 'license_status', 'licenses', 'logo', 'milestones',600 'license_info', 'license_status', 'licenses', 'milestones',
598 'mugshot', 'name_with_project', 'newCodeImport',601 'mugshot', 'name_with_project', 'newCodeImport',
599 'obsolete_translatable_series', 'official_answers',602 'obsolete_translatable_series', 'official_bug_tags',
600 'official_anything', 'official_blueprints', 'official_bug_tags',603 'packagedInDistros', 'packagings',
601 'official_codehosting', 'official_malone', 'owner',
602 'parent_subscription_target', 'packagedInDistros', 'packagings',
603 'past_sprints', 'personHasDriverRights', 'pillar',604 'past_sprints', 'personHasDriverRights', 'pillar',
604 'primary_translatable', 'private_bugs',605 'primary_translatable', 'private_bugs',
605 'programminglang', 'project', 'qualifies_for_free_hosting',606 'programminglang', 'qualifies_for_free_hosting',
606 'recipes', 'redeemSubscriptionVoucher', 'registrant', 'releases',607 'recipes', 'redeemSubscriptionVoucher', 'registrant', 'releases',
607 'remote_product', 'removeCustomLanguageCode',608 'remote_product', 'removeCustomLanguageCode',
608 'screenshotsurl',609 'screenshotsurl',
@@ -610,7 +611,7 @@
610 'series',611 'series',
611 'sharesTranslationsWithOtherSide', 'sourceforgeproject',612 'sharesTranslationsWithOtherSide', 'sourceforgeproject',
612 'sourcepackages', 'specification_sharing_policy', 'specifications',613 'sourcepackages', 'specification_sharing_policy', 'specifications',
613 'sprints', 'summary', 'target_type_display', 'title',614 'sprints', 'summary', 'target_type_display',
614 'translatable_packages', 'translatable_series',615 'translatable_packages', 'translatable_series',
615 'translation_focus', 'translationgroup', 'translationgroups',616 'translation_focus', 'translationgroup', 'translationgroups',
616 'translationpermission', 'translations_usage', 'ubuntu_packages',617 'translationpermission', 'translations_usage', 'ubuntu_packages',