Files
shopship/apps/billing/management/commands/setup_bazaar_settings.py
T
2026-08-31 15:11:52 +03:30

99 lines
5.3 KiB
Python

"""
جایگزینِ خط‌فرمانیِ پر کردنِ دستیِ فرمِ ادمین برای 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(
"توکن ثابت ذخیره شد — از همین الان خرید باید کار کند. برای فعال‌کردنِ تمدیدِ "
"خودکار (اختیاری)، از پنل ادمین دکمه‌ی «اتصال به کافه‌بازار» را بزن."
)
)