<?php require_once __DIR__ . '/../security/auth_chain.php'; require_once __DIR__ . '/../system/db.php'; if (!defined('DASHBOARD_ROOT')) define('DASHBOARD_ROOT', dirname(__DIR__, 2)); require_once '/var/www/shared/encryption.php'; require_once DASHBOARD_ROOT . '/core/shield_relay.php'; header('Content-Type: application/json'); if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['ok' => false, 'error' => 'Method not allowed']); exit; } if (!function_exists('admin_check')) { session_start(); if (empty($_SESSION['admin_id'])) { http_response_code(403); echo json_encode(['ok' => false, 'error' => 'Unauthorized']); exit; } } $data = json_decode(file_get_contents('php://input'), true); $action = $data['action'] ?? ''; $db = DB::get(); $STATUS_ACTIVE = 3002; $STATUS_INACTIVE = 3001; $CAT_ACTIVE = 6001; $CAT_INACTIVE = 6000; switch ($action) { case 'register_store': $domain = trim($data['domain'] ?? ''); $name = trim($data['store_name'] ?? ''); $accent = trim($data['accent_color'] ?? '#2D6A4F'); if (!$domain || !preg_match('/^[a-z0-9.-]+\.[a-z]{2,}$/i', $domain)) { echo json_encode(['ok' => false, 'error' => 'Invalid domain format']); exit; } $stmt = $db->prepare('INSERT INTO stores (domain, campaign_name, store_name, accent_color, is_active) VALUES (:domain, :name, :sname, :accent, 1)'); $stmt->execute([ ':domain' => Encryption::encrypt(strtolower($domain)), ':name' => Encryption::encrypt($name ?: $domain), ':sname' => Encryption::encrypt($name ?: $domain), ':accent' => $accent, ]); $storeId = $db->lastInsertId(); $dnsResult = triggerDnsZone($domain); triggerDomainSync(); echo json_encode([ 'ok' => true, 'store_id' => (int)$storeId, 'dns' => $dnsResult, 'message' => 'Store registered. DNS zone created. Domain syncing to Proxy.', ]); break; case 'activate_store': $storeId = (int)($data['store_id'] ?? 0); if (!$storeId) { echo json_encode(['ok' => false, 'error' => 'Missing store_id']); exit; } $db->prepare('UPDATE stores SET is_active = 1 WHERE id = :id')->execute([':id' => $storeId]); triggerDomainSync(); echo json_encode(['ok' => true, 'message' => 'Store activated, domain syncing to Proxy']); break; case 'deactivate_store': $storeId = (int)($data['store_id'] ?? 0); if (!$storeId) { echo json_encode(['ok' => false, 'error' => 'Missing store_id']); exit; } $db->beginTransaction(); try { $db->prepare('UPDATE stores SET is_active = 0 WHERE id = :id') ->execute([':id' => $storeId]); $db->prepare('UPDATE products SET status_code = :inactive WHERE store_id = :sid AND status_code = :active') ->execute([':inactive' => $STATUS_INACTIVE, ':sid' => $storeId, ':active' => $STATUS_ACTIVE]); $db->prepare('UPDATE categories SET status_code = :inactive WHERE store_id = :sid AND status_code = :active') ->execute([':inactive' => $CAT_INACTIVE, ':sid' => $storeId, ':active' => $CAT_ACTIVE]); $db->prepare('UPDATE storefront_blocks SET is_active = 0, status_code = :inactive WHERE store_id = :sid AND status_code = :active') ->execute([':inactive' => $CAT_INACTIVE, ':sid' => $storeId, ':active' => $CAT_ACTIVE]); $db->commit(); } catch (\Exception $e) { $db->rollBack(); echo json_encode(['ok' => false, 'error' => 'Database error during deactivation']); exit; } triggerDomainSync(); echo json_encode(['ok' => true, 'message' => 'Store deactivated. Domain dropped. Products/categories/blocks moved to inactive (reusable).']); break; case 'delete_store': $storeId = (int)($data['store_id'] ?? 0); if (!$storeId) { echo json_encode(['ok' => false, 'error' => 'Missing store_id']); exit; } $domainRow = $db->prepare('SELECT domain FROM stores WHERE id = :id'); $domainRow->execute([':id' => $storeId]); $domainName = $domainRow->fetchColumn(); if ($domainName && Encryption::isEncrypted($domainName)) { $domainName = Encryption::decrypt($domainName); } $db->prepare('DELETE FROM stores WHERE id = :id')->execute([':id' => $storeId]); if ($domainName) { ShieldRelay::exec('dns', "dns delete-zone {$domainName}", 10); } triggerDomainSync(); echo json_encode(['ok' => true, 'message' => 'Domain record deleted. DNS zone removed. Inactive products/categories/blocks preserved for reuse.']); break; default: echo json_encode(['ok' => false, 'error' => 'Unknown action']); } function triggerDomainSync() { $script = '/opt/cleanearth/sync_domains.sh'; if (file_exists($script)) { exec("bash $script > /dev/null 2>&1 &"); } } function triggerDnsZone(string $domain): array { $create = ShieldRelay::exec('dns', "dns create-zone {$domain}", 10); if (!$create['ok']) { return ['ok' => false, 'step' => 'create-zone', 'error' => $create['output'] ?? 'failed']; } $defaults = ShieldRelay::exec('dns', "dns add-defaults {$domain}", 15); return [ 'ok' => $defaults['ok'], 'zone' => $domain, 'step' => 'add-defaults', 'output' => $defaults['output'] ?? '', ]; } 