2021-02-28 01:08:13 +01:00
|
|
|
import _ from "lodash";
|
2020-08-01 03:43:15 +02:00
|
|
|
|
2021-02-28 01:08:13 +01:00
|
|
|
import * as channel from "./channel";
|
2021-02-28 01:10:03 +01:00
|
|
|
import * as message_store from "./message_store";
|
2021-02-28 01:08:33 +01:00
|
|
|
import * as starred_messages from "./starred_messages";
|
2021-02-28 21:33:10 +01:00
|
|
|
import * as ui from "./ui";
|
2021-02-28 21:30:08 +01:00
|
|
|
import * as unread_ops from "./unread_ops";
|
2021-02-28 00:39:51 +01:00
|
|
|
|
2021-03-01 12:57:56 +01:00
|
|
|
function send_flag_update_for_messages(msg_ids, flag, op) {
|
2017-12-16 13:33:54 +01:00
|
|
|
channel.post({
|
2020-07-15 01:29:15 +02:00
|
|
|
url: "/json/messages/flags",
|
2017-12-16 13:33:54 +01:00
|
|
|
data: {
|
2021-03-01 12:57:56 +01:00
|
|
|
messages: JSON.stringify(msg_ids),
|
2020-07-20 22:18:43 +02:00
|
|
|
flag,
|
|
|
|
op,
|
2017-12-16 13:33:54 +01:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2021-02-28 01:08:13 +01:00
|
|
|
export const _unread_batch_size = 1000;
|
|
|
|
|
|
|
|
export const send_read = (function () {
|
2019-11-02 00:06:25 +01:00
|
|
|
let queue = [];
|
|
|
|
let on_success;
|
|
|
|
let start;
|
2014-01-31 17:03:52 +01:00
|
|
|
function server_request() {
|
|
|
|
// Wait for server IDs before sending flags
|
2020-07-02 01:39:34 +02:00
|
|
|
const real_msgs = queue.filter((msg) => !msg.locally_echoed);
|
|
|
|
const real_msg_ids = real_msgs.map((msg) => msg.id);
|
2014-01-31 17:03:52 +01:00
|
|
|
|
|
|
|
if (real_msg_ids.length === 0) {
|
2014-03-07 23:03:46 +01:00
|
|
|
setTimeout(start, 100);
|
2014-01-31 17:03:52 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-28 01:08:13 +01:00
|
|
|
const real_msg_ids_batch = real_msg_ids.slice(0, _unread_batch_size);
|
2019-05-04 04:10:05 +02:00
|
|
|
|
2014-03-07 23:04:01 +01:00
|
|
|
// We have some real IDs. If there are any left in the queue when this
|
|
|
|
// call finishes, they will be handled in the success callback.
|
|
|
|
|
2014-01-31 17:03:52 +01:00
|
|
|
channel.post({
|
2020-07-15 01:29:15 +02:00
|
|
|
url: "/json/messages/flags",
|
2020-07-15 00:34:28 +02:00
|
|
|
data: {messages: JSON.stringify(real_msg_ids_batch), op: "add", flag: "read"},
|
2018-12-18 19:34:45 +01:00
|
|
|
success: on_success,
|
2014-01-31 17:03:52 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-21 17:51:52 +01:00
|
|
|
start = _.throttle(server_request, 1000);
|
2014-01-31 17:03:52 +01:00
|
|
|
|
2016-12-02 14:06:06 +01:00
|
|
|
on_success = function on_success(data) {
|
2020-07-16 23:29:01 +02:00
|
|
|
if (data === undefined || data.messages === undefined) {
|
2014-01-31 17:03:52 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-02 01:39:34 +02:00
|
|
|
queue = queue.filter((message) => !data.messages.includes(message.id));
|
2014-01-31 17:03:52 +01:00
|
|
|
|
|
|
|
if (queue.length > 0) {
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-12-21 17:51:52 +01:00
|
|
|
function add(messages) {
|
|
|
|
queue = queue.concat(messages);
|
2014-01-31 17:03:52 +01:00
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
|
|
|
return add;
|
2020-07-16 22:35:58 +02:00
|
|
|
})();
|
2014-01-31 17:03:52 +01:00
|
|
|
|
2022-10-21 11:52:47 +02:00
|
|
|
export function mark_as_read(message_ids) {
|
|
|
|
send_flag_update_for_messages(message_ids, "read", "add");
|
|
|
|
}
|
|
|
|
|
2021-08-05 00:59:03 +02:00
|
|
|
export function mark_as_unread(message_ids) {
|
|
|
|
send_flag_update_for_messages(message_ids, "read", "remove");
|
|
|
|
}
|
|
|
|
|
2021-02-28 01:08:13 +01:00
|
|
|
export function save_collapsed(message) {
|
2021-03-01 12:57:56 +01:00
|
|
|
send_flag_update_for_messages([message.id], "collapsed", "add");
|
2021-02-28 01:08:13 +01:00
|
|
|
}
|
2014-01-31 17:03:52 +01:00
|
|
|
|
2021-02-28 01:08:13 +01:00
|
|
|
export function save_uncollapsed(message) {
|
2021-03-01 12:57:56 +01:00
|
|
|
send_flag_update_for_messages([message.id], "collapsed", "remove");
|
2021-02-28 01:08:13 +01:00
|
|
|
}
|
2014-01-31 17:03:52 +01:00
|
|
|
|
2018-08-01 20:11:32 +02:00
|
|
|
// This updates the state of the starred flag in local data
|
|
|
|
// structures, and triggers a UI rerender.
|
2021-02-28 01:08:13 +01:00
|
|
|
export function update_starred_flag(message_id, new_value) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const message = message_store.get(message_id);
|
2018-10-12 22:51:54 +02:00
|
|
|
if (message === undefined) {
|
|
|
|
// If we don't have the message locally, do nothing; if later
|
|
|
|
// we fetch it, it'll come with the correct `starred` state.
|
|
|
|
return;
|
|
|
|
}
|
2018-08-01 02:29:10 +02:00
|
|
|
message.starred = new_value;
|
2018-08-01 19:02:38 +02:00
|
|
|
ui.update_starred_view(message_id, new_value);
|
2021-02-28 01:08:13 +01:00
|
|
|
}
|
2018-08-01 02:29:10 +02:00
|
|
|
|
2021-02-28 01:08:13 +01:00
|
|
|
export function toggle_starred_and_update_server(message) {
|
2017-12-16 13:33:54 +01:00
|
|
|
if (message.locally_echoed) {
|
|
|
|
// This is defensive code for when you hit the "*" key
|
|
|
|
// before we get a server ack. It's rare that somebody
|
|
|
|
// can star this quickly, and we don't have a good way
|
|
|
|
// to tell the server which message was starred.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
message.starred = !message.starred;
|
|
|
|
|
2019-07-10 02:03:41 +02:00
|
|
|
// Unlike most calls to mark messages as read, we don't check
|
|
|
|
// msg_list.can_mark_messages_read, because starring a message is an
|
|
|
|
// explicit interaction and we'd like to preserve the user
|
|
|
|
// expectation invariant that all starred messages are read.
|
2018-04-04 21:32:45 +02:00
|
|
|
unread_ops.notify_server_message_read(message);
|
2018-08-01 19:02:38 +02:00
|
|
|
ui.update_starred_view(message.id, message.starred);
|
2017-12-16 13:33:54 +01:00
|
|
|
|
|
|
|
if (message.starred) {
|
2021-03-01 12:57:56 +01:00
|
|
|
send_flag_update_for_messages([message.id], "starred", "add");
|
2018-08-17 03:46:32 +02:00
|
|
|
starred_messages.add([message.id]);
|
2017-03-19 00:30:32 +01:00
|
|
|
} else {
|
2021-03-01 12:57:56 +01:00
|
|
|
send_flag_update_for_messages([message.id], "starred", "remove");
|
2018-08-17 03:46:32 +02:00
|
|
|
starred_messages.remove([message.id]);
|
2017-03-19 00:30:32 +01:00
|
|
|
}
|
2021-02-28 01:08:13 +01:00
|
|
|
}
|
2017-03-19 00:30:32 +01:00
|
|
|
|
2021-02-28 01:08:13 +01:00
|
|
|
export function unstar_all_messages() {
|
2021-02-26 21:23:32 +01:00
|
|
|
const starred_msg_ids = starred_messages.get_starred_msg_ids();
|
2021-03-01 12:57:56 +01:00
|
|
|
send_flag_update_for_messages(starred_msg_ids, "starred", "remove");
|
2021-02-28 01:08:13 +01:00
|
|
|
}
|
2021-03-08 09:25:25 +01:00
|
|
|
|
|
|
|
export function unstar_all_messages_in_topic(stream_id, topic) {
|
starred messages: Fix "unstar all in topic" is incomplete.
Currently, when there are some old starred messages
in a topic, it is possible that some of them won't be
unstarred on doing "Unstar all messages in topic".
This happens when those messages haven't been fetched
yet from the server, and we have no way to verify if
they actually belong to the topic.
This commit fixes that by changing this mechanism to
first fetch all starred messages in the topic from
the server, and then send their IDs back to the backend
to unstar them.
While doing this, we assume that the user does not
have more than 1000 starred messages in that topic.
Note that, we still depend on the local data to
decide whether or not the "Unstar all messages in
topic" option should be shown in the topic popover.
A method similar to the above cannot be used here, because
making server requests before opening the popover
could visually slow down the popover opening.
Using local data for the topic popover would probably
not be a big problem, because users would want to
unstar all messages in a topic probably after noticing
that there are a lot of them, meaning there was at least
one starred message from that topic which was already
fetched, which is sufficient for us to conclude that
we need to show the option in the topic popover.
Fixes #17790
2021-04-02 08:10:11 +02:00
|
|
|
const data = {
|
|
|
|
anchor: "newest",
|
|
|
|
// In the unlikely event the user has >1000 starred messages
|
|
|
|
// in a topic, this won't find them all. This is probably an
|
|
|
|
// acceptable bug; one can do it multiple times, and we avoid
|
|
|
|
// creating an API endpoint just for this very minor feature.
|
|
|
|
num_before: 1000,
|
|
|
|
num_after: 0,
|
|
|
|
narrow: JSON.stringify([
|
|
|
|
{operator: "stream", operand: stream_id},
|
|
|
|
{operator: "topic", operand: topic},
|
|
|
|
{operator: "is", operand: "starred"},
|
|
|
|
]),
|
|
|
|
};
|
|
|
|
|
|
|
|
channel.get({
|
|
|
|
url: "/json/messages",
|
|
|
|
data,
|
|
|
|
success(data) {
|
|
|
|
const messages = data.messages;
|
|
|
|
const starred_message_ids = messages.map((message) => message.id);
|
|
|
|
send_flag_update_for_messages(starred_message_ids, "starred", "remove");
|
|
|
|
},
|
|
|
|
});
|
2021-03-08 09:25:25 +01:00
|
|
|
}
|