← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/private-bug-unsubscribe-confirm-2 into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/private-bug-unsubscribe-confirm-2 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #485126 in Launchpad itself: "Accidentally unsubscribing myself from a private bug makes the bug inaccessible"
  https://bugs.launchpad.net/launchpad/+bug/485126

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/private-bug-unsubscribe-confirm-2/+merge/77091

Building on the work started in https://code.launchpad.net/~stevenk/launchpad/private-bug-unsubscribe-confirm/+merge/76326, this branch adds the private bug unsubscribe warning to the edit subscriptions overlay.
-- 
https://code.launchpad.net/~stevenk/launchpad/private-bug-unsubscribe-confirm-2/+merge/77091
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/private-bug-unsubscribe-confirm-2 into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py	2011-09-25 23:43:15 +0000
+++ lib/lp/bugs/browser/bug.py	2011-09-27 04:44:27 +0000
@@ -664,6 +664,7 @@
         LaunchpadView.initialize(self)
         cache = IJSONRequestCache(self.request).objects
         self.extractBugSubscriptionDetails(self.user, self.context, cache)
+        cache['bug_is_private'] = self.context.private
         if self.user:
             cache['notifications_text'] = self.notifications_text
 

=== modified file 'lib/lp/bugs/javascript/bug_subscription_portlet.js'
--- lib/lp/bugs/javascript/bug_subscription_portlet.js	2011-09-21 04:24:04 +0000
+++ lib/lp/bugs/javascript/bug_subscription_portlet.js	2011-09-27 04:44:27 +0000
@@ -200,64 +200,102 @@
         overlay.destroy();
         link.replaceClass('spinner', 'edit');
     };
+    // The on-click handler for make_action nodes.
+    var make_action_on_click = function (
+        e, method_name, css_class, parameters) {
+        var active_link = e.currentTarget;
+        active_link.replaceClass(css_class, 'spinner');
+        var handler = new Y.lp.client.ErrorHandler();
+        handler.showError = function(error_msg) {
+            Y.lp.app.errors.display_error(
+                active_link.get('parentNode'), error_msg);
+        };
+        handler.clearProgressUI = function () {
+            active_link.replaceClass('spinner', css_class);
+        };
+        var config = {
+            on: {
+                success: function(response) {
+                    if (Y.Lang.isValue(response)) {
+                        // This is a subscription.  Update the cache.
+                        LP.cache.subscription = response.getAttrs();
+                    }
+                    if (method_name === 'mute') {
+                        // Special case: update main mute link.
+                        mute_link.replaceClass(
+                            UNMUTED_CLASS, MUTED_CLASS);
+                        mute_link.set('text', 'Unmute bug mail');
+                        Y.lp.anim.green_flash(
+                            { node: mute_link.get('parentNode') }).run();
+                    } else if (method_name === 'unsubscribe') {
+                        // Special case: delete cache.
+                        delete LP.cache.subscription;
+                        if (!LP.cache.other_subscription_notifications) {
+                            // Special case: hide mute link.
+                            mute_div.addClass('hidden');
+                        }
+                    } else if (method_name === 'subscribe') {
+                        // Special case: reveal mute link.
+                        mute_div.removeClass('hidden');
+                    }
+                    active_link.replaceClass('spinner', css_class);
+                    update_subscription_status();
+                    clean_up();
+                },
+                failure: handler.getFailureHandler()
+            },
+            parameters: parameters
+        };
+        lp_client().named_post(
+            LP.cache.context.bug_link, method_name, config);
+    };
     // The make_action function is the workhorse for creating all the
     // JavaScript action links we need. Given the `text` that the link
     // should display, the `class` name to show the appropriate sprite,
     // the `method_name` to call on the server, and the `parameters` to
     // send across, it returns a link node with the click handler properly
     // set.
-    // XXX StevenK 2011-09-26 bug=485126 We should expand the overlay here
-    // and ask for confirmation if it's a private bug.
     var make_action = function(text, css_class, method_name, parameters) {
         result = make_link(text, css_class)
             .addClass('js-action');
         result.on('click', function (e) {
             e.halt();
-            var active_link = e.currentTarget;
-            active_link.replaceClass(css_class, 'spinner');
-            var handler = new Y.lp.client.ErrorHandler();
-            handler.showError = function(error_msg) {
-                Y.lp.app.errors.display_error(
-                    active_link.get('parentNode'), error_msg);
-            };
-            handler.clearProgressUI = function () {
-                active_link.replaceClass('spinner', css_class);
-            };
-            var config = {
-                on: {
-                    success: function(response) {
-                        if (Y.Lang.isValue(response)) {
-                            // This is a subscription.  Update the cache.
-                            LP.cache.subscription = response.getAttrs();
-                        }
-                        if (method_name === 'mute') {
-                            // Special case: update main mute link.
-                            mute_link.replaceClass(
-                                UNMUTED_CLASS, MUTED_CLASS);
-                            mute_link.set('text', 'Unmute bug mail');
-                            Y.lp.anim.green_flash(
-                                { node: mute_link.get('parentNode') }).run();
-                        } else if (method_name === 'unsubscribe') {
-                            // Special case: delete cache.
-                            delete LP.cache.subscription;
-                            if (!LP.cache.other_subscription_notifications) {
-                                // Special case: hide mute link.
-                                mute_div.addClass('hidden');
-                            }
-                        } else if (method_name === 'subscribe') {
-                            // Special case: reveal mute link.
-                            mute_div.removeClass('hidden');
-                        }
-                        active_link.replaceClass('spinner', css_class);
-                        update_subscription_status();
-                        clean_up();
-                    },
-                    failure: handler.getFailureHandler()
-                },
-                parameters: parameters
-            };
-            lp_client().named_post(
-                LP.cache.context.bug_link, method_name, config);
+            var method_call = function() {
+                make_action_on_click(e, method_name, css_class, parameters);
+            };
+            if (method_name === 'unsubscribe') {
+                var private_bug_warning_node = Y.Node.create(
+                    ['<div class="private-bug-warning"><p>You will not ',
+                    'have access to this bug or any of its pages if you ',
+                    'unsubscribe. If you want to stop emails, choose the ',
+                    '"Mute bug mail" option.</p>',
+                    '<p>Do you really want to unsubscribe from this bug?',
+                    '</p><div class="extra-form-buttons">',
+                    '<button class="lazr-pos lazr-btn ok-btn" ',
+                    'type="submit"></button>',
+                    '<button class="lazr-neg lazr-btn cancel-btn" ',
+                    'type="button"></button></div></div>'].join(''));
+                if (
+                    Y.Lang.isBoolean(LP.cache.bug_is_private) &&
+                    LP.cache.bug_is_private) {
+                    var remove_div = Y.one('.remove-direct-subscription');
+                    var ok_btn = private_bug_warning_node.one('.ok-btn');
+                    ok_btn.on('click', function (internal_e) {
+                        e.halt();
+                        method_call();
+                    });
+                    var cancel_btn = private_bug_warning_node.one(
+                        '.cancel-btn');
+                    cancel_btn.on('click', function() {
+                        private_bug_warning_node.remove();
+                    });
+                    remove_div.insert(private_bug_warning_node, 'after');
+                } else {
+                    method_call();
+                }
+            } else {
+                method_call();
+            }
             });
         return result;
     };
@@ -320,6 +358,7 @@
     // has an existing direct subscription.
     var unsubscribe_node = tag('div')
         .setStyle('margin-top', '1.5em')
+        .addClass('remove-direct-subscription')
         .append(make_action(
             'Remove your direct subscription', 'remove',
             'unsubscribe', {})

=== modified file 'lib/lp/bugs/javascript/tests/test_bug_subscription_portlet.js'
--- lib/lp/bugs/javascript/tests/test_bug_subscription_portlet.js	2011-06-21 05:37:38 +0000
+++ lib/lp/bugs/javascript/tests/test_bug_subscription_portlet.js	2011-09-27 04:44:27 +0000
@@ -553,6 +553,9 @@
         this.link().simulate('click');
         var overlay = Y.one('.pretty-overlay-window');
         overlay.one('a.remove').simulate('click');
+        // There is no warning.
+        var warning = overlay.one('.private-bug-warning');
+        Y.Assert.isNull(warning);
         // We got an appropriate call to the webservice.
         Y.Assert.areEqual('named_post', module._lp_client.received[0][0]);
         var args = module._lp_client.received[0][1];
@@ -570,6 +573,46 @@
             this.status_node.get('text'));
     },
 
+    test_unsubscribe_from_private_bug: function() {
+        this.init(LIFECYCLE, false);
+        window.LP.cache.bug_is_private = true;
+        this.link().simulate('click');
+        var overlay = Y.one('.pretty-overlay-window');
+        overlay.one('a.remove').simulate('click');
+        // The overlay now has a warning.
+        var warning = overlay.one('.private-bug-warning');
+        Y.Assert.isTrue(Y.Lang.isValue(warning));
+        // Find and click the OK button.
+        var ok_btn = warning.one('.ok-btn');
+        ok_btn.simulate('click');
+        // We got an appropriate call to the webservice.
+        Y.Assert.areEqual('named_post', module._lp_client.received[0][0]);
+        var args = module._lp_client.received[0][1];
+        Y.Assert.areEqual(this.bug_link, args[0]);
+        Y.Assert.areEqual('unsubscribe', args[1]);
+        Y.ObjectAssert.areEqual({}, args[2].parameters);
+        // The overlay has been destroyed, and the spinner is gone.
+        Y.Assert.isFalse(Y.Lang.isValue(Y.one('.pretty-overlay-window')));
+        Y.Assert.isFalse(this.link().hasClass('spinner'));
+    },
+
+    test_unsubscribe_from_private_bug_cancel: function() {
+        this.init(LIFECYCLE, false);
+        window.LP.cache.bug_is_private = true;
+        this.link().simulate('click');
+        var overlay = Y.one('.pretty-overlay-window');
+        overlay.one('a.remove').simulate('click');
+        // The overlay now has a warning.
+        var warning = overlay.one('.private-bug-warning');
+        Y.Assert.isTrue(Y.Lang.isValue(warning));
+        // Find and click the Cancel button.
+        var cancel_btn = warning.one('.cancel-btn');
+        cancel_btn.simulate('click');
+        // The warning is gone.
+        var warning = overlay.one('.private-bug-warning');
+        Y.Assert.isNull(warning);
+    },
+
     test_unsubscribe_with_other: function() {
         this.init(LIFECYCLE, true);
         this.link().simulate('click');