mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
This commit solves the bug which keeps the announce stream checkbox checked for non-admin users when users are only allowed to create private streams and not public streams. The desired behavior is to not allow users to announce private streams, so we keep the checkbox unchecked and disabled. This commit fixes the above mentioned bug by removing the if-else block which was executed after update_announce_stream_state (the function which handles updating the checkbox considering if the realm has notifications stream or not and whether the stream being created is public or private) and only checks whether the realm has notification stream or not to show or hide the announce stream checkbox irrespective of privacy of the stream being created. This commit also fixes the handler to update the checkbox state on changing privacy to update the checkbox state only on changing privacy value and not on toggling the checkbox itself or changing post policy. Fixes #21705.
402 lines
14 KiB
JavaScript
402 lines
14 KiB
JavaScript
import $ from "jquery";
|
|
|
|
import render_announce_stream_docs from "../templates/announce_stream_docs.hbs";
|
|
import render_subscription_invites_warning_modal from "../templates/confirm_dialog/confirm_subscription_invites_warning.hbs";
|
|
|
|
import * as channel from "./channel";
|
|
import * as confirm_dialog from "./confirm_dialog";
|
|
import {$t, $t_html} from "./i18n";
|
|
import * as loading from "./loading";
|
|
import {page_params} from "./page_params";
|
|
import * as people from "./people";
|
|
import * as stream_create_subscribers from "./stream_create_subscribers";
|
|
import * as stream_data from "./stream_data";
|
|
import * as stream_settings_ui from "./stream_settings_ui";
|
|
import * as ui_report from "./ui_report";
|
|
|
|
let created_stream;
|
|
|
|
export function reset_created_stream() {
|
|
created_stream = undefined;
|
|
}
|
|
|
|
export function set_name(stream) {
|
|
created_stream = stream;
|
|
}
|
|
|
|
export function get_name() {
|
|
return created_stream;
|
|
}
|
|
|
|
class StreamSubscriptionError {
|
|
report_no_subs_to_stream() {
|
|
$("#stream_subscription_error").text(
|
|
$t({defaultMessage: "You cannot create a stream with no subscribers!"}),
|
|
);
|
|
$("#stream_subscription_error").show();
|
|
}
|
|
|
|
cant_create_stream_without_susbscribing() {
|
|
$("#stream_subscription_error").text(
|
|
$t({
|
|
defaultMessage:
|
|
"You must be an organization administrator to create a stream without subscribing.",
|
|
}),
|
|
);
|
|
$("#stream_subscription_error").show();
|
|
}
|
|
|
|
clear_errors() {
|
|
$("#stream_subscription_error").hide();
|
|
}
|
|
}
|
|
const stream_subscription_error = new StreamSubscriptionError();
|
|
|
|
class StreamNameError {
|
|
report_already_exists() {
|
|
$("#stream_name_error").text(
|
|
$t({defaultMessage: "A stream with this name already exists"}),
|
|
);
|
|
$("#stream_name_error").show();
|
|
}
|
|
|
|
clear_errors() {
|
|
$("#stream_name_error").hide();
|
|
}
|
|
|
|
report_empty_stream() {
|
|
$("#stream_name_error").text($t({defaultMessage: "A stream needs to have a name"}));
|
|
$("#stream_name_error").show();
|
|
}
|
|
|
|
select() {
|
|
$("#create_stream_name").trigger("focus").trigger("select");
|
|
}
|
|
|
|
pre_validate(stream_name) {
|
|
// Don't worry about empty strings...we just want to call this
|
|
// to warn users early before they start doing too much work
|
|
// after they make the effort to type in a stream name. (The
|
|
// use case here is that I go to create a stream, only to find
|
|
// out it already exists, and I was just too lazy to look at
|
|
// the public streams that I'm not subscribed to yet. Once I
|
|
// realize the stream already exists, I may want to cancel.)
|
|
if (stream_name && stream_data.get_sub(stream_name)) {
|
|
this.report_already_exists();
|
|
return;
|
|
}
|
|
|
|
this.clear_errors();
|
|
}
|
|
|
|
validate_for_submit(stream_name) {
|
|
if (!stream_name) {
|
|
this.report_empty_stream();
|
|
this.select();
|
|
return false;
|
|
}
|
|
|
|
if (stream_data.get_sub(stream_name)) {
|
|
this.report_already_exists();
|
|
this.select();
|
|
return false;
|
|
}
|
|
|
|
// If we got this far, then we think we have a new unique stream
|
|
// name, so we'll submit to the server. (It's still plausible,
|
|
// however, that there's some invite-only stream that we don't
|
|
// know about locally that will cause a name collision.)
|
|
return true;
|
|
}
|
|
}
|
|
const stream_name_error = new StreamNameError();
|
|
|
|
// Within the new stream modal...
|
|
function update_announce_stream_state() {
|
|
// If there is no notifications_stream, we simply hide the widget.
|
|
if (!stream_data.realm_has_notifications_stream()) {
|
|
$("#announce-new-stream").hide();
|
|
return;
|
|
}
|
|
|
|
// If the stream is invite only, disable the "Announce stream" option.
|
|
// Otherwise enable it.
|
|
const $announce_stream_checkbox = $("#announce-new-stream input");
|
|
const $announce_stream_label = $("#announce-new-stream");
|
|
let disable_it = false;
|
|
const privacy_type = $("input:radio[name=privacy]:checked").val();
|
|
const is_invite_only =
|
|
privacy_type === "invite-only" || privacy_type === "invite-only-public-history";
|
|
$announce_stream_label.removeClass("control-label-disabled");
|
|
|
|
if (is_invite_only) {
|
|
disable_it = true;
|
|
$announce_stream_checkbox.prop("checked", false);
|
|
$announce_stream_label.addClass("control-label-disabled");
|
|
}
|
|
|
|
$announce_stream_checkbox.prop("disabled", disable_it);
|
|
$("#announce-new-stream").show();
|
|
}
|
|
|
|
function create_stream() {
|
|
const data = {};
|
|
const stream_name = $("#create_stream_name").val().trim();
|
|
const description = $("#create_stream_description").val().trim();
|
|
created_stream = stream_name;
|
|
|
|
// Even though we already check to make sure that while typing the user cannot enter
|
|
// newline characters (by pressing the Enter key) it would still be possible to copy
|
|
// and paste over a description with newline characters in it. Prevent that.
|
|
if (description.includes("\n")) {
|
|
ui_report.client_error(
|
|
$t_html({defaultMessage: "The stream description cannot contain newline characters."}),
|
|
$(".stream_create_info"),
|
|
);
|
|
return undefined;
|
|
}
|
|
data.subscriptions = JSON.stringify([{name: stream_name, description}]);
|
|
|
|
let invite_only;
|
|
let history_public_to_subscribers;
|
|
let is_web_public;
|
|
const privacy_setting = $("#stream_creation_form input[name=privacy]:checked").val();
|
|
|
|
switch (privacy_setting) {
|
|
case "invite-only": {
|
|
invite_only = true;
|
|
history_public_to_subscribers = false;
|
|
is_web_public = false;
|
|
|
|
break;
|
|
}
|
|
case "invite-only-public-history": {
|
|
invite_only = true;
|
|
history_public_to_subscribers = true;
|
|
is_web_public = false;
|
|
|
|
break;
|
|
}
|
|
case "web-public": {
|
|
invite_only = false;
|
|
history_public_to_subscribers = true;
|
|
is_web_public = true;
|
|
|
|
break;
|
|
}
|
|
default: {
|
|
invite_only = false;
|
|
history_public_to_subscribers = true;
|
|
is_web_public = false;
|
|
}
|
|
}
|
|
|
|
data.is_web_public = JSON.stringify(is_web_public);
|
|
data.invite_only = JSON.stringify(invite_only);
|
|
data.history_public_to_subscribers = JSON.stringify(history_public_to_subscribers);
|
|
|
|
const stream_post_policy = Number.parseInt(
|
|
$("#stream_creation_form select[name=stream-post-policy]").val(),
|
|
10,
|
|
);
|
|
|
|
data.stream_post_policy = JSON.stringify(stream_post_policy);
|
|
|
|
let message_retention_selection = $(
|
|
"#stream_creation_form select[name=stream_message_retention_setting]",
|
|
).val();
|
|
if (message_retention_selection === "retain_for_period") {
|
|
message_retention_selection = Number.parseInt(
|
|
$("#stream_creation_form input[name=stream-message-retention-days]").val(),
|
|
10,
|
|
);
|
|
}
|
|
|
|
data.message_retention_days = JSON.stringify(message_retention_selection);
|
|
|
|
const announce =
|
|
stream_data.realm_has_notifications_stream() &&
|
|
$("#announce-new-stream input").prop("checked");
|
|
data.announce = JSON.stringify(announce);
|
|
|
|
// TODO: We can eliminate the user_ids -> principals conversion
|
|
// once we upgrade the backend to accept user_ids.
|
|
const user_ids = stream_create_subscribers.get_principals();
|
|
data.principals = JSON.stringify(user_ids);
|
|
|
|
loading.make_indicator($("#stream_creating_indicator"), {
|
|
text: $t({defaultMessage: "Creating stream..."}),
|
|
});
|
|
|
|
// Subscribe yourself and possible other people to a new stream.
|
|
return channel.post({
|
|
url: "/json/users/me/subscriptions",
|
|
data,
|
|
success() {
|
|
$("#create_stream_name").val("");
|
|
$("#create_stream_description").val("");
|
|
ui_report.success(
|
|
$t_html({defaultMessage: "Stream successfully created!"}),
|
|
$(".stream_create_info"),
|
|
);
|
|
loading.destroy_indicator($("#stream_creating_indicator"));
|
|
// The rest of the work is done via the subscribe event we will get
|
|
},
|
|
error(xhr) {
|
|
const msg = JSON.parse(xhr.responseText).msg;
|
|
if (msg.includes("access")) {
|
|
// If we can't access the stream, we can safely assume it's
|
|
// a duplicate stream that we are not invited to.
|
|
//
|
|
// BUG: This check should be using error codes, not
|
|
// parsing the error string, so it works correctly
|
|
// with i18n. And likely we should be reporting the
|
|
// error text directly rather than turning it into
|
|
// "Error creating stream"?
|
|
stream_name_error.report_already_exists(stream_name);
|
|
stream_name_error.trigger("select");
|
|
}
|
|
|
|
ui_report.error(
|
|
$t_html({defaultMessage: "Error creating stream"}),
|
|
xhr,
|
|
$(".stream_create_info"),
|
|
);
|
|
loading.destroy_indicator($("#stream_creating_indicator"));
|
|
},
|
|
});
|
|
}
|
|
|
|
export function new_stream_clicked(stream_name) {
|
|
// this changes the tab switcher (settings/preview) which isn't necessary
|
|
// to a add new stream title.
|
|
stream_settings_ui.show_subs_pane.create_stream();
|
|
$(".stream-row.active").removeClass("active");
|
|
|
|
if (stream_name !== "") {
|
|
$("#create_stream_name").val(stream_name);
|
|
}
|
|
show_new_stream_modal();
|
|
$("#create_stream_name").trigger("focus");
|
|
}
|
|
|
|
function clear_error_display() {
|
|
stream_name_error.clear_errors();
|
|
$(".stream_create_info").hide();
|
|
stream_subscription_error.clear_errors();
|
|
}
|
|
|
|
export function show_new_stream_modal() {
|
|
$("#stream-creation").removeClass("hide");
|
|
$(".right .settings").hide();
|
|
stream_settings_ui.hide_or_disable_stream_privacy_options_if_required($("#stream-creation"));
|
|
|
|
stream_create_subscribers.build_widgets();
|
|
|
|
// Select the first visible and enabled choice for stream privacy.
|
|
$("#make-invite-only input:visible:not([disabled])").first().prop("checked", true);
|
|
// Make the options default to the same each time:
|
|
// "announce stream" on.
|
|
$("#stream_creation_form .stream-message-retention-days-input").hide();
|
|
$("#stream_creation_form select[name=stream_message_retention_setting]").val("realm_default");
|
|
|
|
// Add listener to .show stream-message-retention-days-input that we've hidden above
|
|
$("#stream_creation_form .stream_message_retention_setting").on("change", (e) => {
|
|
if (e.target.value === "retain_for_period") {
|
|
$("#stream_creation_form .stream-message-retention-days-input").show();
|
|
} else {
|
|
$("#stream_creation_form .stream-message-retention-days-input").hide();
|
|
}
|
|
});
|
|
|
|
update_announce_stream_state();
|
|
clear_error_display();
|
|
}
|
|
|
|
export function set_up_handlers() {
|
|
const $people_to_add_holder = $("#people_to_add").expectOne();
|
|
stream_create_subscribers.create_handlers($people_to_add_holder);
|
|
|
|
const $container = $("#stream-creation").expectOne();
|
|
|
|
$container.on("change", ".stream-privacy-values input", update_announce_stream_state);
|
|
|
|
$container.on("click", ".finalize_create_stream", (e) => {
|
|
e.preventDefault();
|
|
clear_error_display();
|
|
|
|
const stream_name = $("#create_stream_name").val().trim();
|
|
const name_ok = stream_name_error.validate_for_submit(stream_name);
|
|
|
|
if (!name_ok) {
|
|
return;
|
|
}
|
|
|
|
const principals = stream_create_subscribers.get_principals();
|
|
if (principals.length === 0) {
|
|
stream_subscription_error.report_no_subs_to_stream();
|
|
return;
|
|
}
|
|
if (!principals.includes(people.my_current_user_id()) && !page_params.is_admin) {
|
|
stream_subscription_error.cant_create_stream_without_susbscribing();
|
|
return;
|
|
}
|
|
|
|
if (principals.length >= 50) {
|
|
const html_body = render_subscription_invites_warning_modal({
|
|
stream_name,
|
|
count: principals.length,
|
|
});
|
|
|
|
confirm_dialog.launch({
|
|
html_heading: $t_html({defaultMessage: "Large number of subscribers"}),
|
|
html_body,
|
|
on_click: () => {
|
|
create_stream();
|
|
},
|
|
});
|
|
} else {
|
|
create_stream();
|
|
}
|
|
});
|
|
|
|
$container.on("input", "#create_stream_name", () => {
|
|
const stream_name = $("#create_stream_name").val().trim();
|
|
|
|
// This is an inexpensive check.
|
|
stream_name_error.pre_validate(stream_name);
|
|
});
|
|
|
|
$container.on("mouseover", "#announce-stream-docs", (e) => {
|
|
const $announce_stream_docs = $("#announce-stream-docs");
|
|
$announce_stream_docs.popover({
|
|
placement: "right",
|
|
content: render_announce_stream_docs({
|
|
notifications_stream: stream_data.get_notifications_stream(),
|
|
}),
|
|
html: true,
|
|
trigger: "manual",
|
|
});
|
|
$announce_stream_docs.popover("show");
|
|
$announce_stream_docs.data("popover").tip().css("z-index", 2000);
|
|
$announce_stream_docs
|
|
.data("popover")
|
|
.tip()
|
|
.find(".popover-content")
|
|
.css("margin", "9px 14px");
|
|
e.stopPropagation();
|
|
});
|
|
$container.on("mouseout", "#announce-stream-docs", (e) => {
|
|
$("#announce-stream-docs").popover("hide");
|
|
e.stopPropagation();
|
|
});
|
|
|
|
// Do not allow the user to enter newline characters while typing out the
|
|
// stream's description during it's creation.
|
|
$container.on("keydown", "#create_stream_description", (e) => {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
}
|