feat: документация из Nextcloud, график у сотрудника, автоочистка фото, мониторинг, итог мастера, фильтр по местам; доп. сервисы в docker-compose

- docker-compose.yml: профили docs (Nextcloud), office (ONLYOFFICE Document Server), ai (Ollama + скачивание модели)
- автонастройка: адреса Nextcloud, ONLYOFFICE, портала и модели подставляются из .env или по именам сервисов
  во внутренней сети Docker; значения из интерфейса важнее
- локальная модель в своей сети (имя сервиса, частный IP) подключается без ключа API
- .env.example, docs/DEPLOY.md (раздел 7а), README
This commit is contained in:
darkorion
2026-10-13 13:27:20 +03:00
parent 3a6e1f444c
commit 0f239d5015
44 changed files with 2131 additions and 94 deletions
+5 -2
View File
@@ -77,7 +77,8 @@ def env():
# ---------------------------------------------------------------- аутентификация
PUBLIC = {("POST", "/auth/login"), ("POST", "/auth/refresh"), ("POST", "/auth/logout"),
("GET", "/health"), ("GET", "/demo/status"),
("GET", "/public/report-options"), ("POST", "/public/incidents"), ("GET", "/app/version")} # публичная форма инцидента: без входа, с лимитом
("GET", "/public/report-options"), ("POST", "/public/incidents"), ("GET", "/app/version"),
("GET", "/docs/raw/{token}")} # исходник для ONLYOFFICE: только по короткой подписанной ссылке (проверка — test_scope_docs) # публичная форма инцидента: без входа, с лимитом
def test_every_api_route_requires_auth(env):
@@ -392,7 +393,9 @@ def test_stored_photo_name_is_server_generated(env):
from app.models import Photo
with SessionLocal() as s:
for p in s.query(Photo).all():
assert ".." not in p.path and not p.path.startswith(("/", "\\")) and len(p.path.split("/")) == 3
parts = p.path.split("/")
parts = parts[1:] if parts[0] == "keep" else parts # keep/ — фото «хранить более года»
assert ".." not in p.path and not p.path.startswith(("/", "\\")) and len(parts) == 3
def test_static_path_traversal_blocked(env):