from django.contrib import messages from django.shortcuts import redirect, render from django.urls import reverse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods from analytics.services import attribute_lead_from_request from contacts.models import Channel, ConsentRecord, Contact from leads.models import Lead from messaging.services import ( channel_preferences, parse_unsubscribe_token, process_unsubscribe_token, set_channel_preferences, unsubscribe_all, ) from public.forms import ContactForm, NotifyForm def home(request): return render(request, "public/home.html") def about(request): return render(request, "public/about.html") @require_http_methods(["GET", "POST"]) def contact(request): if request.method == "POST": form = ContactForm(request.POST) if form.is_valid(): data = form.cleaned_data defaults = { "first_name": data["first_name"], "last_name": data.get("last_name") or "", "phone": data.get("phone") or "", "source": Contact.Source.CONTACT_FORM, } postal = Contact.make_postal_address( line1=data.get("address_line1") or "", line2=data.get("address_line2") or "", city=data.get("address_city") or "", state=data.get("address_state") or "", zip_code=data.get("address_zip") or "", ) if Contact.postal_address_has_content(postal): defaults["postal_address"] = postal contact_obj, _ = Contact.objects.update_or_create( email=data["email"].lower(), defaults=defaults, ) ConsentRecord.objects.update_or_create( contact=contact_obj, channel=Channel.EMAIL, defaults={"opted_in": True, "reason": "contact_form"}, ) if (data.get("phone") or "").strip(): ConsentRecord.objects.update_or_create( contact=contact_obj, channel=Channel.SMS, defaults={"opted_in": True, "reason": "contact_form"}, ) interest = data.get("interest") or "" interest_label = dict(ContactForm.INTEREST_CHOICES).get(interest, interest) body = data.get("message") or "" if interest_label: body = f"Interest: {interest_label}\n\n{body}".strip() lead = Lead.objects.create( contact=contact_obj, message=body, status=Lead.Status.NEW, ) attribute_lead_from_request(request, lead) messages.success(request, "Thanks — Monica will be in touch soon.") return redirect(f"{reverse('public:contact')}?sent=1") else: form = ContactForm() return render(request, "public/contact.html", {"form": form}) @require_http_methods(["GET", "POST"]) def under_construction(request): """Direct route (also used by middleware). Accepts notify-me emails.""" if request.method == "POST": form = NotifyForm(request.POST) if form.is_valid(): email = form.cleaned_data["email"].lower() Contact.objects.get_or_create( email=email, defaults={ "first_name": "", "source": Contact.Source.NOTIFY_ME, }, ) messages.success(request, "You're on the list — we'll email when we launch.") return redirect("public:under_construction") else: form = NotifyForm() return render(request, "public/under_construction.html", {"form": form}) @csrf_exempt @require_http_methods(["GET", "POST"]) def unsubscribe_one_click(request, token: str): """ One-click opt-out for the channel encoded in the token. CSRF-exempt so mail clients can POST List-Unsubscribe=One-Click (RFC 8058). """ ok = process_unsubscribe_token(token) if not ok: return render(request, "public/unsubscribe.html", {"valid": False}) return redirect("public:unsubscribe", token=token) @require_http_methods(["GET", "POST"]) def unsubscribe(request, token: str): """ Signed-token preference center for email / SMS / postcard. GET ?one_click=1 opts out the token channel then redirects here. POST saves checkboxes or unsubscribes from all channels. """ contact, token_channel = parse_unsubscribe_token(token) if not contact: return render( request, "public/unsubscribe.html", {"valid": False}, ) if request.method == "GET" and request.GET.get("one_click") in { "1", "true", "yes", }: process_unsubscribe_token(token) return redirect("public:unsubscribe", token=token) if request.method == "POST": action = (request.POST.get("action") or "save").strip() if action == "unsubscribe_all": unsubscribe_all(contact, reason="preferences_unsubscribe_all") messages.success( request, "You are unsubscribed from all marketing channels." ) else: prefs = { Channel.EMAIL: "consent_email" in request.POST, Channel.SMS: "consent_sms" in request.POST, Channel.POSTCARD: "consent_postcard" in request.POST, } set_channel_preferences( contact, prefs, reason="preferences_save" ) messages.success(request, "Your communication preferences were saved.") return redirect("public:unsubscribe", token=token) contact = Contact.objects.prefetch_related("consents").get(pk=contact.pk) prefs = channel_preferences(contact) identity = contact.email or contact.phone or contact.full_name or "your profile" return render( request, "public/unsubscribe.html", { "valid": True, "contact": contact, "identity": identity, "prefs": prefs, "token_channel": token_channel, "token": token, }, ) def page_not_found(request, exception): return render(request, "public/404.html", status=404)