"""E1 (B21): RBAC-ядро — подразделения МЧС, роли/права, сессии, auth-журнал. Иерархия подразделений: РЦУ РЧС (rcu) → ОУМЧС (oblast) → Г(Р)ОЧС (gor_rayon). Роли — как в РВС-админке (is_system), права атомарные, user_roles M2M. Сессии server-side: JWT несёт session_id, каждый запрос проверяет сессию в БД (отзыв по блокировке пользователя/окончании срока). Модели добавлены в backend/models.py; здесь — только константы (seed-данные) и хелперы прав/скоупа. """ from __future__ import annotations from sqlalchemy import text # ---- Иерархия подразделений ---- UNIT_KINDS = ('rcu', 'oblast', 'gor_rayon') # ---- Роли (is_system) ---- SYSTEM_ROLES = ( 'admin', # РЦУ РЧС: все права, все операции 'coordinator', # ОУМЧС: поиски своей области, управление подчинёнными Г(Р)ОЧС 'operator', # Г(Р)ОЧС: свои поиски (create/update) 'observer', # только просмотр ) # ---- Атомарные права ---- PERMISSIONS = ( 'view', 'create', 'update', 'delete', 'export', 'manage_users', 'manage_roles', 'view_audit', 'manage_security', ) ROLE_PERMISSIONS: dict[str, tuple[str, ...]] = { 'admin': PERMISSIONS, 'coordinator': ('view', 'create', 'update', 'export', 'manage_users', 'view_audit'), 'operator': ('view', 'create', 'update'), 'observer': ('view',), } # Роли-совместимость со старым единым role-полем: admin/coordinator/operator/observer # покрывают прежние operator/field/admin (field ≈ operator: полевой доступ). # ---- Политика безопасности (security_settings) ---- SECURITY_DEFAULTS = { 'password_min_length': '8', 'password_require_complexity': 'true', 'password_expiry_days': '90', 'password_history_count': '5', 'max_failed_logins': '5', 'lockout_duration_minutes': '15', 'session_timeout_minutes': '1440', 'session_idle_timeout_minutes': '60', 'max_concurrent_sessions': '3', 'audit_retention_days': '90', } def descendant_unit_ids(conn, unit_id: str) -> list[str]: """Все id подразделения + его потомков (для гео-скоупа). Рекурсивный CTE.""" rows = conn.execute( text(""" WITH RECURSIVE tree AS ( SELECT id FROM mchs_units WHERE id = :uid UNION ALL SELECT u.id FROM mchs_units u JOIN tree t ON u.parent_id = t.id ) SELECT id FROM tree """), {'unit_id': unit_id}, ).fetchall() return [str(r[0]) for r in rows]