2021-06-25 15:16:29 +02:00
|
|
|
import $ from "jquery";
|
|
|
|
|
2023-02-22 23:03:47 +01:00
|
|
|
import * as resolved_topic from "../shared/src/resolved_topic";
|
2022-08-19 21:36:33 +02:00
|
|
|
import render_compose_banner from "../templates/compose_banner/compose_banner.hbs";
|
2022-08-20 02:51:13 +02:00
|
|
|
import render_not_subscribed_warning from "../templates/compose_banner/not_subscribed_warning.hbs";
|
2022-08-23 01:03:37 +02:00
|
|
|
import render_private_stream_warning from "../templates/compose_banner/private_stream_warning.hbs";
|
2023-11-21 07:04:19 +01:00
|
|
|
import render_stream_wildcard_warning from "../templates/compose_banner/stream_wildcard_warning.hbs";
|
2023-11-21 20:12:13 +01:00
|
|
|
import render_wildcard_mention_not_allowed_error from "../templates/compose_banner/wildcard_mention_not_allowed_error.hbs";
|
2023-11-07 18:51:28 +01:00
|
|
|
import render_compose_limit_indicator from "../templates/compose_limit_indicator.hbs";
|
2021-06-25 15:16:29 +02:00
|
|
|
|
|
|
|
import * as channel from "./channel";
|
2022-08-30 22:24:54 +02:00
|
|
|
import * as compose_banner from "./compose_banner";
|
2021-06-25 15:16:29 +02:00
|
|
|
import * as compose_pm_pill from "./compose_pm_pill";
|
|
|
|
import * as compose_state from "./compose_state";
|
2021-11-30 06:26:05 +01:00
|
|
|
import * as compose_ui from "./compose_ui";
|
2022-08-19 22:24:06 +02:00
|
|
|
import {$t} from "./i18n";
|
2023-11-24 15:06:42 +01:00
|
|
|
import * as message_store from "./message_store";
|
2021-06-25 15:16:29 +02:00
|
|
|
import {page_params} from "./page_params";
|
|
|
|
import * as peer_data from "./peer_data";
|
|
|
|
import * as people from "./people";
|
2023-11-24 15:06:42 +01:00
|
|
|
import * as reactions from "./reactions";
|
|
|
|
import * as recent_senders from "./recent_senders";
|
2021-06-25 15:16:29 +02:00
|
|
|
import * as settings_config from "./settings_config";
|
2021-07-28 17:47:40 +02:00
|
|
|
import * as settings_data from "./settings_data";
|
2021-06-25 15:16:29 +02:00
|
|
|
import * as stream_data from "./stream_data";
|
2023-05-18 15:53:21 +02:00
|
|
|
import * as sub_store from "./sub_store";
|
2021-06-25 15:16:29 +02:00
|
|
|
import * as util from "./util";
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
let user_acknowledged_stream_wildcard = false;
|
2023-11-10 21:00:25 +01:00
|
|
|
let upload_in_progress = false;
|
|
|
|
let message_too_long = false;
|
|
|
|
let recipient_disallowed = false;
|
2021-06-25 15:16:29 +02:00
|
|
|
|
2023-11-24 16:10:03 +01:00
|
|
|
export let wildcard_mention_threshold = 15;
|
2021-06-25 15:16:29 +02:00
|
|
|
|
2023-11-10 21:00:25 +01:00
|
|
|
export function set_upload_in_progress(status) {
|
|
|
|
upload_in_progress = status;
|
|
|
|
update_send_button_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
function set_message_too_long(status) {
|
|
|
|
message_too_long = status;
|
|
|
|
update_send_button_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function set_recipient_disallowed(status) {
|
|
|
|
recipient_disallowed = status;
|
|
|
|
update_send_button_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
function update_send_button_status() {
|
|
|
|
$(".message-send-controls").toggleClass(
|
|
|
|
"disabled-message-send-controls",
|
|
|
|
message_too_long || upload_in_progress || recipient_disallowed,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_disabled_send_tooltip() {
|
|
|
|
if (message_too_long) {
|
|
|
|
return $t({defaultMessage: "Message length shouldn't be greater than 10000 characters."});
|
|
|
|
} else if (upload_in_progress) {
|
|
|
|
return $t({defaultMessage: "Cannot send message while files are being uploaded."});
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2021-07-28 17:47:40 +02:00
|
|
|
export function needs_subscribe_warning(user_id, stream_id) {
|
|
|
|
// This returns true if all of these conditions are met:
|
|
|
|
// * the user is valid
|
|
|
|
// * the user is not already subscribed to the stream
|
|
|
|
// * the user has no back-door way to see stream messages
|
|
|
|
// (i.e. bots on public/private streams)
|
|
|
|
//
|
|
|
|
// You can think of this as roughly answering "is there an
|
|
|
|
// actionable way to subscribe the user and do they actually
|
|
|
|
// need it?".
|
|
|
|
//
|
|
|
|
// We expect the caller to already have verified that we're
|
|
|
|
// sending to a valid stream and trying to mention the user.
|
|
|
|
|
2023-06-16 15:23:45 +02:00
|
|
|
const user = people.maybe_get_user_by_id(user_id);
|
2021-07-28 17:47:40 +02:00
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user.is_bot) {
|
|
|
|
// Bots may receive messages on public/private streams even if they are
|
|
|
|
// not subscribed.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream_data.is_user_subscribed(stream_id, user_id)) {
|
|
|
|
// If our user is already subscribed
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-24 12:27:44 +02:00
|
|
|
function get_stream_id_for_textarea($textarea) {
|
|
|
|
// Returns the stream ID, if any, associated with the textarea:
|
|
|
|
// The recipient of a message being edited, or the target
|
|
|
|
// recipient of a message being drafted in the compose box.
|
|
|
|
// Returns undefined if the appropriate context is a direct
|
|
|
|
// message conversation.
|
|
|
|
const is_in_editing_area = $textarea.closest(".message_row").length > 0;
|
|
|
|
|
|
|
|
if (is_in_editing_area) {
|
|
|
|
const stream_id_str = $textarea
|
|
|
|
.closest(".recipient_row")
|
|
|
|
.find(".message_header")
|
|
|
|
.attr("data-stream-id");
|
|
|
|
if (stream_id_str === undefined) {
|
|
|
|
// Direct messages don't have a data-stream-id.
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
return Number.parseInt(stream_id_str, 10);
|
|
|
|
}
|
|
|
|
|
2023-09-26 20:28:39 +02:00
|
|
|
return compose_state.stream_id();
|
2023-05-24 12:15:44 +02:00
|
|
|
}
|
|
|
|
|
2023-05-02 11:05:37 +02:00
|
|
|
export function warn_if_private_stream_is_linked(linked_stream, $textarea) {
|
2023-05-24 12:27:44 +02:00
|
|
|
const stream_id = get_stream_id_for_textarea($textarea);
|
|
|
|
|
2023-05-24 12:15:44 +02:00
|
|
|
if (!stream_id) {
|
2023-05-24 12:27:44 +02:00
|
|
|
// There are two cases in which the `stream_id` will be
|
|
|
|
// omitted, and we want to exclude the warning banner:
|
|
|
|
//
|
|
|
|
// 1. We currently do not warn about links to private streams
|
|
|
|
// in direct messages; it would probably be an improvement to
|
|
|
|
// do so when one of the recipients is not subscribed.
|
|
|
|
//
|
|
|
|
// 2. If we have an invalid stream name, we do not warn about
|
|
|
|
// it here; we will show an error to the user when they try to
|
|
|
|
// send the message.
|
2021-07-28 17:47:40 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the stream we're linking to is not invite-only, then it's
|
|
|
|
// public, and there is no need to warn about it, since all
|
|
|
|
// members can already see all the public streams.
|
|
|
|
//
|
|
|
|
// Theoretically, we could still do a warning if there are any
|
|
|
|
// guest users subscribed to the stream we're posting to; we may
|
|
|
|
// change this policy if user feedback suggests it'd be an
|
|
|
|
// improvement.
|
|
|
|
if (!linked_stream.invite_only) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't warn if subscribers list of current compose_stream is
|
|
|
|
// a subset of linked_stream's subscribers list, because
|
|
|
|
// everyone will be subscribed to the linked stream and so
|
|
|
|
// knows it exists. (But always warn Zephyr users, since
|
|
|
|
// we may not know their stream's subscribers.)
|
|
|
|
if (
|
2023-05-24 12:15:44 +02:00
|
|
|
peer_data.is_subscriber_subset(stream_id, linked_stream.stream_id) &&
|
2021-07-28 17:47:40 +02:00
|
|
|
!page_params.realm_is_zephyr_mirror_realm
|
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-23 01:03:37 +02:00
|
|
|
const new_row = render_private_stream_warning({
|
2022-08-30 22:24:54 +02:00
|
|
|
banner_type: compose_banner.WARNING,
|
2022-08-23 01:03:37 +02:00
|
|
|
stream_name: linked_stream.name,
|
2022-08-30 22:24:54 +02:00
|
|
|
classname: compose_banner.CLASSNAMES.private_stream_warning,
|
2022-08-23 01:03:37 +02:00
|
|
|
});
|
2023-05-02 11:05:37 +02:00
|
|
|
const $container = compose_banner.get_compose_banner_container($textarea);
|
|
|
|
compose_banner.append_compose_banner_to_banner_list(new_row, $container);
|
2021-07-28 17:47:40 +02:00
|
|
|
}
|
|
|
|
|
2023-05-02 11:05:37 +02:00
|
|
|
export function warn_if_mentioning_unsubscribed_user(mentioned, $textarea) {
|
2021-07-28 17:47:40 +02:00
|
|
|
// Disable for Zephyr mirroring realms, since we never have subscriber lists there
|
|
|
|
if (page_params.realm_is_zephyr_mirror_realm) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const user_id = mentioned.user_id;
|
|
|
|
|
|
|
|
if (mentioned.is_broadcast) {
|
|
|
|
return; // don't check if @all/@everyone/@stream
|
|
|
|
}
|
|
|
|
|
2023-05-24 12:27:44 +02:00
|
|
|
const stream_id = get_stream_id_for_textarea($textarea);
|
2021-07-28 17:47:40 +02:00
|
|
|
|
2023-05-24 12:15:44 +02:00
|
|
|
if (!stream_id) {
|
2021-07-28 17:47:40 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-24 12:15:44 +02:00
|
|
|
if (needs_subscribe_warning(user_id, stream_id)) {
|
2023-05-02 11:05:37 +02:00
|
|
|
const $banner_container = compose_banner.get_compose_banner_container($textarea);
|
|
|
|
const $existing_invites_area = $banner_container.find(
|
|
|
|
`.${CSS.escape(compose_banner.CLASSNAMES.recipient_not_subscribed)}`,
|
2022-08-20 02:51:13 +02:00
|
|
|
);
|
2021-07-28 17:47:40 +02:00
|
|
|
|
2023-03-02 01:58:25 +01:00
|
|
|
const existing_invites = [...$existing_invites_area].map((user_row) =>
|
2021-07-28 17:47:40 +02:00
|
|
|
Number.parseInt($(user_row).data("user-id"), 10),
|
|
|
|
);
|
|
|
|
|
2022-08-20 02:51:13 +02:00
|
|
|
const can_subscribe_other_users = settings_data.user_can_subscribe_other_users();
|
|
|
|
|
2021-07-28 17:47:40 +02:00
|
|
|
if (!existing_invites.includes(user_id)) {
|
|
|
|
const context = {
|
|
|
|
user_id,
|
2023-05-24 12:15:44 +02:00
|
|
|
stream_id,
|
2022-08-30 22:24:54 +02:00
|
|
|
banner_type: compose_banner.WARNING,
|
2022-08-20 02:51:13 +02:00
|
|
|
button_text: can_subscribe_other_users
|
|
|
|
? $t({defaultMessage: "Subscribe them"})
|
|
|
|
: null,
|
|
|
|
can_subscribe_other_users,
|
2021-07-28 17:47:40 +02:00
|
|
|
name: mentioned.full_name,
|
2022-08-30 22:24:54 +02:00
|
|
|
classname: compose_banner.CLASSNAMES.recipient_not_subscribed,
|
2023-09-13 19:30:52 +02:00
|
|
|
should_add_guest_user_indicator: people.should_add_guest_user_indicator(user_id),
|
2021-07-28 17:47:40 +02:00
|
|
|
};
|
|
|
|
|
2022-08-20 02:51:13 +02:00
|
|
|
const new_row = render_not_subscribed_warning(context);
|
2023-05-02 11:05:37 +02:00
|
|
|
const $container = compose_banner.get_compose_banner_container($textarea);
|
|
|
|
compose_banner.append_compose_banner_to_banner_list(new_row, $container);
|
2021-07-28 17:47:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 05:43:24 +01:00
|
|
|
// Called when clearing the compose box and similar contexts to clear
|
|
|
|
// the warning for composing to a resolved topic, if present. Also clears
|
|
|
|
// the state for whether this warning has already been shown in the
|
|
|
|
// current narrow.
|
2021-07-27 21:48:11 +02:00
|
|
|
export function clear_topic_resolved_warning() {
|
2023-02-02 05:43:24 +01:00
|
|
|
compose_state.set_recipient_viewed_topic_resolved_banner(false);
|
2023-04-01 01:42:40 +02:00
|
|
|
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.topic_resolved)}`).remove();
|
2021-07-27 21:48:11 +02:00
|
|
|
}
|
|
|
|
|
2022-03-16 01:31:01 +01:00
|
|
|
export function warn_if_topic_resolved(topic_changed) {
|
2022-08-04 08:30:55 +02:00
|
|
|
if (compose_state.recipient_has_topics()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-03-16 01:31:01 +01:00
|
|
|
// This function is called with topic_changed=false on every
|
|
|
|
// keypress when typing a message, so it should not do anything
|
|
|
|
// expensive in that case.
|
|
|
|
//
|
|
|
|
// Pass topic_changed=true if this function was called in response
|
|
|
|
// to a topic being edited.
|
2021-07-27 21:48:11 +02:00
|
|
|
const topic_name = compose_state.topic();
|
|
|
|
|
2022-03-16 01:31:01 +01:00
|
|
|
if (!topic_changed && !resolved_topic.is_resolved(topic_name)) {
|
|
|
|
// The resolved topic warning will only ever appear when
|
|
|
|
// composing to a resolve topic, so we return early without
|
|
|
|
// inspecting additional fields in this case.
|
|
|
|
return;
|
|
|
|
}
|
2021-07-27 21:48:11 +02:00
|
|
|
|
2023-05-26 02:48:11 +02:00
|
|
|
const stream_id = compose_state.stream_id();
|
2022-03-16 01:31:01 +01:00
|
|
|
const message_content = compose_state.message_content();
|
2023-05-26 02:48:11 +02:00
|
|
|
const sub = stream_data.get_sub_by_id(stream_id);
|
2021-07-27 21:48:11 +02:00
|
|
|
|
2022-03-16 01:31:01 +01:00
|
|
|
if (sub && message_content !== "" && resolved_topic.is_resolved(topic_name)) {
|
2023-02-02 05:43:24 +01:00
|
|
|
if (compose_state.has_recipient_viewed_topic_resolved_banner()) {
|
|
|
|
// We display the resolved topic banner at most once per narrow.
|
2022-03-16 01:31:01 +01:00
|
|
|
return;
|
2021-07-27 21:48:11 +02:00
|
|
|
}
|
|
|
|
|
2022-10-18 13:48:30 +02:00
|
|
|
const button_text = settings_data.user_can_move_messages_to_another_topic()
|
2022-08-19 21:36:33 +02:00
|
|
|
? $t({defaultMessage: "Unresolve topic"})
|
|
|
|
: null;
|
|
|
|
|
2021-07-27 21:48:11 +02:00
|
|
|
const context = {
|
2022-08-30 22:24:54 +02:00
|
|
|
banner_type: compose_banner.WARNING,
|
2021-07-27 21:48:11 +02:00
|
|
|
stream_id: sub.stream_id,
|
|
|
|
topic_name,
|
2022-08-19 21:36:33 +02:00
|
|
|
banner_text: $t({
|
|
|
|
defaultMessage:
|
|
|
|
"You are sending a message to a resolved topic. You can send as-is or unresolve the topic first.",
|
|
|
|
}),
|
|
|
|
button_text,
|
2022-08-30 22:24:54 +02:00
|
|
|
classname: compose_banner.CLASSNAMES.topic_resolved,
|
2021-07-27 21:48:11 +02:00
|
|
|
};
|
|
|
|
|
2022-08-19 21:36:33 +02:00
|
|
|
const new_row = render_compose_banner(context);
|
2023-05-02 11:05:37 +02:00
|
|
|
compose_banner.append_compose_banner_to_banner_list(new_row, $("#compose_banners"));
|
2023-02-02 05:43:24 +01:00
|
|
|
compose_state.set_recipient_viewed_topic_resolved_banner(true);
|
2021-07-27 21:48:11 +02:00
|
|
|
} else {
|
2022-08-19 21:36:33 +02:00
|
|
|
clear_topic_resolved_warning();
|
2021-07-27 21:48:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
function show_stream_wildcard_warnings(opts) {
|
2023-05-04 15:43:44 +02:00
|
|
|
const subscriber_count = peer_data.get_subscriber_count(opts.stream_id) || 0;
|
2023-05-18 15:53:21 +02:00
|
|
|
const stream_name = sub_store.maybe_get_stream_name(opts.stream_id);
|
2023-05-04 15:43:44 +02:00
|
|
|
const is_edit_container = opts.$banner_container.closest(".edit_form_banners").length > 0;
|
|
|
|
const classname = compose_banner.CLASSNAMES.wildcard_warning;
|
|
|
|
|
|
|
|
let button_text = opts.scheduling_message
|
|
|
|
? $t({defaultMessage: "Yes, schedule"})
|
2023-05-08 15:29:13 +02:00
|
|
|
: $t({defaultMessage: "Yes, send"});
|
2021-06-25 15:16:29 +02:00
|
|
|
|
2023-05-04 15:43:44 +02:00
|
|
|
if (is_edit_container) {
|
|
|
|
button_text = $t({defaultMessage: "Yes, save"});
|
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
const stream_wildcard_template = render_stream_wildcard_warning({
|
2022-08-30 22:24:54 +02:00
|
|
|
banner_type: compose_banner.WARNING,
|
2022-08-20 21:07:32 +02:00
|
|
|
subscriber_count,
|
2023-05-08 15:29:13 +02:00
|
|
|
stream_name,
|
2023-11-21 07:04:19 +01:00
|
|
|
stream_wildcard_mention: opts.stream_wildcard_mention,
|
2023-05-08 15:29:13 +02:00
|
|
|
button_text,
|
2022-08-20 21:07:32 +02:00
|
|
|
hide_close_button: true,
|
|
|
|
classname,
|
2023-05-04 16:04:30 +02:00
|
|
|
scheduling_message: opts.scheduling_message,
|
2021-06-25 15:16:29 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// only show one error for any number of @all or @everyone mentions
|
2023-05-04 15:43:44 +02:00
|
|
|
if (opts.$banner_container.find(`.${CSS.escape(classname)}`).length === 0) {
|
|
|
|
compose_banner.append_compose_banner_to_banner_list(
|
2023-11-21 07:04:19 +01:00
|
|
|
stream_wildcard_template,
|
2023-05-04 15:43:44 +02:00
|
|
|
opts.$banner_container,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// if there is already a banner, replace it with the new one
|
2023-05-09 13:04:01 +02:00
|
|
|
compose_banner.update_or_append_banner(
|
2023-11-21 07:04:19 +01:00
|
|
|
stream_wildcard_template,
|
2023-05-09 13:04:01 +02:00
|
|
|
classname,
|
|
|
|
opts.$banner_container,
|
|
|
|
);
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
user_acknowledged_stream_wildcard = false;
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
export function clear_stream_wildcard_warnings($banner_container) {
|
2022-08-30 22:24:54 +02:00
|
|
|
const classname = compose_banner.CLASSNAMES.wildcard_warning;
|
2023-05-08 15:29:13 +02:00
|
|
|
$banner_container.find(`.${CSS.escape(classname)}`).remove();
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
export function set_user_acknowledged_stream_wildcard_flag(value) {
|
|
|
|
user_acknowledged_stream_wildcard = value;
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function get_invalid_recipient_emails() {
|
|
|
|
const private_recipients = util.extract_pm_recipients(
|
|
|
|
compose_state.private_message_recipient(),
|
|
|
|
);
|
|
|
|
const invalid_recipients = private_recipients.filter(
|
|
|
|
(email) => !people.is_valid_email_for_compose(email),
|
|
|
|
);
|
|
|
|
|
|
|
|
return invalid_recipients;
|
|
|
|
}
|
|
|
|
|
|
|
|
function check_unsubscribed_stream_for_send(stream_name, autosubscribe) {
|
|
|
|
let result;
|
|
|
|
if (!autosubscribe) {
|
|
|
|
return "not-subscribed";
|
|
|
|
}
|
|
|
|
|
|
|
|
// In the rare circumstance of the autosubscribe option, we
|
|
|
|
// *Synchronously* try to subscribe to the stream before sending
|
|
|
|
// the message. This is deprecated and we hope to remove it; see
|
|
|
|
// #4650.
|
|
|
|
channel.post({
|
|
|
|
url: "/json/subscriptions/exists",
|
|
|
|
data: {stream: stream_name, autosubscribe: true},
|
|
|
|
async: false,
|
|
|
|
success(data) {
|
|
|
|
if (data.subscribed) {
|
|
|
|
result = "subscribed";
|
|
|
|
} else {
|
|
|
|
result = "not-subscribed";
|
|
|
|
}
|
|
|
|
},
|
|
|
|
error(xhr) {
|
|
|
|
if (xhr.status === 404) {
|
|
|
|
result = "does-not-exist";
|
|
|
|
} else {
|
|
|
|
result = "error";
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-11-15 03:55:43 +01:00
|
|
|
function is_recipient_large_stream() {
|
|
|
|
return (
|
|
|
|
compose_state.stream_id() &&
|
2023-11-24 16:10:03 +01:00
|
|
|
peer_data.get_subscriber_count(compose_state.stream_id()) > wildcard_mention_threshold
|
2023-11-15 03:55:43 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-11-24 15:06:42 +01:00
|
|
|
export function topic_participant_count_more_than_threshold(stream_id, topic) {
|
|
|
|
// Topic participants:
|
|
|
|
// Users who either sent or reacted to the messages in the topic.
|
|
|
|
const participant_ids = new Set();
|
|
|
|
|
|
|
|
const sender_ids = recent_senders.get_topic_recent_senders(stream_id, topic);
|
|
|
|
for (const id of sender_ids) {
|
|
|
|
participant_ids.add(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If senders count is greater than threshold, no need to calculate reactors.
|
|
|
|
if (participant_ids.size > wildcard_mention_threshold) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const sender_id of sender_ids) {
|
|
|
|
const message_ids = recent_senders.get_topic_message_ids_for_sender(
|
|
|
|
stream_id,
|
|
|
|
topic,
|
|
|
|
sender_id,
|
|
|
|
);
|
|
|
|
for (const message_id of message_ids) {
|
|
|
|
const message = message_store.get(message_id);
|
|
|
|
if (message) {
|
|
|
|
const message_reactions = reactions.get_message_reactions(message);
|
|
|
|
const reactor_ids = message_reactions.flatMap((obj) => obj.user_ids);
|
|
|
|
for (const id of reactor_ids) {
|
|
|
|
participant_ids.add(id);
|
|
|
|
}
|
|
|
|
if (participant_ids.size > wildcard_mention_threshold) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function is_recipient_large_topic() {
|
|
|
|
return (
|
|
|
|
compose_state.stream_id() &&
|
|
|
|
topic_participant_count_more_than_threshold(
|
|
|
|
compose_state.stream_id(),
|
|
|
|
compose_state.topic(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-11-24 16:10:03 +01:00
|
|
|
function wildcard_mention_policy_authorizes_user() {
|
2021-06-25 15:16:29 +02:00
|
|
|
if (
|
|
|
|
page_params.realm_wildcard_mention_policy ===
|
|
|
|
settings_config.wildcard_mention_policy_values.by_everyone.code
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
page_params.realm_wildcard_mention_policy ===
|
|
|
|
settings_config.wildcard_mention_policy_values.nobody.code
|
|
|
|
) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
page_params.realm_wildcard_mention_policy ===
|
2022-07-05 16:56:12 +02:00
|
|
|
settings_config.wildcard_mention_policy_values.by_admins_only.code
|
2021-06-25 15:16:29 +02:00
|
|
|
) {
|
|
|
|
return page_params.is_admin;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
page_params.realm_wildcard_mention_policy ===
|
|
|
|
settings_config.wildcard_mention_policy_values.by_moderators_only.code
|
|
|
|
) {
|
|
|
|
return page_params.is_admin || page_params.is_moderator;
|
|
|
|
}
|
2022-11-16 15:50:46 +01:00
|
|
|
|
2021-06-25 15:16:29 +02:00
|
|
|
if (
|
|
|
|
page_params.realm_wildcard_mention_policy ===
|
|
|
|
settings_config.wildcard_mention_policy_values.by_full_members.code
|
|
|
|
) {
|
|
|
|
if (page_params.is_admin) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
const person = people.get_by_user_id(page_params.user_id);
|
|
|
|
const current_datetime = new Date(Date.now());
|
|
|
|
const person_date_joined = new Date(person.date_joined);
|
|
|
|
const days = (current_datetime - person_date_joined) / 1000 / 86400;
|
|
|
|
|
|
|
|
return days >= page_params.realm_waiting_period_threshold && !page_params.is_guest;
|
|
|
|
}
|
|
|
|
return !page_params.is_guest;
|
|
|
|
}
|
|
|
|
|
2023-11-24 15:06:42 +01:00
|
|
|
export function stream_wildcard_mention_allowed() {
|
2023-11-24 16:10:03 +01:00
|
|
|
return !is_recipient_large_stream() || wildcard_mention_policy_authorizes_user();
|
2023-11-15 03:55:43 +01:00
|
|
|
}
|
|
|
|
|
2023-11-24 15:06:42 +01:00
|
|
|
export function topic_wildcard_mention_allowed() {
|
|
|
|
return !is_recipient_large_topic() || wildcard_mention_policy_authorizes_user();
|
|
|
|
}
|
|
|
|
|
2023-11-24 16:10:03 +01:00
|
|
|
export function set_wildcard_mention_threshold(value) {
|
|
|
|
wildcard_mention_threshold = value;
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
2023-05-04 15:43:44 +02:00
|
|
|
export function validate_stream_message_mentions(opts) {
|
|
|
|
const subscriber_count = peer_data.get_subscriber_count(opts.stream_id) || 0;
|
2021-06-25 15:16:29 +02:00
|
|
|
|
|
|
|
// If the user is attempting to do a wildcard mention in a large
|
2023-11-15 03:55:43 +01:00
|
|
|
// stream, check if they permission to do so. If yes, warn them
|
|
|
|
// if they haven't acknowledged the wildcard warning yet.
|
2023-11-24 16:10:03 +01:00
|
|
|
if (opts.stream_wildcard_mention !== null && subscriber_count > wildcard_mention_threshold) {
|
|
|
|
if (!wildcard_mention_policy_authorizes_user()) {
|
2023-11-21 20:12:13 +01:00
|
|
|
const new_row = render_wildcard_mention_not_allowed_error({
|
|
|
|
banner_type: compose_banner.ERROR,
|
|
|
|
classname: compose_banner.CLASSNAMES.wildcards_not_allowed,
|
|
|
|
stream_wildcard_mention: opts.stream_wildcard_mention,
|
|
|
|
});
|
|
|
|
compose_banner.append_compose_banner_to_banner_list(new_row, opts.$banner_container);
|
2021-06-25 15:16:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
if (!user_acknowledged_stream_wildcard) {
|
|
|
|
show_stream_wildcard_warnings(opts);
|
2021-06-25 15:16:29 +02:00
|
|
|
|
|
|
|
$("#compose-send-button").prop("disabled", false);
|
2021-11-30 06:26:05 +01:00
|
|
|
compose_ui.hide_compose_spinner();
|
2021-06-25 15:16:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// the message no longer contains @all or @everyone
|
2023-11-21 07:04:19 +01:00
|
|
|
clear_stream_wildcard_warnings(opts.$banner_container);
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
// at this point, the user has either acknowledged the warning or removed @all / @everyone
|
2023-11-21 07:04:19 +01:00
|
|
|
user_acknowledged_stream_wildcard = false;
|
2021-06-25 15:16:29 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function validation_error(error_type, stream_name) {
|
2023-05-02 11:05:37 +02:00
|
|
|
const $banner_container = $("#compose_banners");
|
2021-06-25 15:16:29 +02:00
|
|
|
switch (error_type) {
|
|
|
|
case "does-not-exist":
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_stream_does_not_exist_error(stream_name);
|
2021-06-25 15:16:29 +02:00
|
|
|
return false;
|
|
|
|
case "error":
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "Error checking subscription."}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.subscription_error,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2023-07-19 16:09:53 +02:00
|
|
|
$("#compose_select_recipient_widget_wrapper"),
|
2021-06-25 15:16:29 +02:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
case "not-subscribed": {
|
2023-04-01 01:42:40 +02:00
|
|
|
if (
|
|
|
|
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.user_not_subscribed)}`)
|
|
|
|
.length
|
|
|
|
) {
|
2022-08-23 00:12:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
2021-06-25 15:16:29 +02:00
|
|
|
const sub = stream_data.get_sub(stream_name);
|
2022-08-23 00:12:29 +02:00
|
|
|
const new_row = render_compose_banner({
|
2022-08-30 22:24:54 +02:00
|
|
|
banner_type: compose_banner.ERROR,
|
2022-08-23 00:12:29 +02:00
|
|
|
banner_text: $t({
|
|
|
|
defaultMessage:
|
|
|
|
"You're not subscribed to this stream. You will not be notified if other users reply to your message.",
|
|
|
|
}),
|
|
|
|
button_text: stream_data.can_toggle_subscription(sub)
|
|
|
|
? $t({defaultMessage: "Subscribe"})
|
|
|
|
: null,
|
2022-08-30 22:24:54 +02:00
|
|
|
classname: compose_banner.CLASSNAMES.user_not_subscribed,
|
2022-08-23 00:12:29 +02:00
|
|
|
// The message cannot be sent until the user subscribes to the stream, so
|
|
|
|
// closing the banner would be more confusing than helpful.
|
|
|
|
hide_close_button: true,
|
2021-06-25 15:16:29 +02:00
|
|
|
});
|
2023-05-02 11:05:37 +02:00
|
|
|
compose_banner.append_compose_banner_to_banner_list(new_row, $banner_container);
|
2021-06-25 15:16:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function validate_stream_message_address_info(stream_name) {
|
2021-11-23 00:37:45 +01:00
|
|
|
if (stream_data.is_subscribed_by_name(stream_name)) {
|
2021-06-25 15:16:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
const autosubscribe = page_params.narrow_stream !== undefined;
|
|
|
|
const error_type = check_unsubscribed_stream_for_send(stream_name, autosubscribe);
|
|
|
|
return validation_error(error_type, stream_name);
|
|
|
|
}
|
|
|
|
|
2023-05-04 15:43:44 +02:00
|
|
|
function validate_stream_message(scheduling_message) {
|
2023-05-26 02:48:11 +02:00
|
|
|
const stream_id = compose_state.stream_id();
|
2023-05-02 11:05:37 +02:00
|
|
|
const $banner_container = $("#compose_banners");
|
2023-09-26 20:28:39 +02:00
|
|
|
if (stream_id === undefined) {
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "Please specify a stream."}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.missing_stream,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2023-07-19 16:09:53 +02:00
|
|
|
$("#compose_select_recipient_widget_wrapper"),
|
2021-06-25 15:16:29 +02:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (page_params.realm_mandatory_topics) {
|
|
|
|
const topic = compose_state.topic();
|
2022-03-08 11:52:29 +01:00
|
|
|
// TODO: We plan to migrate the empty topic to only using the
|
|
|
|
// `""` representation for i18n reasons, but have not yet done so.
|
|
|
|
if (topic === "" || topic === "(no topic)") {
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "Topics are required in this organization."}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.topic_missing,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2023-11-02 19:29:54 +01:00
|
|
|
$("input#stream_message_recipient_topic"),
|
2021-06-25 15:16:29 +02:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-26 02:48:11 +02:00
|
|
|
const sub = stream_data.get_sub_by_id(stream_id);
|
2021-06-25 15:16:29 +02:00
|
|
|
if (!sub) {
|
2023-05-26 02:48:11 +02:00
|
|
|
return validation_error("does-not-exist", stream_id);
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
2021-12-27 13:03:26 +01:00
|
|
|
if (!stream_data.can_post_messages_in_stream(sub)) {
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({
|
2021-12-27 13:03:26 +01:00
|
|
|
defaultMessage: "You do not have permission to post in this stream.",
|
|
|
|
}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.no_post_permissions,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2021-12-27 13:03:26 +01:00
|
|
|
);
|
2021-06-25 15:16:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-11-21 07:04:19 +01:00
|
|
|
const stream_wildcard_mention = util.find_stream_wildcard_mentions(
|
|
|
|
compose_state.message_content(),
|
|
|
|
);
|
2021-06-25 15:16:29 +02:00
|
|
|
|
2021-12-22 19:30:36 +01:00
|
|
|
if (
|
2023-05-26 02:48:11 +02:00
|
|
|
!validate_stream_message_address_info(sub.name) ||
|
2023-05-04 15:43:44 +02:00
|
|
|
!validate_stream_message_mentions({
|
|
|
|
stream_id: sub.stream_id,
|
|
|
|
$banner_container,
|
2023-11-21 07:04:19 +01:00
|
|
|
stream_wildcard_mention,
|
2023-05-04 15:43:44 +02:00
|
|
|
scheduling_message,
|
|
|
|
})
|
2021-12-22 19:30:36 +01:00
|
|
|
) {
|
|
|
|
return false;
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The function checks whether the recipients are users of the realm or cross realm users (bots
|
|
|
|
// for now)
|
|
|
|
function validate_private_message() {
|
|
|
|
const user_ids = compose_pm_pill.get_user_ids();
|
2023-05-02 11:05:37 +02:00
|
|
|
const $banner_container = $("#compose_banners");
|
2021-06-25 15:16:29 +02:00
|
|
|
|
|
|
|
if (
|
2022-11-04 15:17:28 +01:00
|
|
|
page_params.realm_private_message_policy ===
|
|
|
|
settings_config.private_message_policy_values.disabled.code &&
|
2021-06-25 15:16:29 +02:00
|
|
|
(user_ids.length !== 1 || !people.get_by_user_id(user_ids[0]).is_bot)
|
|
|
|
) {
|
|
|
|
// Unless we're composing to a bot
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2023-01-24 19:49:56 +01:00
|
|
|
$t({defaultMessage: "Direct messages are disabled in this organization."}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.private_messages_disabled,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2021-06-25 15:16:29 +02:00
|
|
|
$("#private_message_recipient"),
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compose_state.private_message_recipient().length === 0) {
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "Please specify at least one valid recipient."}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.missing_private_message_recipient,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2021-06-25 15:16:29 +02:00
|
|
|
$("#private_message_recipient"),
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
} else if (page_params.realm_is_zephyr_mirror_realm) {
|
|
|
|
// For Zephyr mirroring realms, the frontend doesn't know which users exist
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const invalid_recipients = get_invalid_recipient_emails();
|
|
|
|
|
|
|
|
let context = {};
|
|
|
|
if (invalid_recipients.length === 1) {
|
|
|
|
context = {recipient: invalid_recipients.join(",")};
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "The recipient {recipient} is not valid."}, context),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.invalid_recipient,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2021-06-25 15:16:29 +02:00
|
|
|
$("#private_message_recipient"),
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
} else if (invalid_recipients.length > 1) {
|
|
|
|
context = {recipients: invalid_recipients.join(",")};
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "The recipients {recipients} are not valid."}, context),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.invalid_recipients,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2021-06-25 15:16:29 +02:00
|
|
|
$("#private_message_recipient"),
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const user_id of user_ids) {
|
|
|
|
if (!people.is_person_active(user_id)) {
|
|
|
|
context = {full_name: people.get_by_user_id(user_id).full_name};
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({defaultMessage: "You cannot send messages to deactivated users."}, context),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.deactivated_user,
|
2023-05-02 11:05:37 +02:00
|
|
|
$banner_container,
|
2021-06-25 15:16:29 +02:00
|
|
|
$("#private_message_recipient"),
|
|
|
|
);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-07-10 19:33:45 +02:00
|
|
|
export function check_overflow_text() {
|
2022-03-16 01:31:01 +01:00
|
|
|
// This function is called when typing every character in the
|
|
|
|
// compose box, so it's important that it not doing anything
|
|
|
|
// expensive.
|
2021-07-07 12:13:19 +02:00
|
|
|
const text = compose_state.message_content();
|
|
|
|
const max_length = page_params.max_message_length;
|
2023-11-01 18:43:48 +01:00
|
|
|
const $indicator = $("#compose-limit-indicator");
|
2021-07-07 12:13:19 +02:00
|
|
|
|
|
|
|
if (text.length > max_length) {
|
2022-01-25 11:36:19 +01:00
|
|
|
$indicator.addClass("over_limit");
|
2023-11-02 19:29:54 +01:00
|
|
|
$("textarea#compose-textarea").addClass("over_limit");
|
2023-11-07 18:51:28 +01:00
|
|
|
$indicator.html(
|
|
|
|
render_compose_limit_indicator({
|
|
|
|
text_length: text.length,
|
|
|
|
max_length,
|
|
|
|
}),
|
|
|
|
);
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t(
|
2021-07-10 19:33:45 +02:00
|
|
|
{
|
|
|
|
defaultMessage:
|
2021-07-28 01:03:19 +02:00
|
|
|
"Message length shouldn't be greater than {max_length} characters.",
|
2021-07-10 19:33:45 +02:00
|
|
|
},
|
|
|
|
{max_length},
|
|
|
|
),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.message_too_long,
|
2023-05-02 11:05:37 +02:00
|
|
|
$("#compose_banners"),
|
2021-07-10 19:33:45 +02:00
|
|
|
);
|
2023-11-10 21:00:25 +01:00
|
|
|
set_message_too_long(true);
|
2021-07-07 12:13:19 +02:00
|
|
|
} else if (text.length > 0.9 * max_length) {
|
2022-01-25 11:36:19 +01:00
|
|
|
$indicator.removeClass("over_limit");
|
2023-11-02 19:29:54 +01:00
|
|
|
$("textarea#compose-textarea").removeClass("over_limit");
|
2023-11-07 18:51:28 +01:00
|
|
|
$indicator.html(
|
|
|
|
render_compose_limit_indicator({
|
|
|
|
text_length: text.length,
|
|
|
|
max_length,
|
|
|
|
}),
|
|
|
|
);
|
2023-11-10 21:00:25 +01:00
|
|
|
set_message_too_long(false);
|
2023-04-01 01:42:40 +02:00
|
|
|
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.message_too_long)}`).remove();
|
2021-07-07 12:13:19 +02:00
|
|
|
} else {
|
2022-01-25 11:36:19 +01:00
|
|
|
$indicator.text("");
|
2023-11-02 19:29:54 +01:00
|
|
|
$("textarea#compose-textarea").removeClass("over_limit");
|
2021-07-07 12:13:19 +02:00
|
|
|
|
2023-11-10 21:00:25 +01:00
|
|
|
set_message_too_long(false);
|
2023-04-01 01:42:40 +02:00
|
|
|
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.message_too_long)}`).remove();
|
2021-07-07 12:13:19 +02:00
|
|
|
}
|
2022-07-29 14:30:39 +02:00
|
|
|
|
|
|
|
return text.length;
|
2021-07-07 12:13:19 +02:00
|
|
|
}
|
|
|
|
|
2023-03-28 08:35:22 +02:00
|
|
|
export function validate_message_length() {
|
2021-07-10 19:33:45 +02:00
|
|
|
if (compose_state.message_content().length > page_params.max_message_length) {
|
2023-11-02 19:29:54 +01:00
|
|
|
$("textarea#compose-textarea").addClass("flash");
|
|
|
|
setTimeout(() => $("textarea#compose-textarea").removeClass("flash"), 1500);
|
2021-07-10 19:33:45 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-04 15:43:44 +02:00
|
|
|
export function validate(scheduling_message) {
|
2021-06-25 15:16:29 +02:00
|
|
|
const message_content = compose_state.message_content();
|
|
|
|
if (/^\s*$/.test(message_content)) {
|
2023-11-02 19:29:54 +01:00
|
|
|
$("textarea#compose-textarea").toggleClass("invalid", true);
|
2021-06-25 15:16:29 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($("#zephyr-mirror-error").is(":visible")) {
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.show_error_message(
|
2022-08-19 22:24:06 +02:00
|
|
|
$t({
|
2021-06-25 15:16:29 +02:00
|
|
|
defaultMessage:
|
|
|
|
"You need to be running Zephyr mirroring in order to send messages!",
|
|
|
|
}),
|
2022-08-30 22:24:54 +02:00
|
|
|
compose_banner.CLASSNAMES.zephyr_not_running,
|
2023-05-02 11:05:37 +02:00
|
|
|
$("#compose_banners"),
|
2021-06-25 15:16:29 +02:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
2023-03-28 08:35:22 +02:00
|
|
|
if (!validate_message_length()) {
|
2021-07-07 12:13:19 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-25 15:16:29 +02:00
|
|
|
if (compose_state.get_message_type() === "private") {
|
|
|
|
return validate_private_message();
|
|
|
|
}
|
2023-05-04 15:43:44 +02:00
|
|
|
return validate_stream_message(scheduling_message);
|
2021-06-25 15:16:29 +02:00
|
|
|
}
|
2023-10-12 02:22:29 +02:00
|
|
|
|
|
|
|
export function convert_mentions_to_silent_in_direct_messages(mention_text, full_name, user_id) {
|
|
|
|
if (compose_state.get_message_type() !== "private") {
|
|
|
|
return mention_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
const recipient_user_id = compose_pm_pill.get_user_ids();
|
|
|
|
if (recipient_user_id.toString() !== user_id.toString()) {
|
|
|
|
return mention_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
const mention_str = people.get_mention_syntax(full_name, user_id, false);
|
|
|
|
const silent_mention_str = people.get_mention_syntax(full_name, user_id, true);
|
|
|
|
mention_text = mention_text.replace(mention_str, silent_mention_str);
|
|
|
|
// also replace other mentions...
|
|
|
|
compose_ui.replace_syntax(mention_str, silent_mention_str);
|
|
|
|
|
|
|
|
return mention_text;
|
|
|
|
}
|