""" ثبتِ MessageCampaign و CampaignDelivery در Django Admin. این ماژول صرفاً برای مشاهده/مدیریتِ دستیِ کمپین‌ها و بررسیِ وضعیتِ تحویل‌هاست؛ هیچ منطقِ اجرای کمپین (execute_campaign) اینجا صدا زده نمی‌شه — طبق MessageCampaign.__doc__ و CampaignDelivery.__doc__، اجرا و پنلِ ادمینِ مربوط به execution فیچرِ بعدیه. - MessageCampaignAdmin: امکانِ ساخت/ویرایش/حذفِ کمپین (فیلدهای معمولی، بدون منطقِ اجرا) رو با ModelAdmin پیش‌فرضِ Django فراهم می‌کنه. - CampaignDeliveryAdmin: صرفاً read-only. CampaignDelivery یک لاگِ وضعیتِ تولیدشده توسطِ execute_campaign()‌ه (طبق docstring خودش)؛ دستکاریِ دستیِ status/error_message از ادمین می‌تونه این لاگ رو با چیزی که واقعاً برای کاربر اتفاق افتاده (یا نیفتاده) ناسازگار کنه و رفتارِ idempotency/unique-constraint که در campaigns.services روی همین رکوردها تکیه می‌کنه رو دور بزنه. به همین دلیل add/change/delete همه غیرفعالن؛ تنها راهِ دیدنِ رکوردها لیست/دیتیلِ read-only‌ه. """ from django.contrib import admin from .models import CampaignDelivery, MessageCampaign @admin.register(MessageCampaign) class MessageCampaignAdmin(admin.ModelAdmin): list_display = ('id', 'title', 'channel', 'created_at') list_filter = ('channel',) search_fields = ('title', 'body') readonly_fields = ('created_at',) fields = ('title', 'body', 'channel', 'target_filter', 'created_at') @admin.register(CampaignDelivery) class CampaignDeliveryAdmin(admin.ModelAdmin): """ نمایشِ read-only: لیست و صفحه‌ی جزئیاتِ هر رکورد همیشه قابلِ مشاهده‌ست (has_view_permission صریحاً True)، ولی هیچ راهی برای افزودن، ویرایش یا حذفِ رکورد از ادمین وجود نداره تا وضعیتِ تحویل (که فقط باید توسطِ campaigns.services.execute_campaign آپدیت بشه) از ادمین دست‌کاری نشه. """ list_display = ('id', 'campaign', 'user_id', 'channel', 'status', 'created_at') list_filter = ('channel', 'status') search_fields = ('user_id', 'error_message') fields = ('campaign', 'user_id', 'channel', 'status', 'error_message', 'created_at') readonly_fields = fields def has_view_permission(self, request, obj=None): # صریحاً True: بدونِ override، fallbackِ پیش‌فرضِ Django به کاربرِ # staffِ بدونِ پرمیشنِ view/change حتی اجازه‌ی دیدنِ این صفحه‌ی # read-only رو هم نمی‌ده — یعنی مدل عملاً غیرقابلِ‌دسترس می‌شه، نه # فقط view-only. return True def has_add_permission(self, request): return False def has_change_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False