import random from django.db.models import Prefetch from django.http import Http404, JsonResponse from django.shortcuts import render from django.urls import reverse from django.views import View from django.views.generic import DetailView, ListView, TemplateView from apps.products.models import MainProduct, SubProduct from .forms import ContactForm from .models import ( AboutSection, ContactSubmission, ContactSubmissionAttachment, CustomPage, FAQEntry, HeroSection, HomepageSection, PageVideo, ) VIDEO_PREVIEW_LIMIT = 3 VIDEO_ARCHIVE_PAGE_SIZE = 6 def _video_preview_context(queryset, archive_url): total = queryset.count() return { "videos": queryset[:VIDEO_PREVIEW_LIMIT], "videos_total_count": total, "videos_archive_url": archive_url if total > VIDEO_PREVIEW_LIMIT else "", } def _homepage_products_catalog_queryset(): return ( MainProduct.objects.filter(is_active=True) .prefetch_related( Prefetch( "sub_products", queryset=SubProduct.objects.filter(is_active=True).order_by("order", "name"), ) ) .order_by("order", "name") ) class HomeView(TemplateView): template_name = "pages/home.html" def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["hero"] = HeroSection.objects.first() ctx["homepage_sections"] = ( HomepageSection.objects.filter(is_active=True) .prefetch_related("items") .order_by("order") ) ctx["homepage_products"] = ( MainProduct.objects.filter(is_active=True, show_on_homepage=True) .order_by("homepage_order", "order") ) ctx["homepage_products_catalog"] = _homepage_products_catalog_queryset() return ctx class AboutView(TemplateView): template_name = "pages/about.html" def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["about_sections"] = ( AboutSection.objects.filter(is_active=True) .prefetch_related("items") .order_by("order") ) return ctx class FAQView(ListView): model = FAQEntry template_name = "pages/faq.html" context_object_name = "faq_entries" queryset = FAQEntry.objects.filter(is_active=True) def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) videos = PageVideo.objects.filter( page=PageVideo.PAGE_FAQ, is_active=True, ).order_by("order", "pk") preview = _video_preview_context( videos, reverse( "pages:video_archive", kwargs={"library": PageVideo.PAGE_FAQ}, ), ) ctx["faq_videos"] = preview["videos"] ctx["videos_total_count"] = preview["videos_total_count"] ctx["videos_archive_url"] = preview["videos_archive_url"] return ctx class ContactView(View): template_name = "pages/contact.html" def _new_captcha(self, request): a, b = random.randint(1, 9), random.randint(1, 9) request.session["captcha_answer"] = a + b return f"{a} + {b}" def get(self, request, *args, **kwargs): videos = PageVideo.objects.filter( page=PageVideo.PAGE_CONTACT, is_active=True, ).order_by("order", "pk") preview = _video_preview_context( videos, reverse( "pages:video_archive", kwargs={"library": PageVideo.PAGE_CONTACT}, ), ) return render( request, self.template_name, { "form": ContactForm(), "captcha_question": self._new_captcha(request), "contact_videos": preview["videos"], "videos_total_count": preview["videos_total_count"], "videos_archive_url": preview["videos_archive_url"], }, ) def post(self, request, *args, **kwargs): form = ContactForm( request.POST, file_list=request.FILES.getlist("attachments"), ) expected = request.session.get("captcha_answer") captcha_question = self._new_captcha(request) captcha_ok = False try: captcha_ok = int(request.POST.get("captcha_answer", "")) == expected except (ValueError, TypeError): pass if form.is_valid() and captcha_ok: submission = form.save() for uploaded_file, original_name in form.cleaned_data.get( "attachments", [] ): attachment = ContactSubmissionAttachment( submission=submission, original_filename=original_name, ) attachment.file.save(original_name, uploaded_file, save=True) return JsonResponse({"success": True}) errors: dict = {} if not captcha_ok: errors["captcha"] = ["Incorrect answer — please try again."] errors.update( {field: [str(e) for e in errs] for field, errs in form.errors.items()} ) return JsonResponse( {"success": False, "errors": errors, "captcha_question": captcha_question}, status=400, ) class CustomPageView(DetailView): model = CustomPage template_name = "pages/custom_page.html" context_object_name = "custom_page" slug_url_kwarg = "slug" def get_queryset(self): return CustomPage.objects.filter(is_published=True) def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["page_sections"] = ( self.object.sections.filter(is_active=True) .prefetch_related("items") .order_by("order") ) ctx["homepage_products"] = ( MainProduct.objects.filter(is_active=True, show_on_homepage=True) .order_by("homepage_order", "order") ) ctx["homepage_products_catalog"] = _homepage_products_catalog_queryset() return ctx class PageVideoArchiveView(ListView): model = PageVideo template_name = "videos/archive.html" context_object_name = "videos" paginate_by = VIDEO_ARCHIVE_PAGE_SIZE PAGE_CONFIG = { PageVideo.PAGE_CONTACT: ( "Contact videos", "Guides and updates from the Radiuma team.", "pages:contact", ), PageVideo.PAGE_FAQ: ( "FAQ videos", "Video answers to common questions.", "pages:faq", ), } def get_page_config(self): try: return self.PAGE_CONFIG[self.kwargs["library"]] except KeyError as exc: raise Http404("Video library not found.") from exc def get_queryset(self): self.get_page_config() return PageVideo.objects.filter( page=self.kwargs["library"], is_active=True, ).order_by("order", "pk") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) title, description, source_url_name = self.get_page_config() context.update( { "library_title": title, "library_description": description, "library_back_url": reverse(source_url_name), "library_back_label": "Back to page", "pagination_range": context["paginator"].get_elided_page_range( context["page_obj"].number ), } ) return context