Add configurable max revisions limit with customer counter and operator override

This commit is contained in:
Troll (Hermes Agent) 2026-08-01 21:36:23 +00:00
parent 5b6012aa3d
commit 506d07179a
5 changed files with 99 additions and 22 deletions

100
app.py
View file

@ -33,6 +33,8 @@ import ssl
from email.message import EmailMessage
from pathlib import Path
import json
# Flask and related imports
from flask import Flask, request, render_template, redirect, url_for, flash, session, send_from_directory, abort, current_app
from werkzeug.utils import secure_filename
@ -202,7 +204,19 @@ def play(token):
req = get_request_by_token(token)
if not req:
abort(404)
return render_template('player.html', req=req)
# Load runtime max revisions setting.
cfg_path = Path(current_app.config['UPLOAD_FOLDER']).parent / 'booth_settings.json'
runtime_settings = {}
if cfg_path.exists():
try:
runtime_settings = json.loads(cfg_path.read_text())
except (json.JSONDecodeError, OSError):
runtime_settings = {}
max_revisions = runtime_settings.get('max_revisions', current_app.config['MAX_REVISIONS'])
revisions_left = max(0, max_revisions - (req.get('revision_count') or 0))
return render_template('player.html', req=req, revisions_left=revisions_left)
@app.route('/play/<token>/approve', methods=['POST'])
@ -236,29 +250,42 @@ def revise(token):
so the operator sees it in the dashboard queue.
"""
note = request.form.get('revision_note', '').strip()
# Increment revision counter and archive current files before new versions are uploaded.
req = get_request_by_token(token)
if req:
new_count = (req.get('revision_count') or 0) + 1
upload_dir = Path(current_app.config['UPLOAD_FOLDER']) / str(req['id'])
if upload_dir.exists():
for field, version in (('song_a_path', 'A'), ('song_b_path', 'B')):
path = req.get(field)
if path and Path(path).exists():
old = Path(path)
archived = upload_dir / f"Rev{new_count}-{old.name}"
try:
old.rename(archived)
# Keep path pointing to the archived file; operator will upload new files.
req[field] = str(archived)
except OSError:
pass
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)
else:
if not req:
abort(404)
# Enforce max revisions limit for customer-submitted revisions.
cfg_path = Path(current_app.config['UPLOAD_FOLDER']).parent / 'booth_settings.json'
runtime_settings = {}
if cfg_path.exists():
try:
runtime_settings = json.loads(cfg_path.read_text())
except (json.JSONDecodeError, OSError):
runtime_settings = {}
max_revisions = runtime_settings.get('max_revisions', current_app.config['MAX_REVISIONS'])
current_count = req.get('revision_count') or 0
if current_count >= max_revisions:
flash('Revision limit reached. Please speak to the booth operator if you need further changes.', 'error')
return redirect(url_for('play', token=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'])
if upload_dir.exists():
for field, version in (('song_a_path', 'A'), ('song_b_path', 'B')):
path = req.get(field)
if path and Path(path).exists():
old = Path(path)
archived = upload_dir / f"Rev{new_count}-{old.name}"
try:
old.rename(archived)
req[field] = str(archived)
except OSError:
pass
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)
# NOTE: No operator email is sent; the dashboard is the single queue.
flash('Your feedback has been saved. We will regenerate and update you.', 'success')
return redirect(url_for('play', token=token))
@ -479,6 +506,16 @@ def admin_settings():
for req in all_requests:
status_counts[req['status']] = status_counts.get(req['status'], 0) + 1
# Load persistent runtime settings (max_revisions overrides env var if set).
cfg_path = Path(current_app.config['UPLOAD_FOLDER']).parent / 'booth_settings.json'
runtime_settings = {}
if cfg_path.exists():
try:
runtime_settings = json.loads(cfg_path.read_text())
except (json.JSONDecodeError, OSError):
runtime_settings = {}
current_max_revisions = runtime_settings.get('max_revisions', current_app.config['MAX_REVISIONS'])
# Compute upload folder stats.
total_upload_size = 0
upload_file_count = 0
@ -555,6 +592,24 @@ def admin_settings():
flash('System reset complete. All orders and files have been cleared.', 'success')
return redirect(url_for('admin_settings'))
elif action == 'save_max_revisions':
# Update the MAX_REVISIONS config from the settings form.
try:
val = int(request.form.get('max_revisions', '2').strip())
if val < 0:
raise ValueError
# Store in a simple config file so it persists across restarts.
cfg_path = Path(current_app.config['UPLOAD_FOLDER']).parent / 'booth_settings.json'
data = {}
if cfg_path.exists():
data = json.loads(cfg_path.read_text())
data['max_revisions'] = val
cfg_path.write_text(json.dumps(data))
flash(f'Maximum revisions set to {val}.', 'success')
except ValueError:
flash('Invalid revision limit. Please enter a non-negative number.', 'error')
return redirect(url_for('admin_settings'))
return render_template(
'admin/settings.html',
health=health,
@ -566,7 +621,8 @@ def admin_settings():
upload_dir_count=request_dir_count,
upload_size=format_bytes(total_upload_size),
db_path=str(db_path),
upload_path=str(upload_root)
upload_path=str(upload_root),
current_max_revisions=current_max_revisions,
)