115 lines
3.6 KiB
Python
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),",
|
|
)
|