← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wallyworld/launchpad/refactor-bugs-subscriber-javascript into lp:launchpad

 

Ian Booth has proposed merging lp:~wallyworld/launchpad/refactor-bugs-subscriber-javascript into lp:launchpad with lp:~wallyworld/launchpad/blueprint-subscriptions-tales-refactor as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/refactor-bugs-subscriber-javascript/+merge/63954

This is branch #3 of a series of branches to add an ajax implementation for subscribing/unsubscribing to/from blueprints. The work is needed to fix bug 50875 - allow a team to be unsubscribed from a blueprint.

== Implementation ==

Move the javascript source files subscriber.js and subscribers_list.js and their associated tests from lp.bugs.javascript to lp.app.javascript. Perform a few simple refactorings to remove some bug specific functionality.

The code will be reused by the blueprints subscription work in a subsequent branch.

== Tests ==

Run the existing yui tests:
lp/app/javascript/tests/test_subscription.html
lp/app/javascript/tests/test_subscriptions_list.html
lp/bugs/javascript/tests/test_me_too.html
lp/bugs/javascript/tests/test_subscription.html


-- 
https://code.launchpad.net/~wallyworld/launchpad/refactor-bugs-subscriber-javascript/+merge/63954
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/refactor-bugs-subscriber-javascript into lp:launchpad.
=== renamed file 'lib/lp/bugs/javascript/subscriber.js' => 'lib/lp/app/javascript/subscriber.js'
--- lib/lp/bugs/javascript/subscriber.js	2011-05-18 21:36:46 +0000
+++ lib/lp/app/javascript/subscriber.js	2011-06-09 04:24:43 +0000
@@ -6,9 +6,9 @@
  * @submodule subscriber
  */
 
-YUI.add('lp.bugs.subscriber', function(Y) {
+YUI.add('lp.app.subscriber', function(Y) {
 
-var namespace = Y.namespace('lp.bugs.subscriber');
+var namespace = Y.namespace('lp.app.subscriber');
 namespace.subscription_labels = {
     'EDIT': 'Edit subscription',
     'SUBSCRIBE': 'Subscribe',
@@ -60,7 +60,7 @@
         value: null
     },
 
-    'bug_notification_level': {
+    'notification_level': {
         value: 'Discussion'
     }
 };

=== renamed file 'lib/lp/bugs/javascript/subscribers_list.js' => 'lib/lp/app/javascript/subscribers_list.js'
--- lib/lp/bugs/javascript/subscribers_list.js	2011-05-18 18:37:07 +0000
+++ lib/lp/app/javascript/subscribers_list.js	2011-06-09 04:24:43 +0000
@@ -7,9 +7,9 @@
  * @submodule subscribers_list
  */
 
-YUI.add('lp.bugs.subscribers_list', function(Y) {
+YUI.add('lp.app.subscribers_list', function(Y) {
 
-var namespace = Y.namespace('lp.bugs.subscribers_list');
+var namespace = Y.namespace('lp.app.subscribers_list');
 
 /**
  * Reset the subscribers list if needed.
@@ -47,17 +47,13 @@
  *
  * @method remove_user_link
  * @param subscriber {Subscriber} Subscriber that you want to remove.
- * @param is_dupe {Boolean} Uses subscription link from the duplicates
- *     instead.
+ * @param id_prefix {String} A prefix to use when constructing the node id.
  */
-function remove_user_link(subscriber, is_dupe) {
-    var user_node_id;
+function remove_user_link(subscriber, id_prefix) {
     var user_name = subscriber.get('css_name');
-    if (is_dupe === true) {
-        user_node_id = '#dupe-' + user_name;
-    } else {
-        user_node_id = '#direct-' + user_name;
-    }
+    if (id_prefix == undefined)
+        id_prefix = '';
+    var user_node_id = '#' + id_prefix + user_name;
     var user_node = Y.one(user_node_id);
     if (Y.Lang.isValue(user_node)) {
         // If there's an icon, we remove it prior to animation

=== renamed file 'lib/lp/bugs/javascript/tests/test_subscriber.html' => 'lib/lp/app/javascript/tests/test_subscriber.html'
--- lib/lp/bugs/javascript/tests/test_subscriber.html	2011-02-28 00:54:30 +0000
+++ lib/lp/app/javascript/tests/test_subscriber.html	2011-06-09 04:24:43 +0000
@@ -17,7 +17,7 @@
       href="../../../../canonical/launchpad/javascript/test.css" />
 
     <script type="text/javascript"
-      src="../../../app/javascript/client.js"></script>
+      src="../client.js"></script>
 
     <!-- The module under test -->
     <script type="text/javascript"

=== renamed file 'lib/lp/bugs/javascript/tests/test_subscriber.js' => 'lib/lp/app/javascript/tests/test_subscriber.js'
--- lib/lp/bugs/javascript/tests/test_subscriber.js	2011-04-22 16:59:16 +0000
+++ lib/lp/app/javascript/tests/test_subscriber.js	2011-06-09 04:24:43 +0000
@@ -1,9 +1,9 @@
 YUI({
     base: '../../../../canonical/launchpad/icing/yui/',
     filter: 'raw', combine: false, fetchCSS: false
-    }).use('test', 'console', 'lp.bugs.subscriber', function(Y) {
+    }).use('test', 'console', 'lp.app.subscriber', function(Y) {
 
-var suite = new Y.Test.Suite("lp.bugs.subscriber Tests");
+var suite = new Y.Test.Suite("lp.app.subscriber Tests");
 
 /*
  * Test that all the parts of the user name
@@ -16,7 +16,7 @@
         this.config = {
             uri: '/~deryck'
         };
-        this.subscriber = new Y.lp.bugs.subscriber.Subscriber(this.config);
+        this.subscriber = new Y.lp.app.subscriber.Subscriber(this.config);
     },
 
     tearDown: function() {
@@ -63,7 +63,7 @@
             uri: '/~foo+bar',
             subscriber_ids: {'foo+bar': 'subscriber-16'}
         };
-        this.subscriber = new Y.lp.bugs.subscriber.Subscriber(this.config);
+        this.subscriber = new Y.lp.app.subscriber.Subscriber(this.config);
     },
 
     tearDown: function() {
@@ -104,7 +104,7 @@
             uri: '/~tester',
             user_node: node
         };
-        this.subscriber = new Y.lp.bugs.subscriber.Subscriber(this.config);
+        this.subscriber = new Y.lp.app.subscriber.Subscriber(this.config);
     },
 
     tearDown: function() {
@@ -131,7 +131,7 @@
         this.config = {
             uri: '/~tester'
         };
-        this.subscriber = new Y.lp.bugs.subscriber.Subscriber(this.config);
+        this.subscriber = new Y.lp.app.subscriber.Subscriber(this.config);
     },
 
     tearDown: function() {
@@ -153,7 +153,7 @@
 function APIStubSubscriber(config) {
     APIStubSubscriber.superclass.constructor.apply(this, arguments);
 }
-Y.extend(APIStubSubscriber, Y.lp.bugs.subscriber.Subscriber, {
+Y.extend(APIStubSubscriber, Y.lp.app.subscriber.Subscriber, {
     get_display_name_from_api: function(client) {
         this.set('display_name', 'From API');
         this.set_truncated_display_name();
@@ -213,7 +213,7 @@
             is_direct: true,
             is_team: true
         };
-        this.subscription = new Y.lp.bugs.subscriber.Subscription(
+        this.subscription = new Y.lp.app.subscriber.Subscription(
             this.config);
     },
 
@@ -253,7 +253,7 @@
     },
 
     test_already_subscribed: function() {
-        var person = new Y.lp.bugs.subscriber.Subscriber({uri: '/~tester'});
+        var person = new Y.lp.app.subscriber.Subscriber({uri: '/~tester'});
         this.subscription.set('person', person);
         Y.Assert.isTrue(
             this.subscription.is_already_subscribed(),
@@ -261,7 +261,7 @@
     },
 
     test_is_current_user_subscribing: function() {
-        var person = new Y.lp.bugs.subscriber.Subscriber({uri: '/~tester'});
+        var person = new Y.lp.app.subscriber.Subscriber({uri: '/~tester'});
         this.subscription.set('person', person);
         var subscriber = this.subscription.get('person');
         this.subscription.set('subscriber', subscriber);

=== renamed file 'lib/lp/bugs/javascript/tests/test_subscribers_list.html' => 'lib/lp/app/javascript/tests/test_subscribers_list.html'
--- lib/lp/bugs/javascript/tests/test_subscribers_list.html	2011-04-28 13:32:29 +0000
+++ lib/lp/app/javascript/tests/test_subscribers_list.html	2011-06-09 04:24:43 +0000
@@ -17,9 +17,9 @@
       href="../../../../canonical/launchpad/javascript/test.css" />
 
     <script type="text/javascript"
-      src="../../../app/javascript/client.js"></script>
+      src="../client.js"></script>
     <script type="text/javascript"
-      src="../../../app/javascript/errors.js"></script>
+      src="../errors.js"></script>
 
     <!-- Pre-requisite -->
     <script type="text/javascript"

=== renamed file 'lib/lp/bugs/javascript/tests/test_subscribers_list.js' => 'lib/lp/app/javascript/tests/test_subscribers_list.js'
--- lib/lp/bugs/javascript/tests/test_subscribers_list.js	2011-05-18 18:34:19 +0000
+++ lib/lp/app/javascript/tests/test_subscribers_list.js	2011-06-09 04:24:43 +0000
@@ -1,12 +1,12 @@
 YUI({
     base: '../../../../canonical/launchpad/icing/yui/',
     filter: 'raw', combine: false, fetchCSS: false
-    }).use('test', 'console', 'lp.bugs.subscriber',
-           'lp.bugs.subscribers_list', 'node-event-simulate',
+    }).use('test', 'console', 'lp.app.subscriber',
+           'lp.app.subscribers_list', 'node-event-simulate',
            function(Y) {
 
-var suite = new Y.Test.Suite("lp.bugs.subscribers_list Tests");
-var module = Y.lp.bugs.subscribers_list;
+var suite = new Y.Test.Suite("lp.app.subscribers_list Tests");
+var module = Y.lp.app.subscribers_list;
 
 
 /**
@@ -147,17 +147,17 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
-        var other_person = new Y.lp.bugs.subscriber.Subscriber({
+        var other_person = new Y.lp.app.subscriber.Subscriber({
             uri: 'someone',
             subscriber_ids: this.subscriber_ids
         });
         this.addSubscriber(this.root, other_person);
 
-        module.remove_user_link(person);
+        module.remove_user_link(person, 'direct-');
 
         // `other_person` is not removed.
         Y.Assert.isNotNull(
@@ -171,7 +171,7 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
@@ -182,7 +182,7 @@
             .appendChild('<img></img>')
             .set('id', 'unsubscribe-icon-' + css_name);
 
-        module.remove_user_link(person);
+        module.remove_user_link(person, 'direct-');
 
         // Unsubscribe icon is removed immediatelly.
         Y.Assert.isNull(this.root.one('#unsubscribe-icon-' + css_name));
@@ -194,13 +194,13 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
         this.addSubscriber(this.root, person);
 
-        module.remove_user_link(person);
+        module.remove_user_link(person, 'direct-');
 
         this.wait(function() {
             // There is no subscriber link anymore.
@@ -217,13 +217,13 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
         this.addSubscriber(this.root, person);
 
-        module.remove_user_link(person, true);
+        module.remove_user_link(person, 'dupe-');
 
         this.wait(function() {
             // There is no subscriber link anymore.
@@ -237,13 +237,13 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root, true);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
         this.addSubscriber(this.root, person, true);
 
-        module.remove_user_link(person, true);
+        module.remove_user_link(person, 'dupe-');
 
         this.wait(function() {
             // There is no subscriber link anymore.
@@ -260,13 +260,13 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root, true);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
         this.addSubscriber(this.root, person, true);
 
-        module.remove_user_link(person);
+        module.remove_user_link(person, 'direct-');
 
         this.wait(function() {
             // There is no subscriber link anymore.
@@ -281,7 +281,7 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root, true);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
@@ -289,7 +289,7 @@
         this.addSubscriber(this.root, person, true);
 
         // Remove the duplicate subscription link.
-        module.remove_user_link(person, true);
+        module.remove_user_link(person, 'dupe-');
 
         this.wait(function() {
             // Remaining entry is the direct subscription one.
@@ -307,7 +307,7 @@
         // Set-up subscribers list.
         setUpSubscribersList(this.root, true);
 
-        var person = new Y.lp.bugs.subscriber.Subscriber({
+        var person = new Y.lp.app.subscriber.Subscriber({
             uri: 'myself',
             subscriber_ids: this.subscriber_ids
         });
@@ -315,7 +315,7 @@
         this.addSubscriber(this.root, person, true);
 
         // Remove the direct subscription link.
-        module.remove_user_link(person);
+        module.remove_user_link(person, 'direct-');
 
         this.wait(function() {
             // Remaining entry is the duplicate subscription one.

=== modified file 'lib/lp/bugs/javascript/bugtask_index.js'
--- lib/lp/bugs/javascript/bugtask_index.js	2011-05-12 02:09:42 +0000
+++ lib/lp/bugs/javascript/bugtask_index.js	2011-06-09 04:24:43 +0000
@@ -1116,4 +1116,4 @@
                         "lazr.overlay", "lazr.choiceedit", "lp.app.picker",
                         "lp.client", "escape",
                         "lp.client.plugins", "lp.bugs.bugtask_index.portlets",
-                        "lp.bugs.subscriber", "lp.app.errors"]});
+                        "lp.app.subscriber", "lp.app.errors"]});

=== modified file 'lib/lp/bugs/javascript/bugtask_index_portlets.js'
--- lib/lp/bugs/javascript/bugtask_index_portlets.js	2011-06-03 21:16:03 +0000
+++ lib/lp/bugs/javascript/bugtask_index_portlets.js	2011-06-09 04:24:43 +0000
@@ -24,15 +24,19 @@
 // used or not.
 var use_advanced_subscriptions = false;
 
-var subscription_labels = Y.lp.bugs.subscriber.subscription_labels;
+var subscription_labels = Y.lp.app.subscriber.subscription_labels;
 
-submit_button_html =
+var submit_button_html =
     '<button type="submit" name="field.actions.change" ' +
     'value="Change" class="lazr-pos lazr-btn" >OK</button>';
-cancel_button_html =
+var cancel_button_html =
     '<button type="button" name="field.actions.cancel" ' +
     'class="lazr-neg lazr-btn" >Cancel</button>';
 
+// Prefixes to qualify the subscription nodes.
+var direct_node_prefix = 'direct-';
+var dupe_node_prefix = 'dupe-';
+
 // The set of subscriber CSS IDs as a JSON struct.
 var subscriber_ids;
 
@@ -225,13 +229,13 @@
  * Set click handlers for unsubscribe remove icons.
  *
  * @method setup_unsubscribe_icon_handlers
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  */
 function setup_unsubscribe_icon_handlers() {
-    var subscription = new Y.lp.bugs.subscriber.Subscription({
+    var subscription = new Y.lp.app.subscriber.Subscription({
         link: Y.one('.menu-link-subscription'),
         spinner: Y.one('#sub-unsub-spinner'),
-        subscriber: new Y.lp.bugs.subscriber.Subscriber({
+        subscriber: new Y.lp.app.subscriber.Subscriber({
             uri: LP.links.me,
             subscriber_ids: subscriber_ids
         })
@@ -243,6 +247,37 @@
     }, '.unsub-icon');
 }
 
+<<<<<<< TREE
+=======
+/*
+ * Set up and return a Subscription object for the mute link.
+ * @method get_mute_subscription
+ */
+function get_mute_subscription() {
+    setup_client_and_bug();
+    var mute_link = Y.one('.menu-link-mute_subscription');
+    if (Y.Lang.isNull(mute_link)) {
+        return null;
+    }
+    var mute_subscription = new Y.lp.app.subscriber.Subscription({
+        link: mute_link,
+        spinner: Y.one('#mute-unmute-spinner'),
+        subscriber: new Y.lp.app.subscriber.Subscriber({
+            uri: LP.links.me,
+            subscriber_ids: subscriber_ids
+        })
+    });
+    var parent_node = mute_link.get('parentNode');
+    mute_subscription.set(
+        'is_subscribed', !parent_node.hasClass('subscribed-false'));
+    mute_subscription.set(
+        'is_muted', parent_node.hasClass('muted-true'));
+    mute_subscription.set(
+        'person', mute_subscription.get('subscriber'));
+    return mute_subscription;
+}
+
+>>>>>>> MERGE-SOURCE
 
 /**
  * We can have at most one advanced subscription overlay shown,
@@ -388,6 +423,7 @@
         is_muted = parent_node.hasClass('muted-true');
     }
     parent_node.removeClass('hidden');
+<<<<<<< TREE
     if (is_muted) {
         parent_node.replaceClass('muted-false', 'muted-true');
         link.set('innerHTML', "Unmute bug mail");
@@ -396,6 +432,47 @@
         parent_node.replaceClass('muted-true', 'muted-false');
         link.set('innerHTML', "Mute bug mail");
         link.replaceClass('unmute', 'mute');
+=======
+    if (mute_subscription.get('is_muted')) {
+        parent_node.removeClass('muted-false');
+        parent_node.addClass('muted-true');
+        mute_link.setAttribute(
+            'href', mute_link.getAttribute('href').replace(
+                /\+mute$/, '+subscribe'));
+        mute_subscription.disable_spinner("Unmute bug mail");
+    } else {
+        parent_node.removeClass('muted-true');
+        parent_node.addClass('muted-false');
+        mute_link.setAttribute(
+            'href', mute_link.getAttribute('href').replace(
+                /\+subscribe$/, '+mute'));
+        mute_subscription.disable_spinner("Mute bug mail");
+    }
+}
+
+/*
+ * Update the subscription links after the mute button has been clicked.
+ *
+ * @param mute_subscription {Object} A Y.lp.app.subscriber.Subscription
+ *                                   object.
+ */
+function update_subscription_after_mute_or_unmute(mute_subscription) {
+    var subscription = get_subscribe_self_subscription();
+    var subscription_link = subscription.get('link');
+
+    subscription.enable_spinner('Updating...');
+    if (mute_subscription.get('is_muted')) {
+        subscription.disable_spinner(subscription_labels.SUBSCRIBE);
+        if (subscription.has_duplicate_subscriptions()) {
+            set_subscription_link_parent_class(
+                subscription_link, false, true);
+        } else {
+            set_subscription_link_parent_class(
+                subscription_link, false, false);
+        }
+    } else {
+        subscription.disable_spinner(subscription_labels.SUBSCRIBE);
+>>>>>>> MERGE-SOURCE
     }
 }
 
@@ -405,10 +482,10 @@
  */
 function get_subscribe_self_subscription() {
     setup_client_and_bug();
-    var subscription = new Y.lp.bugs.subscriber.Subscription({
+    var subscription = new Y.lp.app.subscriber.Subscription({
         link: Y.one('.menu-link-subscription'),
         spinner: Y.one('#sub-unsub-spinner'),
-        subscriber: new Y.lp.bugs.subscriber.Subscriber({
+        subscriber: new Y.lp.app.subscriber.Subscriber({
             uri: LP.links.me,
             subscriber_ids: subscriber_ids
         })
@@ -436,10 +513,10 @@
  */
 function get_team_subscription(team_uri) {
     setup_client_and_bug();
-    var subscription = new Y.lp.bugs.subscriber.Subscription({
+    var subscription = new Y.lp.app.subscriber.Subscription({
         link: Y.one('.menu-link-subscription'),
         spinner: Y.one('#sub-unsub-spinner'),
-        subscriber: new Y.lp.bugs.subscriber.Subscriber({
+        subscriber: new Y.lp.app.subscriber.Subscriber({
             uri: team_uri,
             subscriber_ids: subscriber_ids
         })
@@ -593,14 +670,14 @@
  *
  * @method unsubscribe_user_via_icon
  * @param icon {Node} The remove icon that was clicked.
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
 */
 function unsubscribe_user_via_icon(icon, subscription) {
     icon.set('src', '/@@/spinner');
     var icon_parent = icon.get('parentNode');
 
     var user_uri = get_user_uri_from_icon(icon);
-    var person = new Y.lp.bugs.subscriber.Subscriber({
+    var person = new Y.lp.app.subscriber.Subscriber({
         uri: user_uri,
         subscriber_ids: subscriber_ids
     });
@@ -640,7 +717,8 @@
             success: function(client) {
                 var num_person_links = Y.all(
                     '.' + person.get('css_name')).size();
-                Y.lp.bugs.subscribers_list.remove_user_link(person, is_dupe);
+                var prefix = is_dupe?dupe_node_prefix:direct_node_prefix;
+                Y.lp.app.subscribers_list.remove_user_link(person, prefix);
                 var has_direct, has_dupes;
                 if (num_person_links === 1 &&
                     subscription.is_current_user_subscribing()) {
@@ -684,7 +762,7 @@
  * interactions.
  *
  * @method setup_advanced_subscription_overlay
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  */
 function setup_advanced_subscription_overlay(subscription, text) {
     var header = Y.Node.create('<h2 />').set('text', text);
@@ -707,7 +785,7 @@
  * loaded. That way the overlay won't appear empty.
  *
  * @method load_and_show_advanced_subscription_overlay
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  * @param subscription_overlay {Object} A Y.lazr.FormOverlay to load
  *                                      content into.
  */
@@ -740,13 +818,13 @@
  * Subscribe the current user via the LP API.
  *
  * @method subscribe_current_user
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  */
 function subscribe_current_user(subscription) {
     subscription.enable_spinner('Subscribing...');
     var subscription_link = subscription.get('link');
     var subscriber = subscription.get('subscriber');
-    var bug_notification_level = subscription.get('bug_notification_level');
+    var bug_notification_level = subscription.get('notification_level');
 
     // This is always a direct subscription.
     subscription.set('is_direct', true);
@@ -809,7 +887,7 @@
  * Unsubscribe the current user via the LP API.
  *
  * @method unsubscribe_current_user
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  */
 function unsubscribe_current_user(subscription) {
     subscription.enable_spinner('Unsubscribing...');
@@ -859,8 +937,9 @@
                 }
 
                 var is_dupe = !original_is_direct;
-                Y.lp.bugs.subscribers_list.remove_user_link(
-                    subscriber, is_dupe);
+                var prefix = is_dupe?dupe_node_prefix:direct_node_prefix;
+                Y.lp.app.subscribers_list.remove_user_link(
+                    subscriber, prefix);
             },
 
             failure: error_handler.getFailureHandler()
@@ -897,10 +976,102 @@
 }
 
 /*
+<<<<<<< TREE
+=======
+ * Mute the current user via the LP API.
+ *
+ * @method mute_current_user
+ * @param subscription {Object} A Y.lp.bugs.subscribe.Subscription object.
+ */
+function mute_current_user(subscription) {
+    subscription.enable_spinner('Muting...');
+    var subscription_link = subscription.get('link');
+    var subscriber = subscription.get('subscriber');
+
+    var error_handler = new Y.lp.client.ErrorHandler();
+    error_handler.clearProgressUI = function () {
+        subscription.disable_spinner();
+    };
+    error_handler.showError = function (error_msg) {
+        Y.lp.app.errors.display_error(subscription_link, error_msg);
+    };
+
+    var config = {
+        on: {
+            success: function(client) {
+                subscription.disable_spinner('Unmute bug mail');
+                var flash_node = subscription_link.get('parentNode');
+                var mute_anim = Y.lazr.anim.green_flash({ node: flash_node });
+                mute_anim.run();
+
+                // Remove the subscriber's name from the subscriber
+                // list, if it's there.
+                Y.lp.app.subscribers_list.remove_user_link(
+                    subscriber, direct_node_prefix);
+                subscription.set('is_muted', true);
+                update_mute_after_subscription_change(subscription);
+                update_subscription_after_mute_or_unmute(subscription);
+            },
+
+            failure: error_handler.getFailureHandler()
+        },
+
+        parameters: {
+            person: Y.lp.client.get_absolute_uri(
+                subscriber.get('escaped_uri'))
+        }
+    };
+    lp_client.named_post(bug_repr.self_link, 'mute', config);
+}
+
+/*
+ * Unmute the current user via the LP API.
+ *
+ * @method unmute_current_user
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
+ */
+function unmute_current_user(subscription) {
+    subscription.enable_spinner('Unmuting...');
+    var subscription_link = subscription.get('link');
+    var subscriber = subscription.get('subscriber');
+
+    var error_handler = new Y.lp.client.ErrorHandler();
+    error_handler.clearProgressUI = function () {
+        subscription.disable_spinner();
+    };
+    error_handler.showError = function (error_msg) {
+        Y.lp.app.errors.display_error(subscription_link, error_msg);
+    };
+
+    var config = {
+        on: {
+            success: function(client) {
+                subscription.disable_spinner('Mute bug mail');
+                var flash_node = subscription_link.get('parentNode');
+                var anim = Y.lazr.anim.green_flash({ node: flash_node });
+                anim.run();
+                subscription.set('is_muted', false);
+                update_mute_after_subscription_change(subscription);
+                update_subscription_after_mute_or_unmute(subscription);
+            },
+
+            failure: error_handler.getFailureHandler()
+        },
+
+        parameters: {
+            person: Y.lp.client.get_absolute_uri(
+                subscriber.get('escaped_uri'))
+        }
+    };
+    lp_client.named_post(bug_repr.self_link, 'unmute', config);
+}
+
+/*
+>>>>>>> MERGE-SOURCE
  * Initialize click handler for the subscribe someone else link.
  *
  * @method setup_subscribe_someone_else_handler
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  */
 function setup_subscribe_someone_else_handler(subscription) {
     var config = {
@@ -919,7 +1090,7 @@
  * Build the HTML for a user link for the subscribers list.
  *
  * @method build_user_link_html
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  * @return html {String} The HTML used for creating a subscriber link.
  */
 function build_user_link_html(subscription) {
@@ -1232,7 +1403,7 @@
         // The user isn't subscribed or muted, and the request is
         // for himself (iow, not for a team).
         subscription.set(
-            'bug_notification_level',
+            'notification_level',
             form_data['field.bug_notification_level']);
         subscribe_current_user(subscription);
     } else if (is_muted && request_for_self) {
@@ -1255,7 +1426,7 @@
  * @result {Object} The object representing a person returned by the API.
  */
 function subscribe_someone_else(result, subscription) {
-    var person = new Y.lp.bugs.subscriber.Subscriber({
+    var person = new Y.lp.app.subscriber.Subscriber({
         uri: result.api_uri,
         display_name: result.title,
         subscriber_ids: subscriber_ids
@@ -1286,7 +1457,7 @@
  * cannot be used.
  *
  * @method check_can_be_unsubscribed
- * @param subscription {Object} A Y.lp.bugs.subscriber.Subscription object.
+ * @param subscription {Object} A Y.lp.app.subscriber.Subscription object.
  */
 function check_can_be_unsubscribed(subscription) {
     var error_handler = new Y.lp.client.ErrorHandler();
@@ -1412,6 +1583,6 @@
                         "lazr.formoverlay", "lazr.anim", "lazr.base",
                         "lazr.overlay", "lazr.choiceedit", "lp.app.picker",
                         "lp.client",
-                        "lp.client.plugins", "lp.bugs.subscriber",
-                        "lp.bugs.subscribers_list",
+                        "lp.client.plugins", "lp.app.subscriber",
+                        "lp.app.subscribers_list",
                         "lp.bugs.bug_notification_level", "lp.app.errors"]});

=== modified file 'lib/lp/bugs/javascript/tests/test_me_too.html'
--- lib/lp/bugs/javascript/tests/test_me_too.html	2011-02-28 00:54:30 +0000
+++ lib/lp/bugs/javascript/tests/test_me_too.html	2011-06-09 04:24:43 +0000
@@ -29,7 +29,7 @@
   </script>
   <script type="text/javascript"
     src="../../../app/javascript/client.js"></script>
-  <script type="text/javascript" src="../subscriber.js"></script>
+  <script type="text/javascript" src="../../../app/javascript/subscriber.js"></script>
 
   <!-- The module under test -->
   <script type="text/javascript" src="../bugtask_index.js"></script>