""" جایگزینِ خط‌فرمانیِ پر کردنِ دستیِ فرمِ ادمین برای BazaarSettings — همان چند مقداری که کافه‌بازار می‌خواهد (Application id، Access Token، Client ID/Secret، کلید تخفیف پویا) را این‌جا می‌پرسد و مستقیم در دیتابیس ذخیره می‌کند. اجرا: python manage.py setup_bazaar_settings هیچ مقداری در خط‌فرمان به‌عنوان آرگومان پاس داده نمی‌شود (چون در تاریخچه‌ی شل/history ذخیره می‌شد) — همه چیز تعاملی و با getpass پرسیده می‌شود (پیست‌کردن در ترمینال کار می‌کند، فقط روی صفحه نمایش داده نمی‌شود). Enter خالی یعنی «مقدارِ فعلی را دست نزن» — پس اجرای دوباره‌ی این دستور فقط برای عوض‌کردنِ یکی-دو فیلد هم امن است، بقیه‌ی فیلدها دست‌نخورده می‌مانند. """ import getpass from django.core.management.base import BaseCommand from apps.billing.models import BazaarSettings def _mask(value: str) -> str: if not value: return "(خالی)" if len(value) <= 8: return "•" * len(value) return f"{value[:4]}…{value[-4:]} ({len(value)} کاراکتر)" def _prompt_secret(label: str, current: str) -> str: hint = f" [فعلی: {_mask(current)} — Enter برای بدون‌تغییر]" if current else " [Enter برای رد کردن]" value = getpass.getpass(f"{label}{hint}: ").strip() return value or current def _prompt_plain(label: str, current: str, default: str = "") -> str: shown_current = current or default hint = f" [فعلی: {shown_current} — Enter برای بدون‌تغییر]" if shown_current else "" value = input(f"{label}{hint}: ").strip() return value or shown_current class Command(BaseCommand): help = "پر کردنِ تعاملیِ تنظیمات کافه‌بازار (BazaarSettings) بدون نیاز به پنل ادمین." def handle(self, *args, **options): settings_obj = BazaarSettings.get_solo() self.stdout.write(self.style.NOTICE("تنظیمات کافه‌بازار — Enter خالی یعنی مقدار فعلی دست‌نخورده بماند.\n")) package_name = _prompt_plain( "Application id اپ (مثلا ir.niqow.kangelo)", settings_obj.package_name, default="ir.niqow.kangelo" ) access_token = _prompt_secret( "Access Token (توکن ثابتِ «روش جدید» پیشخان، یا هر access_token دیگر)", settings_obj.access_token, ) client_id = _prompt_plain("Client ID (روش قدیمی/OAuth — اختیاری)", settings_obj.client_id) client_secret = _prompt_secret("Client Secret (روش قدیمی/OAuth — اختیاری)", settings_obj.client_secret) dynamic_discount_secret = _prompt_secret( "کلید امضای تخفیف پویا (اختیاری، فقط اگر می‌خواهی این ویژگی را استفاده کنی)", settings_obj.dynamic_discount_secret, ) # عمدا دست‌نخورده می‌مانند: refresh_token و access_token_expires_at فقط # با دکمه‌ی «اتصال به کافه‌بازار» (OAuth) در پنل ادمین پر می‌شوند — # پر کردنِ دستی‌شان این‌جا معنی ندارد چون بدونِ چرخه‌ی واقعیِ OAuth # (redirect + code) هیچ access_token واقعی‌ای برایشان وجود ندارد. settings_obj.package_name = package_name settings_obj.access_token = access_token settings_obj.client_id = client_id settings_obj.client_secret = client_secret settings_obj.dynamic_discount_secret = dynamic_discount_secret settings_obj.save() self.stdout.write("") self.stdout.write(self.style.SUCCESS("ذخیره شد. خلاصه‌ی مقادیر فعلی:")) self.stdout.write(f" Application id: {settings_obj.package_name or '(خالی)'}") self.stdout.write(f" Access Token: {_mask(settings_obj.access_token)}") self.stdout.write(f" Client ID: {settings_obj.client_id or '(خالی)'}") self.stdout.write(f" Client Secret: {_mask(settings_obj.client_secret)}") self.stdout.write(f" کلید تخفیف پویا: {_mask(settings_obj.dynamic_discount_secret)}") self.stdout.write(f" Refresh Token: {_mask(settings_obj.refresh_token)} (دست‌نخورده)") self.stdout.write( f" انقضای Access Token: {settings_obj.access_token_expires_at or '(خالی — یعنی توکن ثابت، بدون تمدید خودکار)'}" ) if settings_obj.access_token and not settings_obj.access_token_expires_at: self.stdout.write("") self.stdout.write( self.style.NOTICE( "توکن ثابت ذخیره شد — از همین الان خرید باید کار کند. برای فعال‌کردنِ تمدیدِ " "خودکار (اختیاری)، از پنل ادمین دکمه‌ی «اتصال به کافه‌بازار» را بزن." ) )