feat(manager): auto-provision WhatsApp Bridge on demo create/destroy
- Add POS_INTERNAL_URL config for cross-VM API calls - create_demo now calls POS /internal/whatsapp-bridge after tenant creation - delete_tenant now destroys bridge container before dropping DB - Graceful fallback if bridge provisioning fails
This commit is contained in:
@@ -29,6 +29,9 @@ MANAGER_JWT_EXPIRES = int(os.environ.get("MANAGER_JWT_EXPIRES", "28800")) # 8 h
|
|||||||
# Internal API key for manager-to-POS operations
|
# Internal API key for manager-to-POS operations
|
||||||
INTERNAL_API_KEY = os.environ.get("INTERNAL_API_KEY", "")
|
INTERNAL_API_KEY = os.environ.get("INTERNAL_API_KEY", "")
|
||||||
|
|
||||||
|
# ─── POS Server (for internal API calls from manager VM) ───────────────────
|
||||||
|
POS_INTERNAL_URL = os.environ.get("POS_INTERNAL_URL", "http://192.168.10.91:5001")
|
||||||
|
|
||||||
# ─── Demo Settings ─────────────────────────────────────────────────────────
|
# ─── Demo Settings ─────────────────────────────────────────────────────────
|
||||||
DEMO_DEFAULT_DAYS = int(os.environ.get("DEMO_DEFAULT_DAYS", "14"))
|
DEMO_DEFAULT_DAYS = int(os.environ.get("DEMO_DEFAULT_DAYS", "14"))
|
||||||
DEMO_DEFAULT_PIN = os.environ.get("DEMO_DEFAULT_PIN", "0000")
|
DEMO_DEFAULT_PIN = os.environ.get("DEMO_DEFAULT_PIN", "0000")
|
||||||
|
|||||||
@@ -153,6 +153,31 @@ def create_demo(name, email, demo_days=None, subdomain=None, pin="0000"):
|
|||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
# Auto-provision WhatsApp Bridge
|
||||||
|
try:
|
||||||
|
import urllib.request
|
||||||
|
import json as _json
|
||||||
|
from config import POS_INTERNAL_URL, INTERNAL_API_KEY
|
||||||
|
bridge_payload = _json.dumps({
|
||||||
|
"tenant_id": tenant_id,
|
||||||
|
"subdomain": subdomain,
|
||||||
|
"db_name": result["db_name"]
|
||||||
|
}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
f"{POS_INTERNAL_URL}/pos/api/internal/whatsapp-bridge",
|
||||||
|
data=bridge_payload,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Internal-Key": INTERNAL_API_KEY
|
||||||
|
},
|
||||||
|
method="POST"
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||||
|
bridge_data = _json.loads(resp.read().decode())
|
||||||
|
result["whatsapp_bridge"] = bridge_data
|
||||||
|
except Exception as e:
|
||||||
|
result["whatsapp_bridge_error"] = str(e)
|
||||||
|
|
||||||
result["demo_days"] = days
|
result["demo_days"] = days
|
||||||
result["expires_at"] = str(datetime.now() + timedelta(days=days))
|
result["expires_at"] = str(datetime.now() + timedelta(days=days))
|
||||||
result["access_url"] = f"https://{subdomain}.nexusautoparts.com.mx/pos/login"
|
result["access_url"] = f"https://{subdomain}.nexusautoparts.com.mx/pos/login"
|
||||||
@@ -221,6 +246,26 @@ def delete_tenant(tenant_id):
|
|||||||
if not tenant:
|
if not tenant:
|
||||||
raise ValueError("Tenant not found")
|
raise ValueError("Tenant not found")
|
||||||
db_name = tenant["db_name"]
|
db_name = tenant["db_name"]
|
||||||
|
subdomain = tenant.get("subdomain") or f"tenant-{tenant_id}"
|
||||||
|
|
||||||
|
# Destroy WhatsApp Bridge container
|
||||||
|
try:
|
||||||
|
import urllib.request
|
||||||
|
import json as _json
|
||||||
|
from config import POS_INTERNAL_URL, INTERNAL_API_KEY
|
||||||
|
bridge_payload = _json.dumps({"subdomain": subdomain}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
f"{POS_INTERNAL_URL}/pos/api/internal/whatsapp-bridge",
|
||||||
|
data=bridge_payload,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Internal-Key": INTERNAL_API_KEY
|
||||||
|
},
|
||||||
|
method="DELETE"
|
||||||
|
)
|
||||||
|
urllib.request.urlopen(req, timeout=15)
|
||||||
|
except Exception:
|
||||||
|
pass # Bridge may not exist
|
||||||
|
|
||||||
conn = get_master_conn()
|
conn = get_master_conn()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|||||||
Reference in New Issue
Block a user