feat: przegląd baz na udziale + globalne włączanie/wyłączanie (DAN-15/PRE-09)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 12s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 40s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m3s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m35s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 14s
Testy / Kontrola składni wszystkich warstw (push) Successful in 10s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 12s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 40s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m3s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m35s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 14s
Testy / Kontrola składni wszystkich warstw (push) Successful in 10s
Wymaganie przedefiniowane pod model serwerowy (#47): nie wybiera się folderu — pliki leżą na stałym NFS. Potrzeba za to WIDZIEĆ, jakie bazy są dostępne i móc zdecydować, które biorą udział w interpretacji. Warstwa danych: `bases.py` (lista plików + metaopis: nazwa, ścieżka, rozmiar, data, stan) i endpoint `/bases`. Wyłączone bazy są ODSIEWANE z kandydatów przy wyszukiwaniu, więc naprawdę nie biorą udziału w interpretacji — nie tylko znikają z listy. Lista wyłączonych wchodzi do klucza cache zapytań: bez tego zmiana ustawień oddawałaby wynik sprzed zmiany, czyli treść bazy uznanej za wyłączoną. `list_bases()` doszło do interfejsu dostawcy jako OPCJONALNE (SQL nie operuje na plikach → pusto, zamiast wywrotki). Przelot logika → prezentacja i ekran „Ustawienia" z tabelą baz. Przez łącze idą SAME METADANE — podgląd listy nie jest kolejną drogą do wyniesienia treści. Stan przełączników jest DEKLARATYWNY (`DISABLED_BASES`), nie klikalny — i to jest świadome: udział z bazami montujemy read-only, a katalog cache to `emptyDir`, więc zapisany przełącznik ginąłby przy restarcie poda i po cichu włączał z powrotem wyłączoną bazę. Ekran mówi wprost, jak wyłączyć bazę i dlaczego nie klikaniem. Tryb klikalny wymagałby dołożenia trwałego wolumenu. Weryfikacja na żywym łańcuchu: `/bases` przechodzi przez SZYFROWANE łącze (logic→data), pokazuje 3 bazy z metaopisem i stanem; wyszukiwanie daje 3 → 2 → 0 wierszy w miarę wyłączania baz. Testy: dane +6, prezentacja +6. Dane 13, logika 277, prezentacja 249. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #55.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""Przegląd baz na udziale i ich globalne włączanie/wyłączanie (DAN-15 / PRE-09).
|
||||
|
||||
Wymaganie przedefiniowane pod model serwerowy: pliki baz leżą na stałym NFS, więc
|
||||
nie wybiera się folderu — potrzeba za to WIDZIEĆ, jakie bazy są dostępne (nazwa +
|
||||
metaopis) i móc globalnie zdecydować, które biorą udział w interpretacji.
|
||||
|
||||
Stan przełączników trzymamy DEKLARATYWNIE w zmiennej `DISABLED_BASES`, a nie w
|
||||
pliku, bo warstwa danych nie ma gdzie trwale zapisywać: udział z bazami jest
|
||||
montowany read-only, a katalog cache to `emptyDir` (ginie przy restarcie poda).
|
||||
Zapis do pliku po cichu wracałby więc do stanu sprzed restartu — a ciche
|
||||
przywrócenie wyłączonej bazy jest gorsze niż konieczność edycji konfiguracji.
|
||||
|
||||
Dopasowanie jest tolerancyjne: wpis pasuje po nazwie pliku ALBO po ścieżce
|
||||
względnej — żeby dało się wyłączyć zarówno „stara_baza.xlsx", jak i
|
||||
„archiwum/stara_baza.xlsx".
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def disabled_entries() -> list[str]:
|
||||
return [e.strip() for e in os.getenv("DISABLED_BASES", "").split(",") if e.strip()]
|
||||
|
||||
|
||||
def _relative(path: Path, root: Path) -> str:
|
||||
try:
|
||||
return str(path.relative_to(root))
|
||||
except ValueError:
|
||||
return path.name
|
||||
|
||||
|
||||
def is_enabled(path: str | Path, root: str | Path, entries: list[str] | None = None) -> bool:
|
||||
"""Czy baza bierze udział w wyszukiwaniu interpretacji."""
|
||||
entries = disabled_entries() if entries is None else entries
|
||||
if not entries:
|
||||
return True
|
||||
p = Path(path)
|
||||
rel = _relative(p, Path(root))
|
||||
return not any(e == p.name or e == rel for e in entries)
|
||||
|
||||
|
||||
def list_bases(root: str | Path, paths: list[str]) -> list[dict]:
|
||||
"""Bazy dostępne na udziale + metaopis. Celowo TANI opis (dane z systemu
|
||||
plików): przy setkach plików liczenie rekordów oznaczałoby wczytanie każdego."""
|
||||
root = Path(root)
|
||||
entries = disabled_entries()
|
||||
out: list[dict] = []
|
||||
for raw in paths:
|
||||
p = Path(raw)
|
||||
try:
|
||||
st = p.stat()
|
||||
size_mb, modified = round(st.st_size / (1024 * 1024), 2), st.st_mtime
|
||||
except OSError:
|
||||
size_mb, modified = None, None
|
||||
out.append({
|
||||
"name": p.name,
|
||||
"path": _relative(p, root),
|
||||
"size_mb": size_mb,
|
||||
"modified": (datetime.fromtimestamp(modified, tz=timezone.utc).strftime("%Y-%m-%d")
|
||||
if modified else None),
|
||||
"enabled": is_enabled(p, root, entries),
|
||||
})
|
||||
return out
|
||||
Reference in New Issue
Block a user