Skip to content

Commit 9c1d365

Browse files
author
SM_SAYEED
committed
for timestamp assigning sqlite is used instead of python
1 parent cbe63be commit 9c1d365

File tree

1 file changed

+71
-166
lines changed

1 file changed

+71
-166
lines changed

app.py

Lines changed: 71 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def ensure_uploads_log_schema():
7373
def auto_log_material_files():
7474
"""
7575
Walk UPLOAD_FOLDER and upsert one row per (property, tab, filename).
76-
Idempotent: safe to call many times; never throws UNIQUE errors.
76+
Idempotent and uses SQLite CURRENT_TIMESTAMP (no Python datetime).
7777
"""
7878
ensure_uploads_log_schema()
7979

@@ -82,7 +82,7 @@ def auto_log_material_files():
8282
return {"status": "skip", "reason": "UPLOAD_FOLDER missing", "added_or_updated": 0}
8383

8484
allowed_exts = (ALLOWED_DATASET_EXTENSIONS | ALLOWED_RESULTS_EXTENSIONS)
85-
rows = [] # (property, tab, filename, uploaded_at)
85+
rows = [] # (property, tab, filename)
8686

8787
for root, _dirs, files in os.walk(root_dir):
8888
for fname in files:
@@ -100,7 +100,8 @@ def auto_log_material_files():
100100

101101
if len(parts) >= 3:
102102
prop, tab, filename = parts[0], parts[1], parts[2]
103-
rows.append((prop, tab, filename, datetime.utcnow().isoformat(timespec="seconds")))
103+
if tab in ("dataset", "results"):
104+
rows.append((prop, tab, filename))
104105

105106
if not rows:
106107
return {"status": "ok", "added_or_updated": 0}
@@ -110,9 +111,9 @@ def auto_log_material_files():
110111
c = conn.cursor()
111112
upsert = """
112113
INSERT INTO uploads_log (property, tab, filename, uploaded_at)
113-
VALUES (?, ?, ?, ?)
114+
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
114115
ON CONFLICT(property, tab, filename)
115-
DO UPDATE SET uploaded_at = excluded.uploaded_at
116+
DO UPDATE SET uploaded_at = CURRENT_TIMESTAMP
116117
"""
117118
for r in rows:
118119
c.execute(upsert, r)
@@ -246,34 +247,38 @@ def _startup_once():
246247

247248
# ========== ROUTES ==========
248249

249-
250+
#########################################################
250251
# Admin only rescanning for duplicates and re-importing
251252

252-
@app.route("/admin/rescan_uploads")
253-
def admin_rescan_uploads():
254-
if not session.get("admin"):
255-
return redirect(url_for("login"))
256-
257-
def count_rows():
253+
@app.route('/admin/rescan_uploads')
254+
def rescan_uploads():
255+
"""
256+
Re-scan the UPLOAD_FOLDER and upsert entries into uploads_log.
257+
Returns JSON with counts. Uses CURRENT_TIMESTAMP in SQL.
258+
"""
259+
try:
260+
# observe before/after for quick sanity checks
258261
with sqlite3.connect(DB_NAME) as conn:
259262
cur = conn.cursor()
260263
cur.execute("SELECT COUNT(*) FROM uploads_log")
261-
return cur.fetchone()[0]
264+
before = cur.fetchone()[0]
262265

263-
before = count_rows()
264-
try:
265266
result = auto_log_material_files()
267+
268+
with sqlite3.connect(DB_NAME) as conn:
269+
cur = conn.cursor()
270+
cur.execute("SELECT COUNT(*) FROM uploads_log")
271+
after = cur.fetchone()[0]
272+
273+
return jsonify({
274+
"status": result.get("status", "ok"),
275+
"added_or_updated": result.get("added_or_updated", 0),
276+
"rows_before": before,
277+
"rows_after": after
278+
})
266279
except Exception as e:
267280
return jsonify({"status": f"auto_log_material_files failed: {e}"}), 500
268-
after = count_rows()
269-
270-
return jsonify({
271-
"status": result.get("status"),
272-
"added_or_updated": result.get("added_or_updated"),
273-
"rows_before": before,
274-
"rows_after": after
275-
})
276-
281+
#########################################################
277282
# -- Admin login/logout --
278283
@app.route('/login', methods=['GET', 'POST'])
279284
def login():
@@ -291,7 +296,7 @@ def logout():
291296
session.pop('admin', None)
292297
flash("Logged out.")
293298
return redirect(url_for('public_home'))
294-
299+
#########################################################
295300
# -- Admin-only home page (upload/import/query) --
296301
@app.route('/admin', methods=['GET', 'POST'])
297302
def admin_home():
@@ -324,106 +329,8 @@ def admin_home():
324329
uploads=uploads,
325330
music_clips=music_clips
326331
)
327-
328-
# -- View and import (admin only) --
329-
@app.route('/view/<path:filename>', methods=['GET', 'POST'])
330-
def view_table(filename):
331-
admin = session.get('admin', False)
332-
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
333-
ext = filename.rsplit('.', 1)[1].lower()
334-
table_name = filename.replace('.', '_').replace('-', '_').replace('/', '_').replace('\\', '_')
335-
336-
try:
337-
if ext == 'csv':
338-
df = pd.read_csv(filepath)
339-
elif ext == 'npy':
340-
arr = np.load(filepath, allow_pickle=True)
341-
if isinstance(arr, np.ndarray):
342-
if arr.ndim == 2:
343-
df = pd.DataFrame(arr)
344-
elif arr.ndim == 1 and hasattr(arr[0], 'dtype') and arr[0].dtype.names:
345-
df = pd.DataFrame(arr)
346-
else:
347-
df = pd.DataFrame(arr)
348-
else:
349-
return "Unsupported NPY format for display."
350-
else:
351-
return "Unsupported file type."
352-
except Exception as e:
353-
return f"Could not read file: {e}"
354-
355-
# Only allow import if admin
356-
if admin and request.method == 'POST' and 'import_sql' in request.form:
357-
with sqlite3.connect(DB_NAME) as conn:
358-
df.to_sql(table_name, conn, if_exists='replace', index=False)
359-
flash(f"Table '{table_name}' imported to SQLite.")
360-
361-
return render_template('view_table.html',
362-
tables=[df.to_html(classes='data')],
363-
titles=df.columns.values,
364-
filename=filename,
365-
imported_table=table_name,
366-
admin=admin)
367-
368-
369-
# -- SQL query tool (admin only) --
370-
@app.route('/query', methods=['GET', 'POST'])
371-
def query_sql():
372-
if not session.get('admin'):
373-
return redirect(url_for('login'))
374-
375-
# List all tables for dropdown or info
376-
tables = []
377-
with sqlite3.connect(DB_NAME) as conn:
378-
c = conn.cursor()
379-
c.execute("SELECT name FROM sqlite_master WHERE type='table';")
380-
tables = [r[0] for r in c.fetchall()]
381-
382-
sql = ""
383-
result_html = ""
384-
error_msg = ""
385-
386-
if request.method == 'POST':
387-
sql = request.form['sql']
388-
try:
389-
with sqlite3.connect(DB_NAME) as conn:
390-
c = conn.cursor()
391-
c.execute(sql)
392-
# Try to fetch rows, if any
393-
try:
394-
rows = c.fetchall()
395-
if rows:
396-
# Get column names
397-
columns = [desc[0] for desc in c.description]
398-
import pandas as pd
399-
df = pd.DataFrame(rows, columns=columns)
400-
result_html = df.to_html(classes='data')
401-
else:
402-
result_html = "<p><b>Query executed successfully.</b></p>"
403-
except Exception:
404-
result_html = "<p><b>Query executed successfully.</b></p>"
405-
conn.commit()
406-
except Exception as e:
407-
error_msg = str(e)
408-
return render_template(
409-
'sql_query.html',
410-
tables=tables,
411-
sql=sql,
412-
result_html=result_html,
413-
error_msg=error_msg,
414-
admin=True
415-
)
416-
417-
# ========== PUBLIC ROUTES (view/download only) ==========
418-
419-
@app.route('/')
420-
def public_home():
421-
return render_template('landing.html')
422-
#########################################################
423-
@app.route('/materials')
424-
def materials_portal():
425-
return render_template('materials_portal.html')
426332
#########################################################
333+
# -- View and import (admin only) --
427334
@app.route('/materials/<property_name>/<tab>', methods=['GET', 'POST'])
428335
def property_detail(property_name, tab):
429336
# ---- titles / guards ----
@@ -438,35 +345,39 @@ def property_detail(property_name, tab):
438345

439346
upload_message = ""
440347
edit_message = ""
441-
is_admin = session.get('admin', False)
348+
is_admin = bool(session.get('admin'))
442349

443350
# ---- admin POST handlers ----
444351
if is_admin and request.method == 'POST':
445352
# Inline row edit
446353
if 'edit_row' in request.form:
447-
row_filename = request.form.get('row_filename')
448-
safe_row_filename = secure_filename(os.path.basename(row_filename or ""))
449-
354+
row_filename = request.form.get('row_filename') or ''
355+
safe_row_filename = secure_filename(os.path.basename(row_filename))
450356
new_desc = (request.form.get('row_description') or '').strip()
451-
if tab == 'dataset':
452-
new_source = (request.form.get('row_source') or '').strip()
453-
with sqlite3.connect(DB_NAME) as conn:
454-
c = conn.cursor()
455-
c.execute("""
357+
358+
with sqlite3.connect(DB_NAME) as conn:
359+
c = conn.cursor()
360+
if tab == 'dataset':
361+
new_source = (request.form.get('row_source') or '').strip()
362+
c.execute(
363+
"""
456364
UPDATE uploads_log
457365
SET source = ?, description = ?
458366
WHERE property = ? AND tab = ? AND filename = ?
459-
""", (new_source, new_desc, property_name, tab, safe_row_filename))
460-
conn.commit()
461-
else:
462-
with sqlite3.connect(DB_NAME) as conn:
463-
c = conn.cursor()
464-
c.execute("""
367+
""",
368+
(new_source, new_desc, property_name, tab, safe_row_filename),
369+
)
370+
else:
371+
c.execute(
372+
"""
465373
UPDATE uploads_log
466374
SET description = ?
467375
WHERE property = ? AND tab = ? AND filename = ?
468-
""", (new_desc, property_name, tab, safe_row_filename))
469-
conn.commit()
376+
""",
377+
(new_desc, property_name, tab, safe_row_filename),
378+
)
379+
conn.commit()
380+
470381
edit_message = f"Updated info for {safe_row_filename}."
471382

472383
# New file upload
@@ -479,12 +390,9 @@ def property_detail(property_name, tab):
479390
if tab == 'dataset':
480391
is_allowed = allowed_dataset_file(f.filename)
481392
allowed_types = "CSV or NPY"
482-
elif tab == 'results':
393+
else: # results
483394
is_allowed = allowed_results_file(f.filename)
484395
allowed_types = "JPG, PNG, GIF, PDF, or DOCX"
485-
else:
486-
is_allowed = False
487-
allowed_types = ""
488396

489397
if not is_allowed:
490398
upload_message = f"File type not allowed. Only {allowed_types} supported."
@@ -496,41 +404,37 @@ def property_detail(property_name, tab):
496404
filepath = os.path.join(property_folder, safe_filename)
497405
f.save(filepath)
498406

499-
# Log to DB (idempotent)
407+
# Log to DB (idempotent; no Python datetime)
500408
with sqlite3.connect(DB_NAME) as conn:
501409
c = conn.cursor()
502410
c.execute(
503411
"""
504412
INSERT INTO uploads_log (property, tab, filename, uploaded_at)
505-
VALUES (?, ?, ?, ?)
413+
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
506414
ON CONFLICT(property, tab, filename)
507-
DO UPDATE SET uploaded_at = excluded.uploaded_at
415+
DO UPDATE SET uploaded_at = CURRENT_TIMESTAMP
508416
""",
509-
(property_name, tab, safe_filename, datetime.datetime.now().isoformat()),
417+
(property_name, tab, safe_filename),
510418
)
511419
conn.commit()
512420

513421
upload_message = f"File {safe_filename} uploaded for {pretty_titles[property_name]} {tab.title()}!"
514422

515-
# ---- fetch current uploads (dedup to 1 row per filename; keep newest) ----
423+
# ---- fetch current uploads (unique per key thanks to UNIQUE index) ----
516424
with sqlite3.connect(DB_NAME) as conn:
517425
c = conn.cursor()
518-
c.execute("""
519-
SELECT u.filename,
520-
COALESCE(u.source, '') AS source,
521-
COALESCE(u.description, '') AS description,
522-
u.uploaded_at
523-
FROM uploads_log AS u
524-
JOIN (
525-
SELECT filename, MAX(uploaded_at) AS max_ts
526-
FROM uploads_log
527-
WHERE property = ? AND tab = ?
528-
GROUP BY filename
529-
) AS m
530-
ON m.filename = u.filename AND u.uploaded_at = m.max_ts
531-
WHERE u.property = ? AND u.tab = ?
532-
ORDER BY u.uploaded_at DESC
533-
""", (property_name, tab, property_name, tab))
426+
c.execute(
427+
"""
428+
SELECT filename,
429+
COALESCE(source, '') AS source,
430+
COALESCE(description, '') AS description,
431+
uploaded_at
432+
FROM uploads_log
433+
WHERE property = ? AND tab = ?
434+
ORDER BY uploaded_at DESC, filename
435+
""",
436+
(property_name, tab),
437+
)
534438
uploads = c.fetchall()
535439

536440
return render_template(
@@ -796,6 +700,7 @@ def extract_drive_id(link):
796700
message = "❌ Invalid link or missing title."
797701

798702
return render_template('add_drive_clip.html', message=message)
703+
799704
#########################################################
800705

801706
# ========== MAIN ==========

0 commit comments

Comments
 (0)