models.py 3.86 KB
Newer Older
1 2
from typing import List

3
from django.contrib.auth.models import AbstractUser
4 5
from django.core.exceptions import ValidationError
from django.db import models
6
from django.utils.functional import cached_property
7 8 9 10 11 12 13 14 15 16 17 18 19
from rest_framework.response import Response

from backend_app.models.abstract.base import BaseModelSerializer
from backend_app.models.abstract.base import BaseModelViewSet
from backend_app.permissions.app_permissions import IsOwner, ReadOnly
from backend_app.utils import get_user_level, OBJ_MODERATION_PERMISSIONS


def validate(user, allow_sharing_personal_info):
    """
    Custom validation to ensure that moderators, DRI and staff can't be "anonymous" on the plateform
    """
    if (
20 21
        get_user_level(user) >= OBJ_MODERATION_PERMISSIONS["moderator"]
        and not allow_sharing_personal_info
22 23 24 25 26 27
    ):
        raise ValidationError(
            {
                "allow_sharing_personal_info": "Users that are moderators, members of DRI or staff, must allow sharing of their 'identity', sorry."
            }
        )
28 29 30 31 32 33 34 35 36


class User(AbstractUser):
    @cached_property
    def cached_groups(self) -> List[str]:
        out = ["authenticated_user"]
        for group in self.groups.all():
            out.append(group.name)
        return out
37 38 39 40 41 42

    allow_sharing_personal_info = models.BooleanField(default=True, null=False)
    secondary_email = models.EmailField(null=True, blank=True)
    pseudo = models.CharField(
        blank=False, null=False, max_length=12, default="Anonymous42"
    )
43 44 45
    has_validated_cgu = models.BooleanField(default=False, null=False)
    has_validated_rgpd = models.BooleanField(default=False, null=False)
    is_banned = models.BooleanField(default=False, null=False)
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

    def save(self, *args, **kwargs):
        """
        Custom save function to ensure consistency.
        """

        # if the object is not created yet, we can't check to what groups it belongs
        if self.pk is not None:
            validate(self, self.allow_sharing_personal_info)
        return super().save(*args, **kwargs)


class UserSerializer(BaseModelSerializer):
    def validate(self, attrs):
        """
        Also validate at the serializer level to prevent error 500
        """
        data = super().validate(attrs)
        aspi = data["allow_sharing_personal_info"]
        validate(self.get_user_from_request(), aspi)
        return data

    class Meta:
        model = User
        fields = BaseModelSerializer.Meta.fields + (
            "username",
            "first_name",
            "last_name",
            "email",
            "allow_sharing_personal_info",
            "secondary_email",
            "pseudo",
            "is_staff",
        )
80
        read_only_fields = ("username", "first_name", "last_name", "email")
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114


class UserViewset(BaseModelViewSet):
    def list(self, request, *args, **kwargs):
        # Prevent the querying of all objects.
        return Response(list())

    def retrieve(self, request, *args, **kwargs):
        # Custom behavior to return only the correct set of attributes depending
        # On allow_sharing_personal_info
        instance = self.get_object()
        serializer = self.get_serializer(instance)

        if instance == self.request.user or self.request.user.is_staff:
            out = serializer.data
        else:
            # serializer.data is a property we can't set it again, so we need a little trick for the output
            # First we copy all the values
            out = dict(serializer.data)
            # Then we "correct" them
            for key in [
                "username",
                "first_name",
                "last_name",
                "email",
                "secondary_email",
            ]:
                out[key] = None
        return Response(out)

    queryset = User.objects.all()
    permission_classes = (IsOwner | ReadOnly,)
    serializer_class = UserSerializer
    end_point_route = "users"