130 lines
4.6 KiB
Python
130 lines
4.6 KiB
Python
import json
|
|
import time
|
|
from pathlib import Path
|
|
from django.http import StreamingHttpResponse, JsonResponse
|
|
from django.conf import settings
|
|
from django.core.validators import validate_email
|
|
from django.core.exceptions import ValidationError
|
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
|
|
def send_progress_update(step, message, progress):
|
|
"""Helper to send a progress update as JSON"""
|
|
return json.dumps({"step": step, "message": message, "progress": progress}) + "\n"
|
|
|
|
|
|
@xframe_options_exempt
|
|
@csrf_exempt
|
|
def submit_quote(request):
|
|
"""
|
|
Handle quote submission with progress updates.
|
|
Steps:
|
|
1. Upload files
|
|
2. Save files
|
|
3. Send email
|
|
4. Verify email sent
|
|
"""
|
|
if request.method != "POST":
|
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
|
|
# Read form data first (files need to be read from request)
|
|
email = request.POST.get("email", "").strip()
|
|
notes = request.POST.get("notes", "").strip()
|
|
files = request.FILES.getlist("files")
|
|
|
|
def process_quote():
|
|
try:
|
|
# Step 1: Validate email
|
|
yield send_progress_update(1, "Validating email address...", 5)
|
|
|
|
if not email:
|
|
raise ValueError("Email is required")
|
|
|
|
try:
|
|
validate_email(email)
|
|
except ValidationError:
|
|
raise ValueError(f"Invalid email address: {email}")
|
|
|
|
yield send_progress_update(1, "Email validated successfully", 10)
|
|
|
|
# Step 2: Create submission & upload files
|
|
from quotes.models import Submission, SubmissionFile
|
|
|
|
# Create a Submission entry
|
|
submission = Submission.objects.create(
|
|
email=email,
|
|
description=notes,
|
|
)
|
|
|
|
yield send_progress_update(2, "Created submission entry...", 15)
|
|
|
|
# Save each file and register in the model
|
|
total_files = len(files)
|
|
file_objs = []
|
|
for idx, file in enumerate(files, start=1):
|
|
# Use the original filename and save to MEDIA_ROOT/submission_<id>_filename
|
|
submission_dir = (
|
|
Path(settings.MEDIA_ROOT) / f"submission_{submission.id}"
|
|
)
|
|
submission_dir.mkdir(parents=True, exist_ok=True)
|
|
target_path = submission_dir / file.name
|
|
|
|
with open(target_path, "wb") as f:
|
|
for chunk in file.chunks():
|
|
f.write(chunk)
|
|
|
|
# Register file in SubmissionFile model
|
|
rel_path = (Path(f"submission_{submission.id}") / file.name).as_posix()
|
|
submission_file = SubmissionFile.objects.create(
|
|
submission=submission,
|
|
original_filename=file.name,
|
|
path=rel_path,
|
|
file_size=file.size,
|
|
)
|
|
file_objs.append(submission_file)
|
|
yield send_progress_update(
|
|
2,
|
|
f"Uploaded file {idx} of {total_files}: {file.name}",
|
|
15 + int((idx / total_files) * 30),
|
|
)
|
|
|
|
yield send_progress_update(3, "Files saved...", 50)
|
|
|
|
# Step 4: Send emails
|
|
from quotes.email_utils import send_submission_emails
|
|
|
|
yield send_progress_update(4, "Sending notification email...", 70)
|
|
owner_sent, submitter_sent = send_submission_emails(submission)
|
|
time.sleep(0.3)
|
|
|
|
yield send_progress_update(4, "Sending confirmation email...", 75)
|
|
time.sleep(0.3)
|
|
|
|
# Verify emails were sent
|
|
if not owner_sent and getattr(settings, "OWNER_EMAIL", ""):
|
|
yield send_progress_update(
|
|
"warning",
|
|
"Warning: Owner notification email may not have been sent",
|
|
75,
|
|
)
|
|
if not submitter_sent:
|
|
yield send_progress_update(
|
|
"warning", "Warning: Confirmation email may not have been sent", 75
|
|
)
|
|
|
|
# Complete
|
|
yield send_progress_update(
|
|
5,
|
|
"Quote request submitted successfully! Check your email for confirmation.",
|
|
100,
|
|
)
|
|
|
|
except Exception as e:
|
|
yield send_progress_update("error", f"An error occurred: {str(e)}", 0)
|
|
|
|
response = StreamingHttpResponse(process_quote(), content_type="text/event-stream")
|
|
response["Cache-Control"] = "no-cache"
|
|
response["X-Accel-Buffering"] = "no"
|
|
return response
|