mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
notifications: Split out message_notifications module.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
committed by
Tim Abbott
parent
e48771993b
commit
db20fd12e0
@@ -133,6 +133,7 @@ EXEMPT_FILES = make_set(
|
|||||||
"web/src/message_list_view.js",
|
"web/src/message_list_view.js",
|
||||||
"web/src/message_lists.js",
|
"web/src/message_lists.js",
|
||||||
"web/src/message_live_update.js",
|
"web/src/message_live_update.js",
|
||||||
|
"web/src/message_notifications.js",
|
||||||
"web/src/message_scroll.js",
|
"web/src/message_scroll.js",
|
||||||
"web/src/message_scroll_state.ts",
|
"web/src/message_scroll_state.ts",
|
||||||
"web/src/message_util.js",
|
"web/src/message_util.js",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import * as message_edit from "./message_edit";
|
|||||||
import * as message_edit_history from "./message_edit_history";
|
import * as message_edit_history from "./message_edit_history";
|
||||||
import * as message_helper from "./message_helper";
|
import * as message_helper from "./message_helper";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
|
import * as message_notifications from "./message_notifications";
|
||||||
import * as message_store from "./message_store";
|
import * as message_store from "./message_store";
|
||||||
import * as message_util from "./message_util";
|
import * as message_util from "./message_util";
|
||||||
import * as narrow from "./narrow";
|
import * as narrow from "./narrow";
|
||||||
@@ -161,7 +162,7 @@ export function insert_new_messages(messages, sent_by_this_client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unread_ops.process_visible();
|
unread_ops.process_visible();
|
||||||
notifications.received_messages(messages);
|
message_notifications.received_messages(messages);
|
||||||
stream_list.update_streams_sidebar();
|
stream_list.update_streams_sidebar();
|
||||||
pm_list.update_private_messages();
|
pm_list.update_private_messages();
|
||||||
recent_view_ui.process_messages(messages);
|
recent_view_ui.process_messages(messages);
|
||||||
@@ -482,7 +483,7 @@ export function update_messages(events) {
|
|||||||
anchor_message.last_edit_timestamp = event.edit_timestamp;
|
anchor_message.last_edit_timestamp = event.edit_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications.received_messages([anchor_message]);
|
message_notifications.received_messages([anchor_message]);
|
||||||
alert_words.process_message(anchor_message);
|
alert_words.process_message(anchor_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
404
web/src/message_notifications.js
Normal file
404
web/src/message_notifications.js
Normal file
@@ -0,0 +1,404 @@
|
|||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
import * as alert_words from "./alert_words";
|
||||||
|
import * as blueslip from "./blueslip";
|
||||||
|
import {$t} from "./i18n";
|
||||||
|
import * as message_parser from "./message_parser";
|
||||||
|
import * as narrow from "./narrow";
|
||||||
|
import * as notifications from "./notifications";
|
||||||
|
import * as people from "./people";
|
||||||
|
import * as spoilers from "./spoilers";
|
||||||
|
import * as stream_data from "./stream_data";
|
||||||
|
import * as ui_util from "./ui_util";
|
||||||
|
import * as unread from "./unread";
|
||||||
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as user_topics from "./user_topics";
|
||||||
|
|
||||||
|
function get_notification_content(message) {
|
||||||
|
let content;
|
||||||
|
// Convert the content to plain text, replacing emoji with their alt text
|
||||||
|
const $content = $("<div>").html(message.content);
|
||||||
|
ui_util.replace_emoji_with_text($content);
|
||||||
|
spoilers.hide_spoilers_in_notification($content);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$content.text().trim() === "" &&
|
||||||
|
(message_parser.message_has_image(message) ||
|
||||||
|
message_parser.message_has_attachment(message))
|
||||||
|
) {
|
||||||
|
content = $t({defaultMessage: "(attached file)"});
|
||||||
|
} else {
|
||||||
|
content = $content.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.is_me_message) {
|
||||||
|
content = message.sender_full_name + content.slice(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(message.type === "private" || message.type === "test-notification") &&
|
||||||
|
!user_settings.pm_content_in_desktop_notifications
|
||||||
|
) {
|
||||||
|
content = "New direct message from " + message.sender_full_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.length > 150) {
|
||||||
|
let i;
|
||||||
|
// Truncate content at a word boundary
|
||||||
|
for (i = 150; i > 0; i -= 1) {
|
||||||
|
if (content[i] === " ") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content = content.slice(0, i);
|
||||||
|
content += " [...]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function debug_notification_source_value(message) {
|
||||||
|
let notification_source;
|
||||||
|
|
||||||
|
if (message.type === "private" || message.type === "test-notification") {
|
||||||
|
notification_source = "pm";
|
||||||
|
} else if (message.mentioned) {
|
||||||
|
notification_source = "mention";
|
||||||
|
} else if (message.alerted) {
|
||||||
|
notification_source = "alert";
|
||||||
|
} else {
|
||||||
|
notification_source = "stream";
|
||||||
|
}
|
||||||
|
|
||||||
|
blueslip.debug("Desktop notification from source " + notification_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_notification_key(message) {
|
||||||
|
let key;
|
||||||
|
|
||||||
|
if (message.type === "private" || message.type === "test-notification") {
|
||||||
|
key = message.display_reply_to;
|
||||||
|
} else {
|
||||||
|
const stream_name = stream_data.get_stream_name_from_id(message.stream_id);
|
||||||
|
key = message.sender_full_name + " to " + stream_name + " > " + message.topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_sender_from_list_of_recipients(message) {
|
||||||
|
return `, ${message.display_reply_to}, `
|
||||||
|
.replace(`, ${message.sender_full_name}, `, ", ")
|
||||||
|
.slice(", ".length, -", ".length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_notification_title(message, content, msg_count) {
|
||||||
|
let title = message.sender_full_name;
|
||||||
|
let other_recipients;
|
||||||
|
|
||||||
|
if (msg_count > 1) {
|
||||||
|
title = msg_count + " messages from " + title;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message.type) {
|
||||||
|
case "test-notification":
|
||||||
|
other_recipients = remove_sender_from_list_of_recipients(message);
|
||||||
|
break;
|
||||||
|
case "private":
|
||||||
|
other_recipients = remove_sender_from_list_of_recipients(message);
|
||||||
|
if (message.display_recipient.length > 2) {
|
||||||
|
// If the message has too many recipients to list them all...
|
||||||
|
if (content.length + title.length + other_recipients.length > 230) {
|
||||||
|
// Then count how many people are in the conversation and summarize
|
||||||
|
// by saying the conversation is with "you and [number] other people"
|
||||||
|
other_recipients =
|
||||||
|
other_recipients.replaceAll(/[^,]/g, "").length + " other people";
|
||||||
|
}
|
||||||
|
|
||||||
|
title += " (to you and " + other_recipients + ")";
|
||||||
|
} else {
|
||||||
|
title += " (to you)";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "stream": {
|
||||||
|
const stream_name = stream_data.get_stream_name_from_id(message.stream_id);
|
||||||
|
title += " (to " + stream_name + " > " + message.topic + ")";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function process_notification(notification) {
|
||||||
|
const message = notification.message;
|
||||||
|
const content = get_notification_content(message);
|
||||||
|
const key = get_notification_key(message);
|
||||||
|
let notification_object;
|
||||||
|
let msg_count = 1;
|
||||||
|
|
||||||
|
debug_notification_source_value(message);
|
||||||
|
|
||||||
|
if (notifications.notice_memory.has(key)) {
|
||||||
|
msg_count = notifications.notice_memory.get(key).msg_count + 1;
|
||||||
|
notification_object = notifications.notice_memory.get(key).obj;
|
||||||
|
notification_object.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = get_notification_title(message, content, msg_count);
|
||||||
|
|
||||||
|
if (notification.desktop_notify) {
|
||||||
|
const icon_url = people.small_avatar_url(message);
|
||||||
|
notification_object = new notifications.NotificationAPI(title, {
|
||||||
|
icon: icon_url,
|
||||||
|
body: content,
|
||||||
|
tag: message.id,
|
||||||
|
});
|
||||||
|
notifications.notice_memory.set(key, {
|
||||||
|
obj: notification_object,
|
||||||
|
msg_count,
|
||||||
|
message_id: message.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof notification_object.addEventListener === "function") {
|
||||||
|
// Sadly, some third-party Electron apps like Franz/Ferdi
|
||||||
|
// misimplement the Notification API not inheriting from
|
||||||
|
// EventTarget. This results in addEventListener being
|
||||||
|
// unavailable for them.
|
||||||
|
notification_object.addEventListener("click", () => {
|
||||||
|
notification_object.close();
|
||||||
|
if (message.type !== "test-notification") {
|
||||||
|
narrow.by_topic(message.id, {trigger: "notification"});
|
||||||
|
}
|
||||||
|
window.focus();
|
||||||
|
});
|
||||||
|
notification_object.addEventListener("close", () => {
|
||||||
|
notifications.notice_memory.delete(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function message_is_notifiable(message) {
|
||||||
|
// Independent of the user's notification settings, are there
|
||||||
|
// properties of the message that unconditionally mean we
|
||||||
|
// shouldn't notify about it.
|
||||||
|
|
||||||
|
if (message.sent_by_me) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a message is edited multiple times, we want to err on the side of
|
||||||
|
// not spamming notifications.
|
||||||
|
if (message.notification_sent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @-<username> mentions take precedence over muted-ness. Note
|
||||||
|
// that @all mentions are still suppressed by muting.
|
||||||
|
if (message.mentioned_me_directly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messages to followed topics take precedence over muted-ness.
|
||||||
|
if (
|
||||||
|
message.type === "stream" &&
|
||||||
|
user_topics.is_topic_followed(message.stream_id, message.topic)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messages to unmuted topics in muted streams may generate desktop notifications.
|
||||||
|
if (
|
||||||
|
message.type === "stream" &&
|
||||||
|
stream_data.is_muted(message.stream_id) &&
|
||||||
|
!user_topics.is_topic_unmuted(message.stream_id, message.topic)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === "stream" && user_topics.is_topic_muted(message.stream_id, message.topic)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything else is on the table; next filter based on notification
|
||||||
|
// settings.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function should_send_desktop_notification(message) {
|
||||||
|
// Always notify for testing notifications.
|
||||||
|
if (message.type === "test-notification") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For streams, send if desktop notifications are enabled for all
|
||||||
|
// message on this stream.
|
||||||
|
if (
|
||||||
|
message.type === "stream" &&
|
||||||
|
stream_data.receives_notifications(message.stream_id, "desktop_notifications")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable_followed_topic_desktop_notifications determines whether we pop up
|
||||||
|
// a notification for messages in followed topics.
|
||||||
|
if (
|
||||||
|
message.type === "stream" &&
|
||||||
|
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
||||||
|
user_settings.enable_followed_topic_desktop_notifications
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable_desktop_notifications determines whether we pop up a
|
||||||
|
// notification for direct messages, mentions, and/or alerts.
|
||||||
|
if (!user_settings.enable_desktop_notifications) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And then we need to check if the message is a direct message,
|
||||||
|
// mention, wildcard mention with wildcard_mentions_notify, or alert.
|
||||||
|
if (message.type === "private") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alert_words.notifies(message)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.mentioned_me_directly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following blocks for 'wildcard mentions' and 'Followed topic wildcard mentions'
|
||||||
|
// should be placed below (as they are right now) the 'user_settings.enable_desktop_notifications'
|
||||||
|
// block because the global, stream-specific, and followed topic wildcard mention
|
||||||
|
// settings are wrappers around the personal-mention setting.
|
||||||
|
// wildcard mentions
|
||||||
|
if (
|
||||||
|
message.mentioned &&
|
||||||
|
stream_data.receives_notifications(message.stream_id, "wildcard_mentions_notify")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Followed topic wildcard mentions
|
||||||
|
if (
|
||||||
|
message.mentioned &&
|
||||||
|
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
||||||
|
user_settings.enable_followed_topic_wildcard_mentions_notify
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function should_send_audible_notification(message) {
|
||||||
|
// If `None` is selected as the notification sound, never send
|
||||||
|
// audible notifications regardless of other configuration.
|
||||||
|
if (user_settings.notification_sound === "none") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For streams, ding if sounds are enabled for all messages on
|
||||||
|
// this stream.
|
||||||
|
if (
|
||||||
|
message.type === "stream" &&
|
||||||
|
stream_data.receives_notifications(message.stream_id, "audible_notifications")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable_followed_topic_audible_notifications determines whether we ding
|
||||||
|
// for messages in followed topics.
|
||||||
|
if (
|
||||||
|
message.type === "stream" &&
|
||||||
|
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
||||||
|
user_settings.enable_followed_topic_audible_notifications
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable_sounds determines whether we ding for direct messages,
|
||||||
|
// mentions, and/or alerts.
|
||||||
|
if (!user_settings.enable_sounds) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And then we need to check if the message is a direct message,
|
||||||
|
// mention, wildcard mention with wildcard_mentions_notify, or alert.
|
||||||
|
if (message.type === "private" || message.type === "test-notification") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alert_words.notifies(message)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.mentioned_me_directly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following blocks for 'wildcard mentions' and 'Followed topic wildcard mentions'
|
||||||
|
// should be placed below (as they are right now) the 'user_settings.enable_sounds'
|
||||||
|
// block because the global, stream-specific, and followed topic wildcard mention
|
||||||
|
// settings are wrappers around the personal-mention setting.
|
||||||
|
// wildcard mentions
|
||||||
|
if (
|
||||||
|
message.mentioned &&
|
||||||
|
stream_data.receives_notifications(message.stream_id, "wildcard_mentions_notify")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Followed topic wildcard mentions
|
||||||
|
if (
|
||||||
|
message.mentioned &&
|
||||||
|
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
||||||
|
user_settings.enable_followed_topic_wildcard_mentions_notify
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function received_messages(messages) {
|
||||||
|
for (const message of messages) {
|
||||||
|
if (!message_is_notifiable(message)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!unread.message_unread(message)) {
|
||||||
|
// The message is already read; Zulip is currently in focus.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.notification_sent = true;
|
||||||
|
|
||||||
|
if (should_send_desktop_notification(message)) {
|
||||||
|
process_notification({
|
||||||
|
message,
|
||||||
|
desktop_notify: notifications.granted_desktop_notifications_permission(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (should_send_audible_notification(message)) {
|
||||||
|
ui_util.play_audio($("#user-notification-sound-audio")[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function send_test_notification(content) {
|
||||||
|
received_messages([
|
||||||
|
{
|
||||||
|
id: Math.random(),
|
||||||
|
type: "test-notification",
|
||||||
|
sender_email: "notification-bot@zulip.com",
|
||||||
|
sender_full_name: "Notification Bot",
|
||||||
|
display_reply_to: "Notification Bot",
|
||||||
|
content,
|
||||||
|
unread: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -3,26 +3,21 @@ import $ from "jquery";
|
|||||||
import render_message_sent_banner from "../templates/compose_banner/message_sent_banner.hbs";
|
import render_message_sent_banner from "../templates/compose_banner/message_sent_banner.hbs";
|
||||||
import render_unmute_topic_banner from "../templates/compose_banner/unmute_topic_banner.hbs";
|
import render_unmute_topic_banner from "../templates/compose_banner/unmute_topic_banner.hbs";
|
||||||
|
|
||||||
import * as alert_words from "./alert_words";
|
|
||||||
import * as blueslip from "./blueslip";
|
import * as blueslip from "./blueslip";
|
||||||
import * as compose_banner from "./compose_banner";
|
import * as compose_banner from "./compose_banner";
|
||||||
import * as hash_util from "./hash_util";
|
import * as hash_util from "./hash_util";
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
import * as message_parser from "./message_parser";
|
|
||||||
import * as narrow from "./narrow";
|
import * as narrow from "./narrow";
|
||||||
import * as narrow_state from "./narrow_state";
|
import * as narrow_state from "./narrow_state";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
import * as spoilers from "./spoilers";
|
|
||||||
import * as stream_data from "./stream_data";
|
import * as stream_data from "./stream_data";
|
||||||
import * as ui_util from "./ui_util";
|
|
||||||
import * as unread from "./unread";
|
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
import * as user_topics from "./user_topics";
|
import * as user_topics from "./user_topics";
|
||||||
|
|
||||||
const notice_memory = new Map();
|
export const notice_memory = new Map();
|
||||||
|
|
||||||
let NotificationAPI;
|
export let NotificationAPI;
|
||||||
|
|
||||||
export function set_notification_api(n) {
|
export function set_notification_api(n) {
|
||||||
NotificationAPI = n;
|
NotificationAPI = n;
|
||||||
@@ -140,171 +135,6 @@ export function notify_above_composebox(
|
|||||||
compose_banner.append_compose_banner_to_banner_list($notification, $("#compose_banners"));
|
compose_banner.append_compose_banner_to_banner_list($notification, $("#compose_banners"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_notification_content(message) {
|
|
||||||
let content;
|
|
||||||
// Convert the content to plain text, replacing emoji with their alt text
|
|
||||||
const $content = $("<div>").html(message.content);
|
|
||||||
ui_util.replace_emoji_with_text($content);
|
|
||||||
spoilers.hide_spoilers_in_notification($content);
|
|
||||||
|
|
||||||
if (
|
|
||||||
$content.text().trim() === "" &&
|
|
||||||
(message_parser.message_has_image(message) ||
|
|
||||||
message_parser.message_has_attachment(message))
|
|
||||||
) {
|
|
||||||
content = $t({defaultMessage: "(attached file)"});
|
|
||||||
} else {
|
|
||||||
content = $content.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.is_me_message) {
|
|
||||||
content = message.sender_full_name + content.slice(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(message.type === "private" || message.type === "test-notification") &&
|
|
||||||
!user_settings.pm_content_in_desktop_notifications
|
|
||||||
) {
|
|
||||||
content = "New direct message from " + message.sender_full_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content.length > 150) {
|
|
||||||
let i;
|
|
||||||
// Truncate content at a word boundary
|
|
||||||
for (i = 150; i > 0; i -= 1) {
|
|
||||||
if (content[i] === " ") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content = content.slice(0, i);
|
|
||||||
content += " [...]";
|
|
||||||
}
|
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
function debug_notification_source_value(message) {
|
|
||||||
let notification_source;
|
|
||||||
|
|
||||||
if (message.type === "private" || message.type === "test-notification") {
|
|
||||||
notification_source = "pm";
|
|
||||||
} else if (message.mentioned) {
|
|
||||||
notification_source = "mention";
|
|
||||||
} else if (message.alerted) {
|
|
||||||
notification_source = "alert";
|
|
||||||
} else {
|
|
||||||
notification_source = "stream";
|
|
||||||
}
|
|
||||||
|
|
||||||
blueslip.debug("Desktop notification from source " + notification_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_notification_key(message) {
|
|
||||||
let key;
|
|
||||||
|
|
||||||
if (message.type === "private" || message.type === "test-notification") {
|
|
||||||
key = message.display_reply_to;
|
|
||||||
} else {
|
|
||||||
const stream_name = stream_data.get_stream_name_from_id(message.stream_id);
|
|
||||||
key = message.sender_full_name + " to " + stream_name + " > " + message.topic;
|
|
||||||
}
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove_sender_from_list_of_recipients(message) {
|
|
||||||
return `, ${message.display_reply_to}, `
|
|
||||||
.replace(`, ${message.sender_full_name}, `, ", ")
|
|
||||||
.slice(", ".length, -", ".length);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_notification_title(message, content, msg_count) {
|
|
||||||
let title = message.sender_full_name;
|
|
||||||
let other_recipients;
|
|
||||||
|
|
||||||
if (msg_count > 1) {
|
|
||||||
title = msg_count + " messages from " + title;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message.type) {
|
|
||||||
case "test-notification":
|
|
||||||
other_recipients = remove_sender_from_list_of_recipients(message);
|
|
||||||
break;
|
|
||||||
case "private":
|
|
||||||
other_recipients = remove_sender_from_list_of_recipients(message);
|
|
||||||
if (message.display_recipient.length > 2) {
|
|
||||||
// If the message has too many recipients to list them all...
|
|
||||||
if (content.length + title.length + other_recipients.length > 230) {
|
|
||||||
// Then count how many people are in the conversation and summarize
|
|
||||||
// by saying the conversation is with "you and [number] other people"
|
|
||||||
other_recipients =
|
|
||||||
other_recipients.replaceAll(/[^,]/g, "").length + " other people";
|
|
||||||
}
|
|
||||||
|
|
||||||
title += " (to you and " + other_recipients + ")";
|
|
||||||
} else {
|
|
||||||
title += " (to you)";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "stream": {
|
|
||||||
const stream_name = stream_data.get_stream_name_from_id(message.stream_id);
|
|
||||||
title += " (to " + stream_name + " > " + message.topic + ")";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function process_notification(notification) {
|
|
||||||
const message = notification.message;
|
|
||||||
const content = get_notification_content(message);
|
|
||||||
const key = get_notification_key(message);
|
|
||||||
let notification_object;
|
|
||||||
let msg_count = 1;
|
|
||||||
|
|
||||||
debug_notification_source_value(message);
|
|
||||||
|
|
||||||
if (notice_memory.has(key)) {
|
|
||||||
msg_count = notice_memory.get(key).msg_count + 1;
|
|
||||||
notification_object = notice_memory.get(key).obj;
|
|
||||||
notification_object.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = get_notification_title(message, content, msg_count);
|
|
||||||
|
|
||||||
if (notification.desktop_notify) {
|
|
||||||
const icon_url = people.small_avatar_url(message);
|
|
||||||
notification_object = new NotificationAPI(title, {
|
|
||||||
icon: icon_url,
|
|
||||||
body: content,
|
|
||||||
tag: message.id,
|
|
||||||
});
|
|
||||||
notice_memory.set(key, {
|
|
||||||
obj: notification_object,
|
|
||||||
msg_count,
|
|
||||||
message_id: message.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof notification_object.addEventListener === "function") {
|
|
||||||
// Sadly, some third-party Electron apps like Franz/Ferdi
|
|
||||||
// misimplement the Notification API not inheriting from
|
|
||||||
// EventTarget. This results in addEventListener being
|
|
||||||
// unavailable for them.
|
|
||||||
notification_object.addEventListener("click", () => {
|
|
||||||
notification_object.close();
|
|
||||||
if (message.type !== "test-notification") {
|
|
||||||
narrow.by_topic(message.id, {trigger: "notification"});
|
|
||||||
}
|
|
||||||
window.focus();
|
|
||||||
});
|
|
||||||
notification_object.addEventListener("close", () => {
|
|
||||||
notice_memory.delete(key);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function close_notification(message) {
|
export function close_notification(message) {
|
||||||
for (const [key, notice_mem_entry] of notice_memory) {
|
for (const [key, notice_mem_entry] of notice_memory) {
|
||||||
if (notice_mem_entry.message_id === message.id) {
|
if (notice_mem_entry.message_id === message.id) {
|
||||||
@@ -314,192 +144,6 @@ export function close_notification(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function message_is_notifiable(message) {
|
|
||||||
// Independent of the user's notification settings, are there
|
|
||||||
// properties of the message that unconditionally mean we
|
|
||||||
// shouldn't notify about it.
|
|
||||||
|
|
||||||
if (message.sent_by_me) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a message is edited multiple times, we want to err on the side of
|
|
||||||
// not spamming notifications.
|
|
||||||
if (message.notification_sent) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @-<username> mentions take precedence over muted-ness. Note
|
|
||||||
// that @all mentions are still suppressed by muting.
|
|
||||||
if (message.mentioned_me_directly) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages to followed topics take precedence over muted-ness.
|
|
||||||
if (
|
|
||||||
message.type === "stream" &&
|
|
||||||
user_topics.is_topic_followed(message.stream_id, message.topic)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages to unmuted topics in muted streams may generate desktop notifications.
|
|
||||||
if (
|
|
||||||
message.type === "stream" &&
|
|
||||||
stream_data.is_muted(message.stream_id) &&
|
|
||||||
!user_topics.is_topic_unmuted(message.stream_id, message.topic)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.type === "stream" && user_topics.is_topic_muted(message.stream_id, message.topic)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything else is on the table; next filter based on notification
|
|
||||||
// settings.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function should_send_desktop_notification(message) {
|
|
||||||
// Always notify for testing notifications.
|
|
||||||
if (message.type === "test-notification") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For streams, send if desktop notifications are enabled for all
|
|
||||||
// message on this stream.
|
|
||||||
if (
|
|
||||||
message.type === "stream" &&
|
|
||||||
stream_data.receives_notifications(message.stream_id, "desktop_notifications")
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable_followed_topic_desktop_notifications determines whether we pop up
|
|
||||||
// a notification for messages in followed topics.
|
|
||||||
if (
|
|
||||||
message.type === "stream" &&
|
|
||||||
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
|
||||||
user_settings.enable_followed_topic_desktop_notifications
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable_desktop_notifications determines whether we pop up a
|
|
||||||
// notification for direct messages, mentions, and/or alerts.
|
|
||||||
if (!user_settings.enable_desktop_notifications) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// And then we need to check if the message is a direct message,
|
|
||||||
// mention, wildcard mention with wildcard_mentions_notify, or alert.
|
|
||||||
if (message.type === "private") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alert_words.notifies(message)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.mentioned_me_directly) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following blocks for 'wildcard mentions' and 'Followed topic wildcard mentions'
|
|
||||||
// should be placed below (as they are right now) the 'user_settings.enable_desktop_notifications'
|
|
||||||
// block because the global, stream-specific, and followed topic wildcard mention
|
|
||||||
// settings are wrappers around the personal-mention setting.
|
|
||||||
// wildcard mentions
|
|
||||||
if (
|
|
||||||
message.mentioned &&
|
|
||||||
stream_data.receives_notifications(message.stream_id, "wildcard_mentions_notify")
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Followed topic wildcard mentions
|
|
||||||
if (
|
|
||||||
message.mentioned &&
|
|
||||||
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
|
||||||
user_settings.enable_followed_topic_wildcard_mentions_notify
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function should_send_audible_notification(message) {
|
|
||||||
// If `None` is selected as the notification sound, never send
|
|
||||||
// audible notifications regardless of other configuration.
|
|
||||||
if (user_settings.notification_sound === "none") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For streams, ding if sounds are enabled for all messages on
|
|
||||||
// this stream.
|
|
||||||
if (
|
|
||||||
message.type === "stream" &&
|
|
||||||
stream_data.receives_notifications(message.stream_id, "audible_notifications")
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable_followed_topic_audible_notifications determines whether we ding
|
|
||||||
// for messages in followed topics.
|
|
||||||
if (
|
|
||||||
message.type === "stream" &&
|
|
||||||
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
|
||||||
user_settings.enable_followed_topic_audible_notifications
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable_sounds determines whether we ding for direct messages,
|
|
||||||
// mentions, and/or alerts.
|
|
||||||
if (!user_settings.enable_sounds) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// And then we need to check if the message is a direct message,
|
|
||||||
// mention, wildcard mention with wildcard_mentions_notify, or alert.
|
|
||||||
if (message.type === "private" || message.type === "test-notification") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alert_words.notifies(message)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.mentioned_me_directly) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following blocks for 'wildcard mentions' and 'Followed topic wildcard mentions'
|
|
||||||
// should be placed below (as they are right now) the 'user_settings.enable_sounds'
|
|
||||||
// block because the global, stream-specific, and followed topic wildcard mention
|
|
||||||
// settings are wrappers around the personal-mention setting.
|
|
||||||
// wildcard mentions
|
|
||||||
if (
|
|
||||||
message.mentioned &&
|
|
||||||
stream_data.receives_notifications(message.stream_id, "wildcard_mentions_notify")
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Followed topic wildcard mentions
|
|
||||||
if (
|
|
||||||
message.mentioned &&
|
|
||||||
user_topics.is_topic_followed(message.stream_id, message.topic) &&
|
|
||||||
user_settings.enable_followed_topic_wildcard_mentions_notify
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function granted_desktop_notifications_permission() {
|
export function granted_desktop_notifications_permission() {
|
||||||
return NotificationAPI && NotificationAPI.permission === "granted";
|
return NotificationAPI && NotificationAPI.permission === "granted";
|
||||||
}
|
}
|
||||||
@@ -510,44 +154,6 @@ export function request_desktop_notifications_permission() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function received_messages(messages) {
|
|
||||||
for (const message of messages) {
|
|
||||||
if (!message_is_notifiable(message)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!unread.message_unread(message)) {
|
|
||||||
// The message is already read; Zulip is currently in focus.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.notification_sent = true;
|
|
||||||
|
|
||||||
if (should_send_desktop_notification(message)) {
|
|
||||||
process_notification({
|
|
||||||
message,
|
|
||||||
desktop_notify: granted_desktop_notifications_permission(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (should_send_audible_notification(message)) {
|
|
||||||
ui_util.play_audio($("#user-notification-sound-audio")[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function send_test_notification(content) {
|
|
||||||
received_messages([
|
|
||||||
{
|
|
||||||
id: Math.random(),
|
|
||||||
type: "test-notification",
|
|
||||||
sender_email: "notification-bot@zulip.com",
|
|
||||||
sender_full_name: "Notification Bot",
|
|
||||||
display_reply_to: "Notification Bot",
|
|
||||||
content,
|
|
||||||
unread: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that this returns values that are not HTML-escaped, for use in
|
// Note that this returns values that are not HTML-escaped, for use in
|
||||||
// Handlebars templates that will do further escaping.
|
// Handlebars templates that will do further escaping.
|
||||||
function get_message_header(message) {
|
function get_message_header(message) {
|
||||||
@@ -736,13 +342,13 @@ export function reify_message_id(opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function register_click_handlers({on_click_scroll_to_selected}) {
|
export function register_click_handlers({on_click_scroll_to_selected}) {
|
||||||
$("#compose_banners").on(
|
$("#compose_banners").on(
|
||||||
"click",
|
"click",
|
||||||
".narrow_to_recipient .above_compose_banner_action_link",
|
".narrow_to_recipient .above_compose_banner_action_link",
|
||||||
(e) => {
|
(e) => {
|
||||||
const message_id = $(e.currentTarget).data("message-id");
|
const message_id = $(e.currentTarget).data("message-id");
|
||||||
narrow.by_topic(message_id, {trigger: "compose_notification"});
|
narrow.by_topic(message_id, {trigger: "notification"});
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as blueslip from "./blueslip";
|
|||||||
import * as channel from "./channel";
|
import * as channel from "./channel";
|
||||||
import * as confirm_dialog from "./confirm_dialog";
|
import * as confirm_dialog from "./confirm_dialog";
|
||||||
import {$t, $t_html} from "./i18n";
|
import {$t, $t_html} from "./i18n";
|
||||||
import * as notifications from "./notifications";
|
import * as message_notifications from "./message_notifications";
|
||||||
import {page_params} from "./page_params";
|
import {page_params} from "./page_params";
|
||||||
import * as settings_config from "./settings_config";
|
import * as settings_config from "./settings_config";
|
||||||
import * as settings_org from "./settings_org";
|
import * as settings_org from "./settings_org";
|
||||||
@@ -280,7 +280,7 @@ export function set_up(settings_panel) {
|
|||||||
// intentionally don't let organization administrators set
|
// intentionally don't let organization administrators set
|
||||||
// organization-level defaults.
|
// organization-level defaults.
|
||||||
$container.find(".send_test_notification").on("click", () => {
|
$container.find(".send_test_notification").on("click", () => {
|
||||||
notifications.send_test_notification(
|
message_notifications.send_test_notification(
|
||||||
$t({defaultMessage: "This is what a Zulip notification looks like."}),
|
$t({defaultMessage: "This is what a Zulip notification looks like."}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ const {run_test} = require("./lib/test");
|
|||||||
// replace them with {}.
|
// replace them with {}.
|
||||||
const huddle_data = mock_esm("../src/huddle_data");
|
const huddle_data = mock_esm("../src/huddle_data");
|
||||||
const message_lists = mock_esm("../src/message_lists");
|
const message_lists = mock_esm("../src/message_lists");
|
||||||
|
const message_notifications = mock_esm("../src/message_notifications");
|
||||||
const message_util = mock_esm("../src/message_util");
|
const message_util = mock_esm("../src/message_util");
|
||||||
const notifications = mock_esm("../src/notifications");
|
|
||||||
const pm_list = mock_esm("../src/pm_list");
|
const pm_list = mock_esm("../src/pm_list");
|
||||||
const recent_view_data = mock_esm("../src/recent_view_data");
|
const recent_view_data = mock_esm("../src/recent_view_data");
|
||||||
const stream_list = mock_esm("../src/stream_list");
|
const stream_list = mock_esm("../src/stream_list");
|
||||||
@@ -99,9 +99,9 @@ run_test("insert_message", ({override}) => {
|
|||||||
assert.equal(message_store.get(new_message.id), undefined);
|
assert.equal(message_store.get(new_message.id), undefined);
|
||||||
|
|
||||||
helper.redirect(huddle_data, "process_loaded_messages");
|
helper.redirect(huddle_data, "process_loaded_messages");
|
||||||
|
helper.redirect(message_notifications, "received_messages");
|
||||||
helper.redirect(message_util, "add_new_messages_data");
|
helper.redirect(message_util, "add_new_messages_data");
|
||||||
helper.redirect(message_util, "add_new_messages");
|
helper.redirect(message_util, "add_new_messages");
|
||||||
helper.redirect(notifications, "received_messages");
|
|
||||||
helper.redirect(recent_view_data, "process_message");
|
helper.redirect(recent_view_data, "process_message");
|
||||||
helper.redirect(stream_list, "update_streams_sidebar");
|
helper.redirect(stream_list, "update_streams_sidebar");
|
||||||
helper.redirect(unread_ops, "process_visible");
|
helper.redirect(unread_ops, "process_visible");
|
||||||
@@ -122,7 +122,7 @@ run_test("insert_message", ({override}) => {
|
|||||||
[message_util, "add_new_messages"],
|
[message_util, "add_new_messages"],
|
||||||
[unread_ui, "update_unread_counts"],
|
[unread_ui, "update_unread_counts"],
|
||||||
[unread_ops, "process_visible"],
|
[unread_ops, "process_visible"],
|
||||||
[notifications, "received_messages"],
|
[message_notifications, "received_messages"],
|
||||||
[stream_list, "update_streams_sidebar"],
|
[stream_list, "update_streams_sidebar"],
|
||||||
[recent_view_data, "process_message"],
|
[recent_view_data, "process_message"],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const {page_params} = require("./lib/zpage_params");
|
|||||||
|
|
||||||
const message_edit = mock_esm("../src/message_edit");
|
const message_edit = mock_esm("../src/message_edit");
|
||||||
const message_lists = mock_esm("../src/message_lists");
|
const message_lists = mock_esm("../src/message_lists");
|
||||||
const notifications = mock_esm("../src/notifications");
|
const message_notifications = mock_esm("../src/message_notifications");
|
||||||
const pm_list = mock_esm("../src/pm_list");
|
const pm_list = mock_esm("../src/pm_list");
|
||||||
const stream_list = mock_esm("../src/stream_list");
|
const stream_list = mock_esm("../src/stream_list");
|
||||||
const unread_ui = mock_esm("../src/unread_ui");
|
const unread_ui = mock_esm("../src/unread_ui");
|
||||||
@@ -99,7 +99,7 @@ run_test("update_messages", () => {
|
|||||||
|
|
||||||
const side_effects = [
|
const side_effects = [
|
||||||
[message_edit, "end_message_edit"],
|
[message_edit, "end_message_edit"],
|
||||||
[notifications, "received_messages"],
|
[message_notifications, "received_messages"],
|
||||||
[unread_ui, "update_unread_counts"],
|
[unread_ui, "update_unread_counts"],
|
||||||
[stream_list, "update_streams_sidebar"],
|
[stream_list, "update_streams_sidebar"],
|
||||||
[pm_list, "update_private_messages"],
|
[pm_list, "update_private_messages"],
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const user_topics = zrequire("user_topics");
|
|||||||
const stream_data = zrequire("stream_data");
|
const stream_data = zrequire("stream_data");
|
||||||
|
|
||||||
const notifications = zrequire("notifications");
|
const notifications = zrequire("notifications");
|
||||||
|
const message_notifications = zrequire("message_notifications");
|
||||||
|
|
||||||
// Not muted streams
|
// Not muted streams
|
||||||
const general = {
|
const general = {
|
||||||
@@ -82,10 +83,10 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "whatever",
|
topic: "whatever",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
// Not notifiable because it was sent by the current user
|
// Not notifiable because it was sent by the current user
|
||||||
assert.equal(notifications.message_is_notifiable(message), false);
|
assert.equal(message_notifications.message_is_notifiable(message), false);
|
||||||
|
|
||||||
// Case 2: If the user has already been sent a notification about this message,
|
// Case 2: If the user has already been sent a notification about this message,
|
||||||
// DO NOT notify the user
|
// DO NOT notify the user
|
||||||
@@ -103,9 +104,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "whatever",
|
topic: "whatever",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), false);
|
assert.equal(message_notifications.message_is_notifiable(message), false);
|
||||||
|
|
||||||
// Case 3: If a message mentions the user directly,
|
// Case 3: If a message mentions the user directly,
|
||||||
// DO notify the user
|
// DO notify the user
|
||||||
@@ -121,9 +122,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: muted.stream_id,
|
stream_id: muted.stream_id,
|
||||||
topic: "topic_three",
|
topic: "topic_three",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Case 4: If the message has been sent to a followed topic,
|
// Case 4: If the message has been sent to a followed topic,
|
||||||
// DO visually and audibly notify the user if 'enable_followed_topic_desktop_notifications'
|
// DO visually and audibly notify the user if 'enable_followed_topic_desktop_notifications'
|
||||||
@@ -140,17 +141,17 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "followed topic",
|
topic: "followed topic",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// But not if 'enable_followed_topic_desktop_notifications'
|
// But not if 'enable_followed_topic_desktop_notifications'
|
||||||
// and 'enable_followed_topic_audible_notifications' are disabled.
|
// and 'enable_followed_topic_audible_notifications' are disabled.
|
||||||
user_settings.enable_followed_topic_desktop_notifications = false;
|
user_settings.enable_followed_topic_desktop_notifications = false;
|
||||||
user_settings.enable_followed_topic_audible_notifications = false;
|
user_settings.enable_followed_topic_audible_notifications = false;
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), false);
|
assert.equal(message_notifications.should_send_desktop_notification(message), false);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), false);
|
assert.equal(message_notifications.should_send_audible_notification(message), false);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
user_settings.enable_followed_topic_desktop_notifications = true;
|
user_settings.enable_followed_topic_desktop_notifications = true;
|
||||||
@@ -168,9 +169,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "vanilla",
|
topic: "vanilla",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Case 6:
|
// Case 6:
|
||||||
// Wildcard mention should trigger notification in unmuted topic
|
// Wildcard mention should trigger notification in unmuted topic
|
||||||
@@ -186,21 +187,21 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "vanilla",
|
topic: "vanilla",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// But not if it's disabled
|
// But not if it's disabled
|
||||||
user_settings.wildcard_mentions_notify = false;
|
user_settings.wildcard_mentions_notify = false;
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), false);
|
assert.equal(message_notifications.should_send_desktop_notification(message), false);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), false);
|
assert.equal(message_notifications.should_send_audible_notification(message), false);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// And the stream-level setting overrides the global setting
|
// And the stream-level setting overrides the global setting
|
||||||
general.wildcard_mentions_notify = true;
|
general.wildcard_mentions_notify = true;
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
user_settings.wildcard_mentions_notify = true;
|
user_settings.wildcard_mentions_notify = true;
|
||||||
@@ -220,9 +221,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: muted.stream_id,
|
stream_id: muted.stream_id,
|
||||||
topic: "whatever",
|
topic: "whatever",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), false);
|
assert.equal(message_notifications.message_is_notifiable(message), false);
|
||||||
|
|
||||||
// Case 8: If a message is in a muted stream
|
// Case 8: If a message is in a muted stream
|
||||||
// and does mention the user DIRECTLY,
|
// and does mention the user DIRECTLY,
|
||||||
@@ -238,9 +239,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: muted.stream_id,
|
stream_id: muted.stream_id,
|
||||||
topic: "whatever",
|
topic: "whatever",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Case 9: If a message is in a muted topic
|
// Case 9: If a message is in a muted topic
|
||||||
// and does not mention the user DIRECTLY (i.e. wildcard mention),
|
// and does not mention the user DIRECTLY (i.e. wildcard mention),
|
||||||
@@ -256,9 +257,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "muted topic",
|
topic: "muted topic",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), false);
|
assert.equal(message_notifications.message_is_notifiable(message), false);
|
||||||
|
|
||||||
// Case 10:
|
// Case 10:
|
||||||
// Wildcard mentions in a followed topic with 'wildcard_mentions_notify',
|
// Wildcard mentions in a followed topic with 'wildcard_mentions_notify',
|
||||||
@@ -280,15 +281,15 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "followed topic",
|
topic: "followed topic",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), true);
|
assert.equal(message_notifications.should_send_audible_notification(message), true);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// But not if 'enable_followed_topic_wildcard_mentions_notify' is disabled
|
// But not if 'enable_followed_topic_wildcard_mentions_notify' is disabled
|
||||||
user_settings.enable_followed_topic_wildcard_mentions_notify = false;
|
user_settings.enable_followed_topic_wildcard_mentions_notify = false;
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), false);
|
assert.equal(message_notifications.should_send_desktop_notification(message), false);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), false);
|
assert.equal(message_notifications.should_send_audible_notification(message), false);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
user_settings.wildcard_mentions_notify = true;
|
user_settings.wildcard_mentions_notify = true;
|
||||||
@@ -310,9 +311,9 @@ test("message_is_notifiable", () => {
|
|||||||
topic: "whatever",
|
topic: "whatever",
|
||||||
};
|
};
|
||||||
user_settings.notification_sound = "none";
|
user_settings.notification_sound = "none";
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), true);
|
assert.equal(message_notifications.should_send_desktop_notification(message), true);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), false);
|
assert.equal(message_notifications.should_send_audible_notification(message), false);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
user_settings.notification_sound = "ding";
|
user_settings.notification_sound = "ding";
|
||||||
@@ -332,9 +333,9 @@ test("message_is_notifiable", () => {
|
|||||||
stream_id: general.stream_id,
|
stream_id: general.stream_id,
|
||||||
topic: "whatever",
|
topic: "whatever",
|
||||||
};
|
};
|
||||||
assert.equal(notifications.should_send_desktop_notification(message), false);
|
assert.equal(message_notifications.should_send_desktop_notification(message), false);
|
||||||
assert.equal(notifications.should_send_audible_notification(message), false);
|
assert.equal(message_notifications.should_send_audible_notification(message), false);
|
||||||
assert.equal(notifications.message_is_notifiable(message), true);
|
assert.equal(message_notifications.message_is_notifiable(message), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("basic_notifications", () => {
|
test("basic_notifications", () => {
|
||||||
@@ -393,7 +394,7 @@ test("basic_notifications", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send notification.
|
// Send notification.
|
||||||
notifications.process_notification({message: message_1, desktop_notify: true});
|
message_notifications.process_notification({message: message_1, desktop_notify: true});
|
||||||
n = notifications.get_notifications();
|
n = notifications.get_notifications();
|
||||||
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
||||||
assert.equal(n.size, 1);
|
assert.equal(n.size, 1);
|
||||||
@@ -408,7 +409,7 @@ test("basic_notifications", () => {
|
|||||||
|
|
||||||
// Send notification.
|
// Send notification.
|
||||||
message_1.id = 1001;
|
message_1.id = 1001;
|
||||||
notifications.process_notification({message: message_1, desktop_notify: true});
|
message_notifications.process_notification({message: message_1, desktop_notify: true});
|
||||||
n = notifications.get_notifications();
|
n = notifications.get_notifications();
|
||||||
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
||||||
assert.equal(n.size, 1);
|
assert.equal(n.size, 1);
|
||||||
@@ -416,14 +417,14 @@ test("basic_notifications", () => {
|
|||||||
|
|
||||||
// Process same message again. Notification count shouldn't increase.
|
// Process same message again. Notification count shouldn't increase.
|
||||||
message_1.id = 1002;
|
message_1.id = 1002;
|
||||||
notifications.process_notification({message: message_1, desktop_notify: true});
|
message_notifications.process_notification({message: message_1, desktop_notify: true});
|
||||||
n = notifications.get_notifications();
|
n = notifications.get_notifications();
|
||||||
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
||||||
assert.equal(n.size, 1);
|
assert.equal(n.size, 1);
|
||||||
assert.equal(last_shown_message_id, message_1.id);
|
assert.equal(last_shown_message_id, message_1.id);
|
||||||
|
|
||||||
// Send another message. Notification count should increase.
|
// Send another message. Notification count should increase.
|
||||||
notifications.process_notification({message: message_2, desktop_notify: true});
|
message_notifications.process_notification({message: message_2, desktop_notify: true});
|
||||||
n = notifications.get_notifications();
|
n = notifications.get_notifications();
|
||||||
assert.equal(n.has("Gus Fring to general > lunch"), true);
|
assert.equal(n.has("Gus Fring to general > lunch"), true);
|
||||||
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
assert.equal(n.has("Jesse Pinkman to general > whatever"), true);
|
||||||
|
|||||||
Reference in New Issue
Block a user