From bc4f38726addaf2cfbf35e4bf0b02e79a3e8927b Mon Sep 17 00:00:00 2001 From: Mia Wu Date: Wed, 3 Jun 2026 16:15:09 -0400 Subject: [PATCH] fixed db problem --- docker-compose.yml | 5 +++++ server/app.py | 2 ++ server/data/dashboard.db | Bin 0 -> 356352 bytes server/data/dashboard.db-shm | Bin 0 -> 32768 bytes server/data/dashboard.db-wal | Bin 0 -> 45352 bytes server/db_py.py | 15 +++++++++++++-- server/watcher.py | 29 +++++++++++++++++++++++++++++ 7 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 server/data/dashboard.db create mode 100644 server/data/dashboard.db-shm create mode 100644 server/data/dashboard.db-wal create mode 100644 server/watcher.py diff --git a/docker-compose.yml b/docker-compose.yml index 2c2b42e..74dd8db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,10 +7,12 @@ services: environment: - HOST_BROWSE_ROOT=${HOST_BROWSE_ROOT} - HOST_MOUNT_ROOT=/host + - DASHBOARD_DB_PATH=/app/data/dashboard.db volumes: - type: bind source: ./server target: /app + - db_data:/app/data - type: bind source: ${HOST_BROWSE_ROOT} target: /host @@ -37,3 +39,6 @@ services: - frontend restart: unless-stopped +volumes: + db_data: + diff --git a/server/app.py b/server/app.py index cdbe015..14cd59e 100644 --- a/server/app.py +++ b/server/app.py @@ -147,6 +147,8 @@ def _create_default_user_if_missing(username, password, role): def _ensure_default_users(): + if count_users() > 0: + print("[server] Users already exist, skipping default account seeding.") if count_users() == 0: print("[server] No users found. Seeding default accounts...") diff --git a/server/data/dashboard.db b/server/data/dashboard.db new file mode 100644 index 0000000000000000000000000000000000000000..659e622dc5be1a9dcf57b1ec956b4ff515670ea2 GIT binary patch literal 356352 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 literal 0 HcmV?d00001 diff --git a/server/data/dashboard.db-wal b/server/data/dashboard.db-wal new file mode 100644 index 0000000000000000000000000000000000000000..df9ffcd4097def7c3d224b1042ad376c21378426 GIT binary patch literal 45352 zcmeI*OK99h90%~-Y)F$xyF$bm4-z2-sZ{3uSjoktYDhy9XpMN$d6p2<)WjwgG$BFo zCenjfK@dSv^k~3?kAtW;5h|^h9<(6!L8;V}&YuusVpM1@N%{WS!0zn+|IBUo*bGUdvt2-q&<0Rz$MOAVoGuDoTfZ5%N^4?3a_F{Qj44f4Zx>%Y6aF!f^HX_fa&qkWh;CBc<=rFsG$RfiQ1`4^fof>!gEXBoRf8 zG+GfEwaeN%;kflYdXs2*V)i^)qgPTU-!;00bZa0SG_<0uX=z1Rwwb2<&%(?nYmIeW|0ZqtVkU}AJq%+5YV7f-OUbK|4q z1Cq1gog&JWU_(hPq^OLQ!b%^7vs7ryVhox~VpzTCCo5&H|@;^Loga8B}009U<00Izz00bZa0SN3Vfz5h>1C5?~i4inP z_d2UCZsZ8QKl1zX)z4Nht=9|Os5NiwsR5uf5P$##AOHafKmY;|fB*y_009W>R-mii z=&hfdFB?Br>jGQ$7Z{$o`qJRwyC0!mV7JJ)9|91700bZa0SG_<0uX=z1R${21a_IYfUT009U<00Izz00bZa0SN40ft8W=|2d~H zESwz~9(`o)IXX5yb>h_YKn~7EQ_klj+Ij6mj^1nIVv50PfL{^jDIN2+>(w&t~3^IF+t02c%x009U<00Izz00bZa0SG_< z0{dTJvs|G4-}V>ietG`F`Lzd@u)o0mpKgo*0uX=z1Rwwb2tWV=5P$##Ah4sr=Kcch x<@+uB3w-j{!5{Cx@A?wz1$LA}BLpA-0SG_<0uX=z1Rwwb2tZ)}3hYoX@E07k`cMD> literal 0 HcmV?d00001 diff --git a/server/db_py.py b/server/db_py.py index fc8065e..d5bca76 100644 --- a/server/db_py.py +++ b/server/db_py.py @@ -6,9 +6,15 @@ import threading from contextlib import contextmanager BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -DB_PATH = os.path.join(BASE_DIR, "dashboard.db") +_DEFAULT_DB_PATH = os.path.join(BASE_DIR, "data", "dashboard.db") +if os.path.exists("/.dockerenv"): + _DEFAULT_DB_PATH = "/app/data/dashboard.db" + +DB_PATH = os.getenv("DASHBOARD_DB_PATH", _DEFAULT_DB_PATH) CONFIG_JSON = os.path.join(BASE_DIR, "config.json") +os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) + _conn = sqlite3.connect(DB_PATH, check_same_thread=False) _conn.row_factory = sqlite3.Row _lock = threading.RLock() @@ -27,7 +33,12 @@ def _tx(): def _init_db(): with _tx(): - _conn.execute("PRAGMA journal_mode=WAL;") + try: + _conn.execute("PRAGMA journal_mode=WAL;") + except sqlite3.OperationalError as exc: + # Fallback for filesystems where WAL is unavailable. + print(f"[db] WAL unavailable ({exc}); falling back to DELETE journal mode") + _conn.execute("PRAGMA journal_mode=DELETE;") _conn.executescript( """ CREATE TABLE IF NOT EXISTS config ( diff --git a/server/watcher.py b/server/watcher.py new file mode 100644 index 0000000..5c7137d --- /dev/null +++ b/server/watcher.py @@ -0,0 +1,29 @@ +import os +import sys +import time +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +class TestResultsHandler(FileSystemEventHandler): + def __init__(self, callback): + super().__init__() + self.callback = callback + + def on_created(self, event): + if event.is_directory: + print(f"[watcher] Detected new test result directory: {event.src_path}") + self.callback(event.src_path) + + +def start_watching_results_dir(results_dir, callback): + event_handler = TestResultsHandler(callback) + observer = Observer() + observer.schedule(event_handler, results_dir, recursive=False) + observer.start() + print(f"[watcher] Started watching for new test results in: {results_dir}") + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + observer.stop() + observer.join() \ No newline at end of file