make the domain configuration, not code: two env vars move everything
A domain change is coming (the Zarinpal terminal rejects the current callback domain). ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS, CORS defaults, the Bazaar redirect URI and deploy.sh's public health URL each spelled the domain out. They now derive from PUBLIC_BASE_URL and FRONTEND_URL, which keep today's domain as their default; env values for the three lists are still added on top, so the old domain can stay allowed while DNS moves. ZARINPAL_CALLBACK_URL used os.environ.get(key, default), so an empty key in .env produced an empty callback and every payment would fail closed. It now uses the same `.strip() or` fallback as its neighbours; the new test caught it. config/tests_domains.py loads settings in a subprocess with a new domain and fails if any derived value still mentions the old one. docs/operations.md gains the step-by-step domain move (DNS, .env, Zarinpal/Bazaar panels, frontend config.js, verification). CLAUDE.md records that the frontend is now ours and where the rebuild stands. 624 tests green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
62
config/tests_domains.py
Normal file
62
config/tests_domains.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
دامنه فقط از PUBLIC_BASE_URL و FRONTEND_URL میآید.
|
||||
|
||||
تنظیمات در زمانِ import ساخته میشوند، پس هر حالت در یک پروسهی جدا با env
|
||||
خودش بار میشود. اگر کسی دوباره دامنهای را مستقیم در settings بنویسد، حالتِ
|
||||
«دامنهی تازه» اینجا قرمز میشود.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
PROBE = """
|
||||
import json, os
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'config.settings'
|
||||
import django; django.setup()
|
||||
from django.conf import settings as s
|
||||
print(json.dumps({
|
||||
'hosts': s.ALLOWED_HOSTS, 'csrf': s.CSRF_TRUSTED_ORIGINS, 'cors': s.CORS_ALLOWED_ORIGINS,
|
||||
'callback': s.ZARINPAL_CALLBACK_URL, 'redirect': s.ZARINPAL_REDIRECT_URL, 'bazaar': s.BAZAAR_REDIRECT_URI,
|
||||
}))
|
||||
"""
|
||||
|
||||
|
||||
def load_settings(**env):
|
||||
clean = {k: v for k, v in os.environ.items() if not k.startswith(('DJANGO_ALLOWED', 'CSRF_', 'CORS_', 'ZARINPAL_', 'BAZAAR_REDIRECT', 'PUBLIC_BASE', 'FRONTEND_URL'))}
|
||||
clean.update(env)
|
||||
# .env محلی نباید مقدارهای آزمون را بپوشاند؛ python-dotenv متغیرِ موجود را عوض نمیکند،
|
||||
# پس کلیدهای خالی را هم صریح میگذاریم.
|
||||
for key in ('DJANGO_ALLOWED_HOSTS', 'CSRF_TRUSTED_ORIGINS', 'CORS_ALLOWED_ORIGINS', 'ZARINPAL_CALLBACK_URL',
|
||||
'ZARINPAL_REDIRECT_URL', 'BAZAAR_REDIRECT_URI'):
|
||||
clean.setdefault(key, '')
|
||||
out = subprocess.run([sys.executable, '-c', PROBE], cwd=BASE_DIR, env=clean, capture_output=True, text=True, check=True)
|
||||
return json.loads(out.stdout.strip().splitlines()[-1])
|
||||
|
||||
|
||||
class DomainSettingsTests(SimpleTestCase):
|
||||
def test_new_domain_moves_everything(self):
|
||||
s = load_settings(PUBLIC_BASE_URL='https://api.new-domain.ir', FRONTEND_URL='https://app.new-domain.ir/')
|
||||
self.assertIn('api.new-domain.ir', s['hosts'])
|
||||
self.assertIn('app.new-domain.ir', s['hosts'])
|
||||
self.assertIn('https://app.new-domain.ir', s['cors'])
|
||||
self.assertIn('https://api.new-domain.ir', s['csrf'])
|
||||
self.assertEqual(s['callback'], 'https://api.new-domain.ir/api/payment/zarinpal/callback')
|
||||
self.assertEqual(s['redirect'], 'https://app.new-domain.ir/')
|
||||
self.assertEqual(s['bazaar'], 'https://api.new-domain.ir/api/payment/bazaar/verify')
|
||||
self.assertNotIn('tadrisino2', json.dumps(s))
|
||||
|
||||
def test_extra_domain_is_added_not_replacing(self):
|
||||
s = load_settings(
|
||||
PUBLIC_BASE_URL='https://api.new-domain.ir', FRONTEND_URL='https://app.new-domain.ir',
|
||||
DJANGO_ALLOWED_HOSTS='old.example.ir', CORS_ALLOWED_ORIGINS='https://old.example.ir',
|
||||
)
|
||||
self.assertIn('old.example.ir', s['hosts'])
|
||||
self.assertIn('api.new-domain.ir', s['hosts'])
|
||||
self.assertIn('https://old.example.ir', s['cors'])
|
||||
self.assertIn('https://app.new-domain.ir', s['cors'])
|
||||
Reference in New Issue
Block a user