/** * 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, 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, viewerId: string | null | undefined, ): number { return members.filter((m) => isMemberVisibleTo(m, playlist, viewerId)) .length; }