from __future__ import annotations from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from django.urls import reverse from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from orgs.models import Organization, UserProfile from recycle_core.models import ProvidedService from recycle_core.models import Material, ScrapListing, PickupOrder from cms.models import Post, PostCategory from .forms import ( PickupRequestForm, ContactForm, RegistrationForm, PublicUserForm, PublicUserPhotoForm, PublicUserProfileExtraForm, ) from .models import Lead from recycle_core.controllers.pickup_request import ( PickupRequestController, PickupRequestData, ) from django.contrib.auth.views import LoginView from django.urls import reverse def home(request): org = getattr(request, "org", None) posts_qs = Post.objects.all() if org is not None: posts_qs = posts_qs.filter(organization=org) posts = posts_qs.order_by("-published_at")[:3] listings_qs = ScrapListing.objects.filter(is_public=True) if org is not None: listings_qs = listings_qs.filter(organization=org) listings = listings_qs.order_by("-created_at")[:6] materials_qs = Material.objects.all().order_by("name") if org is not None: materials_qs = materials_qs.filter(organization=org) materials = materials_qs[:12] services_qs = ProvidedService.objects.none() if org is not None: services_qs = ProvidedService.objects.filter(organization=org, is_enabled=True).order_by("display_order", "id") services = list(services_qs) pickup_form = PickupRequestForm() contact_form = ContactForm() register_form = RegistrationForm() return render( request, "public_frontend/home.html", { "posts": posts, "listings": listings, "materials": materials, "services": services, "pickup_form": pickup_form, "contact_form": contact_form, "org": org, "register_form": register_form, }, ) def materials_list(request): org = getattr(request, "org", None) qs = Material.objects.all().order_by("name") if org is not None: qs = qs.filter(organization=org) return render(request, "public_frontend/materials_list.html", {"materials": qs, "org": org}) def listings_list(request): org = getattr(request, "org", None) qs = ScrapListing.objects.filter(is_public=True, status=ScrapListing.STATUS_OPEN).order_by("-created_at") if org is not None: qs = qs.filter(organization=org) paginator = Paginator(qs, 12) page = request.GET.get("page") try: page_obj = paginator.page(page) except PageNotAnInteger: page_obj = paginator.page(1) except EmptyPage: page_obj = paginator.page(paginator.num_pages) return render(request, "public_frontend/listings_list.html", {"page_obj": page_obj, "listings": page_obj.object_list, "org": org}) def listing_detail(request, pk: int): org = getattr(request, "org", None) base_qs = ScrapListing.objects.filter(is_public=True) if org is not None: base_qs = base_qs.filter(organization=org) listing = get_object_or_404(base_qs, pk=pk) return render(request, "public_frontend/listing_detail.html", {"listing": listing, "org": org}) def service_detail(request, pk: int): org = getattr(request, "org", None) base_qs = ProvidedService.objects.filter(is_enabled=True) if org is not None: base_qs = base_qs.filter(organization=org) service = get_object_or_404(base_qs, pk=pk) return render(request, "public_frontend/service_detail.html", {"service": service, "org": org}) def pickup_request(request): org = getattr(request, "org", None) # Prefill form for authenticated users initial = {} if request.user.is_authenticated: u = request.user full_name = (getattr(u, "get_full_name", lambda: "")() or "").strip() initial["name"] = full_name or u.username if getattr(u, "email", ""): initial["email"] = u.email form = PickupRequestForm(request.POST or None, request.FILES or None, initial=initial) if request.method == "POST": if not org: messages.error(request, "Organization context missing.") return redirect("public_frontend:pickup_request") if form.is_valid(): ctrl = PickupRequestController() data = PickupRequestData( organization=org, name=form.cleaned_data.get("name"), email=form.cleaned_data.get("email", ""), phone=form.cleaned_data.get("phone", ""), address=form.cleaned_data.get("address", ""), materials=form.cleaned_data.get("materials", ""), preferred_at=form.cleaned_data.get("preferred_at"), files=request.FILES.getlist("photos") if hasattr(request, "FILES") and "photos" in request.FILES else [], created_by=request.user if request.user.is_authenticated else None, ) result = ctrl.submit(data) if result.ok: messages.success(request, "Thanks! Your pickup request was submitted.") return redirect("public_frontend:home") else: messages.error(request, result.error or "Unable to submit your request.") else: messages.error(request, "Please correct the errors below.") return render(request, "public_frontend/pickup_request.html", {"form": form, "org": org}) def contact(request): org = getattr(request, "org", None) form = ContactForm(request.POST or None) if request.method == "POST": if not org: messages.error(request, "Organization context missing.") return redirect("public_frontend:contact") if form.is_valid(): Lead.objects.create( organization=org, name=form.cleaned_data["name"], email=form.cleaned_data["email"], phone=form.cleaned_data.get("phone", ""), subject=form.cleaned_data.get("subject", ""), message=form.cleaned_data.get("message", ""), source="contact", created_by=request.user if request.user.is_authenticated else None, ) messages.success(request, "Thanks! We will get back to you shortly.") return redirect("public_frontend:home") messages.error(request, "Please correct the errors below.") return render(request, "public_frontend/contact.html", {"form": form, "org": org}) def register(request): from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from orgs.models import UserProfile org = getattr(request, "org", None) if not org: messages.error(request, "Organization context missing.") return redirect("public_frontend:home") form = RegistrationForm(request.POST or None) if request.method == "POST": if form.is_valid(): User = get_user_model() user = User(username=form.cleaned_data["username"], email=form.cleaned_data["email"], is_active=False) user.set_password(form.cleaned_data["password1"]) user.save() role = form.cleaned_data["role"] # Create org profile UserProfile.objects.create(user=user, organization=org, role=role) # Add to group matching the role if exists try: g = Group.objects.filter(name=role).first() if g: user.groups.add(g) except Exception: pass messages.success(request, "Account created. Please wait for admin approval.") return redirect("public_frontend:home") else: messages.error(request, "Please correct the errors below.") return render(request, "public_frontend/register.html", {"form": form, "org": org}) def blog_list(request): org = getattr(request, "org", None) qs = Post.objects.all().order_by("-published_at", "-created_at") if org is not None: qs = qs.filter(organization=org) paginator = Paginator(qs, 10) page = request.GET.get("page") try: page_obj = paginator.page(page) except PageNotAnInteger: page_obj = paginator.page(1) except EmptyPage: page_obj = paginator.page(paginator.num_pages) return render(request, "public_frontend/blog_list.html", {"page_obj": page_obj, "posts": page_obj.object_list, "org": org}) def blog_detail(request, slug: str): org = getattr(request, "org", None) base_qs = Post.objects.all() if org is not None: base_qs = base_qs.filter(organization=org) post = get_object_or_404(base_qs, slug=slug) # Ensure markdown is rendered; fallback to raw content if needed html = getattr(post, "content_html", None) or getattr(post, "content", "") return render(request, "public_frontend/blog_detail.html", {"post": post, "html": html, "org": org}) class PublicLoginView(LoginView): template_name = "public_frontend/login.html" redirect_authenticated_user = True def get_success_url(self): return reverse("public_frontend:home") from django.contrib.auth.decorators import login_required from django.contrib.auth import get_user_model from django.utils import timezone from recycle_core.models import CarbonEvent, CarbonBalance @login_required def my_profile(request): user = request.user profile = getattr(user, "recycle_profile", None) role_code = getattr(profile, "role", None) role_label = dict(UserProfile.ROLE_CHOICES).get(role_code, "-") if role_code else "-" if request.method == "POST": form_user = PublicUserForm(request.POST, instance=user) form_photo = PublicUserPhotoForm(request.POST, request.FILES, instance=profile) if profile else None form_extras = PublicUserProfileExtraForm(request.POST, instance=profile) if profile else None ok_user = form_user.is_valid() ok_photo = True if form_photo is None else form_photo.is_valid() ok_extras = True if form_extras is None else form_extras.is_valid() if ok_user and ok_photo and ok_extras: form_user.save() if form_photo is not None: form_photo.save() if form_extras is not None: form_extras.save() messages.success(request, "Profile updated.") return redirect(reverse("public_frontend:my_profile")) messages.error(request, "Please correct the errors below.") else: form_user = PublicUserForm(instance=user) form_photo = PublicUserPhotoForm(instance=profile) if profile else None form_extras = PublicUserProfileExtraForm(instance=profile) if profile else None # Request history (pickup requests submitted via public form, matched by email) history = [] try: email = (user.email or "").strip() if email: qs = Lead.objects.filter(email__iexact=email, source="pickup_request").order_by("-created_at") org = getattr(request, "org", None) if org is not None: qs = qs.filter(organization=org) history = list(qs[:20]) except Exception: history = [] # Carbon summary for user's organization org = getattr(request, "org", None) or getattr(profile, "organization", None) carbon = None if org is not None: today = timezone.now().date() bal = CarbonBalance.objects.filter(organization=org, year=today.year, month=today.month).first() pending = CarbonEvent.objects.filter(organization=org, status=CarbonEvent.STATUS_PENDING).count() carbon = { "pending_events": pending, "approved_mtd": bal.approved_kgco2e if bal else 0, } return render( request, "public_frontend/my_profile.html", { "form_user": form_user, "form_photo": form_photo, "form_extras": form_extras, "has_profile": bool(profile), "username_value": user.username, "role_label": role_label, "request_history": history, "carbon": carbon, }, )