launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15210
[Merge] lp:~stevenk/launchpad/filter-spec-lists into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/filter-spec-lists into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1130480 in Launchpad itself: "Linking a private blueprint to a public bug/branch makes that artefact inaccessible"
https://bugs.launchpad.net/launchpad/+bug/1130480
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/filter-spec-lists/+merge/149748
Change IBug.specifications so that it returns a resultset of the linked specifications that the user can view.
Add a new method, IBranch.getSpecificationLinks() that will return a resultset of the specification links themselves (since that's what IBranch.spec_links does) that the user can view. IBranch.spec_links continues to live since it's exported via the API.
--
https://code.launchpad.net/~stevenk/launchpad/filter-spec-lists/+merge/149748
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/filter-spec-lists into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py 2012-09-28 01:25:36 +0000
+++ lib/lp/bugs/browser/bug.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""IBug related view classes."""
@@ -536,6 +536,10 @@
"""
return getUtility(ILaunchBag).bugtask
+ @property
+ def specifications(self):
+ return self.context.specifications(self.user)
+
class BugInformationTypePortletView(InformationTypePortletMixin,
LaunchpadView):
=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py 2013-02-06 04:56:33 +0000
+++ lib/lp/bugs/model/bug.py 2013-02-21 06:03:23 +0000
@@ -98,6 +98,11 @@
from lp.app.interfaces.services import IService
from lp.app.model.launchpad import InformationTypeMixin
from lp.app.validators import LaunchpadValidationError
+from lp.blueprints.model.specification import Specification
+from lp.blueprints.model.specificationbug import SpecificationBug
+from lp.blueprints.model.specificationsearch import (
+ get_specification_privacy_filter,
+ )
from lp.bugs.adapters.bug import convert_to_information_type
from lp.bugs.adapters.bugchange import (
BranchLinkedToBug,
@@ -360,11 +365,7 @@
cves = SQLRelatedJoin('Cve', intermediateTable='BugCve',
orderBy='sequence', joinColumn='bug', otherColumn='cve')
cve_links = SQLMultipleJoin('BugCve', joinColumn='bug', orderBy='id')
- duplicates = SQLMultipleJoin(
- 'Bug', joinColumn='duplicateof', orderBy='id')
- specifications = SQLRelatedJoin('Specification', joinColumn='bug',
- otherColumn='specification', intermediateTable='SpecificationBug',
- orderBy='-datecreated')
+ duplicates = SQLMultipleJoin('Bug', joinColumn='duplicateof', orderBy='id')
questions = SQLRelatedJoin('Question', joinColumn='bug',
otherColumn='question', intermediateTable='QuestionBug',
orderBy='-datecreated')
@@ -379,6 +380,14 @@
heat_last_updated = UtcDateTimeCol(default=None)
latest_patch_uploaded = UtcDateTimeCol(default=None)
+ def specifications(self, user):
+ return IStore(SpecificationBug).using(
+ Specification,
+ Join(SpecificationBug, SpecificationBug.bugID == self.id)).find(
+ Specification,
+ Specification.id == SpecificationBug.specificationID,
+ *get_specification_privacy_filter(user))
+
@property
def security_related(self):
return self.information_type in SECURITY_INFORMATION_TYPES
=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py 2012-10-18 14:43:24 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -528,7 +528,7 @@
])
-class TestBugTaskPrivacy(TestCase):
+class TestBugTaskPrivacy(TestCaseWithFactory):
"""Verify that the bug is either private or public.
XXX: rharding 2012-05-14 bug=999298: These tests are ported from doctests
@@ -553,14 +553,15 @@
ubuntu_team = getUtility(IPersonSet).getByEmail('support@xxxxxxxxxx')
bug_upstream_firefox_crashes.bug.subscribe(ubuntu_team, ubuntu_team)
- old_state = Snapshot(bug_upstream_firefox_crashes.bug,
- providing=IBug)
- self.assertTrue(bug_upstream_firefox_crashes.bug.setPrivate(True,
- foobar))
-
- bug_set_private = ObjectModifiedEvent(bug_upstream_firefox_crashes.bug,
- old_state,
- ["id", "title", "private"])
+ old_state = Snapshot(
+ bug_upstream_firefox_crashes.bug, providing=IBug)
+ self.assertTrue(
+ bug_upstream_firefox_crashes.bug.setPrivate(True, foobar))
+
+ bug_set_private = ObjectModifiedEvent(
+ bug_upstream_firefox_crashes.bug, old_state,
+ ["id", "title", "private"])
+
notify(bug_set_private)
flush_database_updates()
@@ -671,6 +672,22 @@
bug_upstream_firefox_crashes.transitionToStatus(
BugTaskStatus.NEW, getUtility(ILaunchBag).user)
+ def test_bug_specifications_is_filtered_for_anonymous(self):
+ bug = self.factory.makeBug()
+ spec = self.factory.makeSpecification(
+ information_type=InformationType.PROPRIETARY)
+ with person_logged_in(spec.product.owner):
+ spec.linkBug(bug)
+ self.assertEqual([], list(bug.specifications(None)))
+
+ def test_bug_specifications_for_accepted_user(self):
+ bug = self.factory.makeBug()
+ spec = self.factory.makeSpecification(
+ information_type=InformationType.PROPRIETARY)
+ with person_logged_in(spec.product.owner):
+ spec.linkBug(bug)
+ self.assertEqual([spec], list(bug.specifications(spec.product.owner)))
+
class TestBugTaskDelta(TestCaseWithFactory):
=== modified file 'lib/lp/bugs/templates/bug-portlet-specs.pt'
--- lib/lp/bugs/templates/bug-portlet-specs.pt 2009-10-29 21:39:12 +0000
+++ lib/lp/bugs/templates/bug-portlet-specs.pt 2013-02-21 06:03:23 +0000
@@ -3,10 +3,10 @@
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
class="portlet vertical" id="portlet-blueprints"
- tal:condition="context/specifications">
+ tal:condition="view/specifications">
<h2>Related blueprints</h2>
<ul>
- <li tal:repeat="spec context/specifications"
+ <li tal:repeat="spec view/specifications"
tal:content="structure spec/fmt:link" />
</ul>
</div>
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py 2012-12-12 04:59:52 +0000
+++ lib/lp/code/browser/branch.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Branch views."""
@@ -354,7 +354,7 @@
return Link('+linkbug', text, icon='add')
def link_blueprint(self):
- if self.context.spec_links:
+ if list(self.context.getSpecificationLinks(self.user)):
text = 'Link to another blueprint'
else:
text = 'Link to a blueprint'
@@ -689,6 +689,10 @@
self.context.branch, IBranch['lifecycle_status'],
header='Change status to', css_class_prefix='branchstatus')
+ @property
+ def spec_links(self):
+ return self.context.getSpecificationLinks(self.user)
+
class BranchInProductView(BranchView):
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2013-01-07 02:40:55 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Views, navigation and actions for BranchMergeProposals."""
@@ -719,8 +719,11 @@
def has_bug_or_spec(self):
"""Return whether or not the merge proposal has a linked bug or spec.
"""
- branch = self.context.source_branch
- return self.linked_bugtasks or branch.spec_links
+ return self.linked_bugtasks or self.spec_links
+
+ @property
+ def spec_links(self):
+ return self.context.source_branch.getSpecificationLinks(self.user)
@cachedproperty
def linked_bugtasks(self):
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2013-01-16 06:41:43 +0000
+++ lib/lp/code/interfaces/branch.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Branch interfaces."""
@@ -482,6 +482,9 @@
value_type=Reference(Interface)), # Really ISpecificationBranch
as_of="beta")
+ def getSpecificationLinks(user):
+ """Fetch the `ISpecificationBranch`'s that the user can view."""
+
@call_with(registrant=REQUEST_USER)
@operation_parameters(
spec=Reference(schema=Interface)) # Really ISpecification
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2013-02-14 05:36:37 +0000
+++ lib/lp/code/model/branch.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -66,6 +66,11 @@
IPrivacy,
)
from lp.app.interfaces.services import IService
+from lp.blueprints.model.specification import Specification
+from lp.blueprints.model.specificationbranch import SpecificationBranch
+from lp.blueprints.model.specificationsearch import (
+ get_specification_privacy_filter,
+ )
from lp.bugs.interfaces.bugtask import IBugTaskSet
from lp.bugs.interfaces.bugtaskfilter import filter_bugtasks_by_context
from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
@@ -438,9 +443,19 @@
"""See `IBranch`."""
return bug.unlinkBranch(self, user)
- spec_links = SQLMultipleJoin('SpecificationBranch',
- joinColumn='branch',
- orderBy='id')
+ spec_links = SQLMultipleJoin(
+ 'SpecificationBranch', joinColumn='branch', orderBy='id')
+
+ def getSpecificationLinks(self, user):
+ tables = [
+ SpecificationBranch,
+ Join(
+ Specification,
+ SpecificationBranch.specificationID == Specification.id)]
+ return Store.of(self).using(*tables).find(
+ SpecificationBranch,
+ SpecificationBranch.branchID == self.id,
+ *get_specification_privacy_filter(user))
def linkSpecification(self, spec, registrant):
"""See `IBranch`."""
@@ -459,8 +474,7 @@
@property
def active_landing_targets(self):
"""Merge proposals not in final states where this branch is source."""
- store = Store.of(self)
- return store.find(
+ return Store.of(self).find(
BranchMergeProposal, BranchMergeProposal.source_branch == self,
Not(BranchMergeProposal.queue_status.is_in(
BRANCH_MERGE_PROPOSAL_FINAL_STATES)))
@@ -615,8 +629,7 @@
def getStackedBranches(self):
"""See `IBranch`."""
- store = Store.of(self)
- return store.find(Branch, Branch.stacked_on == self)
+ return Store.of(self).find(Branch, Branch.stacked_on == self)
def getStackedOnBranches(self):
"""See `IBranch`."""
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2013-01-07 02:40:55 +0000
+++ lib/lp/code/model/tests/test_branch.py 2013-02-21 06:03:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for Branches."""
@@ -1573,10 +1573,10 @@
spec2.linkBranch(self.branch, self.branch.owner)
spec2_branch_id = self.branch.spec_links[1].id
self.branch.destroySelf(break_references=True)
- self.assertRaises(SQLObjectNotFound, SpecificationBranch.get,
- spec1_branch_id)
- self.assertRaises(SQLObjectNotFound, SpecificationBranch.get,
- spec2_branch_id)
+ self.assertRaises(
+ SQLObjectNotFound, SpecificationBranch.get, spec1_branch_id)
+ self.assertRaises(
+ SQLObjectNotFound, SpecificationBranch.get, spec2_branch_id)
def test_branchWithSeriesRequirements(self):
"""Deletion requirements for a series' branch are right."""
=== modified file 'lib/lp/code/templates/branch-macros.pt'
--- lib/lp/code/templates/branch-macros.pt 2012-08-07 07:07:02 +0000
+++ lib/lp/code/templates/branch-macros.pt 2013-02-21 06:03:23 +0000
@@ -76,7 +76,7 @@
<metal:branch-link use-macro="branch/@@+macros/bug-branch-links"/>
</tal:branch-link>
- <div tal:repeat="spec_link mergeproposal/source_branch/spec_links">
+ <div tal:repeat="spec_link view/spec_links">
<img src="/@@/blueprint"
tal:replace="structure spec_link/specification/image:icon" />
<a tal:attributes="href spec_link/specification/fmt:url:blueprints"
@@ -140,7 +140,7 @@
show_edit - show the edit form
</tal:comment>
- <tal:spec-tasks repeat="spec_branch branch/spec_links">
+ <tal:spec-tasks repeat="spec_branch view/spec_links">
<div tal:define="has_edit_permission spec_branch/required:launchpad.AnyPerson;
show_edit show_edit|nothing;
show_edit python: show_edit and has_edit_permission;
Follow ups