mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat(users): guest role + reserved guest principal, excluded from count/list
This commit is contained in:
1 parent
fb7f187ede
commit
60c8a5c993
2 files changed
+35
-4
No files matched your search
+26
-1
@@ -1,6 +1,6 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||||
import { createDatabase, type BotDatabase } from "./database.js";
|
import { createDatabase, type BotDatabase } from "./database.js";
|
||||||
import { createUserStore, UsernameTakenError, type UserStore } from "./users.js";
|
import { createUserStore, UsernameTakenError, GUEST_USER_ID, GUEST_USERNAME, type UserStore } from "./users.js";
|
||||||
|
|
||||||
describe("UserStore", () => {
|
describe("UserStore", () => {
|
||||||
let botDb: BotDatabase;
|
let botDb: BotDatabase;
|
||||||
@@ -184,3 +184,28 @@ describe("UserStore", () => {
|
|||||||
expect(users.countAdmins()).toBe(1);
|
expect(users.countAdmins()).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("guest row exclusion", () => {
|
||||||
|
let botDb: BotDatabase;
|
||||||
|
let users: UserStore;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
botDb = createDatabase(":memory:");
|
||||||
|
users = createUserStore(botDb.db);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
botDb.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("countUsers and listUsers ignore the reserved guest row", async () => {
|
||||||
|
await users.createUser("alice", "password123", "member");
|
||||||
|
// Insert the reserved guest row directly (mirrors the migration).
|
||||||
|
botDb.db.prepare(
|
||||||
|
"INSERT INTO users (id, username, passwordHash, createdAt, updatedAt, role) VALUES (?, ?, ?, ?, ?, 'guest')"
|
||||||
|
).run(GUEST_USER_ID, GUEST_USERNAME, "!", Date.now(), Date.now());
|
||||||
|
|
||||||
|
expect(users.countUsers()).toBe(1); // alice only
|
||||||
|
expect(users.listUsers().some((u) => u.id === GUEST_USER_ID)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
+9
-3
@@ -4,7 +4,13 @@ import bcrypt from "bcryptjs";
|
|||||||
|
|
||||||
const BCRYPT_ROUNDS = 12;
|
const BCRYPT_ROUNDS = 12;
|
||||||
|
|
||||||
export type UserRole = "admin" | "member";
|
export type UserRole = "admin" | "member" | "guest";
|
||||||
|
|
||||||
|
/** Reserved synthetic principal for login-less guest sessions. The username is
|
||||||
|
* non-ASCII so it can never collide with an API-created account (which is
|
||||||
|
* validated against ^[A-Za-z0-9_\-.]{3,32}$). */
|
||||||
|
export const GUEST_USER_ID = "__guest__";
|
||||||
|
export const GUEST_USERNAME = "游客";
|
||||||
|
|
||||||
export interface UserRow {
|
export interface UserRow {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -39,7 +45,7 @@ export class UsernameTakenError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createUserStore(db: Database.Database): UserStore {
|
export function createUserStore(db: Database.Database): UserStore {
|
||||||
const countStmt = db.prepare("SELECT COUNT(*) AS n FROM users");
|
const countStmt = db.prepare("SELECT COUNT(*) AS n FROM users WHERE role != 'guest'");
|
||||||
const countAdminsStmt = db.prepare("SELECT COUNT(*) AS n FROM users WHERE role = 'admin'");
|
const countAdminsStmt = db.prepare("SELECT COUNT(*) AS n FROM users WHERE role = 'admin'");
|
||||||
const insertStmt = db.prepare(
|
const insertStmt = db.prepare(
|
||||||
"INSERT INTO users (id, username, passwordHash, createdAt, updatedAt, role) VALUES (?, ?, ?, ?, ?, ?)"
|
"INSERT INTO users (id, username, passwordHash, createdAt, updatedAt, role) VALUES (?, ?, ?, ?, ?, ?)"
|
||||||
@@ -57,7 +63,7 @@ export function createUserStore(db: Database.Database): UserStore {
|
|||||||
"UPDATE users SET role = ?, updatedAt = ? WHERE id = ?"
|
"UPDATE users SET role = ?, updatedAt = ? WHERE id = ?"
|
||||||
);
|
);
|
||||||
const listUsersStmt = db.prepare(
|
const listUsersStmt = db.prepare(
|
||||||
"SELECT id, username, createdAt, role FROM users ORDER BY createdAt ASC"
|
"SELECT id, username, createdAt, role FROM users WHERE role != 'guest' ORDER BY createdAt ASC"
|
||||||
);
|
);
|
||||||
const deleteUserStmt = db.prepare("DELETE FROM users WHERE id = ?");
|
const deleteUserStmt = db.prepare("DELETE FROM users WHERE id = ?");
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user