from django.contrib.auth import get_user_model from django.db import transaction from django.utils import timezone from rest_framework import serializers from .models import Invitation User = get_user_model() class UserSerializer(serializers.ModelSerializer): is_admin = serializers.SerializerMethodField() class Meta: model = User fields = [ 'id', 'username', 'first_name', 'last_name', 'email', 'is_active', 'is_staff', 'is_superuser', 'is_admin', '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 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.' ) }) 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