TorbatYar/scripts/deploy_tenant_site.py
Mortezakoohjani 12c8615615 Ship enterprise Accounting FE/API with CRUD parity and production wiring.
Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 15:26:43 +03:30

112 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Deploy tenant-site feature + SSL for torbatkaracademy."""
from __future__ import annotations
import base64
import sys
from pathlib import Path
import paramiko
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
ROOT = Path(__file__).resolve().parents[1]
PASS = "Moli@5404"
REMOTE = "/home/morteza/torbatyar"
def connect(host, user):
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(host, username=user, password=PASS, timeout=30, allow_agent=False, look_for_keys=False)
return c
def run(c, cmd, sudo=False, timeout=300):
if sudo:
b64 = base64.b64encode(cmd.encode()).decode()
full = f"echo {PASS!r} | sudo -S -p '' bash -c 'echo {b64} | base64 -d | bash'"
else:
full = cmd
_, o, e = c.exec_command(full, timeout=timeout, get_pty=True)
text = (o.read() + e.read()).decode("utf-8", "replace")
print(text[-6000:] if len(text) > 6000 else text)
return text
def main():
files = [
"backend/core-service/app/api/v1/public_tenant.py",
"backend/core-service/app/api/v1/__init__.py",
"frontend/app/page.tsx",
"frontend/app/auth/callback/page.tsx",
"frontend/components/SiteHeader.tsx",
"frontend/components/TenantSitePage.tsx",
"frontend/lib/api.ts",
"frontend/lib/auth.ts",
"frontend/lib/tenant-host.ts",
"frontend/hooks/useTenantHost.ts",
"docker-compose.yml",
"infrastructure/deploy/.env.production.example",
"infrastructure/nginx/torbatyar.ir.conf",
]
app = connect("192.168.10.162", "morteza")
sftp = app.open_sftp()
for rel in files:
if rel.startswith("infrastructure/nginx"):
continue
local = ROOT / rel
remote = f"{REMOTE}/{rel}"
# ensure parent
sftp.put(str(local), remote)
print("up", rel)
# update .env with PLATFORM_BASE_DOMAIN
try:
with sftp.file(f"{REMOTE}/.env", "r") as f:
env = f.read().decode("utf-8", "replace")
except Exception:
env = (ROOT / "infrastructure/deploy/.env.production.example").read_text(encoding="utf-8")
if "NEXT_PUBLIC_PLATFORM_BASE_DOMAIN" not in env:
env += "\nNEXT_PUBLIC_PLATFORM_BASE_DOMAIN=torbatyar.ir\n"
with sftp.file(f"{REMOTE}/.env", "w") as f:
f.write(env)
sftp.close()
run(
app,
f"""
cd {REMOTE}
docker compose up -d --force-recreate core-service frontend
sleep 15
curl -sS -m 10 'http://127.0.0.1:8000/api/v1/public/tenant-site?slug=torbatkaracademy' -H 'Host: torbatkaracademy.torbatyar.ir'
echo
curl -sS -m 10 -o /dev/null -w 'fe=%{{http_code}}\\n' -H 'Host: torbatkaracademy.torbatyar.ir' http://127.0.0.1:3000/
""",
sudo=True,
timeout=240,
)
app.close()
ngx = connect("192.168.10.156", "torbatyaruser")
conf = (ROOT / "infrastructure/nginx/torbatyar.ir.conf").read_text(encoding="utf-8")
b64 = base64.b64encode(conf.encode()).decode()
run(
ngx,
f"""
echo {b64} | base64 -d > /etc/nginx/conf.d/torbatyar.ir.conf
certbot certonly --webroot -w /var/www/html --expand --non-interactive --agree-tos --email support@torbatyar.ir \
-d torbatyar.ir -d www.torbatyar.ir -d api.torbatyar.ir -d identity.torbatyar.ir -d auth.torbatyar.ir \
-d torbatkaracademy.torbatyar.ir 2>&1 | tail -n 30
nginx -t && systemctl reload nginx && echo RELOADED
curl -sk -m 15 -o /dev/null -w 'tenant_https=%{{http_code}}\\n' --resolve torbatkaracademy.torbatyar.ir:443:192.168.10.156 https://torbatkaracademy.torbatyar.ir/
curl -sk -m 15 --resolve api.torbatyar.ir:443:192.168.10.156 'https://api.torbatyar.ir/api/v1/public/tenant-site?slug=torbatkaracademy'
echo
""",
sudo=True,
timeout=300,
)
ngx.close()
if __name__ == "__main__":
main()