stream settings: Warn users before locking them out of a stream.

Organization owners can make streams private even if they're not
subscribed to them, but cannot access private streams they're not
subscribed to. This means they're able to lock themself out of streams.

This change warns users of this and give them a chance to subscribe.

Fixes #26437.
This commit is contained in:
evykassirer 2023-08-09 13:30:51 -07:00 committed by Tim Abbott
parent e8b7aad462
commit 4c2995c613
3 changed files with 80 additions and 0 deletions

View File

@ -1,11 +1,13 @@
import $ from "jquery"; import $ from "jquery";
import pygments_data from "../generated/pygments_data.json"; import pygments_data from "../generated/pygments_data.json";
import render_compose_banner from "../templates/compose_banner/compose_banner.hbs";
import render_settings_deactivate_realm_modal from "../templates/confirm_dialog/confirm_deactivate_realm.hbs"; import render_settings_deactivate_realm_modal from "../templates/confirm_dialog/confirm_deactivate_realm.hbs";
import render_settings_admin_auth_methods_list from "../templates/settings/admin_auth_methods_list.hbs"; import render_settings_admin_auth_methods_list from "../templates/settings/admin_auth_methods_list.hbs";
import * as blueslip from "./blueslip"; import * as blueslip from "./blueslip";
import * as channel from "./channel"; import * as channel from "./channel";
import * as compose_banner from "./compose_banner";
import {csrf_token} from "./csrf"; import {csrf_token} from "./csrf";
import * as dialog_widget from "./dialog_widget"; import * as dialog_widget from "./dialog_widget";
import * as dropdown_widget from "./dropdown_widget"; import * as dropdown_widget from "./dropdown_widget";
@ -994,6 +996,19 @@ export function check_property_changed(elem, for_realm_default_settings, sub) {
return current_val !== proposed_val; return current_val !== proposed_val;
} }
function switching_to_private(properties_elements, for_realm_default_settings) {
for (const elem of properties_elements) {
const $elem = $(elem);
const property_name = extract_property_name($elem, for_realm_default_settings);
if (property_name !== "stream_privacy") {
continue;
}
const proposed_val = get_input_element_value($elem, "radio-group");
return proposed_val === "invite-only-public-history" || proposed_val === "invite-only";
}
return false;
}
export function save_discard_widget_status_handler($subsection, for_realm_default_settings, sub) { export function save_discard_widget_status_handler($subsection, for_realm_default_settings, sub) {
$subsection.find(".subsection-failed-status p").hide(); $subsection.find(".subsection-failed-status p").hide();
$subsection.find(".save-button").show(); $subsection.find(".save-button").show();
@ -1005,6 +1020,39 @@ export function save_discard_widget_status_handler($subsection, for_realm_defaul
const $save_btn_controls = $subsection.find(".subsection-header .save-button-controls"); const $save_btn_controls = $subsection.find(".subsection-header .save-button-controls");
const button_state = show_change_process_button ? "unsaved" : "discarded"; const button_state = show_change_process_button ? "unsaved" : "discarded";
change_save_button_state($save_btn_controls, button_state); change_save_button_state($save_btn_controls, button_state);
// If this widget is for a stream, and the stream isn't currently private
// but being changed to private, and the user changing this setting isn't
// subscribed, we show a warning that they won't be able to access the
// stream after making it private unless they subscribe.
if (!sub) {
return;
}
if (
button_state === "unsaved" &&
!sub.invite_only &&
!sub.subscribed &&
switching_to_private(properties_elements, for_realm_default_settings)
) {
if ($("#stream_permission_settings .stream_privacy_warning").length > 0) {
return;
}
const context = {
banner_type: compose_banner.WARNING,
banner_text: $t({
defaultMessage:
"Only subscribers can access or join private streams, so you will lose access to this stream if you convert it to a private stream while not subscribed to it.",
}),
button_text: $t({defaultMessage: "Subscribe"}),
classname: "stream_privacy_warning",
stream_id: sub.stream_id,
};
$("#stream_permission_settings .stream-permissions-warning-banner").append(
render_compose_banner(context),
);
} else {
$("#stream_permission_settings .stream-permissions-warning-banner").empty();
}
} }
export function init_dropdown_widgets() { export function init_dropdown_widgets() {

View File

@ -466,6 +466,36 @@ export function initialize() {
return true; return true;
}); });
$("#streams_overlay_container").on(
"click",
".stream-permissions-warning-banner .main-view-banner-close-button",
(event) => {
event.preventDefault();
$("#stream_permission_settings .stream-permissions-warning-banner").empty();
},
);
$("#streams_overlay_container").on(
"click",
".stream-permissions-warning-banner .main-view-banner-action-button",
(event) => {
event.preventDefault();
event.stopPropagation();
const $target = $(event.target).parents(".main-view-banner");
const stream_id = Number.parseInt($target.attr("data-stream-id"), 10);
// Makes sure we take the correct stream_row.
const $stream_row = $(
`#streams_overlay_container div.stream-row[data-stream-id='${CSS.escape(
stream_id,
)}']`,
);
const sub = sub_store.get(stream_id);
stream_settings_ui.sub_or_unsub(sub, $stream_row);
$("#stream_permission_settings .stream-permissions-warning-banner").empty();
},
);
function save_stream_info(e) { function save_stream_info(e) {
const sub = get_sub_for_target(e.currentTarget); const sub = get_sub_for_target(e.currentTarget);

View File

@ -52,6 +52,8 @@
{{> ../settings/settings_save_discard_widget section_name="stream-permissions" }} {{> ../settings/settings_save_discard_widget section_name="stream-permissions" }}
</div> </div>
<div class="stream-permissions-warning-banner"></div>
{{> stream_types {{> stream_types
stream_post_policy_values=../stream_post_policy_values stream_post_policy_values=../stream_post_policy_values
stream_privacy_policy_values=../stream_privacy_policy_values stream_privacy_policy_values=../stream_privacy_policy_values