cleanup: trim bloated multi-line comments across the project

This commit is contained in:
2026-08-26 03:22:20 +03:30
parent 83435c5a5f
commit 683bd40169
27 changed files with 235 additions and 699 deletions

View File

@@ -27,18 +27,11 @@ def apply_offer(*, user_id: int, offer: Offer, source: str) -> UserOffer | None:
if not offer.is_active:
return None
# ⚠️ اصلاح: قبلاً هر IntegrityError داخل کل بلوکِ atomic (که شاملِ
# grant_free_subscription هم می‌شد) به‌عنوان «duplicate UserOffer»
# تفسیر می‌شد و None برمی‌گردوند — یعنی اگه یک IntegrityError واقعیِ
# دیگه (مثلاً داخل grant_free_subscription) اتفاق می‌افتاد، خطا قورت
# داده می‌شد و caller فکر می‌کرد «کاربر قبلاً این آفر رو گرفته»، در
# حالی که اصلاً چنین چیزی نبود. حالا فقط IntegrityError ناشی از
# UniqueConstraintِ خودِ UserOffer.create (duplicate واقعی) گرفته
# می‌شه — با یک savepoint جداگانه (atomic تودرتو) که فقط همون create
# رو rollback می‌کنه، نه کل تراکنش رو — و خطاهای دیگه (مثلاً از داخل
# grant_free_subscription) عادی propagate می‌شن. atomic بودنِ کلِ
# عملیات (UserOffer + Subscription + expires_at) هم دست‌نخورده باقی
# مونده، دقیقاً طبق همون دلیلی که در docstring بالا توضیح داده شده.
# فقط IntegrityErrorِ ناشیِ از UniqueConstraintِ خودِ UserOffer.create
# (duplicate واقعی) اینجا گرفته می‌شه، با یک savepoint مجزا که فقط
# همون create رو rollback می‌کنه — وگرنه یک IntegrityErrorِ دیگه (مثلاً
# داخلِ grant_free_subscription) قورت داده می‌شد و caller اشتباهاً فکر
# می‌کرد کاربر قبلاً این آفر رو گرفته.
with transaction.atomic():
try:
with transaction.atomic(): # savepoint مجزا فقط برای create

View File

@@ -102,12 +102,7 @@ class RedeemOfferCodeThrottleTests(TestCase):
self.assertEqual(blocked_response.status_code, 429)
def test_throttle_is_scoped_per_user_not_shared_globally(self):
# ⚠️ توجه: از یک کاربرِ *غیرمهمان* استفاده می‌شه (نه یک حسابِ مهمانِ
# دومِ متفاوت)، چون طبقِ فیکسِ GuestAwareDiscountThrottle حساب‌های
# مهمان دیگه bucket جداگانه ندارن (نگاه کنید به
# RedeemOfferCodeGuestThrottleBypassTests پایین‌تر) — این تست فقط
# رفتارِ per-user برای کاربرهایِ ثبت‌نام‌شده رو تضمین می‌کنه که باید
# دقیقاً مثلِ قبل دست‌نخورده بمونه.
# کاربرِ غیرمهمان (نه یک حسابِ مهمانِ دوم، که دیگه bucket جدا نداره).
other_user = User.objects.create(is_guest=False, name='', phone='+989120000701')
other_token = issue_access_token(other_user.id)
@@ -299,12 +294,7 @@ class ValidateDiscountThrottleTests(TestCase):
self.assertEqual(blocked_response.status_code, 429)
def test_throttle_is_scoped_per_user_not_shared_globally(self):
# ⚠️ توجه: از یک کاربرِ *غیرمهمان* استفاده می‌شه (نه یک حسابِ مهمانِ
# دومِ متفاوت)، چون طبقِ فیکسِ GuestAwareDiscountThrottle حساب‌های
# مهمان دیگه bucket جداگانه ندارن (نگاه کنید به
# ValidateDiscountGuestThrottleBypassTests پایین‌تر) — این تست فقط
# رفتارِ per-user برای کاربرهایِ ثبت‌نام‌شده رو تضمین می‌کنه که باید
# دقیقاً مثلِ قبل دست‌نخورده بمونه.
# کاربرِ غیرمهمان (نه یک حسابِ مهمانِ دوم، که دیگه bucket جدا نداره).
other_user = User.objects.create(is_guest=False, name='', phone='+989120000731')
other_token = issue_access_token(other_user.id)
@@ -387,12 +377,7 @@ class RedeemDiscountThrottleTests(TestCase):
self.assertEqual(blocked_response.status_code, 429)
def test_throttle_is_scoped_per_user_not_shared_globally(self):
# ⚠️ توجه: از یک کاربرِ *غیرمهمان* استفاده می‌شه (نه یک حسابِ مهمانِ
# دومِ متفاوت)، چون طبقِ فیکسِ GuestAwareDiscountThrottle حساب‌های
# مهمان دیگه bucket جداگانه ندارن (نگاه کنید به
# RedeemDiscountGuestThrottleBypassTests پایین‌تر) — این تست فقط
# رفتارِ per-user برای کاربرهایِ ثبت‌نام‌شده رو تضمین می‌کنه که باید
# دقیقاً مثلِ قبل دست‌نخورده بمونه.
# کاربرِ غیرمهمان (نه یک حسابِ مهمانِ دوم، که دیگه bucket جدا نداره).
other_user = User.objects.create(is_guest=False, name='', phone='+989120000301')
other_token = issue_access_token(other_user.id)
other_order = Order.objects.create(

View File

@@ -69,21 +69,11 @@ class ValidateDiscountView(APIView):
# صورت کلاینت بدون احراز هویت می‌تواند کدهای تخفیف را probe کند.
permission_classes = [IsAuthenticated]
# ⚠️ اضافه شده: این endpoint خودِ type/value کد رو هم برمی‌گردونه (نه
# فقط valid/invalid)، پس بدونِ throttle یک کاربرِ احرازهویت‌شده می‌تونست
# بی‌نهایت کدهای تخفیف رو probe کنه و جزئیاتشون رو یاد بگیره. طبقِ
# همون الگویِ ScopedRateThrottle که برای RedeemOfferCodeView
# (offer_redeem) اضافه شد: چون کاربر احرازهویت‌شده، کلید بر اساسِ pk
# کاربره (نه IP). نرخ کمی بالاتر از offer_redeem انتخاب شده چون این
# یک چکِ read-only پیش از خریده (ممکنه کاربر چند کد رو قبل از تصمیمِ
# نهایی امتحان کنه)، نه خودِ مصرف کد.
# ⚠️ اصلاح شده: چون کاربرهای مهمان (GuestSessionView) با هر deviceId
# جدید یک pk تازه می‌گیرن، ScopedRateThrottleِ ساده (کلید بر اساسِ
# user.pk) توسطِ چرخشِ حساب مهمان قابل‌دورزدن بود. حالا از همون
# GuestAwareDiscountThrottleِ مشترک (که RedeemDiscountView/
# RedeemOfferCodeView هم استفاده می‌کنن) استفاده می‌شه که برای
# کاربرهای مهمان کلید رو بر اساسِ IP می‌سازه و برای کاربرهای
# غیرمهمان رفتارِ per-user قبلی رو دست‌نخورده نگه می‌داره.
# این endpoint type/value کد رو برمی‌گردونه، پس بدونِ throttle یک
# کاربر می‌تونست بی‌نهایت کد رو probe کنه؛ نرخ کمی بالاتر از
# offer_redeem چون این یک چکِ read-only پیش از خریده. GuestAwareDiscountThrottle
# مشترک (هم اینجا هم RedeemDiscountView/RedeemOfferCodeView) برای
# مهمان‌ها کلید رو بر اساسِ IP می‌سازه تا چرخشِ حساب bucket تازه نده.
throttle_scope = 'discount_validate'
throttle_classes = [GuestAwareDiscountThrottle]
@@ -117,23 +107,11 @@ class RedeemDiscountView(APIView):
permission_classes = [IsAuthenticated]
# ⚠️ اضافه شده: این endpoint هم دقیقاً همون oracle ای که باعث شد
# ValidateDiscountView و RedeemOfferCodeView throttle بگیرن رو داره —
# کدِ ناموجود ۴۰۴ می‌گیره، کدِ موجود-ولی-نامعتبر ۴۰۰ می‌گیره، پس بدونِ
# throttle یک کاربرِ احرازهویت‌شده می‌تونست کدهای تخفیف رو روی سفارشِ
# خودش probe/brute-force کنه. اینجا ریسک از اون دوتا هم بیشتره، چون
# حدسِ درست صرفاً اطلاعات لو نمی‌ده؛ یک کدِ واقعی رو مصرف می‌کنه
# (سهمِ max_uses مشترک بین همه‌ی کاربرها رو می‌خوره) و باعثِ افتِ
# واقعیِ مبلغِ سفارش می‌شه؛ ضمناً هر تلاش دو تا select_for_update و یک
# تراکنشِ دیتابیسی اجرا می‌کنه که گرون‌تر از GET سبکِ validate است.
# طبقِ همون الگو، ScopedRateThrottle با کلیدِ per-user (نه IP) اضافه شد.
# ⚠️ اصلاح شده: چون کاربرهای مهمان (GuestSessionView) با هر deviceId
# جدید یک pk تازه می‌گیرن، ScopedRateThrottleِ ساده (کلید بر اساسِ
# user.pk) توسطِ چرخشِ حساب مهمان قابل‌دورزدن بود. حالا از
# GuestAwareDiscountThrottle استفاده می‌شه که برای کاربرهای مهمان
# کلید رو بر اساسِ IP می‌سازه (دقیقاً همون الگویِ GuestAwareAIThrottle
# و GuestAwareFamilyThrottle) و برای کاربرهای غیرمهمان رفتارِ per-user
# قبلی رو دست‌نخورده نگه می‌داره.
# همون oracleِ probe مثلِ ValidateDiscountView، ولی ریسکش بیشتره: حدسِ
# درست یه کدِ واقعی رو مصرف می‌کنه (سهمِ max_uses مشترک) و مبلغِ سفارش
# رو واقعاً کم می‌کنه، ضمن اینکه هر تلاش دو select_for_update و یه
# تراکنشه. GuestAwareDiscountThrottle برای مهمان‌ها کلید رو بر اساسِ IP
# می‌سازه تا چرخشِ حساب bucket تازه نده.
throttle_scope = 'discount_redeem'
throttle_classes = [GuestAwareDiscountThrottle]
@@ -200,24 +178,11 @@ class RedeemOfferCodeView(APIView):
permission_classes = [IsAuthenticated]
# ⚠️ اضافه شده: کدهای نامعتبر فقط یک ValidationError ساده (۴۰۰) برمی‌گردونن
# و هیچ throttleای اینجا نبود؛ یعنی یک کاربرِ احرازهویت‌شده می‌تونست
# بدونِ هیچ محدودیتی کدهای آفر رو حدس بزنه (offer-code probing). طبقِ
# همون الگویِ ScopedRateThrottle که در بقیه‌ی اکشن‌هایِ کم‌تکرار/حساسِ
# پروژه استفاده شده (مثلِ purchase در subscription، support_create در
# support)، اینجا هم یک throttle_scope مجزا اضافه شد.
# ⚠️ اصلاح شده: چون کاربرهای مهمان (GuestSessionView) با هر deviceId
# جدید یک pk تازه می‌گیرن، ScopedRateThrottleِ ساده (کلید بر اساسِ
# user.pk) توسطِ چرخشِ حساب مهمان قابل‌دورزدن بود — به‌خصوص اینجا
# حساس‌تره چون Offer.code سراسری/یکتاست و redeem_offer_code() فقط
# جلوی تکرارِ *همون* کاربر رو می‌گیره، نه کاربرهای مهمانِ جدید (یک
# حسابِ مهمانِ چرخشی می‌تونست همون آفرِ سراسری رو دوباره از
# apply_offer() بگیره). حالا از همون GuestAwareDiscountThrottle که
# برای RedeemDiscountView اضافه شد استفاده می‌شه (دقیقاً همون الگویِ
# GuestAwareAIThrottle، GuestAwareFamilyThrottle و
# GuestAwarePurchaseThrottle) که برای کاربرهای مهمان کلید رو بر
# اساسِ IP می‌سازه و برای کاربرهای غیرمهمان رفتارِ per-user قبلی رو
# دست‌نخورده نگه می‌داره.
# بدونِ throttle، کدهای آفر قابلِ probe بودن؛ اینجا حساس‌تره چون
# Offer.code سراسری/یکتاست و redeem_offer_code() فقط جلوی تکرارِ همون
# کاربر رو می‌گیره — یک حسابِ مهمانِ چرخشی می‌تونست همون آفرِ سراسری رو
# دوباره بگیره. GuestAwareDiscountThrottle برای مهمان‌ها کلید رو بر
# اساسِ IP می‌سازه تا چرخشِ حساب bucket تازه نده.
throttle_scope = 'offer_redeem'
throttle_classes = [GuestAwareDiscountThrottle]