feat(gps): фильтры heartbeat-эхо/valid=false/spike; доступ к GPS и Финансам — матрица на /users (пользователи+роли)

This commit is contained in:
2026-08-26 17:13:49 +03:00
parent 2fb7ad6606
commit ac4f89d42e
16 changed files with 431 additions and 227 deletions

View File

@@ -1,33 +1,13 @@
import { gpsStorage } from "./storage";
import { hasModuleAccess, type ModuleAccessUser } from "../utils/module-access";
/**
* Контроль доступа к GPS-вкладке.
*
* Правило:
* - admin приложения (users.app_role = 'admin') — доступ всегда;
* - если allowed_user_ids и allowed_role_ids оба пустые/NULL — доступ у всех;
* - иначе — если user.id ∈ allowedUserIds ИЛИ пользователь состоит
* в организационной роли из allowedRoleIds (таблицы roles/role_members).
* Правило: users.gps_access OR любая организационная роль пользователя
* с gps_access OR appRole = 'admin' (см. utils/module-access).
* Раньше использовались gps_settings.allowed_user_ids/allowed_role_ids —
* колонки остались в БД, но больше не читаются.
*/
export async function hasGpsAccess(
user: { id: number; organizationId: number; appRole?: string },
settings?: Awaited<ReturnType<typeof gpsStorage.getSettings>>
): Promise<boolean> {
if (user.appRole === "admin") return true;
const s = settings ?? (await gpsStorage.getSettings(user.organizationId));
const userIds = s.allowedUserIds ?? [];
const roleIds = s.allowedRoleIds ?? [];
// Оба списка пустые — модуль открыт всем
if (userIds.length === 0 && roleIds.length === 0) return true;
if (userIds.includes(user.id)) return true;
if (roleIds.length > 0) {
const userRoleIds = await gpsStorage.getUserRoleIds(user.id, user.organizationId);
if (userRoleIds.some((id) => roleIds.includes(id))) return true;
}
return false;
export async function hasGpsAccess(user: ModuleAccessUser): Promise<boolean> {
return hasModuleAccess(user, "gps");
}