mirror of https://github.com/zulip/zulip.git
compose_validate: Convert module to TypeScript.
This commit is contained in:
parent
fd3c7728fc
commit
533a6153b2
|
@ -80,7 +80,7 @@ EXEMPT_FILES = make_set(
|
|||
"web/src/compose_textarea.ts",
|
||||
"web/src/compose_tooltips.js",
|
||||
"web/src/compose_ui.ts",
|
||||
"web/src/compose_validate.js",
|
||||
"web/src/compose_validate.ts",
|
||||
"web/src/composebox_typeahead.js",
|
||||
"web/src/condense.ts",
|
||||
"web/src/confirm_dialog.ts",
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import $ from "jquery";
|
||||
import assert from "minimalistic-assert";
|
||||
import {z} from "zod";
|
||||
|
||||
import * as resolved_topic from "../shared/src/resolved_topic";
|
||||
import render_compose_banner from "../templates/compose_banner/compose_banner.hbs";
|
||||
|
@ -26,6 +28,8 @@ import * as settings_data from "./settings_data";
|
|||
import {current_user, realm} from "./state_data";
|
||||
import * as stream_data from "./stream_data";
|
||||
import * as sub_store from "./sub_store";
|
||||
import type {StreamSubscription} from "./sub_store";
|
||||
import type {UserOrMention} from "./typeahead_helper";
|
||||
import * as util from "./util";
|
||||
|
||||
let user_acknowledged_stream_wildcard = false;
|
||||
|
@ -33,31 +37,42 @@ let upload_in_progress = false;
|
|||
let message_too_long = false;
|
||||
let recipient_disallowed = false;
|
||||
|
||||
type StreamWildcardOptions = {
|
||||
stream_id: number;
|
||||
$banner_container: JQuery;
|
||||
scheduling_message: boolean;
|
||||
stream_wildcard_mention: string | null;
|
||||
};
|
||||
|
||||
export let wildcard_mention_threshold = 15;
|
||||
|
||||
export function set_upload_in_progress(status) {
|
||||
const server_subscription_exists_schema = z.object({
|
||||
subscribed: z.boolean(),
|
||||
});
|
||||
|
||||
export function set_upload_in_progress(status: boolean): void {
|
||||
upload_in_progress = status;
|
||||
update_send_button_status();
|
||||
}
|
||||
|
||||
function set_message_too_long(status) {
|
||||
function set_message_too_long(status: boolean): void {
|
||||
message_too_long = status;
|
||||
update_send_button_status();
|
||||
}
|
||||
|
||||
export function set_recipient_disallowed(status) {
|
||||
export function set_recipient_disallowed(status: boolean): void {
|
||||
recipient_disallowed = status;
|
||||
update_send_button_status();
|
||||
}
|
||||
|
||||
function update_send_button_status() {
|
||||
function update_send_button_status(): void {
|
||||
$(".message-send-controls").toggleClass(
|
||||
"disabled-message-send-controls",
|
||||
message_too_long || upload_in_progress || recipient_disallowed,
|
||||
);
|
||||
}
|
||||
|
||||
export function get_disabled_send_tooltip() {
|
||||
export function get_disabled_send_tooltip(): string {
|
||||
if (message_too_long) {
|
||||
return $t({defaultMessage: "Message length shouldn't be greater than 10000 characters."});
|
||||
} else if (upload_in_progress) {
|
||||
|
@ -66,7 +81,7 @@ export function get_disabled_send_tooltip() {
|
|||
return "";
|
||||
}
|
||||
|
||||
export function needs_subscribe_warning(user_id, stream_id) {
|
||||
export function needs_subscribe_warning(user_id: number, stream_id: number): boolean {
|
||||
// This returns true if all of these conditions are met:
|
||||
// * the user is valid
|
||||
// * the user is not already subscribed to the stream
|
||||
|
@ -100,7 +115,7 @@ export function needs_subscribe_warning(user_id, stream_id) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function get_stream_id_for_textarea($textarea) {
|
||||
function get_stream_id_for_textarea($textarea: JQuery<HTMLTextAreaElement>): number | undefined {
|
||||
// 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.
|
||||
|
@ -123,7 +138,10 @@ function get_stream_id_for_textarea($textarea) {
|
|||
return compose_state.stream_id();
|
||||
}
|
||||
|
||||
export function warn_if_private_stream_is_linked(linked_stream, $textarea) {
|
||||
export function warn_if_private_stream_is_linked(
|
||||
linked_stream: StreamSubscription,
|
||||
$textarea: JQuery<HTMLTextAreaElement>,
|
||||
): void {
|
||||
const stream_id = get_stream_id_for_textarea($textarea);
|
||||
|
||||
if (!stream_id) {
|
||||
|
@ -184,20 +202,21 @@ export function warn_if_private_stream_is_linked(linked_stream, $textarea) {
|
|||
}
|
||||
}
|
||||
|
||||
export function warn_if_mentioning_unsubscribed_user(mentioned, $textarea) {
|
||||
export function warn_if_mentioning_unsubscribed_user(
|
||||
mentioned: UserOrMention,
|
||||
$textarea: JQuery<HTMLTextAreaElement>,
|
||||
): void {
|
||||
// Disable for Zephyr mirroring realms, since we never have subscriber lists there
|
||||
if (realm.realm_is_zephyr_mirror_realm) {
|
||||
return;
|
||||
}
|
||||
|
||||
const user_id = mentioned.user_id;
|
||||
|
||||
if (mentioned.is_broadcast) {
|
||||
return; // don't check if @all/@everyone/@stream
|
||||
}
|
||||
const user_id = mentioned.user_id;
|
||||
|
||||
const stream_id = get_stream_id_for_textarea($textarea);
|
||||
|
||||
if (!stream_id) {
|
||||
return;
|
||||
}
|
||||
|
@ -239,12 +258,12 @@ export function warn_if_mentioning_unsubscribed_user(mentioned, $textarea) {
|
|||
// 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.
|
||||
export function clear_topic_resolved_warning() {
|
||||
export function clear_topic_resolved_warning(): void {
|
||||
compose_state.set_recipient_viewed_topic_resolved_banner(false);
|
||||
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.topic_resolved)}`).remove();
|
||||
}
|
||||
|
||||
export function warn_if_topic_resolved(topic_changed) {
|
||||
export function warn_if_topic_resolved(topic_changed: boolean): void {
|
||||
// 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.
|
||||
|
@ -297,8 +316,9 @@ export function warn_if_topic_resolved(topic_changed) {
|
|||
}
|
||||
}
|
||||
|
||||
export function warn_if_in_search_view() {
|
||||
if (narrow_state.filter() && !narrow_state.filter().supports_collapsing_recipients()) {
|
||||
export function warn_if_in_search_view(): void {
|
||||
const filter = narrow_state.filter();
|
||||
if (filter && !filter.supports_collapsing_recipients()) {
|
||||
const context = {
|
||||
banner_type: compose_banner.WARNING,
|
||||
banner_text: $t({
|
||||
|
@ -314,7 +334,7 @@ export function warn_if_in_search_view() {
|
|||
}
|
||||
}
|
||||
|
||||
function show_stream_wildcard_warnings(opts) {
|
||||
function show_stream_wildcard_warnings(opts: StreamWildcardOptions): void {
|
||||
const subscriber_count = peer_data.get_subscriber_count(opts.stream_id) || 0;
|
||||
const stream_name = sub_store.maybe_get_stream_name(opts.stream_id);
|
||||
const is_edit_container = opts.$banner_container.closest(".edit_form_banners").length > 0;
|
||||
|
@ -357,16 +377,16 @@ function show_stream_wildcard_warnings(opts) {
|
|||
user_acknowledged_stream_wildcard = false;
|
||||
}
|
||||
|
||||
export function clear_stream_wildcard_warnings($banner_container) {
|
||||
export function clear_stream_wildcard_warnings($banner_container: JQuery): void {
|
||||
const classname = compose_banner.CLASSNAMES.wildcard_warning;
|
||||
$banner_container.find(`.${CSS.escape(classname)}`).remove();
|
||||
}
|
||||
|
||||
export function set_user_acknowledged_stream_wildcard_flag(value) {
|
||||
export function set_user_acknowledged_stream_wildcard_flag(value: boolean): void {
|
||||
user_acknowledged_stream_wildcard = value;
|
||||
}
|
||||
|
||||
export function get_invalid_recipient_emails() {
|
||||
export function get_invalid_recipient_emails(): string[] {
|
||||
const private_recipients = util.extract_pm_recipients(
|
||||
compose_state.private_message_recipient(),
|
||||
);
|
||||
|
@ -377,7 +397,10 @@ export function get_invalid_recipient_emails() {
|
|||
return invalid_recipients;
|
||||
}
|
||||
|
||||
function check_unsubscribed_stream_for_send(stream_name, autosubscribe) {
|
||||
function check_unsubscribed_stream_for_send(
|
||||
stream_name: string,
|
||||
autosubscribe: boolean,
|
||||
): string | undefined {
|
||||
let result;
|
||||
if (!autosubscribe) {
|
||||
return "not-subscribed";
|
||||
|
@ -387,18 +410,19 @@ function check_unsubscribed_stream_for_send(stream_name, autosubscribe) {
|
|||
// *Synchronously* try to subscribe to the stream before sending
|
||||
// the message. This is deprecated and we hope to remove it; see
|
||||
// #4650.
|
||||
channel.post({
|
||||
void channel.post({
|
||||
url: "/json/subscriptions/exists",
|
||||
data: {stream: stream_name, autosubscribe: true},
|
||||
async: false,
|
||||
success(data) {
|
||||
if (data.subscribed) {
|
||||
const clean_data = server_subscription_exists_schema.parse(data);
|
||||
if (clean_data.subscribed) {
|
||||
result = "subscribed";
|
||||
} else {
|
||||
result = "not-subscribed";
|
||||
}
|
||||
},
|
||||
error(xhr) {
|
||||
error(xhr: JQuery.jqXHR) {
|
||||
if (xhr.status === 404) {
|
||||
result = "does-not-exist";
|
||||
} else {
|
||||
|
@ -409,14 +433,18 @@ function check_unsubscribed_stream_for_send(stream_name, autosubscribe) {
|
|||
return result;
|
||||
}
|
||||
|
||||
function is_recipient_large_stream() {
|
||||
return (
|
||||
compose_state.stream_id() &&
|
||||
peer_data.get_subscriber_count(compose_state.stream_id()) > wildcard_mention_threshold
|
||||
);
|
||||
function is_recipient_large_stream(): boolean {
|
||||
const stream_id = compose_state.stream_id();
|
||||
if (stream_id === undefined) {
|
||||
return false;
|
||||
}
|
||||
return peer_data.get_subscriber_count(stream_id) > wildcard_mention_threshold;
|
||||
}
|
||||
|
||||
export function topic_participant_count_more_than_threshold(stream_id, topic) {
|
||||
export function topic_participant_count_more_than_threshold(
|
||||
stream_id: number,
|
||||
topic: string,
|
||||
): boolean {
|
||||
// Topic participants:
|
||||
// Users who either sent or reacted to the messages in the topic.
|
||||
const participant_ids = new Set();
|
||||
|
@ -455,17 +483,15 @@ export function topic_participant_count_more_than_threshold(stream_id, topic) {
|
|||
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(),
|
||||
)
|
||||
);
|
||||
function is_recipient_large_topic(): boolean {
|
||||
const stream_id = compose_state.stream_id();
|
||||
if (stream_id === undefined) {
|
||||
return false;
|
||||
}
|
||||
return topic_participant_count_more_than_threshold(stream_id, compose_state.topic());
|
||||
}
|
||||
|
||||
function wildcard_mention_policy_authorizes_user() {
|
||||
function wildcard_mention_policy_authorizes_user(): boolean {
|
||||
if (
|
||||
realm.realm_wildcard_mention_policy ===
|
||||
settings_config.wildcard_mention_policy_values.by_everyone.code
|
||||
|
@ -500,8 +526,8 @@ function wildcard_mention_policy_authorizes_user() {
|
|||
return true;
|
||||
}
|
||||
const person = people.get_by_user_id(current_user.user_id);
|
||||
const current_datetime = new Date(Date.now());
|
||||
const person_date_joined = new Date(person.date_joined);
|
||||
const current_datetime = new Date(Date.now()).getTime();
|
||||
const person_date_joined = new Date(person.date_joined).getTime();
|
||||
const days = (current_datetime - person_date_joined) / 1000 / 86400;
|
||||
|
||||
return days >= realm.realm_waiting_period_threshold && !current_user.is_guest;
|
||||
|
@ -509,19 +535,19 @@ function wildcard_mention_policy_authorizes_user() {
|
|||
return !current_user.is_guest;
|
||||
}
|
||||
|
||||
export function stream_wildcard_mention_allowed() {
|
||||
export function stream_wildcard_mention_allowed(): boolean {
|
||||
return !is_recipient_large_stream() || wildcard_mention_policy_authorizes_user();
|
||||
}
|
||||
|
||||
export function topic_wildcard_mention_allowed() {
|
||||
export function topic_wildcard_mention_allowed(): boolean {
|
||||
return !is_recipient_large_topic() || wildcard_mention_policy_authorizes_user();
|
||||
}
|
||||
|
||||
export function set_wildcard_mention_threshold(value) {
|
||||
export function set_wildcard_mention_threshold(value: number): void {
|
||||
wildcard_mention_threshold = value;
|
||||
}
|
||||
|
||||
export function validate_stream_message_mentions(opts) {
|
||||
export function validate_stream_message_mentions(opts: StreamWildcardOptions): boolean {
|
||||
const subscriber_count = peer_data.get_subscriber_count(opts.stream_id) || 0;
|
||||
|
||||
// If the user is attempting to do a wildcard mention in a large
|
||||
|
@ -558,7 +584,7 @@ export function validate_stream_message_mentions(opts) {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function validation_error(error_type, stream_name) {
|
||||
export function validation_error(error_type: string, stream_name: string): boolean {
|
||||
const $banner_container = $("#compose_banners");
|
||||
switch (error_type) {
|
||||
case "does-not-exist":
|
||||
|
@ -580,6 +606,8 @@ export function validation_error(error_type, stream_name) {
|
|||
return false;
|
||||
}
|
||||
const sub = stream_data.get_sub(stream_name);
|
||||
// We expect this to be a does-not-exist error if it was undefined.
|
||||
assert(sub !== undefined);
|
||||
const new_row_html = render_compose_banner({
|
||||
banner_type: compose_banner.ERROR,
|
||||
banner_text: $t({
|
||||
|
@ -601,16 +629,17 @@ export function validation_error(error_type, stream_name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function validate_stream_message_address_info(stream_name) {
|
||||
export function validate_stream_message_address_info(stream_name: string): boolean {
|
||||
if (stream_data.is_subscribed_by_name(stream_name)) {
|
||||
return true;
|
||||
}
|
||||
const autosubscribe = page_params.narrow_stream !== undefined;
|
||||
const error_type = check_unsubscribed_stream_for_send(stream_name, autosubscribe);
|
||||
assert(error_type !== undefined);
|
||||
return validation_error(error_type, stream_name);
|
||||
}
|
||||
|
||||
function validate_stream_message(scheduling_message) {
|
||||
function validate_stream_message(scheduling_message: boolean): boolean {
|
||||
const stream_id = compose_state.stream_id();
|
||||
const $banner_container = $("#compose_banners");
|
||||
if (stream_id === undefined) {
|
||||
|
@ -640,7 +669,7 @@ function validate_stream_message(scheduling_message) {
|
|||
|
||||
const sub = stream_data.get_sub_by_id(stream_id);
|
||||
if (!sub) {
|
||||
return validation_error("does-not-exist", stream_id);
|
||||
return validation_error("does-not-exist", stream_id.toString());
|
||||
}
|
||||
|
||||
if (!stream_data.can_post_messages_in_stream(sub)) {
|
||||
|
@ -675,7 +704,7 @@ function validate_stream_message(scheduling_message) {
|
|||
|
||||
// The function checks whether the recipients are users of the realm or cross realm users (bots
|
||||
// for now)
|
||||
function validate_private_message() {
|
||||
function validate_private_message(): boolean {
|
||||
const user_ids = compose_pm_pill.get_user_ids();
|
||||
const $banner_container = $("#compose_banners");
|
||||
|
||||
|
@ -744,7 +773,7 @@ function validate_private_message() {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function check_overflow_text() {
|
||||
export function check_overflow_text(): number {
|
||||
// This function is called when typing every character in the
|
||||
// compose box, so it's important that it not doing anything
|
||||
// expensive.
|
||||
|
@ -795,7 +824,7 @@ export function check_overflow_text() {
|
|||
return text.length;
|
||||
}
|
||||
|
||||
export function validate_message_length() {
|
||||
export function validate_message_length(): boolean {
|
||||
if (compose_state.message_content().length > realm.max_message_length) {
|
||||
$("textarea#compose-textarea").addClass("flash");
|
||||
setTimeout(() => $("textarea#compose-textarea").removeClass("flash"), 1500);
|
||||
|
@ -804,7 +833,7 @@ export function validate_message_length() {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function validate(scheduling_message) {
|
||||
export function validate(scheduling_message: boolean): boolean {
|
||||
const message_content = compose_state.message_content();
|
||||
if (/^\s*$/.test(message_content)) {
|
||||
$("textarea#compose-textarea").toggleClass("invalid", true);
|
||||
|
@ -832,7 +861,11 @@ export function validate(scheduling_message) {
|
|||
return validate_stream_message(scheduling_message);
|
||||
}
|
||||
|
||||
export function convert_mentions_to_silent_in_direct_messages(mention_text, full_name, user_id) {
|
||||
export function convert_mentions_to_silent_in_direct_messages(
|
||||
mention_text: string,
|
||||
full_name: string,
|
||||
user_id: number,
|
||||
): string {
|
||||
if (compose_state.get_message_type() !== "private") {
|
||||
return mention_text;
|
||||
}
|
|
@ -106,6 +106,7 @@ export const realm_schema = z.object({
|
|||
max_avatar_file_size_mib: z.number(),
|
||||
max_icon_file_size_mib: z.number(),
|
||||
max_logo_file_size_mib: z.number(),
|
||||
max_message_length: z.number(),
|
||||
max_topic_length: z.number(),
|
||||
realm_add_custom_emoji_policy: z.number(),
|
||||
realm_allow_edit_history: z.boolean(),
|
||||
|
@ -150,6 +151,7 @@ export const realm_schema = z.object({
|
|||
realm_jitsi_server_url: z.nullable(z.string()),
|
||||
realm_logo_source: z.string(),
|
||||
realm_logo_url: z.string(),
|
||||
realm_mandatory_topics: z.boolean(),
|
||||
realm_move_messages_between_streams_policy: z.number(),
|
||||
realm_name_changes_disabled: z.boolean(),
|
||||
realm_name: z.string(),
|
||||
|
@ -166,6 +168,7 @@ export const realm_schema = z.object({
|
|||
realm_user_group_edit_policy: z.number(),
|
||||
realm_video_chat_provider: z.number(),
|
||||
realm_waiting_period_threshold: z.number(),
|
||||
realm_wildcard_mention_policy: z.number(),
|
||||
server_avatar_changes_disabled: z.boolean(),
|
||||
server_jitsi_server_url: z.nullable(z.string()),
|
||||
server_name_changes_disabled: z.boolean(),
|
||||
|
|
Loading…
Reference in New Issue