# # Copyright 2019 # - Sli # # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, # http://ae.utbm.fr. # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License a published by the Free Software # Foundation; either version 3 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple # Place - Suite 330, Boston, MA 02111-1307, USA. # # from django.conf import settings from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Exists, OuterRef from django.http import HttpResponse from django.shortcuts import get_object_or_404 from django.urls import reverse, reverse_lazy from django.views.generic import ( CreateView, DeleteView, DetailView, FormView, TemplateView, UpdateView, ) from core.auth.mixins import PermissionOrAuthorRequiredMixin from core.models import Notification, User from core.views.mixins import AllowFragment, FragmentMixin, UseFragmentsMixin from pedagogy.forms import ( UECommentForm, UECommentModerationForm, UECommentReportForm, UEForm, ) from pedagogy.models import UE, UEComment, UECommentReport class UECommentCreateView(PermissionRequiredMixin, FragmentMixin, CreateView): model = UEComment template_name = "pedagogy/fragments/ue_comment_form.jinja" form_class = UECommentForm permission_required = "pedagogy.add_uecomment" object = None # Avoid initialisation bug with FragmentMixin @property def ue(self): if hasattr(self, "_ue"): return self._ue self._ue = get_object_or_404(UE, id=self.kwargs.get("ue_id")) return self._ue def has_permission(self): if self.ue.has_user_already_commented(self.request.user): return False return super().has_permission() def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["author_id"] = self.request.user.id kwargs["ue_id"] = self.ue.id kwargs["is_creation"] = True return kwargs def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) | { "action": reverse("pedagogy:comment_create", kwargs={"ue_id": self.ue.id}) } def get_success_url(self): return reverse("pedagogy:comment_detail", kwargs={"comment_id": self.object.id}) class UEDetailView( PermissionRequiredMixin, UseFragmentsMixin, AllowFragment, DetailView ): """Display every comment of an UE and detailed infos about it.""" model = UE pk_url_kwarg = "ue_id" template_name = "pedagogy/ue_detail.jinja" permission_required = "pedagogy.view_ue" fragments = { "add_comment_form": UECommentCreateView, } def get_fragment_data(self): return {"add_comment_form": {"ue_id": self.object.id}} def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) | { "comments": list( self.object.comments.viewable_by(self.request.user) .annotate_is_reported() .select_related("author") .order_by("-publish_date") ), } class UECommentDetailView(PermissionRequiredMixin, DetailView): model = UEComment pk_url_kwarg = "comment_id" template_name = "pedagogy/fragments/ue_comment.jinja" permission_required = "pedagogy.view_ue" context_object_name = "comment" def dispatch(self, *args, **kwargs): res: HttpResponse = super().dispatch(*args, **kwargs) res.headers["HX-Trigger"] = "CommentUpdate" return res def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) | {"ue": self.object.ue} class UECommentUpdateView(PermissionOrAuthorRequiredMixin, AllowFragment, UpdateView): """Allow edit of a given comment.""" model = UEComment form_class = UECommentForm pk_url_kwarg = "comment_id" template_name = "pedagogy/fragments/ue_comment_form.jinja" permission_required = "pedagogy.change_uecomment" author_field = "author" def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["author_id"] = self.object.author_id kwargs["ue_id"] = self.object.ue_id kwargs["is_creation"] = False return kwargs def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) | { "action": reverse( "pedagogy:comment_update", kwargs={"comment_id": self.object.id} ) } def get_success_url(self): return reverse("pedagogy:comment_detail", kwargs={"comment_id": self.object.id}) class UECommentDeleteView(PermissionOrAuthorRequiredMixin, AllowFragment, DeleteView): """Allow to delete a given comment.""" model = UEComment pk_url_kwarg = "comment_id" template_name = "core/delete_confirm.jinja" permission_required = "pedagogy.delete_uecomment" author_field = "author" def form_valid(self, form): self.object.delete() response = HttpResponse(status=200) response.headers["HX-Trigger"] = "CommentUpdate" return response class UEGuideView(PermissionRequiredMixin, TemplateView): """UE guide main page.""" template_name = "pedagogy/guide.jinja" permission_required = "pedagogy.view_ue" class UECommentReportCreateView(PermissionRequiredMixin, CreateView): """Create a new report for an inappropriate comment.""" model = UECommentReport form_class = UECommentReportForm template_name = "core/edit.jinja" permission_required = "pedagogy.add_uecommentreport" def dispatch(self, request, *args, **kwargs): self.ue_comment = get_object_or_404(UEComment, pk=kwargs["comment_id"]) return super().dispatch(request, *args, **kwargs) def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["reporter_id"] = self.request.user.id kwargs["comment_id"] = self.ue_comment.id return kwargs def form_valid(self, form): resp = super().form_valid(form) # Send a message to moderation admins unread_notif_subquery = Notification.objects.filter( user=OuterRef("pk"), type="PEDAGOGY_MODERATION", viewed=False ) for user in User.objects.filter( ~Exists(unread_notif_subquery), groups__id__in=[settings.SITH_GROUP_PEDAGOGY_ADMIN_ID], ): Notification.objects.create( user=user, url=reverse("pedagogy:moderation"), type="PEDAGOGY_MODERATION", ) return resp def get_success_url(self): return reverse("pedagogy:ue_detail", kwargs={"ue_id": self.ue_comment.ue_id}) class UEModerationFormView(PermissionRequiredMixin, FormView): """Moderation interface (Privileged).""" form_class = UECommentModerationForm template_name = "pedagogy/moderation.jinja" permission_required = "pedagogy.delete_uecomment" success_url = reverse_lazy("pedagogy:moderation") def form_valid(self, form): form_clean = form.clean() accepted = form_clean.get("accepted_reports", []) if len(accepted) > 0: # delete the reported comments UEComment.objects.filter(reports__in=accepted).delete() denied = form_clean.get("denied_reports", []) if len(denied) > 0: # delete the comments themselves UECommentReport.objects.filter(id__in={d.id for d in denied}).delete() return super().form_valid(form) class UECreateView(PermissionRequiredMixin, CreateView): """Add a new UE (Privileged).""" model = UE form_class = UEForm template_name = "pedagogy/ue_edit.jinja" permission_required = "pedagogy.add_ue" def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["author_id"] = self.request.user.id return kwargs class UEDeleteView(PermissionRequiredMixin, DeleteView): """Allow to delete an UE (Privileged).""" model = UE pk_url_kwarg = "ue_id" template_name = "core/delete_confirm.jinja" permission_required = "pedagogy.delete_ue" success_url = reverse_lazy("pedagogy:guide") class UEUpdateView(PermissionRequiredMixin, UpdateView): """Allow to edit an UE (Privilegied).""" model = UE form_class = UEForm pk_url_kwarg = "ue_id" template_name = "pedagogy/ue_edit.jinja" permission_required = "pedagogy.change_ue" def get_form_kwargs(self): kwargs = super().get_form_kwargs() obj = self.get_object() kwargs["author_id"] = obj.author_id return kwargs