Files
gerbeur/api/lib/playlist-members.ts

63 lines
2.1 KiB
TypeScript

/**
* Decides which of a playlist's dumps a viewer may see. The playlist service
* filters its listings with it, the WebSocket service filters each client's
* `playlist_dumps_updated` message the same way, and the queries that list
* playlists count their dumps by the same rule.
*
* @module
*/
import type { Playlist } from "../../shared/playlist.ts";
/**
* The fields of a playlist's dump that {@link isMemberVisibleTo} needs. A
* `Dump` has them. For its broadcasts, the playlist service reads only these.
*/
export interface PlaylistMember {
id: string;
isPrivate: boolean;
/** The dump's poster, not the playlist's owner. */
userId: string;
}
/**
* Checks whether `viewerId` may see `member` in `playlist`. A public dump is
* visible to all. A private dump is visible only to the playlist's owner, and
* only if they posted it: moderators don't see it, and neither does the owner
* once someone else's dump in their playlist goes private. A null or undefined
* `viewerId` is a signed-out viewer.
*/
export function isMemberVisibleTo(
member: PlaylistMember,
playlist: Pick<Playlist, "userId">,
viewerId: string | null | undefined,
): boolean {
return !member.isPrivate ||
(member.userId === viewerId && viewerId === playlist.userId);
}
/**
* The `dump_count` column of a query on `playlists p`: how many of the
* playlist's dumps the viewer may see, by {@link isMemberVisibleTo}'s rule.
* Its `?` takes the viewer's id, or `""` for a signed-out one, and comes
* before the query's other parameters, the column being in its select list.
*/
export const VISIBLE_DUMP_COUNT = `(SELECT COUNT(*) FROM playlist_dumps pd
INNER JOIN dumps d ON d.id = pd.dump_id
WHERE pd.playlist_id = p.id
AND (d.is_private = 0 OR (d.user_id = p.user_id AND p.user_id = ?))
) as dump_count`;
/**
* Returns how many of `members` the viewer may see in `playlist`, the
* `dumpCount` the playlist has for them.
*/
export function countVisibleTo(
members: PlaylistMember[],
playlist: Pick<Playlist, "userId">,
viewerId: string | null | undefined,
): number {
return members.filter((m) => isMemberVisibleTo(m, playlist, viewerId))
.length;
}