210 lines
7.8 KiB
Python
210 lines
7.8 KiB
Python
import re
|
|
from django.utils.text import slugify
|
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
|
from rest_framework import serializers
|
|
from rest_framework.exceptions import NotFound
|
|
from django.contrib.auth import get_user_model
|
|
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.utils.text import slugify
|
|
|
|
from .permissions import *
|
|
|
|
|
|
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
|
from rest_framework.exceptions import PermissionDenied
|
|
|
|
|
|
User = get_user_model()
|
|
|
|
class CustomUserSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
"id",
|
|
"username",
|
|
"first_name",
|
|
"last_name",
|
|
"email",
|
|
"role",
|
|
"account_type",
|
|
"email_verified",
|
|
"phone_number",
|
|
"create_time",
|
|
"var_symbol",
|
|
"bank_account",
|
|
"ICO",
|
|
"RC",
|
|
"city",
|
|
"street",
|
|
"PSC",
|
|
"GDPR",
|
|
"is_active",
|
|
]
|
|
read_only_fields = ["id", "create_time", "GDPR", "username"] # <-- removed "account_type"
|
|
|
|
def update(self, instance, validated_data):
|
|
user = self.context["request"].user
|
|
staff_only_fields = ["role", "email_verified", "var_symbol", "is_active"]
|
|
|
|
if user.role not in ["admin", "cityClerk"]:
|
|
unauthorized = [f for f in staff_only_fields if f in validated_data]
|
|
if unauthorized:
|
|
raise PermissionDenied(f"You are not allowed to modify: {', '.join(unauthorized)}")
|
|
|
|
return super().update(instance, validated_data)
|
|
|
|
|
|
|
|
|
|
# Token obtaining Default Serializer
|
|
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
|
|
username_field = User.USERNAME_FIELD
|
|
|
|
def validate(self, attrs):
|
|
login = attrs.get("username")
|
|
password = attrs.get("password")
|
|
|
|
# Allow login by username or email
|
|
user = User.objects.filter(email__iexact=login).first() or \
|
|
User.objects.filter(username__iexact=login).first()
|
|
|
|
if user is None or not user.check_password(password):
|
|
raise serializers.ValidationError(_("No active account found with the given credentials"))
|
|
|
|
# Call the parent validation to create token
|
|
data = super().validate({
|
|
self.username_field: user.username,
|
|
"password": password
|
|
})
|
|
|
|
data["user_id"] = user.id
|
|
data["username"] = user.username
|
|
data["email"] = user.email
|
|
return data
|
|
|
|
|
|
# user creating section start ------------------------------------------
|
|
class UserRegistrationSerializer(serializers.ModelSerializer):
|
|
password = serializers.CharField(
|
|
write_only=True,
|
|
help_text="Heslo musí mít alespoň 8 znaků, obsahovat velká a malá písmena a číslici."
|
|
)
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
'first_name', 'last_name', 'email', 'phone_number', 'password',
|
|
'city', 'street', 'postal_code', 'gdpr'
|
|
]
|
|
extra_kwargs = {
|
|
'first_name': {'required': True, 'help_text': 'Křestní jméno uživatele'},
|
|
'last_name': {'required': True, 'help_text': 'Příjmení uživatele'},
|
|
'email': {'required': True, 'help_text': 'Emailová adresa uživatele'},
|
|
'phone_number': {'required': True, 'help_text': 'Telefonní číslo uživatele'},
|
|
'city': {'required': True, 'help_text': 'Město uživatele'},
|
|
'street': {'required': True, 'help_text': 'Ulice uživatele'},
|
|
'postal_code': {'required': True, 'help_text': 'PSČ uživatele'},
|
|
'gdpr': {'required': True, 'help_text': 'Souhlas se zpracováním osobních údajů'},
|
|
}
|
|
|
|
def validate_password(self, value):
|
|
if len(value) < 8:
|
|
raise serializers.ValidationError("Password must be at least 8 characters long.")
|
|
if not re.search(r"[A-Z]", value):
|
|
raise serializers.ValidationError("Password must contain at least one uppercase letter.")
|
|
if not re.search(r"[a-z]", value):
|
|
raise serializers.ValidationError("Password must contain at least one lowercase letter.")
|
|
if not re.search(r"\d", value):
|
|
raise serializers.ValidationError("Password must contain at least one digit.")
|
|
return value
|
|
|
|
def validate(self, data):
|
|
email = data.get("email")
|
|
phone = data.get("phone_number")
|
|
dgpr = data.get("GDPR")
|
|
if not dgpr:
|
|
raise serializers.ValidationError({"GDPR": "You must agree to the GDPR to register."})
|
|
|
|
if User.objects.filter(email=email).exists():
|
|
raise serializers.ValidationError({"email": "Account with this email already exists."})
|
|
|
|
if phone and User.objects.filter(phone_number=phone).exists():
|
|
raise serializers.ValidationError({"phone_number": "Account with this phone number already exists."})
|
|
|
|
return data
|
|
|
|
def create(self, validated_data):
|
|
password = validated_data.pop("password")
|
|
username = validated_data.get("username", "")
|
|
user = User.objects.create(
|
|
username=username,
|
|
is_active=False, #uživatel je defaultně deaktivovaný
|
|
**validated_data
|
|
)
|
|
user.set_password(password)
|
|
user.save()
|
|
|
|
return user
|
|
|
|
class UserActivationSerializer(serializers.Serializer):
|
|
user_id = serializers.IntegerField()
|
|
var_symbol = serializers.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(9999999999)])
|
|
|
|
def save(self, **kwargs):
|
|
try:
|
|
user = User.objects.get(pk=self.validated_data['user_id'])
|
|
except User.DoesNotExist:
|
|
raise NotFound("User with this ID does not exist.")
|
|
user.var_symbol = self.validated_data['var_symbol']
|
|
user.is_active = True
|
|
user.save()
|
|
return user
|
|
|
|
def to_representation(self, instance):
|
|
return {
|
|
"id": instance.id,
|
|
"email": instance.email,
|
|
"var_symbol": instance.var_symbol,
|
|
"is_active": instance.is_active,
|
|
}
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
'user_id', 'var_symbol'
|
|
]
|
|
extra_kwargs = {
|
|
'user_id': {'required': True, 'help_text': 'ID uživatele'},
|
|
'var_symbol': {'required': True, 'help_text': 'Variablní symbol, zadán úředníkem'},
|
|
}
|
|
# user creating section end --------------------------------------------
|
|
|
|
|
|
class PasswordResetRequestSerializer(serializers.Serializer):
|
|
email = serializers.EmailField(
|
|
help_text="E-mail registrovaného a aktivního uživatele, na který bude zaslán reset hesla."
|
|
)
|
|
|
|
def validate_email(self, value):
|
|
if not User.objects.filter(email=value, is_active=True).exists():
|
|
raise serializers.ValidationError("Účet s tímto emailem neexistuje nebo není aktivní.")
|
|
return value
|
|
|
|
class PasswordResetConfirmSerializer(serializers.Serializer):
|
|
password = serializers.CharField(
|
|
write_only=True,
|
|
help_text="Nové heslo musí mít alespoň 8 znaků, obsahovat velká a malá písmena a číslici."
|
|
)
|
|
|
|
def validate_password(self, value):
|
|
import re
|
|
if len(value) < 8:
|
|
raise serializers.ValidationError("Heslo musí mít alespoň 8 znaků.")
|
|
if not re.search(r"[A-Z]", value):
|
|
raise serializers.ValidationError("Musí obsahovat velké písmeno.")
|
|
if not re.search(r"[a-z]", value):
|
|
raise serializers.ValidationError("Musí obsahovat malé písmeno.")
|
|
if not re.search(r"\d", value):
|
|
raise serializers.ValidationError("Musí obsahovat číslici.")
|
|
return value |