Add revision history log and music files ZIP backup

This commit is contained in:
Troll (Hermes Agent) 2026-08-04 16:54:51 +00:00
parent 8246f641a2
commit cda4d57859
4 changed files with 127 additions and 14 deletions

50
app.py
View file

@ -58,7 +58,7 @@ from werkzeug.utils import secure_filename
# Project imports
from config import Config
from models import init_db, close_db, create_request, get_request_by_id, get_request_by_token, list_requests, update_request, now_utc, delete_request, reset_all_requests, get_db
from models import SCHEMA, get_requests_by_email
from models import SCHEMA, get_requests_by_email, log_revision, list_revision_history
# Audio metadata import
from mutagen.mp3 import MP3
@ -630,6 +630,8 @@ def revise(token):
# Increment revision counter and archive current files before new versions are uploaded.
new_count = current_count + 1
upload_dir = Path(current_app.config['UPLOAD_FOLDER']) / str(req['id'])
old_a, old_b = req.get('song_a_path'), req.get('song_b_path')
new_a, new_b = old_a, old_b
if upload_dir.exists():
for field, version in (('song_a_path', 'A'), ('song_b_path', 'B')):
path = req.get(field)
@ -638,9 +640,14 @@ def revise(token):
archived = upload_dir / f"Rev{new_count}-{old.name}"
try:
old.rename(archived)
if field == 'song_a_path':
new_a = str(archived)
else:
new_b = str(archived)
req[field] = str(archived)
except OSError:
pass
log_revision(req['id'], new_count, note, old_a=old_a, old_b=old_b, new_a=new_a, new_b=new_b)
update_request(req['id'], revision_note=note, status='revisions_requested',
song_a_path=req.get('song_a_path'), song_b_path=req.get('song_b_path'),
customer_approved='none', revision_count=new_count)
@ -963,7 +970,7 @@ def admin_request(rid):
return redirect(url_for('admin_request', rid=rid))
return render_template('admin/request.html', req=req, statuses=STATUS_LABELS, file_exists=file_exists, basename=basename, extra_files=extra_files, callback_url=build_prompt_callback_url(rid))
return render_template('admin/request.html', req=req, statuses=STATUS_LABELS, file_exists=file_exists, basename=basename, extra_files=extra_files, callback_url=build_prompt_callback_url(rid), revision_history=list_revision_history(rid))
@app.route('/admin/request/<int:rid>/delete', methods=['POST'])
@ -1088,19 +1095,20 @@ def admin_settings():
action = request.form.get('action')
if action == 'fix_db':
# Attempt to add missing columns via ALTER TABLE.
if not health['ok'] and health['missing_columns']:
try:
db = get_db()
# Attempt to create missing tables and add missing columns via ALTER TABLE.
try:
db = get_db()
db.executescript(SCHEMA)
if not health['ok'] and health['missing_columns']:
for col in health['missing_columns']:
# Default to TEXT columns; adequate for current schema.
db.execute(f'ALTER TABLE requests ADD COLUMN {col} TEXT')
db.commit()
flash(f'Added missing columns: {", ".join(health["missing_columns"])}. Please refresh the page.', 'success')
except Exception as e:
flash(f'Failed to fix database: {e}', 'error')
else:
flash('No columns need fixing.', 'success')
flash(f'Created missing tables and added columns: {", ".join(health["missing_columns"])}. Please refresh the page.', 'success')
else:
flash('Database schema is up to date.', 'success')
db.commit()
except Exception as e:
flash(f'Failed to fix database: {e}', 'error')
return redirect(url_for('admin_settings'))
elif action == 'reset_system':
@ -1199,6 +1207,24 @@ def admin_settings():
flash('Database file not found.', 'error')
return redirect(url_for('admin_settings'))
elif action == 'download_uploads_zip':
# Zip all files under UPLOAD_FOLDER and send as a download.
import zipfile
zip_path = db_path.with_suffix('.uploads-' + str(int(time.time())) + '.zip')
try:
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
if upload_root.exists():
for entry in upload_root.rglob('*'):
if entry.is_file():
zf.write(str(entry), str(entry.relative_to(upload_root)))
return send_file(str(zip_path), as_attachment=True, download_name='theme-song-booth-uploads.zip')
except Exception as e:
flash(f'Failed to create uploads ZIP: {e}', 'error')
return redirect(url_for('admin_settings'))
finally:
if zip_path.exists():
zip_path.unlink()
elif action == 'restore_db':
# Replace the current database file with an uploaded SQLite backup.
file_obj = request.files.get('db_backup')