← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:hide-make-announcement-link-illegitimate-pillar-owners into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:hide-make-announcement-link-illegitimate-pillar-owners into launchpad:master.

Commit message:
Hide the 'Make announcement' link for illegitimate pillar owners

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/438674
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:hide-make-announcement-link-illegitimate-pillar-owners into launchpad:master.
diff --git a/lib/lp/registry/browser/announcement.py b/lib/lp/registry/browser/announcement.py
index 7ef6105..931acd4 100644
--- a/lib/lp/registry/browser/announcement.py
+++ b/lib/lp/registry/browser/announcement.py
@@ -1,18 +1,19 @@
-# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2023 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Announcement views."""
 
 __all__ = [
     "AnnouncementAddView",
-    "AnnouncementRetargetView",
-    "AnnouncementPublishView",
-    "AnnouncementRetractView",
     "AnnouncementDeleteView",
     "AnnouncementEditView",
+    "AnnouncementPublishView",
+    "AnnouncementRetargetView",
+    "AnnouncementRetractView",
     "AnnouncementSetView",
-    "HasAnnouncementsView",
     "AnnouncementView",
+    "current_user_can_announce",
+    "HasAnnouncementsView",
 ]
 
 from zope.interface import Interface, implementer
@@ -41,6 +42,13 @@ from lp.services.webapp.menu import (
 from lp.services.webapp.publisher import LaunchpadView, canonical_url
 
 
+def current_user_can_announce(pillar):
+    """Can the current user can make announcements for the pillar?"""
+    return check_permission("launchpad.Edit", pillar) and check_permission(
+        "launchpad.AnyLegitimatePerson", pillar
+    )
+
+
 class AnnouncementMenuMixin:
     """A mixin of links common to many menus."""
 
diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
index 1a6257d..3fb8a36 100644
--- a/lib/lp/registry/browser/distribution.py
+++ b/lib/lp/registry/browser/distribution.py
@@ -86,7 +86,10 @@ from lp.bugs.browser.structuralsubscription import (
 from lp.buildmaster.interfaces.processor import IProcessorSet
 from lp.code.browser.vcslisting import TargetDefaultVCSNavigationMixin
 from lp.registry.browser import RegistryEditFormView, add_subscribe_link
-from lp.registry.browser.announcement import HasAnnouncementsView
+from lp.registry.browser.announcement import (
+    HasAnnouncementsView,
+    current_user_can_announce,
+)
 from lp.registry.browser.menu import (
     IRegistryCollectionNavigationMenu,
     RegistryCollectionActionMenuBase,
@@ -571,11 +574,13 @@ class DistributionOverviewMenu(ApplicationMenu, DistributionLinksMixin):
         text = "All milestones"
         return Link("+milestones", text, icon="info")
 
-    @enabled_with_permission("launchpad.Edit")
     def announce(self):
         text = "Make announcement"
         summary = "Publish an item of news for this project"
-        return Link("+announce", text, summary, icon="add")
+        link = Link("+announce", text, summary, icon="add")
+        if not current_user_can_announce(self.context):
+            link.enabled = False
+        return link
 
     def announcements(self):
         text = "Read all announcements"
diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py
index 5f90da9..56c03a3 100644
--- a/lib/lp/registry/browser/product.py
+++ b/lib/lp/registry/browser/product.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2021 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2023 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Browser views for products."""
@@ -127,7 +127,10 @@ from lp.code.interfaces.branchjob import IRosettaUploadJobSource
 from lp.code.interfaces.codeimport import ICodeImport, ICodeImportSet
 from lp.code.interfaces.gitrepository import IGitRepository, IGitRepositorySet
 from lp.registry.browser import BaseRdfView, add_subscribe_link
-from lp.registry.browser.announcement import HasAnnouncementsView
+from lp.registry.browser.announcement import (
+    HasAnnouncementsView,
+    current_user_can_announce,
+)
 from lp.registry.browser.branding import BrandingChangeView
 from lp.registry.browser.menu import (
     IRegistryCollectionNavigationMenu,
@@ -602,11 +605,13 @@ class ProductOverviewMenu(
         text = "View milestones"
         return Link("+milestones", text, icon="info")
 
-    @enabled_with_permission("launchpad.Edit")
     def announce(self):
         text = "Make announcement"
         summary = "Publish an item of news for this project"
-        return Link("+announce", text, summary, icon="add")
+        link = Link("+announce", text, summary, icon="add")
+        if not current_user_can_announce(self.context):
+            link.enabled = False
+        return link
 
     def announcements(self):
         text = "Read all announcements"
diff --git a/lib/lp/registry/browser/project.py b/lib/lp/registry/browser/project.py
index 54eda82..a08d20d 100644
--- a/lib/lp/registry/browser/project.py
+++ b/lib/lp/registry/browser/project.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2023 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Project-related View Classes"""
@@ -59,7 +59,10 @@ from lp.bugs.browser.structuralsubscription import (
     expose_structural_subscription_data_to_js,
 )
 from lp.registry.browser import BaseRdfView, add_subscribe_link
-from lp.registry.browser.announcement import HasAnnouncementsView
+from lp.registry.browser.announcement import (
+    HasAnnouncementsView,
+    current_user_can_announce,
+)
 from lp.registry.browser.branding import BrandingChangeView
 from lp.registry.browser.menu import (
     IRegistryCollectionNavigationMenu,
@@ -232,11 +235,13 @@ class ProjectOverviewMenu(ProjectEditMenuMixin, ApplicationMenu):
         text = "More contributors"
         return Link("+topcontributors", text, icon="info")
 
-    @enabled_with_permission("launchpad.Edit")
     def announce(self):
         text = "Make announcement"
         summary = "Publish an item of news for this project"
-        return Link("+announce", text, summary, icon="add")
+        link = Link("+announce", text, summary, icon="add")
+        if not current_user_can_announce(self.context):
+            link.enabled = False
+        return link
 
     def announcements(self):
         text = "Read all announcements"
diff --git a/lib/lp/registry/stories/announcements/xx-announcements.rst b/lib/lp/registry/stories/announcements/xx-announcements.rst
index 6c36e4e..bddb6fd 100644
--- a/lib/lp/registry/stories/announcements/xx-announcements.rst
+++ b/lib/lp/registry/stories/announcements/xx-announcements.rst
@@ -72,7 +72,8 @@ page.
 
 
 Logged in users can only see it if they have launchpad.Edit on the
-pillar.
+pillar and have an old-enough (config.min_legitimate_account_age), legitimate
+account with sufficient karma (config.min_legitimate_karma).
 
     >>> nopriv_browser = setupBrowser(auth="Basic no-priv@xxxxxxxxxxxxx:test")
     >>> nopriv_browser.open("http://launchpad.test/firefox";)
@@ -87,6 +88,49 @@ pillar.
     ...
     zope.testbrowser.browser.LinkNotFoundError
 
+    >>> from lp.testing.sampledata import ADMIN_EMAIL
+    >>> login(ADMIN_EMAIL)
+    >>> new_user = factory.makePerson(
+    ...     name="new", displayname="new", email="new@xxxxxxxxxxx"
+    ... )
+    >>> new_product = factory.makeProduct(
+    ...     name="new-product", owner=new_user, driver=new_user
+    ... )
+    >>> new_distribution = factory.makeDistribution(
+    ...     name="new-distribution", owner=new_user
+    ... )
+    >>> new_project = factory.makeProject(name="new-project", owner=new_user)
+    >>> logout()
+
+    >>> from lp.services.config import config
+    >>> legitimate_person_config = """
+    ...     [launchpad]
+    ...     min_legitimate_karma: 10
+    ...     min_legitimate_account_age: 7
+    ... """
+    >>> config.push("legitimate person", legitimate_person_config)
+
+    >>> new_user_browser = setupBrowser(auth="Basic new@xxxxxxxxxxx:test")
+    >>> new_user_browser.open("http://launchpad.test/new-product";)
+    >>> new_user_browser.getLink("Make announcement")
+    Traceback (most recent call last):
+    ...
+    zope.testbrowser.browser.LinkNotFoundError
+
+    >>> new_user_browser.open("http://launchpad.test/new-distribution";)
+    >>> new_user_browser.getLink("Make announcement")
+    Traceback (most recent call last):
+    ...
+    zope.testbrowser.browser.LinkNotFoundError
+
+    >>> new_user_browser.open("http://launchpad.test/new-project";)
+    >>> new_user_browser.getLink("Make announcement")
+    Traceback (most recent call last):
+    ...
+    zope.testbrowser.browser.LinkNotFoundError
+    >>> config.pop("legitimate person")
+    (...)
+
     >>> priv_browser = setupBrowser(auth="Basic mark@xxxxxxxxxxx:test")
     >>> priv_browser.open("http://launchpad.test/ubuntu";)
     >>> link = priv_browser.getLink("Make announcement")

Follow ups