From 1a3b0edf4bfbc953975eb66eb9af474f1be118f3 Mon Sep 17 00:00:00 2001 From: Lauryn Menard Date: Tue, 20 Dec 2022 16:52:25 +0100 Subject: [PATCH] account-settings: Disable deactivate account button when only owner. Disables the deactivate account button in the user's account and privacy settings tab if they are the only active organization owner. Adds a tooltip when hovering on the deactivated button to let the user know why the button is disabled. The backend already returns an error for self account deactivation requests if the user is the only organization owner. --- frontend_tests/node_tests/dispatch.js | 1 + frontend_tests/node_tests/people.js | 14 ++++++++++++++ static/js/people.js | 17 +++++++++++++++++ static/js/server_events_dispatch.js | 3 +++ static/js/settings.js | 1 + static/js/settings_account.js | 17 +++++++++++++++++ static/js/tippyjs.js | 12 ++++++++++++ static/styles/settings.css | 12 ++++++++++++ static/templates/settings/account_settings.hbs | 9 ++++++--- 9 files changed, 83 insertions(+), 3 deletions(-) diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js index f84b42e56e..d3493a4f46 100644 --- a/frontend_tests/node_tests/dispatch.js +++ b/frontend_tests/node_tests/dispatch.js @@ -642,6 +642,7 @@ run_test("realm_domains", ({override}) => { }); run_test("realm_user", ({override}) => { + override(settings_account, "maybe_update_deactivate_account_button", noop); let event = event_fixtures.realm_user__add; dispatch({...event}); const added_person = people.get_by_user_id(event.person.user_id); diff --git a/frontend_tests/node_tests/people.js b/frontend_tests/node_tests/people.js index 53c8fcd0b6..1ddf7d4fa3 100644 --- a/frontend_tests/node_tests/people.js +++ b/frontend_tests/node_tests/people.js @@ -590,6 +590,20 @@ test_people("set_custom_profile_field_data", () => { assert.equal(person.profile_data[field.id].rendered_value, "

Field value

"); }); +test_people("is_current_user_only_owner", () => { + const person = people.get_by_email(me.email); + person.is_owner = false; + page_params.is_owner = false; + assert.ok(!people.is_current_user_only_owner()); + + person.is_owner = true; + page_params.is_owner = true; + assert.ok(people.is_current_user_only_owner()); + + people.add_active_user(realm_owner); + assert.ok(!people.is_current_user_only_owner()); +}); + test_people("recipient_counts", () => { const user_id = 99; assert.equal(people.get_recipient_count({user_id}), 0); diff --git a/static/js/people.js b/static/js/people.js index 1bd8ee9c0a..787a54fa94 100644 --- a/static/js/people.js +++ b/static/js/people.js @@ -825,6 +825,23 @@ export function is_active_user_for_popover(user_id) { return false; } +export function is_current_user_only_owner() { + if (!page_params.is_owner || page_params.is_bot) { + return false; + } + + let active_owners = 0; + for (const person of active_user_dict.values()) { + if (person.is_owner && !person.is_bot) { + active_owners += 1; + } + if (active_owners > 1) { + return false; + } + } + return true; +} + export function filter_all_persons(pred) { const ret = []; for (const person of people_by_user_id_dict.values()) { diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js index 8125120355..91439118bc 100644 --- a/static/js/server_events_dispatch.js +++ b/static/js/server_events_dispatch.js @@ -429,15 +429,18 @@ export function dispatch_normal_event(event) { switch (event.op) { case "add": people.add_active_user(event.person); + settings_account.maybe_update_deactivate_account_button(); break; case "remove": people.deactivate(event.person); stream_events.remove_deactivated_user_from_all_streams(event.person.user_id); settings_users.update_view_on_deactivate(event.person.user_id); buddy_list.maybe_remove_key({key: event.person.user_id}); + settings_account.maybe_update_deactivate_account_button(); break; case "update": user_events.update_person(event.person); + settings_account.maybe_update_deactivate_account_button(); break; default: blueslip.error("Unexpected event type realm_user/" + event.op); diff --git a/static/js/settings.js b/static/js/settings.js index 8951c6750b..8b3c17c735 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -106,6 +106,7 @@ export function build_page() { send_read_receipts_tooltip: $t({ defaultMessage: "Read receipts are currently disabled in this organization.", }), + user_is_only_organization_owner: people.is_current_user_only_owner(), }); $(".settings-box").html(rendered_settings_tab); diff --git a/static/js/settings_account.js b/static/js/settings_account.js index 852aa0b5f0..9f8bafd800 100644 --- a/static/js/settings_account.js +++ b/static/js/settings_account.js @@ -135,6 +135,23 @@ export function update_account_settings_display() { update_avatar_change_display(); } +export function maybe_update_deactivate_account_button() { + if (!page_params.is_owner) { + return; + } + + const $deactivate_account_container = $("#deactivate_account_container"); + if ($deactivate_account_container) { + if (people.is_current_user_only_owner()) { + $("#user_deactivate_account_button").prop("disabled", true); + $deactivate_account_container.addClass("only_organization_owner_tooltip"); + } else { + $("#user_deactivate_account_button").prop("disabled", false); + $deactivate_account_container.removeClass("only_organization_owner_tooltip"); + } + } +} + export function update_send_read_receipts_tooltip() { if (page_params.realm_enable_read_receipts) { $("#send_read_receipts_label .settings-info-icon").hide(); diff --git a/static/js/tippyjs.js b/static/js/tippyjs.js index fcf9b4f8ec..0b4a36a587 100644 --- a/static/js/tippyjs.js +++ b/static/js/tippyjs.js @@ -407,6 +407,18 @@ export function initialize() { }, }); + delegate("body", { + target: ["#deactivate_account_container.only_organization_owner_tooltip"], + content: $t({ + defaultMessage: + "Because you are the only organization owner, you cannot deactivate your account.", + }), + appendTo: () => document.body, + onHidden(instance) { + instance.destroy(); + }, + }); + delegate("body", { target: "#pm_tooltip_container", onShow(instance) { diff --git a/static/styles/settings.css b/static/styles/settings.css index 7fa638fded..c1ce87b82d 100644 --- a/static/styles/settings.css +++ b/static/styles/settings.css @@ -183,6 +183,18 @@ h3, } } +#deactivate_account_container { + &.only_organization_owner_tooltip { + cursor: not-allowed; + } +} + +#user_deactivate_account_button { + &:disabled { + pointer-events: none; + } +} + .admin-realm-description { height: 16em; width: 100%; diff --git a/static/templates/settings/account_settings.hbs b/static/templates/settings/account_settings.hbs index 6616c2e6c6..9ca0596cb8 100644 --- a/static/templates/settings/account_settings.hbs +++ b/static/templates/settings/account_settings.hbs @@ -36,9 +36,12 @@
- +
+ +