mirror of
https://github.com/zulip/zulip.git
synced 2026-06-30 21:11:04 +08:00
Some checks failed
Code scanning / CodeQL (push) Has been cancelled
Zulip production suite / Ubuntu 22.04 production build (push) Has been cancelled
Zulip CI / ${{ matrix.name }} (zulip/ci:bookworm, true, false, Debian 12 (Python 3.11, backend + documentation), bookworm) (push) Has been cancelled
Zulip CI / ${{ matrix.name }} (zulip/ci:jammy, false, true, Ubuntu 22.04 (Python 3.10, backend + frontend), jammy) (push) Has been cancelled
Zulip CI / ${{ matrix.name }} (zulip/ci:noble, false, false, Ubuntu 24.04 (Python 3.12, backend), noble) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:bookworm, --test-custom-db, Debian 12 production install with custom db name and user, bookworm) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:jammy, , Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga, jammy) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:noble, , Ubuntu 24.04 production install, noble) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:bookworm-7.0, 7.0 Version Upgrade, bookworm) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:bookworm-8.0, 8.0 Version Upgrade, bookworm) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:jammy-6.0, 6.0 Version Upgrade, jammy) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:noble-9.0, 9.0 Version Upgrade, noble) (push) Has been cancelled
Previously, when the guest role was selected in the Invite modal and guests were restricted from viewing all other users, there was no indication of how many users the invited guests would be able to see once they joined. This commit resolves that issue by adding a note in the Invite modal that dynamically informs users of the number of visible users. Fixes #31159.
176 lines
5.2 KiB
TypeScript
176 lines
5.2 KiB
TypeScript
import * as blueslip from "./blueslip";
|
|
import {LazySet} from "./lazy_set";
|
|
import type {User} from "./people";
|
|
import * as people from "./people";
|
|
import * as sub_store from "./sub_store";
|
|
|
|
// This maps a stream_id to a LazySet of user_ids who are subscribed.
|
|
const stream_subscribers = new Map<number, LazySet>();
|
|
|
|
export function clear_for_testing(): void {
|
|
stream_subscribers.clear();
|
|
}
|
|
|
|
function get_user_set(stream_id: number): LazySet {
|
|
// This is an internal function to get the LazySet of users.
|
|
// We create one on the fly as necessary, but we warn in that case.
|
|
if (!sub_store.get(stream_id)) {
|
|
blueslip.warn(`We called get_user_set for an untracked stream: ${stream_id}`);
|
|
}
|
|
|
|
let subscribers = stream_subscribers.get(stream_id);
|
|
|
|
if (subscribers === undefined) {
|
|
subscribers = new LazySet([]);
|
|
stream_subscribers.set(stream_id, subscribers);
|
|
}
|
|
|
|
return subscribers;
|
|
}
|
|
|
|
export function is_subscriber_subset(stream_id1: number, stream_id2: number): boolean {
|
|
const sub1_set = get_user_set(stream_id1);
|
|
const sub2_set = get_user_set(stream_id2);
|
|
|
|
return [...sub1_set.keys()].every((key) => sub2_set.has(key));
|
|
}
|
|
|
|
export function potential_subscribers(stream_id: number): User[] {
|
|
/*
|
|
This is a list of unsubscribed users
|
|
for the current stream, who the current
|
|
user could potentially subscribe to the
|
|
stream. This may include some bots.
|
|
|
|
We currently use it for typeahead in
|
|
stream_edit.js.
|
|
|
|
This may be a superset of the actual
|
|
subscribers that you can change in some cases
|
|
(like if you're a guest?); we should refine this
|
|
going forward, especially if we use it for something
|
|
other than typeahead. (The guest use case
|
|
may be moot now for other reasons.)
|
|
*/
|
|
|
|
const subscribers = get_user_set(stream_id);
|
|
|
|
function is_potential_subscriber(person: User): boolean {
|
|
// Use verbose style to force better test
|
|
// coverage, plus we may add more conditions over
|
|
// time.
|
|
if (subscribers.has(person.user_id)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return people.filter_all_users(is_potential_subscriber);
|
|
}
|
|
|
|
export function get_subscriber_count(stream_id: number, include_bots = true): number {
|
|
if (include_bots) {
|
|
return get_user_set(stream_id).size;
|
|
}
|
|
|
|
let count = 0;
|
|
for (const user_id of get_user_set(stream_id).keys()) {
|
|
if (!people.is_valid_bot_user(user_id) && people.is_person_active(user_id)) {
|
|
count += 1;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
export function get_subscribers(stream_id: number): number[] {
|
|
// This is our external interface for callers who just
|
|
// want an array of user_ids who are subscribed to a stream.
|
|
const subscribers = get_user_set(stream_id);
|
|
|
|
return [...subscribers.keys()];
|
|
}
|
|
|
|
export function set_subscribers(stream_id: number, user_ids: number[]): void {
|
|
const subscribers = new LazySet(user_ids);
|
|
stream_subscribers.set(stream_id, subscribers);
|
|
}
|
|
|
|
export function add_subscriber(stream_id: number, user_id: number): void {
|
|
// If stream_id/user_id are unknown to us, we will
|
|
// still track it, but we will warn.
|
|
const subscribers = get_user_set(stream_id);
|
|
const person = people.maybe_get_user_by_id(user_id);
|
|
if (person === undefined) {
|
|
blueslip.warn(`We tried to add invalid subscriber: ${user_id}`);
|
|
}
|
|
subscribers.add(user_id);
|
|
}
|
|
|
|
export function remove_subscriber(stream_id: number, user_id: number): boolean {
|
|
const subscribers = get_user_set(stream_id);
|
|
if (!subscribers.has(user_id)) {
|
|
blueslip.warn(`We tried to remove invalid subscriber: ${user_id}`);
|
|
return false;
|
|
}
|
|
|
|
subscribers.delete(user_id);
|
|
|
|
return true;
|
|
}
|
|
|
|
export function bulk_add_subscribers({
|
|
stream_ids,
|
|
user_ids,
|
|
}: {
|
|
stream_ids: number[];
|
|
user_ids: number[];
|
|
}): void {
|
|
// We rely on our callers to validate stream_ids and user_ids.
|
|
for (const stream_id of stream_ids) {
|
|
const subscribers = get_user_set(stream_id);
|
|
for (const user_id of user_ids) {
|
|
subscribers.add(user_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function bulk_remove_subscribers({
|
|
stream_ids,
|
|
user_ids,
|
|
}: {
|
|
stream_ids: number[];
|
|
user_ids: number[];
|
|
}): void {
|
|
// We rely on our callers to validate stream_ids and user_ids.
|
|
for (const stream_id of stream_ids) {
|
|
const subscribers = get_user_set(stream_id);
|
|
for (const user_id of user_ids) {
|
|
subscribers.delete(user_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function is_user_subscribed(stream_id: number, user_id: number): boolean {
|
|
// Most callers should call stream_data.is_user_subscribed,
|
|
// which does additional checks.
|
|
|
|
const subscribers = get_user_set(stream_id);
|
|
return subscribers.has(user_id);
|
|
}
|
|
|
|
export function get_unique_subscriber_count_for_streams(stream_ids: number[]): number {
|
|
const valid_subscribers = new LazySet([]);
|
|
|
|
for (const stream_id of stream_ids) {
|
|
const subscribers = get_user_set(stream_id);
|
|
|
|
for (const user_id of subscribers.keys()) {
|
|
if (!people.is_valid_bot_user(user_id)) {
|
|
valid_subscribers.add(user_id);
|
|
}
|
|
}
|
|
}
|
|
return valid_subscribers.size;
|
|
}
|