← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~allenap/launchpad/sub-search-queries into lp:launchpad

 

Gavin Panella has proposed merging lp:~allenap/launchpad/sub-search-queries into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)


- Add Storm model classes for BugSubscriptionFilter* tables (which
  already exist),

- Add database permissions for the aforementioned tables,

- Clean up some of the code in StructuralSubscriptionTargetMixin.

-- 
https://code.launchpad.net/~allenap/launchpad/sub-search-queries/+merge/35546
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/launchpad/sub-search-queries into lp:launchpad.
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg	2010-09-10 12:59:49 +0000
+++ database/schema/security.cfg	2010-09-15 15:32:53 +0000
@@ -539,6 +539,10 @@
 public.bugnotification                  = SELECT, INSERT
 public.bugnotificationrecipient         = SELECT, INSERT
 public.bugsubscription                  = SELECT
+public.bugsubscriptionfilter            = SELECT
+public.bugsubscriptionfilterstatus      = SELECT
+public.bugsubscriptionfilterimportance  = SELECT
+public.bugsubscriptionfiltertag         = SELECT
 public.bugtask                          = SELECT, INSERT, UPDATE
 public.bugtracker                       = SELECT, INSERT
 public.bugtrackeralias                  = SELECT
@@ -618,6 +622,10 @@
 public.bugactivity                      = SELECT, INSERT
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugsubscription                  = SELECT
+public.bugsubscriptionfilter            = SELECT
+public.bugsubscriptionfilterstatus      = SELECT
+public.bugsubscriptionfilterimportance  = SELECT
+public.bugsubscriptionfiltertag         = SELECT
 public.bugnotification                  = SELECT, INSERT
 public.bugnotificationrecipient         = SELECT, INSERT
 public.structuralsubscription           = SELECT
@@ -804,6 +812,10 @@
 public.bugactivity                      = SELECT, INSERT
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugsubscription                  = SELECT
+public.bugsubscriptionfilter            = SELECT
+public.bugsubscriptionfilterstatus      = SELECT
+public.bugsubscriptionfilterimportance  = SELECT
+public.bugsubscriptionfiltertag         = SELECT
 public.bugnotification                  = SELECT, INSERT
 public.bugnotificationrecipient         = SELECT, INSERT
 public.bugnomination                    = SELECT
@@ -928,6 +940,10 @@
 public.bugpackageinfestation            = SELECT, INSERT, UPDATE
 public.bugproductinfestation            = SELECT, INSERT, UPDATE
 public.bugsubscription                  = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfilter            = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfilterstatus      = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfilterimportance  = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfiltertag         = SELECT, INSERT, UPDATE, DELETE
 public.bugtask                          = SELECT, INSERT, UPDATE, DELETE
 public.bugtracker                       = SELECT, INSERT, UPDATE, DELETE
 public.bugtrackeralias                  = SELECT, INSERT, UPDATE, DELETE
@@ -1154,6 +1170,10 @@
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugjob                           = SELECT, INSERT
 public.bugsubscription                  = SELECT
+public.bugsubscriptionfilter            = SELECT
+public.bugsubscriptionfilterstatus      = SELECT
+public.bugsubscriptionfilterimportance  = SELECT
+public.bugsubscriptionfiltertag         = SELECT
 public.bugnotification                  = SELECT, INSERT
 public.bugnotificationrecipient         = SELECT, INSERT
 public.bugnomination                    = SELECT
@@ -1256,6 +1276,10 @@
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugjob                           = SELECT, INSERT
 public.bugsubscription                  = SELECT
+public.bugsubscriptionfilter            = SELECT
+public.bugsubscriptionfilterstatus      = SELECT
+public.bugsubscriptionfilterimportance  = SELECT
+public.bugsubscriptionfiltertag         = SELECT
 public.bugnotification                  = SELECT, INSERT
 public.bugnotificationrecipient         = SELECT, INSERT
 public.bugnomination                    = SELECT
@@ -1323,6 +1347,10 @@
 public.bugnotification                  = SELECT, INSERT, UPDATE
 public.bugnotificationrecipient         = SELECT, INSERT, UPDATE
 public.bugsubscription                  = SELECT, INSERT
+public.bugsubscriptionfilter            = SELECT, INSERT
+public.bugsubscriptionfilterstatus      = SELECT, INSERT
+public.bugsubscriptionfilterimportance  = SELECT, INSERT
+public.bugsubscriptionfiltertag         = SELECT, INSERT
 public.bugnomination                    = SELECT
 public.bug                              = SELECT, INSERT, UPDATE
 public.bugactivity                      = SELECT, INSERT
@@ -1542,6 +1570,10 @@
 public.bugaffectsperson                 = SELECT, INSERT, UPDATE, DELETE
 public.bugjob                           = SELECT, INSERT
 public.bugsubscription                  = SELECT, INSERT
+public.bugsubscriptionfilter            = SELECT, INSERT
+public.bugsubscriptionfilterstatus      = SELECT, INSERT
+public.bugsubscriptionfilterimportance  = SELECT, INSERT
+public.bugsubscriptionfiltertag         = SELECT, INSERT
 public.bugnotification                  = SELECT, INSERT
 public.bugnotificationattachment        = SELECT
 public.bugnotificationrecipient         = SELECT, INSERT
@@ -1550,6 +1582,10 @@
 public.bugtask                          = SELECT, INSERT, UPDATE
 public.bugmessage                       = SELECT, INSERT
 public.bugsubscription                  = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfilter            = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfilterstatus      = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfilterimportance  = SELECT, INSERT, UPDATE, DELETE
+public.bugsubscriptionfiltertag         = SELECT, INSERT, UPDATE, DELETE
 public.bugtracker                       = SELECT, INSERT
 public.bugtrackeralias                  = SELECT, INSERT
 public.bugwatch                         = SELECT, INSERT
@@ -1809,6 +1845,10 @@
 public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.bugsubscription                  = SELECT, INSERT
+public.bugsubscriptionfilter            = SELECT, INSERT
+public.bugsubscriptionfilterstatus      = SELECT, INSERT
+public.bugsubscriptionfilterimportance  = SELECT, INSERT
+public.bugsubscriptionfiltertag         = SELECT, INSERT
 public.bugmessage                       = SELECT, INSERT
 public.sourcepackagename                = SELECT
 public.job                              = SELECT, INSERT, UPDATE
@@ -1836,6 +1876,10 @@
 public.bug                              = SELECT, UPDATE
 public.bugattachment                    = SELECT, DELETE
 public.bugsubscription                  = SELECT
+public.bugsubscriptionfilter            = SELECT
+public.bugsubscriptionfilterstatus      = SELECT
+public.bugsubscriptionfilterimportance  = SELECT
+public.bugsubscriptionfiltertag         = SELECT
 public.bugaffectsperson                 = SELECT
 public.bugnotification                  = SELECT, DELETE
 public.bugnotificationrecipientarchive  = SELECT

=== modified file 'lib/lp/bugs/model/bugsubscription.py'
--- lib/lp/bugs/model/bugsubscription.py	2010-09-09 21:00:54 +0000
+++ lib/lp/bugs/model/bugsubscription.py	2010-09-15 15:32:53 +0000
@@ -7,13 +7,27 @@
 __all__ = ['BugSubscription']
 
 from sqlobject import ForeignKey
+from storm.base import Storm
+from storm.locals import (
+    Bool,
+    Int,
+    Reference,
+    Unicode,
+    )
 from zope.interface import implements
 
 from canonical.database.constants import UTC_NOW
 from canonical.database.datetimecol import UtcDateTimeCol
-from canonical.database.enumcol import EnumCol
+from canonical.database.enumcol import (
+    DBEnum,
+    EnumCol,
+    )
 from canonical.database.sqlbase import SQLBase
 from lp.bugs.interfaces.bugsubscription import IBugSubscription
+from lp.bugs.interfaces.bugtask import (
+    BugTaskImportance,
+    BugTaskStatus,
+    )
 from lp.registry.enum import BugNotificationLevel
 from lp.registry.interfaces.person import validate_person
 
@@ -66,3 +80,63 @@
         if self.person.is_team:
             return user.inTeam(self.person)
         return user == self.person
+
+
+class BugSubscriptionFilter(Storm):
+    """A filter to specialize a *structural* subscription."""
+
+    __storm_table__ = "BugSubscriptionFilter"
+
+    id = Int(primary=True)
+
+    structural_subscription_id = Int("structuralsubscription", allow_none=False)
+    structural_subscription = Reference(
+        structural_subscription_id, "StructuralSubscription.id")
+
+    find_all_tags = Bool(allow_none=False, default=False)
+    include_any_tags = Bool(allow_none=False, default=False)
+    exclude_any_tags = Bool(allow_none=False, default=False)
+
+    other_parameters = Unicode()
+
+    description = Unicode()
+
+
+class BugSubscriptionFilterStatus(Storm):
+    """Statuses to filter."""
+
+    __storm_table__ = "BugSubscriptionFilterStatus"
+
+    id = Int(primary=True)
+
+    filter_id = Int("filter", allow_none=False)
+    filter = Reference(filter_id, "BugSubscriptionFilter.id")
+
+    status = DBEnum(enum=BugTaskStatus, allow_none=False)
+
+
+class BugSubscriptionFilterImportance(Storm):
+    """Importances to filter."""
+
+    __storm_table__ = "BugSubscriptionFilterImportance"
+
+    id = Int(primary=True)
+
+    filter_id = Int("filter", allow_none=False)
+    filter = Reference(filter_id, "BugSubscriptionFilter.id")
+
+    importance = DBEnum(enum=BugTaskImportance, allow_none=False)
+
+
+class BugSubscriptionFilterTag(Storm):
+    """Tags to filter."""
+
+    __storm_table__ = "BugSubscriptionFilterTag"
+
+    id = Int(primary=True)
+
+    filter_id = Int("filter", allow_none=False)
+    filter = Reference(filter_id, "BugSubscriptionFilter.id")
+
+    include = Bool(allow_none=False)
+    tag = Unicode(allow_none=False)

=== added directory 'lib/lp/bugs/model/tests'
=== added file 'lib/lp/bugs/model/tests/__init__.py'
=== added file 'lib/lp/bugs/model/tests/test_bugsubscription.py'
--- lib/lp/bugs/model/tests/test_bugsubscription.py	1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/model/tests/test_bugsubscription.py	2010-09-15 15:32:53 +0000
@@ -0,0 +1,182 @@
+# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for the bugsubscription module."""
+
+__metaclass__ = type
+
+from canonical.launchpad.interfaces.lpstorm import IStore
+from canonical.testing import DatabaseFunctionalLayer
+from lp.bugs.interfaces.bugtask import (
+    BugTaskImportance,
+    BugTaskStatus,
+    )
+from lp.bugs.model.bugsubscription import (
+    BugSubscriptionFilter,
+    BugSubscriptionFilterImportance,
+    BugSubscriptionFilterStatus,
+    BugSubscriptionFilterTag,
+    )
+from lp.testing import (
+    login_person,
+    TestCaseWithFactory,
+    )
+
+
+class TestBugSubscriptionFilter(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestBugSubscriptionFilter, self).setUp()
+        self.target = self.factory.makeProduct()
+        self.subscriber = self.target.owner
+        login_person(self.subscriber)
+        self.subscription = self.target.addBugSubscription(
+            self.subscriber, self.subscriber)
+
+    def test_basics(self):
+        """Test the basic operation of `BugSubscriptionFilter` objects."""
+        # Create.
+        bug_subscription_filter = BugSubscriptionFilter()
+        bug_subscription_filter.structural_subscription = self.subscription
+        bug_subscription_filter.find_all_tags = True
+        bug_subscription_filter.include_any_tags = True
+        bug_subscription_filter.exclude_any_tags = True
+        bug_subscription_filter.other_parameters = u"foo"
+        bug_subscription_filter.description = u"bar"
+        # Flush and reload.
+        IStore(bug_subscription_filter).flush()
+        IStore(bug_subscription_filter).reload(bug_subscription_filter)
+        # Check.
+        self.assertIsNot(None, bug_subscription_filter.id)
+        self.assertEqual(
+            self.subscription.id,
+            bug_subscription_filter.structural_subscription_id)
+        self.assertEqual(
+            self.subscription,
+            bug_subscription_filter.structural_subscription)
+        self.assertIs(True, bug_subscription_filter.find_all_tags)
+        self.assertIs(True, bug_subscription_filter.include_any_tags)
+        self.assertIs(True, bug_subscription_filter.exclude_any_tags)
+        self.assertEqual(u"foo", bug_subscription_filter.other_parameters)
+        self.assertEqual(u"bar", bug_subscription_filter.description)
+
+    def test_defaults(self):
+        """Test the default values of `BugSubscriptionFilter` objects."""
+        # Create.
+        bug_subscription_filter = BugSubscriptionFilter()
+        bug_subscription_filter.structural_subscription = self.subscription
+        # Check.
+        self.assertIs(False, bug_subscription_filter.find_all_tags)
+        self.assertIs(False, bug_subscription_filter.find_all_tags)
+        self.assertIs(False, bug_subscription_filter.include_any_tags)
+        self.assertIs(False, bug_subscription_filter.exclude_any_tags)
+        self.assertIs(None, bug_subscription_filter.other_parameters)
+        self.assertIs(None, bug_subscription_filter.description)
+
+
+class TestBugSubscriptionFilterStatus(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestBugSubscriptionFilterStatus, self).setUp()
+        self.target = self.factory.makeProduct()
+        self.subscriber = self.target.owner
+        login_person(self.subscriber)
+        self.subscription = self.target.addBugSubscription(
+            self.subscriber, self.subscriber)
+        self.subscription_filter = BugSubscriptionFilter()
+        self.subscription_filter.structural_subscription = self.subscription
+
+    def test_basics(self):
+        """Test the basics of `BugSubscriptionFilterStatus` objects."""
+        # Create.
+        bug_sub_filter_status = BugSubscriptionFilterStatus()
+        bug_sub_filter_status.filter = self.subscription_filter
+        bug_sub_filter_status.status = BugTaskStatus.NEW
+        # Flush and reload.
+        IStore(bug_sub_filter_status).flush()
+        IStore(bug_sub_filter_status).reload(bug_sub_filter_status)
+        # Check.
+        self.assertIsNot(None, bug_sub_filter_status.id)
+        self.assertEqual(
+            self.subscription_filter.id,
+            bug_sub_filter_status.filter_id)
+        self.assertEqual(
+            self.subscription_filter,
+            bug_sub_filter_status.filter)
+        self.assertEqual(BugTaskStatus.NEW, bug_sub_filter_status.status)
+
+
+class TestBugSubscriptionFilterImportance(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestBugSubscriptionFilterImportance, self).setUp()
+        self.target = self.factory.makeProduct()
+        self.subscriber = self.target.owner
+        login_person(self.subscriber)
+        self.subscription = self.target.addBugSubscription(
+            self.subscriber, self.subscriber)
+        self.subscription_filter = BugSubscriptionFilter()
+        self.subscription_filter.structural_subscription = self.subscription
+
+    def test_basics(self):
+        """Test the basics of `BugSubscriptionFilterImportance` objects."""
+        # Create.
+        bug_sub_filter_importance = BugSubscriptionFilterImportance()
+        bug_sub_filter_importance.filter = self.subscription_filter
+        bug_sub_filter_importance.importance = BugTaskImportance.HIGH
+        # Flush and reload.
+        IStore(bug_sub_filter_importance).flush()
+        IStore(bug_sub_filter_importance).reload(bug_sub_filter_importance)
+        # Check.
+        self.assertIsNot(None, bug_sub_filter_importance.id)
+        self.assertEqual(
+            self.subscription_filter.id,
+            bug_sub_filter_importance.filter_id)
+        self.assertEqual(
+            self.subscription_filter,
+            bug_sub_filter_importance.filter)
+        self.assertEqual(
+            BugTaskImportance.HIGH,
+            bug_sub_filter_importance.importance)
+
+
+class TestBugSubscriptionFilterTag(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestBugSubscriptionFilterTag, self).setUp()
+        self.target = self.factory.makeProduct()
+        self.subscriber = self.target.owner
+        login_person(self.subscriber)
+        self.subscription = self.target.addBugSubscription(
+            self.subscriber, self.subscriber)
+        self.subscription_filter = BugSubscriptionFilter()
+        self.subscription_filter.structural_subscription = self.subscription
+
+    def test_basics(self):
+        """Test the basics of `BugSubscriptionFilterTag` objects."""
+        # Create.
+        bug_sub_filter_tag = BugSubscriptionFilterTag()
+        bug_sub_filter_tag.filter = self.subscription_filter
+        bug_sub_filter_tag.include = True
+        bug_sub_filter_tag.tag = u"foo"
+        # Flush and reload.
+        IStore(bug_sub_filter_tag).flush()
+        IStore(bug_sub_filter_tag).reload(bug_sub_filter_tag)
+        # Check.
+        self.assertIsNot(None, bug_sub_filter_tag.id)
+        self.assertEqual(
+            self.subscription_filter.id,
+            bug_sub_filter_tag.filter_id)
+        self.assertEqual(
+            self.subscription_filter,
+            bug_sub_filter_tag.filter)
+        self.assertIs(True, bug_sub_filter_tag.include)
+        self.assertEqual(u"foo", bug_sub_filter_tag.tag)

=== modified file 'lib/lp/registry/model/structuralsubscription.py'
--- lib/lp/registry/model/structuralsubscription.py	2010-08-20 20:31:18 +0000
+++ lib/lp/registry/model/structuralsubscription.py	2010-09-15 15:32:53 +0000
@@ -266,47 +266,36 @@
                          min_blueprint_notification_level=
                          BlueprintNotificationLevel.NOTHING):
         """See `IStructuralSubscriptionTarget`."""
-        target_clause_parts = []
-        for key, value in self._target_args.items():
+        clauses = [
+            "StructuralSubscription.subscriber = Person.id",
+            "StructuralSubscription.bug_notification_level "
+            ">= %s" % quote(min_bug_notification_level),
+            "StructuralSubscription.blueprint_notification_level "
+            ">= %s" % quote(min_blueprint_notification_level),
+            ]
+        for key, value in self._target_args.iteritems():
             if value is None:
-                target_clause_parts.append(
-                    "StructuralSubscription.%s IS NULL " % (key, ))
+                clauses.append(
+                    "StructuralSubscription.%s IS NULL" % (key,))
             else:
-                target_clause_parts.append(
-                    "StructuralSubscription.%s = %s " % (key, quote(value)))
-        target_clause = " AND ".join(target_clause_parts)
-        query = target_clause + """
-            AND StructuralSubscription.subscriber = Person.id
-            """
-        all_subscriptions = StructuralSubscription.select(
-            query,
-            orderBy='Person.displayname',
-            clauseTables=['Person'])
-        subscriptions = [sub for sub
-                         in all_subscriptions
-                         if ((sub.bug_notification_level >=
-                             min_bug_notification_level) and
-                             (sub.blueprint_notification_level >=
-                              min_blueprint_notification_level))]
-        return subscriptions
+                clauses.append(
+                    "StructuralSubscription.%s = %s" % (key, quote(value)))
+        query = " AND ".join(clauses)
+        return StructuralSubscription.select(
+            query, orderBy='Person.displayname', clauseTables=['Person'])
 
     def getBugNotificationsRecipients(self, recipients=None, level=None):
         """See `IStructuralSubscriptionTarget`."""
-        subscribers = set()
         if level is None:
             subscriptions = self.bug_subscriptions
         else:
             subscriptions = self.getSubscriptions(
                 min_bug_notification_level=level)
-        for subscription in subscriptions:
-            if (level is not None and
-                subscription.bug_notification_level < level):
-                continue
-            subscriber = subscription.subscriber
-            subscribers.add(subscriber)
-            if recipients is not None:
-                recipients.addStructuralSubscriber(
-                    subscriber, self)
+        subscribers = set(
+            subscription.subscriber for subscription in subscriptions)
+        if recipients is not None:
+            for subscriber in subscribers:
+                recipients.addStructuralSubscriber(subscriber, self)
         parent = self.parent_subscription_target
         if parent is not None:
             subscribers.update(