feat: editable customer email in admin + email validation on public form

This commit is contained in:
Troll (Hermes Agent) 2026-08-02 16:51:32 +00:00
parent 4af9322c9d
commit bf9f9e09fd
4 changed files with 48 additions and 13 deletions

40
app.py
View file

@ -30,6 +30,7 @@ Admin routes:
# Standard library imports
import os
import re
import shutil
import smtplib
import ssl
@ -38,7 +39,6 @@ from email.message import EmailMessage
from pathlib import Path
import json
import time
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
@ -318,14 +318,18 @@ def request_form():
"""
Public request form.
GET -> shows the form with the banner image.
POST -> creates a database record, sends a confirmation email,
and redirects to the thanks page.
POST -> validates the email, creates a database record, sends a
confirmation email, and redirects to the thanks page.
Rate limited to 5 submissions per minute per IP.
"""
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')
return render_template('request.html'), 400
rid = create_request(
name=request.form.get('name', '').strip(),
email=request.form.get('email', '').strip(),
email=email,
hobbies=request.form.get('hobbies', '').strip(),
notable_facts=request.form.get('notable_facts', '').strip(),
style_genre=request.form.get('style_genre', '').strip(),
@ -491,6 +495,15 @@ def admin_login():
return render_template('admin/login.html')
def is_valid_email(email):
"""Return True if the given string looks like a valid email address."""
if not email:
return False
# Very loose regex: local@domain.tld, no spaces, with a real TLD part.
pattern = r"^[^\s@]+@[^\s@]+\.[^\s@]+$"
return re.match(pattern, email) is not None
@app.route('/admin/logout')
def admin_logout():
"""Clear the admin session."""
@ -517,9 +530,11 @@ def admin_dashboard():
def admin_request(rid):
"""
Detail/edit page for a single request.
GET -> render customer info, prompt, upload status, email status, and delivery forms.
POST -> handle one of four actions:
save_prompt, upload_songs, notify_customer, mark_paid_deliver
GET -> render customer info (email editable), prompt, upload status,
email status, and delivery forms.
POST -> handle one of five actions:
update_customer_email, save_prompt, upload_songs,
notify_customer, mark_paid_deliver
Uploaded MP3s are tagged with metadata defaults from /admin/settings.
"""
redir = require_admin()
@ -549,7 +564,16 @@ def admin_request(rid):
if request.method == 'POST':
action = request.form.get('action')
if action == 'save_prompt':
if action == 'update_customer_email':
new_email = request.form.get('email', '').strip().lower()
if not is_valid_email(new_email):
flash('Please enter a valid email address.', 'error')
return redirect(url_for('admin_request', rid=rid))
update_request(rid, email=new_email)
flash('Customer email updated.', 'success')
return redirect(url_for('admin_request', rid=rid))
elif action == 'save_prompt':
# Store the generated title/style/lyrics and mark prompt ready.
update_request(rid,
suno_title=request.form.get('suno_title', '').strip(),