#!/usr/bin/env bash set -euo pipefail cd "${1:-/home/sevenhill/qmax}/deploy" docker compose stop trap 'docker compose start >/dev/null 2>&1 || true' EXIT legacy_phone="$(sed -n 's/^QMAX_MAX_PHONE_NUMBER=//p' .env | tail -n 1)" docker run --rm -i --user 0 --entrypoint python \ -e LEGACY_PHONE="$legacy_phone" \ --mount type=volume,source=deploy_qmax-data,target=/qmax \ --mount type=volume,source=deploy_qmax-pymax-session,target=/sessions \ deploy-qmax-pymax-worker - <<'PY' import os import pathlib import shutil import sqlite3 db = sqlite3.connect("/qmax/qmax.db") row = db.execute(""" select u.Id, coalesce(nullif(u.PhoneNumber, ''), nullif(s.PhoneNumber, '')) from Users u left join MaxAccountStates s on s.UserId = u.Id order by u.CreatedAt limit 1 """).fetchone() if not row: raise SystemExit("No legacy QMAX user found") user_id = str(row[0]).replace("-", "").lower() phone = str(row[1] or os.environ.get("LEGACY_PHONE") or "").strip() if not phone: raise SystemExit("Legacy QMAX user has no phone number") root = pathlib.Path("/sessions/pymax-session") source = root / "session.db" target = root / "accounts" / user_id if not source.is_file(): raise SystemExit(f"Legacy PyMax session is missing: {source}") target.mkdir(parents=True, exist_ok=True) os.chmod(target, 0o700) if not (target / "session.db").exists(): shutil.copy2(source, target / "session.db") contacts = root / "phone-contact-ids.json" if contacts.is_file() and not (target / contacts.name).exists(): shutil.copy2(contacts, target / contacts.name) (target / "phone.txt").write_text(phone, encoding="utf-8") os.chmod(target / "phone.txt", 0o600) print(f"MIGRATED_ACCOUNT={user_id}") print(f"SESSION_BYTES={(target / 'session.db').stat().st_size}") PY docker compose start trap - EXIT test "$(docker compose ps --status running --services | wc -l)" -eq 2