Louis Mazin 4db822aebe big maj
2026-10-05 17:52:28 +02:00

136 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError as DjangoValidationError
from django.db import transaction
from django.utils import timezone
from rest_framework import serializers
from .models import Invitation
from .permissions import default_permissions, effective_permissions, management_permissions
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
is_admin = serializers.SerializerMethodField()
permissions = serializers.SerializerMethodField()
management_permissions = serializers.SerializerMethodField()
color = serializers.RegexField(r'^#[0-9a-fA-F]{6}$', required=False)
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'is_staff',
'is_superuser',
'is_admin',
'permissions',
'management_permissions',
'date_joined',
'color',
]
read_only_fields = ['id', 'date_joined', 'is_admin']
def get_is_admin(self, obj):
return obj.is_superuser or obj.is_staff
def get_permissions(self, obj):
if not hasattr(self, '_permission_defaults'):
self._permission_defaults = default_permissions()
return effective_permissions(obj, self._permission_defaults)
def get_management_permissions(self, obj):
return management_permissions(obj)
def validate(self, attrs):
actor = self.context['request'].user
if not actor.is_superuser:
if self.instance.is_superuser:
raise serializers.ValidationError('Seul un superutilisateur peut modifier ce compte.')
if attrs.get('is_superuser', False):
raise serializers.ValidationError({'is_superuser': 'Seul un superutilisateur peut accorder ce rôle.'})
if self.instance.pk == actor.pk:
if not attrs.get('is_active', self.instance.is_active):
raise serializers.ValidationError({'is_active': 'Vous ne pouvez pas désactiver votre propre compte.'})
if not (attrs.get('is_staff', self.instance.is_staff) or attrs.get('is_superuser', self.instance.is_superuser)):
raise serializers.ValidationError('Vous ne pouvez pas retirer votre propre accès administrateur.')
return attrs
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
password_confirm = serializers.CharField(write_only=True)
invite = serializers.UUIDField(write_only=True)
class Meta:
model = User
fields = [
'username',
'password',
'password_confirm',
'first_name',
'last_name',
'invite',
]
def validate(self, attrs):
if attrs['password'] != attrs['password_confirm']:
raise serializers.ValidationError({
'password_confirm': (
'Les mots de passe ne correspondent pas.'
)
})
candidate = User(**{field: attrs.get(field, '') for field in ('username', 'first_name', 'last_name')})
try:
validate_password(attrs['password'], candidate)
except DjangoValidationError as error:
raise serializers.ValidationError({'password': error.messages}) from error
return attrs
def validate_invite(self, value):
try:
invitation = Invitation.objects.get(token=value)
except Invitation.DoesNotExist as error:
raise serializers.ValidationError(
'Ce lien d’invitation est invalide.'
) from error
if not invitation.is_valid:
raise serializers.ValidationError(
'Ce lien d’invitation est expiré ou déjà utilisé.'
)
return value
def create(self, validated_data):
invitation_token = validated_data.pop('invite')
validated_data.pop('password_confirm')
with transaction.atomic():
invitation = (
Invitation.objects
.select_for_update()
.get(token=invitation_token)
)
if not invitation.is_valid:
raise serializers.ValidationError({
'invite': (
'Ce lien d’invitation est expiré ou déjà utilisé.'
)
})
user = User.objects.create_user(**validated_data)
invitation.used_at = timezone.now()
invitation.save(update_fields=['used_at'])
return user