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
1=== modified file 'lib/lp/bugs/browser/tests/test_bug_views.py'
2--- lib/lp/bugs/browser/tests/test_bug_views.py 2012-11-11 23:39:34 +0000
3+++ lib/lp/bugs/browser/tests/test_bug_views.py 2012-11-12 11:53:43 +0000
4@@ -28,6 +28,7 @@
5 from zope.security.proxy import removeSecurityProxy
6
7 from lp.app.enums import InformationType
8+from lp.app.interfaces.services import IService
9 from lp.bugs.adapters.bugchange import BugAttachmentChange
10 from lp.registry.enums import BugSharingPolicy
11 from lp.registry.interfaces.accesspolicy import (
12@@ -499,6 +500,28 @@
13 self.assertEqual(
14 u'Private', soup.find('label', text="Private"))
15
16+ def test_bugtask_view_user_with_grant_on_bug_for_private_product(self):
17+ # The regular bug view is properly rendered even if the user
18+ # does not have permissions to view every detail of a product.
19+ owner = self.factory.makePerson()
20+ product = self.factory.makeProduct(
21+ owner=owner,
22+ information_type=InformationType.PROPRIETARY)
23+ user = self.factory.makePerson()
24+ with person_logged_in(owner):
25+ bug = self.factory.makeBug(
26+ target=product, information_type=InformationType.PROPRIETARY)
27+ getUtility(IService, 'sharing').ensureAccessGrants(
28+ [user], owner, bugs=[bug])
29+ launchbag = getUtility(IOpenLaunchBag)
30+ launchbag.add(bug)
31+ launchbag.add(bug.default_bugtask)
32+ with person_logged_in(user):
33+ view = create_initialized_view(
34+ bug.default_bugtask, name=u'+index', principal=user)
35+ contents = view.render()
36+ self.assertTrue(bug.title in contents)
37+
38
39 class TestBugTextViewPrivateTeams(TestCaseWithFactory):
40 """ Test for rendering BugTextView with private team artifacts.
41
42=== modified file 'lib/lp/registry/configure.zcml'
43--- lib/lp/registry/configure.zcml 2012-11-11 23:39:34 +0000
44+++ lib/lp/registry/configure.zcml 2012-11-12 11:53:43 +0000
45@@ -1356,6 +1356,25 @@
46 set_schema="lp.registry.interfaces.product.IProductModerateRestricted"
47 set_attributes="active"/>
48
49+ <!-- IBugTarget -->
50+
51+ <require
52+ permission="launchpad.LimitedView"
53+ attributes="
54+ bugtargetdisplayname"/>
55+
56+ <require
57+ permission="launchpad.View"
58+ attributes="
59+ bug_reported_acknowledgement
60+ bug_reporting_guidelines
61+ bugtargetname
62+ createBug
63+ enable_bugfiling_duplicate_search
64+ getBugTaskWeightFunction
65+ pillar
66+ searchTasks"/>
67+
68 <!-- IHasAliases -->
69
70 <require
71@@ -1391,8 +1410,19 @@
72 <!-- IStructuralSubscriptionTarget -->
73
74 <require
75+ permission="launchpad.LimitedView"
76+ attributes="
77+ parent_subscription_target" />
78+ <require
79 permission="launchpad.View"
80- interface="lp.bugs.interfaces.structuralsubscription.IStructuralSubscriptionTargetRead" />
81+ attributes="
82+ bug_subscriptions
83+ getSubscription
84+ getSubscriptions
85+ target_type_display
86+ userCanAlterBugSubscription
87+ userCanAlterSubscription
88+ userHasBugSubscriptions" />
89 <require
90 permission="launchpad.AnyAllowedPerson"
91 interface="lp.bugs.interfaces.structuralsubscription.IStructuralSubscriptionTargetWrite" />
92
93=== modified file 'lib/lp/registry/interfaces/product.py'
94--- lib/lp/registry/interfaces/product.py 2012-11-11 23:39:34 +0000
95+++ lib/lp/registry/interfaces/product.py 2012-11-12 11:53:43 +0000
96@@ -428,11 +428,27 @@
97 """True if the given user has access to this product."""
98
99
100-class IProductLimitedView(Interface):
101+class IProductLimitedView(IHasLogo, IHasOwner, ILaunchpadUsage):
102 """Attributes that must be visible for person with artifact grants
103 on bugs, branches or specifications for the product.
104 """
105
106+ displayname = exported(
107+ TextLine(
108+ title=_('Display Name'),
109+ description=_("""The name of the project as it would appear in a
110+ paragraph.""")),
111+ exported_as='display_name')
112+
113+ logo = exported(
114+ LogoImageUpload(
115+ title=_("Logo"), required=False,
116+ default_image_resource='/@@/product-logo',
117+ description=_(
118+ "An image of exactly 64x64 pixels that will be displayed in "
119+ "the heading of all pages related to this project. It should "
120+ "be no bigger than 50kb in size.")))
121+
122 name = exported(
123 ProductNameField(
124 title=_('Name'),
125@@ -442,16 +458,14 @@
126 "letters, numbers, dots, hyphens or pluses. "
127 "Keep this name short; it is used in URLs as shown above.")))
128
129-
130-class IProductView(
131- IBugTarget, ICanGetMilestonesDirectly, IHasAppointedDriver, IHasBranches,
132- IHasDrivers, IHasExternalBugTracker, IHasIcon,
133- IHasLogo, IHasMergeProposals, IHasMilestones, IHasExpirableBugs,
134- IHasMugshot, IHasOwner, IHasSprints, IHasTranslationImports,
135- ITranslationPolicy, IKarmaContext, ILaunchpadUsage, IMakesAnnouncements,
136- IOfficialBugTagTargetPublic, IHasOOPSReferences,
137- ISpecificationTarget, IHasRecipes, IHasCodeImports, IServiceUsage):
138- """Public IProduct properties."""
139+ owner = exported(
140+ PersonChoice(
141+ title=_('Maintainer'),
142+ required=True,
143+ vocabulary='ValidPillarOwner',
144+ description=_("The restricted team, moderated team, or person "
145+ "who maintains the project information in "
146+ "Launchpad.")))
147
148 project = exported(
149 ReferenceChoice(
150@@ -469,14 +483,21 @@
151 'and security policy will apply to this project.')),
152 exported_as='project_group')
153
154- owner = exported(
155- PersonChoice(
156- title=_('Maintainer'),
157- required=True,
158- vocabulary='ValidPillarOwner',
159- description=_("The restricted team, moderated team, or person "
160- "who maintains the project information in "
161- "Launchpad.")))
162+ title = exported(
163+ Title(
164+ title=_('Title'),
165+ description=_("The project title. Should be just a few words.")))
166+
167+
168+class IProductView(
169+ ICanGetMilestonesDirectly, IHasAppointedDriver, IHasBranches,
170+ IHasDrivers, IHasExternalBugTracker, IHasIcon,
171+ IHasMergeProposals, IHasMilestones, IHasExpirableBugs,
172+ IHasMugshot, IHasSprints, IHasTranslationImports,
173+ ITranslationPolicy, IKarmaContext, IMakesAnnouncements,
174+ IOfficialBugTagTargetPublic, IHasOOPSReferences,
175+ ISpecificationTarget, IHasRecipes, IHasCodeImports, IServiceUsage):
176+ """Public IProduct properties."""
177
178 registrant = exported(
179 PublicPersonChoice(
180@@ -503,18 +524,6 @@
181 "required because there might be a project driver and also a "
182 "driver appointed in the overarching project group.")
183
184- displayname = exported(
185- TextLine(
186- title=_('Display Name'),
187- description=_("""The name of the project as it would appear in a
188- paragraph.""")),
189- exported_as='display_name')
190-
191- title = exported(
192- Title(
193- title=_('Title'),
194- description=_("The project title. Should be just a few words.")))
195-
196 summary = exported(
197 Summary(
198 title=_('Summary'),
199@@ -614,15 +623,6 @@
200 "will be displayed next to the project name everywhere in "
201 "Launchpad that we refer to the project and link to it.")))
202
203- logo = exported(
204- LogoImageUpload(
205- title=_("Logo"), required=False,
206- default_image_resource='/@@/product-logo',
207- description=_(
208- "An image of exactly 64x64 pixels that will be displayed in "
209- "the heading of all pages related to this project. It should "
210- "be no bigger than 50kb in size.")))
211-
212 mugshot = exported(
213 MugshotImageUpload(
214 title=_("Brand"), required=False,
215@@ -917,7 +917,7 @@
216
217
218 class IProduct(
219- IHasBugSupervisor, IProductEditRestricted,
220+ IBugTarget, IHasBugSupervisor, IProductEditRestricted,
221 IProductModerateRestricted, IProductDriverRestricted, IProductView,
222 IProductLimitedView, IProductPublic, IQuestionTarget, IRootContext,
223 IStructuralSubscriptionTarget, IInformationType, IPillar):
224
225=== modified file 'lib/lp/registry/tests/test_product.py'
226--- lib/lp/registry/tests/test_product.py 2012-11-11 23:39:34 +0000
227+++ lib/lp/registry/tests/test_product.py 2012-11-12 11:53:43 +0000
228@@ -551,7 +551,11 @@
229 CheckerPublic: set((
230 'active', 'id', 'information_type', 'pillar_category', 'private',
231 'userCanView',)),
232- 'launchpad.LimitedView': set(('name', )),
233+ 'launchpad.LimitedView': set((
234+ 'bugtargetdisplayname', 'displayname', 'enable_bug_expiration',
235+ 'logo', 'name', 'official_answers', 'official_anything',
236+ 'official_blueprints', 'official_codehosting', 'official_malone',
237+ 'owner', 'parent_subscription_target', 'project', 'title', )),
238 'launchpad.View': set((
239 '_getOfficialTagClause', '_all_specifications',
240 '_valid_specifications', 'active_or_packaged_series',
241@@ -561,16 +565,15 @@
242 'blueprints_usage', 'branch_sharing_policy',
243 'bug_reported_acknowledgement', 'bug_reporting_guidelines',
244 'bug_sharing_policy', 'bug_subscriptions', 'bug_supervisor',
245- 'bug_tracking_usage', 'bugtargetdisplayname', 'bugtargetname',
246- 'bugtracker', 'canUserAlterAnswerContact',
247- 'codehosting_usage',
248+ 'bug_tracking_usage', 'bugtargetname',
249+ 'bugtracker', 'canUserAlterAnswerContact', 'codehosting_usage',
250 'coming_sprints', 'commercial_subscription',
251 'commercial_subscription_is_due', 'createBug',
252 'createCustomLanguageCode', 'custom_language_codes',
253 'date_next_suggest_packaging', 'datecreated', 'description',
254 'development_focus', 'development_focusID',
255- 'direct_answer_contacts', 'displayname', 'distrosourcepackages',
256- 'downloadurl', 'driver', 'drivers', 'enable_bug_expiration',
257+ 'direct_answer_contacts', 'distrosourcepackages',
258+ 'downloadurl', 'driver', 'drivers',
259 'enable_bugfiling_duplicate_search', 'findReferencedOOPS',
260 'findSimilarFAQs', 'findSimilarQuestions', 'freshmeatproject',
261 'getAllowedBugInformationTypes',
262@@ -594,15 +597,13 @@
263 'has_custom_language_codes', 'has_milestones', 'homepage_content',
264 'homepageurl', 'icon', 'invitesTranslationEdits',
265 'invitesTranslationSuggestions',
266- 'license_info', 'license_status', 'licenses', 'logo', 'milestones',
267+ 'license_info', 'license_status', 'licenses', 'milestones',
268 'mugshot', 'name_with_project', 'newCodeImport',
269- 'obsolete_translatable_series', 'official_answers',
270- 'official_anything', 'official_blueprints', 'official_bug_tags',
271- 'official_codehosting', 'official_malone', 'owner',
272- 'parent_subscription_target', 'packagedInDistros', 'packagings',
273+ 'obsolete_translatable_series', 'official_bug_tags',
274+ 'packagedInDistros', 'packagings',
275 'past_sprints', 'personHasDriverRights', 'pillar',
276 'primary_translatable', 'private_bugs',
277- 'programminglang', 'project', 'qualifies_for_free_hosting',
278+ 'programminglang', 'qualifies_for_free_hosting',
279 'recipes', 'redeemSubscriptionVoucher', 'registrant', 'releases',
280 'remote_product', 'removeCustomLanguageCode',
281 'screenshotsurl',
282@@ -610,7 +611,7 @@
283 'series',
284 'sharesTranslationsWithOtherSide', 'sourceforgeproject',
285 'sourcepackages', 'specification_sharing_policy', 'specifications',
286- 'sprints', 'summary', 'target_type_display', 'title',
287+ 'sprints', 'summary', 'target_type_display',
288 'translatable_packages', 'translatable_series',
289 'translation_focus', 'translationgroup', 'translationgroups',
290 'translationpermission', 'translations_usage', 'ubuntu_packages',