← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~gary/launchpad/bug728370-direct-subs into lp:launchpad

 

Gary Poster has proposed merging lp:~gary/launchpad/bug728370-direct-subs into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~gary/launchpad/bug728370-direct-subs/+merge/57703

This branch is another incremental step towards the "unsubscribe in anger story."  It has two parts.

The main task is to set up a simple way to include actions.  This branch creates placeholder actions corresponding to the initial cut of actions I expect to provide for non-direct non-personal subscriptions and associates them with the proper output.  Tests are adjusted to show the new data.

A side task was that I saw that it was possible to have the same team shown multiple times for assignees and direct team subscriptions.  I added tests for this case and changed the pertinent code (gosh it would be nice to have a more robust mapping implementation in JS!).

Thank you

Gary
-- 
https://code.launchpad.net/~gary/launchpad/bug728370-direct-subs/+merge/57703
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~gary/launchpad/bug728370-direct-subs into lp:launchpad.
=== modified file 'lib/lp/bugs/javascript/subscription.js'
--- lib/lp/bugs/javascript/subscription.js	2011-04-13 15:47:48 +0000
+++ lib/lp/bugs/javascript/subscription.js	2011-04-14 15:27:20 +0000
@@ -109,6 +109,20 @@
     ADMIN_TEAM_OWNER: _ADMIN_BECAUSE_TEAM_IS + _OWNER,
 });
 
+/* These are the actions */
+var actions = {
+    CHANGE_ASSIGNEES: function () {
+    },
+    UNSUBSCRIBE_DUPLICATES: function () {
+    },
+    CHANGE_TEAM_SUBSCRIPTIONS: function () {
+    },
+    SET_BUG_SUPERVISOR: function () {
+    },
+    NONE: function () {
+    }
+};
+namespace._actions = actions;
 
 /**
  * Return appropriate object based on the number.
@@ -205,44 +219,43 @@
  * than one, variable `teams` is set containing all the teams.
  */
 function gather_subscriptions_by_role(
-    category, team_singular, team_plural,
-    admin_team_singular, admin_team_plural) {
-    var subscriptions = [];
-    if (category.as_team_member.length > 0) {
-        var teams = [];
-        for (var index in category.as_team_member) {
-            var team_subscription = category.as_team_member[index];
-            teams.push(get_link_data(team_subscription.principal));
-        }
-        var sub = choose_by_number(
-            category.as_team_member.length,
-            { reason: team_singular,
-              vars: {
-                  team: teams[0] } },
-            { reason: team_plural,
-              vars: {
-                  teams: teams } });
-        subscriptions.push(sub);
-    }
-
-    if (category.as_team_admin.length > 0) {
-        var teams = [];
-        for (var index in category.as_team_admin) {
-            var team_subscription = category.as_team_admin[index];
-            teams.push(get_link_data(team_subscription.principal));
-        }
-        var sub = choose_by_number(
-            category.as_team_admin.length,
-            { reason: admin_team_singular,
-              vars: {
-                  team: teams[0] } },
-            { reason: admin_team_plural,
-              vars: {
-                  teams: teams } });
-        subscriptions.push(sub);
-    }
-
-    return subscriptions;
+    category, team_config, admin_team_config) {
+    var results = [],
+        work = [{subscriptions: category.as_team_member,
+                 config: team_config},
+                {subscriptions: category.as_team_admin,
+                 config: admin_team_config}];
+    for (var work_index in work) {
+        var subscriptions = work[work_index]['subscriptions'];
+        var config = work[work_index]['config'];
+        if (subscriptions.length > 0) {
+            var team_map = {};
+            var teams = [];
+            for (var index in subscriptions) {
+                var team_subscription = subscriptions[index],
+                    team = team_subscription.principal,
+                    key = team.web_link,
+                    key = Y.Lang.isValue(key) ? key : team; // For tests.
+                if (!Y.Lang.isValue(team_map[key])) {
+                    var link_data = get_link_data(team);
+                    team_map[team.web_link] = link_data;
+                    teams.push(link_data);
+                }
+            }
+            var sub = choose_by_number(
+                subscriptions.length,
+                { reason: config.singular,
+                  vars: {
+                      team: teams[0] } },
+                { reason: config.plural,
+                  vars: {
+                      teams: teams } });
+            sub['action'] = config.action;
+            results.push(sub);
+        }
+    }
+
+    return results;
 }
 
 /**
@@ -255,14 +268,20 @@
     if (category.personal.length > 0) {
         subscriptions.push(
             { reason: reasons.YOU_ASSIGNED,
-              vars: {} });
+              vars: {},
+              action: actions.CHANGE_ASSIGNEES });
     }
 
     // We add all the team assignments grouped by roles in the team.
     return subscriptions.concat(
         gather_subscriptions_by_role(
-            category, reasons.TEAM_ASSIGNED, reasons.TEAMS_ASSIGNED,
-            reasons.ADMIN_TEAM_ASSIGNED, reasons.ADMIN_TEAMS_ASSIGNED));
+            category,
+            {singular: reasons.TEAM_ASSIGNED,
+             plural: reasons.TEAMS_ASSIGNED,
+             action: actions.NONE},
+            {singular: reasons.ADMIN_TEAM_ASSIGNED,
+             plural: reasons.ADMIN_TEAMS_ASSIGNED,
+             action: actions.CHANGE_ASSIGNEES}));
 }
 namespace._gather_subscriptions_as_assignee =
         gather_subscriptions_as_assignee;
@@ -280,7 +299,8 @@
             reason: reasons.YOU_OWNER,
             vars: {
                 pillar: get_link_data(subscription.pillar)
-            }
+            },
+            action: actions.SET_BUG_SUPERVISOR
         });
     }
 
@@ -291,7 +311,8 @@
             vars: {
                 team: get_link_data(team_subscription.principal),
                 pillar: get_link_data(team_subscription.pillar)
-            }
+            },
+            action: actions.NONE
         });
     }
 
@@ -302,7 +323,8 @@
             vars: {
                 team: get_link_data(team_subscription.principal),
                 pillar: get_link_data(team_subscription.pillar)
-            }
+            },
+            action: actions.SET_BUG_SUPERVISOR
         });
     }
 
@@ -312,7 +334,7 @@
         gather_subscriptions_as_supervisor;
 
 function gather_dupe_subscriptions_by_team(team_subscriptions,
-                                           singular, plural) {
+                                           singular, plural, action) {
     var subscriptions = [];
 
     // Collated list of { team: ..., bugs: []} records.
@@ -346,6 +368,7 @@
             { reason: plural,
               vars: { duplicate_bugs: team_dupes.bugs,
                       team: get_link_data(team_dupes.team) }});
+        sub['action'] = action;
         subscriptions.push(sub);
     }
     return subscriptions;
@@ -371,6 +394,7 @@
               vars: { duplicate_bug: dupes[0] }},
             { reason: reasons.YOU_SUBSCRIBED_TO_DUPLICATES,
               vars: { duplicate_bugs: dupes }});
+        sub['action'] = actions.UNSUBSCRIBE_DUPLICATES
         subscriptions.push(sub);
     }
 
@@ -379,14 +403,16 @@
         gather_dupe_subscriptions_by_team(
             category.as_team_member,
             reasons.TEAM_SUBSCRIBED_TO_DUPLICATE,
-            reasons.TEAM_SUBSCRIBED_TO_DUPLICATES));
+            reasons.TEAM_SUBSCRIBED_TO_DUPLICATES,
+            actions.NONE));
 
     // Get subscriptions as team admin, grouped by teams.
     subscriptions = subscriptions.concat(
         gather_dupe_subscriptions_by_team(
             category.as_team_admin,
             reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATE,
-            reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATES));
+            reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATES,
+            actions.UNSUBSCRIBE_DUPLICATES));
 
     return subscriptions;
 }
@@ -399,8 +425,13 @@
 function gather_subscriptions_through_team(category) {
     var reasons = namespace._reasons;
     return gather_subscriptions_by_role(
-        category, reasons.TEAM_SUBSCRIBED, reasons.TEAMS_SUBSCRIBED,
-        reasons.ADMIN_TEAM_SUBSCRIBED, reasons.ADMIN_TEAMS_SUBSCRIBED);
+        category,
+        {singular: reasons.TEAM_SUBSCRIBED,
+         plural: reasons.TEAMS_SUBSCRIBED,
+         action: actions.NONE},
+        {singular: reasons.ADMIN_TEAM_SUBSCRIBED,
+         plural:reasons.ADMIN_TEAMS_SUBSCRIBED,
+         action: actions.CHANGE_TEAM_SUBSCRIPTIONS});
 }
 namespace._gather_subscriptions_through_team =
         gather_subscriptions_through_team;

=== modified file 'lib/lp/bugs/javascript/tests/test_subscription.js'
--- lib/lp/bugs/javascript/tests/test_subscription.js	2011-04-13 14:19:19 +0000
+++ lib/lp/bugs/javascript/tests/test_subscription.js	2011-04-14 15:27:20 +0000
@@ -123,6 +123,7 @@
         var subs = module._gather_subscriptions_as_assignee(mock_category);
         Y.Assert.areEqual(1, subs.length);
         Y.Assert.areEqual(module._reasons.YOU_ASSIGNED, subs[0].reason);
+        Y.Assert.areEqual(module._actions.CHANGE_ASSIGNEES, subs[0].action);
     },
 
     test_team_member: function() {
@@ -139,6 +140,7 @@
         Y.Assert.areEqual(module._reasons.TEAM_ASSIGNED, subs[0].reason);
         // And there is a 'team' variable containing the team object.
         Y.Assert.areEqual('my team', subs[0].vars.team);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
     },
 
     test_team_member_multiple: function() {
@@ -158,6 +160,36 @@
         // And there is a 'teams' variable containing all the team objects.
         Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
                                     subs[0].vars.teams);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
+    },
+
+    test_team_member_multiple_duplicate: function() {
+        // As with the previous test, but we need to show that each team is
+        // only represented once even if they are responsible for multiple
+        // bug tasks.
+        // We test with full-fledged objects to make sure they work with the
+        // mechanism used to find dupes.
+        var team1 = {display_name: 'team 1',
+                     web_link: 'http://launchpad.net/~team1'},
+            team2 = {display_name: 'team 2',
+                     web_link: 'http://launchpad.net/~team2'},
+            mock_category = {
+            count: 2,
+            personal: [],
+            as_team_member: [{ principal: team1 },
+                             { principal: team2 },
+                             { principal: team2 },],
+            as_team_admin: []
+            },
+            subs = module._gather_subscriptions_as_assignee(mock_category);
+        Y.Assert.areEqual(1, subs.length);
+        Y.Assert.areEqual(module._reasons.TEAMS_ASSIGNED, subs[0].reason);
+        // And there is a 'teams' variable containing all the team objects.
+        var teams_found = [];
+        for (var index in subs[0].vars.teams) {
+            teams_found.push(subs[0].vars.teams[index].title);
+        }
+        Y.ArrayAssert.itemsAreEqual(['team 1', 'team 2'], teams_found);
     },
 
     test_team_admin: function() {
@@ -175,6 +207,7 @@
             module._reasons.ADMIN_TEAM_ASSIGNED, subs[0].reason);
         // And there is a 'team' variable containing the team object.
         Y.Assert.areEqual('my team', subs[0].vars.team);
+        Y.Assert.areEqual(module._actions.CHANGE_ASSIGNEES, subs[0].action);
     },
 
     test_team_admin_multiple: function() {
@@ -195,6 +228,35 @@
         // And there is a 'teams' variable containing all the team objects.
         Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
                                     subs[0].vars.teams);
+        Y.Assert.areEqual(module._actions.CHANGE_ASSIGNEES, subs[0].action);
+    },
+
+    test_team_admin_multiple_duplicate: function() {
+        // As with the previous test, but we need to show that each team is
+        // only represented once even if they are responsible for multiple
+        // bug tasks.
+        // We test with full-fledged objects to make sure they work with the
+        // mechanism used to find dupes.
+        var team1 = {display_name: 'team 1',
+                     web_link: 'http://launchpad.net/~team1'},
+            team2 = {display_name: 'team 2',
+                     web_link: 'http://launchpad.net/~team2'},
+            mock_category = {
+            count: 2,
+            personal: [],
+            as_team_admin: [{ principal: team1 },
+                            { principal: team2 },
+                            { principal: team2 },],
+            as_team_member: []
+            },
+            subs = module._gather_subscriptions_as_assignee(mock_category);
+        Y.Assert.areEqual(1, subs.length);
+        // And there is a 'teams' variable containing all the team objects.
+        var teams_found = [];
+        for (var index in subs[0].vars.teams) {
+            teams_found.push(subs[0].vars.teams[index].title);
+        }
+        Y.ArrayAssert.itemsAreEqual(['team 1', 'team 2'], teams_found);
     },
 
     test_combined: function() {
@@ -259,6 +321,7 @@
         Y.Assert.areEqual(1, subs.length);
         Y.Assert.areEqual(module._reasons.YOU_OWNER, subs[0].reason);
         Y.Assert.areEqual('project', subs[0].vars.pillar);
+        Y.Assert.areEqual(module._actions.SET_BUG_SUPERVISOR, subs[0].action);
     },
 
     test_personal_multiple: function() {
@@ -291,6 +354,7 @@
         // And there is a 'team' variable containing the team object.
         Y.Assert.areEqual('my team', subs[0].vars.team);
         Y.Assert.areEqual('project', subs[0].vars.pillar);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
     },
 
     test_team_member_multiple: function() {
@@ -327,6 +391,7 @@
         // And there is a 'team' variable containing the team object.
         Y.Assert.areEqual('my team', subs[0].vars.team);
         Y.Assert.areEqual('project', subs[0].vars.pillar);
+        Y.Assert.areEqual(module._actions.SET_BUG_SUPERVISOR, subs[0].action);
     },
 
     test_team_admin_multiple: function() {
@@ -415,6 +480,8 @@
         Y.Assert.areEqual(
             module._reasons.YOU_SUBSCRIBED_TO_DUPLICATE, subs[0].reason);
         Y.Assert.areEqual('dupe bug', subs[0].vars.duplicate_bug);
+        Y.Assert.areEqual(module._actions.UNSUBSCRIBE_DUPLICATES,
+                          subs[0].action);
     },
 
     test_personal_multiple: function() {
@@ -433,6 +500,8 @@
             module._reasons.YOU_SUBSCRIBED_TO_DUPLICATES, subs[0].reason);
         Y.ArrayAssert.itemsAreEqual(
             ['dupe1', 'dupe2'], subs[0].vars.duplicate_bugs);
+        Y.Assert.areEqual(module._actions.UNSUBSCRIBE_DUPLICATES,
+                          subs[0].action);
     },
 
     test_team_member: function() {
@@ -453,6 +522,7 @@
         Y.Assert.areEqual('my team', subs[0].vars.team);
         // And a 'duplicate_bug' variable pointing to the dupe.
         Y.Assert.areEqual('dupe', subs[0].vars.duplicate_bug);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
     },
 
     test_team_member_multiple_bugs: function() {
@@ -480,6 +550,7 @@
         // And a 'duplicate_bugs' variable with the list of dupes.
         Y.ArrayAssert.itemsAreEqual(
             ['dupe1', 'dupe2'], subs[0].vars.duplicate_bugs);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
     },
 
     test_team_member_multiple: function() {
@@ -520,6 +591,8 @@
         Y.Assert.areEqual('my team', subs[0].vars.team);
         // And a 'duplicate_bug' variable pointing to the dupe.
         Y.Assert.areEqual('dupe', subs[0].vars.duplicate_bug);
+        Y.Assert.areEqual(module._actions.UNSUBSCRIBE_DUPLICATES,
+                          subs[0].action);
     },
 
     test_team_admin_multiple_bugs: function() {
@@ -548,6 +621,8 @@
         // And a 'duplicate_bugs' variable with the list of dupes.
         Y.ArrayAssert.itemsAreEqual(
             ['dupe1', 'dupe2'], subs[0].vars.duplicate_bugs);
+        Y.Assert.areEqual(module._actions.UNSUBSCRIBE_DUPLICATES,
+                          subs[0].action);
     },
 
     test_team_admin_multiple: function() {
@@ -639,6 +714,7 @@
         Y.Assert.areEqual(module._reasons.TEAM_SUBSCRIBED, subs[0].reason);
         // And there is a 'team' variable containing the team object.
         Y.Assert.areEqual('my team', subs[0].vars.team);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
     },
 
     test_team_member_multiple: function() {
@@ -656,6 +732,35 @@
         // And there is a 'teams' variable containing all the team objects.
         Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
                                     subs[0].vars.teams);
+        Y.Assert.areEqual(module._actions.NONE, subs[0].action);
+    },
+
+    test_team_member_multiple_duplicate: function() {
+        // As with the previous test, but we need to show that each team is
+        // only represented once even if they are responsible for multiple
+        // bug tasks.
+        // We test with full-fledged objects to make sure they work with the
+        // mechanism used to find dupes.
+        var team1 = {display_name: 'team 1',
+                     web_link: 'http://launchpad.net/~team1'},
+            team2 = {display_name: 'team 2',
+                     web_link: 'http://launchpad.net/~team2'},
+            mock_category = {
+            count: 2,
+            personal: [],
+            as_team_member: [{ principal: team1 },
+                             { principal: team2 },
+                             { principal: team2 },],
+            as_team_admin: []
+            },
+            subs = module._gather_subscriptions_through_team(mock_category);
+        Y.Assert.areEqual(1, subs.length);
+        // And there is a 'teams' variable containing all the team objects.
+        var teams_found = [];
+        for (var index in subs[0].vars.teams) {
+            teams_found.push(subs[0].vars.teams[index].title);
+        }
+        Y.ArrayAssert.itemsAreEqual(['team 1', 'team 2'], teams_found);
     },
 
     test_team_admin: function() {
@@ -672,6 +777,8 @@
             module._reasons.ADMIN_TEAM_SUBSCRIBED, subs[0].reason);
         // And there is a 'team' variable containing the team object.
         Y.Assert.areEqual('my team', subs[0].vars.team);
+        Y.Assert.areEqual(module._actions.CHANGE_TEAM_SUBSCRIPTIONS,
+                          subs[0].action);
     },
 
     test_team_admin_multiple: function() {
@@ -690,6 +797,36 @@
         // And there is a 'teams' variable containing all the team objects.
         Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
                                     subs[0].vars.teams);
+        Y.Assert.areEqual(module._actions.CHANGE_TEAM_SUBSCRIPTIONS,
+                          subs[0].action);
+    },
+
+    test_team_admin_multiple_duplicate: function() {
+        // As with the previous test, but we need to show that each team is
+        // only represented once even if they are responsible for multiple
+        // bug tasks.
+        // We test with full-fledged objects to make sure they work with the
+        // mechanism used to find dupes.
+        var team1 = {display_name: 'team 1',
+                     web_link: 'http://launchpad.net/~team1'},
+            team2 = {display_name: 'team 2',
+                     web_link: 'http://launchpad.net/~team2'},
+            mock_category = {
+            count: 2,
+            personal: [],
+            as_team_admin: [{ principal: team1 },
+                            { principal: team2 },
+                            { principal: team2 },],
+            as_team_member: []
+            },
+            subs = module._gather_subscriptions_through_team(mock_category);
+        Y.Assert.areEqual(1, subs.length);
+        // And there is a 'teams' variable containing all the team objects.
+        var teams_found = [];
+        for (var index in subs[0].vars.teams) {
+            teams_found.push(subs[0].vars.teams[index].title);
+        }
+        Y.ArrayAssert.itemsAreEqual(['team 1', 'team 2'], teams_found);
     },
 
     test_combined: function() {