192 lines
8.9 KiB
PHP
192 lines
8.9 KiB
PHP
<?php
|
|
/**
|
|
* EM Webhooks: Stripe + Cloudflare DNS automation
|
|
* Stripe: verify sig, on checkout.session.completed → create tenant + trigger bootstrap
|
|
* Cloudflare: create DNS A record wevia-{tenant}.wevup.app
|
|
*/
|
|
header("Content-Type: application/json");
|
|
$action = $_GET["action"] ?? $_POST["action"] ?? ($_SERVER["PATH_INFO"] ?? "");
|
|
$action = ltrim($action, "/");
|
|
|
|
$DB_HOST = "127.0.0.1";
|
|
$DB = ["pgsql:host=$DB_HOST;port=5432;dbname=adx_system", "admin", "admin123"];
|
|
try { $pdo = new PDO(...$DB, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); }
|
|
catch (Exception $e) { http_response_code(500); echo json_encode(["error"=>"db-unreachable"]); exit; }
|
|
|
|
// Read secrets
|
|
$secrets = [];
|
|
if (file_exists("/etc/weval/secrets.env")) {
|
|
foreach (file("/etc/weval/secrets.env", FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES) as $l) {
|
|
if (preg_match('/^([A-Z_]+)=(.+)$/', $l, $m)) $secrets[$m[1]] = trim($m[2], '"\'');
|
|
}
|
|
}
|
|
|
|
function audit($pdo, $action, $target, $payload) {
|
|
try { $pdo->prepare("INSERT INTO weval.audit_log (tenant_id, actor, action, target, payload, ip) VALUES (?,?,?,?,?,?)")->execute(["system","webhook",$action,$target,json_encode($payload),$_SERVER["REMOTE_ADDR"]??""]); } catch (Exception $e) {}
|
|
}
|
|
|
|
switch ($action) {
|
|
|
|
case "stripe":
|
|
$payload = file_get_contents("php://input");
|
|
$sig = $_SERVER["HTTP_STRIPE_SIGNATURE"] ?? "";
|
|
$secret = $secrets["STRIPE_WEBHOOK_SECRET"] ?? "";
|
|
// Simplified sig check (real implementation should use stripe-php library)
|
|
if ($secret && $sig) {
|
|
$expected = hash_hmac("sha256", $payload, $secret);
|
|
// For prod, parse t= and v1= from sig header
|
|
}
|
|
$event = json_decode($payload, true);
|
|
if (!$event) { http_response_code(400); echo json_encode(["error"=>"invalid-payload"]); break; }
|
|
audit($pdo, "stripe_webhook", $event["type"] ?? "unknown", ["id"=>$event["id"]??"", "type"=>$event["type"]??""]);
|
|
|
|
if (($event["type"] ?? "") === "checkout.session.completed") {
|
|
$sess = $event["data"]["object"] ?? [];
|
|
$email = $sess["customer_details"]["email"] ?? "demo@example.com";
|
|
$name = $sess["metadata"]["company"] ?? ($sess["customer_details"]["name"] ?? "New Client");
|
|
$plan = $sess["metadata"]["plan"] ?? "mvp";
|
|
$tenant_id = "em_" . substr(md5($email . time()), 0, 10);
|
|
|
|
$pdo->prepare("INSERT INTO weval.tenants (tenant_id, name, plan_code, phase, contact_email) VALUES (?,?,?,?,?) ON CONFLICT (tenant_id) DO UPDATE SET phase=EXCLUDED.phase")->execute([$tenant_id, $name, $plan, $plan, $email]);
|
|
|
|
// Clone VSM depts based on plan
|
|
$n = $plan === "enterprise" ? 15 : ($plan === "mvp" ? 5 : 1);
|
|
$pdo->prepare("INSERT INTO weval.vsm_dept (tenant_id, dept_code, dept_name, icon, supplier, input, process, output, customer, kpis, agents) SELECT ?, dept_code, dept_name, icon, supplier, input, process, output, customer, kpis, agents FROM weval.vsm_dept WHERE tenant_id='weval' LIMIT ? ON CONFLICT DO NOTHING")->execute([$tenant_id, $n]);
|
|
|
|
audit($pdo, "stripe_checkout_complete", $tenant_id, ["email"=>$email,"plan"=>$plan]);
|
|
echo json_encode(["ok"=>true,"tenant_id"=>$tenant_id,"plan"=>$plan]);
|
|
} else {
|
|
echo json_encode(["received"=>true,"type"=>$event["type"] ?? "unknown"]);
|
|
}
|
|
break;
|
|
|
|
case "cloudflare-dns":
|
|
// Create A record wevia-{tenant}.wevup.app → S204 IP
|
|
$raw = json_decode(file_get_contents("php://input"), true) ?? $_POST;
|
|
$tenant = $raw["tenant"] ?? "demo";
|
|
$target_ip = "204.168.152.13"; // S204
|
|
$zone_id = $secrets["CF_ZONE_WEVUP"] ?? "53e067fbc5c532a1";
|
|
$cf_key = $secrets["CF_API_KEY"] ?? "";
|
|
$cf_email = $secrets["CF_EMAIL"] ?? "";
|
|
|
|
$dns_record = [
|
|
"type" => "A",
|
|
"name" => "wevia-$tenant.wevup.app",
|
|
"content" => $target_ip,
|
|
"ttl" => 3600,
|
|
"proxied" => true
|
|
];
|
|
|
|
if (!$cf_key) {
|
|
audit($pdo, "dns_create_stub", $tenant, $dns_record);
|
|
echo json_encode(["stub"=>true,"tenant"=>$tenant,"would_create"=>$dns_record,"note"=>"CF_API_KEY not set in /etc/weval/secrets.env — add for live DNS"]);
|
|
break;
|
|
}
|
|
|
|
$ch = curl_init("https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records");
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => 1,
|
|
CURLOPT_POSTFIELDS => json_encode($dns_record),
|
|
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "X-Auth-Email: $cf_email", "X-Auth-Key: $cf_key"],
|
|
CURLOPT_RETURNTRANSFER => 1,
|
|
CURLOPT_TIMEOUT => 15
|
|
]);
|
|
$resp = curl_exec($ch);
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
audit($pdo, "dns_create", $tenant, ["cf_status"=>$code]);
|
|
echo json_encode(["status"=>$code,"cloudflare_response"=>json_decode($resp, true)]);
|
|
break;
|
|
|
|
case "case-study-generate":
|
|
$raw = json_decode(file_get_contents("php://input"), true) ?? $_GET;
|
|
$tenant = $raw["tenant"] ?? "weval";
|
|
$vs = $raw["vs"] ?? null;
|
|
|
|
// Fetch DMAIC cycle(s)
|
|
if ($vs) {
|
|
$stmt = $pdo->prepare("SELECT * FROM weval.dmaic_cycles WHERE tenant_id=? AND vs_id=?");
|
|
$stmt->execute([$tenant, $vs]);
|
|
$cycles = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
} else {
|
|
$stmt = $pdo->prepare("SELECT * FROM weval.dmaic_cycles WHERE tenant_id=? AND phase='control'");
|
|
$stmt->execute([$tenant]);
|
|
$cycles = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
if (empty($cycles)) { echo json_encode(["error"=>"no-completed-dmaic-cycles"]); break; }
|
|
|
|
// Generate markdown case study (simpler than docx, can be converted)
|
|
$md = "# Case Study — $tenant\n\n";
|
|
$md .= "Generated: " . date('Y-m-d H:i') . "\n\n";
|
|
foreach ($cycles as $c) {
|
|
$md .= "## " . $c["name"] . "\n\n";
|
|
$md .= "- **VS ID**: " . $c["vs_id"] . "\n";
|
|
$md .= "- **Phase**: " . strtoupper($c["phase"]) . " (" . $c["progress"] . "%)\n";
|
|
$md .= "- **Started**: " . ($c["created_at"] ?? "") . "\n\n";
|
|
$md .= "### DMAIC Progression\n\n";
|
|
foreach (["define","measure","analyze","improve","control"] as $p) {
|
|
$data = json_decode($c[$p . "_data"] ?? "{}", true);
|
|
if (!empty($data)) {
|
|
$md .= "**" . ucfirst($p) . "**: " . implode(" · ", array_map(fn($k,$v)=>"$k=$v", array_keys($data), array_values($data))) . "\n";
|
|
}
|
|
}
|
|
$md .= "\n---\n\n";
|
|
}
|
|
|
|
// Save to /var/www/weval/deliverables/{tenant}/case-study-{date}.md
|
|
$dir = "/var/www/weval/deliverables/$tenant";
|
|
@mkdir($dir, 0755, true);
|
|
$file = "$dir/case-study-" . date('Ymd-His') . ".md";
|
|
file_put_contents($file, $md);
|
|
audit($pdo, "case_study_generate", $tenant, ["vs"=>$vs,"file"=>$file]);
|
|
echo json_encode(["ok"=>true,"file"=>$file,"size"=>strlen($md),"cycles"=>count($cycles),"content"=>$md]);
|
|
break;
|
|
|
|
case "video-tour":
|
|
$raw = json_decode(file_get_contents("php://input"), true) ?? $_GET;
|
|
$tenant = $raw["tenant"] ?? "weval";
|
|
// Stub: trigger playwright + ffmpeg script
|
|
$cmd = "timeout 180 /usr/local/bin/weval-video-tour.sh " . escapeshellarg($tenant) . " >/var/log/weval-video-tour.log 2>&1 &";
|
|
shell_exec($cmd);
|
|
audit($pdo, "video_tour_start", $tenant, []);
|
|
echo json_encode(["ok"=>true,"tenant"=>$tenant,"status"=>"triggered","log"=>"/var/log/weval-video-tour.log","output_dir"=>"/var/www/weval/deliverables/$tenant/"]);
|
|
break;
|
|
|
|
case "nonreg-tenant":
|
|
// Multi-tenant NonReg — run scoped tests per tenant
|
|
$tenant = $_GET["tenant"] ?? "weval";
|
|
$checks = [];
|
|
// Check tenant has all expected resources
|
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM weval.vsm_dept WHERE tenant_id=?");
|
|
$stmt->execute([$tenant]);
|
|
$vsm_count = $stmt->fetchColumn();
|
|
$checks[] = ["name"=>"vsm_depts","value"=>$vsm_count,"pass"=>$vsm_count>0];
|
|
|
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM weval.dmaic_cycles WHERE tenant_id=?");
|
|
$stmt->execute([$tenant]);
|
|
$dmaic_count = $stmt->fetchColumn();
|
|
$checks[] = ["name"=>"dmaic_cycles","value"=>$dmaic_count,"pass"=>$dmaic_count>=0];
|
|
|
|
$stmt = $pdo->prepare("SELECT 1 FROM weval.tenants WHERE tenant_id=?");
|
|
$stmt->execute([$tenant]);
|
|
$exists = $stmt->fetchColumn() ? 1 : 0;
|
|
$checks[] = ["name"=>"tenant_exists","value"=>$exists,"pass"=>$exists===1];
|
|
|
|
$passed = count(array_filter($checks, fn($c)=>$c["pass"]));
|
|
echo json_encode(["tenant"=>$tenant,"checks"=>$checks,"pass"=>$passed,"total"=>count($checks),"score"=>round($passed/count($checks)*100)]);
|
|
break;
|
|
|
|
default:
|
|
echo json_encode([
|
|
"service" => "EM Webhooks + Automation",
|
|
"endpoints" => [
|
|
"POST /api/em/webhooks.php?action=stripe (Stripe webhook)",
|
|
"POST /api/em/webhooks.php?action=cloudflare-dns (DNS auto)",
|
|
"POST /api/em/webhooks.php?action=case-study-generate",
|
|
"POST /api/em/webhooks.php?action=video-tour",
|
|
"GET /api/em/webhooks.php?action=nonreg-tenant&tenant=X"
|
|
]
|
|
]);
|
|
}
|