cleanup: trim bloated multi-line comments across the project
This commit is contained in:
@@ -56,47 +56,19 @@ class UserAdmin(admin.ModelAdmin):
|
||||
list_filter = ('is_guest',)
|
||||
actions = ['send_sms_to_selected']
|
||||
|
||||
# permissions=['change']: بدونِ این، جنگو این اکشن رو بر اساسِ
|
||||
# has_change_permission فیلتر نمیکنه (فقط اکشنهایی که با پارامترِ
|
||||
# permissions تعریف شده باشن فیلتر میشن)، یعنی کاربری که فقط
|
||||
# view_user داره (مثلِ گروهِ Supervisor) میتونه با یک POSTِ مستقیم
|
||||
# همین اکشن رو صدا بزنه و واقعاً پیامک بفرسته، حتی بدونِ اینکه دکمهی
|
||||
# اکشن رو در UI ببینه. با permissions=['change']، ModelAdmin.response_action
|
||||
# خودش (get_actions -> _filter_actions_by_permissions) این اکشن رو
|
||||
# فقط برای کاربرانِ دارایِ change_user در دسترس میذاره؛ برای بقیه
|
||||
# (مثلِ Supervisor) اصلاً در actions ثبتشده نیست، پس درخواستِ مستقیم
|
||||
# هم بیاثر میمونه (پیامِ هشدارِ استانداردِ «اکشنی انتخاب نشده»).
|
||||
# permissions=['change']: بدونِ این، کاربرِ فقط-view (گروهِ Supervisor)
|
||||
# میتونست با POSTِ مستقیم این اکشن رو صدا بزنه بدونِ دیدنِ دکمه در UI؛
|
||||
# این پارامتر باعث میشه ModelAdmin فقط برای change_user در دسترس بذارتش.
|
||||
@admin.action(description='ارسال پیامک به کاربران انتخابشده', permissions=['change'])
|
||||
def send_sms_to_selected(self, request, queryset):
|
||||
"""
|
||||
قدمِ اولیهی مینیمالِ فیچرِ «ارسالِ پیامک از ادمین»: یک اکشنِ ادمینِ
|
||||
معمولی روی UserAdmin که یک صفحهی میانیِ ساده (فرمِ متنِ پیامک) رو
|
||||
نشون میده و بعد از تأیید، دقیقاً به همون کاربرهایی که در changelist
|
||||
انتخاب شدن، همون متن رو با accounts.services.send_sms موجود ارسال
|
||||
میکنه.
|
||||
"""اکشنِ ادمین برای ارسالِ پیامک به کاربرانِ انتخابشده یا غیرفعال؛
|
||||
گیرنده با فیلدِ «target» انتخاب میشه (cutoffِ «غیرفعال» رو خودِ ادمین
|
||||
در فرم وارد میکنه، چیزی hardcode نیست).
|
||||
|
||||
گیرندهها با فیلدِ «target» در فرم انتخاب میشن:
|
||||
- 'selected' (پیشفرض): همون queryset که ادمین در changelist
|
||||
انتخاب کرده — رفتارِ قبلی، بدون تغییر.
|
||||
- 'inactive': کاربرانِ غیرفعال، با استفاده از
|
||||
accounts.services.get_inactive_users(since) — cutoff (تاریخ)
|
||||
رو خودِ ادمین در فرم وارد میکنه، هیچ عددِ روزی hardcode نشده.
|
||||
|
||||
عمداً محدود نگه داشته شده:
|
||||
- هیچ مدلِ کمپین/بدنهی جدیدی ساخته/persist نمیشه (نه رکوردی از
|
||||
پیام، نه رکوردی از تحویل)؛ ارسال کاملاً بلادرنگه.
|
||||
- هیچ زمانبندی، صفِ پسزمینه، یا فیلترِ هدفگیریِ دیگهای (غیر از
|
||||
selected/inactive) نیست.
|
||||
- محافظتِ سقف: چون ارسال هنوز کاملاً synchronous و توی همون
|
||||
request انجام میشه (نه صفِ پسزمینه)، اگر تعدادِ گیرندهها از
|
||||
settings.ADMIN_SMS_MAX_RECIPIENTS بیشتر باشه، اکشن هیچ پیامکی
|
||||
ارسال نمیکنه و فقط خطا نشون میده — تا یک انتخاب/تاریخِ خیلی
|
||||
بزرگ باعثِ تایماوتِ request یا overload شدنِ پروایدر نشه.
|
||||
- هیچ منطقِ provider تکرار نشده؛ send_sms عیناً همون تابعِ موجودیه
|
||||
که OTP و campaigns هم ازش استفاده میکنن.
|
||||
- کاربرانِ بدونِ شمارهتلفن (مثلِ مهمان) بهسادگی skip میشن.
|
||||
- شکستِ ارسال برای یک کاربر (SMSDeliveryError) کلِ اکشن رو متوقف
|
||||
نمیکنه؛ فقط شمارشِ failed رو زیاد میکنه و برای بقیه ادامه میده.
|
||||
ارسال کاملاً synchronous و توی همون requestه (نه صفِ پسزمینه)، پس
|
||||
اگر گیرندهها از settings.ADMIN_SMS_MAX_RECIPIENTS بیشتر باشن، اکشن
|
||||
هیچ پیامکی نمیفرسته تا request تایماوت نکنه یا provider overload نشه.
|
||||
شکستِ ارسال برای یک کاربر بقیه را متوقف نمیکنه.
|
||||
"""
|
||||
if 'apply' in request.POST:
|
||||
form = SendSMSForm(request.POST)
|
||||
@@ -123,10 +95,8 @@ class UserAdmin(admin.ModelAdmin):
|
||||
),
|
||||
level=messages.ERROR,
|
||||
)
|
||||
# بهجای return None، به رندرِ مشترکِ پایینِ تابع سقوط
|
||||
# میکنیم تا فرم دوباره (بدونِ ارسالِ هیچ پیامکی) نشون
|
||||
# داده بشه — دقیقاً همون الگویی که برای فرمِ نامعتبر
|
||||
# استفاده میشه.
|
||||
# سقوط به رندرِ مشترکِ پایین (نه return None) چون None از
|
||||
# یک اکشنِ ادمین باعثِ ریدایرکتِ ۳۰۲ میشه، نه رندرِ مستقیم.
|
||||
else:
|
||||
sent_count = 0
|
||||
failed_count = 0
|
||||
@@ -158,12 +128,8 @@ class UserAdmin(admin.ModelAdmin):
|
||||
f'{skipped_no_phone} کاربر بدونِ شمارهتلفن رد شدن (پیامک ارسال نشد).',
|
||||
level=messages.WARNING,
|
||||
)
|
||||
# توجه: قبلاً اینجا `return None` بود؛ حذف شد چون در
|
||||
# جنگو، None برگردوندن از یک اکشنِ ادمین باعثِ یک
|
||||
# ریدایرکتِ ۳۰۲ واقعی میشه (نه رندرِ مستقیمِ ۲۰۰)،
|
||||
# درست برخلافِ چیزی که این کامنت قبلاً فرض کرده بود.
|
||||
# حالا همالگو با شاخهی cap-exceeded، سقوط میکنیم به
|
||||
# رندرِ مشترکِ پایینِ تابع.
|
||||
# سقوط به رندرِ مشترکِ پایین (نه return None)، همالگو با
|
||||
# شاخهی cap-exceeded.
|
||||
else:
|
||||
form = SendSMSForm()
|
||||
|
||||
@@ -195,38 +161,15 @@ class OTPCodeAdmin(admin.ModelAdmin):
|
||||
list_filter = ('is_used',)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# صفحهی «ناظر» (Supervisor)
|
||||
# صفحهی «ناظر» (Supervisor): یک ایندکسِ read-only از لینکها به
|
||||
# changelistهای موجود (کاربران/پرداختها/اشتراکها)، داخلِ همون AdminSite
|
||||
# پیشفرض — نه AdminSite جدا و بدون هیچ ModelAdmin جدید.
|
||||
#
|
||||
# یک صفحهی خیلی کوچیک و *read-only* داخلِ همون AdminSiteِ پیشفرضِ جنگو
|
||||
# (django.contrib.admin.site) — نه یک AdminSite جدا، و نه CRUDِ موازی.
|
||||
# این صفحه صرفاً یک ایندکسِ گروهی از لینکهایی به همون changelistهای
|
||||
# ModelAdmin موجودِ پروژهست: کاربران (accounts.UserAdmin)، پرداختها
|
||||
# (payment.OrderAdmin / payment.TransactionAdmin) و اشتراکها
|
||||
# (subscription.SubscriptionAdmin). هیچ منطقِ کسبوکار یا ModelAdmin
|
||||
# جدیدی اینجا ساخته نمیشه.
|
||||
#
|
||||
# محدودیتِ واقعیِ read-only از طریقِ سیستمِ استانداردِ Group/Permission
|
||||
# جنگو تأمین میشه، نه با پنهونکردنِ لینک:
|
||||
# - هر لینک در این صفحه فقط وقتی نشون داده میشه که کاربر پرمیشنِ
|
||||
# view_<model> مربوطه رو داشته باشه (request.user.has_perm(...)).
|
||||
# - حتی اگه کسی مستقیماً URL تغییر/افزودن/حذف رو حدس بزنه، خودِ
|
||||
# changelist/change/add/delete viewهای اون ModelAdminها (که اینجا هیچ
|
||||
# overrideای نشدن) طبقِ has_view_permission/has_change_permission/
|
||||
# has_add_permission/has_delete_permission پیشفرضِ ModelAdmin — که
|
||||
# مستقیماً از Permission مدلِ کاربر میخونن — چک میکنن؛ یعنی گروهِ
|
||||
# Supervisor (که با دستورِ مدیریتیِ setup_supervisor_group فقط پرمیشنِ
|
||||
# view_* میگیره) حتی با دسترسیِ مستقیم به URL هم نمیتونه add/change/
|
||||
# delete کنه.
|
||||
# - خودِ صفحه هم مثلِ هر صفحهی دیگهی Admin با admin.site.admin_view
|
||||
# wrap شده، یعنی همون احرازِ هویت/is_staff استانداردِ Admin رو داره؛
|
||||
# ولی is_staff بهتنهایی برای *ورود به خودِ صفحه* کافی نیست — پایینتر
|
||||
# قبل از هر کارِ دیگهای عضویتِ کاربر در گروهِ Supervisor هم چک میشه
|
||||
# (request.user.groups.filter(name=SUPERVISOR_GROUP_NAME))، وگرنه
|
||||
# PermissionDenied (۴۰۳) بالا میره. این یک سیستمِ پرمیشنِ جدید نیست؛
|
||||
# فقط از همون گروهِ Supervisorِ موجود (که setup_supervisor_group
|
||||
# میسازه) برای گیتکیپینگِ ورود به صفحه استفاده میکنه.
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# read-only بودن با پنهونکردنِ لینک تضمین نمیشه، بلکه با پرمیشنِ استانداردِ
|
||||
# جنگو: هر لینک فقط با view_<model> نشون داده میشه و حتی دسترسیِ مستقیم به
|
||||
# URLِ change/add/delete هم توسطِ پرمیشنِ پیشفرضِ همون ModelAdminها رد میشه
|
||||
# (گروهِ Supervisor فقط view_* داره). is_staff بهتنهایی برای ورود کافی
|
||||
# نیست؛ عضویت در گروهِ Supervisor هم چک میشه، وگرنه PermissionDenied.
|
||||
|
||||
SUPERVISOR_GROUP_NAME = 'Supervisor'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user