from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.permissions import BasePermission
from django_filters import rest_framework as filters
from backend_app.models.abstract.essentialModule import (
EssentialModule,
EssentialModuleSerializer,
EssentialModuleViewSet,
)
from backend_app.models.exchange import Exchange
from backend_app.models.university import University
from backend_app.permissions.app_permissions import ReadOnly, IsStaff, NoDelete, NoPost
from backend_app.permissions.moderation import ModerationLevels
from backend_app.serializers import ExchangeSerializer
from backend_app.utils import CustomPagination
class ExchangeFeedback(EssentialModule):
moderation_level = ModerationLevels.DEPENDING_ON_SITE_SETTINGS
exchange = models.OneToOneField(
Exchange,
on_delete=models.CASCADE,
related_name="feedbacks",
primary_key=True,
null=False,
default=0,
)
general_comment = models.TextField(null=True, max_length=1500)
academical_level_appreciation = models.IntegerField(
default=0, validators=[MinValueValidator(-5), MaxValueValidator(5)]
)
foreign_student_welcome = models.IntegerField(
default=0, validators=[MinValueValidator(-5), MaxValueValidator(5)]
)
cultural_interest = models.IntegerField(
default=0, validators=[MinValueValidator(-5), MaxValueValidator(5)]
)
# A bit of denormalization (managed by signals)
university = models.ForeignKey(University, on_delete=models.PROTECT, null=True)
# Field to tell that the instance hasn't been edited as of now
untouched = models.BooleanField(default=True, null=False)
class ExchangeFeedbackSerializer(EssentialModuleSerializer):
check_obj_permissions_for_edit = True
exchange = ExchangeSerializer(read_only=True)
def update(self, instance, validated_data):
instance.untouched = False
return super().update(instance, validated_data)
class Meta:
model = ExchangeFeedback
fields = EssentialModuleSerializer.Meta.fields + (
"university",
"exchange",
"general_comment",
"academical_level_appreciation",
"foreign_student_welcome",
"cultural_interest",
"untouched",
)
read_only_fields = ("university", "exchange", "untouched")
class ExchangePermission(BasePermission):
"""
Permission that checks that the requester is the student concern by the exchange.
"""
def has_object_permission(self, request, view, obj):
exchange = obj.exchange
if exchange.student is None:
return False
return request.user.pk == obj.exchange.student.pk
class CharInFilter(filters.BaseInFilter, filters.CharFilter):
pass
class ExchangeFeedbackFilter(filters.FilterSet):
exchange__student_major_in = CharInFilter(
field_name="exchange__student_major", lookup_expr="in"
)
exchange__student_minor_in = CharInFilter(
field_name="exchange__student_minor", lookup_expr="in"
)
class Meta:
model = ExchangeFeedback
fields = ["exchange__student_major_in", "exchange__student_minor_in"]
class ExchangeFeedbackFilterBackend(DjangoFilterBackend):
filterset_base = ExchangeFeedbackFilter
class ExchangeFeedbackViewSet(EssentialModuleViewSet):
permission_classes = (
NoDelete & NoPost & (ReadOnly | IsStaff | ExchangePermission),
)
queryset = (
ExchangeFeedback.objects.filter(
exchange__unlinked=False
) # only display linked instances
.order_by("-exchange__year", "exchange__semester", "exchange_id")
.select_related("exchange", "updated_by", "moderated_by", "exchange__student")
.prefetch_related(
"exchange__exchange_courses",
"exchange__exchange_courses__course_feedback",
"exchange__exchange_courses__course_feedback__updated_by",
"exchange__exchange_courses__course_feedback__moderated_by",
)
)
serializer_class = ExchangeFeedbackSerializer
end_point_route = "exchangeFeedbacks"
filterset_fields = ("university", "untouched")
filter_backends = (filters.DjangoFilterBackend, ExchangeFeedbackFilterBackend)
required_filterset_fields = ("university",)
pagination_class = CustomPagination
|