154 lines
5.2 KiB
TypeScript
154 lines
5.2 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import {
|
|
createUser,
|
|
deleteUser,
|
|
getUserByUsername,
|
|
getUserTelegramChatId,
|
|
getUsersWithTelegramChatId,
|
|
setUserTelegramChatId,
|
|
setUserClientAccessScope,
|
|
setUserClientAccessRule,
|
|
canUserAccessClient,
|
|
} from "./users";
|
|
|
|
const createdUserIds: number[] = [];
|
|
|
|
async function createTempUser(role: "viewer" | "operator" | "admin") {
|
|
const username = `tg_${role.slice(0, 3)}_${Date.now().toString(36)}${Math.floor(Math.random() * 1000).toString(36)}`;
|
|
const result = await createUser(username, "Aa1!VeryLongTestPassword_2026", role, "test");
|
|
expect(result.success).toBe(true);
|
|
const user = getUserByUsername(username);
|
|
expect(user).not.toBeNull();
|
|
createdUserIds.push(user!.id);
|
|
return user!;
|
|
}
|
|
|
|
function cleanupCreatedUsers() {
|
|
while (createdUserIds.length > 0) {
|
|
const id = createdUserIds.pop();
|
|
if (typeof id === "number") {
|
|
deleteUser(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
describe("per-user Telegram settings", () => {
|
|
test("new user has no telegram chat ID", async () => {
|
|
try {
|
|
const user = await createTempUser("operator");
|
|
expect(getUserTelegramChatId(user.id)).toBeNull();
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
|
|
test("setUserTelegramChatId stores and retrieves chat ID", async () => {
|
|
try {
|
|
const user = await createTempUser("operator");
|
|
|
|
const result = setUserTelegramChatId(user.id, "123456789");
|
|
expect(result.success).toBe(true);
|
|
|
|
expect(getUserTelegramChatId(user.id)).toBe("123456789");
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
|
|
test("setUserTelegramChatId with null clears the chat ID", async () => {
|
|
try {
|
|
const user = await createTempUser("viewer");
|
|
|
|
setUserTelegramChatId(user.id, "987654321");
|
|
expect(getUserTelegramChatId(user.id)).toBe("987654321");
|
|
|
|
setUserTelegramChatId(user.id, null);
|
|
expect(getUserTelegramChatId(user.id)).toBeNull();
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
|
|
test("getUsersWithTelegramChatId returns only users with configured chat IDs", async () => {
|
|
try {
|
|
const user1 = await createTempUser("operator");
|
|
const user2 = await createTempUser("viewer");
|
|
const user3 = await createTempUser("operator");
|
|
|
|
setUserTelegramChatId(user1.id, "chat_111");
|
|
// user2 has no chat ID
|
|
setUserTelegramChatId(user3.id, "chat_333");
|
|
|
|
const withChatId = getUsersWithTelegramChatId();
|
|
const ourUsers = withChatId.filter((u) => [user1.id, user2.id, user3.id].includes(u.id));
|
|
|
|
expect(ourUsers.length).toBe(2);
|
|
expect(ourUsers.some((u) => u.id === user1.id && u.telegram_chat_id === "chat_111")).toBe(true);
|
|
expect(ourUsers.some((u) => u.id === user3.id && u.telegram_chat_id === "chat_333")).toBe(true);
|
|
expect(ourUsers.some((u) => u.id === user2.id)).toBe(false);
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
|
|
test("getUsersWithTelegramChatId returns role and client_scope", async () => {
|
|
try {
|
|
const operator = await createTempUser("operator");
|
|
setUserTelegramChatId(operator.id, "chat_op");
|
|
setUserClientAccessScope(operator.id, "allowlist");
|
|
|
|
const users = getUsersWithTelegramChatId();
|
|
const found = users.find((u) => u.id === operator.id);
|
|
expect(found).not.toBeNull();
|
|
expect(found!.role).toBe("operator");
|
|
expect(found!.client_scope).toBe("allowlist");
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
|
|
test("per-user notification filtering respects client access", async () => {
|
|
try {
|
|
const operator = await createTempUser("operator");
|
|
setUserTelegramChatId(operator.id, "chat_filter");
|
|
setUserClientAccessScope(operator.id, "allowlist");
|
|
setUserClientAccessRule(operator.id, "allowed-client", "allow");
|
|
|
|
// Operator should see allowed-client but not other-client
|
|
expect(canUserAccessClient(operator.id, operator.role, "allowed-client")).toBe(true);
|
|
expect(canUserAccessClient(operator.id, operator.role, "other-client")).toBe(false);
|
|
|
|
// This simulates what the notification delivery does:
|
|
// get users with chat IDs, then filter by canUserAccessClient
|
|
const recipients = getUsersWithTelegramChatId();
|
|
const opRecipient = recipients.find((r) => r.id === operator.id);
|
|
expect(opRecipient).not.toBeNull();
|
|
|
|
const canAccessAllowed = canUserAccessClient(operator.id, operator.role, "allowed-client");
|
|
const canAccessOther = canUserAccessClient(operator.id, operator.role, "other-client");
|
|
|
|
expect(canAccessAllowed).toBe(true);
|
|
expect(canAccessOther).toBe(false);
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
|
|
test("admin with telegram chat ID can access all clients", async () => {
|
|
try {
|
|
const admin = await createTempUser("admin");
|
|
setUserTelegramChatId(admin.id, "chat_admin");
|
|
|
|
expect(canUserAccessClient(admin.id, admin.role, "any-client-1")).toBe(true);
|
|
expect(canUserAccessClient(admin.id, admin.role, "any-client-2")).toBe(true);
|
|
|
|
const recipients = getUsersWithTelegramChatId();
|
|
const adminRecipient = recipients.find((r) => r.id === admin.id);
|
|
expect(adminRecipient).not.toBeNull();
|
|
expect(adminRecipient!.telegram_chat_id).toBe("chat_admin");
|
|
} finally {
|
|
cleanupCreatedUsers();
|
|
}
|
|
});
|
|
});
|