Портал технической службы: наряды и чек-листы, задачи, отказы и неисправности, анализ надёжности, карты, склады, приложение для Android

This commit is contained in:
darkorion
2026-10-13 09:09:53 +03:00
commit c298f5a830
247 changed files with 23200 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
"""Состояние демо-режима (общее для db/security/роутеров). Хранится в файле, чтобы пережить перезапуск.
Демо-режим — персональный: отдельная тестовая БД существует рядом с боевой, а в неё «входят» только те пользователи,
кто его включил (или кого включил администратор). Остальные продолжают работать с боевыми данными.
Какая БД нужна конкретному запросу, определяется по токену (claim mode) — см. REQUEST_DEMO и app/db.py."""
import json
import os
from contextvars import ContextVar
from pathlib import Path
from . import config
_FLAG = Path(config.DATA_DIR) / "demo_mode.json"
# запрос пришёл с демо-токеном (выставляется middleware в main.py, читается get_db, push, user_out и т. п.)
REQUEST_DEMO: ContextVar[bool] = ContextVar("request_demo", default=False)
class State:
active = False # демо-БД существует
db_file = "" # имя файла демо-БД в DATA_DIR
photo_dir = ""
owner_id = None # администратор, создавший демо-набор (его копия в демо-БД имеет тот же id)
since = ""
users: set = set() # id пользователей БОЕВОЙ БД, которые сейчас работают в демо
epoch = 0 # увеличивается при пересоздании/удалении демо-БД: старые демо-токены становятся недействительны
def load():
State.active, State.users = False, set()
if _FLAG.is_file():
try:
d = json.loads(_FLAG.read_text(encoding="utf-8"))
State.epoch = int(d.get("epoch", 0))
if d.get("db_file") and (Path(config.DATA_DIR) / d["db_file"]).is_file():
State.active, State.db_file, State.photo_dir = True, d["db_file"], d["photo_dir"]
State.owner_id, State.since = d.get("owner_id", d.get("admin_id")), d.get("since", "")
State.users = set(d.get("users", [State.owner_id] if State.owner_id else []))
except Exception:
pass
if not State.active:
State.db_file, State.photo_dir, State.owner_id, State.users = "", "", None, set()
save()
def save():
os.makedirs(config.DATA_DIR, exist_ok=True)
tmp = _FLAG.with_suffix(".tmp")
tmp.write_text(json.dumps({"db_file": State.db_file, "photo_dir": State.photo_dir, "owner_id": State.owner_id,
"since": State.since, "users": sorted(State.users), "epoch": State.epoch}), encoding="utf-8")
os.replace(tmp, _FLAG)
def clear():
State.active, State.db_file, State.photo_dir, State.owner_id, State.since = False, "", "", None, ""
State.users = set()
State.epoch += 1
save()
def user_in_demo(real_id: int | None) -> bool:
return State.active and real_id is not None and real_id in State.users
def is_demo_request() -> bool:
return State.active and REQUEST_DEMO.get()