diff --git a/README.md b/README.md index 22a4eef..3868ff5 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A Flask web app for a convention booth where visitors request a custom AI-genera - **Request form** (`/request`) — visitors enter name, email, hobbies, notable facts, preferred style/genre, vocal gender preference, and extra requests. A branded banner image is shown. The email field is validated to reduce delivery problems. If the operator marks the booth as closed, this page shows a closed banner and message instead. - **Closed page** (`/request`) — when the booth is marked closed from `/admin/settings`, visitors see the closed banner and a friendly "goblin engineers are on a break" message. +- **Order status lookup** (`/status`) — customers enter their email to see all their requests, current status, and the private player link once songs are uploaded. - **Confirmation page** (`/thanks/`) — shows the request number after submission. - **FAQ page** (`/faq`) — answers common customer questions. - **Private player page** (`/play/`) — customer receives an email with a unique link. They can stream Version A and Version B, pick one (or both), or request a limited number of revisions. @@ -63,6 +64,7 @@ pending → prompt_ready → songs_uploaded → awaiting_payment → paid → de | `templates/closed.html` | Message shown on `/request` when the booth is marked closed. | | `templates/request.html` | Customer request form. | | `templates/thanks.html` | Post-submission confirmation. | +| `templates/status.html` | Customer order status lookup. | | `templates/faq.html` | Customer FAQ page. | | `templates/player.html` | Customer audio player, approval, and revision form. | | `templates/admin/login.html` | Admin login page. | diff --git a/REVIEW.md b/REVIEW.md index 504bf0c..0f5892d 100644 --- a/REVIEW.md +++ b/REVIEW.md @@ -35,6 +35,7 @@ Flask app that lets convention attendees request custom AI-generated theme songs | `templates/admin/dashboard.html` | Queue table + filters + auto-refresh + topbar Reset System button. | | `templates/admin/settings.html` | SMTP config, MP3 metadata defaults, DB backup/restore, health check, reset. | | `templates/faq.html` | Customer FAQ page. | +| `templates/status.html` | Customer order status lookup. | | `templates/closed.html` | Message shown on `/request` when the booth is marked closed. | | `docker-compose.yml` | No `env_file`; variables come from Portainer. | diff --git a/app.py b/app.py index 94be26b..b03b671 100644 --- a/app.py +++ b/app.py @@ -54,7 +54,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 +from models import SCHEMA, get_requests_by_email # Audio metadata import from mutagen.mp3 import MP3 @@ -392,6 +392,26 @@ def thanks(rid): return render_template('thanks.html', req=req) +@app.route('/status', methods=['GET', 'POST']) +def status_lookup(): + """ + Public order status lookup page. + Customers enter their email to see all their requests and their current + statuses, plus the private player link once songs have been uploaded. + """ + requests_list = [] + email = '' + searched = False + if request.method == 'POST': + email = request.form.get('email', '').strip().lower() + if not is_valid_email(email): + flash('Please enter a valid email address.', 'error') + else: + requests_list = get_requests_by_email(email) + searched = True + return render_template('status.html', email=email, requests=requests_list, searched=searched, statuses=STATUS_LABELS) + + @app.route('/faq') def faq(): """Customer-facing frequently asked questions page.""" diff --git a/models.py b/models.py index bbd422d..a780064 100644 --- a/models.py +++ b/models.py @@ -129,6 +129,17 @@ def list_requests(status=None): return [dict(r) for r in rows] +def get_requests_by_email(email): + """Fetch all requests for a given email address, newest first. + Email is compared case-insensitively and stripped of whitespace.""" + db = get_db() + rows = db.execute( + "SELECT * FROM requests WHERE LOWER(TRIM(email)) = LOWER(TRIM(?)) ORDER BY created_at DESC", + (email,) + ).fetchall() + return [dict(r) for r in rows] + + def update_request(request_id, **fields): """ Update arbitrary columns for a request. diff --git a/templates/request.html b/templates/request.html index a23d6a0..f1cfc36 100644 --- a/templates/request.html +++ b/templates/request.html @@ -122,7 +122,7 @@

🎵 Get Your Custom Theme Song 🎶

Tell us about yourself and we'll craft a one-of-a-kind song just for you.

-

Questions? Read our FAQ →

+

Questions? Read our FAQ → · Already ordered? Check status →

{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} diff --git a/templates/status.html b/templates/status.html new file mode 100644 index 0000000..0d2f7b9 --- /dev/null +++ b/templates/status.html @@ -0,0 +1,190 @@ + + + + + + Check Your Order Status — Trollgorithm Theme Song Booth + + + +
+ + +
+

🔍 Check Your Order Status

+

Enter the email address you used when you requested your song.

+ + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} + {% endwith %} + +
+ + + +
+ + {% if searched %} +
+ {% if requests %} + {% for req in requests %} +
+

Request #{{ req.id }} — {{ req.name }}

+

Status: {{ statuses[req.status] }}

+ + {% if req.customer_approved != 'none' %} +

You selected: {% if req.customer_approved == 'both' %}Both Versions{% else %}Version {{ req.customer_approved.upper() }}{% endif %}

+ {% endif %} + + {% if req.song_a_path and req.song_b_path %} +

Your preview link:

+ 🎧 Listen & Pick Your Version + {% endif %} +
+ {% endfor %} + {% else %} +

No requests found for that email address. Make sure you used the same email you gave us at the booth.

+ {% endif %} +
+ {% endif %} + + ← Back to the request form +
+
+ +