Postgres support (DB_* env), LoginEvent audit table, Choice.value 300, deploy.sh pg_dump backup

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 11:48:48 +03:30
parent e00f6b80eb
commit 042df25738
11 changed files with 261 additions and 38 deletions

View File

@@ -224,8 +224,7 @@ printf ' دیتابیس و بکاپ‌ها فقط برای %s خواندنی‌
# به‌عنوانِ فرمان روی سرور نیست). اگر بکاپ نشد، migrate اجرا نمی‌شود: دیپلوی بی‌بکاپ را
# عمداً نمی‌پذیریم. فقط ۲ بکاپِ خودکارِ آخر (db-before-deploy-*: همین انتشار و یکی قبل‌تر) نگه داشته می‌شود تا دیسکِ
# مشترک پر نشود؛ بکاپ‌های دستی با نامِ دیگر دست نمی‌خورند.
# آزموده‌نشده: Postgres (بعد از مهاجرت باید pg_dump جایگزین شود؛ اینجا فقط هشدار می‌دهد)،
# و بکاپ از بیرونِ ماشین که هنوز نیست (بند ۱۷ در چک‌لیستِ لانچ).
# Postgres با pg_dump (آزموده‌نشده روی سرور تا انتقال)؛ بکاپ از بیرونِ ماشین که هنوز نیست (بند ۱۷ در چک‌لیستِ لانچ).
step "بکاپِ دیتابیس"
python - <<'PYBACKUP' || fail "بکاپِ دیتابیس نشد؛ migrate اجرا نشد و هیچ تغییری روی داده اعمال نشد."
import datetime
@@ -241,8 +240,24 @@ django.setup()
from django.conf import settings
db = settings.DATABASES['default']
if db['ENGINE'] == 'django.db.backends.postgresql':
import subprocess
os.makedirs('.deploy-backups', mode=0o700, exist_ok=True)
dst = '.deploy-backups/db-before-deploy-%s.pgdump' % datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
env = dict(os.environ, PGPASSWORD=db['PASSWORD'])
# فرمتِ custom (فشرده)؛ رمز از env می‌رود نه argv چون ps روی این ماشین argv را به همه نشان می‌دهد.
subprocess.run(['pg_dump', '-Fc', '-h', db['HOST'], '-p', str(db['PORT']), '-U', db['USER'],
'-f', dst, db['NAME']], env=env, check=True)
os.chmod(dst, 0o600)
# فقط خوانا بودنِ فایل را می‌سنجد؛ بازیابیِ واقعی روی دیتابیسِ دیگر آزموده نشده.
subprocess.run(['pg_restore', '--list', dst], check=True, stdout=subprocess.DEVNULL)
print(f' {dst} ({os.path.getsize(dst) // 2**20} MB، pg_restore --list: ok)')
old = sorted(glob.glob('.deploy-backups/db-before-deploy-*.pgdump'))[:-2]
for path in old:
os.remove(path)
raise SystemExit(0)
if db['ENGINE'] != 'django.db.backends.sqlite3':
print(f" ⚠ موتورِ دیتابیس {db['ENGINE']} است؛ بکاپِ خودکار فقط SQLite را پوشش می‌دهد. خودتان بکاپ بگیرید.")
print(f" ⚠ موتورِ دیتابیس {db['ENGINE']} است؛ بکاپِ خودکار فقط SQLite و Postgres را پوشش می‌دهد. خودتان بکاپ بگیرید.")
raise SystemExit(0)
src_path = str(db['NAME'])