feat(gps): фильтры heartbeat-эхо/valid=false/spike; доступ к GPS и Финансам — матрица на /users (пользователи+роли)
This commit is contained in:
41
server/utils/module-access.ts
Normal file
41
server/utils/module-access.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { db } from "../db";
|
||||
import { roles, roleMembers } from "@shared/schema";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
|
||||
/**
|
||||
* Доступ к модулям (GPS / Финансы) по флагам users.<flag> и roles.<flag>.
|
||||
*
|
||||
* Effective-доступ = users.<flag> OR любая организационная роль пользователя
|
||||
* с флагом OR appRole = 'admin'. Оба флага NOT NULL DEFAULT true — при выкатке
|
||||
* никто не блокируется; админ снимает галки в матрице на странице /users.
|
||||
*
|
||||
* Для Финансов флаг работает как ДОПОЛНИТЕЛЬНЫЙ ограничитель поверх
|
||||
* существующего app-role права finance.manage (см. requirePermission) —
|
||||
* только отбирает доступ, не добавляет.
|
||||
*/
|
||||
|
||||
export type ModuleAccessKey = "gps" | "finance";
|
||||
|
||||
export interface ModuleAccessUser {
|
||||
id: number;
|
||||
organizationId: number;
|
||||
appRole?: string;
|
||||
gpsAccess?: boolean;
|
||||
financeAccess?: boolean;
|
||||
}
|
||||
|
||||
export async function hasModuleAccess(user: ModuleAccessUser, module: ModuleAccessKey): Promise<boolean> {
|
||||
if (user.appRole === "admin") return true;
|
||||
|
||||
const userFlag = module === "gps" ? user.gpsAccess : user.financeAccess;
|
||||
if (userFlag) return true;
|
||||
|
||||
// Флаг любой организационной роли пользователя
|
||||
const rows = await db
|
||||
.select({ gpsAccess: roles.gpsAccess, financeAccess: roles.financeAccess })
|
||||
.from(roleMembers)
|
||||
.innerJoin(roles, eq(roleMembers.roleId, roles.id))
|
||||
.where(and(eq(roleMembers.userId, user.id), eq(roles.organizationId, user.organizationId)));
|
||||
|
||||
return rows.some((r) => (module === "gps" ? r.gpsAccess : r.financeAccess));
|
||||
}
|
||||
Reference in New Issue
Block a user