← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/bug-limitedview into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/bug-limitedview into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #434733 in Launchpad itself: "marking public bug as duplicate of private bug leads to confusing UI"
  https://bugs.launchpad.net/launchpad/+bug/434733

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/bug-limitedview/+merge/94088

Add a security adapter for launchpad.LimitedView on IBug.

Write tests that check launchpad.View and launchpad.LimitedView on a variety of bugs.

Add a missing copyright header to test_bug.py.
-- 
https://code.launchpad.net/~stevenk/launchpad/bug-limitedview/+merge/94088
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bug-limitedview into lp:launchpad.
=== modified file 'lib/lp/bugs/security.py'
--- lib/lp/bugs/security.py	2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/security.py	2012-02-22 05:38:20 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Security adapters for the bugs module."""
@@ -256,3 +256,30 @@
         return (
             self.obj.structural_subscription is None or
             user.inTeam(self.obj.structural_subscription.subscriber))
+
+
+class PublicOrPrivateBugExistence(AuthorizationBase):
+    """Restrict knowing about the existence of bugs.
+
+    Knowing the existence of a private bug allow traversing to its URL and
+    displaying the bug number.
+    """
+    permission = 'launchpad.LimitedView'
+    usedfor = IBug
+
+    def checkUnauthenticated(self):
+        """Unauthenticated users can only view public bugs."""
+        return not self.obj.private
+
+    def checkAuthenticated(self, user):
+        """By default, we simply perform a View permission check.
+
+        We also grant limited viewability to users who are subscribed via
+        a duplicate bug.
+        """
+        if self.forwardCheckAuthenticated(
+            user, self.obj, 'launchpad.View'):
+            return True
+
+        return not self.obj.private or self.obj.isSubscribedToDupes(
+            user.person)

=== modified file 'lib/lp/bugs/tests/test_bug.py'
--- lib/lp/bugs/tests/test_bug.py	2012-02-15 08:13:51 +0000
+++ lib/lp/bugs/tests/test_bug.py	2012-02-22 05:38:20 +0000
@@ -1,4 +1,4 @@
-
+# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for lp.bugs.model.Bug."""
@@ -22,7 +22,9 @@
     UserCannotEditBugTaskImportance,
     UserCannotEditBugTaskMilestone,
     )
+from lp.services.webapp.authorization import check_permission
 from lp.testing import (
+    celebrity_logged_in,
     person_logged_in,
     StormStatementRecorder,
     TestCaseWithFactory,
@@ -297,3 +299,45 @@
         params.setBugTarget(product=target)
         bug = getUtility(IBugSet).createBug(params)
         self.assertEqual([cve], [cve_link.cve for cve_link in bug.cve_links])
+
+
+class TestBugSecurityAdapters(TestCaseWithFactory):
+    layer = DatabaseFunctionalLayer
+
+    def test_anon_public_bug(self):
+        # An anonymous user can see a public bug.
+        bug = self.factory.makeBug()
+        self.assertTrue(check_permission('launchpad.View', bug))
+
+    def test_anon_private_bug(self):
+        # An anonymous user can not see a private bug.
+        bug = self.factory.makeBug(private=True)
+        self.assertFalse(check_permission('launchpad.View', bug))
+
+    def test_user_public_bug(self):
+        # A user can see a public bug.
+        bug = self.factory.makeBug()
+        person = self.factory.makePerson()
+        with person_logged_in(person):
+            self.assertTrue(check_permission('launchpad.View', bug))
+
+    def test_user_private_bug(self):
+        # A user can not see a public bug.
+        bug = self.factory.makeBug(private=True)
+        person = self.factory.makePerson()
+        with person_logged_in(person):
+            self.assertFalse(check_permission('launchpad.View', bug))
+
+    def test_user_private_bug_subscribed_to_public_dup(self):
+        # A user has limited visibility of a private bug if they are
+        # subscribed to a duplicate.
+        bug = self.factory.makeBug(private=True)
+        person = self.factory.makePerson()
+        dup = self.factory.makeBug()
+        with person_logged_in(dup.owner):
+            dup.subscribe(person, dup.owner)
+        with celebrity_logged_in('admin'):
+            dup.markAsDuplicate(bug)
+        with person_logged_in(person):
+            self.assertFalse(check_permission('launchpad.View', bug))
+            self.assertTrue(check_permission('launchpad.LimitedView', bug))


Follow ups