mirror of
https://github.com/zulip/zulip.git
synced 2025-11-02 21:13:36 +00:00
This commit adds a warning to the confirmation modal displayed when the last user of a private stream attempts to unsubscribe. The warning explains that, as the only subscriber, unsubscribing will result in the stream being automatically archived. This change helps ensure that users are aware of the consequences of their actions and can make informed decisions. Fixes: #23954
332 lines
11 KiB
JavaScript
332 lines
11 KiB
JavaScript
import $ from "jquery";
|
|
|
|
import render_unsubscribe_private_stream_modal from "../templates/confirm_dialog/confirm_unsubscribe_private_stream.hbs";
|
|
import render_stream_member_list_entry from "../templates/stream_settings/stream_member_list_entry.hbs";
|
|
import render_stream_subscription_request_result from "../templates/stream_settings/stream_subscription_request_result.hbs";
|
|
|
|
import * as add_subscribers_pill from "./add_subscribers_pill";
|
|
import * as blueslip from "./blueslip";
|
|
import * as confirm_dialog from "./confirm_dialog";
|
|
import * as hash_util from "./hash_util";
|
|
import {$t, $t_html} from "./i18n";
|
|
import * as ListWidget from "./list_widget";
|
|
import {page_params} from "./page_params";
|
|
import * as peer_data from "./peer_data";
|
|
import * as people from "./people";
|
|
import * as settings_data from "./settings_data";
|
|
import * as stream_data from "./stream_data";
|
|
import * as sub_store from "./sub_store";
|
|
import * as subscriber_api from "./subscriber_api";
|
|
import * as ui from "./ui";
|
|
|
|
export let pill_widget;
|
|
let current_stream_id;
|
|
let subscribers_list_widget;
|
|
|
|
function format_member_list_elem(person) {
|
|
return render_stream_member_list_entry({
|
|
name: person.full_name,
|
|
user_id: person.user_id,
|
|
is_current_user: person.user_id === page_params.user_id,
|
|
email: settings_data.email_for_user_settings(person),
|
|
can_edit_subscribers: page_params.is_admin,
|
|
show_email: settings_data.show_email(),
|
|
});
|
|
}
|
|
|
|
function get_sub(stream_id) {
|
|
const sub = sub_store.get(stream_id);
|
|
if (!sub) {
|
|
blueslip.error("get_sub() failed id lookup: " + stream_id);
|
|
return undefined;
|
|
}
|
|
return sub;
|
|
}
|
|
|
|
function show_stream_subscription_request_result({
|
|
message,
|
|
add_class,
|
|
remove_class,
|
|
subscribed_users,
|
|
already_subscribed_users,
|
|
ignored_deactivated_users,
|
|
}) {
|
|
const $stream_subscription_req_result_elem = $(
|
|
".stream_subscription_request_result",
|
|
).expectOne();
|
|
const html = render_stream_subscription_request_result({
|
|
message,
|
|
subscribed_users,
|
|
already_subscribed_users,
|
|
ignored_deactivated_users,
|
|
});
|
|
ui.get_content_element($stream_subscription_req_result_elem).html(html);
|
|
if (add_class) {
|
|
$stream_subscription_req_result_elem.addClass(add_class);
|
|
}
|
|
if (remove_class) {
|
|
$stream_subscription_req_result_elem.removeClass(remove_class);
|
|
}
|
|
}
|
|
|
|
export function enable_subscriber_management({sub, $parent_container}) {
|
|
const stream_id = sub.stream_id;
|
|
|
|
const $pill_container = $parent_container.find(".pill-container");
|
|
|
|
// current_stream_id and pill_widget are module-level variables
|
|
current_stream_id = stream_id;
|
|
|
|
function get_potential_subscribers() {
|
|
return peer_data.potential_subscribers(stream_id);
|
|
}
|
|
|
|
pill_widget = add_subscribers_pill.create({
|
|
$pill_container,
|
|
get_potential_subscribers,
|
|
});
|
|
|
|
const user_ids = peer_data.get_subscribers(stream_id);
|
|
|
|
// We track a single subscribers_list_widget for this module, since we
|
|
// only ever have one list of subscribers visible at a time.
|
|
subscribers_list_widget = make_list_widget({
|
|
$parent_container,
|
|
name: "stream_subscribers",
|
|
user_ids,
|
|
});
|
|
}
|
|
|
|
function make_list_widget({$parent_container, name, user_ids}) {
|
|
const users = people.get_users_from_ids(user_ids);
|
|
people.sort_but_pin_current_user_on_top(users);
|
|
|
|
const $list_container = $parent_container.find(".subscriber_table");
|
|
$list_container.empty();
|
|
|
|
const $simplebar_container = $parent_container.find(".subscriber_list_container");
|
|
|
|
return ListWidget.create($list_container, users, {
|
|
name,
|
|
modifier(item) {
|
|
return format_member_list_elem(item);
|
|
},
|
|
filter: {
|
|
$element: $parent_container.find(".search"),
|
|
predicate(person, value) {
|
|
const matcher = people.build_person_matcher(value);
|
|
const match = matcher(person);
|
|
|
|
return match;
|
|
},
|
|
},
|
|
$simplebar_container,
|
|
});
|
|
}
|
|
|
|
function subscribe_new_users({pill_user_ids}) {
|
|
const sub = get_sub(current_stream_id);
|
|
if (!sub) {
|
|
return;
|
|
}
|
|
|
|
const deactivated_users = new Set();
|
|
const active_user_ids = pill_user_ids.filter((user_id) => {
|
|
if (!people.is_person_active(user_id)) {
|
|
deactivated_users.add(user_id);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
const user_id_set = new Set(active_user_ids);
|
|
|
|
if (user_id_set.has(page_params.user_id) && sub.subscribed) {
|
|
// We don't want to send a request to subscribe ourselves
|
|
// if we are already subscribed to this stream. This
|
|
// case occurs when creating user pills from a stream.
|
|
user_id_set.delete(page_params.user_id);
|
|
}
|
|
let ignored_deactivated_users;
|
|
if (deactivated_users.size > 0) {
|
|
ignored_deactivated_users = Array.from(deactivated_users);
|
|
ignored_deactivated_users = ignored_deactivated_users.map((user_id) =>
|
|
people.get_by_user_id(user_id),
|
|
);
|
|
}
|
|
if (user_id_set.size === 0) {
|
|
show_stream_subscription_request_result({
|
|
message: $t({defaultMessage: "No user to subscribe."}),
|
|
add_class: "text-error",
|
|
remove_class: "text-success",
|
|
ignored_deactivated_users,
|
|
});
|
|
return;
|
|
}
|
|
|
|
const user_ids = Array.from(user_id_set);
|
|
|
|
function invite_success(data) {
|
|
pill_widget.clear();
|
|
const subscribed_users = Object.keys(data.subscribed).map((email) =>
|
|
people.get_by_email(email),
|
|
);
|
|
const already_subscribed_users = Object.keys(data.already_subscribed).map((email) =>
|
|
people.get_by_email(email),
|
|
);
|
|
|
|
show_stream_subscription_request_result({
|
|
add_class: "text-success",
|
|
remove_class: "text-error",
|
|
subscribed_users,
|
|
already_subscribed_users,
|
|
ignored_deactivated_users,
|
|
});
|
|
}
|
|
|
|
function invite_failure(xhr) {
|
|
const error = JSON.parse(xhr.responseText);
|
|
show_stream_subscription_request_result({
|
|
message: error.msg,
|
|
add_class: "text-error",
|
|
remove_class: "text-success",
|
|
});
|
|
}
|
|
|
|
subscriber_api.add_user_ids_to_stream(user_ids, sub, invite_success, invite_failure);
|
|
}
|
|
|
|
function remove_subscriber({stream_id, target_user_id, $list_entry}) {
|
|
const sub = get_sub(stream_id);
|
|
if (!sub) {
|
|
return;
|
|
}
|
|
|
|
function removal_success(data) {
|
|
let message;
|
|
|
|
if (stream_id !== current_stream_id) {
|
|
blueslip.info("Response for subscription removal came too late.");
|
|
return;
|
|
}
|
|
|
|
if (data.removed.length > 0) {
|
|
// Remove the user from the subscriber list.
|
|
$list_entry.remove();
|
|
message = $t({defaultMessage: "Unsubscribed successfully!"});
|
|
// The rest of the work is done via the subscription -> remove event we will get
|
|
} else {
|
|
message = $t({defaultMessage: "User is already not subscribed."});
|
|
}
|
|
show_stream_subscription_request_result({
|
|
message,
|
|
add_class: "text-success",
|
|
remove_class: "text-remove",
|
|
});
|
|
}
|
|
|
|
function removal_failure() {
|
|
show_stream_subscription_request_result({
|
|
message: $t({defaultMessage: "Error removing user from this stream."}),
|
|
add_class: "text-error",
|
|
remove_class: "text-success",
|
|
});
|
|
}
|
|
|
|
function remove_user_from_private_stream() {
|
|
subscriber_api.remove_user_id_from_stream(
|
|
target_user_id,
|
|
sub,
|
|
removal_success,
|
|
removal_failure,
|
|
);
|
|
}
|
|
|
|
if (sub.invite_only && people.is_my_user_id(target_user_id)) {
|
|
const sub_count = peer_data.get_subscriber_count(stream_id);
|
|
|
|
const html_body = render_unsubscribe_private_stream_modal({
|
|
message: $t({
|
|
defaultMessage: "Once you leave this stream, you will not be able to rejoin.",
|
|
}),
|
|
display_stream_archive_warning: sub_count === 1,
|
|
});
|
|
|
|
confirm_dialog.launch({
|
|
html_heading: $t_html(
|
|
{defaultMessage: "Unsubscribe from {stream_name}"},
|
|
{stream_name: sub.name},
|
|
),
|
|
html_body,
|
|
on_click: remove_user_from_private_stream,
|
|
});
|
|
return;
|
|
}
|
|
|
|
subscriber_api.remove_user_id_from_stream(
|
|
target_user_id,
|
|
sub,
|
|
removal_success,
|
|
removal_failure,
|
|
);
|
|
}
|
|
|
|
export function update_subscribers_list(sub) {
|
|
// This is for the "Subscribers" tab of the right panel.
|
|
// Render subscriptions only if stream settings is open
|
|
if (!hash_util.is_editing_stream(sub.stream_id)) {
|
|
blueslip.info("ignoring subscription for stream that is no longer being edited");
|
|
return;
|
|
}
|
|
|
|
if (sub.stream_id !== current_stream_id) {
|
|
// This should never happen if the prior check works correctly.
|
|
blueslip.error("current_stream_id does not match sub.stream_id for some reason");
|
|
return;
|
|
}
|
|
|
|
if (!stream_data.can_view_subscribers(sub)) {
|
|
$(".subscriber_list_settings_container").hide();
|
|
} else {
|
|
// Re-render the whole list when we add new users. This is
|
|
// inefficient for the single-user case, but using the big-hammer
|
|
// approach is superior when you do things like add subscribers
|
|
// from an existing stream or a user group.
|
|
const subscriber_ids = peer_data.get_subscribers(sub.stream_id);
|
|
update_subscribers_list_widget(subscriber_ids);
|
|
$(".subscriber_list_settings_container").show();
|
|
}
|
|
}
|
|
|
|
function update_subscribers_list_widget(subscriber_ids) {
|
|
// This re-renders the subscribers_list_widget with a new
|
|
// list of subscriber_ids.
|
|
const users = people.get_users_from_ids(subscriber_ids);
|
|
people.sort_but_pin_current_user_on_top(users);
|
|
subscribers_list_widget.replace_list_data(users);
|
|
}
|
|
|
|
export function initialize() {
|
|
add_subscribers_pill.set_up_handlers({
|
|
get_pill_widget: () => pill_widget,
|
|
$parent_container: $("#manage_streams_container"),
|
|
pill_selector: ".edit_subscribers_for_stream .pill-container",
|
|
button_selector: ".edit_subscribers_for_stream .add-subscriber-button",
|
|
action: subscribe_new_users,
|
|
});
|
|
|
|
$("#manage_streams_container").on(
|
|
"submit",
|
|
".edit_subscribers_for_stream .subscriber_list_remove form",
|
|
(e) => {
|
|
e.preventDefault();
|
|
|
|
const $list_entry = $(e.target).closest("tr");
|
|
const target_user_id = Number.parseInt($list_entry.attr("data-subscriber-id"), 10);
|
|
const stream_id = current_stream_id;
|
|
|
|
remove_subscriber({stream_id, target_user_id, $list_entry});
|
|
},
|
|
);
|
|
}
|