from django.contrib.auth.mixins import LoginRequiredMixin from django.http import Http404 from django.shortcuts import get_object_or_404 from django.views.generic import DetailView, ListView from .markdown import render_markdown from .models import GuidePage, allowed_audiences class GuideAccessMixin: """Scope the help centre by PORTAL first, then by role. Being an admin does not mean seeing every guide in every portal: the buyer portal lists buyer guides (the audience of its readers), the ops portal lists ops guides, and the admin guides only appear in the ops portal for admin/superuser accounts. See apps.guides.models.allowed_audiences. """ def get_portal(self): return getattr(self.request.resolver_match, "namespace", None) or "portal" def get_allowed_audiences(self): user = self.request.user return allowed_audiences( self.get_portal(), role=getattr(user, "role", None), is_superuser=user.is_superuser, ) def get_help_root(self): return f"/{self.get_portal()}/help/" class GuideIndexView(LoginRequiredMixin, GuideAccessMixin, ListView): model = GuidePage context_object_name = "guides" def get_queryset(self): return GuidePage.objects.filter(audience__in=self.get_allowed_audiences()) def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["help_root"] = self.get_help_root() return ctx class GuideDetailView(LoginRequiredMixin, GuideAccessMixin, DetailView): model = GuidePage # the templates read {{ guide.title }}; without this the object arrives as # "object" and every guide detail page renders a blank browser title context_object_name = "guide" def get_object(self, queryset=None): path = f"user-guides/{self.kwargs['page_path']}" page = get_object_or_404(GuidePage, path=path) if page.audience not in self.get_allowed_audiences(): raise Http404("This guide is not available in this portal.") return page def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) help_root = self.get_help_root() ctx["help_root"] = help_root ctx["guide_html"] = render_markdown(self.object.content, self.object.path, help_root) ctx["guides"] = GuidePage.objects.filter(audience__in=self.get_allowed_audiences()) return ctx