Initial commit - clean project structure
This commit is contained in:
92
affiliate/views.py
Normal file
92
affiliate/views.py
Normal file
@@ -0,0 +1,92 @@
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import AffiliateAccount, Conversion
|
||||
from .serializers import (
|
||||
AffiliateMeResponseSerializer,
|
||||
ConversionListResponseSerializer,
|
||||
TrackRequestSerializer,
|
||||
TrackResponseSerializer,
|
||||
)
|
||||
|
||||
|
||||
class AffiliateMeView(APIView):
|
||||
"""GET /api/affiliate/me — حساب و کد ارجاع کاربر"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@extend_schema(responses=AffiliateMeResponseSerializer, tags=['Affiliate (affiliate)'])
|
||||
def get(self, request):
|
||||
account, _ = AffiliateAccount.objects.get_or_create(user_id=request.user.id)
|
||||
|
||||
data = {'referralCode': account.referral_code, 'commissionRate': account.commission_rate}
|
||||
return Response(AffiliateMeResponseSerializer(data).data)
|
||||
|
||||
|
||||
class TrackConversionView(APIView):
|
||||
"""
|
||||
POST /api/affiliate/track — ثبت کلیک/ارجاع
|
||||
|
||||
طبق سند، این اپ فقط با referralCode به AffiliateAccount وصل میشه
|
||||
(نه توکن کاربر)، چون referredUserId خودش کاربر تازهارجاعشدهست که
|
||||
لزوماً صاحب حساب افیلیت نیست؛ پس اینجا permission پیشفرض (AllowAny)
|
||||
نگه داشته شده، دقیقاً مثل ValidateDiscountView در اپ discount.
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
request=TrackRequestSerializer, responses=TrackResponseSerializer, tags=['Affiliate (affiliate)']
|
||||
)
|
||||
def post(self, request):
|
||||
serializer = TrackRequestSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
v = serializer.validated_data
|
||||
|
||||
account = get_object_or_404(AffiliateAccount, referral_code=v['referralCode'])
|
||||
referred_user_id = int(v['referredUserId'])
|
||||
|
||||
# ⚠️ اصلاح امنیتی: قبلاً referredUserId بدون هیچ اعتبارسنجیای
|
||||
# مستقیم مصرف میشد؛ یعنی میشد برای یک کاربر ناموجود Conversion
|
||||
# ساخت یا با فرستادن userId خودِ صاحب حساب affiliate، به خودش
|
||||
# ارجاع داد (self-referral). حالا هر دو حالت رد میشن.
|
||||
from accounts.models import User as AccountUser
|
||||
|
||||
if not AccountUser.objects.filter(pk=referred_user_id).exists():
|
||||
raise ValidationError({'referredUserId': 'چنین کاربری وجود ندارد.'})
|
||||
|
||||
if referred_user_id == account.user_id:
|
||||
raise ValidationError({'referredUserId': 'امکان ثبت ارجاع برای خودِ صاحب کد وجود ندارد.'})
|
||||
|
||||
conversion, _ = Conversion.objects.get_or_create(
|
||||
referred_user_id=referred_user_id,
|
||||
defaults={'affiliate_account': account},
|
||||
)
|
||||
|
||||
data = {'success': True, 'conversionId': str(conversion.pk), 'status': conversion.status}
|
||||
return Response(TrackResponseSerializer(data).data)
|
||||
|
||||
|
||||
class ConversionsListView(APIView):
|
||||
"""GET /api/affiliate/conversions — لیست تبدیلها و کمیسیون"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@extend_schema(responses=ConversionListResponseSerializer, tags=['Affiliate (affiliate)'])
|
||||
def get(self, request):
|
||||
account = AffiliateAccount.objects.filter(user_id=request.user.id).first()
|
||||
conversions = account.conversions.all() if account else Conversion.objects.none()
|
||||
|
||||
items = [
|
||||
{
|
||||
'id': str(c.pk),
|
||||
'referredUserId': str(c.referred_user_id),
|
||||
'status': c.status,
|
||||
'commissionAmount': c.commission_amount,
|
||||
}
|
||||
for c in conversions
|
||||
]
|
||||
data = {'conversions': items}
|
||||
return Response(ConversionListResponseSerializer(data).data)
|
||||
Reference in New Issue
Block a user