2021-04-04 15:15:18 +02:00
|
|
|
import * as hash_util from "./hash_util";
|
|
|
|
import * as peer_data from "./peer_data";
|
2024-03-23 08:06:21 +01:00
|
|
|
import type {User} from "./people";
|
2021-04-04 15:15:18 +02:00
|
|
|
import * as settings_config from "./settings_config";
|
2024-02-13 02:08:16 +01:00
|
|
|
import {current_user} from "./state_data";
|
2021-04-04 15:15:18 +02:00
|
|
|
import * as stream_data from "./stream_data";
|
2023-10-12 02:41:29 +02:00
|
|
|
import type {StreamSpecificNotificationSettings, StreamSubscription} from "./sub_store";
|
2021-04-15 17:02:54 +02:00
|
|
|
import * as sub_store from "./sub_store";
|
2024-03-23 08:06:21 +01:00
|
|
|
import * as timerender from "./timerender";
|
2021-07-28 16:00:58 +02:00
|
|
|
import {user_settings} from "./user_settings";
|
2021-04-04 15:15:18 +02:00
|
|
|
import * as util from "./util";
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
export type SettingsSubscription = StreamSubscription & {
|
2024-03-23 08:06:21 +01:00
|
|
|
date_created_string: string;
|
2023-10-12 02:41:29 +02:00
|
|
|
is_realm_admin: boolean;
|
2024-03-23 08:06:21 +01:00
|
|
|
creator: User | undefined;
|
|
|
|
is_creator: boolean;
|
2023-10-12 02:41:29 +02:00
|
|
|
can_change_name_description: boolean;
|
|
|
|
should_display_subscription_button: boolean;
|
|
|
|
should_display_preview_button: boolean;
|
|
|
|
can_change_stream_permissions: boolean;
|
|
|
|
can_access_subscribers: boolean;
|
|
|
|
can_add_subscribers: boolean;
|
|
|
|
can_remove_subscribers: boolean;
|
|
|
|
preview_url: string;
|
|
|
|
is_old_stream: boolean;
|
|
|
|
subscriber_count: number;
|
|
|
|
};
|
|
|
|
|
|
|
|
export function get_sub_for_settings(sub: StreamSubscription): SettingsSubscription {
|
2023-10-12 02:30:57 +02:00
|
|
|
return {
|
|
|
|
...sub,
|
|
|
|
|
2024-03-23 08:06:21 +01:00
|
|
|
// We get timestamp in seconds from the API but timerender needs milliseconds.
|
|
|
|
date_created_string: timerender.get_localized_date_or_time_for_format(
|
|
|
|
new Date(sub.date_created * 1000),
|
|
|
|
"dayofyear_year",
|
|
|
|
),
|
|
|
|
creator: stream_data.maybe_get_creator_details(sub.creator_id),
|
|
|
|
|
|
|
|
is_creator: sub.creator_id === current_user.user_id,
|
2024-02-13 02:08:16 +01:00
|
|
|
is_realm_admin: current_user.is_admin,
|
2023-10-12 02:30:57 +02:00
|
|
|
// Admin can change any stream's name & description either stream is public or
|
|
|
|
// private, subscribed or unsubscribed.
|
2024-09-13 21:18:15 +02:00
|
|
|
can_change_name_description: stream_data.can_edit_description(),
|
2023-10-12 02:30:57 +02:00
|
|
|
|
|
|
|
should_display_subscription_button: stream_data.can_toggle_subscription(sub),
|
|
|
|
should_display_preview_button: stream_data.can_preview(sub),
|
|
|
|
can_change_stream_permissions: stream_data.can_change_permissions(sub),
|
|
|
|
can_access_subscribers: stream_data.can_view_subscribers(sub),
|
|
|
|
can_add_subscribers: stream_data.can_subscribe_others(sub),
|
|
|
|
can_remove_subscribers: stream_data.can_unsubscribe_others(sub),
|
|
|
|
|
|
|
|
preview_url: hash_util.by_stream_url(sub.stream_id),
|
|
|
|
is_old_stream: sub.stream_weekly_traffic !== null,
|
|
|
|
|
|
|
|
subscriber_count: peer_data.get_subscriber_count(sub.stream_id),
|
|
|
|
};
|
2021-04-04 15:15:18 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
function get_subs_for_settings(subs: StreamSubscription[]): SettingsSubscription[] {
|
2021-04-04 15:15:18 +02:00
|
|
|
// We may eventually add subscribers to the subs here, rather than
|
|
|
|
// delegating, so that we can more efficiently compute subscriber counts
|
|
|
|
// (in bulk). If that plan appears to have been aborted, feel free to
|
|
|
|
// inline this.
|
2024-01-27 20:20:37 +01:00
|
|
|
return subs.filter((sub) => !sub.is_archived).map((sub) => get_sub_for_settings(sub));
|
2021-04-04 15:15:18 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
export function get_updated_unsorted_subs(): SettingsSubscription[] {
|
2021-04-04 15:15:18 +02:00
|
|
|
let all_subs = stream_data.get_unsorted_subs();
|
|
|
|
|
|
|
|
// We don't display unsubscribed streams to guest users.
|
2024-02-13 02:08:16 +01:00
|
|
|
if (current_user.is_guest) {
|
2021-04-04 15:15:18 +02:00
|
|
|
all_subs = all_subs.filter((sub) => sub.subscribed);
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_subs_for_settings(all_subs);
|
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
export function get_unmatched_streams_for_notification_settings(): ({
|
|
|
|
[notification_name in keyof StreamSpecificNotificationSettings]: boolean;
|
|
|
|
} & {
|
|
|
|
stream_name: string;
|
|
|
|
stream_id: number;
|
|
|
|
color: string;
|
|
|
|
invite_only: boolean;
|
|
|
|
is_web_public: boolean;
|
|
|
|
})[] {
|
2021-04-04 15:15:18 +02:00
|
|
|
const subscribed_rows = stream_data.subscribed_subs();
|
|
|
|
subscribed_rows.sort((a, b) => util.strcmp(a.name, b.name));
|
|
|
|
|
|
|
|
const notification_settings = [];
|
|
|
|
for (const row of subscribed_rows) {
|
|
|
|
let make_table_row = false;
|
2023-10-12 02:41:29 +02:00
|
|
|
function get_notification_setting(
|
|
|
|
notification_name: keyof StreamSpecificNotificationSettings,
|
|
|
|
): boolean {
|
2022-08-25 21:09:32 +02:00
|
|
|
const default_setting =
|
|
|
|
user_settings[
|
|
|
|
settings_config.generalize_stream_notification_setting[notification_name]
|
|
|
|
];
|
2021-04-04 15:15:18 +02:00
|
|
|
const stream_setting = stream_data.receives_notifications(
|
|
|
|
row.stream_id,
|
|
|
|
notification_name,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (stream_setting !== default_setting) {
|
|
|
|
make_table_row = true;
|
|
|
|
}
|
2023-10-12 02:30:57 +02:00
|
|
|
return stream_setting;
|
2021-04-04 15:15:18 +02:00
|
|
|
}
|
2023-10-12 02:30:57 +02:00
|
|
|
const settings_values = {
|
|
|
|
desktop_notifications: get_notification_setting("desktop_notifications"),
|
|
|
|
audible_notifications: get_notification_setting("audible_notifications"),
|
|
|
|
push_notifications: get_notification_setting("push_notifications"),
|
|
|
|
email_notifications: get_notification_setting("email_notifications"),
|
|
|
|
wildcard_mentions_notify: get_notification_setting("wildcard_mentions_notify"),
|
|
|
|
};
|
2021-04-04 15:15:18 +02:00
|
|
|
// We do not need to display the streams whose settings
|
|
|
|
// match with the global settings defined by the user.
|
|
|
|
if (make_table_row) {
|
2023-10-12 02:30:57 +02:00
|
|
|
notification_settings.push({
|
|
|
|
...settings_values,
|
|
|
|
stream_name: row.name,
|
|
|
|
stream_id: row.stream_id,
|
|
|
|
color: row.color,
|
|
|
|
invite_only: row.invite_only,
|
|
|
|
is_web_public: row.is_web_public,
|
|
|
|
});
|
2021-04-04 15:15:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return notification_settings;
|
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
export function get_streams_for_settings_page(): SettingsSubscription[] {
|
2021-04-04 15:15:18 +02:00
|
|
|
// TODO: This function is only used for copy-from-stream, so
|
|
|
|
// the current name is slightly misleading now, plus
|
|
|
|
// it's not entirely clear we need unsubscribed streams
|
|
|
|
// for that. Also we may be revisiting that UI.
|
|
|
|
|
|
|
|
// Build up our list of subscribed streams from the data we already have.
|
|
|
|
const subscribed_rows = stream_data.subscribed_subs();
|
|
|
|
const unsubscribed_rows = stream_data.unsubscribed_subs();
|
|
|
|
|
|
|
|
// Sort and combine all our streams.
|
2023-10-12 02:41:29 +02:00
|
|
|
function by_name(a: StreamSubscription, b: StreamSubscription): number {
|
2021-04-04 15:15:18 +02:00
|
|
|
return util.strcmp(a.name, b.name);
|
|
|
|
}
|
|
|
|
subscribed_rows.sort(by_name);
|
|
|
|
unsubscribed_rows.sort(by_name);
|
2023-03-02 01:58:25 +01:00
|
|
|
const all_subs = [...unsubscribed_rows, ...subscribed_rows];
|
2021-04-04 15:15:18 +02:00
|
|
|
|
|
|
|
return get_subs_for_settings(all_subs);
|
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
export function sort_for_stream_settings(stream_ids: number[], order: string): void {
|
|
|
|
function name(stream_id: number): string {
|
2021-04-15 17:02:54 +02:00
|
|
|
const sub = sub_store.get(stream_id);
|
2021-04-04 15:15:18 +02:00
|
|
|
if (!sub) {
|
|
|
|
return "";
|
|
|
|
}
|
2021-06-12 12:16:43 +02:00
|
|
|
return sub.name;
|
2021-04-04 15:15:18 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
function weekly_traffic(stream_id: number): number {
|
2021-04-15 17:02:54 +02:00
|
|
|
const sub = sub_store.get(stream_id);
|
2021-04-04 18:21:29 +02:00
|
|
|
if (sub && sub.stream_weekly_traffic !== null) {
|
2021-04-04 15:15:18 +02:00
|
|
|
return sub.stream_weekly_traffic;
|
|
|
|
}
|
|
|
|
// don't intersperse new streams with zero-traffic existing streams
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
function by_stream_name(id_a: number, id_b: number): number {
|
2021-04-04 15:15:18 +02:00
|
|
|
const stream_a_name = name(id_a);
|
|
|
|
const stream_b_name = name(id_b);
|
2021-06-12 12:16:43 +02:00
|
|
|
return util.strcmp(stream_a_name, stream_b_name);
|
2021-04-04 15:15:18 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
function by_subscriber_count(id_a: number, id_b: number): number {
|
2021-04-04 15:15:18 +02:00
|
|
|
const out = peer_data.get_subscriber_count(id_b) - peer_data.get_subscriber_count(id_a);
|
|
|
|
if (out === 0) {
|
|
|
|
return by_stream_name(id_a, id_b);
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2023-10-12 02:41:29 +02:00
|
|
|
function by_weekly_traffic(id_a: number, id_b: number): number {
|
2021-04-04 15:15:18 +02:00
|
|
|
const out = weekly_traffic(id_b) - weekly_traffic(id_a);
|
|
|
|
if (out === 0) {
|
|
|
|
return by_stream_name(id_a, id_b);
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
const orders = new Map([
|
|
|
|
["by-stream-name", by_stream_name],
|
|
|
|
["by-subscriber-count", by_subscriber_count],
|
|
|
|
["by-weekly-traffic", by_weekly_traffic],
|
|
|
|
]);
|
|
|
|
|
|
|
|
if (order === undefined || !orders.has(order)) {
|
|
|
|
order = "by-stream-name";
|
|
|
|
}
|
|
|
|
|
|
|
|
stream_ids.sort(orders.get(order));
|
|
|
|
}
|