atlas-iac/dockerfiles/hermes-webui-telegram-project-patch.py
2026-08-16 15:59:09 -03:00

115 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Group trusted Telegram API sessions under a system WebUI project."""
from __future__ import annotations
from pathlib import Path
ROOT = Path("/opt/hermes-webui")
def replace_exact(path: Path, before: str, after: str, count: int = 1) -> None:
"""Replace a pinned upstream fragment and fail closed on source drift."""
source = path.read_text(encoding="utf-8")
if source.count(before) != count:
raise SystemExit(f"Telegram project patch context changed in {path}")
path.write_text(source.replace(before, after, count), encoding="utf-8")
models = ROOT / "api/models.py"
replace_exact(
models,
"""def _profile_has_user_projects() -> bool:
""",
"""TELEGRAM_PROJECT_NAME = 'Telegram'
_TELEGRAM_PROJECT_LOCK = threading.Lock()
def ensure_telegram_project() -> str:
\"\"\"Return the per-profile system project for trusted Telegram sessions.\"\"\"
from api.profiles import get_active_profile_name, _is_root_profile
active = get_active_profile_name() or 'default'
with _TELEGRAM_PROJECT_LOCK:
projects = load_projects()
for project in projects:
if project.get('name') != TELEGRAM_PROJECT_NAME:
continue
row_profile = project.get('profile')
if row_profile == active:
return project['project_id']
if _is_root_profile(row_profile or 'default') and _is_root_profile(active):
return project['project_id']
project_id = uuid.uuid4().hex[:12]
projects.append({
'project_id': project_id,
'name': TELEGRAM_PROJECT_NAME,
'color': '#229ed9',
'profile': active,
'created_at': time.time(),
})
save_projects(projects)
return project_id
def _profile_has_user_projects() -> bool:
""",
)
replace_exact(
models,
"reserved = {CRON_PROJECT_NAME, WEBHOOK_PROJECT_NAME}",
"reserved = {CRON_PROJECT_NAME, WEBHOOK_PROJECT_NAME, TELEGRAM_PROJECT_NAME}",
)
replace_exact(
models,
""" _webhook_pid_cache: list[str | None] = [None]
def _webhook_pid():
if _webhook_pid_cache[0] is None:
_webhook_pid_cache[0] = ensure_webhook_project()
return _webhook_pid_cache[0]
def _state_row_project_id(sid: str, source: str | None) -> str | None:
if is_cron_session(sid, source):
return _cron_pid()
if is_webhook_session(sid, source):
return _webhook_pid()
return None
""",
""" _webhook_pid_cache: list[str | None] = [None]
def _webhook_pid():
if _webhook_pid_cache[0] is None:
_webhook_pid_cache[0] = ensure_webhook_project()
return _webhook_pid_cache[0]
_telegram_pid_cache: list[str | None] = [None]
def _telegram_pid():
if _telegram_pid_cache[0] is None:
_telegram_pid_cache[0] = ensure_telegram_project()
return _telegram_pid_cache[0]
def _state_row_project_id(row: dict) -> str | None:
sid = str(row.get('id') or '')
source = str(row.get('source') or '')
if is_cron_session(sid, source):
return _cron_pid()
if is_webhook_session(sid, source):
return _webhook_pid()
session_key = str(row.get('session_key') or '')
if source == 'api_server' and (
session_key == 'telegram' or session_key.startswith('telegram-topic-')
):
return _telegram_pid()
return None
""",
)
replace_exact(
models,
"'project_id': _state_row_project_id(sid, _source),",
"'project_id': _state_row_project_id(row),",
)