import re from django.utils import timezone from django.contrib.auth.hashers import make_password from rest_framework import serializers from accounts.models import ( AppVersion, IAmPrincipal, IAmPrincipalExtendedData, IAmPrincipalType, # IAmPrincipalKYCDetails, ) from manage_events.models import EventInteractionType, EventPrincipalInteraction, FreeUsageFeatureLimit, PrincipalPreference from manage_referrals.models import ( ReferralCode, ReferralRecord, ) from goodtimes import constants, date_utils from manage_subscriptions.models import PrincipalSubscription, SubscriptionStatus def clean_phone(number: str): """Validates number starts with +91 or 0, then 10 digits""" number_pattern = re.compile(r"^(?:\+91|0)\d{10}$") result = number_pattern.match(number) if not result: raise serializers.ValidationError({"phone_no": constants.PHONE_NUMBER_INVALID}) if number.startswith("0"): return "+91" + number[1:] return number # class PhoneSerializer(serializers.Serializer): # phone_no = serializers.CharField(max_length=15, required=True) # def validate(self, attrs): # phone_no = attrs.get("phone_no") # cleaned_number = clean_phone(phone_no) # attrs["phone_no"] = cleaned_number # return super().validate(attrs) class EmailSerializer(serializers.Serializer): email = serializers.EmailField( required=True, ) principal_type = serializers.CharField(required=True, write_only=True) def validate_principal_type_name(self, value): """ Check that the principal_type_name corresponds to a valid IAmPrincipalType. """ if not IAmPrincipalType.objects.filter(name=value).exists(): raise serializers.ValidationError("Invalid principal type name.") return value class BasePasswordSerializer(serializers.Serializer): confirm_password = serializers.CharField(max_length=20, write_only=True) def validate(self, attrs): password = attrs.get("password") confirm_password = attrs.pop("confirm_password", None) if password != confirm_password: raise serializers.ValidationError( {"confirm_password": "Password do not match"} ) return super().validate(attrs) def update(self, instance, validated_data): new_password = validated_data.get("password") if new_password: instance.password = make_password(new_password) # instance.set_password(new_password) instance.save() return instance class RegistrationSerializer(BasePasswordSerializer, serializers.ModelSerializer): # email = serializers.EmailField( # required=True, # ) class Meta: model = IAmPrincipal fields = ["first_name", "last_name", "email", "password", "confirm_password"] extra_kwargs = { "first_name": {"required": True}, "last_name": {"required": True}, "email": {"required": True}, } # def validate(self, attrs): # email = attrs.get("email") # # Check if the email is already associated with any user # user_with_email = IAmPrincipal.objects.filter(email=email).first() # if user_with_email: # raise serializers.ValidationError({"email": [constants.EMAIL_EXISTS]}) # # # Check if the user has a different phone number # # if user_with_email.phone_no != phone_no: # # raise serializers.ValidationError({"email": [constants.EMAIL_EXISTS]}) # return attrs def update(self, instance, validated_data): # update prinicpal instance fiedls based on the validation data instance.first_name = validated_data.get("first_name", instance.first_name) instance.last_name = validated_data.get("last_name", instance.last_name) instance.email = validated_data.get("email", instance.email) instance.username = validated_data.get("email", instance.email) # Set the new password (if provided) correctly using set_password method if "password" in validated_data: new_password = validated_data["password"] print("new_password serializers: ", new_password) instance.set_password( new_password ) # Correctly use set_password without assignment instance.save() return instance class RegistrationPasswordSerializer( BasePasswordSerializer, serializers.ModelSerializer ): class Meta: model = IAmPrincipal fields = ["email", "password", "confirm_password"] class PasswordResetSerializer(BasePasswordSerializer, serializers.ModelSerializer): class Meta: model = IAmPrincipal fields = ["password", "confirm_password"] from phonenumbers import parse, phonenumberutil, NumberParseException class ProfileSerializer(serializers.ModelSerializer): profile_photo = serializers.ImageField(required=False) principal_type_name = serializers.SerializerMethodField(read_only=True) email = serializers.CharField(read_only=True) is_active = serializers.BooleanField(read_only=True) phone_no = serializers.CharField(required=True) class Meta: model = IAmPrincipal fields = [ "principal_type", "principal_type_name", "profile_photo", "player_id", "first_name", "last_name", 'business_name', "phone_no", "email", "linkedin_profile", "youtube_profile", "facebook_profile", "instagram_profile", "twitter_profile", "website", "is_active", ] # def validate_phone_no(self, value): # try: # # Parse the phone number # phone_number = parse(value) # # Check for validity # if not phonenumberutil.is_valid_number(phone_number): # raise serializers.ValidationError('Please enter a valid phone number.') # return value # except NumberParseException: # raise serializers.ValidationError('The phone number format is invalid.') def update(self, instance, validated_data): instance.profile_photo = validated_data.get( "profile_photo", instance.profile_photo ) instance.first_name = validated_data.get("first_name", instance.first_name) instance.last_name = validated_data.get("last_name", instance.last_name) return super().update(instance, validated_data) def get_image_url(self, obj, field_name, request): image_field = getattr(obj, field_name) if image_field: return request.build_absolute_uri(image_field.url) return "" def get_principal_type_name(self, obj): return obj.principal_type.name if obj.principal_type else None def to_representation(self, instance): data = super().to_representation(instance) request = self.context.get("request") data["profile_photo"] = self.get_image_url(instance, "profile_photo", request) return data class ProfileExtendedDataSerializer(serializers.ModelSerializer): invite_count = serializers.SerializerMethodField(read_only=True) principal_type_name = serializers.SerializerMethodField(read_only=True) has_active_subscription = serializers.SerializerMethodField(read_only=True) preference = serializers.SerializerMethodField(read_only=True) principal_preference_count = serializers.SerializerMethodField(read_only=True) going_events_count = serializers.SerializerMethodField(read_only=True) interested_events_count = serializers.SerializerMethodField(read_only=True) feature_limit = serializers.SerializerMethodField(read_only=True) class Meta: model = IAmPrincipal fields = [ "principal_type_name", "invite_count", "register_complete", "has_active_subscription", "preference", "principal_preference_count", "going_events_count", "interested_events_count", "feature_limit" ] def get_going_events_count(self, obj): return EventPrincipalInteraction.objects.filter( principal=obj, status=EventInteractionType.GOING ).count() def get_interested_events_count(self, obj): return EventPrincipalInteraction.objects.filter( principal=obj, status=EventInteractionType.INTERESTED ).count() def get_invite_count(self, obj): if obj: return ReferralRecord.get_invite_count(obj) return 0 def get_principal_type_name(self, obj): return obj.principal_type.name if obj.principal_type else None def get_preference(self, obj): return PrincipalPreference.objects.filter(principal=obj).exists() def get_principal_preference_count(self, obj): principal_preference = PrincipalPreference.objects.filter(principal=obj).first() if principal_preference: categories = principal_preference.preferred_categories.all() return categories.count() return 0 def get_has_active_subscription(self, obj): subscription_status = { "has_active_subscription": False, "in_grace_period": False, "grace_period_end_date": None, "subscription_id": None, } today = timezone.now().date() # Attempt to find the active subscription with the furthest grace_period_end_date latest_subscription = PrincipalSubscription.get_principal_subscription(obj) print(f"subscrition record {latest_subscription}") if latest_subscription: subscription_status["subscription_id"] = ( latest_subscription.stripe_subscription_id ) # Check if we're within the grace period if today <= latest_subscription.grace_period_end_date: subscription_status["has_active_subscription"] = ( today <= latest_subscription.end_date ) subscription_status["in_grace_period"] = ( latest_subscription.end_date < today <= latest_subscription.grace_period_end_date ) subscription_status["grace_period_end_date"] = ( latest_subscription.grace_period_end_date ) return subscription_status def get_feature_limit(self, obj): from manage_events.api.serializers import FreeUsageFeatureLimitSerializer obj = FreeUsageFeatureLimit.objects.first() return FreeUsageFeatureLimitSerializer().to_representation(obj) # class PrincipalKYCDetailsSerializer(serializers.ModelSerializer): # aadhar_front_image = serializers.ImageField(required=False) # aadhar_back_image = serializers.ImageField(required=False) # pan_image = serializers.ImageField(required=False) # class Meta: # model = IAmPrincipalKYCDetails # fields = [ # "aadhar_front_image", # "aadhar_back_image", # "aadhar_number", # "is_aadhar_verified", # "pan_image", # "pan_number", # "is_pan_verified", # "account_no", # "bank_name", # "branch_name", # "ifsc_code", # ] # def create(self, validated_data): # # Extract and set the principal (user) from the request context # validated_data["principal"] = self.context.get("request").user # return super(PrincipalKYCDetailsSerializer, self).create(validated_data) # def get_image_url(self, obj, field_name, request): # image_field = getattr(obj, field_name) # if image_field: # return request.build_absolute_uri(image_field.url) # return "" # def to_representation(self, instance): # data = super().to_representation(instance) # request = self.context.get("request") # if request: # data["aadhar_front_image"] = self.get_image_url( # instance, "aadhar_front_image", request # ) # data["aadhar_back_image"] = self.get_image_url( # instance, "aadhar_back_image", request # ) # data["pan_image"] = self.get_image_url(instance, "pan_image", request) # return data class ReferralCodeSerializer(serializers.ModelSerializer): class Meta: model = ReferralCode fields = ["referral_code"] class ReferralRecordSerializer(serializers.ModelSerializer): name = serializers.SerializerMethodField() join_at = serializers.SerializerMethodField() class Meta: model = ReferralRecord fields = ["name", "join_at"] def get_name(self, obj): # Check if the referred_principal is set (not None) and get the full name if obj.referred_principal: return obj.referred_principal.get_full_name() return None def get_join_at(self, obj): return date_utils.format_date_to_string(obj.created_on) # added 's' to differentiate with Email Serializer class EmailSerializers(serializers.Serializer): email = serializers.EmailField(required=True) # otp = serializers.CharField(required=True) class ProfilePhotoSerializer(serializers.ModelSerializer): class Meta: model = IAmPrincipal fields = ("email", "profile_photo", "first_name") class PlayerIDSerializer(serializers.Serializer): player_id = serializers.CharField(max_length=255) class AppVersionSerializer(serializers.ModelSerializer): class Meta: model = AppVersion fields = [ "app_type", "version", "force_upgrade", "recommend_upgrade", ] class IAmPrincipalExtendedDataSerializer(serializers.ModelSerializer): class Meta: model = IAmPrincipalExtendedData fields = "__all__"