Files
goodtimes/accounts/api/serializers.py

399 lines
14 KiB
Python

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__"