@@ -253,78 +253,91 @@ def make_file_public(file_id: str):
253253#==================================================#
254254
255255def ensure_uploads_log_schema ():
256- """Public catalog (uploads_log) + audit history (uploads_audit) with triggers."""
256+ """
257+ Create/upgrade:
258+ - uploads_log (public catalog)
259+ - uploads_audit (history)
260+ - audit triggers (insert/update/delete on uploads_log)
261+ Never let a UNIQUE index error block creating the audit bits.
262+ """
257263 with sqlite3 .connect (DB_NAME ) as conn :
258264 c = conn .cursor ()
259265
260- # Public catalog (what public pages read )
266+ # 1) Public catalog (Drive-era columns included )
261267 c .execute ("""
262- CREATE TABLE IF NOT EXISTS uploads_log (
263- id INTEGER PRIMARY KEY AUTOINCREMENT,
264- property TEXT NOT NULL,
265- tab TEXT NOT NULL, -- 'dataset' | 'results'
266- filename TEXT NOT NULL, -- human-visible label
267- uploaded_at TEXT, -- first/last touch, maintained by app
268- -- Drive-first metadata
269- storage TEXT, -- 'drive' | 'local' (legacy)
270- drive_id TEXT,
271- preview_url TEXT,
272- download_url TEXT,
273- source TEXT,
274- description TEXT,
275- UNIQUE(property, tab, filename)
276- )
268+ CREATE TABLE IF NOT EXISTS uploads_log (
269+ id INTEGER PRIMARY KEY AUTOINCREMENT,
270+ property TEXT NOT NULL,
271+ tab TEXT NOT NULL, -- 'dataset' | 'results'
272+ filename TEXT NOT NULL, -- human-visible label
273+ uploaded_at TEXT, -- first/last touch, maintained by app
274+ -- Drive-first metadata
275+ storage TEXT, -- 'drive' | 'local' (legacy)
276+ drive_id TEXT,
277+ preview_url TEXT,
278+ download_url TEXT,
279+ source TEXT,
280+ description TEXT,
281+ UNIQUE(property, tab, filename)
282+ )
277283 """ )
278284
279- # Ensure index exists even on old DBs
280- c .execute ("""
281- CREATE UNIQUE INDEX IF NOT EXISTS idx_uploads_unique
282- ON uploads_log(property, tab, filename)
283- """ )
285+ # 2) Unique index: wrap so it never blocks later steps
286+ try :
287+ c .execute ("""
288+ CREATE UNIQUE INDEX IF NOT EXISTS idx_uploads_unique
289+ ON uploads_log(property, tab, filename)
290+ """ )
291+ except sqlite3 .OperationalError as e :
292+ # e.g., duplicates present -> index creation fails. Log and continue.
293+ app .logger .warning ("ensure_uploads_log_schema: unique index creation skipped: %s" , e )
284294
285- # ---- Audit table
295+ # 3) Audit table (history)
286296 c .execute ("""
287- CREATE TABLE IF NOT EXISTS uploads_audit (
288- id INTEGER PRIMARY KEY AUTOINCREMENT,
289- property TEXT NOT NULL,
290- tab TEXT NOT NULL,
291- filename TEXT NOT NULL,
292- action TEXT NOT NULL, -- add | update | delete
293- at TEXT NOT NULL
294- )
297+ CREATE TABLE IF NOT EXISTS uploads_audit (
298+ id INTEGER PRIMARY KEY AUTOINCREMENT,
299+ property TEXT NOT NULL,
300+ tab TEXT NOT NULL,
301+ filename TEXT NOT NULL,
302+ action TEXT NOT NULL, -- add | update | delete
303+ at TEXT NOT NULL
304+ )
295305 """ )
296306
297- # Helper to create triggers idempotently
298- def ensure_trigger (name , ddl ):
307+ # 4) Triggers ( create only if missing)
308+ def ensure_trigger (name : str , ddl : str ):
299309 c .execute ("SELECT 1 FROM sqlite_master WHERE type='trigger' AND name=?" , (name ,))
300310 if not c .fetchone ():
301311 c .execute (ddl )
302312
303313 ensure_trigger ("trg_ul_insert_audit" , """
304- CREATE TRIGGER trg_ul_insert_audit
305- AFTER INSERT ON uploads_log
306- BEGIN
307- INSERT INTO uploads_audit(property, tab, filename, action, at)
308- VALUES (NEW.property, NEW.tab, NEW.filename, 'add',
309- COALESCE(NEW.uploaded_at, CURRENT_TIMESTAMP));
310- END;""" )
314+ CREATE TRIGGER trg_ul_insert_audit
315+ AFTER INSERT ON uploads_log
316+ BEGIN
317+ INSERT INTO uploads_audit(property, tab, filename, action, at)
318+ VALUES (NEW.property, NEW.tab, NEW.filename, 'add',
319+ COALESCE(NEW.uploaded_at, CURRENT_TIMESTAMP));
320+ END;
321+ """ )
311322
312323 ensure_trigger ("trg_ul_update_audit" , """
313- CREATE TRIGGER trg_ul_update_audit
314- AFTER UPDATE ON uploads_log
315- BEGIN
316- INSERT INTO uploads_audit(property, tab, filename, action, at)
317- VALUES (NEW.property, NEW.tab, NEW.filename, 'update',
318- COALESCE(NEW.uploaded_at, CURRENT_TIMESTAMP));
319- END;""" )
324+ CREATE TRIGGER trg_ul_update_audit
325+ AFTER UPDATE ON uploads_log
326+ BEGIN
327+ INSERT INTO uploads_audit(property, tab, filename, action, at)
328+ VALUES (NEW.property, NEW.tab, NEW.filename, 'update',
329+ COALESCE(NEW.uploaded_at, CURRENT_TIMESTAMP));
330+ END;
331+ """ )
320332
321333 ensure_trigger ("trg_ul_delete_audit" , """
322- CREATE TRIGGER trg_ul_delete_audit
323- AFTER DELETE ON uploads_log
324- BEGIN
325- INSERT INTO uploads_audit(property, tab, filename, action, at)
326- VALUES (OLD.property, OLD.tab, OLD.filename, 'delete', CURRENT_TIMESTAMP);
327- END;""" )
334+ CREATE TRIGGER trg_ul_delete_audit
335+ AFTER DELETE ON uploads_log
336+ BEGIN
337+ INSERT INTO uploads_audit(property, tab, filename, action, at)
338+ VALUES (OLD.property, OLD.tab, OLD.filename, 'delete', CURRENT_TIMESTAMP);
339+ END;
340+ """ )
328341
329342 conn .commit ()
330343#==================================================#
@@ -730,37 +743,66 @@ def admin_home():
730743 if not session .get ('admin' ):
731744 return redirect (url_for ('login' ))
732745
733- # Make sure catalog + audit schema exist (triggers are created here too)
734- ensure_uploads_log_schema ()
746+ # Ensure base schema exists (tables + triggers), but never crash this page
735747 try :
736- ensure_uploads_log_columns () # Add Drive-era columns if missing
748+ ensure_uploads_log_schema ()
737749 except Exception as e :
738- app .logger .warning ("ensure_uploads_log_columns : %s" , e )
750+ app .logger .warning ("ensure_uploads_log_schema raised : %s" , e )
739751
740- # Build the history table: when first added, and whether still present publicly
741- with sqlite3 .connect (DB_NAME ) as conn :
742- c = conn .cursor ()
743- c .execute ("""
744- WITH hist AS (
745- SELECT property, tab, filename,
746- MIN(CASE WHEN action='add' THEN at END) AS first_added,
747- MAX(at) AS last_event
748- FROM uploads_audit
749- GROUP BY property, tab, filename
750- )
751- SELECT
752- h.filename AS file_name,
753- COALESCE(h.first_added, h.last_event) AS uploaded_at,
754- CASE WHEN u.rowid IS NULL THEN 'Absent' ELSE 'Present' END AS public_view_status
755- FROM hist h
756- LEFT JOIN uploads_log u
757- ON u.property=h.property AND u.tab=h.tab AND u.filename=h.filename
758- ORDER BY uploaded_at DESC, h.filename;
759- """ )
760- audit_rows = c .fetchall ()
752+ # Best effort: make sure Drive-era columns exist (storage, drive_id, etc.)
753+ try :
754+ ensure_uploads_log_columns () # your existing helper that ALTER TABLE as needed
755+ except Exception as e :
756+ app .logger .warning ("ensure_uploads_log_columns raised: %s" , e )
761757
762- return render_template ('admin_home.html' , audit_rows = audit_rows )
758+ # Guard: if audit table still missing (older DBs), create it quickly so page works
759+ try :
760+ with sqlite3 .connect (DB_NAME ) as conn :
761+ c = conn .cursor ()
762+ c .execute ("SELECT name FROM sqlite_master WHERE type='table' AND name='uploads_audit'" )
763+ if not c .fetchone ():
764+ c .execute ("""
765+ CREATE TABLE IF NOT EXISTS uploads_audit (
766+ id INTEGER PRIMARY KEY AUTOINCREMENT,
767+ property TEXT NOT NULL,
768+ tab TEXT NOT NULL,
769+ filename TEXT NOT NULL,
770+ action TEXT NOT NULL, -- add | update | delete
771+ at TEXT NOT NULL
772+ )
773+ """ )
774+ conn .commit ()
775+ except Exception as e :
776+ app .logger .warning ("guard-create uploads_audit failed: %s" , e )
777+
778+ # Build the history table (don’t crash page if something’s off)
779+ audit_rows = []
780+ try :
781+ with sqlite3 .connect (DB_NAME ) as conn :
782+ c = conn .cursor ()
783+ c .execute ("""
784+ WITH hist AS (
785+ SELECT property, tab, filename,
786+ MIN(CASE WHEN action='add' THEN at END) AS first_added,
787+ MAX(at) AS last_event
788+ FROM uploads_audit
789+ GROUP BY property, tab, filename
790+ )
791+ SELECT
792+ h.filename AS file_name,
793+ COALESCE(h.first_added, h.last_event) AS uploaded_at,
794+ CASE WHEN u.rowid IS NULL THEN 'Absent' ELSE 'Present' END AS public_view_status
795+ FROM hist h
796+ LEFT JOIN uploads_log u
797+ ON u.property=h.property AND u.tab=h.tab AND u.filename=h.filename
798+ ORDER BY uploaded_at DESC, h.filename;
799+ """ )
800+ audit_rows = c .fetchall ()
801+ except Exception as e :
802+ app .logger .warning ("admin_home query failed: %s" , e )
803+ audit_rows = []
763804
805+ return render_template ('admin_home.html' , audit_rows = audit_rows )
764806#########################################################
765807
766808@app .route ("/admin/fix_uploads_uniqueness" , methods = ["GET" , "POST" ])
0 commit comments