v4: a playlist's dump count is of the dumps the viewer may see — it counted every dump in the playlist, so a card said "3 dumps" over a page listing two, and told everyone how many private dumps a playlist held. The lists (/playlists, a profile's playlists and followed ones, the search, a dump's playlists, the add-to-playlist panel) now count by isMemberVisibleTo's rule, in SQL as VISIBLE_DUMP_COUNT (lib/playlist-members.ts): the public dumps, and for the owner their own private ones. GET /api/playlists and /api/users/:key/follow/playlists read the optional sign-in for it. The community page and the digests count the public dumps, their figures being the same for every reader. Live, playlist_created and playlist_updated carry each socket's own count: broadcastChange builds the owner's message and the others' apart. playlist_dumps_updated loses its dumpCount, a client counting the dumps it is sent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,72 @@ test("a public playlist hides its private dumps from everyone but their owner",
|
||||
);
|
||||
});
|
||||
|
||||
test("a playlist's dumpCount is of the dumps the viewer may see", async () => {
|
||||
const owner = await createUser();
|
||||
const author = await createUser();
|
||||
const pl = insertPlaylist({ userId: owner.id, title: "Counted banana" });
|
||||
const pub = insertDump({ userId: owner.id });
|
||||
const mine = insertDump({ userId: owner.id, isPrivate: true });
|
||||
// Someone else's, gone private after it was added: its owner no longer
|
||||
// sees it there, and neither does its poster.
|
||||
const theirs = insertDump({ userId: author.id, isPrivate: true });
|
||||
for (const [i, d] of [pub, mine, theirs].entries()) {
|
||||
db.prepare(
|
||||
`INSERT INTO playlist_dumps (playlist_id, dump_id, position, added_at)
|
||||
VALUES (?, ?, ?, ?);`,
|
||||
).run(pl.id, d.id, i, new Date().toISOString());
|
||||
}
|
||||
await put(`/api/me/follow/playlists/${pl.id}`, { auth: author.auth });
|
||||
|
||||
const lists = [
|
||||
"/api/playlists",
|
||||
`/api/users/@${owner.username}/playlists`,
|
||||
`/api/users/@${author.username}/follow/playlists`,
|
||||
];
|
||||
for (
|
||||
const [auth, expected] of [
|
||||
[owner.auth, 2],
|
||||
[author.auth, 1],
|
||||
[undefined, 1],
|
||||
] as const
|
||||
) {
|
||||
for (const url of lists) {
|
||||
const { items } = (await get<PaginatedData<Playlist>>(url, { auth }))
|
||||
.data;
|
||||
assertEquals(items.map((p) => p.dumpCount), [expected], url);
|
||||
}
|
||||
assertEquals(
|
||||
(await get<{ playlists: Playlist[] }>("/api/search?q=banana", { auth }))
|
||||
.data.playlists.map((p) => p.dumpCount),
|
||||
[expected],
|
||||
);
|
||||
assertEquals(
|
||||
(await get<Playlist[]>(`/api/dumps/${pub.id}/playlists`, { auth })).data
|
||||
.map((p) => p.dumpCount),
|
||||
[expected],
|
||||
);
|
||||
const page = await get<PlaylistWithDumps>(`/api/playlists/${pl.id}`, {
|
||||
auth,
|
||||
});
|
||||
assertEquals(page.data.dumpCount, expected);
|
||||
assertEquals(ids(page).length, expected);
|
||||
}
|
||||
assertEquals(
|
||||
(await get<PlaylistMembership[]>(`/api/me/playlists?contains=${pub.id}`, {
|
||||
auth: owner.auth,
|
||||
})).data.map((m) => [m.hasDump, m.playlist.dumpCount]),
|
||||
[[true, 2]],
|
||||
);
|
||||
// An edit answers with the editor's count.
|
||||
assertEquals(
|
||||
(await put<Playlist>(`/api/playlists/${pl.id}`, {
|
||||
auth: owner.auth,
|
||||
json: { title: "Counted" },
|
||||
})).data.dumpCount,
|
||||
2,
|
||||
);
|
||||
});
|
||||
|
||||
test("reorder: must name exactly the current members", async () => {
|
||||
const owner = await createUser();
|
||||
const { id } = insertPlaylist({ userId: owner.id });
|
||||
|
||||
Reference in New Issue
Block a user