mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 21:12:49 +08:00
fix(guest): add playCollection permission so guests can Play All playlist/album (#103)
- New guest flag playCollection (default OFF), gates play-playlist/play-album - Keeps playNow's non-destructive semantics intact (Play All clears the queue) - Admin-toggleable in Settings → 游客模式; default-off, backward-compatible - Frontend: gate the 播放全部 button on the flag + surface 403 as a toast instead of failing silently (the silent-failure half of the issue)
This commit is contained in:
1 parent
e2fa288f48
commit
70c0273ae7
11 files changed
+61
-22
No files matched your search
@@ -301,6 +301,7 @@ const guest = (perms: Partial<Record<string, boolean>> = {}) => ({
|
||||
transport: false,
|
||||
removeClear: false,
|
||||
playMode: false,
|
||||
playCollection: false,
|
||||
...perms,
|
||||
},
|
||||
});
|
||||
@@ -373,7 +374,19 @@ describe("guest enforcement on player routes", () => {
|
||||
expect((await request(mountGuest({ transport: true })).post(`/api/player/${ALLOWED_BOT}/add-song`).send({ song: SONG })).status).toBe(403);
|
||||
});
|
||||
|
||||
it("guests are always denied /play, /prev, /stop, /play-song, /play-at, /play-playlist, /play-album, /playlist, /profile even with ALL flags on", async () => {
|
||||
it("playCollection flag gates /play-playlist, /play-album (issue #103)", async () => {
|
||||
const allow = mountGuest({ playCollection: true });
|
||||
const deny = mountGuest({ playCollection: false });
|
||||
expect((await request(allow).post(`/api/player/${ALLOWED_BOT}/play-playlist`).send({ playlistId: "1" })).status).not.toBe(403);
|
||||
expect((await request(allow).post(`/api/player/${ALLOWED_BOT}/play-album`).send({ albumId: "1" })).status).not.toBe(403);
|
||||
expect((await request(deny).post(`/api/player/${ALLOWED_BOT}/play-playlist`).send({ playlistId: "1" })).status).toBe(403);
|
||||
expect((await request(deny).post(`/api/player/${ALLOWED_BOT}/play-album`).send({ albumId: "1" })).status).toBe(403);
|
||||
// playCollection does NOT leak into the destructive single-song / queue ops.
|
||||
expect((await request(allow).post(`/api/player/${ALLOWED_BOT}/play`).send({ query: "x" })).status).toBe(403);
|
||||
expect((await request(allow).post(`/api/player/${ALLOWED_BOT}/play-song`).send({ song: SONG })).status).toBe(403);
|
||||
});
|
||||
|
||||
it("guests are always denied /play, /prev, /stop, /play-song, /play-at, /playlist, /profile even with ALL flags on", async () => {
|
||||
const all = mountGuest({
|
||||
addToQueue: true,
|
||||
playNext: true,
|
||||
@@ -382,14 +395,13 @@ describe("guest enforcement on player routes", () => {
|
||||
transport: true,
|
||||
removeClear: true,
|
||||
playMode: true,
|
||||
playCollection: true,
|
||||
});
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/play`).send({ query: "x" })).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/prev`)).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/stop`)).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/play-song`).send({ song: SONG })).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/play-at`).send({ index: 0 })).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/play-playlist`).send({ playlistId: "1" })).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/play-album`).send({ albumId: "1" })).status).toBe(403);
|
||||
expect((await request(all).post(`/api/player/${ALLOWED_BOT}/playlist`).send({ playlistId: "1" })).status).toBe(403);
|
||||
expect((await request(all).put(`/api/player/${ALLOWED_BOT}/profile`).send({})).status).toBe(403);
|
||||
});
|
||||
|
||||
@@ -265,7 +265,7 @@ export function createPlayerRouter(
|
||||
|
||||
// Play a playlist by ID — stores metadata only, resolves URL for first song
|
||||
// Respects current play mode (random = pick random first song)
|
||||
router.post("/:botId/play-playlist", authorize({ capability: "player.control" }), async (req, res) => {
|
||||
router.post("/:botId/play-playlist", authorize({ capability: "player.control", guestFlag: "playCollection" }), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { playlistId, platform } = req.body;
|
||||
@@ -352,7 +352,7 @@ export function createPlayerRouter(
|
||||
});
|
||||
|
||||
// Play an album by ID — mirrors play-playlist but calls getAlbumSongs
|
||||
router.post("/:botId/play-album", authorize({ capability: "player.control" }), async (req, res) => {
|
||||
router.post("/:botId/play-album", authorize({ capability: "player.control", guestFlag: "playCollection" }), async (req, res) => {
|
||||
try {
|
||||
const bot = (req as any).bot;
|
||||
const { albumId, platform } = req.body;
|
||||
|
||||
@@ -217,6 +217,7 @@ describe("session router — guest mode", () => {
|
||||
transport: false,
|
||||
removeClear: false,
|
||||
playMode: false,
|
||||
playCollection: false,
|
||||
},
|
||||
guestBots: "all",
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user