Merge lp:~jcsackett/launchpad/bugtasks-deacitvated-context-632847 into lp:launchpad

Proposed by j.c.sackett
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 12363
Proposed branch: lp:~jcsackett/launchpad/bugtasks-deacitvated-context-632847
Merge into: lp:launchpad
Diff against target: 201 lines (+73/-16)
4 files modified
lib/lp/bugs/browser/tests/test_buglisting.py (+47/-2)
lib/lp/bugs/model/bugtask.py (+12/-0)
lib/lp/registry/browser/tests/test_milestone.py (+11/-7)
lib/lp/registry/browser/tests/test_person_view.py (+3/-7)
To merge this branch: bzr merge lp:~jcsackett/launchpad/bugtasks-deacitvated-context-632847
Reviewer Review Type Date Requested Status
Robert Collins (community) Needs Fixing
Graham Binns (community) code Approve
Review via email: mp+48925@code.launchpad.net

Commit message

[r=gmb][bug=632847] Adds check to prevent bugtasks for deactivated products from showing up for people who can't see the product.

Description of the change

Summary
=======

Per bug 632847, bugtasks for deactivated projects can show up in search results. Users clicking on links for these bugtasks then get a 404. The best fix for this is to make sure that users that can't verify the deactivated project (i.e. aren't registry admins) don't see those bugtasks.

Preimplementation
=================

Spoke with Deryck Hodge and Curtis Hovey

Proposed Fix
============

Add a step in the query building for bug search that checks is the searching user is in registry admins; if they're not, filter out bugtasks for deactivated products.

Implementation
==============

lib/lp/bugs/browser/tests/test_buglisting.py
--------------------------------------------
Tests added.

lib/lp/bugs/model/bugtask.py
----------------------------
A check is added to see if the searching user is in registry admins; if they're not, an extra clause is added to the query to remove products that are deactivated.

lib/lp/registry/browser/tests/test_person_view.py
-------------------------------------------------
Drive by clean up of whitespace while trying to decide where to place new tests.

Tests
=====

bin/test -t test_buglisting

Demo & QA
=========

Using the link provided in the bug (though switch to qastaging). If you are signed in and are a member of registry admins, you should see the bugtask reported as problematic in the bugtask. If you are not in registry admins (or logout), you should not see it.

Lint
====

make lint output:

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/browser/tests/test_buglisting.py
  lib/lp/bugs/model/bugtask.py
  lib/lp/registry/browser/tests/test_person_view.py

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

Just one comment: test_listing_seen_with_permission needs a comment at the start of it stating the expected behaviour (it's obvious from the test, but I don't want to have to parse the test to understand what it's testing).

Other than that this is great; r=me.

review: Approve (code)
Revision history for this message
Robert Collins (lifeless) wrote :

Uhm
this is a correlated subquery; generally this about the worst performing thing we can do: it repeats the same work hundreds of thousands of times.

Worse, we're adding a lookup to product for every bug found, even if we're search in a context where this is impossible and irrelevant - e.g. distro or product searches.

I'm going to roll this back out today to avoid blocking deploys : we have massive issues with bug search already.

review: Needs Fixing

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_buglisting.py'
2--- lib/lp/bugs/browser/tests/test_buglisting.py 2011-02-08 05:54:20 +0000
3+++ lib/lp/bugs/browser/tests/test_buglisting.py 2011-02-10 17:40:33 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2010 Canonical Ltd. This software is licensed under the
6+# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 __metaclass__ = type
10@@ -21,15 +21,60 @@
11 from lp.testing import (
12 BrowserTestCase,
13 login_person,
14+ login,
15+ logout,
16 person_logged_in,
17 StormStatementRecorder,
18 TestCaseWithFactory,
19 )
20-
21 from lp.testing.matchers import HasQueryCount
22 from lp.testing.views import create_initialized_view
23
24
25+class DeactivatedContextBugTaskTestCase(TestCaseWithFactory):
26+
27+ layer = DatabaseFunctionalLayer
28+
29+ def setUp(self):
30+ super(DeactivatedContextBugTaskTestCase, self).setUp()
31+ self.person = self.factory.makePerson()
32+ self.active_product = self.factory.makeProduct()
33+ self.inactive_product = self.factory.makeProduct()
34+ bug = self.factory.makeBug(product=self.active_product)
35+ self.active_bugtask = self.factory.makeBugTask(
36+ bug=bug,
37+ target=self.active_product)
38+ self.inactive_bugtask = self.factory.makeBugTask(
39+ bug=bug,
40+ target=self.inactive_product)
41+ with person_logged_in(self.person):
42+ self.active_bugtask.transitionToAssignee(self.person)
43+ self.inactive_bugtask.transitionToAssignee(self.person)
44+ login('admin@canonical.com')
45+ self.inactive_product.active = False
46+ logout()
47+
48+ def test_listing_not_seen_without_permission(self):
49+ # Someone without permission to see deactiveated projects does
50+ # not see bugtasks for deactivated projects.
51+ login('no-priv@canonical.com')
52+ view = create_initialized_view(self.person, "+bugs")
53+ self.assertEqual([self.active_bugtask], list(view.searchUnbatched()))
54+
55+ def test_listing_seen_with_permission(self):
56+ # Someone with permission to see deactiveated projects
57+ # can see bugtasks for deactivated projects.
58+ login('admin@canonical.com')
59+ registry_owner = getUtility(
60+ ILaunchpadCelebrities).registry_experts.teamowner
61+ logout()
62+ login_person(registry_owner)
63+ view = create_initialized_view(self.person, "+bugs")
64+ self.assertEqual(
65+ sorted([self.active_bugtask, self.inactive_bugtask]),
66+ sorted(list(view.searchUnbatched())))
67+
68+
69 class TestBugTaskSearchListingPage(BrowserTestCase):
70
71 layer = DatabaseFunctionalLayer
72
73=== modified file 'lib/lp/bugs/model/bugtask.py'
74--- lib/lp/bugs/model/bugtask.py 2011-02-08 22:12:39 +0000
75+++ lib/lp/bugs/model/bugtask.py 2011-02-10 17:40:33 +0000
76@@ -78,6 +78,9 @@
77 from canonical.launchpad.components.decoratedresultset import (
78 DecoratedResultSet,
79 )
80+from canonical.launchpad.interfaces.launchpad import (
81+ IPersonRoles,
82+ )
83 from canonical.launchpad.helpers import shortlist
84 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
85 from canonical.launchpad.interfaces.lpstorm import IStore
86@@ -1775,6 +1778,15 @@
87 if params.status is not None:
88 extra_clauses.append(self._buildStatusClause(params.status))
89
90+ if params.user is not None:
91+ user_roles = IPersonRoles(params.user)
92+ if not user_roles.in_registry_experts:
93+ extra_clauses.append(
94+ """NOT EXISTS (SELECT TRUE
95+ FROM Product
96+ WHERE Product.id = BugTask.product
97+ AND Product.active = False)""")
98+
99 if params.milestone:
100 if IProjectGroupMilestone.providedBy(params.milestone):
101 where_cond = """
102
103=== modified file 'lib/lp/registry/browser/tests/test_milestone.py'
104--- lib/lp/registry/browser/tests/test_milestone.py 2011-02-08 11:13:57 +0000
105+++ lib/lp/registry/browser/tests/test_milestone.py 2011-02-10 17:40:33 +0000
106@@ -177,10 +177,11 @@
107 self.add_bug(bugtask_count)
108 login_person(self.owner)
109 view = create_initialized_view(milestone, '+index')
110- # Eliminate permission check for the admin team from the
111- # recorded queries by loading it now. If the test ever breaks,
112- # the person fixing it won't waste time trying to track this
113+ # Eliminate permission checks for the admin team and registry_experts
114+ # from the recorded queries by loading it now. If the test ever
115+ # breaks, the person fixing it won't waste time trying to track them
116 # query down.
117+ getUtility(ILaunchpadCelebrities).registry_experts
118 getUtility(ILaunchpadCelebrities).admin
119 with StormStatementRecorder() as recorder:
120 bugtasks = list(view.bugtasks)
121@@ -244,7 +245,7 @@
122 def test_milestone_eager_loading(self):
123 # Verify that the number of queries does not increase with more
124 # bugs with different assignees.
125- query_limit = 34
126+ query_limit = 37
127 self.add_bug(3)
128 self.assert_milestone_page_query_count(
129 self.milestone, query_limit=query_limit)
130@@ -260,7 +261,10 @@
131 # is very large already, if the test fails due to such a change,
132 # please cut some more of the existing fat out of it rather than
133 # increasing the cap.
134- page_query_limit = 34
135+
136+ # Fetch some things into the cache so we don't muck with query
137+ # counts.
138+ page_query_limit = 37
139 product = self.factory.makeProduct()
140 login_person(product.owner)
141 milestone = self.factory.makeMilestone(
142@@ -424,12 +428,12 @@
143 # 7. Load links to branches.
144 bugtask_count = 10
145 self.assert_bugtasks_query_count(
146- self.milestone, bugtask_count, query_limit=9)
147+ self.milestone, bugtask_count, query_limit=11)
148
149 def test_milestone_eager_loading(self):
150 # Verify that the number of queries does not increase with more
151 # bugs with different assignees.
152- query_limit = 33
153+ query_limit = 36
154 self.add_bug(3)
155 self.assert_milestone_page_query_count(
156 self.milestone, query_limit=query_limit)
157
158=== modified file 'lib/lp/registry/browser/tests/test_person_view.py'
159--- lib/lp/registry/browser/tests/test_person_view.py 2011-01-14 21:20:46 +0000
160+++ lib/lp/registry/browser/tests/test_person_view.py 2011-02-10 17:40:33 +0000
161@@ -1,4 +1,4 @@
162-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
163+# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
164 # GNU Affero General Public License version 3 (see the file LICENSE).
165
166 __metaclass__ = type
167@@ -7,7 +7,6 @@
168 from storm.expr import LeftJoin
169 from storm.store import Store
170 from testtools.matchers import (
171- Equals,
172 LessThan,
173 )
174 from zope.component import getUtility
175@@ -28,16 +27,14 @@
176 LaunchpadFunctionalLayer,
177 LaunchpadZopelessLayer,
178 )
179-
180 from lp.app.errors import NotFoundError
181 from lp.bugs.model.bugtask import BugTask
182 from lp.buildmaster.enums import BuildStatus
183 from lp.registry.browser.person import (
184 PersonEditView,
185 PersonView,
186- TeamInvitationView)
187-
188-
189+ TeamInvitationView,
190+ )
191 from lp.registry.interfaces.karma import IKarmaCacheManager
192 from lp.registry.interfaces.person import (
193 PersonVisibility,
194@@ -47,7 +44,6 @@
195 ITeamMembershipSet,
196 TeamMembershipStatus,
197 )
198-
199 from lp.registry.model.karma import KarmaCategory
200 from lp.registry.model.milestone import milestone_sort_key
201 from lp.soyuz.enums import (