from django.db import models
from django.db.models import Q
from rest_framework import serializers
from backend_app.fields import JSONField
from backend_app.models.abstract.base import (
BaseModel,
BaseModelSerializer,
BaseModelViewSet,
)
from backend_app.models.university import University
from backend_app.permissions.app_permissions import IsOwner, ReadOnly, IsPublic
from backend_app.permissions.moderation import ModerationLevels
from backend_app.validation.validators import (
RecommendationListJsonContentValidator,
RecommendationListUnivValidator,
)
from base_app.models import User
json_content_validator = RecommendationListJsonContentValidator()
univ_content_validator = RecommendationListUnivValidator()
class RecommendationList(BaseModel):
moderation_level = ModerationLevels.NO_MODERATION
last_update = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=100)
owner = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="user_recommendation_list"
)
is_public = models.BooleanField(default=False)
followers = models.ManyToManyField(
User, related_name="followed_recommendation_list"
)
description = models.CharField(max_length=300, default="")
content = JSONField(
default=list, validators=[json_content_validator, univ_content_validator]
)
universities = models.ManyToManyField(University)
def save(self, *args, **kwargs):
"""
Custom save function to ensure consistency.
Won't be active on first create
"""
# Will crash if pk is None
if self.pk is not None:
self.universities.clear()
univ_ids_in_list = RecommendationListUnivValidator.get_universities_ids_from_content(
self.content
)
for univ in University.objects.all():
if univ.pk in univ_ids_in_list:
self.universities.add(univ)
return super().save(*args, **kwargs)
class RecommendationListSerializer(BaseModelSerializer):
last_update = serializers.DateTimeField(read_only=True)
universities = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
is_user_owner = serializers.SerializerMethodField()
is_user_follower = serializers.SerializerMethodField()
nb_followers = serializers.SerializerMethodField()
owner_pseudo = serializers.SerializerMethodField()
def get_is_user_owner(self, obj):
return self.get_user_from_request().pk == obj.owner.pk
def get_is_user_follower(self, obj):
if obj.pk is None:
return False
else:
return obj.followers.filter(pk=self.get_user_from_request().pk).exists()
def get_nb_followers(self, obj):
if obj.is_public:
return obj.followers.count()
else:
return 0
def get_owner_pseudo(self, obj):
return obj.owner.pseudo
def create(self, validated_data):
# make sure we cannot create list for others
validated_data["owner"] = self.get_user_from_request()
return super().create(validated_data)
class Meta:
model = RecommendationList
fields = BaseModelSerializer.Meta.fields + (
"title",
"owner",
"is_public",
"nb_followers",
"description",
"content",
"is_user_owner",
"is_user_follower",
"universities",
"last_update",
"owner_pseudo",
)
class RecommendationListSerializerShort(RecommendationListSerializer):
class Meta:
model = RecommendationList
fields = BaseModelSerializer.Meta.fields + (
"title",
"owner",
"is_public",
"nb_followers",
"is_user_owner",
"description",
"last_update",
"owner_pseudo",
)
class RecommendationListViewSet(BaseModelViewSet):
serializer_class = RecommendationListSerializer
end_point_route = "recommendationLists"
permission_classes = (IsOwner | (IsPublic & ReadOnly),)
def get_serializer_class(self):
if "action" in self.__dict__ and self.action == "list":
return RecommendationListSerializerShort
else:
return RecommendationListSerializer
def get_queryset(self): # this functions allows to get the user's lists
owned = Q(owner=self.request.user)
followed = Q(followers__in=[self.request.user], is_public=True)
query = owned | followed
if "action" in self.__dict__ and self.action != "list":
is_public = Q(is_public=True)
query = query | is_public
return RecommendationList.objects.filter(query).prefetch_related(
"owner", "universities"
)
|