Remove the guest system entirely: no is_guest/device_id, no guest throttles, phone login is the only way in

accounts.0008 drops the columns and refuses to run while guest rows exist.
Docs describe the current state; tests that only proved guest behaviour are gone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 18:20:10 +03:30
parent 8835e01595
commit 663252a260
61 changed files with 357 additions and 1518 deletions

View File

@@ -15,42 +15,6 @@ from .serializers import (
)
class GuestAwareAffiliateThrottle(ScopedRateThrottle):
"""
همان الگویِ GuestAwareDiscountThrottle
و بقیه؛ چرخشِ حسابِ مهمان (deviceId جدید → pk جدید) یک ScopedRateThrottleِ
سادهٔ per-user رو دور می‌زد. اینجا حساس‌تره چون referralCode یک
شناسه‌ی حدس‌زدنی‌ست (404 برای کدِ نامعتبر = oracle) و یک حدسِ درست
یک Conversion واقعی می‌سازه که به کمیسیونِ مالیِ affiliate صاحبِ کد
منجر می‌شه؛ یعنی بدونِ این throttle، چرخشِ حساب مهمان به مهاجم
guessهای عملاً نامحدودی برای enumerate/fraud کردنِ کدهای رفرال
می‌داد. برای کاربرهای مهمان کلیدِ cache از pk به IP کلاینت تغییر
می‌کنه؛ رفتارِ throttle برای کاربرهای غیرمهمان (per-user، مثلِ
قبل) دست‌نخورده می‌مونه.
"""
def get_cache_key(self, request, view):
user = request.user
if user and user.is_authenticated and getattr(user, 'is_guest', False):
ident = f'guest-ip:{self.get_ident(request)}'
elif user and user.is_authenticated:
ident = user.pk
else:
ident = self.get_ident(request)
return self.cache_format % {'scope': self.scope, 'ident': ident}
def _reject_guest(user):
"""
مهمان نه کدِ معرف می‌گیرد نه معرفی‌شده حساب می‌شود: حسابِ مهمان با هر
deviceId تازه ساخته می‌شود، پس شمردنش فقط آمار را باد می‌کرد. بعد از ورود
با شماره، همان کاربر (با همان پیشرفت) می‌تواند کد را ثبت کند.
"""
if getattr(user, 'is_guest', False):
raise PermissionDenied('برنامه‌ی معرفی بعد از ورود با شماره‌ی موبایل فعال می‌شود.')
class AffiliateMeView(APIView):
"""GET /api/affiliate/me — حساب و کد ارجاع کاربر"""
@@ -58,7 +22,6 @@ class AffiliateMeView(APIView):
@extend_schema(responses=AffiliateMeResponseSerializer, tags=['Affiliate (affiliate)'])
def get(self, request):
_reject_guest(request.user)
account, _ = AffiliateAccount.objects.get_or_create(user_id=request.user.id)
paid = account.conversions.filter(status='paid')
data = {
@@ -88,10 +51,9 @@ class TrackConversionView(APIView):
permission_classes = [IsAuthenticated]
# referralCode نامعتبر ۴۰۴ می‌گیره (یک oracle قابل‌probe)، پس throttle
# مجزا هم probe رو کند می‌کنه هم (با GuestAwareAffiliateThrottle) جلویِ
# bucket تازه از چرخشِ حساب مهمان رو می‌گیره.
# مجزا probe رو کند می‌کنه.
throttle_scope = 'affiliate_track'
throttle_classes = [GuestAwareAffiliateThrottle]
throttle_classes = [ScopedRateThrottle]
@extend_schema(
request=TrackRequestSerializer, responses=TrackResponseSerializer, tags=['Affiliate (affiliate)']
@@ -100,7 +62,6 @@ class TrackConversionView(APIView):
serializer = TrackRequestSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
v = serializer.validated_data
_reject_guest(request.user)
account = get_object_or_404(AffiliateAccount, referral_code=v['referralCode'])
referred_user_id = request.user.id