mirror of
https://github.com/zulip/zulip.git
synced 2025-11-01 20:44:04 +00:00
message: Differentiate between new local messages and server messages.
This commit is contained in:
@@ -14,6 +14,7 @@ import * as echo_state from "./echo_state.ts";
|
||||
import * as hash_util from "./hash_util.ts";
|
||||
import * as local_message from "./local_message.ts";
|
||||
import * as markdown from "./markdown.ts";
|
||||
import type {InsertNewMessagesOpts} from "./message_events.ts";
|
||||
import * as message_events_util from "./message_events_util.ts";
|
||||
import * as message_list_data_cache from "./message_list_data_cache.ts";
|
||||
import * as message_lists from "./message_lists.ts";
|
||||
@@ -87,7 +88,7 @@ export type LocalMessage = MessageRequestObject & {
|
||||
content_type: "text/html";
|
||||
sender_email: string;
|
||||
sender_full_name: string;
|
||||
avatar_url?: string | null | undefined;
|
||||
avatar_url: string;
|
||||
timestamp: number;
|
||||
local_id: string;
|
||||
locally_echoed: boolean;
|
||||
@@ -253,11 +254,7 @@ export function track_local_message(message: Message): void {
|
||||
export function insert_local_message(
|
||||
message_request: MessageRequest,
|
||||
local_id_float: number,
|
||||
insert_new_messages: (
|
||||
messages: LocalMessage[],
|
||||
send_by_this_client: boolean,
|
||||
deliver_locally: boolean,
|
||||
) => Message[],
|
||||
insert_new_messages: (opts: InsertNewMessagesOpts) => Message[],
|
||||
): Message {
|
||||
// Shallow clone of message request object that is turned into something suitable
|
||||
// for zulip.js:add_message
|
||||
@@ -285,7 +282,11 @@ export function insert_local_message(
|
||||
|
||||
local_message.display_recipient = build_display_recipient(local_message);
|
||||
|
||||
const [message] = insert_new_messages([local_message], true, true);
|
||||
const [message] = insert_new_messages({
|
||||
type: "local_message",
|
||||
raw_messages: [local_message],
|
||||
sent_by_this_client: true,
|
||||
});
|
||||
assert(message !== undefined);
|
||||
|
||||
return message;
|
||||
@@ -297,11 +298,7 @@ export function is_slash_command(content: string): boolean {
|
||||
|
||||
export let try_deliver_locally = (
|
||||
message_request: MessageRequest,
|
||||
insert_new_messages: (
|
||||
messages: LocalMessage[],
|
||||
send_by_this_client: boolean,
|
||||
deliver_locally: boolean,
|
||||
) => Message[],
|
||||
insert_new_messages: (opts: InsertNewMessagesOpts) => Message[],
|
||||
): Message | undefined => {
|
||||
// Checks if the message request can be locally echoed, and if so,
|
||||
// adds a local echoed copy of the message to appropriate message lists.
|
||||
|
||||
@@ -16,6 +16,7 @@ import * as compose_validate from "./compose_validate.ts";
|
||||
import * as direct_message_group_data from "./direct_message_group_data.ts";
|
||||
import * as drafts from "./drafts.ts";
|
||||
import * as echo from "./echo.ts";
|
||||
import type {LocalMessage} from "./echo.ts";
|
||||
import type {Filter} from "./filter.ts";
|
||||
import * as lightbox from "./lightbox.ts";
|
||||
import * as message_edit from "./message_edit.ts";
|
||||
@@ -212,7 +213,11 @@ export let update_views_filtered_on_message_property = (
|
||||
messages_to_remove.delete(raw_message.id);
|
||||
const message = message_store.get(raw_message.id);
|
||||
messages_to_add.push(
|
||||
message ?? message_helper.process_new_message(raw_message),
|
||||
message ??
|
||||
message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message,
|
||||
}),
|
||||
);
|
||||
}
|
||||
msg_list.data.remove([...messages_to_remove]);
|
||||
@@ -243,7 +248,10 @@ export let update_views_filtered_on_message_property = (
|
||||
// we reach here but `message_helper.process_new_message`
|
||||
// already handles that case.
|
||||
for (const raw_message of parsed_data.messages) {
|
||||
message_helper.process_new_message(raw_message);
|
||||
message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message,
|
||||
});
|
||||
}
|
||||
update_views_filtered_on_message_property(
|
||||
message_ids,
|
||||
@@ -292,14 +300,37 @@ export function rewire_update_views_filtered_on_message_property(
|
||||
update_views_filtered_on_message_property = value;
|
||||
}
|
||||
|
||||
export function insert_new_messages(
|
||||
raw_messages: RawMessage[],
|
||||
sent_by_this_client: boolean,
|
||||
deliver_locally: boolean,
|
||||
): Message[] {
|
||||
const messages = raw_messages.map((raw_message) =>
|
||||
message_helper.process_new_message(raw_message, deliver_locally),
|
||||
);
|
||||
export type InsertNewMessagesOpts = {
|
||||
sent_by_this_client: boolean;
|
||||
} & (
|
||||
| {
|
||||
type: "server_message";
|
||||
raw_messages: RawMessage[];
|
||||
}
|
||||
| {
|
||||
type: "local_message";
|
||||
raw_messages: LocalMessage[];
|
||||
}
|
||||
);
|
||||
|
||||
export function insert_new_messages(opts: InsertNewMessagesOpts): Message[] {
|
||||
const deliver_locally = opts.type === "local_message";
|
||||
let messages: Message[] = [];
|
||||
if (opts.type === "server_message") {
|
||||
messages = opts.raw_messages.map((raw_message) =>
|
||||
message_helper.process_new_message({
|
||||
type: opts.type,
|
||||
raw_message,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
messages = opts.raw_messages.map((raw_message) =>
|
||||
message_helper.process_new_message({
|
||||
type: opts.type,
|
||||
raw_message,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const any_untracked_unread_messages = unread.process_loaded_messages(messages, false);
|
||||
direct_message_group_data.process_loaded_messages(messages);
|
||||
@@ -355,7 +386,7 @@ export function insert_new_messages(
|
||||
// sent_by_this_client will be true if ANY of the messages
|
||||
// were sent by this client; notifications.notify_local_mixes
|
||||
// will filter out any not sent by us.
|
||||
if (sent_by_this_client) {
|
||||
if (opts.sent_by_this_client) {
|
||||
compose_notifications.notify_local_mixes(messages, need_user_to_scroll, {
|
||||
narrow_to_recipient(message_id) {
|
||||
message_view.narrow_by_topic(message_id, {trigger: "outside_current_view"});
|
||||
|
||||
@@ -147,7 +147,10 @@ function process_result(data: MessageFetchResponse, opts: MessageFetchOptions):
|
||||
const raw_messages = data.messages;
|
||||
|
||||
const messages = raw_messages.map((raw_message) =>
|
||||
message_helper.process_new_message(raw_message),
|
||||
message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message,
|
||||
}),
|
||||
);
|
||||
const has_found_oldest = opts.msg_list?.data.fetch_status.has_found_oldest() ?? false;
|
||||
const has_found_newest = opts.msg_list?.data.fetch_status.has_found_newest() ?? false;
|
||||
|
||||
@@ -2,7 +2,8 @@ import _ from "lodash";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
import * as alert_words from "./alert_words.ts";
|
||||
import * as blueslip from "./blueslip.ts";
|
||||
import type {LocalMessage} from "./echo.ts";
|
||||
import {electron_bridge} from "./electron_bridge.ts";
|
||||
import * as message_store from "./message_store.ts";
|
||||
import type {Message, RawMessage} from "./message_store.ts";
|
||||
import * as message_user_ids from "./message_user_ids.ts";
|
||||
@@ -15,41 +16,47 @@ import * as stream_topic_history from "./stream_topic_history.ts";
|
||||
import * as user_status from "./user_status.ts";
|
||||
import * as util from "./util.ts";
|
||||
|
||||
export function process_new_message(raw_message: RawMessage, deliver_locally = false): Message {
|
||||
export type NewMessage =
|
||||
| {
|
||||
type: "server_message";
|
||||
raw_message: RawMessage;
|
||||
}
|
||||
| {
|
||||
type: "local_message";
|
||||
raw_message: LocalMessage;
|
||||
};
|
||||
|
||||
export function process_new_message(opts: NewMessage): Message {
|
||||
// Call this function when processing a new message. After
|
||||
// a message is processed and inserted into the message store
|
||||
// cache, most modules use message_store.get to look at
|
||||
// messages.
|
||||
const cached_msg = message_store.get_cached_message(raw_message.id);
|
||||
const cached_msg = message_store.get_cached_message(opts.raw_message.id);
|
||||
if (cached_msg !== undefined) {
|
||||
// Copy the match topic and content over if they exist on
|
||||
// the new message
|
||||
if (util.get_match_topic(raw_message) !== undefined) {
|
||||
util.set_match_data(cached_msg, raw_message);
|
||||
// the new message. Local messages will never have match metadata,
|
||||
// since we need the server to calculate it.
|
||||
if (
|
||||
opts.type === "server_message" &&
|
||||
util.get_match_topic(opts.raw_message) !== undefined
|
||||
) {
|
||||
util.set_match_data(cached_msg, opts.raw_message);
|
||||
}
|
||||
return cached_msg;
|
||||
}
|
||||
|
||||
const message_with_booleans =
|
||||
message_store.convert_raw_message_to_message_with_booleans(raw_message);
|
||||
people.extract_people_from_message(message_with_booleans);
|
||||
const message_with_booleans = message_store.convert_raw_message_to_message_with_booleans(opts);
|
||||
people.extract_people_from_message(message_with_booleans.message);
|
||||
|
||||
const sent_by_me = people.is_my_user_id(message_with_booleans.sender_id);
|
||||
people.maybe_incr_recipient_count({...message_with_booleans, sent_by_me});
|
||||
const sent_by_me = people.is_my_user_id(message_with_booleans.message.sender_id);
|
||||
people.maybe_incr_recipient_count({...message_with_booleans.message, sent_by_me});
|
||||
|
||||
let status_emoji_info;
|
||||
const sender = people.maybe_get_user_by_id(message_with_booleans.sender_id);
|
||||
const sender = people.maybe_get_user_by_id(message_with_booleans.message.sender_id);
|
||||
if (sender) {
|
||||
message_with_booleans.sender_full_name = sender.full_name;
|
||||
message_with_booleans.sender_email = sender.email;
|
||||
status_emoji_info = user_status.get_status_emoji(message_with_booleans.sender_id);
|
||||
}
|
||||
|
||||
// TODO: Remove this once we've converted more message code to typescript
|
||||
// and also have confirmed we don't see this error for some period of time.
|
||||
if (!raw_message.reactions) {
|
||||
blueslip.error("expected raw_message to have reactions");
|
||||
raw_message.reactions = [];
|
||||
message_with_booleans.message.sender_full_name = sender.full_name;
|
||||
message_with_booleans.message.sender_email = sender.email;
|
||||
status_emoji_info = user_status.get_status_emoji(message_with_booleans.message.sender_id);
|
||||
}
|
||||
|
||||
// TODO: Rather than adding this field to the message object, it
|
||||
@@ -57,65 +64,127 @@ export function process_new_message(raw_message: RawMessage, deliver_locally = f
|
||||
// => clean_reactions data for the message, with care being taken
|
||||
// to make sure reify_message_id moves the data structure
|
||||
// properly.
|
||||
const clean_reactions = reactions.generate_clean_reactions(raw_message);
|
||||
const clean_reactions = reactions.generate_clean_reactions(opts.raw_message);
|
||||
|
||||
let message: Message;
|
||||
if (message_with_booleans.type === "stream") {
|
||||
const topic = message_with_booleans.topic ?? message_with_booleans.subject;
|
||||
if (message_with_booleans.message.type === "stream") {
|
||||
let topic;
|
||||
if (message_with_booleans.type === "local_message") {
|
||||
topic = message_with_booleans.message.topic;
|
||||
} else {
|
||||
topic = message_with_booleans.message.topic ?? message_with_booleans.message.subject;
|
||||
}
|
||||
assert(topic !== undefined);
|
||||
|
||||
// We add fully delivered messages to stream_topic_history,
|
||||
// being careful to not include locally echoed messages, which
|
||||
// don't have permanent IDs and don't belong in that structure.
|
||||
if (!deliver_locally) {
|
||||
if (message_with_booleans.type === "server_message") {
|
||||
stream_topic_history.add_message({
|
||||
stream_id: message_with_booleans.stream_id,
|
||||
stream_id: message_with_booleans.message.stream_id,
|
||||
topic_name: topic,
|
||||
message_id: message_with_booleans.id,
|
||||
message_id: message_with_booleans.message.id,
|
||||
});
|
||||
}
|
||||
|
||||
recent_senders.process_stream_message({
|
||||
stream_id: message_with_booleans.stream_id,
|
||||
stream_id: message_with_booleans.message.stream_id,
|
||||
topic,
|
||||
sender_id: message_with_booleans.sender_id,
|
||||
id: message_with_booleans.id,
|
||||
sender_id: message_with_booleans.message.sender_id,
|
||||
id: message_with_booleans.message.id,
|
||||
});
|
||||
|
||||
message = {
|
||||
..._.omit(message_with_booleans, ["reactions", "subject"]),
|
||||
sent_by_me,
|
||||
status_emoji_info,
|
||||
is_private: false,
|
||||
is_stream: true,
|
||||
reply_to: message_with_booleans.sender_email,
|
||||
topic,
|
||||
stream: stream_data.get_stream_name_from_id(message_with_booleans.stream_id),
|
||||
clean_reactions,
|
||||
display_reply_to: undefined,
|
||||
};
|
||||
message.submessages ??= [];
|
||||
if (message_with_booleans.type === "server_message") {
|
||||
const {reactions, subject, ...rest} = message_with_booleans.message;
|
||||
message = {
|
||||
...rest,
|
||||
sent_by_me,
|
||||
status_emoji_info,
|
||||
is_private: false,
|
||||
is_stream: true,
|
||||
reply_to: message_with_booleans.message.sender_email,
|
||||
topic,
|
||||
stream: stream_data.get_stream_name_from_id(
|
||||
message_with_booleans.message.stream_id,
|
||||
),
|
||||
clean_reactions,
|
||||
display_reply_to: undefined,
|
||||
};
|
||||
} else {
|
||||
const {reactions, ...rest} = message_with_booleans.message;
|
||||
// Ideally display_recipient would be not optional in LocalMessage
|
||||
// or MessageWithBooleans, ideally by refactoring the use of
|
||||
// `build_display_recipient`, but that's complicated to type right now.
|
||||
// When we have a new format for `display_recipient` in message objects in
|
||||
// the API itself, we'll naturally clean this up.
|
||||
assert(rest.display_recipient !== undefined);
|
||||
message = {
|
||||
...rest,
|
||||
sent_by_me,
|
||||
status_emoji_info,
|
||||
is_private: false,
|
||||
is_stream: true,
|
||||
reply_to: message_with_booleans.message.sender_email,
|
||||
topic,
|
||||
stream: stream_data.get_stream_name_from_id(
|
||||
message_with_booleans.message.stream_id,
|
||||
),
|
||||
clean_reactions,
|
||||
display_reply_to: undefined,
|
||||
display_recipient: rest.display_recipient,
|
||||
client: electron_bridge === undefined ? "website" : "ZulipElectron",
|
||||
submessages: [],
|
||||
};
|
||||
}
|
||||
message_user_ids.add_user_id(message.sender_id);
|
||||
} else {
|
||||
const pm_with_user_ids = people.pm_with_user_ids(message_with_booleans);
|
||||
const pm_with_user_ids = people.pm_with_user_ids(message_with_booleans.message);
|
||||
assert(pm_with_user_ids !== undefined);
|
||||
const pm_with_url = people.pm_with_url(message_with_booleans);
|
||||
const pm_with_url = people.pm_with_url(message_with_booleans.message);
|
||||
assert(pm_with_url !== undefined);
|
||||
const to_user_ids = people.pm_reply_user_string(message_with_booleans);
|
||||
const to_user_ids = people.pm_reply_user_string(message_with_booleans.message);
|
||||
assert(to_user_ids !== undefined);
|
||||
message = {
|
||||
..._.omit(message_with_booleans, "reactions"),
|
||||
sent_by_me,
|
||||
status_emoji_info,
|
||||
is_private: true,
|
||||
is_stream: false,
|
||||
reply_to: util.normalize_recipients(message_store.get_pm_emails(message_with_booleans)),
|
||||
display_reply_to: message_store.get_pm_full_names(pm_with_user_ids),
|
||||
pm_with_url,
|
||||
to_user_ids,
|
||||
clean_reactions,
|
||||
};
|
||||
message.submessages ??= [];
|
||||
if (message_with_booleans.type === "server_message") {
|
||||
message = {
|
||||
..._.omit(message_with_booleans.message, "reactions"),
|
||||
sent_by_me,
|
||||
status_emoji_info,
|
||||
is_private: true,
|
||||
is_stream: false,
|
||||
reply_to: util.normalize_recipients(
|
||||
message_store.get_pm_emails(message_with_booleans.message),
|
||||
),
|
||||
display_reply_to: message_store.get_pm_full_names(pm_with_user_ids),
|
||||
pm_with_url,
|
||||
to_user_ids,
|
||||
clean_reactions,
|
||||
};
|
||||
} else {
|
||||
const {reactions, topic_links, ...rest} = message_with_booleans.message;
|
||||
// Ideally display_recipient would be not optional in LocalMessage
|
||||
// or MessageWithBooleans, ideally by refactoring the use of
|
||||
// `build_display_recipient`, but that's complicated to type right now.
|
||||
// When we have a new format for `display_recipient` in message objects in
|
||||
// the API itself, we'll naturally clean this up.
|
||||
assert(rest.display_recipient !== undefined);
|
||||
message = {
|
||||
...rest,
|
||||
sent_by_me,
|
||||
status_emoji_info,
|
||||
is_private: true,
|
||||
is_stream: false,
|
||||
reply_to: util.normalize_recipients(
|
||||
message_store.get_pm_emails(message_with_booleans.message),
|
||||
),
|
||||
display_reply_to: message_store.get_pm_full_names(pm_with_user_ids),
|
||||
pm_with_url,
|
||||
to_user_ids,
|
||||
clean_reactions,
|
||||
display_recipient: rest.display_recipient,
|
||||
submessages: [],
|
||||
client: electron_bridge === undefined ? "website" : "ZulipElectron",
|
||||
};
|
||||
}
|
||||
|
||||
pm_conversations.process_message(message);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import _ from "lodash";
|
||||
import * as z from "zod/mini";
|
||||
|
||||
import * as blueslip from "./blueslip.ts";
|
||||
import type {LocalMessage} from "./echo.ts";
|
||||
import type {NewMessage} from "./message_helper.ts";
|
||||
import * as people from "./people.ts";
|
||||
import {topic_link_schema} from "./types.ts";
|
||||
import type {UserStatusEmojiInfo} from "./user_status.ts";
|
||||
@@ -108,10 +110,7 @@ export type RawMessage = z.infer<typeof raw_message_schema>;
|
||||
|
||||
// We add these boolean properties to Raw message in
|
||||
// `message_store.convert_raw_message_to_message_with_booleans` method.
|
||||
export type MessageWithBooleans = (
|
||||
| Omit<RawMessage & {type: "private"}, "flags">
|
||||
| Omit<RawMessage & {type: "stream"}, "flags">
|
||||
) & {
|
||||
type Booleans = {
|
||||
unread: boolean;
|
||||
historical: boolean;
|
||||
starred: boolean;
|
||||
@@ -124,6 +123,20 @@ export type MessageWithBooleans = (
|
||||
alerted: boolean;
|
||||
};
|
||||
|
||||
type RawMessageWithBooleans = (
|
||||
| Omit<RawMessage & {type: "private"}, "flags">
|
||||
| Omit<RawMessage & {type: "stream"}, "flags">
|
||||
) &
|
||||
Booleans;
|
||||
|
||||
type LocalMessageWithBooleans = (
|
||||
| Omit<LocalMessage & {type: "private"}, "flags">
|
||||
| Omit<LocalMessage & {type: "stream"}, "flags">
|
||||
) &
|
||||
Booleans;
|
||||
|
||||
export type MessageWithBooleans = RawMessageWithBooleans | LocalMessageWithBooleans;
|
||||
|
||||
export type MessageCleanReaction = {
|
||||
class: string;
|
||||
count: number;
|
||||
@@ -139,8 +152,8 @@ export type MessageCleanReaction = {
|
||||
};
|
||||
|
||||
export type Message = (
|
||||
| Omit<MessageWithBooleans & {type: "private"}, "reactions">
|
||||
| Omit<MessageWithBooleans & {type: "stream"}, "reactions" | "subject">
|
||||
| Omit<RawMessageWithBooleans & {type: "private"}, "reactions">
|
||||
| Omit<RawMessageWithBooleans & {type: "stream"}, "reactions" | "subject">
|
||||
) & {
|
||||
clean_reactions: Map<string, MessageCleanReaction>;
|
||||
|
||||
@@ -214,7 +227,9 @@ export function get(message_id: number): Message | undefined {
|
||||
return stored_messages.get(message_id);
|
||||
}
|
||||
|
||||
export function get_pm_emails(message: Message | MessageWithBooleans): string {
|
||||
export function get_pm_emails(
|
||||
message: Message | MessageWithBooleans | LocalMessageWithBooleans,
|
||||
): string {
|
||||
const user_ids = people.pm_with_user_ids(message) ?? [];
|
||||
const emails = user_ids
|
||||
.map((user_id) => {
|
||||
@@ -238,10 +253,16 @@ export function get_pm_full_names(user_ids: number[]): string {
|
||||
return sorted_names.join(", ");
|
||||
}
|
||||
|
||||
export function convert_raw_message_to_message_with_booleans(
|
||||
message: RawMessage,
|
||||
): MessageWithBooleans {
|
||||
const flags = message.flags ?? [];
|
||||
export function convert_raw_message_to_message_with_booleans(opts: NewMessage):
|
||||
| {
|
||||
type: "server_message";
|
||||
message: RawMessageWithBooleans;
|
||||
}
|
||||
| {
|
||||
type: "local_message";
|
||||
message: LocalMessageWithBooleans;
|
||||
} {
|
||||
const flags = opts.raw_message.flags ?? [];
|
||||
|
||||
function convert_flag(flag_name: string): boolean {
|
||||
return flags.includes(flag_name);
|
||||
@@ -268,15 +289,39 @@ export function convert_raw_message_to_message_with_booleans(
|
||||
|
||||
// We have to return these separately because of how the `MessageWithBooleans`
|
||||
// type is set up.
|
||||
if (message.type === "private") {
|
||||
if (opts.type === "local_message") {
|
||||
if (opts.raw_message.type === "private") {
|
||||
return {
|
||||
type: "local_message",
|
||||
message: {
|
||||
..._.omit(opts.raw_message, "flags"),
|
||||
...converted_flags,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
..._.omit(message, "flags"),
|
||||
...converted_flags,
|
||||
type: "local_message",
|
||||
message: {
|
||||
..._.omit(opts.raw_message, "flags"),
|
||||
...converted_flags,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (opts.raw_message.type === "private") {
|
||||
return {
|
||||
type: "server_message",
|
||||
message: {
|
||||
..._.omit(opts.raw_message, "flags"),
|
||||
...converted_flags,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
..._.omit(message, "flags"),
|
||||
...converted_flags,
|
||||
type: "server_message",
|
||||
message: {
|
||||
..._.omit(opts.raw_message, "flags"),
|
||||
...converted_flags,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -585,7 +585,10 @@ export let show = (raw_terms: NarrowTerm[], show_opts: ShowMessageViewOpts): voi
|
||||
// message locally available and then call
|
||||
// message_view.show recursively, setting a flag to
|
||||
// indicate we've already done this.
|
||||
message_helper.process_new_message(data.message);
|
||||
message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message: data.message,
|
||||
});
|
||||
show(raw_terms, {
|
||||
...opts,
|
||||
fetched_target_message: true,
|
||||
|
||||
@@ -616,6 +616,12 @@ export function pm_with_user_ids(message: Message | MessageWithBooleans): number
|
||||
typeof message.display_recipient !== "string",
|
||||
"Private messages should have list of recipients",
|
||||
);
|
||||
// Ideally display_recipient would be not optional in LocalMessage
|
||||
// or MessageWithBooleans, ideally by refactoring the use of
|
||||
// `build_display_recipient`, but that's complicated to type right now.
|
||||
// When we have a new format for `display_recipient` in message objects in
|
||||
// the API itself, we'll naturally clean this up.
|
||||
assert(message.display_recipient !== undefined);
|
||||
|
||||
if (message.display_recipient.length === 0) {
|
||||
blueslip.error("Empty recipient list in message");
|
||||
@@ -1728,6 +1734,7 @@ function get_involved_people(message: MessageWithBooleans): DisplayRecipientUser
|
||||
typeof message.display_recipient !== "string",
|
||||
"Private messages should have list of recipients",
|
||||
);
|
||||
assert(message.display_recipient !== undefined);
|
||||
involved_people = message.display_recipient;
|
||||
}
|
||||
|
||||
@@ -1811,6 +1818,8 @@ export function maybe_incr_recipient_count(
|
||||
return;
|
||||
}
|
||||
|
||||
assert(message.display_recipient !== undefined);
|
||||
|
||||
// Track the number of direct messages we've sent to this person
|
||||
// to improve autocomplete
|
||||
for (const recip of message.display_recipient) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import render_message_reactions from "../templates/message_reactions.hbs";
|
||||
|
||||
import * as blueslip from "./blueslip.ts";
|
||||
import * as channel from "./channel.ts";
|
||||
import type {LocalMessage} from "./echo.ts";
|
||||
import * as emoji from "./emoji.ts";
|
||||
import type {EmojiRenderingDetails} from "./emoji.ts";
|
||||
import {$t} from "./i18n.ts";
|
||||
@@ -518,7 +519,9 @@ export function get_message_reactions(message: Message): MessageCleanReaction[]
|
||||
return [...message.clean_reactions.values()];
|
||||
}
|
||||
|
||||
export function generate_clean_reactions(message: RawMessage): Map<string, MessageCleanReaction> {
|
||||
export function generate_clean_reactions(
|
||||
message: RawMessage | LocalMessage,
|
||||
): Map<string, MessageCleanReaction> {
|
||||
/*
|
||||
generate_clean_reactions processes the raw message.reactions object,
|
||||
which will contain one object for each individual reaction, even
|
||||
|
||||
@@ -122,8 +122,11 @@ function get_events_success(events) {
|
||||
// But in any case, insert_new_messages handles multiple
|
||||
// messages, only one of which was sent by this client,
|
||||
// correctly.
|
||||
|
||||
message_events.insert_new_messages(messages, sent_by_this_client, false);
|
||||
message_events.insert_new_messages({
|
||||
type: "server_message",
|
||||
raw_messages: messages,
|
||||
sent_by_this_client,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
blueslip.error("Failed to insert new messages", undefined, error);
|
||||
|
||||
@@ -237,7 +237,7 @@ export function sorted_ids(ids: number[]): number[] {
|
||||
return id_list;
|
||||
}
|
||||
|
||||
export function set_match_data(target: Message, source: MatchedMessage): void {
|
||||
export function set_match_data(target: Message, source: MatchedMessage | RawMessage): void {
|
||||
target.match_subject = source.match_subject;
|
||||
target.match_content = source.match_content;
|
||||
}
|
||||
|
||||
@@ -316,9 +316,10 @@ test_ui("send_message", ({override, override_rewire, mock_template}) => {
|
||||
|
||||
override_rewire(echo, "try_deliver_locally", (message_request) => {
|
||||
const local_id_float = 123.04;
|
||||
return echo.insert_local_message(message_request, local_id_float, (messages) => {
|
||||
assert.equal(messages[0].timestamp, fake_now);
|
||||
return messages;
|
||||
return echo.insert_local_message(message_request, local_id_float, (messages_data) => {
|
||||
assert.equal(messages_data.type, "local_message");
|
||||
assert.equal(messages_data.raw_messages[0].timestamp, fake_now);
|
||||
return messages_data.raw_messages;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -316,7 +316,8 @@ run_test("insert_local_message streams", ({override}) => {
|
||||
get_topic_links_called = true;
|
||||
});
|
||||
|
||||
const insert_new_messages = ([message]) => {
|
||||
const insert_new_messages = (message_data) => {
|
||||
const [message] = message_data.raw_messages;
|
||||
assert.equal(message.display_recipient, "general");
|
||||
assert.equal(message.timestamp, fake_now);
|
||||
assert.equal(message.sender_email, "iago@zulip.com");
|
||||
@@ -375,7 +376,8 @@ run_test("insert_local_message direct message", ({override}) => {
|
||||
let render_called = false;
|
||||
let insert_message_called = false;
|
||||
|
||||
const insert_new_messages = ([message]) => {
|
||||
const insert_new_messages = (message_data) => {
|
||||
const [message] = message_data.raw_messages;
|
||||
assert.equal(message.display_recipient.length, 2);
|
||||
insert_message_called = true;
|
||||
return [message];
|
||||
@@ -415,7 +417,8 @@ run_test("test reify_message_id", ({override}) => {
|
||||
sender_id: 123,
|
||||
draft_id: 100,
|
||||
};
|
||||
echo.insert_local_message(message_request, local_id_float, (messages) => {
|
||||
echo.insert_local_message(message_request, local_id_float, (message_data) => {
|
||||
const messages = message_data.raw_messages;
|
||||
messages.map((message) => echo.track_local_message(message));
|
||||
return messages;
|
||||
});
|
||||
|
||||
@@ -74,7 +74,10 @@ run_test("message_store", () => {
|
||||
// Let's add a message into our message_store via
|
||||
// message_helper.process_new_message.
|
||||
assert.equal(message_store.get(in_message.id), undefined);
|
||||
message_helper.process_new_message(in_message);
|
||||
message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message: in_message,
|
||||
});
|
||||
const message = message_store.get(in_message.id);
|
||||
assert.equal(message.alerted, true);
|
||||
|
||||
@@ -97,7 +100,10 @@ run_test("unread", () => {
|
||||
assert.equal(unread.num_unread_for_topic(stream_id, topic_name), 0);
|
||||
|
||||
let in_message = {...messages.isaac_to_denmark_stream};
|
||||
in_message = message_helper.process_new_message(in_message);
|
||||
in_message = message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message: in_message,
|
||||
});
|
||||
|
||||
unread.process_loaded_messages([in_message]);
|
||||
assert.equal(unread.num_unread_for_topic(stream_id, topic_name), 1);
|
||||
|
||||
@@ -111,7 +111,10 @@ run_test("insert_message", ({override}) => {
|
||||
helper.redirect(unread_ui, "update_unread_counts");
|
||||
helper.redirect(activity, "set_received_new_messages");
|
||||
|
||||
message_events.insert_new_messages([new_message]);
|
||||
message_events.insert_new_messages({
|
||||
type: "server_message",
|
||||
raw_messages: [new_message],
|
||||
});
|
||||
|
||||
// Even though we have stubbed a *lot* of code, our
|
||||
// tests can still verify the main "narrative" of how
|
||||
|
||||
@@ -81,9 +81,14 @@ run_test("update_messages", ({override, override_rewire}) => {
|
||||
topic: "lunch",
|
||||
type: "stream",
|
||||
reactions: [],
|
||||
submessages: [],
|
||||
avatar_url: `/avatar/${alice.user_id}`,
|
||||
};
|
||||
|
||||
const original_message = message_helper.process_new_message(raw_message);
|
||||
const original_message = message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message,
|
||||
});
|
||||
|
||||
assert.equal(original_message.mentioned, true);
|
||||
assert.equal(original_message.unread, true);
|
||||
@@ -141,6 +146,7 @@ run_test("update_messages", ({override, override_rewire}) => {
|
||||
|
||||
assert.deepEqual(rendered_mgs, [
|
||||
{
|
||||
avatar_url: `/avatar/${alice.user_id}`,
|
||||
display_reply_to: undefined,
|
||||
alerted: false,
|
||||
clean_reactions: new Map(),
|
||||
|
||||
@@ -7,12 +7,12 @@ const {mock_esm, set_global, zrequire} = require("./lib/namespace.cjs");
|
||||
const {run_test, noop} = require("./lib/test.cjs");
|
||||
const blueslip = require("./lib/zblueslip.cjs");
|
||||
|
||||
mock_esm("../src/settings_data", {
|
||||
user_can_access_all_other_users: () => true,
|
||||
mock_esm("../src/electron_bridge", {
|
||||
electron_bridge: {},
|
||||
});
|
||||
|
||||
mock_esm("../src/stream_topic_history", {
|
||||
add_message: noop,
|
||||
mock_esm("../src/settings_data", {
|
||||
user_can_access_all_other_users: () => true,
|
||||
});
|
||||
|
||||
mock_esm("../src/recent_senders", {
|
||||
@@ -111,8 +111,12 @@ test("process_new_message", () => {
|
||||
is_me_message: false,
|
||||
id: 2067,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${me.user_id}`,
|
||||
};
|
||||
message = message_helper.process_new_message(message);
|
||||
message = message_helper.process_new_message({
|
||||
type: "local_message",
|
||||
raw_message: message,
|
||||
});
|
||||
|
||||
assert.deepEqual(message_user_ids.user_ids().sort(), [me.user_id, bob.user_id, cindy.user_id]);
|
||||
|
||||
@@ -132,8 +136,13 @@ test("process_new_message", () => {
|
||||
match_subject: "topic foo",
|
||||
match_content: "bar content",
|
||||
reactions: [],
|
||||
submessages: [],
|
||||
avatar_url: "/some/path/to/avatar",
|
||||
};
|
||||
message = message_helper.process_new_message(message);
|
||||
message = message_helper.process_new_message({
|
||||
type: "server_message",
|
||||
raw_message: message,
|
||||
});
|
||||
|
||||
assert.equal(message.reply_to, "bob@example.com,cindy@example.com");
|
||||
assert.equal(message.to_user_ids, "103,104");
|
||||
@@ -150,9 +159,13 @@ test("process_new_message", () => {
|
||||
subject: "the_subject",
|
||||
id: 2068,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${denise.user_id}`,
|
||||
};
|
||||
|
||||
message = message_helper.process_new_message(message);
|
||||
message = message_helper.process_new_message({
|
||||
type: "local_message",
|
||||
raw_message: message,
|
||||
});
|
||||
assert.equal(message.reply_to, "denise@example.com");
|
||||
assert.deepEqual(message.flags, undefined);
|
||||
assert.equal(message.alerted, false);
|
||||
@@ -163,18 +176,6 @@ test("process_new_message", () => {
|
||||
cindy.user_id,
|
||||
denise.user_id,
|
||||
]);
|
||||
|
||||
message = {
|
||||
sender_email: denise.email,
|
||||
sender_id: denise.user_id,
|
||||
type: "stream",
|
||||
display_recipient: "Zoolippy",
|
||||
topic: "cool thing",
|
||||
subject: "the_subject",
|
||||
id: 2069,
|
||||
};
|
||||
blueslip.expect("error", "expected raw_message to have reactions", 1);
|
||||
message_helper.process_new_message(message);
|
||||
});
|
||||
|
||||
test("message_booleans_parity", () => {
|
||||
@@ -184,7 +185,10 @@ test("message_booleans_parity", () => {
|
||||
const assert_bool_match = (flags, expected_message) => {
|
||||
let set_message = {topic: "convert_raw_message_to_message_with_booleans", flags};
|
||||
const update_message = {topic: "update_booleans"};
|
||||
set_message = message_store.convert_raw_message_to_message_with_booleans(set_message);
|
||||
set_message = message_store.convert_raw_message_to_message_with_booleans({
|
||||
type: "server_message",
|
||||
raw_message: set_message,
|
||||
}).message;
|
||||
message_store.update_booleans(update_message, flags);
|
||||
for (const key of Object.keys(expected_message)) {
|
||||
assert.equal(
|
||||
@@ -340,6 +344,7 @@ test("update_property", () => {
|
||||
display_recipient: devel.name,
|
||||
id: 100,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${alice.user_id}`,
|
||||
};
|
||||
let message2 = {
|
||||
type: "stream",
|
||||
@@ -351,9 +356,16 @@ test("update_property", () => {
|
||||
display_recipient: denmark.name,
|
||||
id: 101,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${bob.user_id}`,
|
||||
};
|
||||
message1 = message_helper.process_new_message(message1);
|
||||
message2 = message_helper.process_new_message(message2);
|
||||
message1 = message_helper.process_new_message({
|
||||
type: "local_message",
|
||||
raw_message: message1,
|
||||
});
|
||||
message2 = message_helper.process_new_message({
|
||||
type: "local_message",
|
||||
raw_message: message2,
|
||||
});
|
||||
|
||||
assert.equal(message1.sender_full_name, alice.full_name);
|
||||
assert.equal(message2.sender_full_name, bob.full_name);
|
||||
@@ -389,6 +401,7 @@ test("remove", () => {
|
||||
topic: "test",
|
||||
id: 100,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${alice.user_id}`,
|
||||
};
|
||||
const message2 = {
|
||||
type: "stream",
|
||||
@@ -400,6 +413,7 @@ test("remove", () => {
|
||||
topic: "test",
|
||||
id: 101,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${bob.user_id}`,
|
||||
};
|
||||
const message3 = {
|
||||
type: "stream",
|
||||
@@ -411,9 +425,13 @@ test("remove", () => {
|
||||
topic: "test",
|
||||
id: 102,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${cindy.user_id}`,
|
||||
};
|
||||
for (const message of [message1, message2]) {
|
||||
message_helper.process_new_message(message);
|
||||
message_helper.process_new_message({
|
||||
type: "local_message",
|
||||
raw_message: message,
|
||||
});
|
||||
}
|
||||
|
||||
const deleted_message_ids = [message1.id, message3.id, 104];
|
||||
@@ -434,6 +452,7 @@ test("get_message_ids_in_stream", () => {
|
||||
topic: "test",
|
||||
id: 100,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${alice.user_id}`,
|
||||
};
|
||||
const message2 = {
|
||||
sender_email: "me@example.com",
|
||||
@@ -444,6 +463,7 @@ test("get_message_ids_in_stream", () => {
|
||||
is_me_message: false,
|
||||
id: 101,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${me.user_id}`,
|
||||
};
|
||||
const message3 = {
|
||||
type: "stream",
|
||||
@@ -455,6 +475,7 @@ test("get_message_ids_in_stream", () => {
|
||||
topic: "test",
|
||||
id: 102,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${cindy.user_id}`,
|
||||
};
|
||||
const message4 = {
|
||||
type: "stream",
|
||||
@@ -466,10 +487,14 @@ test("get_message_ids_in_stream", () => {
|
||||
topic: "test",
|
||||
id: 103,
|
||||
reactions: [],
|
||||
avatar_url: `/avatar/${me.user_id}`,
|
||||
};
|
||||
|
||||
for (const message of [message1, message2, message3, message4]) {
|
||||
message_helper.process_new_message(message);
|
||||
message_helper.process_new_message({
|
||||
type: "local_message",
|
||||
raw_message: message,
|
||||
});
|
||||
}
|
||||
|
||||
assert.deepEqual(message_store.get_message_ids_in_stream(devel.stream_id), [100, 103]);
|
||||
|
||||
@@ -92,7 +92,8 @@ run_test("message_event", ({override}) => {
|
||||
};
|
||||
|
||||
let inserted;
|
||||
override(message_events, "insert_new_messages", (messages) => {
|
||||
override(message_events, "insert_new_messages", (message_data) => {
|
||||
const messages = message_data.raw_messages;
|
||||
assert.equal(messages[0].content, event.message.content);
|
||||
inserted = true;
|
||||
return messages;
|
||||
|
||||
Reference in New Issue
Block a user