mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 13:02:49 +08:00
feat(perm): permission store + capability tokens + tables
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
547aaa304e
commit
aaf6ba2ab4
3 files changed
+157
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import type Database from "better-sqlite3";
|
||||
|
||||
export const CAPABILITIES = [
|
||||
"player.control",
|
||||
"player.queue",
|
||||
"bot.manage",
|
||||
"platform.auth",
|
||||
"quality",
|
||||
] as const;
|
||||
export type Capability = (typeof CAPABILITIES)[number];
|
||||
|
||||
/** Marker token stored in user_permissions meaning "all bots, incl. future". */
|
||||
export const BOTS_ALL = "bots.all";
|
||||
|
||||
/** Capabilities granted to a newly-created member by default. */
|
||||
export const BASIC_TIER_CAPABILITIES: Capability[] = ["player.control", "player.queue"];
|
||||
|
||||
export function isCapability(x: string): x is Capability {
|
||||
return (CAPABILITIES as readonly string[]).includes(x);
|
||||
}
|
||||
|
||||
export type BotAccess = "all" | string[];
|
||||
|
||||
export interface PermissionStore {
|
||||
getCapabilities(userId: string): Capability[];
|
||||
getBotAccess(userId: string): BotAccess;
|
||||
setPermissions(userId: string, input: { capabilities: string[]; bots: BotAccess }): void;
|
||||
pruneBot(botId: string): void;
|
||||
}
|
||||
|
||||
export function createPermissionStore(db: Database.Database): PermissionStore {
|
||||
const selCaps = db.prepare("SELECT permission FROM user_permissions WHERE userId = ?");
|
||||
const delCaps = db.prepare("DELETE FROM user_permissions WHERE userId = ?");
|
||||
const insCap = db.prepare("INSERT OR IGNORE INTO user_permissions (userId, permission) VALUES (?, ?)");
|
||||
const selBots = db.prepare("SELECT botId FROM user_bot_access WHERE userId = ?");
|
||||
const delBots = db.prepare("DELETE FROM user_bot_access WHERE userId = ?");
|
||||
const insBot = db.prepare("INSERT OR IGNORE INTO user_bot_access (userId, botId) VALUES (?, ?)");
|
||||
const pruneBotStmt = db.prepare("DELETE FROM user_bot_access WHERE botId = ?");
|
||||
|
||||
return {
|
||||
getCapabilities(userId) {
|
||||
return (selCaps.all(userId) as { permission: string }[])
|
||||
.map((r) => r.permission)
|
||||
.filter((p): p is Capability => isCapability(p));
|
||||
},
|
||||
getBotAccess(userId) {
|
||||
const all = (selCaps.all(userId) as { permission: string }[]).some((r) => r.permission === BOTS_ALL);
|
||||
if (all) return "all";
|
||||
return (selBots.all(userId) as { botId: string }[]).map((r) => r.botId);
|
||||
},
|
||||
setPermissions(userId, input) {
|
||||
const caps = input.capabilities.filter(isCapability);
|
||||
const tx = db.transaction(() => {
|
||||
delCaps.run(userId);
|
||||
delBots.run(userId);
|
||||
for (const c of caps) insCap.run(userId, c);
|
||||
if (input.bots === "all") {
|
||||
insCap.run(userId, BOTS_ALL);
|
||||
} else {
|
||||
for (const b of input.bots) insBot.run(userId, b);
|
||||
}
|
||||
});
|
||||
tx();
|
||||
},
|
||||
pruneBot(botId) {
|
||||
pruneBotStmt.run(botId);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user