← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/bugsubscriptionfilter-itype-ui into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/bugsubscriptionfilter-itype-ui into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1026757 in Launchpad itself: "cannot filter structural subscriptions by information type"
  https://bugs.launchpad.net/launchpad/+bug/1026757

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/bugsubscriptionfilter-itype-ui/+merge/118472

Hook up the UI to allow people to filter structural subscriptions by the information type of a bug.
-- 
https://code.launchpad.net/~stevenk/launchpad/bugsubscriptionfilter-itype-ui/+merge/118472
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/bugsubscriptionfilter-itype-ui into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bugsubscriptionfilter.py'
--- lib/lp/bugs/browser/bugsubscriptionfilter.py	2012-03-13 00:45:33 +0000
+++ lib/lp/bugs/browser/bugsubscriptionfilter.py	2012-08-07 05:37:22 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """View classes for bug subscription filters."""
@@ -70,6 +70,15 @@
     # in particular, if no importances are checked, or no statuses.
     filters_everything = False
 
+    def _english_condition(self, variable, description):
+        condition = []
+        if len(variable) > 0:
+            condition.append(
+                u"the %s is %s" % (description, english_list(
+                    (kind.title for kind in sorted(variable)),
+                    conjunction=u"or")))
+        return condition
+
     @property
     def conditions(self):
         """Descriptions of the bug subscription filter's conditions."""
@@ -80,24 +89,19 @@
                 'the bug')
             conditions.append(
                 mapping[bug_notification_level].lower()[:-1])
-        statuses = self.context.statuses
-        if len(statuses) > 0:
-            conditions.append(
-                u"the status is %s" % english_list(
-                    (status.title for status in sorted(statuses)),
-                    conjunction=u"or"))
-        importances = self.context.importances
-        if len(importances) > 0:
-            conditions.append(
-                u"the importance is %s" % english_list(
-                    (importance.title for importance in sorted(importances)),
-                    conjunction=u"or"))
+        conditions.extend(
+            self._english_condition(self.context.statuses, 'status'))
+        conditions.extend(
+            self._english_condition(self.context.importances, 'importance'))
         tags = self.context.tags
         if len(tags) > 0:
             conditions.append(
                 u"the bug is tagged with %s" % english_list(
                     sorted(tags), conjunction=(
                         u"and" if self.context.find_all_tags else u"or")))
+        conditions.extend(
+            self._english_condition(self.context.information_types,
+            'information type'))
         return conditions
 
 
@@ -110,6 +114,7 @@
         "description",
         "statuses",
         "importances",
+        "information_types",
         "tags",
         "find_all_tags",
         )
@@ -117,6 +122,7 @@
     custom_widget("description", TextWidget, displayWidth=50)
     custom_widget("statuses", LabeledMultiCheckBoxWidget)
     custom_widget("importances", LabeledMultiCheckBoxWidget)
+    custom_widget("information_types", LabeledMultiCheckBoxWidget)
     custom_widget("tags", BugTagsFrozenSetWidget, displayWidth=35)
 
     # Define in concrete subclass to be the target of the

=== modified file 'lib/lp/bugs/browser/structuralsubscription.py'
--- lib/lp/bugs/browser/structuralsubscription.py	2012-03-18 01:29:07 +0000
+++ lib/lp/bugs/browser/structuralsubscription.py	2012-08-07 05:37:22 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -52,6 +52,7 @@
     IStructuralSubscriptionTarget,
     IStructuralSubscriptionTargetHelper,
     )
+from lp.registry.enums import InformationType
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.distributionsourcepackage import (
     IDistributionSourcePackage,
@@ -210,8 +211,7 @@
         Returns True is the user is subscribed to bug notifications
         for the context target.
         """
-        subscription = self.context.getSubscription(person)
-        return subscription is not None
+        return self.context.getSubscription(person) is not None
 
     def currentUserIsSubscribed(self):
         """Return True, if the current user is subscribed."""
@@ -415,6 +415,7 @@
     expose_user_administered_teams_to_js(request, user, context)
     expose_enum_to_js(request, BugTaskImportance, 'importances')
     expose_enum_to_js(request, BugTaskStatus, 'statuses')
+    expose_enum_to_js(request, InformationType, 'information_types')
     if subscriptions is None:
         try:
             # No subscriptions, which means we are on a target
@@ -432,10 +433,7 @@
 
 def expose_enum_to_js(request, enum, name):
     """Make a list of enum titles and value available to JavaScript."""
-    info = []
-    for item in enum:
-        info.append(item.title)
-    IJSONRequestCache(request).objects[name] = info
+    IJSONRequestCache(request).objects[name] = [item.title for item in enum]
 
 
 def expose_user_administered_teams_to_js(request, user, context,

=== modified file 'lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py'
--- lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py	2012-03-13 00:45:33 +0000
+++ lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py	2012-08-07 05:37:22 +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).
 
 """Tests for bug subscription filter browser code."""
@@ -22,6 +22,7 @@
     BugTaskImportance,
     BugTaskStatus,
     )
+from lp.registry.enums import InformationType
 from lp.services.webapp.publisher import canonical_url
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
@@ -320,6 +321,17 @@
             [u"the bug is tagged with *, bar, and foo"],
             self.view.conditions)
 
+    def test_conditions_for_information_types(self):
+        # If no information types have been specified nothing is returned.
+        self.assertEqual([], self.view.conditions)
+        # If set, a description of the information type is returned.
+        with person_logged_in(self.owner):
+            self.subscription_filter.information_types = [
+                InformationType.PRIVATESECURITY, InformationType.USERDATA]
+        self.assertEqual(
+            [u"the information type is Private Security or Private"],
+            self.view.conditions)
+
     def assertRender(self, dt_content=None, dd_content=None):
         root = html.fromstring(self.view.render())
         if dt_content is not None:
@@ -435,6 +447,7 @@
             "field.description": "New description",
             "field.statuses": ["NEW", "INCOMPLETE"],
             "field.importances": ["LOW", "MEDIUM"],
+            "field.information_types": ["USERDATA"],
             "field.tags": u"foo bar",
             "field.find_all_tags": "on",
             "field.actions.update": "Update",
@@ -445,8 +458,7 @@
             self.assertEqual([], view.errors)
         # The subscription filter has been updated.
         self.assertEqual(
-            u"New description",
-            self.subscription_filter.description)
+            u"New description", self.subscription_filter.description)
         self.assertEqual(
             frozenset([BugTaskStatus.NEW, BugTaskStatus.INCOMPLETE]),
             self.subscription_filter.statuses)
@@ -454,10 +466,11 @@
             frozenset([BugTaskImportance.LOW, BugTaskImportance.MEDIUM]),
             self.subscription_filter.importances)
         self.assertEqual(
-            frozenset([u"foo", u"bar"]),
-            self.subscription_filter.tags)
-        self.assertTrue(
-            self.subscription_filter.find_all_tags)
+            frozenset([InformationType.USERDATA]),
+            self.subscription_filter.information_types)
+        self.assertEqual(
+            frozenset([u"foo", u"bar"]), self.subscription_filter.tags)
+        self.assertTrue(self.subscription_filter.find_all_tags)
 
     def test_delete(self):
         # The filter can be deleted by using the delete action.
@@ -551,6 +564,7 @@
             "field.description": "New description",
             "field.statuses": ["NEW", "INCOMPLETE"],
             "field.importances": ["LOW", "MEDIUM"],
+            "field.information_types": ["PRIVATESECURITY"],
             "field.tags": u"foo bar",
             "field.find_all_tags": "on",
             "field.actions.create": "Create",
@@ -573,7 +587,8 @@
             frozenset([BugTaskImportance.LOW, BugTaskImportance.MEDIUM]),
             subscription_filter.importances)
         self.assertEqual(
-            frozenset([u"foo", u"bar"]),
-            subscription_filter.tags)
-        self.assertTrue(
-            subscription_filter.find_all_tags)
+            frozenset([InformationType.PRIVATESECURITY]),
+            subscription_filter.information_types)
+        self.assertEqual(
+            frozenset([u"foo", u"bar"]), subscription_filter.tags)
+        self.assertTrue(subscription_filter.find_all_tags)

=== modified file 'lib/lp/registry/javascript/structural-subscription.js'
--- lib/lp/registry/javascript/structural-subscription.js	2012-07-20 22:48:23 +0000
+++ lib/lp/registry/javascript/structural-subscription.js	2012-08-07 05:37:22 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2011 Canonical Ltd.  This software is licensed under the
+/* Copyright 2011-2012 Canonical Ltd.  This software is licensed under the
  * GNU Affero General Public License version 3 (see the file LICENSE).
  *
  * Form overlay widgets and subscriber handling for structural subscriptions.
@@ -103,7 +103,8 @@
         tags: [],
         find_all_tags: false,
         importances: [],
-        statuses: []
+        statuses: [],
+        information_types: []
     };
 
     // Set the notification level.
@@ -137,10 +138,14 @@
         if (form_data.statuses.length > 0) {
             patch_data.statuses = form_data.statuses;
         }
+        if (form_data.information_types.length > 0) {
+            patch_data.information_types = form_data.information_types;
+        }
     } else {
         // clear out the tags, statuses, and importances in case this is an
         // edit.
         patch_data.tags = patch_data.importances = patch_data.statuses = [];
+        patch_data.information_types = [];
     }
     return patch_data;
 }
@@ -431,6 +436,8 @@
         content_node, LP.cache.statuses, LP.cache.statuses);
     set_checkboxes(
         content_node, LP.cache.importances, LP.cache.importances);
+    set_checkboxes(
+        content_node, LP.cache.information_types, LP.cache.information_types);
     content_node.one('[name="tags"]').set('value', '');
     set_radio_buttons(
         content_node, [MATCH_ALL, MATCH_ANY], MATCH_ALL);
@@ -556,7 +563,8 @@
 
     var statuses_ai,
         importances_ai,
-        tags_ai;
+        tags_ai,
+        information_types_ai;
 
     // Build tags pane.
     tags_ai = new Y.AccordionItem( {
@@ -644,6 +652,28 @@
     var official_bug_tags = LP.cache.context.official_bug_tags || [];
     namespace.bug_tag_completer = Y.lp.bugs.tags_entry.setup_tag_complete(
         'input[name="tags"]', official_bug_tags);
+
+    // Build information_types pane.
+    information_types_ai = new Y.AccordionItem( {
+        label: "Information types",
+        expanded: false,
+        alwaysVisible: false,
+        id: "information_types_ai",
+        contentHeight: {method: "auto"}
+    } );
+    var information_types = LP.cache.information_types;
+    selectors = make_selector_controls('information_types');
+    information_types_ai.set("bodyContent",
+        Y.Node.create('<div id="information_types-wrapper"></div>')
+            .append(selectors.node)
+            .append(make_table(information_types, 'information_types', 4)));
+    accordion.addItem(information_types_ai);
+    // Wire up the 'all' and 'none' selectors.
+    node = content_node.one('#information_types-wrapper');
+    selectors.all_link.on('click',
+        make_select_handler(node, information_types, true));
+    selectors.none_link.on('click',
+        make_select_handler(node, information_types, false));
     return accordion;
 }
 
@@ -1042,10 +1072,12 @@
 function set_filter_statuses_and_importances(content_node, filter) {
     var is_lifecycle = filter.bug_notification_level==='Lifecycle',
         statuses = filter.statuses,
-        importances = filter.importances;
+        importances = filter.importances,
+        information_types = filter.information_types;
     if (is_lifecycle) {
         statuses = LP.cache.statuses;
         importances = LP.cache.importances;
+        information_types = LP.cache.information_types;
     } else {
         // An absence of values is equivalent to all values.
         if (statuses.length === 0) {
@@ -1054,10 +1086,15 @@
         if (importances.length === 0) {
             importances = LP.cache.importances;
         }
+        if (information_types.length === 0) {
+            information_types = LP.cache.information_types;
+        }
     }
     set_checkboxes(content_node, LP.cache.statuses, statuses);
     set_checkboxes(
         content_node, LP.cache.importances, importances);
+    set_checkboxes(
+        content_node, LP.cache.information_types, information_types);
 }
 
 /**
@@ -1082,6 +1119,7 @@
         has_advanced_filters = !is_lifecycle && (
             filter.statuses.length ||
                 filter.importances.length ||
+                filter.information_types.length ||
                 filter.tags.length) > 0,
         filters = has_advanced_filters ? [ADVANCED_FILTER] : [],
         event = ADDED_OR_CHANGED;
@@ -1555,6 +1593,13 @@
                 'are of importance: '+filter.importances.join(', ')));
     }
 
+    // Format information type conditions.
+    if (filter.information_types.length !== 0) {
+        filter_items.push(Y.Node.create('<li></li>')
+            .set('text',
+                'are of information type: '+filter.information_types.join(', ')));
+    }
+
     // Format tag conditions.
     if (filter.tags.length !== 0) {
         var tag_desc = Y.Node.create('<li>are tagged with </li>')

=== modified file 'lib/lp/registry/javascript/tests/test_structural_subscription.js'
--- lib/lp/registry/javascript/tests/test_structural_subscription.js	2012-07-31 06:14:21 +0000
+++ lib/lp/registry/javascript/tests/test_structural_subscription.js	2012-08-07 05:37:22 +0000
@@ -86,6 +86,9 @@
                                'Invalid', 'Won\'t Fix', 'Expired',
                                'Confirmed', 'Triaged', 'In Progress',
                                'Fix Committed', 'Fix Released', 'Unknown'];
+          LP.cache.information_types = ['Public', 'Public Security',
+                                        'Private Security', 'Private',
+                                        'Properitary'];
           LP.links.me = 'https://launchpad.dev/api/~someone';
           return original_lp;
     }
@@ -124,6 +127,7 @@
             LP.cache.administratedTeams = [];
             LP.cache.importances = [];
             LP.cache.statuses = [];
+            LP.cache.information_types = [];
 
             this.configuration = {
                 content_box: content_box_id
@@ -226,6 +230,7 @@
             LP.cache.administratedTeams = [];
             LP.cache.importances = [];
             LP.cache.statuses = [];
+            LP.cache.information_types = [];
 
             this.configuration = {
                 content_box: content_box_id
@@ -357,6 +362,7 @@
             LP.cache.administratedTeams = [];
             LP.cache.importances = [];
             LP.cache.statuses = [];
+            LP.cache.information_types = [];
             LP.links.me = 'https://launchpad.dev/api/~someone';
 
             var lp_client = function() {};
@@ -417,6 +423,7 @@
             LP.cache.administratedTeams = [];
             LP.cache.importances = [];
             LP.cache.statuses = [];
+            LP.cache.information_types = [];
             LP.links.me = 'https://launchpad.dev/api/~someone';
 
             var lp_client = function() {};
@@ -702,6 +709,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -737,6 +745,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -775,6 +784,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -815,6 +825,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1015,7 +1026,8 @@
                 tags: [' one two THREE '],
                 tag_match: [''],
                 importances: [],
-                statuses: []
+                statuses: [],
+                information_types: []
             };
             var patch_data = module._extract_form_data(form_data);
             // Note that the tags are converted to lower case
@@ -1032,7 +1044,8 @@
                 tags: ['tag'],
                 tag_match: ['match-all'],
                 importances: [],
-                statuses: []
+                statuses: [],
+                information_types: []
             };
             var patch_data = module._extract_form_data(form_data);
             Assert.isTrue(patch_data.find_all_tags);
@@ -1046,7 +1059,8 @@
                 tags: ['tag'],
                 tag_match: [],
                 importances: [],
-                statuses: []
+                statuses: [],
+                information_types: []
             };
             var patch_data = module._extract_form_data(form_data);
             Assert.isFalse(patch_data.find_all_tags);
@@ -1063,7 +1077,8 @@
                 tags: ['tag'],
                 tag_match: ['match-all'],
                 importances: ['importance1'],
-                statuses: ['status1']
+                statuses: ['status1'],
+                information_types: ['informationtype1']
             };
             var patch_data = module._extract_form_data(form_data);
             // Since advanced-filter isn't set, all the advanced values should
@@ -1072,6 +1087,7 @@
             ArrayAssert.isEmpty(patch_data.tags);
             ArrayAssert.isEmpty(patch_data.importances);
             ArrayAssert.isEmpty(patch_data.statuses);
+            ArrayAssert.isEmpty(patch_data.information_types);
         }
 
     }));
@@ -1092,6 +1108,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion'
@@ -1183,6 +1200,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion'
@@ -1251,6 +1269,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1353,6 +1372,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1513,6 +1533,7 @@
                     return {
                         importances: [],
                         statuses: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1561,6 +1582,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1580,6 +1602,7 @@
                     return {
                         importances: [],
                         statuses: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1621,6 +1644,7 @@
                     {filter: {
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',
@@ -1770,6 +1794,7 @@
                         description: 'DESCRIPTION',
                         statuses: [],
                         importances: [],
+                        information_types: [],
                         tags: [],
                         find_all_tags: true,
                         bug_notification_level: 'Discussion',


Follow ups