launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #13410
[Merge] lp:~abentley/launchpad/workitems-for-private-blueprints into lp:launchpad
Aaron Bentley has proposed merging lp:~abentley/launchpad/workitems-for-private-blueprints into lp:launchpad.
Commit message:
Filter non-Public blueprints for +upcomingwork.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1056891 in Launchpad itself: "Specification privacy: upcoming work won't load for anyone if there's any private data on it"
https://bugs.launchpad.net/launchpad/+bug/1056891
For more details, see:
https://code.launchpad.net/~abentley/launchpad/workitems-for-private-blueprints/+merge/129736
= Summary =
Fix bug #1056891: Specification privacy: upcoming work won't load for anyone if there's any private data on it
== Proposed fix ==
Use standard filter to ensure that only specifications visible to the viewer are listed.
== Pre-implementation notes ==
None
== LOC Rationale ==
Part of private products
== Implementation details ==
Add user parameter to getAssignedSpecificationWorkItemsDueBefore, supply view.user.
Update LaunchpadObjectFactory.makeSpecification to use milestone.product as needed.
== Tests ==
bin/test -t test_non_public_specifications -t Test_getAssignedSpecificationWorkItemsDueBefore
== Demo and Q/A ==
1. create a project with other/proprietary license as a regular user
2. create a milestone targetted to a date in the future (in the next 180 days for it to show up on +upcomingwork page)
3. create a private blueprint, assign it to yourself and milestone from 2
4. add a workitem to the blueprint
5. check /people/+me/+upcomingwork to ensure it displays correctly for yourself
6. log in as a different user and load that same page
It should omit the proprietary spec's workitem, but otherwise work normally.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/blueprints/browser/tests/test_person_upcomingwork.py
lib/lp/testing/factory.py
lib/lp/blueprints/browser/person_upcomingwork.py
lib/lp/registry/model/person.py
lib/lp/registry/tests/test_person.py
--
https://code.launchpad.net/~abentley/launchpad/workitems-for-private-blueprints/+merge/129736
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/workitems-for-private-blueprints into lp:launchpad.
=== modified file 'lib/lp/blueprints/browser/person_upcomingwork.py'
--- lib/lp/blueprints/browser/person_upcomingwork.py 2012-07-05 11:47:25 +0000
+++ lib/lp/blueprints/browser/person_upcomingwork.py 2012-10-15 18:58:21 +0000
@@ -277,7 +277,8 @@
Only work items whose milestone have a due date between today and the
given cut-off date are included in the results.
"""
- workitems = person.getAssignedSpecificationWorkItemsDueBefore(cutoff_date)
+ workitems = person.getAssignedSpecificationWorkItemsDueBefore(cutoff_date,
+ user)
# For every specification that has work items in the list above, create
# one SpecWorkItemContainer holding the work items from that spec that are
# targeted to the same milestone and assigned to this person (or its
=== modified file 'lib/lp/blueprints/browser/tests/test_person_upcomingwork.py'
--- lib/lp/blueprints/browser/tests/test_person_upcomingwork.py 2012-07-24 06:39:54 +0000
+++ lib/lp/blueprints/browser/tests/test_person_upcomingwork.py 2012-10-15 18:58:21 +0000
@@ -11,6 +11,7 @@
from zope.security.proxy import removeSecurityProxy
+from lp.app.enums import InformationType
from lp.blueprints.browser.person_upcomingwork import (
GenericWorkItem,
getWorkItemsDueBefore,
@@ -391,6 +392,29 @@
with anonymous_logged_in():
self.assertIn(bugtask.bug.title, tomorrows_group)
+ def test_non_public_specifications(self):
+ """Work items for non-public specs are filtered correctly."""
+ person = self.factory.makePerson()
+ proprietary_spec = self.factory.makeSpecification(
+ information_type=InformationType.PROPRIETARY)
+ today_milestone = self.factory.makeMilestone(
+ dateexpected=self.today, product=proprietary_spec.product)
+ public_workitem = self.factory.makeSpecificationWorkItem(
+ assignee=person, milestone=today_milestone)
+ proprietary_workitem = self.factory.makeSpecificationWorkItem(
+ assignee=person, milestone=today_milestone,
+ specification=proprietary_spec)
+ browser = self.getViewBrowser(
+ person, view_name='+upcomingwork')
+ self.assertIn(public_workitem.specification.name, browser.contents)
+ self.assertNotIn(proprietary_workitem.specification.name,
+ browser.contents)
+ browser = self.getViewBrowser(
+ person, view_name='+upcomingwork',
+ user=proprietary_workitem.specification.product.owner)
+ self.assertIn(proprietary_workitem.specification.name,
+ browser.contents)
+
class TestPersonUpcomingWorkView(TestCaseWithFactory):
=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py 2012-10-03 07:25:14 +0000
+++ lib/lp/registry/model/person.py 2012-10-15 18:58:21 +0000
@@ -128,6 +128,7 @@
SpecificationSort,
)
from lp.blueprints.model.specification import (
+ get_specification_privacy_filter,
HasSpecificationsMixin,
Specification,
)
@@ -1462,7 +1463,7 @@
return list(Store.of(self).find(
TeamParticipation.personID, TeamParticipation.teamID == self.id))
- def getAssignedSpecificationWorkItemsDueBefore(self, date):
+ def getAssignedSpecificationWorkItemsDueBefore(self, date, user):
"""See `IPerson`."""
from lp.registry.model.person import Person
from lp.registry.model.product import Product
@@ -1479,7 +1480,8 @@
Specification.milestoneID) == Milestone.id),
]
today = datetime.today().date()
- query = AND(
+ query = And(
+ get_specification_privacy_filter(user),
Milestone.dateexpected <= date, Milestone.dateexpected >= today,
WorkItem.deleted == False,
OR(WorkItem.assignee_id.is_in(self.participant_ids),
=== modified file 'lib/lp/registry/tests/test_person.py'
--- lib/lp/registry/tests/test_person.py 2012-09-28 06:15:58 +0000
+++ lib/lp/registry/tests/test_person.py 2012-10-15 18:58:21 +0000
@@ -1225,7 +1225,7 @@
milestone=self.future_milestone)
workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
- self.current_milestone.dateexpected)
+ self.current_milestone.dateexpected, self.team)
self.assertEqual([workitem], list(workitems))
@@ -1238,7 +1238,7 @@
title=u'workitem', specification=assigned_spec, deleted=True)
workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
- self.current_milestone.dateexpected)
+ self.current_milestone.dateexpected, self.team)
self.assertEqual([], list(workitems))
def test_workitems_assigned_to_others_working_on_blueprint(self):
@@ -1258,7 +1258,7 @@
assignee=self.factory.makePerson())
workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
- self.current_milestone.dateexpected)
+ self.current_milestone.dateexpected, self.team)
self.assertContentEqual([workitem, workitem_for_other_person],
list(workitems))
@@ -1273,7 +1273,8 @@
self.factory.makeSpecificationWorkItem(
title=u'workitem 1', specification=spec)
- workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(today)
+ workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
+ today, self.team)
self.assertEqual([], list(workitems))
@@ -1293,7 +1294,7 @@
milestone=self.current_milestone)
workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
- self.current_milestone.dateexpected)
+ self.current_milestone.dateexpected, self.team)
self.assertEqual([workitem], list(workitems))
@@ -1317,10 +1318,29 @@
assignee=self.team.teamowner)
workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
- self.current_milestone.dateexpected)
+ self.current_milestone.dateexpected, self.team)
self.assertEqual([workitem], list(workitems))
+ def test_listings_consider_spec_visibility(self):
+ # This spec is visible only to the product owner, even though it is
+ # assigned to self.team.teamowner. Therefore, it is listed only for
+ # product.owner, not the team.
+ product = self.factory.makeProduct(
+ information_type=InformationType.PROPRIETARY)
+ milestone = self.factory.makeMilestone(
+ dateexpected=self.current_milestone.dateexpected, product=product)
+ spec = self.factory.makeSpecification(
+ milestone=milestone, information_type=InformationType.PROPRIETARY)
+ workitem = self.factory.makeSpecificationWorkItem(
+ specification=spec, assignee=self.team.teamowner)
+ workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
+ milestone.dateexpected, self.team)
+ self.assertNotIn(workitem, workitems)
+ workitems = self.team.getAssignedSpecificationWorkItemsDueBefore(
+ milestone.dateexpected, product.owner)
+ self.assertIn(workitem, workitems)
+
def _makeProductSpec(self, milestone_dateexpected):
assignee = self.factory.makePerson()
with person_logged_in(self.team.teamowner):
@@ -1362,7 +1382,7 @@
with StormStatementRecorder() as recorder:
workitems = list(
self.team.getAssignedSpecificationWorkItemsDueBefore(
- dateexpected))
+ dateexpected, self.team))
for workitem in workitems:
workitem.assignee
workitem.milestone
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2012-10-11 04:21:07 +0000
+++ lib/lp/testing/factory.py 2012-10-15 18:58:21 +0000
@@ -2082,6 +2082,9 @@
"""
proprietary = (information_type not in PUBLIC_INFORMATION_TYPES and
information_type is not None)
+ if (product is None and milestone is not None and
+ milestone.productseries is not None):
+ product = milestone.productseries.product
if distribution is None and product is None:
if proprietary:
specification_sharing_policy = (
@@ -2234,7 +2237,7 @@
def makeCodeImport(self, svn_branch_url=None, cvs_root=None,
cvs_module=None, target=None, branch_name=None,
- git_repo_url=None,
+ git_repo_url=None,
bzr_branch_url=None, registrant=None,
rcs_type=None, review_status=None):
"""Create and return a new, arbitrary code import.
Follow ups