from django.conf import settings from django.db.models import Q from djoser import serializers as djoser_serializers from djoser.conf import settings as djoser_settings from rest_framework import serializers from rest_framework.exceptions import AuthenticationFailed from .models import User, BonusProgramTransaction, BonusType from .utils import verify_telegram_authentication class UserSerializer(serializers.ModelSerializer): name = serializers.CharField(source='first_name') lastname = serializers.CharField(source='middle_name') surname = serializers.CharField(source='last_name') class Meta: model = User fields = ('id', 'email', 'phone', 'role', 'name', 'lastname', 'surname', 'balance', 'referral_code', 'is_draft_user') class BonusProgramTransactionSerializer(serializers.ModelSerializer): type = serializers.CharField(source='get_type_display') class Meta: model = BonusProgramTransaction fields = ('id', 'type', 'date', 'amount', 'comment', 'was_cancelled') def non_zero_validator(value): if value == 0: raise serializers.ValidationError("Value cannot be zero") return value class UserBalanceUpdateSerializer(BonusProgramTransactionSerializer): amount = serializers.IntegerField(validators=[non_zero_validator]) type = serializers.SerializerMethodField() class Meta: model = BonusProgramTransactionSerializer.Meta.model fields = BonusProgramTransactionSerializer.Meta.fields read_only_fields = ('id', 'type', 'date') def get_type(self, instance): # Deposit or spent depending on value if instance['amount'] < 0: return BonusType.OTHER_WITHDRAWAL elif instance['amount'] > 0: return BonusType.OTHER_DEPOSIT class SetInitialPasswordSerializer(djoser_serializers.PasswordSerializer): def validate(self, attrs): user = getattr(self, "user", None) or self.context["request"].user # why assert? There are ValidationError / fail everywhere assert user is not None if not user.is_superuser and not user.is_draft_user: raise serializers.ValidationError("To change password, use /users/change_password endpoint") return super().validate(attrs) class UserCreateSerializer(djoser_serializers.UserCreateSerializer): email = serializers.EmailField(required=True) class TokenCreateSerializer(serializers.Serializer): email_or_phone = serializers.CharField() password = serializers.CharField(required=False, style={"input_type": "password"}) default_error_messages = { "invalid_credentials": djoser_settings.CONSTANTS.messages.INVALID_CREDENTIALS_ERROR, "inactive_account": djoser_settings.CONSTANTS.messages.INACTIVE_ACCOUNT_ERROR, } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.user = None def validate(self, attrs): email_or_phone = attrs.get('email_or_phone') password = attrs.get("password") user = User.objects.filter(Q(email=email_or_phone) | Q(phone=email_or_phone)).first() if not user or not user.check_password(password) or not user.is_active: raise AuthenticationFailed() self.user = user return attrs class TelegramCallbackSerializer(serializers.Serializer): id = serializers.IntegerField() first_name = serializers.CharField(allow_null=True) username = serializers.CharField(allow_null=True) photo_url = serializers.URLField(allow_null=True) auth_date = serializers.IntegerField() hash = serializers.CharField() def validate(self, attrs): verify_telegram_authentication(bot_token=settings.TG_BOT_TOKEN, request_data=attrs) return attrs