| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- 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,
- },
- )
|