Sith/pedagogy/views.py
2024-06-26 19:17:57 +02:00

334 lines
9.5 KiB
Python

# -*- coding:utf-8 -*-
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the whole source code at https://github.com/ae-utbm/sith3
#
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
#
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
from django.utils import html
from django.views.generic import (
CreateView,
DeleteView,
FormView,
ListView,
UpdateView,
View,
)
from haystack.query import SearchQuerySet
from rest_framework.renderers import JSONRenderer
from core.models import Notification, RealGroup
from core.views import (
CanCreateMixin,
CanEditPropMixin,
CanViewMixin,
DetailFormView,
)
from pedagogy.forms import (
UVCommentForm,
UVCommentModerationForm,
UVCommentReportForm,
UVForm,
)
from pedagogy.models import UV, UVComment, UVCommentReport, UVSerializer
# Some mixins
class CanCreateUVFunctionMixin(View):
"""
Add the function can_create_uv(user) into the template
"""
@staticmethod
def can_create_uv(user):
"""
Creates a dummy instance of UV and test is_owner
"""
return user.is_owner(UV())
def get_context_data(self, **kwargs):
"""
Pass the function to the template
"""
kwargs = super(CanCreateUVFunctionMixin, self).get_context_data(**kwargs)
kwargs["can_create_uv"] = self.can_create_uv
return kwargs
# Acutal views
class UVDetailFormView(CanViewMixin, CanCreateUVFunctionMixin, DetailFormView):
"""
Dispaly every comment of an UV and detailed infos about it
Allow to comment the UV
"""
model = UV
pk_url_kwarg = "uv_id"
template_name = "pedagogy/uv_detail.jinja"
form_class = UVCommentForm
def get_form_kwargs(self):
kwargs = super(UVDetailFormView, self).get_form_kwargs()
kwargs["author_id"] = self.request.user.id
kwargs["uv_id"] = self.get_object().id
kwargs["is_creation"] = True
return kwargs
def form_valid(self, form):
form.save()
return super(UVDetailFormView, self).form_valid(form)
def get_success_url(self):
return reverse_lazy(
"pedagogy:uv_detail", kwargs={"uv_id": self.get_object().id}
)
class UVCommentUpdateView(CanEditPropMixin, UpdateView):
"""
Allow edit of a given comment
"""
model = UVComment
form_class = UVCommentForm
pk_url_kwarg = "comment_id"
template_name = "core/edit.jinja"
def get_form_kwargs(self):
kwargs = super(UVCommentUpdateView, self).get_form_kwargs()
obj = self.get_object()
kwargs["author_id"] = obj.author.id
kwargs["uv_id"] = obj.uv.id
kwargs["is_creation"] = False
return kwargs
def get_success_url(self):
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv.id})
class UVCommentDeleteView(CanEditPropMixin, DeleteView):
"""
Allow delete of a given comment
"""
model = UVComment
pk_url_kwarg = "comment_id"
template_name = "core/delete_confirm.jinja"
def get_success_url(self):
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv.id})
class UVListView(CanViewMixin, CanCreateUVFunctionMixin, ListView):
"""
UV guide main page
"""
# This is very basic and is prone to changment
model = UV
ordering = ["code"]
template_name = "pedagogy/guide.jinja"
def get(self, *args, **kwargs):
if not self.request.GET.get("json", None):
# Return normal full template response
return super(UVListView, self).get(*args, **kwargs)
# Return serialized response
return HttpResponse(
JSONRenderer().render(UVSerializer(self.get_queryset(), many=True).data),
content_type="application/json",
)
def get_queryset(self):
queryset = super(UVListView, self).get_queryset()
search = self.request.GET.get("search", None)
additional_filters = {}
for filter_type in ["credit_type", "language", "department"]:
arg = self.request.GET.get(filter_type, None)
if arg:
additional_filters[filter_type] = arg
semester = self.request.GET.get("semester", None)
if semester:
if semester in ["AUTUMN", "SPRING"]:
additional_filters["semester__in"] = [semester, "AUTUMN_AND_SPRING"]
else:
additional_filters["semester"] = semester
queryset = queryset.filter(**additional_filters)
if not search:
return queryset
if len(search) == 1:
# It's a search with only one letter
# Haystack doesn't work well with only one letter
return queryset.filter(code__istartswith=search)
try:
qs = (
SearchQuerySet()
.models(self.model)
.autocomplete(auto=html.escape(search))
)
except TypeError:
return self.model.objects.none()
return queryset.filter(
id__in=([o.object.id for o in qs if o.object is not None])
)
class UVCommentReportCreateView(CanCreateMixin, CreateView):
"""
Create a new report for an inapropriate comment
"""
model = UVCommentReport
form_class = UVCommentReportForm
template_name = "core/edit.jinja"
def dispatch(self, request, *args, **kwargs):
self.uv_comment = get_object_or_404(UVComment, pk=kwargs["comment_id"])
return super(UVCommentReportCreateView, self).dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super(UVCommentReportCreateView, self).get_form_kwargs()
kwargs["reporter_id"] = self.request.user.id
kwargs["comment_id"] = self.uv_comment.id
return kwargs
def form_valid(self, form):
resp = super(UVCommentReportCreateView, self).form_valid(form)
# Send a message to moderation admins
for user in (
RealGroup.objects.filter(id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
.first()
.users.all()
):
if not user.notifications.filter(
type="PEDAGOGY_MODERATION", viewed=False
).exists():
Notification(
user=user,
url=reverse("pedagogy:moderation"),
type="PEDAGOGY_MODERATION",
).save()
return resp
def get_success_url(self):
return reverse_lazy(
"pedagogy:uv_detail", kwargs={"uv_id": self.uv_comment.uv.id}
)
class UVModerationFormView(FormView):
"""
Moderation interface (Privileged)
"""
form_class = UVCommentModerationForm
template_name = "pedagogy/moderation.jinja"
def dispatch(self, request, *args, **kwargs):
if not request.user.is_owner(UV()):
raise PermissionDenied
return super(UVModerationFormView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
form_clean = form.clean()
for report in form_clean.get("accepted_reports", []):
try:
report.comment.delete() # Delete the related comment
except ObjectDoesNotExist:
# To avoid errors when two reports points the same comment
pass
for report in form_clean.get("denied_reports", []):
try:
report.delete() # Delete the report itself
except ObjectDoesNotExist:
# To avoid errors when two reports points the same comment
pass
return super(UVModerationFormView, self).form_valid(form)
def get_success_url(self):
return reverse_lazy("pedagogy:moderation")
class UVCreateView(CanCreateMixin, CreateView):
"""
Add a new UV (Privileged)
"""
model = UV
form_class = UVForm
template_name = "pedagogy/uv_edit.jinja"
def get_form_kwargs(self):
kwargs = super(UVCreateView, self).get_form_kwargs()
kwargs["author_id"] = self.request.user.id
return kwargs
def get_success_url(self):
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.id})
class UVDeleteView(CanEditPropMixin, DeleteView):
"""
Allow to delete an UV (Privileged)
"""
model = UV
pk_url_kwarg = "uv_id"
template_name = "core/delete_confirm.jinja"
def get_success_url(self):
return reverse_lazy("pedagogy:guide")
class UVUpdateView(CanEditPropMixin, UpdateView):
"""
Allow to edit an UV (Privilegied)
"""
model = UV
form_class = UVForm
pk_url_kwarg = "uv_id"
template_name = "pedagogy/uv_edit.jinja"
def get_form_kwargs(self):
kwargs = super(UVUpdateView, self).get_form_kwargs()
obj = self.get_object()
kwargs["author_id"] = obj.author.id
return kwargs
def get_success_url(self):
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.id})