v4: a dump or playlist going public notifies its followers — a private dump notified no one when posted, and nothing told its followers when it was made public: the poster's followers never learnt of it, nor did the followers of the public playlists holding it. Likewise, the dumps added to a playlist while it was private were never notified to its followers. updateDump and replaceFileDump now call notifyIfWentPublic, which notifies the poster's followers (user_dump_posted) and, through the new notifyPlaylistFollowersNowPublic, the followers of each public playlist holding the dump (playlist_dump_added). updatePlaylist calls the same function when a playlist goes public, for each public dump in it, from the bottom up. A follower hears of a dump once both it and the playlist are public; the source keys stop a dump made private and public again from notifying twice. 256 backend tests pass, and deno check, deno fmt and doc:lint are clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-10-09 10:23:08 +00:00
parent 256857f72e
commit 7713c5a1b5
5 changed files with 142 additions and 6 deletions

View File

@@ -320,6 +320,33 @@ test("adding to a followed public playlist notifies followers, private dumps exc
});
});
test("a playlist going public notifies its followers of the public dumps added meanwhile", async () => {
const owner = await createUser();
const follower = await createUser();
const { id } = insertPlaylist({ userId: owner.id, title: "Mix" });
await put(`/api/me/follow/playlists/${id}`, { auth: follower.auth });
const before = insertDump({ userId: owner.id, title: "Before" });
await post(`/api/playlists/${id}/dumps/${before.id}`, { auth: owner.auth });
db.prepare(`DELETE FROM notifications WHERE user_id = ?;`).run(owner.id);
const setPublic = (isPublic: boolean) =>
put(`/api/playlists/${id}`, { auth: owner.auth, json: { isPublic } });
await setPublic(false);
const during = insertDump({ userId: owner.id, title: "During" });
const priv = insertDump({ userId: owner.id, isPrivate: true });
for (const d of [during, priv]) {
await post(`/api/playlists/${id}/dumps/${d.id}`, { auth: owner.auth });
}
assertEquals(count(`SELECT COUNT(*) as n FROM notifications;`), 1);
await setPublic(true);
const titles = (db.prepare(
`SELECT data FROM notifications WHERE user_id = ? ORDER BY created_at;`,
).all(follower.id) as { data: string }[]).map((n) =>
JSON.parse(n.data).dumpTitle
);
assertEquals(titles, ["Before", "During"]);
});
test("playlist covers: upload and serve", async () => {
const owner = await createUser();
const other = await createUser();