diff --git a/.gitignore b/.gitignore index 8cb5ce7..9aa8908 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,9 @@ logs/ # Don't commit 12MB+ artifacts — every dev rebuilds locally on first commit. **/graphify-out/ +# ── Uploaded client artifacts (per-instance, regenerated at runtime) ── +FINAL_PRODUCTION_SYSTEM/uploads/client-resources/ + # ── PHP Dependencies (managed by Composer) ──────────────── FINAL_PRODUCTION_SYSTEM/vendor/ diff --git a/FINAL_PRODUCTION_SYSTEM/admin_v2.php b/FINAL_PRODUCTION_SYSTEM/admin_v2.php index cf50293..5937524 100644 --- a/FINAL_PRODUCTION_SYSTEM/admin_v2.php +++ b/FINAL_PRODUCTION_SYSTEM/admin_v2.php @@ -154,7 +154,7 @@ if (isset($_POST['action']) && $_POST['action'] === 'change_language' && isset($_POST['language'])) { $newLang = preg_replace('/[^a-z]/', '', strtolower($_POST['language'])); if (in_array($newLang, ['en', 'ru'])) { - $stmt = $pdo->prepare("UPDATE admin_users SET preferred_language = ? WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('admin_users') . "` SET preferred_language = ? WHERE id = ?"); $stmt->execute([$newLang, $admin_session['admin_id']]); loadLanguage($newLang); if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) { @@ -404,7 +404,7 @@ // Handle logout if (isset($_GET['logout'])) { if (isset($_SESSION['admin_token'])) { - $stmt = $pdo->prepare("UPDATE admin_sessions SET is_active = 0 WHERE session_token = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('admin_sessions') . "` SET is_active = 0 WHERE session_token = ?"); $stmt->execute([$_SESSION['admin_token']]); } session_destroy(); diff --git a/FINAL_PRODUCTION_SYSTEM/api/authenticate-usb.php b/FINAL_PRODUCTION_SYSTEM/api/authenticate-usb.php index bddcedf..3703043 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/authenticate-usb.php +++ b/FINAL_PRODUCTION_SYSTEM/api/authenticate-usb.php @@ -90,8 +90,8 @@ // Find USB device by serial number $stmt = $pdo->prepare(" SELECT d.*, t.full_name, t.is_active - FROM usb_devices d - INNER JOIN technicians t ON d.technician_id = t.technician_id + FROM `" . t('usb_devices') . "` d + INNER JOIN `" . t('technicians') . "` t ON d.technician_id = t.technician_id WHERE d.device_serial_number = ? "); $stmt->execute([$usbSerialNumber]); @@ -165,7 +165,7 @@ // Insert session $stmt = $pdo->prepare(" - INSERT INTO active_sessions ( + INSERT INTO `" . t('active_sessions') . "` ( technician_id, session_token, created_at, expires_at, is_active, auth_method, usb_device_id, computer_name ) VALUES (?, ?, NOW(), ?, 1, 'usb', ?, ?) @@ -180,7 +180,7 @@ // Update USB device last used info $stmt = $pdo->prepare(" - UPDATE usb_devices + UPDATE `" . t('usb_devices') . "` SET last_used_date = NOW(), last_used_ip = ?, last_used_computer_name = ?, @@ -191,7 +191,7 @@ // Update technician last login $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET last_login = NOW(), failed_login_attempts = 0, locked_until = NULL diff --git a/FINAL_PRODUCTION_SYSTEM/api/change-password.php b/FINAL_PRODUCTION_SYSTEM/api/change-password.php index 1fbaa35..d3449ec 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/change-password.php +++ b/FINAL_PRODUCTION_SYSTEM/api/change-password.php @@ -29,7 +29,7 @@ try { // Get technician details $stmt = $pdo->prepare(" - SELECT * FROM technicians + SELECT * FROM `" . t('technicians') . "` WHERE technician_id = ? AND is_active = 1 "); $stmt->execute([$technician_id]); @@ -63,7 +63,7 @@ $new_password_hash = password_hash($new_password, PASSWORD_BCRYPT, ['cost' => BCRYPT_COST]); $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET password_hash = ?, temp_password = NULL, must_change_password = FALSE WHERE technician_id = ? "); diff --git a/FINAL_PRODUCTION_SYSTEM/api/collect-hardware-v2.php b/FINAL_PRODUCTION_SYSTEM/api/collect-hardware-v2.php index 0568dbd..e839e40 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/collect-hardware-v2.php +++ b/FINAL_PRODUCTION_SYSTEM/api/collect-hardware-v2.php @@ -26,8 +26,8 @@ // Validate session token and get technician info $stmt = $pdo->prepare(" SELECT s.technician_id, t.full_name, s.expires_at - FROM active_sessions s - INNER JOIN technicians t ON s.technician_id = t.technician_id + FROM `" . t('active_sessions') . "` s + INNER JOIN `" . t('technicians') . "` t ON s.technician_id = t.technician_id WHERE s.session_token = ? AND s.expires_at > NOW() LIMIT 1 @@ -44,7 +44,7 @@ // Check if hardware info already exists for this order number $stmt = $pdo->prepare(" SELECT id, collection_timestamp - FROM hardware_info + FROM `" . t('hardware_info') . "` WHERE order_number = ? ORDER BY collection_timestamp DESC LIMIT 1 @@ -164,7 +164,7 @@ // Insert hardware information $stmt = $pdo->prepare(" - INSERT INTO hardware_info ( + INSERT INTO `" . t('hardware_info') . "` ( activation_id, order_number, technician_id, session_token, motherboard_manufacturer, motherboard_product, motherboard_serial, motherboard_version, bios_manufacturer, bios_version, bios_release_date, bios_serial_number, @@ -280,7 +280,7 @@ // Log the collection attempt $stmt = $pdo->prepare(" - INSERT INTO hardware_collection_log ( + INSERT INTO `" . t('hardware_collection_log') . "` ( order_number, technician_id, session_token, hardware_info_id, collection_status ) VALUES (?, ?, ?, ?, 'success') "); @@ -316,7 +316,7 @@ try { if (isset($technicianId) && isset($orderNumber) && isset($sessionToken)) { $stmt = $pdo->prepare(" - INSERT INTO hardware_collection_log ( + INSERT INTO `" . t('hardware_collection_log') . "` ( order_number, technician_id, session_token, hardware_info_id, collection_status, error_message ) VALUES (?, ?, ?, NULL, 'failed', ?) diff --git a/FINAL_PRODUCTION_SYSTEM/api/download-resource.php b/FINAL_PRODUCTION_SYSTEM/api/download-resource.php index 509052c..02048a1 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/download-resource.php +++ b/FINAL_PRODUCTION_SYSTEM/api/download-resource.php @@ -30,7 +30,7 @@ // Validate session token $stmt = $pdo->prepare(" SELECT s.technician_id - FROM active_sessions s + FROM `" . t('active_sessions') . "` s WHERE s.session_token = ? AND s.expires_at > NOW() "); $stmt->execute([$sessionToken]); @@ -43,7 +43,7 @@ } // Look up the resource - $stmt = $pdo->prepare("SELECT * FROM client_resources WHERE resource_key = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('client_resources') . "` WHERE resource_key = ?"); $stmt->execute([$resourceKey]); $resource = $stmt->fetch(PDO::FETCH_ASSOC); diff --git a/FINAL_PRODUCTION_SYSTEM/api/get-alt-server-config.php b/FINAL_PRODUCTION_SYSTEM/api/get-alt-server-config.php index fac23f3..519bca3 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/get-alt-server-config.php +++ b/FINAL_PRODUCTION_SYSTEM/api/get-alt-server-config.php @@ -23,8 +23,8 @@ // Verify valid session and get technician preferences $stmt = $pdo->prepare(" SELECT s.technician_id, t.preferred_server - FROM active_sessions s - INNER JOIN technicians t ON s.technician_id = t.technician_id + FROM `" . t('active_sessions') . "` s + INNER JOIN `" . t('technicians') . "` t ON s.technician_id = t.technician_id WHERE s.session_token = ? AND s.expires_at > NOW() "); $stmt->execute([$sessionToken]); @@ -38,7 +38,7 @@ // Helper function to get config value function getConfig($key) { global $pdo; - $stmt = $pdo->prepare("SELECT config_value FROM system_config WHERE config_key = ?"); + $stmt = $pdo->prepare("SELECT config_value FROM `" . t('system_config') . "` WHERE config_key = ?"); $stmt->execute([$key]); $result = $stmt->fetch(PDO::FETCH_ASSOC); return $result ? $result['config_value'] : null; diff --git a/FINAL_PRODUCTION_SYSTEM/api/get-client-config.php b/FINAL_PRODUCTION_SYSTEM/api/get-client-config.php index 758ad8f..86f924b 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/get-client-config.php +++ b/FINAL_PRODUCTION_SYSTEM/api/get-client-config.php @@ -23,7 +23,7 @@ // Verify valid session $stmt = $pdo->prepare(" SELECT s.technician_id - FROM active_sessions s + FROM `" . t('active_sessions') . "` s WHERE s.session_token = ? AND s.expires_at > NOW() "); $stmt->execute([$sessionToken]); diff --git a/FINAL_PRODUCTION_SYSTEM/api/get-key.php b/FINAL_PRODUCTION_SYSTEM/api/get-key.php index 24c37fc..5cde2f4 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/get-key.php +++ b/FINAL_PRODUCTION_SYSTEM/api/get-key.php @@ -21,7 +21,7 @@ if (qcIsEnabled($pdo)) { $globalSettings = qcGetGlobalSettings($pdo); if (!empty($globalSettings['blocking_prevents_key'])) { - $hwStmt = $pdo->prepare("SELECT id FROM hardware_info WHERE order_number = ? ORDER BY collection_timestamp DESC LIMIT 1"); + $hwStmt = $pdo->prepare("SELECT id FROM `" . t('hardware_info') . "` WHERE order_number = ? ORDER BY collection_timestamp DESC LIMIT 1"); $hwStmt->execute([$order_number]); $hwRow = $hwStmt->fetch(PDO::FETCH_ASSOC); if ($hwRow && qcHasBlockingIssues($pdo, (int) $hwRow['id'])) { @@ -47,7 +47,7 @@ // Update existing session with new order number if different if ($existing_session['order_number'] !== $order_number) { $stmt = $pdo->prepare(" - UPDATE active_sessions + UPDATE `" . t('active_sessions') . "` SET order_number = ?, expires_at = DATE_ADD(NOW(), INTERVAL ? MINUTE) WHERE id = ? "); @@ -74,7 +74,7 @@ $pdo->rollback(); // Check if ANY keys exist vs. all keys exhausted (for automatic failover) - $stmt = $pdo->prepare("SELECT COUNT(*) as available_count FROM oem_keys WHERE key_status IN ('unused', 'retry')"); + $stmt = $pdo->prepare("SELECT COUNT(*) as available_count FROM `" . t('oem_keys') . "` WHERE key_status IN ('unused', 'retry')"); $stmt->execute(); $availableCount = $stmt->fetch(PDO::FETCH_ASSOC)['available_count']; @@ -104,7 +104,7 @@ // Insert new session (we already checked for existing sessions above) $stmt = $pdo->prepare(" - INSERT INTO active_sessions (technician_id, session_token, key_id, order_number, expires_at, auth_method, computer_name) + INSERT INTO `" . t('active_sessions') . "` (technician_id, session_token, key_id, order_number, expires_at, auth_method, computer_name) VALUES (?, ?, ?, ?, ?, 'password', ?) "); $stmt->execute([$technician_id, $session_token, $key['id'], $order_number, $expires_at, $computerName]); @@ -121,7 +121,7 @@ // Check key pool levels and send alerts if needed try { $edition = $key['product_type'] ?? 'Unknown'; - $poolStmt = $pdo->prepare("SELECT COUNT(*) as remaining FROM oem_keys WHERE key_status IN ('unused', 'retry') AND product_type = ?"); + $poolStmt = $pdo->prepare("SELECT COUNT(*) as remaining FROM `" . t('oem_keys') . "` WHERE key_status IN ('unused', 'retry') AND product_type = ?"); $poolStmt->execute([$edition]); $remaining = (int)$poolStmt->fetch()['remaining']; diff --git a/FINAL_PRODUCTION_SYSTEM/api/import-csv.php b/FINAL_PRODUCTION_SYSTEM/api/import-csv.php index 98aa1a3..9f1b995 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/import-csv.php +++ b/FINAL_PRODUCTION_SYSTEM/api/import-csv.php @@ -66,7 +66,7 @@ // Try to insert key try { $stmt = $pdo->prepare(" - INSERT INTO oem_keys (product_key, oem_identifier, barcode, key_status, roll_serial) + INSERT INTO `" . t('oem_keys') . "` (product_key, oem_identifier, barcode, key_status, roll_serial) VALUES (?, ?, ?, ?, 'imported') "); $stmt->execute([$product_key, $oem_identifier, $barcode, $key_status]); diff --git a/FINAL_PRODUCTION_SYSTEM/api/login.php b/FINAL_PRODUCTION_SYSTEM/api/login.php index 3ce3275..7734621 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/login.php +++ b/FINAL_PRODUCTION_SYSTEM/api/login.php @@ -16,7 +16,7 @@ try { // Get technician details (including language preference) $stmt = $pdo->prepare(" - SELECT * FROM technicians + SELECT * FROM `" . t('technicians') . "` WHERE technician_id = ? AND is_active = 1 "); $stmt->execute([$technician_id]); @@ -64,7 +64,7 @@ } $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET failed_login_attempts = ?, locked_until = ? WHERE technician_id = ? "); @@ -94,7 +94,7 @@ // Login successful - reset failed attempts $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET failed_login_attempts = 0, locked_until = NULL, last_login = NOW() WHERE technician_id = ? "); @@ -137,7 +137,7 @@ // Include active product lines for order type selection try { - $plStmt = $pdo->query("SELECT id, name, order_pattern, description FROM product_lines WHERE is_active = 1 ORDER BY name ASC"); + $plStmt = $pdo->query("SELECT id, name, order_pattern, description FROM `" . t('product_lines') . "` WHERE is_active = 1 ORDER BY name ASC"); $productLines = $plStmt->fetchAll(PDO::FETCH_ASSOC); if (!empty($productLines)) { $response['product_lines'] = array_map(function($pl) { diff --git a/FINAL_PRODUCTION_SYSTEM/api/middleware/RateLimiter.php b/FINAL_PRODUCTION_SYSTEM/api/middleware/RateLimiter.php index 19d5177..7d2e083 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/middleware/RateLimiter.php +++ b/FINAL_PRODUCTION_SYSTEM/api/middleware/RateLimiter.php @@ -140,7 +140,7 @@ public function logViolation($identifier, $action, $endpoint, $requestCount, $li try { $stmt = $pdo->prepare(" - INSERT INTO rate_limit_violations ( + INSERT INTO `" . t('rate_limit_violations') . "` ( identifier, action, endpoint, client_ip, user_agent, request_count, limit_threshold, window_seconds ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) diff --git a/FINAL_PRODUCTION_SYSTEM/api/report-result.php b/FINAL_PRODUCTION_SYSTEM/api/report-result.php index 579e1ff..d199610 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/report-result.php +++ b/FINAL_PRODUCTION_SYSTEM/api/report-result.php @@ -126,7 +126,7 @@ function validateAPIAccess(): bool { } // NEW: Check if unique ID already exists (prevent duplicates) -$stmt = $pdo->prepare("SELECT id FROM activation_attempts WHERE activation_unique_id = ?"); +$stmt = $pdo->prepare("SELECT id FROM `" . t('activation_attempts') . "` WHERE activation_unique_id = ?"); $stmt->execute([$activationUniqueId]); if ($stmt->fetch()) { jsonResponse([ @@ -156,7 +156,7 @@ function validateAPIAccess(): bool { // Record activation attempt with all required fields $stmt = $pdo->prepare(" - INSERT INTO activation_attempts ( + INSERT INTO `" . t('activation_attempts') . "` ( key_id, technician_id, order_number, @@ -203,7 +203,7 @@ function validateAPIAccess(): bool { if ($result === 'success') { // Success path: Mark key as good and deactivate session $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = 'good', updated_at = NOW() WHERE id = ? @@ -212,7 +212,7 @@ function validateAPIAccess(): bool { // Deactivate session (activation complete) $stmt = $pdo->prepare(" - UPDATE active_sessions + UPDATE `" . t('active_sessions') . "` SET is_active = 0 WHERE id = ? "); @@ -226,7 +226,7 @@ function validateAPIAccess(): bool { } else { // Failure path: Update fail counter and determine key status $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET fail_counter = fail_counter + 1, updated_at = NOW() WHERE id = ? @@ -236,7 +236,7 @@ function validateAPIAccess(): bool { // Get updated fail counter $stmt = $pdo->prepare(" SELECT fail_counter, product_key, oem_identifier - FROM oem_keys + FROM `" . t('oem_keys') . "` WHERE id = ? "); $stmt->execute([$session['key_id']]); @@ -253,7 +253,7 @@ function validateAPIAccess(): bool { if ($failCounter >= $maxAttempts) { // Mark as bad after max failures $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = 'bad' WHERE id = ? "); @@ -264,7 +264,7 @@ function validateAPIAccess(): bool { // Deactivate session (key is bad) $stmt = $pdo->prepare(" - UPDATE active_sessions + UPDATE `" . t('active_sessions') . "` SET is_active = 0 WHERE id = ? "); @@ -275,7 +275,7 @@ function validateAPIAccess(): bool { } else { // Mark for retry $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = 'retry' WHERE id = ? "); @@ -382,7 +382,7 @@ function sendEmailNotification( if ($keyData === null) { $stmt = $pdo->prepare(" SELECT product_key, oem_identifier, fail_counter, key_status - FROM oem_keys + FROM `" . t('oem_keys') . "` WHERE id = ? "); $stmt->execute([$session['key_id']]); @@ -396,7 +396,7 @@ function sendEmailNotification( // Get technician full name $stmt = $pdo->prepare(" SELECT full_name, email - FROM technicians + FROM `" . t('technicians') . "` WHERE technician_id = ? "); $stmt->execute([$session['technician_id']]); diff --git a/FINAL_PRODUCTION_SYSTEM/api/submit-hardware.php b/FINAL_PRODUCTION_SYSTEM/api/submit-hardware.php index e22d856..bb4496b 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/submit-hardware.php +++ b/FINAL_PRODUCTION_SYSTEM/api/submit-hardware.php @@ -47,8 +47,8 @@ // Validate session token and get activation_id $stmt = $pdo->prepare(" SELECT aa.id as activation_id, aa.technician_id, aa.key_id - FROM activation_attempts aa - INNER JOIN active_sessions s ON s.technician_id = aa.technician_id + FROM `" . t('activation_attempts') . "` aa + INNER JOIN `" . t('active_sessions') . "` s ON s.technician_id = aa.technician_id WHERE s.session_token = ? AND aa.order_number = ? AND aa.attempt_result = 'success' @@ -66,7 +66,7 @@ $activationId = $activation['activation_id']; // Check if hardware info already exists for this activation - $stmt = $pdo->prepare("SELECT id FROM hardware_info WHERE activation_id = ?"); + $stmt = $pdo->prepare("SELECT id FROM `" . t('hardware_info') . "` WHERE activation_id = ?"); $stmt->execute([$activationId]); if ($stmt->fetch()) { jsonResponse(['success' => true, 'message' => 'Hardware information already recorded', 'duplicate' => true]); @@ -77,7 +77,7 @@ // Insert hardware information $stmt = $pdo->prepare(" - INSERT INTO hardware_info ( + INSERT INTO `" . t('hardware_info') . "` ( activation_id, order_number, motherboard_manufacturer, @@ -188,7 +188,7 @@ ]); // Update activation_attempts to mark hardware as collected - $stmt = $pdo->prepare("UPDATE activation_attempts SET hardware_collected = 1 WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('activation_attempts') . "` SET hardware_collected = 1 WHERE id = ?"); $stmt->execute([$activationId]); $hardwareId = $pdo->lastInsertId(); diff --git a/FINAL_PRODUCTION_SYSTEM/api/totp-disable.php b/FINAL_PRODUCTION_SYSTEM/api/totp-disable.php index 2148be3..9d59c58 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/totp-disable.php +++ b/FINAL_PRODUCTION_SYSTEM/api/totp-disable.php @@ -62,7 +62,7 @@ // Code verified - disable 2FA $stmt = $pdo->prepare(" - UPDATE admin_totp_secrets + UPDATE `" . t('admin_totp_secrets') . "` SET totp_enabled = 0 WHERE admin_id = ? "); @@ -70,7 +70,7 @@ // Log activity $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log (admin_id, session_id, action, description, ip_address, user_agent) + INSERT INTO `" . t('admin_activity_log') . "` (admin_id, session_id, action, description, ip_address, user_agent) VALUES (?, ?, 'TOTP_DISABLED', '2FA disabled by user', ?, ?) "); $stmt->execute([ diff --git a/FINAL_PRODUCTION_SYSTEM/api/totp-regenerate-backup-codes.php b/FINAL_PRODUCTION_SYSTEM/api/totp-regenerate-backup-codes.php index 0341507..796b8ef 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/totp-regenerate-backup-codes.php +++ b/FINAL_PRODUCTION_SYSTEM/api/totp-regenerate-backup-codes.php @@ -65,7 +65,7 @@ // Update database $stmt = $pdo->prepare(" - UPDATE admin_totp_secrets + UPDATE `" . t('admin_totp_secrets') . "` SET backup_codes = ? WHERE admin_id = ? "); @@ -76,7 +76,7 @@ // Log activity $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log (admin_id, session_id, action, description, ip_address, user_agent) + INSERT INTO `" . t('admin_activity_log') . "` (admin_id, session_id, action, description, ip_address, user_agent) VALUES (?, ?, 'TOTP_BACKUP_REGEN', 'Regenerated 2FA backup codes', ?, ?) "); $stmt->execute([ diff --git a/FINAL_PRODUCTION_SYSTEM/api/totp-setup.php b/FINAL_PRODUCTION_SYSTEM/api/totp-setup.php index a6f799c..9e8ca57 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/totp-setup.php +++ b/FINAL_PRODUCTION_SYSTEM/api/totp-setup.php @@ -24,7 +24,7 @@ // Verify session is valid in DB $stmt = $pdo->prepare(" - SELECT admin_id FROM admin_sessions + SELECT admin_id FROM `" . t('admin_sessions') . "` WHERE id = ? AND admin_id = ? AND is_active = 1 "); $stmt->execute([$sessionId, $adminId]); @@ -33,7 +33,7 @@ } // Get admin info -$stmt = $pdo->prepare("SELECT username, email FROM admin_users WHERE id = ?"); +$stmt = $pdo->prepare("SELECT username, email FROM `" . t('admin_users') . "` WHERE id = ?"); $stmt->execute([$adminId]); $admin = $stmt->fetch(PDO::FETCH_ASSOC); @@ -75,7 +75,7 @@ // Store in database (not yet enabled) if ($existing) { $stmt = $pdo->prepare(" - UPDATE admin_totp_secrets + UPDATE `" . t('admin_totp_secrets') . "` SET totp_secret = ?, backup_codes = ?, totp_enabled = 0, verified_at = NULL, created_at = NOW() WHERE admin_id = ? "); @@ -86,7 +86,7 @@ ]); } else { $stmt = $pdo->prepare(" - INSERT INTO admin_totp_secrets (admin_id, totp_secret, backup_codes, totp_enabled) + INSERT INTO `" . t('admin_totp_secrets') . "` (admin_id, totp_secret, backup_codes, totp_enabled) VALUES (?, ?, ?, 0) "); $stmt->execute([ @@ -108,7 +108,7 @@ // Log activity $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log (admin_id, session_id, action, description, ip_address, user_agent) + INSERT INTO `" . t('admin_activity_log') . "` (admin_id, session_id, action, description, ip_address, user_agent) VALUES (?, ?, 'TOTP_SETUP', 'Started 2FA setup', ?, ?) "); $stmt->execute([ diff --git a/FINAL_PRODUCTION_SYSTEM/api/totp-verify.php b/FINAL_PRODUCTION_SYSTEM/api/totp-verify.php index 93196a6..441ec30 100644 --- a/FINAL_PRODUCTION_SYSTEM/api/totp-verify.php +++ b/FINAL_PRODUCTION_SYSTEM/api/totp-verify.php @@ -69,7 +69,7 @@ // If this is initial setup verification, enable 2FA if ($isSetup && $totpData['totp_enabled'] == 0) { $stmt = $pdo->prepare(" - UPDATE admin_totp_secrets + UPDATE `" . t('admin_totp_secrets') . "` SET totp_enabled = 1, verified_at = NOW() WHERE admin_id = ? "); @@ -77,7 +77,7 @@ // Log activity $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log (admin_id, session_id, action, description, ip_address, user_agent) + INSERT INTO `" . t('admin_activity_log') . "` (admin_id, session_id, action, description, ip_address, user_agent) VALUES (?, NULL, 'TOTP_ENABLED', '2FA successfully enabled', ?, ?) "); $stmt->execute([ @@ -89,7 +89,7 @@ // Log successful verification $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log (admin_id, session_id, action, description, ip_address, user_agent, totp_verified) + INSERT INTO `" . t('admin_activity_log') . "` (admin_id, session_id, action, description, ip_address, user_agent, totp_verified) VALUES (?, NULL, 'TOTP_VERIFIED', ?, ?, ?, 1) "); $stmt->execute([ diff --git a/FINAL_PRODUCTION_SYSTEM/config-production.php b/FINAL_PRODUCTION_SYSTEM/config-production.php index e2850c2..8d004f9 100644 --- a/FINAL_PRODUCTION_SYSTEM/config-production.php +++ b/FINAL_PRODUCTION_SYSTEM/config-production.php @@ -89,7 +89,7 @@ function getConfig($key, $useCache = true) { } try { - $stmt = $pdo->prepare("SELECT config_value FROM system_config WHERE config_key = ?"); + $stmt = $pdo->prepare("SELECT config_value FROM `" . t('system_config') . "` WHERE config_key = ?"); $stmt->execute([$key]); $result = $stmt->fetch(); $value = $result ? $result['config_value'] : null; @@ -192,9 +192,9 @@ function validateSession($token) { try { $stmt = $pdo->prepare(" SELECT s.*, k.product_key, k.key_status, t.is_active as tech_active - FROM active_sessions s - LEFT JOIN oem_keys k ON s.key_id = k.id - LEFT JOIN technicians t ON s.technician_id = t.technician_id + FROM `" . t('active_sessions') . "` s + LEFT JOIN `" . t('oem_keys') . "` k ON s.key_id = k.id + LEFT JOIN `" . t('technicians') . "` t ON s.technician_id = t.technician_id WHERE s.session_token = ? AND s.is_active = 1 AND s.expires_at > NOW() @@ -233,7 +233,7 @@ function allocateKeyAtomically($pdo, $technician_id, $order_number) { // Select and lock the best available key $stmt = $pdo->prepare(" - SELECT * FROM oem_keys + SELECT * FROM `" . t('oem_keys') . "` WHERE key_status IN ('unused', 'retry') AND (fail_counter < 3 OR key_status = 'unused') ORDER BY @@ -250,7 +250,7 @@ function allocateKeyAtomically($pdo, $technician_id, $order_number) { if ($key) { // Mark key as in use immediately $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = 'allocated', last_use_date = CURDATE(), last_use_time = CURTIME(), @@ -295,7 +295,7 @@ function allocateKeyAtomically($pdo, $technician_id, $order_number) { function cleanupExpiredSessions($pdo) { try { $stmt = $pdo->prepare(" - UPDATE active_sessions + UPDATE `" . t('active_sessions') . "` SET is_active = 0 WHERE expires_at < NOW() AND is_active = 1 LIMIT 1000 @@ -321,8 +321,8 @@ function getActiveSession($pdo, $technician_id) { $stmt = $pdo->prepare(" SELECT s.*, k.product_key, k.oem_identifier, k.key_status, k.fail_counter - FROM active_sessions s - LEFT JOIN oem_keys k ON s.key_id = k.id + FROM `" . t('active_sessions') . "` s + LEFT JOIN `" . t('oem_keys') . "` k ON s.key_id = k.id WHERE s.technician_id = ? AND s.is_active = 1 AND s.expires_at > NOW() diff --git a/FINAL_PRODUCTION_SYSTEM/config.php b/FINAL_PRODUCTION_SYSTEM/config.php index 6268dfd..29304e0 100644 --- a/FINAL_PRODUCTION_SYSTEM/config.php +++ b/FINAL_PRODUCTION_SYSTEM/config.php @@ -108,7 +108,7 @@ function getConfig($key, $useCache = true) { } try { - $stmt = $pdo->prepare("SELECT config_value FROM system_config WHERE config_key = ?"); + $stmt = $pdo->prepare("SELECT config_value FROM `" . t('system_config') . "` WHERE config_key = ?"); $stmt->execute([$key]); $result = $stmt->fetch(); $value = $result ? $result['config_value'] : null; diff --git a/FINAL_PRODUCTION_SYSTEM/config/config-template-enhanced.php b/FINAL_PRODUCTION_SYSTEM/config/config-template-enhanced.php index 05474de..289a853 100644 --- a/FINAL_PRODUCTION_SYSTEM/config/config-template-enhanced.php +++ b/FINAL_PRODUCTION_SYSTEM/config/config-template-enhanced.php @@ -46,7 +46,7 @@ function getConfig($key, $default = null) { global $pdo; try { - $stmt = $pdo->prepare("SELECT config_value FROM system_config WHERE config_key = ?"); + $stmt = $pdo->prepare("SELECT config_value FROM `" . t('system_config') . "` WHERE config_key = ?"); $stmt->execute([$key]); $result = $stmt->fetch(); return $result ? $result['config_value'] : $default; @@ -61,7 +61,7 @@ function setConfig($key, $value, $description = '') { global $pdo; try { $stmt = $pdo->prepare(" - INSERT INTO system_config (config_key, config_value, description) + INSERT INTO `" . t('system_config') . "` (config_key, config_value, description) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE config_value = VALUES(config_value), @@ -102,7 +102,7 @@ function validateTechnician($technician_id, $password) { try { $stmt = $pdo->prepare(" - SELECT * FROM technicians + SELECT * FROM `" . t('technicians') . "` WHERE technician_id = ? AND is_active = 1 "); $stmt->execute([$technician_id]); @@ -121,7 +121,7 @@ function validateTechnician($technician_id, $password) { if (password_verify($password, $technician['password_hash'])) { // Reset failed attempts on successful login $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET failed_login_attempts = 0, locked_until = NULL, last_login = NOW() WHERE technician_id = ? "); @@ -132,7 +132,7 @@ function validateTechnician($technician_id, $password) { // Increment failed attempts $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET failed_login_attempts = failed_login_attempts + 1, locked_until = IF(failed_login_attempts + 1 >= 5, DATE_ADD(NOW(), INTERVAL 15 MINUTE), NULL) WHERE technician_id = ? diff --git a/FINAL_PRODUCTION_SYSTEM/constants.php b/FINAL_PRODUCTION_SYSTEM/constants.php index fdb4101..45fc95e 100644 --- a/FINAL_PRODUCTION_SYSTEM/constants.php +++ b/FINAL_PRODUCTION_SYSTEM/constants.php @@ -7,6 +7,11 @@ * Import this file wherever constants are needed. */ +// ── DB table prefix helper (must load before any PDO query) ──────── +// Empty default for backward-compat with installs that pre-date the +// prefix release. The web installer overwrites DB_PREFIX in config.php. +require_once __DIR__ . '/functions/db-helpers.php'; + // ── Authentication ───────────────────────────────────────────────── define('BCRYPT_COST', 12); define('PASSWORD_MIN_LENGTH', 8); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/AclController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/AclController.php index a05b65d..8c9e914 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/AclController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/AclController.php @@ -62,7 +62,7 @@ function handle_acl_create_role(PDO $pdo, array $admin_session, ?array $json_inp } // Rate limit: max 20 custom roles - $stmt = $pdo->prepare("SELECT COUNT(*) FROM acl_roles WHERE is_system_role = 0"); + $stmt = $pdo->prepare("SELECT COUNT(*) FROM `" . t('acl_roles') . "` WHERE is_system_role = 0"); $stmt->execute(); if ((int)$stmt->fetchColumn() >= 20) { jsonResponse(['success' => false, 'error' => 'Maximum custom roles limit reached (20)']); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/BackupsController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/BackupsController.php index 89a5d0c..78f283e 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/BackupsController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/BackupsController.php @@ -8,7 +8,7 @@ function handle_list_backups(PDO $pdo, array $admin_session): void { requirePermission('view_backups', $admin_session); $stmt = $pdo->query(" - SELECT * FROM backup_history + SELECT * FROM `" . t('backup_history') . "` ORDER BY created_at DESC LIMIT 50 "); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/BrandingController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/BrandingController.php index ea96a58..a23d8ea 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/BrandingController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/BrandingController.php @@ -140,7 +140,7 @@ function handle_upload_brand_asset(PDO $pdo, array $admin_session): void { // Store relative path in system_config $relativePath = 'uploads/branding/' . $storedFilename; $stmt = $pdo->prepare(" - INSERT INTO system_config (config_key, config_value, description, updated_at) + INSERT INTO `" . t('system_config') . "` (config_key, config_value, description, updated_at) VALUES (?, ?, '', NOW()) ON DUPLICATE KEY UPDATE config_value = ?, updated_at = NOW() "); @@ -181,7 +181,7 @@ function handle_delete_brand_asset(PDO $pdo, array $admin_session, ?array $json_ // Clear config value $stmt = $pdo->prepare(" - INSERT INTO system_config (config_key, config_value, description, updated_at) + INSERT INTO `" . t('system_config') . "` (config_key, config_value, description, updated_at) VALUES (?, '', '', NOW()) ON DUPLICATE KEY UPDATE config_value = '', updated_at = NOW() "); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ClientResourcesController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ClientResourcesController.php index 5447c94..a9ce0e0 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ClientResourcesController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ClientResourcesController.php @@ -68,7 +68,7 @@ function handle_upload_client_resource(PDO $pdo, array $admin_session): void { $destPath = $uploadDir . '/' . $storedFilename; // Delete existing resource with same key (replace mode) - $existing = $pdo->prepare("SELECT filename FROM client_resources WHERE resource_key = ?"); + $existing = $pdo->prepare("SELECT filename FROM `" . t('client_resources') . "` WHERE resource_key = ?"); $existing->execute([$resourceKey]); $oldFile = $existing->fetchColumn(); if ($oldFile) { @@ -76,7 +76,7 @@ function handle_upload_client_resource(PDO $pdo, array $admin_session): void { if (file_exists($oldPath)) { unlink($oldPath); } - $pdo->prepare("DELETE FROM client_resources WHERE resource_key = ?")->execute([$resourceKey]); + $pdo->prepare("DELETE FROM `" . t('client_resources') . "` WHERE resource_key = ?")->execute([$resourceKey]); } // Move uploaded file @@ -95,7 +95,7 @@ function handle_upload_client_resource(PDO $pdo, array $admin_session): void { // Insert DB record $stmt = $pdo->prepare(" - INSERT INTO client_resources (resource_key, filename, original_filename, file_size, mime_type, checksum_sha256, description, uploaded_by) + INSERT INTO `" . t('client_resources') . "` (resource_key, filename, original_filename, file_size, mime_type, checksum_sha256, description, uploaded_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?) "); $stmt->execute([$resourceKey, $storedFilename, $originalName, $fileSize, $mimeType, $checksum, $description, $adminId]); @@ -134,7 +134,7 @@ function handle_delete_client_resource(PDO $pdo, array $admin_session, ?array $j return; } - $stmt = $pdo->prepare("SELECT filename FROM client_resources WHERE resource_key = ?"); + $stmt = $pdo->prepare("SELECT filename FROM `" . t('client_resources') . "` WHERE resource_key = ?"); $stmt->execute([$resourceKey]); $filename = $stmt->fetchColumn(); @@ -151,7 +151,7 @@ function handle_delete_client_resource(PDO $pdo, array $admin_session, ?array $j } // Delete DB record - $pdo->prepare("DELETE FROM client_resources WHERE resource_key = ?")->execute([$resourceKey]); + $pdo->prepare("DELETE FROM `" . t('client_resources') . "` WHERE resource_key = ?")->execute([$resourceKey]); logAdminActivity( $admin_session['admin_id'], @@ -172,8 +172,8 @@ function handle_list_client_resources(PDO $pdo, array $admin_session): void { $stmt = $pdo->prepare(" SELECT cr.*, au.username AS uploaded_by_name - FROM client_resources cr - LEFT JOIN admin_users au ON cr.uploaded_by = au.id + FROM `" . t('client_resources') . "` cr + LEFT JOIN `" . t('admin_users') . "` au ON cr.uploaded_by = au.id ORDER BY cr.created_at DESC "); $stmt->execute(); @@ -200,7 +200,7 @@ function handle_download_client_resource(PDO $pdo, array $admin_session): void { return; } - $stmt = $pdo->prepare("SELECT filename, original_filename, mime_type, file_size, checksum_sha256 FROM client_resources WHERE resource_key = ?"); + $stmt = $pdo->prepare("SELECT filename, original_filename, mime_type, file_size, checksum_sha256 FROM `" . t('client_resources') . "` WHERE resource_key = ?"); $stmt->execute([$resourceKey]); $resource = $stmt->fetch(PDO::FETCH_ASSOC); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ComplianceController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ComplianceController.php index 6c4395a..94a4350 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ComplianceController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ComplianceController.php @@ -23,7 +23,7 @@ function handle_qc_save_settings(PDO $pdo, array $admin_session, ?array $json_in foreach ($allowedKeys as $key) { if (isset($json_input[$key])) { - $stmt = $pdo->prepare("UPDATE qc_global_settings SET setting_value = ?, updated_by = ? WHERE setting_key = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('qc_global_settings') . "` SET setting_value = ?, updated_by = ? WHERE setting_key = ?"); $stmt->execute([$json_input[$key], $admin_session['admin_id'], $key]); } } @@ -95,7 +95,7 @@ function handle_qc_list_motherboards(PDO $pdo, array $admin_session, ?array $jso unset($row); // Distinct manufacturers for filter dropdown - $mfrs = $pdo->query("SELECT DISTINCT manufacturer FROM qc_motherboard_registry ORDER BY manufacturer")->fetchAll(PDO::FETCH_COLUMN); + $mfrs = $pdo->query("SELECT DISTINCT manufacturer FROM `" . t('qc_motherboard_registry') . "` ORDER BY manufacturer")->fetchAll(PDO::FETCH_COLUMN); jsonResponse([ 'success' => true, @@ -111,7 +111,7 @@ function handle_qc_get_motherboard(PDO $pdo, array $admin_session, ?array $json_ requirePermission('view_compliance', $admin_session); $id = (int) ($_GET['id'] ?? 0); - $stmt = $pdo->prepare("SELECT * FROM qc_motherboard_registry WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('qc_motherboard_registry') . "` WHERE id = ?"); $stmt->execute([$id]); $board = $stmt->fetch(PDO::FETCH_ASSOC); @@ -161,7 +161,7 @@ function handle_qc_update_motherboard(PDO $pdo, array $admin_session, ?array $js $params[] = $admin_session['admin_id']; $params[] = $id; - $stmt = $pdo->prepare("UPDATE qc_motherboard_registry SET " . implode(", ", $fields) . " WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('qc_motherboard_registry') . "` SET " . implode(", ", $fields) . " WHERE id = ?"); $stmt->execute($params); logAdminActivity($admin_session['admin_id'], $admin_session['id'], 'QC_MOTHERBOARD_UPDATE', "Updated motherboard registry #$id"); @@ -174,14 +174,14 @@ function handle_qc_list_manufacturers(PDO $pdo, array $admin_session, ?array $js requirePermission('view_compliance', $admin_session); // Configured manufacturers - $stmt = $pdo->query("SELECT * FROM qc_manufacturer_defaults ORDER BY manufacturer"); + $stmt = $pdo->query("SELECT * FROM `" . t('qc_manufacturer_defaults') . "` ORDER BY manufacturer"); $configured = $stmt->fetchAll(PDO::FETCH_ASSOC); // Unconfigured: manufacturers seen in registry but no defaults entry $stmt = $pdo->query(" SELECT DISTINCT r.manufacturer - FROM qc_motherboard_registry r - LEFT JOIN qc_manufacturer_defaults md ON r.manufacturer = md.manufacturer + FROM `" . t('qc_motherboard_registry') . "` r + LEFT JOIN `" . t('qc_manufacturer_defaults') . "` md ON r.manufacturer = md.manufacturer WHERE md.id IS NULL ORDER BY r.manufacturer "); @@ -200,7 +200,7 @@ function handle_qc_update_manufacturer(PDO $pdo, array $admin_session, ?array $j } $stmt = $pdo->prepare(" - INSERT INTO qc_manufacturer_defaults (manufacturer, secure_boot_required, secure_boot_enforcement, min_bios_version, recommended_bios_version, bios_enforcement, hackbgrt_enforcement, notes, updated_by) + INSERT INTO `" . t('qc_manufacturer_defaults') . "` (manufacturer, secure_boot_required, secure_boot_enforcement, min_bios_version, recommended_bios_version, bios_enforcement, hackbgrt_enforcement, notes, updated_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE secure_boot_required = VALUES(secure_boot_required), @@ -454,7 +454,7 @@ function handle_qc_get_stats(PDO $pdo, array $admin_session, ?array $json_input requirePermission('view_compliance', $admin_session); // Result counts - $stmt = $pdo->query("SELECT check_result, COUNT(*) as cnt FROM qc_compliance_results GROUP BY check_result"); + $stmt = $pdo->query("SELECT check_result, COUNT(*) as cnt FROM `" . t('qc_compliance_results') . "` GROUP BY check_result"); $resultCounts = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); $total = array_sum($resultCounts); @@ -463,8 +463,8 @@ function handle_qc_get_stats(PDO $pdo, array $admin_session, ?array $json_input // Top failing boards $stmt = $pdo->query(" SELECT hi.motherboard_manufacturer, hi.motherboard_product, COUNT(*) as fail_count - FROM qc_compliance_results cr - JOIN hardware_info hi ON cr.hardware_info_id = hi.id + FROM `" . t('qc_compliance_results') . "` cr + JOIN `" . t('hardware_info') . "` hi ON cr.hardware_info_id = hi.id WHERE cr.check_result = 'fail' GROUP BY hi.motherboard_manufacturer, hi.motherboard_product ORDER BY fail_count DESC @@ -473,19 +473,19 @@ function handle_qc_get_stats(PDO $pdo, array $admin_session, ?array $json_input $topFailing = $stmt->fetchAll(PDO::FETCH_ASSOC); // Unresolved blocking - $stmt = $pdo->query("SELECT COUNT(DISTINCT hardware_info_id) FROM qc_compliance_results WHERE enforcement_level = 3 AND check_result = 'fail'"); + $stmt = $pdo->query("SELECT COUNT(DISTINCT hardware_info_id) FROM `" . t('qc_compliance_results') . "` WHERE enforcement_level = 3 AND check_result = 'fail'"); $unresolvedBlocking = (int) $stmt->fetchColumn(); // Registry stats - $stmt = $pdo->query("SELECT COUNT(*) FROM qc_motherboard_registry"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('qc_motherboard_registry') . "`"); $registeredBoards = (int) $stmt->fetchColumn(); - $stmt = $pdo->query("SELECT COUNT(*) FROM qc_manufacturer_defaults"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('qc_manufacturer_defaults') . "`"); $mfrsWithDefaults = (int) $stmt->fetchColumn(); // Check type breakdown $stmt = $pdo->query(" SELECT check_type, check_result, COUNT(*) as cnt - FROM qc_compliance_results + FROM `" . t('qc_compliance_results') . "` GROUP BY check_type, check_result "); $byType = []; diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/DashboardController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/DashboardController.php index 41ee81f..dee6f2c 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/DashboardController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/DashboardController.php @@ -17,7 +17,7 @@ function buildReportHtml(PDO $pdo, string $reportType): string { switch ($reportType) { case 'summary': - $stmt = $pdo->query("SELECT key_status, COUNT(*) as count FROM oem_keys GROUP BY key_status"); + $stmt = $pdo->query("SELECT key_status, COUNT(*) as count FROM `" . t('oem_keys') . "` GROUP BY key_status"); $keyStats = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); $totalKeys = array_sum($keyStats); @@ -32,7 +32,7 @@ function buildReportHtml(PDO $pdo, string $reportType): string { $html .= ''; // Technician summary - $stmt = $pdo->query("SELECT is_active, COUNT(*) as count FROM technicians GROUP BY is_active"); + $stmt = $pdo->query("SELECT is_active, COUNT(*) as count FROM `" . t('technicians') . "` GROUP BY is_active"); $techStats = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); $html .= '

' . __('keys.report_tech_summary') . '

'; $html .= ''; @@ -46,7 +46,7 @@ function buildReportHtml(PDO $pdo, string $reportType): string { SELECT DATE(attempted_date) as date, COUNT(*) as count, SUM(CASE WHEN attempt_result = 'success' THEN 1 ELSE 0 END) as successes, SUM(CASE WHEN attempt_result != 'success' THEN 1 ELSE 0 END) as failures - FROM activation_attempts + FROM `" . t('activation_attempts') . "` WHERE attempted_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY DATE(attempted_date) ORDER BY date DESC @@ -66,8 +66,8 @@ function buildReportHtml(PDO $pdo, string $reportType): string { $stmt = $pdo->query(" SELECT aa.attempted_date, aa.technician_id, aa.order_number, k.product_key, aa.notes - FROM activation_attempts aa - LEFT JOIN oem_keys k ON aa.key_id = k.id + FROM `" . t('activation_attempts') . "` aa + LEFT JOIN `" . t('oem_keys') . "` k ON aa.key_id = k.id WHERE aa.attempt_result != 'success' ORDER BY aa.attempted_date DESC LIMIT 100 @@ -94,7 +94,7 @@ function buildReportHtml(PDO $pdo, string $reportType): string { COUNT(*) as total, SUM(CASE WHEN attempt_result = 'success' THEN 1 ELSE 0 END) as successes, COUNT(DISTINCT technician_id) as unique_techs - FROM activation_attempts + FROM `" . t('activation_attempts') . "` GROUP BY DATE_FORMAT(attempted_date, '%Y-%m') ORDER BY month DESC LIMIT 12 @@ -120,7 +120,7 @@ function handle_get_stats(PDO $pdo, array $admin_session): void { $stats = []; // Key statistics - $stmt = $pdo->query("SELECT key_status, COUNT(*) as count FROM oem_keys GROUP BY key_status"); + $stmt = $pdo->query("SELECT key_status, COUNT(*) as count FROM `" . t('oem_keys') . "` GROUP BY key_status"); $key_stats = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); $stats['keys'] = [ 'unused' => $key_stats['unused'] ?? 0, @@ -132,7 +132,7 @@ function handle_get_stats(PDO $pdo, array $admin_session): void { ]; // Technician statistics - $stmt = $pdo->query("SELECT is_active, COUNT(*) as count FROM technicians GROUP BY is_active"); + $stmt = $pdo->query("SELECT is_active, COUNT(*) as count FROM `" . t('technicians') . "` GROUP BY is_active"); $tech_stats = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); $stats['technicians'] = [ 'active' => $tech_stats[1] ?? 0, @@ -141,13 +141,13 @@ function handle_get_stats(PDO $pdo, array $admin_session): void { ]; // Activation statistics - $stmt = $pdo->query("SELECT COUNT(*) FROM activation_attempts WHERE DATE(attempted_date) = CURDATE()"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('activation_attempts') . "` WHERE DATE(attempted_date) = CURDATE()"); $stats['activations']['today'] = $stmt->fetchColumn(); - $stmt = $pdo->query("SELECT COUNT(*) FROM activation_attempts WHERE YEARWEEK(attempted_date, 1) = YEARWEEK(CURDATE(), 1)"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('activation_attempts') . "` WHERE YEARWEEK(attempted_date, 1) = YEARWEEK(CURDATE(), 1)"); $stats['activations']['week'] = $stmt->fetchColumn(); - $stmt = $pdo->query("SELECT COUNT(*) FROM activation_attempts WHERE YEAR(attempted_date) = YEAR(CURDATE()) AND MONTH(attempted_date) = MONTH(CURDATE())"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('activation_attempts') . "` WHERE YEAR(attempted_date) = YEAR(CURDATE()) AND MONTH(attempted_date) = MONTH(CURDATE())"); $stats['activations']['month'] = $stmt->fetchColumn(); // Daily activation trend — fetch all history, let frontend slice by range @@ -156,7 +156,7 @@ function handle_get_stats(PDO $pdo, array $admin_session): void { COUNT(*) as total, SUM(CASE WHEN attempt_result = 'success' THEN 1 ELSE 0 END) as successes, SUM(CASE WHEN attempt_result != 'success' THEN 1 ELSE 0 END) as failures - FROM activation_attempts + FROM `" . t('activation_attempts') . "` GROUP BY DATE(attempted_date) ORDER BY date ASC "); @@ -188,8 +188,8 @@ function handle_get_stats(PDO $pdo, array $admin_session): void { // Recent activity $stmt = $pdo->prepare(" SELECT aal.created_at, au.username, aal.action, aal.description - FROM admin_activity_log aal - LEFT JOIN admin_users au ON aal.admin_id = au.id + FROM `" . t('admin_activity_log') . "` aal + LEFT JOIN `" . t('admin_users') . "` au ON aal.admin_id = au.id ORDER BY aal.created_at DESC LIMIT 10 "); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/HistoryController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/HistoryController.php index 50dc1e4..705e017 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/HistoryController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/HistoryController.php @@ -71,10 +71,10 @@ function handle_get_hardware(PDO $pdo, array $admin_session): void { $stmt = $pdo->prepare(" SELECT h.*, aa.order_number, aa.attempted_at, aa.technician_id, t.full_name as technician_name, k.product_key - FROM hardware_info h - INNER JOIN activation_attempts aa ON h.activation_id = aa.id - LEFT JOIN technicians t ON aa.technician_id = t.technician_id - LEFT JOIN oem_keys k ON aa.key_id = k.id + FROM `" . t('hardware_info') . "` h + INNER JOIN `" . t('activation_attempts') . "` aa ON h.activation_id = aa.id + LEFT JOIN `" . t('technicians') . "` t ON aa.technician_id = t.technician_id + LEFT JOIN `" . t('oem_keys') . "` k ON aa.key_id = k.id WHERE h.activation_id = ? "); $stmt->execute([$activationId]); @@ -101,10 +101,10 @@ function handle_get_hardware_by_order(PDO $pdo, array $admin_session): void { aa.attempt_result as activation_result, aa.attempted_at as activation_time, k.product_key - FROM hardware_info h - LEFT JOIN technicians t ON h.technician_id = t.technician_id - LEFT JOIN activation_attempts aa ON h.activation_id = aa.id - LEFT JOIN oem_keys k ON aa.key_id = k.id + FROM `" . t('hardware_info') . "` h + LEFT JOIN `" . t('technicians') . "` t ON h.technician_id = t.technician_id + LEFT JOIN `" . t('activation_attempts') . "` aa ON h.activation_id = aa.id + LEFT JOIN `" . t('oem_keys') . "` k ON aa.key_id = k.id WHERE h.order_number = ? ORDER BY h.collection_timestamp DESC LIMIT 1 diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/IntegrationController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/IntegrationController.php index a093ec4..9d64e59 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/IntegrationController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/IntegrationController.php @@ -9,7 +9,7 @@ function handle_list_integrations(PDO $pdo, array $admin_session): void { requirePermission('system_settings', $admin_session); - $stmt = $pdo->query("SELECT * FROM integrations ORDER BY id ASC"); + $stmt = $pdo->query("SELECT * FROM `" . t('integrations') . "` ORDER BY id ASC"); $rows = $stmt->fetchAll(); // Decode config JSON and mask sensitive fields @@ -29,7 +29,7 @@ function handle_list_integrations(PDO $pdo, array $admin_session): void { COUNT(*) as total, SUM(status = 'failed') as failed, SUM(status = 'pending') as pending - FROM integration_events WHERE integration_id = ? + FROM `" . t('integration_events') . "` WHERE integration_id = ? "); $countStmt->execute([$row['id']]); $row['event_counts'] = $countStmt->fetch(); @@ -48,7 +48,7 @@ function handle_get_integration(PDO $pdo, array $admin_session): void { return; } - $stmt = $pdo->prepare("SELECT * FROM integrations WHERE integration_key = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('integrations') . "` WHERE integration_key = ?"); $stmt->execute([$key]); $intg = $stmt->fetch(); if (!$intg) { @@ -61,7 +61,7 @@ function handle_get_integration(PDO $pdo, array $admin_session): void { // Recent events (last 20) $evtStmt = $pdo->prepare(" SELECT id, event_type, status, response_code, error_message, created_at, processed_at - FROM integration_events + FROM `" . t('integration_events') . "` WHERE integration_id = ? ORDER BY created_at DESC LIMIT 20 "); @@ -85,7 +85,7 @@ function handle_save_integration(PDO $pdo, array $admin_session, ?array $json_in return; } - $stmt = $pdo->prepare("SELECT * FROM integrations WHERE integration_key = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('integrations') . "` WHERE integration_key = ?"); $stmt->execute([$key]); $intg = $stmt->fetch(); if (!$intg) { @@ -111,7 +111,7 @@ function handle_save_integration(PDO $pdo, array $admin_session, ?array $json_in } $updateStmt = $pdo->prepare(" - UPDATE integrations + UPDATE `" . t('integrations') . "` SET enabled = ?, config = ?, updated_at = NOW() WHERE integration_key = ? "); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/KeysController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/KeysController.php index b2f6cbe..86115eb 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/KeysController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/KeysController.php @@ -105,7 +105,7 @@ function handle_recycle_key(PDO $pdo, array $admin_session): void { $id = intval($_POST['id'] ?? 0); $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = 'unused', last_use_date = NULL, last_use_time = NULL WHERE id = ? "); @@ -126,7 +126,7 @@ function handle_delete_key(PDO $pdo, array $admin_session): void { $id = intval($_POST['id'] ?? 0); - $stmt = $pdo->prepare("DELETE FROM oem_keys WHERE id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('oem_keys') . "` WHERE id = ?"); $stmt->execute([$id]); logAdminActivity( @@ -265,9 +265,9 @@ function handle_add_keys(PDO $pdo, array $admin_session, ?array $json_input = nu $pdo->beginTransaction(); try { - $checkStmt = $pdo->prepare("SELECT id FROM oem_keys WHERE product_key = ?"); + $checkStmt = $pdo->prepare("SELECT id FROM `" . t('oem_keys') . "` WHERE product_key = ?"); $insertStmt = $pdo->prepare(" - INSERT INTO oem_keys (product_key, oem_identifier, roll_serial, key_status, created_at) + INSERT INTO `" . t('oem_keys') . "` (product_key, oem_identifier, roll_serial, key_status, created_at) VALUES (?, ?, ?, 'unused', NOW()) "); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/LicenseController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/LicenseController.php index 165c59b..4020115 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/LicenseController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/LicenseController.php @@ -17,12 +17,12 @@ function handle_license_status(PDO $pdo, array $admin_session, $json_input): voi $techCount = 0; $keyCount = 0; try { - $stmt = $pdo->query("SELECT COUNT(*) FROM technicians WHERE status = 'active'"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('technicians') . "` WHERE status = 'active'"); $techCount = (int)$stmt->fetchColumn(); } catch (Exception $e) { /* table may not exist */ } try { - $stmt = $pdo->query("SELECT COUNT(*) FROM oem_keys"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('oem_keys') . "`"); $keyCount = (int)$stmt->fetchColumn(); } catch (Exception $e) { /* table may not exist */ } @@ -76,7 +76,7 @@ function handle_license_register(PDO $pdo, array $admin_session, $json_input): v function handle_license_deactivate(PDO $pdo, array $admin_session, $json_input): void { requirePermission('system_settings', $admin_session); - $pdo->exec("UPDATE license_info SET is_active = 0"); + $pdo->exec("UPDATE `" . t('license_info') . "` SET is_active = 0"); saveConfigBatch($pdo, ['license_tier' => 'community']); logAdminActivity( diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/NotificationsController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/NotificationsController.php index 81233f1..9e65f2c 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/NotificationsController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/NotificationsController.php @@ -39,7 +39,7 @@ function handle_push_subscribe(PDO $pdo, array $admin_session, ?array $json_inpu // Upsert: insert or re-activate existing subscription $stmt = $pdo->prepare(" - INSERT INTO push_subscriptions (admin_id, endpoint, p256dh_key, auth_key, user_agent, is_active) + INSERT INTO `" . t('push_subscriptions') . "` (admin_id, endpoint, p256dh_key, auth_key, user_agent, is_active) VALUES (?, ?, ?, ?, ?, 1) ON DUPLICATE KEY UPDATE p256dh_key = VALUES(p256dh_key), auth_key = VALUES(auth_key), user_agent = VALUES(user_agent), is_active = 1, last_used_at = NOW() @@ -58,10 +58,10 @@ function handle_push_unsubscribe(PDO $pdo, array $admin_session, ?array $json_in if (empty($endpoint)) { // Deactivate all subscriptions for this admin - $stmt = $pdo->prepare("UPDATE push_subscriptions SET is_active = 0 WHERE admin_id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('push_subscriptions') . "` SET is_active = 0 WHERE admin_id = ?"); $stmt->execute([$adminId]); } else { - $stmt = $pdo->prepare("UPDATE push_subscriptions SET is_active = 0 WHERE admin_id = ? AND endpoint = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('push_subscriptions') . "` SET is_active = 0 WHERE admin_id = ? AND endpoint = ?"); $stmt->execute([$adminId, $endpoint]); } @@ -75,7 +75,7 @@ function handle_get_push_preferences(PDO $pdo, array $admin_session): void { $adminId = (int)$admin_session['admin_id']; // Get saved preferences - $stmt = $pdo->prepare("SELECT category, enabled FROM push_preferences WHERE admin_id = ?"); + $stmt = $pdo->prepare("SELECT category, enabled FROM `" . t('push_preferences') . "` WHERE admin_id = ?"); $stmt->execute([$adminId]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); @@ -90,7 +90,7 @@ function handle_get_push_preferences(PDO $pdo, array $admin_session): void { } // Check if admin has any active subscriptions - $subStmt = $pdo->prepare("SELECT COUNT(*) FROM push_subscriptions WHERE admin_id = ? AND is_active = 1"); + $subStmt = $pdo->prepare("SELECT COUNT(*) FROM `" . t('push_subscriptions') . "` WHERE admin_id = ? AND is_active = 1"); $subStmt->execute([$adminId]); $hasSubscription = (int)$subStmt->fetchColumn() > 0; @@ -117,7 +117,7 @@ function handle_save_push_preferences(PDO $pdo, array $admin_session, ?array $js $validCategories = ['security', 'keys', 'technicians', 'system', 'devices', 'activation']; $stmt = $pdo->prepare(" - INSERT INTO push_preferences (admin_id, category, enabled) + INSERT INTO `" . t('push_preferences') . "` (admin_id, category, enabled) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE enabled = VALUES(enabled) "); @@ -141,7 +141,7 @@ function handle_get_notifications(PDO $pdo, array $admin_session): void { // Get 50 most recent notifications $stmt = $pdo->prepare(" SELECT id, category, title_key, body, action_url, is_read, created_at - FROM notifications + FROM `" . t('notifications') . "` WHERE admin_id = ? ORDER BY created_at DESC LIMIT 50 @@ -150,7 +150,7 @@ function handle_get_notifications(PDO $pdo, array $admin_session): void { $notifications = $stmt->fetchAll(PDO::FETCH_ASSOC); // Get unread count - $countStmt = $pdo->prepare("SELECT COUNT(*) FROM notifications WHERE admin_id = ? AND is_read = 0"); + $countStmt = $pdo->prepare("SELECT COUNT(*) FROM `" . t('notifications') . "` WHERE admin_id = ? AND is_read = 0"); $countStmt->execute([$adminId]); $unreadCount = (int)$countStmt->fetchColumn(); @@ -170,7 +170,7 @@ function handle_send_test_notification(PDO $pdo, array $admin_session, ?array $j // Insert a bell notification for this admin $stmt = $pdo->prepare(" - INSERT INTO notifications (admin_id, category, title_key, body, action_url) + INSERT INTO `" . t('notifications') . "` (admin_id, category, title_key, body, action_url) VALUES (?, 'system', 'notif.title.system', ?, 'admin_v2.php#notifications') "); $testBody = $type === 'sound' @@ -182,8 +182,8 @@ function handle_send_test_notification(PDO $pdo, array $admin_session, ?array $j if ($type === 'push') { $subStmt = $pdo->prepare(" SELECT ps.endpoint, ps.p256dh_key, ps.auth_key, au.preferred_language - FROM push_subscriptions ps - JOIN admin_users au ON ps.admin_id = au.id + FROM `" . t('push_subscriptions') . "` ps + JOIN `" . t('admin_users') . "` au ON ps.admin_id = au.id WHERE ps.admin_id = ? AND ps.is_active = 1 "); $subStmt->execute([$adminId]); @@ -220,7 +220,7 @@ function handle_send_test_notification(PDO $pdo, array $admin_session, ?array $j foreach ($webPush->flush() as $report) { if ($report->isSubscriptionExpired()) { $endpoint = $report->getRequest()->getUri()->__toString(); - $pdo->prepare("UPDATE push_subscriptions SET is_active = 0 WHERE endpoint = ?") + $pdo->prepare("UPDATE `" . t('push_subscriptions') . "` SET is_active = 0 WHERE endpoint = ?") ->execute([$endpoint]); } } @@ -240,7 +240,7 @@ function handle_mark_notifications_read(PDO $pdo, array $admin_session, ?array $ if ($ids === null || (is_array($ids) && empty($ids))) { // Mark all as read - $stmt = $pdo->prepare("UPDATE notifications SET is_read = 1 WHERE admin_id = ? AND is_read = 0"); + $stmt = $pdo->prepare("UPDATE `" . t('notifications') . "` SET is_read = 1 WHERE admin_id = ? AND is_read = 0"); $stmt->execute([$adminId]); } elseif (is_array($ids)) { $intIds = array_map('intval', $ids); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductVariantsController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductVariantsController.php index 100843f..fa406e6 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductVariantsController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductVariantsController.php @@ -14,8 +14,8 @@ function handle_get_product_lines(PDO $pdo, array $admin_session, ?array $json_i $stmt = $pdo->query(" SELECT pl.*, COUNT(DISTINCT pv.id) AS variant_count - FROM product_lines pl - LEFT JOIN product_variants pv ON pv.line_id = pl.id AND pv.is_active = 1 + FROM `" . t('product_lines') . "` pl + LEFT JOIN `" . t('product_variants') . "` pv ON pv.line_id = pl.id AND pv.is_active = 1 GROUP BY pl.id ORDER BY pl.name "); @@ -32,7 +32,7 @@ function handle_get_product_line(PDO $pdo, array $admin_session, ?array $json_in jsonResponse(['success' => false, 'error' => 'Invalid line ID'], 400); } - $stmt = $pdo->prepare("SELECT * FROM product_lines WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('product_lines') . "` WHERE id = ?"); $stmt->execute([$id]); $line = $stmt->fetch(PDO::FETCH_ASSOC); if (!$line) { @@ -42,7 +42,7 @@ function handle_get_product_line(PDO $pdo, array $admin_session, ?array $json_in // Fetch variants $stmt = $pdo->prepare(" SELECT pv.* - FROM product_variants pv + FROM `" . t('product_variants') . "` pv WHERE pv.line_id = ? AND pv.is_active = 1 ORDER BY pv.disk_size_min_mb "); @@ -104,7 +104,7 @@ function handle_save_product_line(PDO $pdo, array $admin_session, ?array $json_i if ($id > 0) { // Update $stmt = $pdo->prepare(" - UPDATE product_lines + UPDATE `" . t('product_lines') . "` SET name = ?, order_pattern = ?, description = ?, enforcement_level = ?, is_active = ?, secure_boot_enforcement = ?, bios_enforcement = ?, hackbgrt_enforcement = ?, partition_enforcement = ?, missing_drivers_enforcement = ? @@ -116,7 +116,7 @@ function handle_save_product_line(PDO $pdo, array $admin_session, ?array $json_i } else { // Insert $stmt = $pdo->prepare(" - INSERT INTO product_lines (name, order_pattern, description, enforcement_level, is_active, + INSERT INTO `" . t('product_lines') . "` (name, order_pattern, description, enforcement_level, is_active, secure_boot_enforcement, bios_enforcement, hackbgrt_enforcement, partition_enforcement, missing_drivers_enforcement) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) @@ -146,7 +146,7 @@ function handle_delete_product_line(PDO $pdo, array $admin_session, ?array $json jsonResponse(['success' => false, 'error' => 'Invalid line ID'], 400); } - $stmt = $pdo->prepare("UPDATE product_lines SET is_active = 0 WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('product_lines') . "` SET is_active = 0 WHERE id = ?"); $stmt->execute([$id]); logAdminActivity($admin_session['admin_id'], $admin_session['id'], 'PRODUCT_LINE_DELETE', "Deactivated product line ID: $id"); @@ -177,14 +177,14 @@ function handle_save_product_variant(PDO $pdo, array $admin_session, ?array $jso try { if ($id > 0) { $stmt = $pdo->prepare(" - UPDATE product_variants + UPDATE `" . t('product_variants') . "` SET line_id = ?, name = ?, disk_size_min_mb = ?, disk_size_max_mb = ?, is_active = ? WHERE id = ? "); $stmt->execute([$lineId, $name, $diskSizeMin, $diskSizeMax, $isActive, $id]); } else { $stmt = $pdo->prepare(" - INSERT INTO product_variants (line_id, name, disk_size_min_mb, disk_size_max_mb, is_active) + INSERT INTO `" . t('product_variants') . "` (line_id, name, disk_size_min_mb, disk_size_max_mb, is_active) VALUES (?, ?, ?, ?, ?) "); $stmt->execute([$lineId, $name, $diskSizeMin, $diskSizeMax, $isActive]); @@ -192,12 +192,12 @@ function handle_save_product_variant(PDO $pdo, array $admin_session, ?array $jso } // Replace partitions: delete existing, insert new - $stmt = $pdo->prepare("DELETE FROM product_variant_partitions WHERE variant_id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('product_variant_partitions') . "` WHERE variant_id = ?"); $stmt->execute([$id]); if (!empty($partitions)) { $stmt = $pdo->prepare(" - INSERT INTO product_variant_partitions + INSERT INTO `" . t('product_variant_partitions') . "` (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) VALUES (?, ?, ?, ?, ?, ?, ?) "); @@ -257,7 +257,7 @@ function handle_delete_product_variant(PDO $pdo, array $admin_session, ?array $j jsonResponse(['success' => false, 'error' => 'Invalid variant ID'], 400); } - $stmt = $pdo->prepare("UPDATE product_variants SET is_active = 0 WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('product_variants') . "` SET is_active = 0 WHERE id = ?"); $stmt->execute([$id]); logAdminActivity($admin_session['admin_id'], $admin_session['id'], 'PRODUCT_VARIANT_DELETE', "Deactivated variant ID: $id"); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductionController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductionController.php index ab4452b..ebf473c 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductionController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/ProductionController.php @@ -74,10 +74,10 @@ function handle_get_build_report(PDO $pdo, array $admin_session, $json_input): v $uuid = $json_input['uuid'] ?? $_GET['uuid'] ?? ''; if ($id > 0) { - $stmt = $pdo->prepare("SELECT * FROM computer_build_reports WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('computer_build_reports') . "` WHERE id = ?"); $stmt->execute([$id]); } elseif ($uuid) { - $stmt = $pdo->prepare("SELECT * FROM computer_build_reports WHERE report_uuid = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('computer_build_reports') . "` WHERE report_uuid = ?"); $stmt->execute([$uuid]); } else { jsonResponse(['success' => false, 'error' => 'Report ID or UUID required']); @@ -99,7 +99,7 @@ function handle_export_build_report(PDO $pdo, array $admin_session, $json_input) $id = (int)($json_input['id'] ?? $_GET['id'] ?? 0); $format = $json_input['format'] ?? $_GET['format'] ?? 'json'; - $stmt = $pdo->prepare("SELECT * FROM computer_build_reports WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('computer_build_reports') . "` WHERE id = ?"); $stmt->execute([$id]); $report = $stmt->fetch(PDO::FETCH_ASSOC); @@ -204,7 +204,7 @@ function handle_update_build_report_shipping(PDO $pdo, array $admin_session, $js } $params[] = $id; - $stmt = $pdo->prepare("UPDATE computer_build_reports SET " . implode(', ', $sets) . " WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('computer_build_reports') . "` SET " . implode(', ', $sets) . " WHERE id = ?"); $stmt->execute($params); logAdminActivity($admin_session['admin_id'], $admin_session['id'] ?? 0, 'CBR_SHIPPING_UPDATED', "Updated CBR #{$id} shipping: {$shippingStatus}"); @@ -228,13 +228,13 @@ function handle_get_key_pool_status(PDO $pdo, array $admin_session, $json_input) SUM(CASE WHEN key_status = 'allocated' THEN 1 ELSE 0 END) AS allocated_keys, SUM(CASE WHEN key_status = 'good' THEN 1 ELSE 0 END) AS used_keys, SUM(CASE WHEN key_status = 'bad' THEN 1 ELSE 0 END) AS bad_keys - FROM oem_keys + FROM `" . t('oem_keys') . "` GROUP BY oem_identifier "); $pools = $stmt->fetchAll(PDO::FETCH_ASSOC); // Get pool config - $configStmt = $pdo->query("SELECT * FROM key_pool_config ORDER BY product_edition"); + $configStmt = $pdo->query("SELECT * FROM `" . t('key_pool_config') . "` ORDER BY product_edition"); $configs = []; foreach ($configStmt->fetchAll(PDO::FETCH_ASSOC) as $c) { $configs[$c['product_edition']] = $c; @@ -287,7 +287,7 @@ function handle_save_key_pool_config(PDO $pdo, array $admin_session, $json_input } $stmt = $pdo->prepare(" - INSERT INTO key_pool_config (product_edition, low_threshold, critical_threshold, auto_notify, notify_email) + INSERT INTO `" . t('key_pool_config') . "` (product_edition, low_threshold, critical_threshold, auto_notify, notify_email) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE low_threshold = VALUES(low_threshold), @@ -326,15 +326,15 @@ function handle_check_hardware_binding(PDO $pdo, array $admin_session, $json_inp // Return recent bindings $stmt = $pdo->query(" SELECT hkb.*, ok.product_key, ok.oem_identifier AS product_type - FROM hardware_key_bindings hkb - LEFT JOIN oem_keys ok ON ok.id = hkb.product_key_id + FROM `" . t('hardware_key_bindings') . "` hkb + LEFT JOIN `" . t('oem_keys') . "` ok ON ok.id = hkb.product_key_id ORDER BY hkb.bound_at DESC LIMIT 50 "); } else { $stmt = $pdo->prepare(" SELECT hkb.*, ok.product_key, ok.oem_identifier AS product_type - FROM hardware_key_bindings hkb - LEFT JOIN oem_keys ok ON ok.id = hkb.product_key_id + FROM `" . t('hardware_key_bindings') . "` hkb + LEFT JOIN `" . t('oem_keys') . "` ok ON ok.id = hkb.product_key_id WHERE " . implode(' AND ', $where) . " ORDER BY hkb.bound_at DESC LIMIT 50 "); @@ -348,7 +348,7 @@ function handle_check_hardware_binding(PDO $pdo, array $admin_session, $json_inp if ($keyId > 0) { $conflictStmt = $pdo->prepare(" SELECT device_fingerprint, motherboard_serial, bound_at - FROM hardware_key_bindings + FROM `" . t('hardware_key_bindings') . "` WHERE product_key_id = ? AND status = 'active' "); $conflictStmt->execute([$keyId]); @@ -371,7 +371,7 @@ function handle_release_hardware_binding(PDO $pdo, array $admin_session, $json_i } $stmt = $pdo->prepare(" - UPDATE hardware_key_bindings + UPDATE `" . t('hardware_key_bindings') . "` SET status = 'released', released_at = NOW(), released_by_admin_id = ? WHERE id = ? AND status = 'active' "); @@ -411,7 +411,7 @@ function handle_import_dpk_batch(PDO $pdo, array $admin_session): void { // Create batch record $batchStmt = $pdo->prepare(" - INSERT INTO dpk_import_batches + INSERT INTO `" . t('dpk_import_batches') . "` (batch_name, import_source, product_edition, source_filename, source_checksum, imported_by_admin_id, imported_by_username, import_status) VALUES (?, ?, ?, ?, ?, ?, ?, 'processing') @@ -446,9 +446,9 @@ function handle_import_dpk_batch(PDO $pdo, array $admin_session): void { $duplicates = 0; $failed = 0; - $checkExisting = $pdo->prepare("SELECT COUNT(*) FROM oem_keys WHERE product_key = ?"); + $checkExisting = $pdo->prepare("SELECT COUNT(*) FROM `" . t('oem_keys') . "` WHERE product_key = ?"); $insertKey = $pdo->prepare(" - INSERT INTO oem_keys (product_key, oem_identifier, key_status) + INSERT INTO `" . t('oem_keys') . "` (product_key, oem_identifier, key_status) VALUES (?, ?, 'unused') "); @@ -469,7 +469,7 @@ function handle_import_dpk_batch(PDO $pdo, array $admin_session): void { // Update batch record $pdo->prepare(" - UPDATE dpk_import_batches + UPDATE `" . t('dpk_import_batches') . "` SET total_keys = ?, imported_keys = ?, duplicate_keys = ?, failed_keys = ?, import_status = 'completed', completed_at = NOW() WHERE id = ? @@ -483,7 +483,7 @@ function handle_import_dpk_batch(PDO $pdo, array $admin_session): void { // Update key pool replenishment timestamp if ($productEdition && $imported > 0) { $pdo->prepare(" - UPDATE key_pool_config SET last_replenished_at = NOW() WHERE product_edition = ? + UPDATE `" . t('key_pool_config') . "` SET last_replenished_at = NOW() WHERE product_edition = ? ")->execute([$productEdition]); } @@ -526,7 +526,7 @@ function parseDPKXml(string $content): array { function handle_list_dpk_batches(PDO $pdo, array $admin_session, $json_input): void { requirePermission('view_keys', $admin_session); - $stmt = $pdo->query("SELECT * FROM dpk_import_batches ORDER BY created_at DESC LIMIT 50"); + $stmt = $pdo->query("SELECT * FROM `" . t('dpk_import_batches') . "` ORDER BY created_at DESC LIMIT 50"); jsonResponse(['success' => true, 'batches' => $stmt->fetchAll(PDO::FETCH_ASSOC)]); } @@ -621,13 +621,13 @@ function handle_save_work_order(PDO $pdo, array $admin_session, $json_input): vo } $params[] = $id; - $stmt = $pdo->prepare("UPDATE work_orders SET " . implode(', ', $sets) . " WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('work_orders') . "` SET " . implode(', ', $sets) . " WHERE id = ?"); $stmt->execute($params); } else { $data['created_by_admin_id'] = (int)$admin_session['admin_id']; $cols = array_keys($data); $placeholders = array_fill(0, count($cols), '?'); - $stmt = $pdo->prepare("INSERT INTO work_orders (" . implode(',', $cols) . ") VALUES (" . implode(',', $placeholders) . ")"); + $stmt = $pdo->prepare("INSERT INTO `" . t('work_orders') . "` (" . implode(',', $cols) . ") VALUES (" . implode(',', $placeholders) . ")"); $stmt->execute(array_values($data)); $id = (int)$pdo->lastInsertId(); } @@ -646,7 +646,7 @@ function handle_get_work_order(PDO $pdo, array $admin_session, $json_input): voi return; } - $stmt = $pdo->prepare("SELECT * FROM work_orders WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('work_orders') . "` WHERE id = ?"); $stmt->execute([$id]); $order = $stmt->fetch(PDO::FETCH_ASSOC); @@ -659,7 +659,7 @@ function handle_get_work_order(PDO $pdo, array $admin_session, $json_input): voi $cbrStmt = $pdo->prepare(" SELECT id, report_uuid, order_number, activation_status, shipping_status, motherboard_model, cpu_model, created_at - FROM computer_build_reports + FROM `" . t('computer_build_reports') . "` WHERE work_order_id = ? ORDER BY created_at ASC "); @@ -679,7 +679,7 @@ function handle_delete_work_order(PDO $pdo, array $admin_session, $json_input): } // Only allow deleting draft/cancelled orders - $check = $pdo->prepare("SELECT status, work_order_number FROM work_orders WHERE id = ?"); + $check = $pdo->prepare("SELECT status, work_order_number FROM `" . t('work_orders') . "` WHERE id = ?"); $check->execute([$id]); $row = $check->fetch(); @@ -692,7 +692,7 @@ function handle_delete_work_order(PDO $pdo, array $admin_session, $json_input): return; } - $pdo->prepare("DELETE FROM work_orders WHERE id = ?")->execute([$id]); + $pdo->prepare("DELETE FROM `" . t('work_orders') . "` WHERE id = ?")->execute([$id]); logAdminActivity($admin_session['admin_id'], $admin_session['id'] ?? 0, 'WORK_ORDER_DELETED', "Deleted work order: {$row['work_order_number']}"); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/SecurityController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/SecurityController.php index dd3913d..718eaac 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/SecurityController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/SecurityController.php @@ -9,7 +9,7 @@ function handle_get_2fa_status(PDO $pdo, array $admin_session): void { try { $stmt = $pdo->prepare(" SELECT totp_enabled, verified_at, backup_codes - FROM admin_totp_secrets + FROM `" . t('admin_totp_secrets') . "` WHERE admin_id = ? "); $stmt->execute([$admin_session['admin_id']]); @@ -48,8 +48,8 @@ function handle_list_trusted_networks(PDO $pdo, array $admin_session): void { $stmt = $pdo->query(" SELECT tn.*, au.username as created_by_username - FROM trusted_networks tn - LEFT JOIN admin_users au ON tn.created_by_admin_id = au.id + FROM `" . t('trusted_networks') . "` tn + LEFT JOIN `" . t('admin_users') . "` au ON tn.created_by_admin_id = au.id ORDER BY tn.created_at DESC "); $networks = $stmt->fetchAll(PDO::FETCH_ASSOC); @@ -78,7 +78,7 @@ function handle_add_trusted_network(PDO $pdo, array $admin_session, ?array $json } $stmt = $pdo->prepare(" - INSERT INTO trusted_networks ( + INSERT INTO `" . t('trusted_networks') . "` ( network_name, ip_range, bypass_2fa, allow_usb_auth, description, created_by_admin_id ) VALUES (?, ?, ?, ?, ?, ?) "); @@ -99,7 +99,7 @@ function handle_delete_trusted_network(PDO $pdo, array $admin_session, ?array $j $networkId = intval($json_input['network_id'] ?? 0); - $stmt = $pdo->prepare("SELECT network_name FROM trusted_networks WHERE id = ?"); + $stmt = $pdo->prepare("SELECT network_name FROM `" . t('trusted_networks') . "` WHERE id = ?"); $stmt->execute([$networkId]); $network = $stmt->fetch(PDO::FETCH_ASSOC); @@ -108,7 +108,7 @@ function handle_delete_trusted_network(PDO $pdo, array $admin_session, ?array $j return; } - $stmt = $pdo->prepare("DELETE FROM trusted_networks WHERE id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('trusted_networks') . "` WHERE id = ?"); $stmt->execute([$networkId]); logAdminActivity( diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/TaskPipelineController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/TaskPipelineController.php index 6914b76..bc00b25 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/TaskPipelineController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/TaskPipelineController.php @@ -15,7 +15,7 @@ function handle_list_task_templates(PDO $pdo, array $admin_session, $json_input) requirePermission('system_settings', $admin_session); $stmt = $pdo->query(" - SELECT * FROM task_templates + SELECT * FROM `" . t('task_templates') . "` ORDER BY is_system DESC, task_key ASC "); @@ -54,13 +54,13 @@ function handle_save_task_template(PDO $pdo, array $admin_session, $json_input): if ($id > 0) { // Check not editing a system task's key/type - $existing = $pdo->prepare("SELECT is_system FROM task_templates WHERE id = ?"); + $existing = $pdo->prepare("SELECT is_system FROM `" . t('task_templates') . "` WHERE id = ?"); $existing->execute([$id]); $row = $existing->fetch(); if ($row && $row['is_system']) { // System tasks: only allow editing name, description, timeout, on_failure, icon $stmt = $pdo->prepare(" - UPDATE task_templates + UPDATE `" . t('task_templates') . "` SET task_name = ?, description = ?, default_timeout_seconds = ?, default_on_failure = ?, icon = ? WHERE id = ? @@ -68,7 +68,7 @@ function handle_save_task_template(PDO $pdo, array $admin_session, $json_input): $stmt->execute([$taskName, $description, $defaultTimeout, $defaultOnFailure, $icon, $id]); } else { $stmt = $pdo->prepare(" - UPDATE task_templates + UPDATE `" . t('task_templates') . "` SET task_key = ?, task_name = ?, task_type = ?, description = ?, default_code = ?, default_timeout_seconds = ?, default_on_failure = ?, icon = ? WHERE id = ? AND is_system = 0 @@ -77,7 +77,7 @@ function handle_save_task_template(PDO $pdo, array $admin_session, $json_input): } } else { $stmt = $pdo->prepare(" - INSERT INTO task_templates + INSERT INTO `" . t('task_templates') . "` (task_key, task_name, task_type, description, default_code, default_timeout_seconds, default_on_failure, is_system, icon) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?) @@ -101,7 +101,7 @@ function handle_delete_task_template(PDO $pdo, array $admin_session, $json_input } // Cannot delete system tasks - $check = $pdo->prepare("SELECT is_system, task_key FROM task_templates WHERE id = ?"); + $check = $pdo->prepare("SELECT is_system, task_key FROM `" . t('task_templates') . "` WHERE id = ?"); $check->execute([$id]); $row = $check->fetch(); if (!$row) { @@ -114,8 +114,8 @@ function handle_delete_task_template(PDO $pdo, array $admin_session, $json_input } // Remove from all product line assignments first - $pdo->prepare("DELETE FROM product_line_tasks WHERE task_template_id = ?")->execute([$id]); - $pdo->prepare("DELETE FROM task_templates WHERE id = ? AND is_system = 0")->execute([$id]); + $pdo->prepare("DELETE FROM `" . t('product_line_tasks') . "` WHERE task_template_id = ?")->execute([$id]); + $pdo->prepare("DELETE FROM `" . t('task_templates') . "` WHERE id = ? AND is_system = 0")->execute([$id]); logAdminActivity($admin_session['admin_id'], $admin_session['id'] ?? 0, 'TASK_TEMPLATE_DELETED', "Deleted task template: {$row['task_key']} (#{$id})"); @@ -137,8 +137,8 @@ function handle_get_product_line_tasks(PDO $pdo, array $admin_session, $json_inp SELECT plt.*, tt.task_key, tt.task_name AS template_name, tt.task_type, tt.description AS template_description, tt.default_code, tt.default_timeout_seconds, tt.default_on_failure, tt.is_system, tt.icon - FROM product_line_tasks plt - JOIN task_templates tt ON tt.id = plt.task_template_id + FROM `" . t('product_line_tasks') . "` plt + JOIN `" . t('task_templates') . "` tt ON tt.id = plt.task_template_id WHERE plt.product_line_id = ? ORDER BY plt.sort_order ASC "); @@ -165,11 +165,11 @@ function handle_save_product_line_tasks(PDO $pdo, array $admin_session, $json_in $pdo->beginTransaction(); try { // Remove existing assignments - $pdo->prepare("DELETE FROM product_line_tasks WHERE product_line_id = ?")->execute([$productLineId]); + $pdo->prepare("DELETE FROM `" . t('product_line_tasks') . "` WHERE product_line_id = ?")->execute([$productLineId]); // Insert new assignments in order $insertStmt = $pdo->prepare(" - INSERT INTO product_line_tasks + INSERT INTO `" . t('product_line_tasks') . "` (product_line_id, task_template_id, sort_order, enabled, custom_name, custom_code, custom_timeout_seconds, custom_on_failure) VALUES (?, ?, ?, ?, ?, ?, ?, ?) @@ -246,7 +246,7 @@ function handle_get_activation_pipeline(PDO $pdo, array $admin_session, $json_in SELECT id AS task_template_id, task_key, task_name, task_type, default_code AS code, default_timeout_seconds AS timeout_seconds, default_on_failure AS on_failure, 1 AS enabled - FROM task_templates + FROM `" . t('task_templates') . "` WHERE is_system = 1 ORDER BY id ASC "); @@ -263,8 +263,8 @@ function handle_get_activation_pipeline(PDO $pdo, array $admin_session, $json_in COALESCE(plt.custom_timeout_seconds, tt.default_timeout_seconds) AS timeout_seconds, COALESCE(plt.custom_on_failure, tt.default_on_failure) AS on_failure, plt.enabled - FROM product_line_tasks plt - JOIN task_templates tt ON tt.id = plt.task_template_id + FROM `" . t('product_line_tasks') . "` plt + JOIN `" . t('task_templates') . "` tt ON tt.id = plt.task_template_id WHERE plt.product_line_id = ? AND plt.enabled = 1 ORDER BY plt.sort_order ASC "); @@ -277,7 +277,7 @@ function handle_get_activation_pipeline(PDO $pdo, array $admin_session, $json_in SELECT id AS task_template_id, task_key, task_name, task_type, default_code AS code, default_timeout_seconds AS timeout_seconds, default_on_failure AS on_failure, 1 AS enabled - FROM task_templates + FROM `" . t('task_templates') . "` WHERE is_system = 1 ORDER BY id ASC "); @@ -297,7 +297,7 @@ function handle_log_task_execution(PDO $pdo, array $admin_session, $json_input): } $stmt = $pdo->prepare(" - INSERT INTO task_execution_log + INSERT INTO `" . t('task_execution_log') . "` (activation_attempt_id, product_line_id, task_template_id, task_key, task_name, status, started_at, completed_at, duration_ms, output, error_message, technician_id, order_number) diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/TechniciansController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/TechniciansController.php index 9980625..8ab6659 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/TechniciansController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/TechniciansController.php @@ -54,7 +54,7 @@ function handle_list_technicians(PDO $pdo, array $admin_session): void { $stmt = $pdo->query(" SELECT id, technician_id, full_name, email, is_active - FROM technicians + FROM `" . t('technicians') . "` ORDER BY full_name ASC "); $technicians = $stmt->fetchAll(PDO::FETCH_ASSOC); @@ -92,7 +92,7 @@ function handle_add_tech(PDO $pdo, array $admin_session): void { $pdo->beginTransaction(); // Check + insert inside transaction to prevent TOCTOU race condition - $stmt = $pdo->prepare("SELECT COUNT(*) FROM technicians WHERE technician_id = ?"); + $stmt = $pdo->prepare("SELECT COUNT(*) FROM `" . t('technicians') . "` WHERE technician_id = ?"); $stmt->execute([$tech_id]); if ($stmt->fetchColumn() > 0) { $pdo->rollBack(); @@ -101,7 +101,7 @@ function handle_add_tech(PDO $pdo, array $admin_session): void { } $stmt = $pdo->prepare(" - INSERT INTO technicians (technician_id, password_hash, full_name, email, is_active, preferred_language) + INSERT INTO `" . t('technicians') . "` (technician_id, password_hash, full_name, email, is_active, preferred_language) VALUES (?, ?, ?, ?, ?, ?) "); $stmt->execute([$tech_id, $password_hash, $full_name, $email, $is_active, $preferred_language]); @@ -136,7 +136,7 @@ function handle_edit_tech(PDO $pdo, array $admin_session): void { $is_active = isset($_POST['is_active']) ? 1 : 0; $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET full_name = ?, email = ?, is_active = ? WHERE id = ? "); @@ -161,7 +161,7 @@ function handle_get_tech(PDO $pdo, array $admin_session): void { $stmt = $pdo->prepare(" SELECT id, technician_id, full_name, email, is_active, preferred_server, preferred_language - FROM technicians + FROM `" . t('technicians') . "` WHERE id = ? "); $stmt->execute([$techId]); @@ -200,7 +200,7 @@ function handle_update_tech(PDO $pdo, array $admin_session, ?array $json_input = } $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET full_name = ?, email = ?, preferred_language = ?, is_active = ? WHERE id = ? "); @@ -230,7 +230,7 @@ function handle_reset_password(PDO $pdo, array $admin_session): void { $password_hash = password_hash($new_password, PASSWORD_BCRYPT, ['cost' => BCRYPT_COST]); $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET password_hash = ?, must_change_password = 1 WHERE id = ? "); @@ -252,7 +252,7 @@ function handle_toggle_tech(PDO $pdo, array $admin_session): void { $id = intval($_POST['id'] ?? 0); $stmt = $pdo->prepare(" - UPDATE technicians + UPDATE `" . t('technicians') . "` SET is_active = NOT is_active WHERE id = ? "); @@ -273,7 +273,7 @@ function handle_delete_tech(PDO $pdo, array $admin_session): void { $id = intval($_POST['id'] ?? 0); - $stmt = $pdo->prepare("DELETE FROM technicians WHERE id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('technicians') . "` WHERE id = ?"); $stmt->execute([$id]); logAdminActivity( diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/UpgradeController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/UpgradeController.php index 0129469..7325a9c 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/UpgradeController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/UpgradeController.php @@ -34,7 +34,7 @@ function getBackupDir(): string { } function loadUpgradeRow(PDO $pdo, int $upgradeId): ?array { - $stmt = $pdo->prepare("SELECT * FROM upgrade_history WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('upgrade_history') . "` WHERE id = ?"); $stmt->execute([$upgradeId]); return $stmt->fetch(PDO::FETCH_ASSOC) ?: null; } @@ -47,7 +47,7 @@ function updateUpgradeStatus(PDO $pdo, int $id, string $status, array $extra = [ $params[] = $val; } $params[] = $id; - $sql = "UPDATE upgrade_history SET " . implode(', ', $sets) . " WHERE id = ?"; + $sql = "UPDATE `" . t('upgrade_history') . "` SET " . implode(', ', $sets) . " WHERE id = ?"; $stmt = $pdo->prepare($sql); $stmt->execute($params); } @@ -275,7 +275,7 @@ function handle_upgrade_download_github(PDO $pdo, array $admin_session, $json_in // Check no active upgrade $stmt = $pdo->prepare(" - SELECT id, status FROM upgrade_history + SELECT id, status FROM `" . t('upgrade_history') . "` WHERE status NOT IN ('completed', 'failed', 'rolled_back') LIMIT 1 "); @@ -368,7 +368,7 @@ function handle_upgrade_download_github(PDO $pdo, array $admin_session, $json_in // Create upgrade_history row $stmt = $pdo->prepare(" - INSERT INTO upgrade_history + INSERT INTO `" . t('upgrade_history') . "` (from_version, to_version, from_version_code, to_version_code, status, manifest_json, package_filename, package_checksum, admin_id, admin_username) @@ -416,7 +416,7 @@ function handle_upgrade_get_status(PDO $pdo, array $admin_session, $json_input): // Active (non-terminal) upgrade $stmt = $pdo->query(" - SELECT * FROM upgrade_history + SELECT * FROM `" . t('upgrade_history') . "` WHERE status NOT IN ('completed', 'failed', 'rolled_back') ORDER BY created_at DESC LIMIT 1 "); @@ -427,7 +427,7 @@ function handle_upgrade_get_status(PDO $pdo, array $admin_session, $json_input): SELECT id, from_version, to_version, status, package_filename, error_message, started_at, completed_at, rolled_back_at, admin_username, created_at - FROM upgrade_history + FROM `" . t('upgrade_history') . "` ORDER BY created_at DESC LIMIT 10 "); $recentUpgrades = $stmt2->fetchAll(PDO::FETCH_ASSOC); @@ -511,7 +511,7 @@ function handle_upgrade_upload_package(PDO $pdo, array $admin_session): void { // Check no active upgrade in progress $stmt = $pdo->prepare(" - SELECT id, status FROM upgrade_history + SELECT id, status FROM `" . t('upgrade_history') . "` WHERE status NOT IN ('completed', 'failed', 'rolled_back') LIMIT 1 "); @@ -536,7 +536,7 @@ function handle_upgrade_upload_package(PDO $pdo, array $admin_session): void { // Create upgrade_history row $stmt = $pdo->prepare(" - INSERT INTO upgrade_history + INSERT INTO `" . t('upgrade_history') . "` (from_version, to_version, from_version_code, to_version_code, status, manifest_json, package_filename, package_checksum, admin_id, admin_username) @@ -859,7 +859,7 @@ function handle_upgrade_apply(PDO $pdo, array $admin_session, $json_input): void // Lock the row to prevent concurrent execution $pdo->beginTransaction(); - $lockStmt = $pdo->prepare("SELECT id FROM upgrade_history WHERE id = ? FOR UPDATE"); + $lockStmt = $pdo->prepare("SELECT id FROM `" . t('upgrade_history') . "` WHERE id = ? FOR UPDATE"); $lockStmt->execute([$upgradeId]); $lockStmt->closeCursor(); $pdo->commit(); @@ -899,7 +899,7 @@ function handle_upgrade_apply(PDO $pdo, array $admin_session, $json_input): void $migVersion = (int)($mig['version'] ?? 0); // Check if already applied - $checkStmt = $pdo->prepare("SELECT COUNT(*) FROM schema_versions WHERE filename = ?"); + $checkStmt = $pdo->prepare("SELECT COUNT(*) FROM `" . t('schema_versions') . "` WHERE filename = ?"); $checkStmt->execute([basename($migFile)]); $alreadyApplied = (int)$checkStmt->fetchColumn() > 0; $checkStmt->closeCursor(); @@ -945,7 +945,7 @@ function handle_upgrade_apply(PDO $pdo, array $admin_session, $json_input): void // Record in schema_versions $checksum = hash('sha256', $migContent); - $svStmt = $pdo->prepare("INSERT INTO schema_versions (version, filename, checksum) VALUES (?, ?, ?)"); + $svStmt = $pdo->prepare("INSERT INTO `" . t('schema_versions') . "` (version, filename, checksum) VALUES (?, ?, ?)"); $svStmt->execute([$migVersion, basename($migFile), $checksum]); $svStmt->closeCursor(); @@ -1327,7 +1327,7 @@ function handle_upgrade_rollback(PDO $pdo, array $admin_session, $json_input): v ); $freshPdo->prepare(" - INSERT INTO upgrade_history + INSERT INTO `" . t('upgrade_history') . "` (from_version, to_version, status, error_message, admin_id, admin_username, rolled_back_at) VALUES (?, ?, 'rolled_back', ?, ?, ?, ?) @@ -1363,7 +1363,7 @@ function handle_upgrade_history(PDO $pdo, array $admin_session, $json_input): vo status, package_filename, error_message, started_at, completed_at, rolled_back_at, admin_id, admin_username, created_at - FROM upgrade_history + FROM `" . t('upgrade_history') . "` ORDER BY created_at DESC LIMIT 50 "); diff --git a/FINAL_PRODUCTION_SYSTEM/controllers/admin/UsbDevicesController.php b/FINAL_PRODUCTION_SYSTEM/controllers/admin/UsbDevicesController.php index 888e86e..ad824f1 100644 --- a/FINAL_PRODUCTION_SYSTEM/controllers/admin/UsbDevicesController.php +++ b/FINAL_PRODUCTION_SYSTEM/controllers/admin/UsbDevicesController.php @@ -43,7 +43,7 @@ function handle_list_usb_devices(PDO $pdo, array $admin_session): void { // Get USB device statistics $stmt = $pdo->query(" SELECT device_status, COUNT(*) as count - FROM usb_devices + FROM `" . t('usb_devices') . "` GROUP BY device_status "); $statusCounts = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); @@ -79,7 +79,7 @@ function handle_register_usb_device(PDO $pdo, array $admin_session, ?array $json } // Check if technician exists and is active - $stmt = $pdo->prepare("SELECT technician_id, is_active FROM technicians WHERE technician_id = ?"); + $stmt = $pdo->prepare("SELECT technician_id, is_active FROM `" . t('technicians') . "` WHERE technician_id = ?"); $stmt->execute([$technicianId]); $technician = $stmt->fetch(PDO::FETCH_ASSOC); @@ -94,7 +94,7 @@ function handle_register_usb_device(PDO $pdo, array $admin_session, ?array $json } // Check if serial number already exists - $stmt = $pdo->prepare("SELECT device_id, device_name FROM usb_devices WHERE device_serial_number = ?"); + $stmt = $pdo->prepare("SELECT device_id, device_name FROM `" . t('usb_devices') . "` WHERE device_serial_number = ?"); $stmt->execute([$deviceSerial]); $existingDevice = $stmt->fetch(PDO::FETCH_ASSOC); @@ -109,7 +109,7 @@ function handle_register_usb_device(PDO $pdo, array $admin_session, ?array $json // Check max devices per technician limit $maxDevices = (int)getConfig('usb_auth_max_devices_per_tech'); if ($maxDevices > 0) { - $stmt = $pdo->prepare("SELECT COUNT(*) FROM usb_devices WHERE technician_id = ? AND device_status = 'active'"); + $stmt = $pdo->prepare("SELECT COUNT(*) FROM `" . t('usb_devices') . "` WHERE technician_id = ? AND device_status = 'active'"); $stmt->execute([$technicianId]); $currentCount = $stmt->fetchColumn(); @@ -124,7 +124,7 @@ function handle_register_usb_device(PDO $pdo, array $admin_session, ?array $json // Insert new USB device $stmt = $pdo->prepare(" - INSERT INTO usb_devices ( + INSERT INTO `" . t('usb_devices') . "` ( device_serial_number, device_name, technician_id, device_manufacturer, device_model, device_capacity_gb, device_description, registered_by_admin_id @@ -166,7 +166,7 @@ function handle_update_usb_device_status(PDO $pdo, array $admin_session, ?array } // Get device info before update - $stmt = $pdo->prepare("SELECT device_name, technician_id FROM usb_devices WHERE device_id = ?"); + $stmt = $pdo->prepare("SELECT device_name, technician_id FROM `" . t('usb_devices') . "` WHERE device_id = ?"); $stmt->execute([$deviceId]); $device = $stmt->fetch(PDO::FETCH_ASSOC); @@ -178,7 +178,7 @@ function handle_update_usb_device_status(PDO $pdo, array $admin_session, ?array // Update device status if ($newStatus === 'active') { $stmt = $pdo->prepare(" - UPDATE usb_devices + UPDATE `" . t('usb_devices') . "` SET device_status = 'active', disabled_date = NULL, disabled_by_admin_id = NULL, @@ -190,7 +190,7 @@ function handle_update_usb_device_status(PDO $pdo, array $admin_session, ?array $disableReason = $json_input['reason'] ?? null; $stmt = $pdo->prepare(" - UPDATE usb_devices + UPDATE `" . t('usb_devices') . "` SET device_status = ?, disabled_date = NOW(), disabled_by_admin_id = ?, @@ -218,7 +218,7 @@ function handle_delete_usb_device(PDO $pdo, array $admin_session, ?array $json_i $deviceId = intval($json_input['device_id'] ?? 0); - $stmt = $pdo->prepare("SELECT device_name, technician_id FROM usb_devices WHERE device_id = ?"); + $stmt = $pdo->prepare("SELECT device_name, technician_id FROM `" . t('usb_devices') . "` WHERE device_id = ?"); $stmt->execute([$deviceId]); $device = $stmt->fetch(PDO::FETCH_ASSOC); @@ -227,7 +227,7 @@ function handle_delete_usb_device(PDO $pdo, array $admin_session, ?array $json_i return; } - $stmt = $pdo->prepare("DELETE FROM usb_devices WHERE device_id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('usb_devices') . "` WHERE device_id = ?"); $stmt->execute([$deviceId]); logAdminActivity( diff --git a/FINAL_PRODUCTION_SYSTEM/database/2fa_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/2fa_migration.sql index 1f27a42..fc1fae9 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/2fa_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/2fa_migration.sql @@ -6,7 +6,7 @@ -- Table: admin_totp_secrets -- Stores TOTP secrets and backup codes for admin 2FA -CREATE TABLE IF NOT EXISTS `admin_totp_secrets` ( +CREATE TABLE IF NOT EXISTS `#__admin_totp_secrets` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `admin_id` INT NOT NULL COMMENT 'Reference to admin_users.id', `totp_secret` VARCHAR(255) NOT NULL COMMENT 'Base32 encoded TOTP secret', @@ -18,12 +18,12 @@ CREATE TABLE IF NOT EXISTS `admin_totp_secrets` ( UNIQUE KEY `idx_admin_id` (`admin_id`), INDEX `idx_enabled` (`totp_enabled`), - FOREIGN KEY (`admin_id`) REFERENCES `admin_users`(`id`) ON DELETE CASCADE + FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='TOTP 2FA secrets for admin accounts'; -- Table: trusted_networks -- Defines network subnets that are trusted for security bypasses -CREATE TABLE IF NOT EXISTS `trusted_networks` ( +CREATE TABLE IF NOT EXISTS `#__trusted_networks` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `network_name` VARCHAR(100) NOT NULL COMMENT 'Friendly name (e.g., "Office LAN")', `ip_range` VARCHAR(45) NOT NULL COMMENT 'CIDR notation (e.g., 192.168.1.0/24)', @@ -38,12 +38,12 @@ CREATE TABLE IF NOT EXISTS `trusted_networks` ( INDEX `idx_active` (`is_active`), INDEX `idx_bypass_2fa` (`bypass_2fa`, `is_active`), INDEX `idx_usb_auth` (`allow_usb_auth`, `is_active`), - FOREIGN KEY (`created_by_admin_id`) REFERENCES `admin_users`(`id`) ON DELETE SET NULL + FOREIGN KEY (`created_by_admin_id`) REFERENCES `#__admin_users`(`id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Trusted network subnets for security features'; -- Modify: admin_activity_log -- Add columns to track 2FA usage and trusted network bypasses -ALTER TABLE `admin_activity_log` +ALTER TABLE `#__admin_activity_log` ADD COLUMN IF NOT EXISTS `totp_verified` TINYINT(1) NULL COMMENT '1=2FA used, 0=bypassed, NULL=not applicable' AFTER `user_agent`, ADD COLUMN IF NOT EXISTS `trusted_network_id` INT NULL COMMENT 'If bypassed, which network' AFTER `totp_verified`, ADD INDEX IF NOT EXISTS `idx_totp_verified` (`totp_verified`); @@ -55,8 +55,8 @@ SET @fk_exists = (SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS AND CONSTRAINT_NAME = 'fk_admin_activity_log_trusted_network'); SET @sql = IF(@fk_exists = 0, - 'ALTER TABLE `admin_activity_log` ADD CONSTRAINT `fk_admin_activity_log_trusted_network` - FOREIGN KEY (`trusted_network_id`) REFERENCES `trusted_networks`(`id`) ON DELETE SET NULL', + 'ALTER TABLE `#__admin_activity_log` ADD CONSTRAINT `fk_admin_activity_log_trusted_network` + FOREIGN KEY (`trusted_network_id`) REFERENCES `#__trusted_networks`(`id`) ON DELETE SET NULL', 'SELECT "Foreign key already exists"'); PREPARE stmt FROM @sql; @@ -64,7 +64,7 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; -- System configuration for 2FA features -INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES +INSERT INTO `#__system_config` (`config_key`, `config_value`, `description`) VALUES ('totp_2fa_available', '1', 'Enable TOTP 2FA feature (1=yes, 0=no)'), ('totp_issuer_name', 'OEM Activation System', 'TOTP issuer name shown in authenticator app'), ('totp_backup_codes_count', '10', 'Number of backup codes to generate per user'), diff --git a/FINAL_PRODUCTION_SYSTEM/database/acl_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/acl_migration.sql index 1390bf4..d5fd64f 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/acl_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/acl_migration.sql @@ -10,7 +10,7 @@ -- ============================================================ -- Permission Categories (groups permissions for UI accordion) -CREATE TABLE IF NOT EXISTS acl_permission_categories ( +CREATE TABLE IF NOT EXISTS `#__acl_permission_categories` ( id INT AUTO_INCREMENT PRIMARY KEY, category_key VARCHAR(50) NOT NULL UNIQUE, display_name VARCHAR(100) NOT NULL, @@ -19,7 +19,7 @@ CREATE TABLE IF NOT EXISTS acl_permission_categories ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Granular Permissions -CREATE TABLE IF NOT EXISTS acl_permissions ( +CREATE TABLE IF NOT EXISTS `#__acl_permissions` ( id INT AUTO_INCREMENT PRIMARY KEY, permission_key VARCHAR(100) NOT NULL UNIQUE, display_name VARCHAR(100) NOT NULL, @@ -28,13 +28,13 @@ CREATE TABLE IF NOT EXISTS acl_permissions ( resource_type VARCHAR(50) NOT NULL, action_type ENUM('view','create','edit','delete','manage','execute') NOT NULL, is_dangerous TINYINT(1) DEFAULT 0 COMMENT 'Requires confirmation / shown with warning', - FOREIGN KEY (category_id) REFERENCES acl_permission_categories(id), + FOREIGN KEY (category_id) REFERENCES `#__acl_permission_categories`(id), INDEX idx_resource (resource_type), INDEX idx_category (category_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Custom Roles -CREATE TABLE IF NOT EXISTS acl_roles ( +CREATE TABLE IF NOT EXISTS `#__acl_roles` ( id INT AUTO_INCREMENT PRIMARY KEY, role_name VARCHAR(50) NOT NULL UNIQUE, display_name VARCHAR(100) NOT NULL, @@ -51,19 +51,19 @@ CREATE TABLE IF NOT EXISTS acl_roles ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Role <-> Permission Junction -CREATE TABLE IF NOT EXISTS acl_role_permissions ( +CREATE TABLE IF NOT EXISTS `#__acl_role_permissions` ( id INT AUTO_INCREMENT PRIMARY KEY, role_id INT NOT NULL, permission_id INT NOT NULL, granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, granted_by INT NULL, UNIQUE KEY unique_role_perm (role_id, permission_id), - FOREIGN KEY (role_id) REFERENCES acl_roles(id) ON DELETE CASCADE, - FOREIGN KEY (permission_id) REFERENCES acl_permissions(id) ON DELETE CASCADE + FOREIGN KEY (role_id) REFERENCES `#__acl_roles`(id) ON DELETE CASCADE, + FOREIGN KEY (permission_id) REFERENCES `#__acl_permissions`(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Per-User Permission Overrides -CREATE TABLE IF NOT EXISTS acl_user_overrides ( +CREATE TABLE IF NOT EXISTS `#__acl_user_overrides` ( id INT AUTO_INCREMENT PRIMARY KEY, user_type ENUM('admin','technician') NOT NULL, user_id INT NOT NULL, @@ -74,13 +74,13 @@ CREATE TABLE IF NOT EXISTS acl_user_overrides ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by INT NULL, UNIQUE KEY unique_user_perm (user_type, user_id, permission_id), - FOREIGN KEY (permission_id) REFERENCES acl_permissions(id) ON DELETE CASCADE, + FOREIGN KEY (permission_id) REFERENCES `#__acl_permissions`(id) ON DELETE CASCADE, INDEX idx_user (user_type, user_id), INDEX idx_expires (expires_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ACL Change Audit Log -CREATE TABLE IF NOT EXISTS acl_change_log ( +CREATE TABLE IF NOT EXISTS `#__acl_change_log` ( id INT AUTO_INCREMENT PRIMARY KEY, actor_id INT NOT NULL, actor_type ENUM('admin','system') DEFAULT 'admin', @@ -102,15 +102,15 @@ CREATE TABLE IF NOT EXISTS acl_change_log ( -- ============================================================ -- Add custom_role_id to admin_users (links to acl_roles for new ACL) -ALTER TABLE admin_users ADD COLUMN custom_role_id INT NULL AFTER role; -ALTER TABLE admin_users ADD CONSTRAINT fk_admin_acl_role FOREIGN KEY (custom_role_id) REFERENCES acl_roles(id) ON DELETE SET NULL; +ALTER TABLE `#__admin_users` ADD COLUMN custom_role_id INT NULL AFTER role; +ALTER TABLE `#__admin_users` ADD CONSTRAINT fk_admin_acl_role FOREIGN KEY (custom_role_id) REFERENCES `#__acl_roles`(id) ON DELETE SET NULL; -- Add role_id to technicians (links to acl_roles for technician roles) -ALTER TABLE technicians ADD COLUMN role_id INT NULL AFTER is_active; -ALTER TABLE technicians ADD CONSTRAINT fk_tech_acl_role FOREIGN KEY (role_id) REFERENCES acl_roles(id) ON DELETE SET NULL; +ALTER TABLE `#__technicians` ADD COLUMN role_id INT NULL AFTER is_active; +ALTER TABLE `#__technicians` ADD CONSTRAINT fk_tech_acl_role FOREIGN KEY (role_id) REFERENCES `#__acl_roles`(id) ON DELETE SET NULL; -- Add acl_v2_enabled config flag (disabled by default for safety) -INSERT INTO system_config (config_key, config_value, description) +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('acl_v2_enabled', '0', 'Enable database-driven ACL system (0=legacy hardcoded, 1=new ACL)') ON DUPLICATE KEY UPDATE config_key = config_key; @@ -118,7 +118,7 @@ ON DUPLICATE KEY UPDATE config_key = config_key; -- SEED: Permission Categories -- ============================================================ -INSERT INTO acl_permission_categories (category_key, display_name, icon, sort_order) VALUES +INSERT INTO `#__acl_permission_categories` (category_key, display_name, icon, sort_order) VALUES ('dashboard', 'Dashboard & Reports', NULL, 10), ('keys', 'OEM Key Management', NULL, 20), ('technicians', 'Technician Management', NULL, 30), @@ -134,7 +134,7 @@ INSERT INTO acl_permission_categories (category_key, display_name, icon, sort_or -- SEED: Granular Permissions (~38) -- ============================================================ -INSERT INTO acl_permissions (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) VALUES +INSERT INTO `#__acl_permissions` (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) VALUES -- Dashboard (cat 1) ('view_dashboard', 'View Dashboard', 'Access the main dashboard with statistics', 1, 'dashboard', 'view', 0), ('view_reports', 'View Reports', 'Access activation and usage reports', 1, 'dashboard', 'view', 0), @@ -199,7 +199,7 @@ INSERT INTO acl_permissions (permission_key, display_name, description, category -- SEED: Roles (7 admin + 2 technician) -- ============================================================ -INSERT INTO acl_roles (role_name, display_name, description, role_type, is_system_role, priority, color) VALUES +INSERT INTO `#__acl_roles` (role_name, display_name, description, role_type, is_system_role, priority, color) VALUES -- Admin roles ('super_admin', 'Super Administrator', 'Full system access including admin management, system settings, backups, and role management', 'admin', 1, 100, '#dc3545'), ('admin', 'Administrator', 'All data operations except delete, admin management, and system settings', 'admin', 1, 80, '#007bff'), @@ -218,15 +218,15 @@ INSERT INTO acl_roles (role_name, display_name, description, role_type, is_syste -- Helper: Get role and permission IDs for assignment -- super_admin: ALL permissions -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r CROSS JOIN acl_permissions p +FROM `#__acl_roles` r CROSS JOIN `#__acl_permissions` p WHERE r.role_name = 'super_admin'; -- admin: All view + edit/create operations, NO delete, NO admin mgmt, NO system settings, NO role mgmt -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'admin' AND p.permission_key IN ( 'view_dashboard', 'view_reports', 'export_data', 'view_keys', 'add_key', 'import_keys', 'edit_key', 'recycle_key', @@ -239,9 +239,9 @@ WHERE r.role_name = 'admin' AND p.permission_key IN ( ); -- billing_manager: Dashboard, keys (view only), activations (view), reports, export, logs -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'billing_manager' AND p.permission_key IN ( 'view_dashboard', 'view_reports', 'export_data', 'view_keys', @@ -250,9 +250,9 @@ WHERE r.role_name = 'billing_manager' AND p.permission_key IN ( ); -- hr_manager: Dashboard, technician CRUD, password reset, role assignment -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'hr_manager' AND p.permission_key IN ( 'view_dashboard', 'view_technicians', 'add_technician', 'edit_technician', 'reset_tech_password', 'assign_tech_role', @@ -260,9 +260,9 @@ WHERE r.role_name = 'hr_manager' AND p.permission_key IN ( ); -- qc_inspector: View activations, hardware, add notes, export -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'qc_inspector' AND p.permission_key IN ( 'view_dashboard', 'view_reports', 'export_data', 'view_activations', 'add_activation_note', @@ -270,9 +270,9 @@ WHERE r.role_name = 'qc_inspector' AND p.permission_key IN ( ); -- dept_manager: View technicians, activations, hardware, dashboard, add notes -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'dept_manager' AND p.permission_key IN ( 'view_dashboard', 'view_reports', 'export_data', 'view_technicians', @@ -282,9 +282,9 @@ WHERE r.role_name = 'dept_manager' AND p.permission_key IN ( ); -- viewer: Read-only across the board -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'viewer' AND p.permission_key IN ( 'view_dashboard', 'view_reports', 'export_data', 'view_keys', @@ -297,17 +297,17 @@ WHERE r.role_name = 'viewer' AND p.permission_key IN ( ); -- technician_full: Can activate, submit hardware -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'technician_full' AND p.permission_key IN ( 'view_keys', 'view_activations', 'view_hardware' ); -- technician_limited: View only -INSERT INTO acl_role_permissions (role_id, permission_id) +INSERT INTO `#__acl_role_permissions` (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'technician_limited' AND p.permission_key IN ( 'view_keys' ); @@ -317,6 +317,6 @@ WHERE r.role_name = 'technician_limited' AND p.permission_key IN ( -- Map legacy role ENUM to new custom_role_id -- ============================================================ -UPDATE admin_users au -INNER JOIN acl_roles ar ON ar.role_name COLLATE utf8mb4_general_ci = au.role COLLATE utf8mb4_general_ci AND ar.role_type = 'admin' +UPDATE `#__admin_users` au +INNER JOIN `#__acl_roles` ar ON ar.role_name COLLATE utf8mb4_general_ci = au.role COLLATE utf8mb4_general_ci AND ar.role_type = 'admin' SET au.custom_role_id = ar.id; diff --git a/FINAL_PRODUCTION_SYSTEM/database/backup_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/backup_migration.sql index 2efd0aa..183ec9a 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/backup_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/backup_migration.sql @@ -5,7 +5,7 @@ -- Table: backup_history -- Tracks all database backups (automated and manual) -CREATE TABLE IF NOT EXISTS `backup_history` ( +CREATE TABLE IF NOT EXISTS `#__backup_history` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `backup_filename` VARCHAR(255) NOT NULL COMMENT 'Filename in backups directory', `backup_size_mb` DECIMAL(10,2) NOT NULL COMMENT 'Backup file size in megabytes', @@ -25,12 +25,12 @@ CREATE TABLE IF NOT EXISTS `backup_history` ( INDEX `idx_backup_type` (`backup_type`), INDEX `idx_deleted_at` (`deleted_at`), INDEX `idx_filename` (`backup_filename`), - FOREIGN KEY (`created_by_admin_id`) REFERENCES `admin_users`(`id`) ON DELETE SET NULL + FOREIGN KEY (`created_by_admin_id`) REFERENCES `#__admin_users`(`id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Database backup history and tracking'; -- Table: backup_restore_log -- Tracks database restore operations for disaster recovery audit -CREATE TABLE IF NOT EXISTS `backup_restore_log` ( +CREATE TABLE IF NOT EXISTS `#__backup_restore_log` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `backup_history_id` INT NULL COMMENT 'Which backup was restored', `backup_filename` VARCHAR(255) NOT NULL COMMENT 'Backup file used for restore', @@ -44,12 +44,12 @@ CREATE TABLE IF NOT EXISTS `backup_restore_log` ( INDEX `idx_restored_at` (`restored_at`), INDEX `idx_restore_status` (`restore_status`), - FOREIGN KEY (`backup_history_id`) REFERENCES `backup_history`(`id`) ON DELETE SET NULL, - FOREIGN KEY (`restored_by_admin_id`) REFERENCES `admin_users`(`id`) ON DELETE SET NULL + FOREIGN KEY (`backup_history_id`) REFERENCES `#__backup_history`(`id`) ON DELETE SET NULL, + FOREIGN KEY (`restored_by_admin_id`) REFERENCES `#__admin_users`(`id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Database restore operation audit log'; -- System configuration for automated backups -INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES +INSERT INTO `#__system_config` (`config_key`, `config_value`, `description`) VALUES ('backup_enabled', '1', 'Enable automated database backups (1=yes, 0=no)'), ('backup_retention_days', '30', 'Number of days to keep backups before deletion'), ('backup_schedule', '0 2 * * *', 'Backup cron schedule (default: daily at 2 AM UTC)'), diff --git a/FINAL_PRODUCTION_SYSTEM/database/client_config_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/client_config_migration.sql index 2cbda75..bd1b580 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/client_config_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/client_config_migration.sql @@ -5,7 +5,7 @@ -- activation timing, and network diagnostics settings. -- ============================================================= -INSERT INTO system_config (config_key, config_value, description) VALUES +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES -- Pre-Activation Task Toggles ('client_task_wsus_cleanup', '1', 'Enable WSUS cleanup before activation'), ('client_task_security_hardening', '1', 'Enable SMB security hardening'), diff --git a/FINAL_PRODUCTION_SYSTEM/database/client_resources_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/client_resources_migration.sql index ca942ba..ad31235 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/client_resources_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/client_resources_migration.sql @@ -2,7 +2,7 @@ -- Phase 9: PowerShell 7 Migration — Hosted MSI Installer -- Run this migration to add the client_resources table and PS7 config entries -CREATE TABLE IF NOT EXISTS client_resources ( +CREATE TABLE IF NOT EXISTS `#__client_resources` ( id INT AUTO_INCREMENT PRIMARY KEY, resource_key VARCHAR(100) NOT NULL UNIQUE, filename VARCHAR(255) NOT NULL, @@ -14,5 +14,5 @@ CREATE TABLE IF NOT EXISTS client_resources ( uploaded_by INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - FOREIGN KEY (uploaded_by) REFERENCES admin_users(id) ON DELETE SET NULL + FOREIGN KEY (uploaded_by) REFERENCES `#__admin_users`(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/FINAL_PRODUCTION_SYSTEM/database/create_admin.php b/FINAL_PRODUCTION_SYSTEM/database/create_admin.php index 455f123..94379d9 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/create_admin.php +++ b/FINAL_PRODUCTION_SYSTEM/database/create_admin.php @@ -2,8 +2,8 @@ require __DIR__ . '/../config.php'; $hash = password_hash("Admin2024!", PASSWORD_BCRYPT, ["cost" => 10]); // Get super_admin role ID from acl_roles -$roleId = $pdo->query("SELECT id FROM acl_roles WHERE role_name = 'super_admin' LIMIT 1")->fetchColumn() ?: null; +$roleId = $pdo->query("SELECT id FROM `" . t('acl_roles') . "` WHERE role_name = 'super_admin' LIMIT 1")->fetchColumn() ?: null; -$stmt = $pdo->prepare("INSERT INTO admin_users (username, password_hash, full_name, email, role, custom_role_id) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE password_hash = VALUES(password_hash), custom_role_id = VALUES(custom_role_id), failed_login_attempts = 0, locked_until = NULL"); +$stmt = $pdo->prepare("INSERT INTO `" . t('admin_users') . "` (username, password_hash, full_name, email, role, custom_role_id) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE password_hash = VALUES(password_hash), custom_role_id = VALUES(custom_role_id), failed_login_attempts = 0, locked_until = NULL"); $stmt->execute(["admin", $hash, "Administrator", "admin@localhost", "super_admin", $roleId]); echo "Admin user created/reset\n"; diff --git a/FINAL_PRODUCTION_SYSTEM/database/database_admin_security.sql b/FINAL_PRODUCTION_SYSTEM/database/database_admin_security.sql index 0dad74c..e628b04 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/database_admin_security.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/database_admin_security.sql @@ -3,8 +3,8 @@ USE oem_activation; --- Admin users table (separate from technicians) -CREATE TABLE admin_users ( +-- Admin users table (separate from `#__technicians`) +CREATE TABLE `#__admin_users` ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, full_name VARCHAR(100) NOT NULL, @@ -22,11 +22,11 @@ CREATE TABLE admin_users ( created_by INT, INDEX idx_username (username), INDEX idx_is_active (is_active), - FOREIGN KEY (created_by) REFERENCES admin_users(id) + FOREIGN KEY (created_by) REFERENCES `#__admin_users`(id) ); -- Admin sessions table -CREATE TABLE admin_sessions ( +CREATE TABLE `#__admin_sessions` ( id INT AUTO_INCREMENT PRIMARY KEY, admin_id INT NOT NULL, session_token VARCHAR(64) NOT NULL UNIQUE, @@ -36,14 +36,14 @@ CREATE TABLE admin_sessions ( last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, expires_at TIMESTAMP NOT NULL, is_active BOOLEAN DEFAULT TRUE, - FOREIGN KEY (admin_id) REFERENCES admin_users(id), + FOREIGN KEY (admin_id) REFERENCES `#__admin_users`(id), INDEX idx_session_token (session_token), INDEX idx_admin_id (admin_id), INDEX idx_expires_at (expires_at) ); -- Admin activity log -CREATE TABLE admin_activity_log ( +CREATE TABLE `#__admin_activity_log` ( id INT AUTO_INCREMENT PRIMARY KEY, admin_id INT, session_id INT, @@ -52,15 +52,15 @@ CREATE TABLE admin_activity_log ( ip_address VARCHAR(45), user_agent TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (admin_id) REFERENCES admin_users(id), - FOREIGN KEY (session_id) REFERENCES admin_sessions(id), + FOREIGN KEY (admin_id) REFERENCES `#__admin_users`(id), + FOREIGN KEY (session_id) REFERENCES `#__admin_sessions`(id), INDEX idx_admin_id (admin_id), INDEX idx_created_at (created_at), INDEX idx_action (action) ); -- IP whitelist table -CREATE TABLE admin_ip_whitelist ( +CREATE TABLE `#__admin_ip_whitelist` ( id INT AUTO_INCREMENT PRIMARY KEY, ip_address VARCHAR(45) NOT NULL, ip_range VARCHAR(45), @@ -68,13 +68,13 @@ CREATE TABLE admin_ip_whitelist ( is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by INT, - FOREIGN KEY (created_by) REFERENCES admin_users(id), + FOREIGN KEY (created_by) REFERENCES `#__admin_users`(id), INDEX idx_ip_address (ip_address), INDEX idx_is_active (is_active) ); -- Add security configuration -INSERT INTO system_config (config_key, config_value, description) VALUES +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('admin_session_timeout_minutes', '30', 'Admin session timeout in minutes'), ('admin_max_failed_logins', '3', 'Maximum failed admin login attempts'), ('admin_lockout_duration_minutes', '30', 'Admin account lockout duration'), @@ -87,12 +87,12 @@ ON DUPLICATE KEY UPDATE config_value = VALUES(config_value); -- Create initial super admin (password: SuperSecure2024!) -- Password hash for: SuperSecure2024! -INSERT INTO admin_users (username, full_name, email, password_hash, role, must_change_password, created_by) +INSERT INTO `#__admin_users` (username, full_name, email, password_hash, role, must_change_password, created_by) VALUES ('superadmin', 'Super Administrator', 'admin@yourcompany.com', '$2y$12$LQv3c1yqBwlVHpPd7u/Dw.G2K2wjDUl9jhJxfTULt3lOAOWuTDBKG', 'super_admin', TRUE, NULL); -- Add some safe IP addresses (update these for your environment) --- INSERT INTO admin_ip_whitelist (ip_address, description, created_by) VALUES +-- INSERT INTO `#__admin_ip_whitelist` (ip_address, description, created_by) VALUES -- ('192.168.1.0/24', 'Local network', 1), -- ('10.0.0.0/8', 'Internal network', 1); \ No newline at end of file diff --git a/FINAL_PRODUCTION_SYSTEM/database/database_concurrency_indexes.sql b/FINAL_PRODUCTION_SYSTEM/database/database_concurrency_indexes.sql index 247e840..23c4945 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/database_concurrency_indexes.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/database_concurrency_indexes.sql @@ -3,35 +3,35 @@ -- Run this after the main database installation -- Optimize key selection queries (CRITICAL for allocateKeyAtomically) -ALTER TABLE oem_keys +ALTER TABLE `#__oem_keys` ADD INDEX idx_status_fail_date (key_status, fail_counter, last_use_date, id); -- Optimize session lookups for concurrent access -ALTER TABLE active_sessions +ALTER TABLE `#__active_sessions` ADD INDEX idx_tech_active_expires (technician_id, is_active, expires_at); -- Optimize activation attempts queries -ALTER TABLE activation_attempts +ALTER TABLE `#__activation_attempts` ADD INDEX idx_key_tech_date (key_id, technician_id, attempted_at); -- Optimize admin session queries -ALTER TABLE admin_sessions +ALTER TABLE `#__admin_sessions` ADD INDEX idx_admin_active_expires (admin_id, is_active, expires_at); -- Composite index for common technician queries -ALTER TABLE technicians +ALTER TABLE `#__technicians` ADD INDEX idx_active_locked (is_active, locked_until); -- Index for cleanup operations (expired sessions) -ALTER TABLE active_sessions +ALTER TABLE `#__active_sessions` ADD INDEX idx_expires_active (expires_at, is_active); -- Index for audit trail queries -ALTER TABLE admin_activity_log +ALTER TABLE `#__admin_activity_log` ADD INDEX idx_admin_action_time (admin_id, action, created_at); -- Index for key usage statistics -ALTER TABLE oem_keys +ALTER TABLE `#__oem_keys` ADD INDEX idx_first_usage (first_usage_date, key_status); -- Update table statistics for better query planning diff --git a/FINAL_PRODUCTION_SYSTEM/database/database_setup.sql b/FINAL_PRODUCTION_SYSTEM/database/database_setup.sql index 5d9c5d2..56caca0 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/database_setup.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/database_setup.sql @@ -5,7 +5,7 @@ CREATE DATABASE IF NOT EXISTS oem_activation; USE oem_activation; -- Table to store OEM keys -CREATE TABLE oem_keys ( +CREATE TABLE `#__oem_keys` ( id INT AUTO_INCREMENT PRIMARY KEY, product_key VARCHAR(29) NOT NULL UNIQUE, oem_identifier VARCHAR(20) NOT NULL, @@ -21,7 +21,7 @@ CREATE TABLE oem_keys ( ); -- Table to track activation attempts -CREATE TABLE activation_attempts ( +CREATE TABLE `#__activation_attempts` ( id INT AUTO_INCREMENT PRIMARY KEY, key_id INT NOT NULL, order_number VARCHAR(10) NOT NULL, @@ -31,15 +31,15 @@ CREATE TABLE activation_attempts ( attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, client_ip VARCHAR(45), notes TEXT, - FOREIGN KEY (key_id) REFERENCES oem_keys(id), - FOREIGN KEY (technician_id) REFERENCES technicians(technician_id), + FOREIGN KEY (key_id) REFERENCES `#__oem_keys`(id), + FOREIGN KEY (technician_id) REFERENCES `#__technicians`(technician_id), INDEX idx_order_number (order_number), INDEX idx_technician_id (technician_id), INDEX idx_attempted_at (attempted_at) ); -- Table to store active sessions/tokens -CREATE TABLE active_sessions ( +CREATE TABLE `#__active_sessions` ( id INT AUTO_INCREMENT PRIMARY KEY, technician_id VARCHAR(20) NOT NULL, session_token VARCHAR(64) NOT NULL UNIQUE, @@ -48,14 +48,14 @@ CREATE TABLE active_sessions ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP NOT NULL, is_active BOOLEAN DEFAULT TRUE, - FOREIGN KEY (key_id) REFERENCES oem_keys(id), + FOREIGN KEY (key_id) REFERENCES `#__oem_keys`(id), INDEX idx_session_token (session_token), INDEX idx_technician_id (technician_id), INDEX idx_expires_at (expires_at) ); -- Table for system configuration -CREATE TABLE system_config ( +CREATE TABLE `#__system_config` ( config_key VARCHAR(50) PRIMARY KEY, config_value TEXT NOT NULL, description TEXT, @@ -63,7 +63,7 @@ CREATE TABLE system_config ( ); -- Insert basic configuration -INSERT INTO system_config (config_key, config_value, description) VALUES +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('smtp_server', 'smtp.zoho.com', 'SMTP server for notifications'), ('smtp_port', '587', 'SMTP port'), ('smtp_username', 'oem.activation@roo24.chesnotech.ru', 'SMTP username'), diff --git a/FINAL_PRODUCTION_SYSTEM/database/database_setup_with_users.sql b/FINAL_PRODUCTION_SYSTEM/database/database_setup_with_users.sql index aeb3e77..cee0f75 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/database_setup_with_users.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/database_setup_with_users.sql @@ -5,7 +5,7 @@ CREATE DATABASE IF NOT EXISTS oem_activation; USE oem_activation; -- Table to store technician accounts -CREATE TABLE technicians ( +CREATE TABLE `#__technicians` ( id INT AUTO_INCREMENT PRIMARY KEY, technician_id VARCHAR(20) NOT NULL UNIQUE, full_name VARCHAR(100) NOT NULL, @@ -25,7 +25,7 @@ CREATE TABLE technicians ( ); -- Table to store OEM keys -CREATE TABLE oem_keys ( +CREATE TABLE `#__oem_keys` ( id INT AUTO_INCREMENT PRIMARY KEY, product_key VARCHAR(29) NOT NULL UNIQUE, oem_identifier VARCHAR(20) NOT NULL, @@ -41,7 +41,7 @@ CREATE TABLE oem_keys ( ); -- Table to track activation attempts -CREATE TABLE activation_attempts ( +CREATE TABLE `#__activation_attempts` ( id INT AUTO_INCREMENT PRIMARY KEY, key_id INT NOT NULL, technician_id VARCHAR(20) NOT NULL, @@ -51,15 +51,15 @@ CREATE TABLE activation_attempts ( attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, client_ip VARCHAR(45), notes TEXT, - FOREIGN KEY (key_id) REFERENCES oem_keys(id), - FOREIGN KEY (technician_id) REFERENCES technicians(technician_id), + FOREIGN KEY (key_id) REFERENCES `#__oem_keys`(id), + FOREIGN KEY (technician_id) REFERENCES `#__technicians`(technician_id), INDEX idx_order_number (order_number), INDEX idx_technician_id (technician_id), INDEX idx_attempted_at (attempted_at) ); -- Table to store active sessions/tokens -CREATE TABLE active_sessions ( +CREATE TABLE `#__active_sessions` ( id INT AUTO_INCREMENT PRIMARY KEY, technician_id VARCHAR(20) NOT NULL, session_token VARCHAR(64) NOT NULL UNIQUE, @@ -68,15 +68,15 @@ CREATE TABLE active_sessions ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP NOT NULL, is_active BOOLEAN DEFAULT TRUE, - FOREIGN KEY (key_id) REFERENCES oem_keys(id), - FOREIGN KEY (technician_id) REFERENCES technicians(technician_id), + FOREIGN KEY (key_id) REFERENCES `#__oem_keys`(id), + FOREIGN KEY (technician_id) REFERENCES `#__technicians`(technician_id), INDEX idx_session_token (session_token), INDEX idx_technician_id (technician_id), INDEX idx_expires_at (expires_at) ); -- Table for system configuration -CREATE TABLE system_config ( +CREATE TABLE `#__system_config` ( config_key VARCHAR(50) PRIMARY KEY, config_value TEXT NOT NULL, description TEXT, @@ -84,20 +84,20 @@ CREATE TABLE system_config ( ); -- Table for password reset tokens -CREATE TABLE password_reset_tokens ( +CREATE TABLE `#__password_reset_tokens` ( id INT AUTO_INCREMENT PRIMARY KEY, technician_id VARCHAR(20) NOT NULL, reset_token VARCHAR(64) NOT NULL UNIQUE, expires_at TIMESTAMP NOT NULL, used_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (technician_id) REFERENCES technicians(technician_id), + FOREIGN KEY (technician_id) REFERENCES `#__technicians`(technician_id), INDEX idx_reset_token (reset_token), INDEX idx_expires_at (expires_at) ); -- Insert basic configuration -INSERT INTO system_config (config_key, config_value, description) VALUES +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('smtp_server', 'smtp.zoho.com', 'SMTP server for notifications'), ('smtp_port', '587', 'SMTP port'), ('smtp_username', 'oem.activation@roo24.chesnotech.ru', 'SMTP username'), @@ -115,13 +115,13 @@ INSERT INTO system_config (config_key, config_value, description) VALUES ('show_full_keys_in_admin', '0', 'Show full product keys in admin panel (1=yes, 0=no - admin only)'); -- Create default admin account (password: admin123 - CHANGE THIS!) -INSERT INTO technicians (technician_id, full_name, email, password_hash, must_change_password, created_by, notes) +INSERT INTO `#__technicians` (technician_id, full_name, email, password_hash, must_change_password, created_by, notes) VALUES ('admin', 'System Administrator', 'admin@yourcompany.com', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', TRUE, 'system', 'Default admin account - change password immediately'); -- Create sample technician account (password: temp123) -INSERT INTO technicians (technician_id, full_name, email, password_hash, temp_password, must_change_password, created_by, notes) +INSERT INTO `#__technicians` (technician_id, full_name, email, password_hash, temp_password, must_change_password, created_by, notes) VALUES ('tech001', 'John Technician', 'tech001@yourcompany.com', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'temp123', TRUE, 'admin', 'Sample technician account'); \ No newline at end of file diff --git a/FINAL_PRODUCTION_SYSTEM/database/docker-init/00-init.sh b/FINAL_PRODUCTION_SYSTEM/database/docker-init/00-init.sh index bac8e58..fb6bcc1 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/docker-init/00-init.sh +++ b/FINAL_PRODUCTION_SYSTEM/database/docker-init/00-init.sh @@ -15,16 +15,45 @@ DB="${MARIADB_DATABASE:-oem_activation}" SQL_DIR="/docker-entrypoint-initdb.d/sql" MYSQL_CMD="mysql -u root -p${MARIADB_ROOT_PASSWORD} ${DB}" +# ── Table prefix support ───────────────────────────────────── +# SQL files use the Joomla-style sentinel `#__` for table names. +# At init time we substitute it with $KEYGATE_DB_PREFIX (default: empty +# string → identical schema to pre-prefix releases). +PREFIX="${KEYGATE_DB_PREFIX:-}" +SV_TABLE="${PREFIX}schema_versions" + +# Validate prefix: must match ^[a-z][a-z0-9_]{0,9}$ or be empty. +if [ -n "$PREFIX" ]; then + if ! echo "$PREFIX" | grep -qE '^[a-z][a-z0-9_]{0,9}$'; then + echo "[ERROR] Invalid KEYGATE_DB_PREFIX='$PREFIX'. Must match ^[a-z][a-z0-9_]{0,9}\$ or be empty." + exit 1 + fi +fi + echo "=== KeyGate: Database Initialization ===" echo "Database: $DB" echo "SQL directory: $SQL_DIR" +echo "Table prefix: ${PREFIX:-}" + +# ── Substitute #__ → $PREFIX for every .sql file in $SQL_DIR ── +# We copy to /tmp/keygate-sql/ so the original mounted volume stays +# untouched (read-only on some setups). +STAGING="/tmp/keygate-sql" +mkdir -p "$STAGING" +for f in "$SQL_DIR"/*.sql; do + [ -f "$f" ] || continue + base="$(basename "$f")" + # sed -i won't work on read-only mounts; pipe through to a fresh file. + sed "s/#__/${PREFIX}/g" "$f" > "$STAGING/$base" +done +SQL_DIR="$STAGING" # ── Step 0: Ensure schema_versions table exists ────────────── # This must run unconditionally so the tracking table is always present. $MYSQL_CMD < "$SQL_DIR/schema_versions_migration.sql" 2>/dev/null || true # ── Idempotent migration runner ────────────────────────────── -# Checks schema_versions before running; records after success. +# Checks ${PREFIX}schema_versions before running; records after success. run_sql() { local file="$SQL_DIR/$1" local version="$2" @@ -36,7 +65,7 @@ run_sql() { # Check if already applied local applied - applied=$($MYSQL_CMD -N -e "SELECT COUNT(*) FROM schema_versions WHERE filename = '$1'" 2>/dev/null || echo "0") + applied=$($MYSQL_CMD -N -e "SELECT COUNT(*) FROM \`${SV_TABLE}\` WHERE filename = '$1'" 2>/dev/null || echo "0") if [ "$applied" -gt 0 ]; then echo "[SKIP] Already applied: $1" @@ -48,11 +77,18 @@ run_sql() { echo "[WARN] Non-fatal errors in $1 (continuing)" fi - # Compute checksum and record + # Compute checksum from the original (un-substituted) file so the + # checksum is stable regardless of prefix choice. Falls back to staged + # copy if the original isn't accessible. + local original="/docker-entrypoint-initdb.d/sql/$1" local checksum - checksum=$(sha256sum "$file" | cut -d' ' -f1) + if [ -f "$original" ]; then + checksum=$(sha256sum "$original" | cut -d' ' -f1) + else + checksum=$(sha256sum "$file" | cut -d' ' -f1) + fi - $MYSQL_CMD -e "INSERT INTO schema_versions (version, filename, checksum) VALUES ($version, '$1', '$checksum')" + $MYSQL_CMD -e "INSERT INTO \`${SV_TABLE}\` (version, filename, checksum) VALUES ($version, '$1', '$checksum')" echo "[DONE] Applied: $1" } diff --git a/FINAL_PRODUCTION_SYSTEM/database/downloads_acl_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/downloads_acl_migration.sql index d5da7bd..e66a039 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/downloads_acl_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/downloads_acl_migration.sql @@ -5,33 +5,33 @@ -- ============================================================ -- Add "Downloads" permission category -INSERT INTO acl_permission_categories (category_key, display_name, icon, sort_order) +INSERT INTO `#__acl_permission_categories` (category_key, display_name, icon, sort_order) VALUES ('downloads', 'Client Downloads', NULL, 55) ON DUPLICATE KEY UPDATE display_name = VALUES(display_name); -- Add download permissions -INSERT INTO acl_permissions (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) +INSERT INTO `#__acl_permissions` (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) SELECT 'view_downloads', 'View Downloads', 'View and download client tools (launcher, PS7 installer, extensions)', c.id, 'downloads', 'view', 0 -FROM acl_permission_categories c WHERE c.category_key = 'downloads' +FROM `#__acl_permission_categories` c WHERE c.category_key = 'downloads' ON DUPLICATE KEY UPDATE display_name = VALUES(display_name); -INSERT INTO acl_permissions (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) +INSERT INTO `#__acl_permissions` (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) SELECT 'manage_downloads', 'Manage Downloads', 'Upload, replace, and delete client resources', c.id, 'downloads', 'manage', 1 -FROM acl_permission_categories c WHERE c.category_key = 'downloads' +FROM `#__acl_permission_categories` c WHERE c.category_key = 'downloads' ON DUPLICATE KEY UPDATE display_name = VALUES(display_name); -- Grant both permissions to super_admin role INSERT IGNORE INTO acl_role_permissions (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r CROSS JOIN acl_permissions p +FROM `#__acl_roles` r CROSS JOIN `#__acl_permissions` p WHERE r.role_name = 'super_admin' AND p.permission_key IN ('view_downloads', 'manage_downloads'); -- Grant view_downloads to admin role INSERT IGNORE INTO acl_role_permissions (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'admin' AND p.permission_key = 'view_downloads'; diff --git a/FINAL_PRODUCTION_SYSTEM/database/hardware_info_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/hardware_info_migration.sql index cee3e96..8dde0c3 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/hardware_info_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/hardware_info_migration.sql @@ -3,12 +3,12 @@ -- Purpose: Make OEM ID and Roll Serial optional, add hardware tracking -- Step 1: Make OEM ID and Roll Serial optional in oem_keys table -ALTER TABLE oem_keys +ALTER TABLE `#__oem_keys` MODIFY COLUMN oem_identifier VARCHAR(20) NULL DEFAULT NULL, MODIFY COLUMN roll_serial VARCHAR(20) NULL DEFAULT NULL; -- Step 2: Create hardware_info table for tracking PC hardware details -CREATE TABLE IF NOT EXISTS hardware_info ( +CREATE TABLE IF NOT EXISTS `#__hardware_info` ( id INT AUTO_INCREMENT PRIMARY KEY, activation_id INT NOT NULL COMMENT 'Links to activation_attempts.id', order_number VARCHAR(10) NOT NULL COMMENT 'Order number for easy reference', @@ -60,11 +60,11 @@ CREATE TABLE IF NOT EXISTS hardware_info ( INDEX idx_order_number (order_number), INDEX idx_collected_at (collected_at), - FOREIGN KEY (activation_id) REFERENCES activation_attempts(id) ON DELETE CASCADE + FOREIGN KEY (activation_id) REFERENCES `#__activation_attempts`(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Hardware information collected during activation'; -- Step 3: Add hardware_collected flag to activation_attempts -ALTER TABLE activation_attempts +ALTER TABLE `#__activation_attempts` ADD COLUMN hardware_collected TINYINT(1) DEFAULT 0 COMMENT 'Whether hardware info was collected for this activation'; -- Step 4: Create view for easy hardware lookup by order number @@ -86,12 +86,12 @@ SELECT h.ram_total_capacity_gb, h.secure_boot_enabled, h.collected_at AS hardware_collected_at -FROM activation_attempts a -LEFT JOIN technicians t ON a.technician_id = t.technician_id -LEFT JOIN oem_keys k ON a.key_id = k.id -LEFT JOIN hardware_info h ON h.activation_id = a.id +FROM `#__activation_attempts` a +LEFT JOIN `#__technicians` t ON a.technician_id = t.technician_id +LEFT JOIN `#__oem_keys` k ON a.key_id = k.id +LEFT JOIN `#__hardware_info` h ON h.activation_id = a.id ORDER BY a.attempted_at DESC; -- Step 5: (Optional) Add secure_boot_enabled column if table already exists without it -- Run this only if you applied the migration before this column was added: --- ALTER TABLE hardware_info ADD COLUMN secure_boot_enabled TINYINT(1) NULL COMMENT 'Whether Secure Boot is enabled (1=yes, 0=no, NULL=unknown)' AFTER os_architecture; +-- ALTER TABLE `#__hardware_info` ADD COLUMN secure_boot_enabled TINYINT(1) NULL COMMENT 'Whether Secure Boot is enabled (1=yes, 0=no, NULL=unknown)' AFTER os_architecture; diff --git a/FINAL_PRODUCTION_SYSTEM/database/hardware_info_v2_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/hardware_info_v2_migration.sql index ae57497..aa65dbc 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/hardware_info_v2_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/hardware_info_v2_migration.sql @@ -5,48 +5,48 @@ -- Add new columns to hardware_info table -- Chassis / Enclosure Information -ALTER TABLE hardware_info ADD COLUMN chassis_manufacturer VARCHAR(100) NULL AFTER computer_name; -ALTER TABLE hardware_info ADD COLUMN chassis_serial VARCHAR(100) NULL AFTER chassis_manufacturer; -ALTER TABLE hardware_info ADD COLUMN chassis_type VARCHAR(50) NULL AFTER chassis_serial; +ALTER TABLE `#__hardware_info` ADD COLUMN chassis_manufacturer VARCHAR(100) NULL AFTER computer_name; +ALTER TABLE `#__hardware_info` ADD COLUMN chassis_serial VARCHAR(100) NULL AFTER chassis_manufacturer; +ALTER TABLE `#__hardware_info` ADD COLUMN chassis_type VARCHAR(50) NULL AFTER chassis_serial; -- System Product Information (OEM) -ALTER TABLE hardware_info ADD COLUMN system_manufacturer VARCHAR(100) NULL AFTER chassis_type; -ALTER TABLE hardware_info ADD COLUMN system_product_name VARCHAR(200) NULL AFTER system_manufacturer; -ALTER TABLE hardware_info ADD COLUMN system_serial VARCHAR(100) NULL AFTER system_product_name; -ALTER TABLE hardware_info ADD COLUMN system_uuid VARCHAR(50) NULL AFTER system_serial; +ALTER TABLE `#__hardware_info` ADD COLUMN system_manufacturer VARCHAR(100) NULL AFTER chassis_type; +ALTER TABLE `#__hardware_info` ADD COLUMN system_product_name VARCHAR(200) NULL AFTER system_manufacturer; +ALTER TABLE `#__hardware_info` ADD COLUMN system_serial VARCHAR(100) NULL AFTER system_product_name; +ALTER TABLE `#__hardware_info` ADD COLUMN system_uuid VARCHAR(50) NULL AFTER system_serial; -- TPM Information -ALTER TABLE hardware_info ADD COLUMN tpm_present TINYINT(1) NULL AFTER system_uuid; -ALTER TABLE hardware_info ADD COLUMN tpm_version VARCHAR(50) NULL AFTER tpm_present; -ALTER TABLE hardware_info ADD COLUMN tpm_manufacturer VARCHAR(100) NULL AFTER tpm_version; +ALTER TABLE `#__hardware_info` ADD COLUMN tpm_present TINYINT(1) NULL AFTER system_uuid; +ALTER TABLE `#__hardware_info` ADD COLUMN tpm_version VARCHAR(50) NULL AFTER tpm_present; +ALTER TABLE `#__hardware_info` ADD COLUMN tpm_manufacturer VARCHAR(100) NULL AFTER tpm_version; -- CPU Serial (Processor ID) -ALTER TABLE hardware_info ADD COLUMN cpu_serial VARCHAR(50) NULL AFTER cpu_max_clock_speed; +ALTER TABLE `#__hardware_info` ADD COLUMN cpu_serial VARCHAR(50) NULL AFTER cpu_max_clock_speed; -- Network Information -ALTER TABLE hardware_info ADD COLUMN primary_mac_address VARCHAR(20) NULL AFTER computer_name; -ALTER TABLE hardware_info ADD COLUMN local_ip VARCHAR(45) NULL AFTER primary_mac_address; -ALTER TABLE hardware_info ADD COLUMN public_ip VARCHAR(45) NULL AFTER local_ip; -ALTER TABLE hardware_info ADD COLUMN network_adapters JSON NULL COMMENT 'Array of network adapter details with MAC, IP, etc.' AFTER public_ip; +ALTER TABLE `#__hardware_info` ADD COLUMN primary_mac_address VARCHAR(20) NULL AFTER computer_name; +ALTER TABLE `#__hardware_info` ADD COLUMN local_ip VARCHAR(45) NULL AFTER primary_mac_address; +ALTER TABLE `#__hardware_info` ADD COLUMN public_ip VARCHAR(45) NULL AFTER local_ip; +ALTER TABLE `#__hardware_info` ADD COLUMN network_adapters JSON NULL COMMENT 'Array of network adapter details with MAC, IP, etc.' AFTER public_ip; -- Audio Devices -ALTER TABLE hardware_info ADD COLUMN audio_devices JSON NULL COMMENT 'Array of sound device details' AFTER network_adapters; +ALTER TABLE `#__hardware_info` ADD COLUMN audio_devices JSON NULL COMMENT 'Array of sound device details' AFTER network_adapters; -- Monitor Information -ALTER TABLE hardware_info ADD COLUMN monitors JSON NULL COMMENT 'Array of connected monitor details with serials' AFTER audio_devices; +ALTER TABLE `#__hardware_info` ADD COLUMN monitors JSON NULL COMMENT 'Array of connected monitor details with serials' AFTER audio_devices; -- OS Extended Info -ALTER TABLE hardware_info ADD COLUMN os_build_number VARCHAR(20) NULL AFTER os_architecture; -ALTER TABLE hardware_info ADD COLUMN os_install_date VARCHAR(50) NULL AFTER os_build_number; -ALTER TABLE hardware_info ADD COLUMN os_serial_number VARCHAR(100) NULL AFTER os_install_date; +ALTER TABLE `#__hardware_info` ADD COLUMN os_build_number VARCHAR(20) NULL AFTER os_architecture; +ALTER TABLE `#__hardware_info` ADD COLUMN os_install_date VARCHAR(50) NULL AFTER os_build_number; +ALTER TABLE `#__hardware_info` ADD COLUMN os_serial_number VARCHAR(100) NULL AFTER os_install_date; -- Device Fingerprint (composite unique identifier) -ALTER TABLE hardware_info ADD COLUMN device_fingerprint VARCHAR(500) NULL COMMENT 'Composite hardware fingerprint for duplicate detection' AFTER collection_method; +ALTER TABLE `#__hardware_info` ADD COLUMN device_fingerprint VARCHAR(500) NULL COMMENT 'Composite hardware fingerprint for duplicate detection' AFTER collection_method; -- Index for device fingerprint lookups -ALTER TABLE hardware_info ADD INDEX idx_device_fingerprint (device_fingerprint(255)); -ALTER TABLE hardware_info ADD INDEX idx_public_ip (public_ip); -ALTER TABLE hardware_info ADD INDEX idx_primary_mac (primary_mac_address); +ALTER TABLE `#__hardware_info` ADD INDEX idx_device_fingerprint (device_fingerprint(255)); +ALTER TABLE `#__hardware_info` ADD INDEX idx_public_ip (public_ip); +ALTER TABLE `#__hardware_info` ADD INDEX idx_primary_mac (primary_mac_address); -- Update the view to include new network fields CREATE OR REPLACE VIEW v_activation_hardware AS @@ -73,8 +73,8 @@ SELECT h.system_uuid, h.device_fingerprint, h.collected_at AS hardware_collected_at -FROM activation_attempts a -LEFT JOIN technicians t ON a.technician_id = t.technician_id -LEFT JOIN oem_keys k ON a.key_id = k.id -LEFT JOIN hardware_info h ON h.activation_id = a.id +FROM `#__activation_attempts` a +LEFT JOIN `#__technicians` t ON a.technician_id = t.technician_id +LEFT JOIN `#__oem_keys` k ON a.key_id = k.id +LEFT JOIN `#__hardware_info` h ON h.activation_id = a.id ORDER BY a.attempted_at DESC; diff --git a/FINAL_PRODUCTION_SYSTEM/database/hash_temp_passwords.php b/FINAL_PRODUCTION_SYSTEM/database/hash_temp_passwords.php index fb7e21d..322e7f5 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/hash_temp_passwords.php +++ b/FINAL_PRODUCTION_SYSTEM/database/hash_temp_passwords.php @@ -8,7 +8,7 @@ echo "Hashing plaintext temp_passwords...\n"; -$stmt = $pdo->query("SELECT id, temp_password FROM technicians WHERE temp_password IS NOT NULL AND temp_password != ''"); +$stmt = $pdo->query("SELECT id, temp_password FROM `" . t('technicians') . "` WHERE temp_password IS NOT NULL AND temp_password != ''"); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $updated = 0; @@ -20,7 +20,7 @@ } $hashed = password_hash($row['temp_password'], PASSWORD_BCRYPT, ['cost' => BCRYPT_COST]); - $update = $pdo->prepare("UPDATE technicians SET temp_password = ? WHERE id = ?"); + $update = $pdo->prepare("UPDATE `" . t('technicians') . "` SET temp_password = ? WHERE id = ?"); $update->execute([$hashed, $row['id']]); $updated++; echo " Hashed temp_password for ID {$row['id']}\n"; diff --git a/FINAL_PRODUCTION_SYSTEM/database/i18n_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/i18n_migration.sql index 1d3f112..a92be36 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/i18n_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/i18n_migration.sql @@ -2,12 +2,12 @@ -- Run this migration to enable per-user language selection -- Add preferred_language column to admin_users -ALTER TABLE admin_users ADD COLUMN preferred_language VARCHAR(5) DEFAULT 'en' AFTER role; +ALTER TABLE `#__admin_users` ADD COLUMN preferred_language VARCHAR(5) DEFAULT 'en' AFTER role; -- Add preferred_language column to technicians -ALTER TABLE technicians ADD COLUMN preferred_language VARCHAR(5) DEFAULT 'en' AFTER notes; +ALTER TABLE `#__technicians` ADD COLUMN preferred_language VARCHAR(5) DEFAULT 'en' AFTER notes; -- Add system default language setting -INSERT INTO system_config (config_key, config_value, description) +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('default_language', 'en', 'Default system language (en = English, ru = Russian)') ON DUPLICATE KEY UPDATE config_value = config_value; diff --git a/FINAL_PRODUCTION_SYSTEM/database/install.sql b/FINAL_PRODUCTION_SYSTEM/database/install.sql index 0441b3a..88db432 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/install.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/install.sql @@ -8,7 +8,7 @@ START TRANSACTION; SET time_zone = "+00:00"; -- Create technicians table -CREATE TABLE `technicians` ( +CREATE TABLE `#__technicians` ( `id` int(11) NOT NULL AUTO_INCREMENT, `technician_id` varchar(20) NOT NULL, `full_name` varchar(100) NOT NULL, @@ -31,7 +31,7 @@ CREATE TABLE `technicians` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create oem_keys table -CREATE TABLE `oem_keys` ( +CREATE TABLE `#__oem_keys` ( `id` int(11) NOT NULL AUTO_INCREMENT, `product_key` varchar(29) NOT NULL, `oem_identifier` varchar(20) NOT NULL, @@ -56,7 +56,7 @@ CREATE TABLE `oem_keys` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create activation_attempts table -CREATE TABLE `activation_attempts` ( +CREATE TABLE `#__activation_attempts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `key_id` int(11) NOT NULL, `technician_id` varchar(20) NOT NULL, @@ -76,12 +76,12 @@ CREATE TABLE `activation_attempts` ( KEY `idx_attempted_at` (`attempted_at`), KEY `idx_attempted_date` (`attempted_date`), KEY `idx_key_tech_date` (`key_id`, `technician_id`, `attempted_at`), - CONSTRAINT `activation_attempts_ibfk_1` FOREIGN KEY (`key_id`) REFERENCES `oem_keys` (`id`), - CONSTRAINT `activation_attempts_ibfk_2` FOREIGN KEY (`technician_id`) REFERENCES `technicians` (`technician_id`) + CONSTRAINT `activation_attempts_ibfk_1` FOREIGN KEY (`key_id`) REFERENCES `#__oem_keys` (`id`), + CONSTRAINT `activation_attempts_ibfk_2` FOREIGN KEY (`technician_id`) REFERENCES `#__technicians` (`technician_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create active_sessions table -CREATE TABLE `active_sessions` ( +CREATE TABLE `#__active_sessions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `technician_id` varchar(20) NOT NULL, `session_token` varchar(64) NOT NULL, @@ -99,12 +99,12 @@ CREATE TABLE `active_sessions` ( KEY `idx_expires_at` (`expires_at`), KEY `idx_tech_active_expires` (`technician_id`, `is_active`, `expires_at`), KEY `idx_expires_active` (`expires_at`, `is_active`), - CONSTRAINT `active_sessions_ibfk_1` FOREIGN KEY (`key_id`) REFERENCES `oem_keys` (`id`), - CONSTRAINT `active_sessions_ibfk_2` FOREIGN KEY (`technician_id`) REFERENCES `technicians` (`technician_id`) + CONSTRAINT `active_sessions_ibfk_1` FOREIGN KEY (`key_id`) REFERENCES `#__oem_keys` (`id`), + CONSTRAINT `active_sessions_ibfk_2` FOREIGN KEY (`technician_id`) REFERENCES `#__technicians` (`technician_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create admin_users table -CREATE TABLE `admin_users` ( +CREATE TABLE `#__admin_users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `full_name` varchar(100) NOT NULL, @@ -125,11 +125,11 @@ CREATE TABLE `admin_users` ( KEY `created_by` (`created_by`), KEY `idx_username` (`username`), KEY `idx_is_active` (`is_active`), - CONSTRAINT `admin_users_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `admin_users` (`id`) + CONSTRAINT `admin_users_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `#__admin_users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create admin_sessions table -CREATE TABLE `admin_sessions` ( +CREATE TABLE `#__admin_sessions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `admin_id` int(11) NOT NULL, `session_token` varchar(64) NOT NULL, @@ -145,11 +145,11 @@ CREATE TABLE `admin_sessions` ( KEY `idx_session_token` (`session_token`), KEY `idx_admin_id` (`admin_id`), KEY `idx_expires_at` (`expires_at`), - CONSTRAINT `admin_sessions_ibfk_1` FOREIGN KEY (`admin_id`) REFERENCES `admin_users` (`id`) + CONSTRAINT `admin_sessions_ibfk_1` FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create admin_activity_log table -CREATE TABLE `admin_activity_log` ( +CREATE TABLE `#__admin_activity_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `admin_id` int(11) DEFAULT NULL, `session_id` int(11) DEFAULT NULL, @@ -164,12 +164,12 @@ CREATE TABLE `admin_activity_log` ( KEY `idx_admin_id` (`admin_id`), KEY `idx_created_at` (`created_at`), KEY `idx_action` (`action`), - CONSTRAINT `admin_activity_log_ibfk_1` FOREIGN KEY (`admin_id`) REFERENCES `admin_users` (`id`), - CONSTRAINT `admin_activity_log_ibfk_2` FOREIGN KEY (`session_id`) REFERENCES `admin_sessions` (`id`) + CONSTRAINT `admin_activity_log_ibfk_1` FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users` (`id`), + CONSTRAINT `admin_activity_log_ibfk_2` FOREIGN KEY (`session_id`) REFERENCES `#__admin_sessions` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create admin_ip_whitelist table -CREATE TABLE `admin_ip_whitelist` ( +CREATE TABLE `#__admin_ip_whitelist` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ip_address` varchar(45) NOT NULL, `ip_range` varchar(45) DEFAULT NULL, @@ -181,11 +181,11 @@ CREATE TABLE `admin_ip_whitelist` ( KEY `created_by` (`created_by`), KEY `idx_ip_address` (`ip_address`), KEY `idx_is_active` (`is_active`), - CONSTRAINT `admin_ip_whitelist_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `admin_users` (`id`) + CONSTRAINT `admin_ip_whitelist_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `#__admin_users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create system_config table -CREATE TABLE `system_config` ( +CREATE TABLE `#__system_config` ( `config_key` varchar(50) NOT NULL, `config_value` text NOT NULL, `description` text DEFAULT NULL, @@ -194,7 +194,7 @@ CREATE TABLE `system_config` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Create password_reset_tokens table -CREATE TABLE `password_reset_tokens` ( +CREATE TABLE `#__password_reset_tokens` ( `id` int(11) NOT NULL AUTO_INCREMENT, `technician_id` varchar(20) NOT NULL, `reset_token` varchar(64) NOT NULL, @@ -206,11 +206,11 @@ CREATE TABLE `password_reset_tokens` ( KEY `technician_id` (`technician_id`), KEY `idx_reset_token` (`reset_token`), KEY `idx_expires_at` (`expires_at`), - CONSTRAINT `password_reset_tokens_ibfk_1` FOREIGN KEY (`technician_id`) REFERENCES `technicians` (`technician_id`) + CONSTRAINT `password_reset_tokens_ibfk_1` FOREIGN KEY (`technician_id`) REFERENCES `#__technicians` (`technician_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Insert default system configuration -INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES +INSERT INTO `#__system_config` (`config_key`, `config_value`, `description`) VALUES ('smtp_server', 'smtp.zoho.com', 'SMTP server for notifications'), ('smtp_port', '587', 'SMTP port'), ('smtp_username', '', 'SMTP username'), @@ -236,7 +236,7 @@ INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES ('admin_log_retention_days', '365', 'Keep admin activity logs for N days'); -- Create sample technician account (for testing) -INSERT INTO `technicians` (`technician_id`, `full_name`, `email`, `password_hash`, `temp_password`, `must_change_password`, `created_by`, `notes`) VALUES +INSERT INTO `#__technicians` (`technician_id`, `full_name`, `email`, `password_hash`, `temp_password`, `must_change_password`, `created_by`, `notes`) VALUES ('demo', 'Demo Technician', 'demo@example.com', '$2y$12$LQv3c1yqBwlVHpPd7u/Dw.G2K2wjDUl9jhJxfTULt3lOAOWuTDBKG', 'demo123', 1, 'system', 'Demo account for testing - Password: demo123'); COMMIT; \ No newline at end of file diff --git a/FINAL_PRODUCTION_SYSTEM/database/integrations_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/integrations_migration.sql index 4fa2bf3..f60e111 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/integrations_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/integrations_migration.sql @@ -3,7 +3,7 @@ -- Supports osTicket, 1C ERP, and future integrations -- ============================================================= -CREATE TABLE IF NOT EXISTS `integrations` ( +CREATE TABLE IF NOT EXISTS `#__integrations` ( `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `integration_key` VARCHAR(50) NOT NULL UNIQUE, `display_name` VARCHAR(100) NOT NULL, @@ -18,7 +18,7 @@ CREATE TABLE IF NOT EXISTS `integrations` ( `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -CREATE TABLE IF NOT EXISTS `integration_events` ( +CREATE TABLE IF NOT EXISTS `#__integration_events` ( `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `integration_id` INT UNSIGNED NOT NULL, `event_type` VARCHAR(50) NOT NULL, @@ -29,14 +29,14 @@ CREATE TABLE IF NOT EXISTS `integration_events` ( `error_message` TEXT, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `processed_at` TIMESTAMP NULL DEFAULT NULL, - FOREIGN KEY (`integration_id`) REFERENCES `integrations`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`integration_id`) REFERENCES `#__integrations`(`id`) ON DELETE CASCADE, INDEX `idx_ie_status` (`status`), INDEX `idx_ie_event_type` (`event_type`), INDEX `idx_ie_created` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Seed default integrations -INSERT INTO `integrations` (`integration_key`, `display_name`, `description`, `integration_type`, `enabled`, `config`) VALUES +INSERT INTO `#__integrations` (`integration_key`, `display_name`, `description`, `integration_type`, `enabled`, `config`) VALUES ('osticket', 'osTicket', 'Track PC build orders as support tickets in osTicket', 'api_sync', 0, JSON_OBJECT( 'base_url', '', diff --git a/FINAL_PRODUCTION_SYSTEM/database/license_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/license_migration.sql index 49e8cb4..8dbc5dd 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/license_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/license_migration.sql @@ -4,7 +4,7 @@ -- Tracks instance license, tier limits, and validation history. -- ============================================================= -CREATE TABLE IF NOT EXISTS license_info ( +CREATE TABLE IF NOT EXISTS `#__license_info` ( id INT AUTO_INCREMENT PRIMARY KEY, license_key VARCHAR(2048) NOT NULL COMMENT 'JWT license token', instance_id VARCHAR(128) NOT NULL COMMENT 'SHA256 fingerprint of this installation', @@ -26,10 +26,10 @@ CREATE TABLE IF NOT EXISTS license_info ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Default community license limits stored in system_config -INSERT INTO system_config (config_key, config_value, description) VALUES +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('license_tier', 'community', 'Current license tier') ON DUPLICATE KEY UPDATE config_key = config_key; -INSERT INTO system_config (config_key, config_value, description) VALUES +INSERT INTO `#__system_config` (config_key, config_value, description) VALUES ('license_instance_id', '', 'Unique instance fingerprint (auto-generated)') ON DUPLICATE KEY UPDATE config_key = config_key; diff --git a/FINAL_PRODUCTION_SYSTEM/database/missing_drivers_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/missing_drivers_migration.sql index 0cdd5a0..61a4e83 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/missing_drivers_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/missing_drivers_migration.sql @@ -2,21 +2,21 @@ -- Adds driver status tracking and per-check enforcement to product lines -- 1. Add driver columns to hardware_info -ALTER TABLE hardware_info +ALTER TABLE `#__hardware_info` ADD COLUMN IF NOT EXISTS missing_drivers JSON NULL COMMENT 'Array of devices with missing/problematic drivers', ADD COLUMN IF NOT EXISTS missing_drivers_count INT NULL DEFAULT NULL COMMENT 'Number of missing/error drivers detected'; CREATE INDEX IF NOT EXISTS idx_hw_missing_drivers_count ON hardware_info (missing_drivers_count); -- 2. Add enforcement columns to QC tables -ALTER TABLE qc_motherboard_registry +ALTER TABLE `#__qc_motherboard_registry` ADD COLUMN IF NOT EXISTS missing_drivers_enforcement TINYINT(1) NULL COMMENT 'Override: 0=disabled, 1=info, 2=warning, 3=blocking'; -ALTER TABLE qc_manufacturer_defaults +ALTER TABLE `#__qc_manufacturer_defaults` ADD COLUMN IF NOT EXISTS missing_drivers_enforcement TINYINT(1) DEFAULT NULL COMMENT 'Override: 0=disabled, 1=info, 2=warning, 3=blocking'; -- 3. Add per-check enforcement columns to product_lines -ALTER TABLE product_lines +ALTER TABLE `#__product_lines` ADD COLUMN IF NOT EXISTS secure_boot_enforcement TINYINT(1) DEFAULT NULL, ADD COLUMN IF NOT EXISTS bios_enforcement TINYINT(1) DEFAULT NULL, ADD COLUMN IF NOT EXISTS hackbgrt_enforcement TINYINT(1) DEFAULT NULL, @@ -31,5 +31,5 @@ INSERT IGNORE INTO qc_global_settings (setting_key, setting_value, description) VALUES ('default_partition_enforcement', '2', 'Default enforcement for partition layout check (0=disabled, 1=info, 2=warning, 3=blocking)'); -- 5. Widen check_type from ENUM to VARCHAR for extensibility -ALTER TABLE qc_compliance_results +ALTER TABLE `#__qc_compliance_results` MODIFY COLUMN check_type VARCHAR(50) NOT NULL COMMENT 'Check type identifier'; diff --git a/FINAL_PRODUCTION_SYSTEM/database/order_field_config_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/order_field_config_migration.sql index 4d7a821..1d218e1 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/order_field_config_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/order_field_config_migration.sql @@ -5,19 +5,19 @@ -- 1. Widen order_number columns from VARCHAR(10) to VARCHAR(50) -- Preserve original NULL/NOT NULL constraints per table -ALTER TABLE activation_attempts MODIFY order_number VARCHAR(50) NOT NULL; -ALTER TABLE active_sessions MODIFY order_number VARCHAR(50) NULL; -ALTER TABLE hardware_info MODIFY order_number VARCHAR(50) NOT NULL; -ALTER TABLE qc_compliance_results MODIFY order_number VARCHAR(50) NOT NULL; +ALTER TABLE `#__activation_attempts` MODIFY order_number VARCHAR(50) NOT NULL; +ALTER TABLE `#__active_sessions` MODIFY order_number VARCHAR(50) NULL; +ALTER TABLE `#__hardware_info` MODIFY order_number VARCHAR(50) NOT NULL; +ALTER TABLE `#__qc_compliance_results` MODIFY order_number VARCHAR(50) NOT NULL; -- hardware_collection_log: only alter if table exists (not present in all installations) SET @tbl_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hardware_collection_log'); -SET @sql = IF(@tbl_exists > 0, 'ALTER TABLE hardware_collection_log MODIFY order_number VARCHAR(50) NOT NULL', 'SELECT 1'); +SET @sql = IF(@tbl_exists > 0, 'ALTER TABLE `#__hardware_collection_log` MODIFY order_number VARCHAR(50) NOT NULL', 'SELECT 1'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 2. Seed system_config with order field configuration defaults -INSERT INTO system_config (config_key, config_value, description, updated_at) +INSERT INTO `#__system_config` (config_key, config_value, description, updated_at) VALUES ('order_field_label_en', 'Order Number', 'Display label for the order field (English)', NOW()), ('order_field_label_ru', 'Номер заказа', 'Display label for the order field (Russian)', NOW()), diff --git a/FINAL_PRODUCTION_SYSTEM/database/product_variants_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/product_variants_migration.sql index da6ec04..42f324b 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/product_variants_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/product_variants_migration.sql @@ -2,7 +2,7 @@ -- Adds partition layout QC checking via product lines → variants → partition templates -- ── Product Lines (linked to order number patterns) ────────────── -CREATE TABLE IF NOT EXISTS product_lines ( +CREATE TABLE IF NOT EXISTS `#__product_lines` ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, order_pattern VARCHAR(50) NOT NULL COMMENT 'Order number prefix to match, e.g. ЭЛ00-', @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS product_lines ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ── Product Variants (disk size ranges within a product line) ──── -CREATE TABLE IF NOT EXISTS product_variants ( +CREATE TABLE IF NOT EXISTS `#__product_variants` ( id INT AUTO_INCREMENT PRIMARY KEY, line_id INT NOT NULL, name VARCHAR(100) NOT NULL COMMENT 'e.g. RTX 1TB, RTX 512GB', @@ -25,12 +25,12 @@ CREATE TABLE IF NOT EXISTS product_variants ( is_active TINYINT(1) NOT NULL DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - FOREIGN KEY (line_id) REFERENCES product_lines(id) ON DELETE CASCADE, + FOREIGN KEY (line_id) REFERENCES `#__product_lines`(id) ON DELETE CASCADE, UNIQUE KEY uk_line_name (line_id, name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ── Partition Templates (expected layout per variant) ──────────── -CREATE TABLE IF NOT EXISTS product_variant_partitions ( +CREATE TABLE IF NOT EXISTS `#__product_variant_partitions` ( id INT AUTO_INCREMENT PRIMARY KEY, variant_id INT NOT NULL, partition_order INT NOT NULL COMMENT 'Expected position on disk: 1, 2, 3...', @@ -39,16 +39,16 @@ CREATE TABLE IF NOT EXISTS product_variant_partitions ( expected_size_mb INT NOT NULL, tolerance_percent DECIMAL(5,2) NOT NULL DEFAULT 1.00 COMMENT 'Allowed deviation % per partition', is_flexible TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 = absorbs remaining space (e.g. Data partition)', - FOREIGN KEY (variant_id) REFERENCES product_variants(id) ON DELETE CASCADE, + FOREIGN KEY (variant_id) REFERENCES `#__product_variants`(id) ON DELETE CASCADE, UNIQUE KEY uk_variant_order (variant_id, partition_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ── Extend QC compliance results to include partition_layout ───── -ALTER TABLE qc_compliance_results +ALTER TABLE `#__qc_compliance_results` MODIFY COLUMN check_type ENUM('bios_version','secure_boot','hackbgrt_boot_priority','partition_layout') NOT NULL; -- ── Add detected variant tracking to hardware_info ─────────────── -ALTER TABLE hardware_info +ALTER TABLE `#__hardware_info` ADD COLUMN IF NOT EXISTS detected_variant_id INT DEFAULT NULL, ADD COLUMN IF NOT EXISTS detected_variant_name VARCHAR(100) DEFAULT NULL, ADD COLUMN IF NOT EXISTS detected_line_name VARCHAR(100) DEFAULT NULL; diff --git a/FINAL_PRODUCTION_SYSTEM/database/production_tracking_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/production_tracking_migration.sql index 8f247aa..8d4da60 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/production_tracking_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/production_tracking_migration.sql @@ -7,7 +7,7 @@ -- ── 1. Computer Build Reports (CBR) ──────────────────────── -- Structured per-machine reports for auditing and compliance. -CREATE TABLE IF NOT EXISTS computer_build_reports ( +CREATE TABLE IF NOT EXISTS `#__computer_build_reports` ( id INT AUTO_INCREMENT PRIMARY KEY, report_uuid VARCHAR(36) NOT NULL UNIQUE COMMENT 'UUID v4 for external reference', activation_attempt_id INT DEFAULT NULL, @@ -80,7 +80,7 @@ CREATE TABLE IF NOT EXISTS computer_build_reports ( -- ── 2. Key Pool Management ───────────────────────────────── -- Alert thresholds and replenishment tracking per product edition. -CREATE TABLE IF NOT EXISTS key_pool_config ( +CREATE TABLE IF NOT EXISTS `#__key_pool_config` ( id INT AUTO_INCREMENT PRIMARY KEY, product_edition VARCHAR(100) NOT NULL UNIQUE COMMENT 'e.g. Windows 11 Pro, Windows 11 Home', low_threshold INT NOT NULL DEFAULT 10 COMMENT 'Alert when unused keys drop below this', @@ -96,7 +96,7 @@ CREATE TABLE IF NOT EXISTS key_pool_config ( -- ── 3. Hardware Binding Registry ─────────────────────────── -- Tracks which keys have been used on which hardware. -CREATE TABLE IF NOT EXISTS hardware_key_bindings ( +CREATE TABLE IF NOT EXISTS `#__hardware_key_bindings` ( id INT AUTO_INCREMENT PRIMARY KEY, product_key_id INT NOT NULL COMMENT 'FK to oem_keys', device_fingerprint VARCHAR(500) NOT NULL, @@ -118,7 +118,7 @@ CREATE TABLE IF NOT EXISTS hardware_key_bindings ( -- ── 4. DPK Import Batches ────────────────────────────────── -- Tracks bulk key imports from Microsoft OEM deliveries. -CREATE TABLE IF NOT EXISTS dpk_import_batches ( +CREATE TABLE IF NOT EXISTS `#__dpk_import_batches` ( id INT AUTO_INCREMENT PRIMARY KEY, batch_name VARCHAR(255) NOT NULL COMMENT 'e.g. "Microsoft Order #12345"', import_source VARCHAR(100) NOT NULL DEFAULT 'manual' COMMENT 'manual, microsoft_csv, microsoft_xml', @@ -142,7 +142,7 @@ CREATE TABLE IF NOT EXISTS dpk_import_batches ( -- ── 5. Work Orders (Production Line Tracking) ────────────── -- Links builds to customer orders, batch production runs. -CREATE TABLE IF NOT EXISTS work_orders ( +CREATE TABLE IF NOT EXISTS `#__work_orders` ( id INT AUTO_INCREMENT PRIMARY KEY, work_order_number VARCHAR(50) NOT NULL UNIQUE COMMENT 'Auto-generated or manual', batch_number VARCHAR(100) DEFAULT NULL COMMENT 'Production batch grouping', diff --git a/FINAL_PRODUCTION_SYSTEM/database/push_notifications_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/push_notifications_migration.sql index 5fee47b..061e04e 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/push_notifications_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/push_notifications_migration.sql @@ -5,7 +5,7 @@ SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -- Push subscriptions: stores browser push endpoints per admin -CREATE TABLE IF NOT EXISTS `push_subscriptions` ( +CREATE TABLE IF NOT EXISTS `#__push_subscriptions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `admin_id` int(11) NOT NULL, `endpoint` text NOT NULL, @@ -18,11 +18,11 @@ CREATE TABLE IF NOT EXISTS `push_subscriptions` ( PRIMARY KEY (`id`), UNIQUE KEY `uq_admin_endpoint` (`admin_id`, `endpoint`(500)), KEY `idx_admin_active` (`admin_id`, `is_active`), - CONSTRAINT `fk_push_sub_admin` FOREIGN KEY (`admin_id`) REFERENCES `admin_users` (`id`) ON DELETE CASCADE + CONSTRAINT `fk_push_sub_admin` FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Push preferences: per-admin category toggles -CREATE TABLE IF NOT EXISTS `push_preferences` ( +CREATE TABLE IF NOT EXISTS `#__push_preferences` ( `id` int(11) NOT NULL AUTO_INCREMENT, `admin_id` int(11) NOT NULL, `category` varchar(50) NOT NULL, @@ -30,11 +30,11 @@ CREATE TABLE IF NOT EXISTS `push_preferences` ( PRIMARY KEY (`id`), UNIQUE KEY `uq_admin_category` (`admin_id`, `category`), KEY `idx_admin_id` (`admin_id`), - CONSTRAINT `fk_push_pref_admin` FOREIGN KEY (`admin_id`) REFERENCES `admin_users` (`id`) ON DELETE CASCADE + CONSTRAINT `fk_push_pref_admin` FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Notifications: bell dropdown history -CREATE TABLE IF NOT EXISTS `notifications` ( +CREATE TABLE IF NOT EXISTS `#__notifications` ( `id` int(11) NOT NULL AUTO_INCREMENT, `admin_id` int(11) NOT NULL, `category` varchar(50) NOT NULL, @@ -47,11 +47,11 @@ CREATE TABLE IF NOT EXISTS `notifications` ( PRIMARY KEY (`id`), KEY `idx_admin_read` (`admin_id`, `is_read`), KEY `idx_admin_created` (`admin_id`, `created_at` DESC), - CONSTRAINT `fk_notif_admin` FOREIGN KEY (`admin_id`) REFERENCES `admin_users` (`id`) ON DELETE CASCADE + CONSTRAINT `fk_notif_admin` FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- VAPID keys and push settings in system_config -INSERT INTO `system_config` (`config_key`, `config_value`, `description`) +INSERT INTO `#__system_config` (`config_key`, `config_value`, `description`) VALUES ('vapid_public_key', '', 'VAPID public key for Web Push (auto-generated)'), ('vapid_private_key', '', 'VAPID private key for Web Push (auto-generated)'), diff --git a/FINAL_PRODUCTION_SYSTEM/database/qc_compliance_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/qc_compliance_migration.sql index c289c28..2a0a27f 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/qc_compliance_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/qc_compliance_migration.sql @@ -9,15 +9,15 @@ -- 1. New columns on hardware_info -- ============================================================ -ALTER TABLE hardware_info ADD COLUMN boot_order JSON NULL COMMENT 'Ordered list of UEFI boot entries from bcdedit' AFTER device_fingerprint; -ALTER TABLE hardware_info ADD COLUMN hackbgrt_installed TINYINT(1) NULL COMMENT '1=HackBGRT traces found on EFI partition' AFTER boot_order; -ALTER TABLE hardware_info ADD COLUMN hackbgrt_first_boot TINYINT(1) NULL COMMENT '1=HackBGRT is first boot entry' AFTER hackbgrt_installed; +ALTER TABLE `#__hardware_info` ADD COLUMN boot_order JSON NULL COMMENT 'Ordered list of UEFI boot entries from bcdedit' AFTER device_fingerprint; +ALTER TABLE `#__hardware_info` ADD COLUMN hackbgrt_installed TINYINT(1) NULL COMMENT '1=HackBGRT traces found on EFI partition' AFTER boot_order; +ALTER TABLE `#__hardware_info` ADD COLUMN hackbgrt_first_boot TINYINT(1) NULL COMMENT '1=HackBGRT is first boot entry' AFTER hackbgrt_installed; -- ============================================================ -- 2. QC Global Settings (key-value) -- ============================================================ -CREATE TABLE IF NOT EXISTS qc_global_settings ( +CREATE TABLE IF NOT EXISTS `#__qc_global_settings` ( id INT AUTO_INCREMENT PRIMARY KEY, setting_key VARCHAR(100) NOT NULL UNIQUE, setting_value TEXT NOT NULL, @@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS qc_global_settings ( updated_by INT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -INSERT INTO qc_global_settings (setting_key, setting_value, description) VALUES +INSERT INTO `#__qc_global_settings` (setting_key, setting_value, description) VALUES ('qc_enabled', '0', 'Enable hardware compliance checking during activation (0=off, 1=on)'), ('default_bios_enforcement', '1', 'Default BIOS version check enforcement (0=disabled, 1=info, 2=warning, 3=blocking)'), ('default_secure_boot_enforcement', '1', 'Default Secure Boot check enforcement (0=disabled, 1=info, 2=warning, 3=blocking)'), @@ -37,7 +37,7 @@ INSERT INTO qc_global_settings (setting_key, setting_value, description) VALUES -- 3. Manufacturer Defaults -- ============================================================ -CREATE TABLE IF NOT EXISTS qc_manufacturer_defaults ( +CREATE TABLE IF NOT EXISTS `#__qc_manufacturer_defaults` ( id INT AUTO_INCREMENT PRIMARY KEY, manufacturer VARCHAR(100) NOT NULL UNIQUE, secure_boot_required TINYINT(1) DEFAULT 1 COMMENT '1=Secure Boot must be ON', @@ -54,10 +54,10 @@ CREATE TABLE IF NOT EXISTS qc_manufacturer_defaults ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ============================================================ --- 4. Motherboard Registry (auto-populated from hardware_info) +-- 4. Motherboard Registry (auto-populated from `#__hardware_info`) -- ============================================================ -CREATE TABLE IF NOT EXISTS qc_motherboard_registry ( +CREATE TABLE IF NOT EXISTS `#__qc_motherboard_registry` ( id INT AUTO_INCREMENT PRIMARY KEY, manufacturer VARCHAR(100) NOT NULL, product VARCHAR(100) NOT NULL, @@ -85,7 +85,7 @@ CREATE TABLE IF NOT EXISTS qc_motherboard_registry ( -- 5. Compliance Results (per check, per hardware submission) -- ============================================================ -CREATE TABLE IF NOT EXISTS qc_compliance_results ( +CREATE TABLE IF NOT EXISTS `#__qc_compliance_results` ( id INT AUTO_INCREMENT PRIMARY KEY, hardware_info_id INT NOT NULL, order_number VARCHAR(10) NOT NULL, @@ -99,7 +99,7 @@ CREATE TABLE IF NOT EXISTS qc_compliance_results ( motherboard_registry_id INT NULL, is_retroactive TINYINT(1) DEFAULT 0 COMMENT '1=created by retroactive recheck', checked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (hardware_info_id) REFERENCES hardware_info(id) ON DELETE CASCADE, + FOREIGN KEY (hardware_info_id) REFERENCES `#__hardware_info`(id) ON DELETE CASCADE, INDEX idx_hardware_id (hardware_info_id), INDEX idx_order_number (order_number), INDEX idx_check_result (check_result), @@ -110,12 +110,12 @@ CREATE TABLE IF NOT EXISTS qc_compliance_results ( -- 6. ACL: Quality Control permission category + permissions -- ============================================================ -INSERT INTO acl_permission_categories (category_key, display_name, icon, sort_order) VALUES +INSERT INTO `#__acl_permission_categories` (category_key, display_name, icon, sort_order) VALUES ('quality_control', 'Quality Control', NULL, 46); -SET @qc_cat_id = (SELECT id FROM acl_permission_categories WHERE category_key = 'quality_control'); +SET @qc_cat_id = (SELECT id FROM `#__acl_permission_categories` WHERE category_key = 'quality_control'); -INSERT INTO acl_permissions (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) VALUES +INSERT INTO `#__acl_permissions` (permission_key, display_name, description, category_id, resource_type, action_type, is_dangerous) VALUES ('view_compliance', 'View Compliance Results', 'View QC compliance check results and statistics', @qc_cat_id, 'compliance', 'view', 0), ('manage_compliance_rules', 'Manage Compliance Rules', 'Configure motherboard registry and compliance enforcement rules', @qc_cat_id, 'compliance', 'manage', 0), ('manage_compliance', 'Manage QC System', 'Toggle QC feature, trigger retroactive checks, modify global settings', @qc_cat_id, 'compliance', 'manage', 1); @@ -123,23 +123,23 @@ INSERT INTO acl_permissions (permission_key, display_name, description, category -- Grant to super_admin (already gets everything via CROSS JOIN, but explicit for clarity on new installs) INSERT IGNORE INTO acl_role_permissions (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r CROSS JOIN acl_permissions p +FROM `#__acl_roles` r CROSS JOIN `#__acl_permissions` p WHERE r.role_name = 'super_admin' AND p.permission_key IN ('view_compliance', 'manage_compliance_rules', 'manage_compliance'); -- Grant to admin: view + manage rules INSERT IGNORE INTO acl_role_permissions (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'admin' AND p.permission_key IN ('view_compliance', 'manage_compliance_rules'); -- Grant to qc_inspector: view only INSERT IGNORE INTO acl_role_permissions (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'qc_inspector' AND p.permission_key IN ('view_compliance'); -- Grant to dept_manager: view only INSERT IGNORE INTO acl_role_permissions (role_id, permission_id) SELECT r.id, p.id -FROM acl_roles r, acl_permissions p +FROM `#__acl_roles` r, acl_permissions p WHERE r.role_name = 'dept_manager' AND p.permission_key IN ('view_compliance'); diff --git a/FINAL_PRODUCTION_SYSTEM/database/rate_limiting_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/rate_limiting_migration.sql index e037a26..bc4293f 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/rate_limiting_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/rate_limiting_migration.sql @@ -6,7 +6,7 @@ -- Table: rate_limit_violations -- Logs when API rate limits are exceeded for security monitoring -CREATE TABLE IF NOT EXISTS `rate_limit_violations` ( +CREATE TABLE IF NOT EXISTS `#__rate_limit_violations` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `identifier` VARCHAR(100) NOT NULL COMMENT 'IP address or user ID', `action` VARCHAR(50) NOT NULL COMMENT 'Endpoint action (login, get-key, etc.)', @@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS `rate_limit_violations` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Rate limit violation log for security monitoring'; -- System configuration for rate limiting -INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES +INSERT INTO `#__system_config` (`config_key`, `config_value`, `description`) VALUES ('rate_limit_enabled', '1', 'Enable API rate limiting (1=yes, 0=no)'), ('rate_limit_global_per_minute', '100', 'Max requests per minute per IP (all endpoints)'), ('rate_limit_login_per_hour', '20', 'Max login attempts per hour per IP'), diff --git a/FINAL_PRODUCTION_SYSTEM/database/rbac_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/rbac_migration.sql index 0c50dc4..25f5888 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/rbac_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/rbac_migration.sql @@ -13,7 +13,7 @@ SET @role_column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS -- If role column doesn't exist, create it SET @sql = IF(@role_column_exists = 0, - 'ALTER TABLE `admin_users` ADD COLUMN `role` ENUM(''super_admin'', ''admin'', ''viewer'') DEFAULT ''admin'' COMMENT ''Admin role for RBAC''', + 'ALTER TABLE `#__admin_users` ADD COLUMN `role` ENUM(''super_admin'', ''admin'', ''viewer'') DEFAULT ''admin'' COMMENT ''Admin role for RBAC''', 'SELECT "Role column already exists"'); PREPARE stmt FROM @sql; @@ -21,12 +21,12 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Add role tracking to admin_activity_log -ALTER TABLE `admin_activity_log` +ALTER TABLE `#__admin_activity_log` ADD COLUMN IF NOT EXISTS `admin_role` ENUM('super_admin', 'admin', 'viewer') NULL COMMENT 'Role of admin at time of action' AFTER `user_agent`, ADD INDEX IF NOT EXISTS `idx_admin_role` (`admin_role`); --- Create table for permission audit trail -CREATE TABLE IF NOT EXISTS `rbac_permission_denials` ( +-- Create table `#__for` permission audit trail +CREATE TABLE IF NOT EXISTS `#__rbac_permission_denials` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `admin_id` INT NOT NULL COMMENT 'Admin who was denied', `session_id` VARCHAR(64) NULL COMMENT 'Session ID if available', @@ -41,24 +41,24 @@ CREATE TABLE IF NOT EXISTS `rbac_permission_denials` ( INDEX `idx_admin_role` (`admin_role`), INDEX `idx_requested_action` (`requested_action`), INDEX `idx_denied_at` (`denied_at`), - FOREIGN KEY (`admin_id`) REFERENCES `admin_users`(`id`) ON DELETE CASCADE + FOREIGN KEY (`admin_id`) REFERENCES `#__admin_users`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='RBAC permission denial audit log'; -- System configuration for RBAC -INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES +INSERT INTO `#__system_config` (`config_key`, `config_value`, `description`) VALUES ('rbac_enabled', '1', 'Enable role-based access control (1=yes, 0=no)'), ('rbac_log_denials', '1', 'Log permission denials to rbac_permission_denials table'), ('rbac_strict_mode', '1', 'Deny access to undefined permissions (1=yes, 0=allow)') ON DUPLICATE KEY UPDATE `config_value` = VALUES(`config_value`); -- Verify we have at least one super_admin account -SET @super_admin_count = (SELECT COUNT(*) FROM `admin_users` WHERE `role` = 'super_admin'); +SET @super_admin_count = (SELECT COUNT(*) FROM `#__admin_users` WHERE `role` = 'super_admin'); -- If no super_admin exists, promote the first admin to super_admin -UPDATE `admin_users` SET `role` = 'super_admin' -WHERE `id` = (SELECT `id` FROM (SELECT `id` FROM `admin_users` ORDER BY `id` ASC LIMIT 1) AS temp) +UPDATE `#__admin_users` SET `role` = 'super_admin' +WHERE `id` = (SELECT `id` FROM (SELECT `id` FROM `#__admin_users` ORDER BY `id` ASC LIMIT 1) AS temp) AND @super_admin_count = 0; -- Migration complete SELECT 'Migration: RBAC tables and permissions configured successfully' AS status; -SELECT CONCAT('Super admins: ', COUNT(*)) AS super_admin_count FROM `admin_users` WHERE `role` = 'super_admin'; +SELECT CONCAT('Super admins: ', COUNT(*)) AS super_admin_count FROM `#__admin_users` WHERE `role` = 'super_admin'; diff --git a/FINAL_PRODUCTION_SYSTEM/database/schema_versions_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/schema_versions_migration.sql index 7c8c3e3..18b66e3 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/schema_versions_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/schema_versions_migration.sql @@ -1,7 +1,7 @@ -- Schema Version Tracking -- Tracks which migration files have been applied to prevent re-running. -CREATE TABLE IF NOT EXISTS schema_versions ( +CREATE TABLE IF NOT EXISTS `#__schema_versions` ( id INT AUTO_INCREMENT PRIMARY KEY, version INT NOT NULL, filename VARCHAR(255) NOT NULL, diff --git a/FINAL_PRODUCTION_SYSTEM/database/seed_demo_compliance.sql b/FINAL_PRODUCTION_SYSTEM/database/seed_demo_compliance.sql index fcc4699..42f6de5 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/seed_demo_compliance.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/seed_demo_compliance.sql @@ -8,49 +8,49 @@ -- 256GB: OS 120000 MB = 117.1875 GB, Data 121736 MB = 118.8828125 GB -- 1. Delete old compliance results to start fresh -DELETE FROM qc_compliance_results; +DELETE FROM `#__qc_compliance_results`; -- 2. Update existing hardware_info order numbers to follow product line patterns -- Also inject complete_disk_layout JSON for partition checking -- PASS: Good 512 GB layout (ЭЛ00-100001) -UPDATE hardware_info SET order_number = 'ЭЛ00-100001', +UPDATE `#__hardware_info` SET order_number = 'ЭЛ00-100001', complete_disk_layout = '[{"disk_number":0,"disk_model":"Samsung SSD 970 EVO 500GB","disk_size_gb":465.76,"partition_style":"GPT","partitions":[{"partition_number":0,"size_gb":0.25390625,"partition_purpose":"EFI","file_system":"FAT32"},{"partition_number":1,"size_gb":0.015625,"partition_purpose":"MSR","file_system":null},{"partition_number":2,"size_gb":195.3125,"partition_purpose":"OS","file_system":"NTFS","drive_letter":"C:"},{"partition_number":3,"size_gb":1.46484375,"partition_purpose":"Recovery","file_system":"NTFS"},{"partition_number":4,"size_gb":276.7578125,"partition_purpose":"Data","file_system":"NTFS","drive_letter":"D:"},{"partition_number":5,"size_gb":0.1953125,"partition_purpose":"Other","file_system":"FAT32","volume_name":"BIOS","drive_letter":"E:"}]}]' -WHERE id = (SELECT id FROM (SELECT MIN(id) AS id FROM hardware_info) t); +WHERE id = (SELECT id FROM (SELECT MIN(id) AS id FROM `#__hardware_info`) t); -- PASS: Good 512 GB layout (ЭЛ00-100002) -UPDATE hardware_info SET order_number = 'ЭЛ00-100002', +UPDATE `#__hardware_info` SET order_number = 'ЭЛ00-100002', complete_disk_layout = '[{"disk_number":0,"disk_model":"WD Blue SN570 500GB","disk_size_gb":465.76,"partition_style":"GPT","partitions":[{"partition_number":0,"size_gb":0.25390625,"partition_purpose":"EFI","file_system":"FAT32"},{"partition_number":1,"size_gb":0.015625,"partition_purpose":"MSR","file_system":null},{"partition_number":2,"size_gb":195.3125,"partition_purpose":"OS","file_system":"NTFS","drive_letter":"C:"},{"partition_number":3,"size_gb":1.46484375,"partition_purpose":"Recovery","file_system":"NTFS"},{"partition_number":4,"size_gb":276.7578125,"partition_purpose":"Data","file_system":"NTFS","drive_letter":"D:"},{"partition_number":5,"size_gb":0.1953125,"partition_purpose":"Other","file_system":"FAT32","volume_name":"BIOS","drive_letter":"E:"}]}]' -WHERE id = (SELECT id FROM (SELECT id FROM hardware_info ORDER BY id LIMIT 1 OFFSET 1) t); +WHERE id = (SELECT id FROM (SELECT id FROM `#__hardware_info` ORDER BY id LIMIT 1 OFFSET 1) t); -- PASS: Good 1 TB layout (ЛЕ00-200001) -UPDATE hardware_info SET order_number = 'ЛЕ00-200001', +UPDATE `#__hardware_info` SET order_number = 'ЛЕ00-200001', complete_disk_layout = '[{"disk_number":0,"disk_model":"Kingston A2000 1TB","disk_size_gb":931.51,"partition_style":"GPT","partitions":[{"partition_number":0,"size_gb":0.25390625,"partition_purpose":"EFI","file_system":"FAT32"},{"partition_number":1,"size_gb":0.015625,"partition_purpose":"MSR","file_system":null},{"partition_number":2,"size_gb":390.625,"partition_purpose":"OS","file_system":"NTFS","drive_letter":"C:"},{"partition_number":3,"size_gb":1.46484375,"partition_purpose":"Recovery","file_system":"NTFS"},{"partition_number":4,"size_gb":540.0,"partition_purpose":"Data","file_system":"NTFS","drive_letter":"D:"},{"partition_number":5,"size_gb":0.1953125,"partition_purpose":"Other","file_system":"FAT32","volume_name":"BIOS","drive_letter":"E:"}]}]' -WHERE id = (SELECT id FROM (SELECT id FROM hardware_info ORDER BY id LIMIT 1 OFFSET 2) t); +WHERE id = (SELECT id FROM (SELECT id FROM `#__hardware_info` ORDER BY id LIMIT 1 OFFSET 2) t); -- WARNING: 256 GB layout with Data partition slightly too small (ЛЕ00-200002) -- Data is 113.77 GB = 116500 MB but template requires 121736 MB minimum -UPDATE hardware_info SET order_number = 'ЛЕ00-200002', +UPDATE `#__hardware_info` SET order_number = 'ЛЕ00-200002', complete_disk_layout = '[{"disk_number":0,"disk_model":"Samsung SSD 860 EVO 250GB","disk_size_gb":232.89,"partition_style":"GPT","partitions":[{"partition_number":0,"size_gb":0.25390625,"partition_purpose":"EFI","file_system":"FAT32"},{"partition_number":1,"size_gb":0.015625,"partition_purpose":"MSR","file_system":null},{"partition_number":2,"size_gb":117.1875,"partition_purpose":"OS","file_system":"NTFS","drive_letter":"C:"},{"partition_number":3,"size_gb":1.46484375,"partition_purpose":"Recovery","file_system":"NTFS"},{"partition_number":4,"size_gb":113.77,"partition_purpose":"Data","file_system":"NTFS","drive_letter":"D:"},{"partition_number":5,"size_gb":0.1953125,"partition_purpose":"Other","file_system":"FAT32","volume_name":"BIOS","drive_letter":"E:"}]}]' -WHERE id = (SELECT id FROM (SELECT id FROM hardware_info ORDER BY id LIMIT 1 OFFSET 3) t); +WHERE id = (SELECT id FROM (SELECT id FROM `#__hardware_info` ORDER BY id LIMIT 1 OFFSET 3) t); -- PASS: Good 1 TB layout (ИП00-300001) -UPDATE hardware_info SET order_number = 'ИП00-300001', +UPDATE `#__hardware_info` SET order_number = 'ИП00-300001', complete_disk_layout = '[{"disk_number":0,"disk_model":"Crucial P3 1TB","disk_size_gb":931.51,"partition_style":"GPT","partitions":[{"partition_number":0,"size_gb":0.25390625,"partition_purpose":"EFI","file_system":"FAT32"},{"partition_number":1,"size_gb":0.015625,"partition_purpose":"MSR","file_system":null},{"partition_number":2,"size_gb":390.625,"partition_purpose":"OS","file_system":"NTFS","drive_letter":"C:"},{"partition_number":3,"size_gb":1.46484375,"partition_purpose":"Recovery","file_system":"NTFS"},{"partition_number":4,"size_gb":540.0,"partition_purpose":"Data","file_system":"NTFS","drive_letter":"D:"},{"partition_number":5,"size_gb":0.1953125,"partition_purpose":"Other","file_system":"FAT32","volume_name":"BIOS","drive_letter":"E:"}]}]' -WHERE id = (SELECT id FROM (SELECT id FROM hardware_info ORDER BY id LIMIT 1 OFFSET 4) t); +WHERE id = (SELECT id FROM (SELECT id FROM `#__hardware_info` ORDER BY id LIMIT 1 OFFSET 4) t); -- FAIL: Bad 512 GB layout — wrong OS size (150 GB instead of ~195 GB) -UPDATE hardware_info SET order_number = 'ИП00-300002', +UPDATE `#__hardware_info` SET order_number = 'ИП00-300002', complete_disk_layout = '[{"disk_number":0,"disk_model":"WD Blue SN550 500GB","disk_size_gb":465.76,"partition_style":"GPT","partitions":[{"partition_number":0,"size_gb":0.25390625,"partition_purpose":"EFI","file_system":"FAT32"},{"partition_number":1,"size_gb":0.015625,"partition_purpose":"MSR","file_system":null},{"partition_number":2,"size_gb":146.484375,"partition_purpose":"OS","file_system":"NTFS","drive_letter":"C:"},{"partition_number":3,"size_gb":1.46484375,"partition_purpose":"Recovery","file_system":"NTFS"},{"partition_number":4,"size_gb":317.35,"partition_purpose":"Data","file_system":"NTFS","drive_letter":"D:"},{"partition_number":5,"size_gb":0.1953125,"partition_purpose":"Other","file_system":"FAT32","volume_name":"BIOS","drive_letter":"E:"}]}]' -WHERE id = (SELECT id FROM (SELECT id FROM hardware_info ORDER BY id LIMIT 1 OFFSET 5) t); +WHERE id = (SELECT id FROM (SELECT id FROM `#__hardware_info` ORDER BY id LIMIT 1 OFFSET 5) t); -- No disk layout data (ЭЛ00-100003) — will show "no data" for partition check -UPDATE hardware_info SET order_number = 'ЭЛ00-100003' +UPDATE `#__hardware_info` SET order_number = 'ЭЛ00-100003' WHERE order_number NOT LIKE 'ЭЛ00-%' AND order_number NOT LIKE 'ЛЕ00-%' AND order_number NOT LIKE 'ИП00-%' - AND id = (SELECT id FROM (SELECT id FROM hardware_info WHERE order_number NOT LIKE 'ЭЛ00-%' AND order_number NOT LIKE 'ЛЕ00-%' AND order_number NOT LIKE 'ИП00-%' ORDER BY id LIMIT 1) t); + AND id = (SELECT id FROM (SELECT id FROM `#__hardware_info` WHERE order_number NOT LIKE 'ЭЛ00-%' AND order_number NOT LIKE 'ЛЕ00-%' AND order_number NOT LIKE 'ИП00-%' ORDER BY id LIMIT 1) t); -UPDATE hardware_info SET order_number = 'ЛЕ00-200003' +UPDATE `#__hardware_info` SET order_number = 'ЛЕ00-200003' WHERE order_number NOT LIKE 'ЭЛ00-%' AND order_number NOT LIKE 'ЛЕ00-%' AND order_number NOT LIKE 'ИП00-%' - AND id = (SELECT id FROM (SELECT id FROM hardware_info WHERE order_number NOT LIKE 'ЭЛ00-%' AND order_number NOT LIKE 'ЛЕ00-%' AND order_number NOT LIKE 'ИП00-%' ORDER BY id LIMIT 1) t); + AND id = (SELECT id FROM (SELECT id FROM `#__hardware_info` WHERE order_number NOT LIKE 'ЭЛ00-%' AND order_number NOT LIKE 'ЛЕ00-%' AND order_number NOT LIKE 'ИП00-%' ORDER BY id LIMIT 1) t); -- Done. Now trigger "Recheck Historical" from the admin UI to regenerate all compliance results. diff --git a/FINAL_PRODUCTION_SYSTEM/database/seed_variants.sql b/FINAL_PRODUCTION_SYSTEM/database/seed_variants.sql index 3684d8d..7878914 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/seed_variants.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/seed_variants.sql @@ -2,9 +2,9 @@ -- Disk sizes: 256 GB (~238 GB = 243712 MB), 512 GB (~474 GB = 485376 MB), 1 TB (~931 GB = 953344 MB), 2 TB (~1862 GB = 1907200 MB) -- Get product line IDs -SET @pl1 = (SELECT id FROM product_lines WHERE order_pattern = 'ЭЛ00-######'); -SET @pl2 = (SELECT id FROM product_lines WHERE order_pattern = 'ЛЕ00-######'); -SET @pl3 = (SELECT id FROM product_lines WHERE order_pattern = 'ИП00-######'); +SET @pl1 = (SELECT id FROM `#__product_lines` WHERE order_pattern = 'ЭЛ00-######'); +SET @pl2 = (SELECT id FROM `#__product_lines` WHERE order_pattern = 'ЛЕ00-######'); +SET @pl3 = (SELECT id FROM `#__product_lines` WHERE order_pattern = 'ИП00-######'); -- ── Variants for Marketplace 1 ────────────────────────────────── INSERT IGNORE INTO product_variants (line_id, name, disk_size_min_mb, disk_size_max_mb) VALUES @@ -39,9 +39,9 @@ INSERT IGNORE INTO product_variants (line_id, name, disk_size_min_mb, disk_size_ -- 2 TB ~ 1907200 MB total: EFI 260 + MSR 16 + OS 500000 + Recovery 1500 + Data 1405224 + BIOS 200 -- ── 256 GB variants (all 3 product lines) ──────────────────────── -INSERT INTO product_variant_partitions (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) +INSERT INTO `#__product_variant_partitions` (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) SELECT v.id, p.partition_order, p.partition_name, p.partition_type, p.expected_size_mb, p.tolerance_percent, p.is_flexible -FROM product_variants v +FROM `#__product_variants` v CROSS JOIN ( SELECT 1 AS partition_order, 'EFI' AS partition_name, 'EFI System' AS partition_type, 260 AS expected_size_mb, 1.00 AS tolerance_percent, 0 AS is_flexible UNION ALL SELECT 2, 'MSR', 'Microsoft Reserved', 16, 1.00, 0 UNION ALL @@ -54,9 +54,9 @@ WHERE v.name = '256 GB' ON DUPLICATE KEY UPDATE expected_size_mb = VALUES(expected_size_mb), partition_type = VALUES(partition_type), is_flexible = VALUES(is_flexible); -- ── 512 GB variants (all 3 product lines) ──────────────────────── -INSERT INTO product_variant_partitions (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) +INSERT INTO `#__product_variant_partitions` (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) SELECT v.id, p.partition_order, p.partition_name, p.partition_type, p.expected_size_mb, p.tolerance_percent, p.is_flexible -FROM product_variants v +FROM `#__product_variants` v CROSS JOIN ( SELECT 1 AS partition_order, 'EFI' AS partition_name, 'EFI System' AS partition_type, 260 AS expected_size_mb, 1.00 AS tolerance_percent, 0 AS is_flexible UNION ALL SELECT 2, 'MSR', 'Microsoft Reserved', 16, 1.00, 0 UNION ALL @@ -69,9 +69,9 @@ WHERE v.name = '512 GB' ON DUPLICATE KEY UPDATE expected_size_mb = VALUES(expected_size_mb), partition_type = VALUES(partition_type), is_flexible = VALUES(is_flexible); -- ── 1 TB variants (all 3 product lines) ────────────────────────── -INSERT INTO product_variant_partitions (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) +INSERT INTO `#__product_variant_partitions` (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) SELECT v.id, p.partition_order, p.partition_name, p.partition_type, p.expected_size_mb, p.tolerance_percent, p.is_flexible -FROM product_variants v +FROM `#__product_variants` v CROSS JOIN ( SELECT 1 AS partition_order, 'EFI' AS partition_name, 'EFI System' AS partition_type, 260 AS expected_size_mb, 1.00 AS tolerance_percent, 0 AS is_flexible UNION ALL SELECT 2, 'MSR', 'Microsoft Reserved', 16, 1.00, 0 UNION ALL @@ -84,9 +84,9 @@ WHERE v.name = '1 TB' ON DUPLICATE KEY UPDATE expected_size_mb = VALUES(expected_size_mb), partition_type = VALUES(partition_type), is_flexible = VALUES(is_flexible); -- ── 2 TB variants (all 3 product lines) ────────────────────────── -INSERT INTO product_variant_partitions (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) +INSERT INTO `#__product_variant_partitions` (variant_id, partition_order, partition_name, partition_type, expected_size_mb, tolerance_percent, is_flexible) SELECT v.id, p.partition_order, p.partition_name, p.partition_type, p.expected_size_mb, p.tolerance_percent, p.is_flexible -FROM product_variants v +FROM `#__product_variants` v CROSS JOIN ( SELECT 1 AS partition_order, 'EFI' AS partition_name, 'EFI System' AS partition_type, 260 AS expected_size_mb, 1.00 AS tolerance_percent, 0 AS is_flexible UNION ALL SELECT 2, 'MSR', 'Microsoft Reserved', 16, 1.00, 0 UNION ALL diff --git a/FINAL_PRODUCTION_SYSTEM/database/task_pipeline_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/task_pipeline_migration.sql index 5ad75bf..3ec8067 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/task_pipeline_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/task_pipeline_migration.sql @@ -7,7 +7,7 @@ -- ============================================================= -- Global task template library (reusable across product lines) -CREATE TABLE IF NOT EXISTS task_templates ( +CREATE TABLE IF NOT EXISTS `#__task_templates` ( id INT AUTO_INCREMENT PRIMARY KEY, task_key VARCHAR(50) NOT NULL UNIQUE COMMENT 'Internal identifier (e.g. hardware_collection)', task_name VARCHAR(100) NOT NULL COMMENT 'Display name', @@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS task_templates ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Per-product-line task assignments (which tasks run, in what order, with overrides) -CREATE TABLE IF NOT EXISTS product_line_tasks ( +CREATE TABLE IF NOT EXISTS `#__product_line_tasks` ( id INT AUTO_INCREMENT PRIMARY KEY, product_line_id INT NOT NULL COMMENT 'FK to product_lines table', task_template_id INT NOT NULL COMMENT 'FK to task_templates', @@ -40,7 +40,7 @@ CREATE TABLE IF NOT EXISTS product_line_tasks ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Task execution log (tracks what ran during each activation) -CREATE TABLE IF NOT EXISTS task_execution_log ( +CREATE TABLE IF NOT EXISTS `#__task_execution_log` ( id INT AUTO_INCREMENT PRIMARY KEY, activation_attempt_id INT DEFAULT NULL COMMENT 'FK to activation_attempts', product_line_id INT DEFAULT NULL, @@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS task_execution_log ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Seed built-in task templates -INSERT INTO task_templates (task_key, task_name, task_type, description, default_timeout_seconds, default_on_failure, is_system, icon) VALUES +INSERT INTO `#__task_templates` (task_key, task_name, task_type, description, default_timeout_seconds, default_on_failure, is_system, icon) VALUES ('hardware_collection', 'Hardware Collection', 'built_in', 'Collect full hardware inventory (MB, CPU, RAM, GPU, disks, network)', 60, 'stop', 1, 'Cpu'), ('qc_compliance', 'QC Compliance Check', 'built_in', 'Run quality control checks (Secure Boot, BIOS version, HackBGRT)', 30, 'stop', 1, 'ShieldCheck'), ('oem_activation', 'OEM Key Activation', 'built_in', 'Request OEM key from server, install and activate Windows', 180, 'stop', 1, 'Key'), @@ -73,7 +73,7 @@ INSERT INTO task_templates (task_key, task_name, task_type, description, default ON DUPLICATE KEY UPDATE task_name = VALUES(task_name); -- Seed example custom tasks (disabled by default, admin can enable per product line) -INSERT INTO task_templates (task_key, task_name, task_type, description, default_code, default_timeout_seconds, default_on_failure, is_system, icon) VALUES +INSERT INTO `#__task_templates` (task_key, task_name, task_type, description, default_code, default_timeout_seconds, default_on_failure, is_system, icon) VALUES ('set_power_plan', 'Set Power Plan', 'custom', 'Configure Windows power plan (High Performance, Balanced, etc.)', 'powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c # High Performance', 15, 'skip', 0, 'Zap'), ('disable_sleep', 'Disable Sleep Mode', 'custom', 'Prevent the PC from going to sleep', diff --git a/FINAL_PRODUCTION_SYSTEM/database/temp_password_hash_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/temp_password_hash_migration.sql index 7188269..e2b4cef 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/temp_password_hash_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/temp_password_hash_migration.sql @@ -3,7 +3,7 @@ -- and must be followed by running the PHP migration script below. -- Step 1: Widen column to hold bcrypt hashes (60 chars) -ALTER TABLE technicians MODIFY COLUMN temp_password VARCHAR(255) DEFAULT NULL; +ALTER TABLE `#__technicians` MODIFY COLUMN temp_password VARCHAR(255) DEFAULT NULL; -- Step 2: The existing plaintext temp passwords must be hashed via PHP -- because SQL cannot generate bcrypt hashes natively. diff --git a/FINAL_PRODUCTION_SYSTEM/database/unallocated_space_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/unallocated_space_migration.sql index 1827a70..606a568 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/unallocated_space_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/unallocated_space_migration.sql @@ -2,7 +2,7 @@ -- Adds configurable max unallocated space limit for partition QC -- 1. Add per-variant unallocated space limit -ALTER TABLE product_variants +ALTER TABLE `#__product_variants` ADD COLUMN IF NOT EXISTS max_unallocated_mb INT DEFAULT NULL COMMENT 'Max allowed unallocated disk space in MB (NULL = use global setting)'; diff --git a/FINAL_PRODUCTION_SYSTEM/database/upgrade_system_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/upgrade_system_migration.sql index d1ee47a..7037a12 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/upgrade_system_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/upgrade_system_migration.sql @@ -5,7 +5,7 @@ -- verify, rollback. Provides full audit trail. -- ============================================================= -CREATE TABLE IF NOT EXISTS upgrade_history ( +CREATE TABLE IF NOT EXISTS `#__upgrade_history` ( id INT AUTO_INCREMENT PRIMARY KEY, from_version VARCHAR(20) NOT NULL, to_version VARCHAR(20) NOT NULL, diff --git a/FINAL_PRODUCTION_SYSTEM/database/usb_devices_migration.sql b/FINAL_PRODUCTION_SYSTEM/database/usb_devices_migration.sql index ca10291..335bdea 100644 --- a/FINAL_PRODUCTION_SYSTEM/database/usb_devices_migration.sql +++ b/FINAL_PRODUCTION_SYSTEM/database/usb_devices_migration.sql @@ -4,7 +4,7 @@ -- Tracks registered USB devices for passwordless technician auth. -- ============================================================= -CREATE TABLE IF NOT EXISTS usb_devices ( +CREATE TABLE IF NOT EXISTS `#__usb_devices` ( device_id INT AUTO_INCREMENT PRIMARY KEY, device_serial_number VARCHAR(255) NOT NULL UNIQUE, device_name VARCHAR(255) NOT NULL, diff --git a/FINAL_PRODUCTION_SYSTEM/functions/acl.php b/FINAL_PRODUCTION_SYSTEM/functions/acl.php index 8b602f1..8411927 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/acl.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/acl.php @@ -110,7 +110,7 @@ function aclLogDenial($userId, $userType, $permissionKey, $session) { try { $stmt = $pdo->prepare(" - INSERT INTO rbac_permission_denials ( + INSERT INTO `" . t('rbac_permission_denials') . "` ( admin_id, session_id, admin_role, requested_action, endpoint, ip_address, user_agent ) VALUES (?, ?, ?, ?, ?, ?, ?) @@ -150,7 +150,7 @@ function aclGetEffectivePermissions($userType, $userId) { // Check if super_admin $isSuperAdmin = false; if ($roleId) { - $stmt = $pdo->prepare("SELECT role_name FROM acl_roles WHERE id = ?"); + $stmt = $pdo->prepare("SELECT role_name FROM `" . t('acl_roles') . "` WHERE id = ?"); $stmt->execute([$roleId]); $role = $stmt->fetch(PDO::FETCH_ASSOC); if ($role && $role['role_name'] === 'super_admin') { @@ -159,7 +159,7 @@ function aclGetEffectivePermissions($userType, $userId) { } // Get all permissions - $stmt = $pdo->query("SELECT id, permission_key, display_name, category_id, is_dangerous FROM acl_permissions ORDER BY id"); + $stmt = $pdo->query("SELECT id, permission_key, display_name, category_id, is_dangerous FROM `" . t('acl_permissions') . "` ORDER BY id"); $allPerms = $stmt->fetchAll(PDO::FETCH_ASSOC); // Get role permissions @@ -167,8 +167,8 @@ function aclGetEffectivePermissions($userType, $userId) { if ($roleId) { $stmt = $pdo->prepare(" SELECT p.permission_key - FROM acl_role_permissions rp - INNER JOIN acl_permissions p ON rp.permission_id = p.id + FROM `" . t('acl_role_permissions') . "` rp + INNER JOIN `" . t('acl_permissions') . "` p ON rp.permission_id = p.id WHERE rp.role_id = ? "); $stmt->execute([$roleId]); @@ -179,8 +179,8 @@ function aclGetEffectivePermissions($userType, $userId) { $overrides = []; $stmt = $pdo->prepare(" SELECT p.permission_key, uo.is_granted, uo.reason, uo.expires_at - FROM acl_user_overrides uo - INNER JOIN acl_permissions p ON uo.permission_id = p.id + FROM `" . t('acl_user_overrides') . "` uo + INNER JOIN `" . t('acl_permissions') . "` p ON uo.permission_id = p.id WHERE uo.user_type = ? AND uo.user_id = ? AND (uo.expires_at IS NULL OR uo.expires_at > NOW()) "); @@ -232,12 +232,12 @@ function aclGetEffectivePermissions($userType, $userId) { function aclGetRoleById($roleId) { global $pdo; try { - $stmt = $pdo->prepare("SELECT * FROM acl_roles WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('acl_roles') . "` WHERE id = ?"); $stmt->execute([$roleId]); $role = $stmt->fetch(PDO::FETCH_ASSOC); if (!$role) return null; - $stmt = $pdo->prepare("SELECT permission_id FROM acl_role_permissions WHERE role_id = ?"); + $stmt = $pdo->prepare("SELECT permission_id FROM `" . t('acl_role_permissions') . "` WHERE role_id = ?"); $stmt->execute([$roleId]); $role['permission_ids'] = $stmt->fetchAll(PDO::FETCH_COLUMN); @@ -255,8 +255,8 @@ function aclListRoles($roleType = null) { global $pdo; try { $sql = "SELECT r.*, - (SELECT COUNT(*) FROM acl_role_permissions WHERE role_id = r.id) as permission_count - FROM acl_roles r WHERE 1=1"; + (SELECT COUNT(*) FROM `" . t('acl_role_permissions') . "` WHERE role_id = r.id) as permission_count + FROM `" . t('acl_roles') . "` r WHERE 1=1"; $params = []; if ($roleType) { $sql .= " AND r.role_type = ?"; @@ -291,7 +291,7 @@ function aclCreateRole($name, $displayName, $description, $roleType, $color, $pe $pdo->beginTransaction(); $stmt = $pdo->prepare(" - INSERT INTO acl_roles (role_name, display_name, description, role_type, color, is_system_role, priority, created_by) + INSERT INTO `" . t('acl_roles') . "` (role_name, display_name, description, role_type, color, is_system_role, priority, created_by) VALUES (?, ?, ?, ?, ?, 0, 0, ?) "); $stmt->execute([$name, $displayName, $description, $roleType, $color, $actorId]); @@ -299,7 +299,7 @@ function aclCreateRole($name, $displayName, $description, $roleType, $color, $pe // Assign permissions if (!empty($permissionIds)) { - $stmt = $pdo->prepare("INSERT INTO acl_role_permissions (role_id, permission_id, granted_by) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT INTO `" . t('acl_role_permissions') . "` (role_id, permission_id, granted_by) VALUES (?, ?, ?)"); foreach ($permissionIds as $permId) { $stmt->execute([$roleId, $permId, $actorId]); } @@ -329,7 +329,7 @@ function aclUpdateRole($roleId, $data, $actorId) { // Optimistic locking: reject if role was modified since the client loaded it if (!empty($data['expected_updated_at'])) { - $stmt = $pdo->prepare("SELECT updated_at FROM acl_roles WHERE id = ?"); + $stmt = $pdo->prepare("SELECT updated_at FROM `" . t('acl_roles') . "` WHERE id = ?"); $stmt->execute([$roleId]); $currentUpdatedAt = $stmt->fetchColumn(); if ($currentUpdatedAt && $currentUpdatedAt !== $data['expected_updated_at']) { @@ -372,7 +372,7 @@ function aclUpdateRole($roleId, $data, $actorId) { if (!empty($fields)) { $params[] = $roleId; - $stmt = $pdo->prepare("UPDATE acl_roles SET " . implode(', ', $fields) . " WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('acl_roles') . "` SET " . implode(', ', $fields) . " WHERE id = ?"); $stmt->execute($params); } @@ -381,11 +381,11 @@ function aclUpdateRole($roleId, $data, $actorId) { $oldPermIds = $role['permission_ids']; // Clear existing - $stmt = $pdo->prepare("DELETE FROM acl_role_permissions WHERE role_id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('acl_role_permissions') . "` WHERE role_id = ?"); $stmt->execute([$roleId]); // Insert new - $stmt = $pdo->prepare("INSERT INTO acl_role_permissions (role_id, permission_id, granted_by) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT INTO `" . t('acl_role_permissions') . "` (role_id, permission_id, granted_by) VALUES (?, ?, ?)"); foreach ($data['permission_ids'] as $permId) { $stmt->execute([$roleId, $permId, $actorId]); } @@ -428,7 +428,7 @@ function aclDeleteRole($roleId, $actorId) { $pdo->beginTransaction(); // role_permissions will cascade delete - $stmt = $pdo->prepare("DELETE FROM acl_roles WHERE id = ? AND is_system_role = 0"); + $stmt = $pdo->prepare("DELETE FROM `" . t('acl_roles') . "` WHERE id = ? AND is_system_role = 0"); $stmt->execute([$roleId]); aclLogChange($actorId, 'delete_role', 'role', $roleId, $role['display_name'], @@ -480,10 +480,10 @@ function aclAssignPermissions($roleId, $permissionIds, $actorId) { $oldPermIds = $role['permission_ids']; - $stmt = $pdo->prepare("DELETE FROM acl_role_permissions WHERE role_id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('acl_role_permissions') . "` WHERE role_id = ?"); $stmt->execute([$roleId]); - $stmt = $pdo->prepare("INSERT INTO acl_role_permissions (role_id, permission_id, granted_by) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT INTO `" . t('acl_role_permissions') . "` (role_id, permission_id, granted_by) VALUES (?, ?, ?)"); foreach ($permissionIds as $permId) { $stmt->execute([$roleId, $permId, $actorId]); } @@ -511,7 +511,7 @@ function aclSetUserOverride($userType, $userId, $permissionId, $isGranted, $reas global $pdo; try { $stmt = $pdo->prepare(" - INSERT INTO acl_user_overrides (user_type, user_id, permission_id, is_granted, reason, expires_at, created_by) + INSERT INTO `" . t('acl_user_overrides') . "` (user_type, user_id, permission_id, is_granted, reason, expires_at, created_by) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE is_granted = VALUES(is_granted), reason = VALUES(reason), expires_at = VALUES(expires_at), created_by = VALUES(created_by), @@ -520,7 +520,7 @@ function aclSetUserOverride($userType, $userId, $permissionId, $isGranted, $reas $stmt->execute([$userType, $userId, $permissionId, $isGranted ? 1 : 0, $reason, $expiresAt, $actorId]); // Get permission key for logging - $stmt2 = $pdo->prepare("SELECT permission_key FROM acl_permissions WHERE id = ?"); + $stmt2 = $pdo->prepare("SELECT permission_key FROM `" . t('acl_permissions') . "` WHERE id = ?"); $stmt2->execute([$permissionId]); $permKey = $stmt2->fetchColumn(); @@ -544,14 +544,14 @@ function aclRemoveUserOverride($userType, $userId, $permissionId, $actorId) { // Get current override for logging $stmt = $pdo->prepare(" SELECT uo.*, p.permission_key - FROM acl_user_overrides uo - INNER JOIN acl_permissions p ON uo.permission_id = p.id + FROM `" . t('acl_user_overrides') . "` uo + INNER JOIN `" . t('acl_permissions') . "` p ON uo.permission_id = p.id WHERE uo.user_type = ? AND uo.user_id = ? AND uo.permission_id = ? "); $stmt->execute([$userType, $userId, $permissionId]); $old = $stmt->fetch(PDO::FETCH_ASSOC); - $stmt = $pdo->prepare("DELETE FROM acl_user_overrides WHERE user_type = ? AND user_id = ? AND permission_id = ?"); + $stmt = $pdo->prepare("DELETE FROM `" . t('acl_user_overrides') . "` WHERE user_type = ? AND user_id = ? AND permission_id = ?"); $stmt->execute([$userType, $userId, $permissionId]); if ($old) { @@ -575,8 +575,8 @@ function aclGetUserOverrides($userType, $userId) { try { $stmt = $pdo->prepare(" SELECT uo.*, p.permission_key, p.display_name as permission_name, p.category_id - FROM acl_user_overrides uo - INNER JOIN acl_permissions p ON uo.permission_id = p.id + FROM `" . t('acl_user_overrides') . "` uo + INNER JOIN `" . t('acl_permissions') . "` p ON uo.permission_id = p.id WHERE uo.user_type = ? AND uo.user_id = ? ORDER BY p.id "); @@ -599,11 +599,11 @@ function aclListPermissions($categoryId = null) { global $pdo; try { // Get categories - $stmt = $pdo->query("SELECT * FROM acl_permission_categories ORDER BY sort_order"); + $stmt = $pdo->query("SELECT * FROM `" . t('acl_permission_categories') . "` ORDER BY sort_order"); $categories = $stmt->fetchAll(PDO::FETCH_ASSOC); // Get permissions - $sql = "SELECT * FROM acl_permissions"; + $sql = "SELECT * FROM `" . t('acl_permissions') . "`"; $params = []; if ($categoryId) { $sql .= " WHERE category_id = ?"; @@ -646,11 +646,11 @@ function aclGetUserRoleId($userType, $userId) { global $pdo; try { if ($userType === 'admin') { - $stmt = $pdo->prepare("SELECT custom_role_id FROM admin_users WHERE id = ?"); + $stmt = $pdo->prepare("SELECT custom_role_id FROM `" . t('admin_users') . "` WHERE id = ?"); $stmt->execute([$userId]); return $stmt->fetchColumn() ?: null; } elseif ($userType === 'technician') { - $stmt = $pdo->prepare("SELECT role_id FROM technicians WHERE id = ?"); + $stmt = $pdo->prepare("SELECT role_id FROM `" . t('technicians') . "` WHERE id = ?"); $stmt->execute([$userId]); return $stmt->fetchColumn() ?: null; } @@ -668,8 +668,8 @@ function aclGetRoleUserCount($roleId) { try { $stmt = $pdo->prepare(" SELECT - (SELECT COUNT(*) FROM admin_users WHERE custom_role_id = ?) + - (SELECT COUNT(*) FROM technicians WHERE role_id = ?) as total + (SELECT COUNT(*) FROM `" . t('admin_users') . "` WHERE custom_role_id = ?) + + (SELECT COUNT(*) FROM `" . t('technicians') . "` WHERE role_id = ?) as total "); $stmt->execute([$roleId, $roleId]); return (int)$stmt->fetchColumn(); @@ -686,7 +686,7 @@ function aclLogChange($actorId, $action, $targetType, $targetId, $targetName, $o global $pdo; try { $stmt = $pdo->prepare(" - INSERT INTO acl_change_log (actor_id, action, target_type, target_id, target_name, old_value, new_value, ip_address) + INSERT INTO `" . t('acl_change_log') . "` (actor_id, action, target_type, target_id, target_name, old_value, new_value, ip_address) VALUES (?, ?, ?, ?, ?, ?, ?, ?) "); $stmt->execute([ diff --git a/FINAL_PRODUCTION_SYSTEM/functions/admin-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/admin-helpers.php index 8e3855e..51bc3d0 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/admin-helpers.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/admin-helpers.php @@ -27,8 +27,8 @@ function validateAdminSession() { s.id, s.admin_id, s.expires_at, s.last_activity, u.username, u.full_name, u.role, u.is_active, u.preferred_language, u.password_changed_at, u.must_change_password - FROM admin_sessions s - JOIN admin_users u ON s.admin_id = u.id + FROM `" . t('admin_sessions') . "` s + JOIN `" . t('admin_users') . "` u ON s.admin_id = u.id WHERE s.session_token = ? AND s.is_active = 1 "); $stmt->execute([$_SESSION['admin_token']]); @@ -41,7 +41,7 @@ function validateAdminSession() { // Check if session expired (hard expiry set at creation time) if (strtotime($session['expires_at']) < time()) { - $stmt = $pdo->prepare("UPDATE admin_sessions SET is_active = 0 WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('admin_sessions') . "` SET is_active = 0 WHERE id = ?"); $stmt->execute([$session['id']]); return false; } @@ -50,7 +50,7 @@ function validateAdminSession() { $timeoutMinutes = (int) getConfigWithDefault('admin_session_timeout_minutes', DEFAULT_ADMIN_SESSION_TIMEOUT_MINUTES); $timeoutSeconds = $timeoutMinutes * 60; if (strtotime($session['last_activity']) < (time() - $timeoutSeconds)) { - $stmt = $pdo->prepare("UPDATE admin_sessions SET is_active = 0 WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('admin_sessions') . "` SET is_active = 0 WHERE id = ?"); $stmt->execute([$session['id']]); return false; } @@ -71,7 +71,7 @@ function validateAdminSession() { } // Update last activity - $stmt = $pdo->prepare("UPDATE admin_sessions SET last_activity = NOW() WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('admin_sessions') . "` SET last_activity = NOW() WHERE id = ?"); $stmt->execute([$session['id']]); return $session; @@ -93,7 +93,7 @@ function logAdminActivity($admin_id, $session_id, $action, $description = '') { global $pdo; try { $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log (admin_id, session_id, action, description, ip_address, user_agent) + INSERT INTO `" . t('admin_activity_log') . "` (admin_id, session_id, action, description, ip_address, user_agent) VALUES (?, ?, ?, ?, ?, ?) "); $stmt->execute([ @@ -125,7 +125,7 @@ function authenticateAdmin($username, $password) { $lockoutMinutes = (int) getConfigWithDefault('admin_lockout_duration_minutes', DEFAULT_ADMIN_LOCKOUT_MINUTES); $sessionTimeout = (int) getConfigWithDefault('admin_session_timeout_minutes', DEFAULT_ADMIN_SESSION_TIMEOUT_MINUTES); - $stmt = $pdo->prepare("SELECT * FROM admin_users WHERE username = ? AND is_active = 1"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('admin_users') . "` WHERE username = ? AND is_active = 1"); $stmt->execute([$username]); $admin = $stmt->fetch(); @@ -153,7 +153,7 @@ function authenticateAdmin($username, $password) { } $stmt = $pdo->prepare(" - UPDATE admin_users + UPDATE `" . t('admin_users') . "` SET failed_login_attempts = ?, locked_until = ? WHERE id = ? "); @@ -172,7 +172,7 @@ function authenticateAdmin($username, $password) { $expires_at = date('Y-m-d H:i:s', time() + ($sessionTimeout * 60)); $stmt = $pdo->prepare(" - INSERT INTO admin_sessions (admin_id, session_token, ip_address, user_agent, expires_at) + INSERT INTO `" . t('admin_sessions') . "` (admin_id, session_token, ip_address, user_agent, expires_at) VALUES (?, ?, ?, ?, ?) "); $stmt->execute([ @@ -182,7 +182,7 @@ function authenticateAdmin($username, $password) { // Reset failed attempts $stmt = $pdo->prepare(" - UPDATE admin_users + UPDATE `" . t('admin_users') . "` SET failed_login_attempts = 0, locked_until = NULL, last_login = NOW(), last_login_ip = ? WHERE id = ? "); @@ -217,7 +217,7 @@ function getUploadErrorMessage(int $errorCode): string { */ function saveConfigBatch(PDO $pdo, array $configs, array $descriptions = []): void { $stmt = $pdo->prepare(" - INSERT INTO system_config (config_key, config_value, description, updated_at) + INSERT INTO `" . t('system_config') . "` (config_key, config_value, description, updated_at) VALUES (?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE config_value = ?, updated_at = NOW() "); @@ -251,8 +251,8 @@ function isActorSuperAdmin($adminId) { global $pdo; try { $stmt = $pdo->prepare(" - SELECT r.role_name FROM acl_roles r - INNER JOIN admin_users u ON u.custom_role_id = r.id + SELECT r.role_name FROM `" . t('acl_roles') . "` r + INNER JOIN `" . t('admin_users') . "` u ON u.custom_role_id = r.id WHERE u.id = ? AND r.role_name = 'super_admin' "); $stmt->execute([$adminId]); diff --git a/FINAL_PRODUCTION_SYSTEM/functions/csv-import.php b/FINAL_PRODUCTION_SYSTEM/functions/csv-import.php index 11ee83b..91b7cb5 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/csv-import.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/csv-import.php @@ -180,14 +180,14 @@ function importComprehensiveKeyRow($row, $format) { try { // Check if key already exists - $stmt = $pdo->prepare("SELECT id, key_status FROM oem_keys WHERE product_key = ?"); + $stmt = $pdo->prepare("SELECT id, key_status FROM `" . t('oem_keys') . "` WHERE product_key = ?"); $stmt->execute([$product_key]); $existing = $stmt->fetch(PDO::FETCH_ASSOC); if ($existing) { // Update existing key $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = ?, oem_identifier = ?, roll_serial = ?, fail_counter = ?, last_use_date = ?, last_use_time = ?, first_usage_date = ?, first_usage_time = ?, updated_at = NOW() @@ -200,7 +200,7 @@ function importComprehensiveKeyRow($row, $format) { } else { // Insert new key $stmt = $pdo->prepare(" - INSERT INTO oem_keys (product_key, oem_identifier, roll_serial, key_status, fail_counter, + INSERT INTO `" . t('oem_keys') . "` (product_key, oem_identifier, roll_serial, key_status, fail_counter, last_use_date, last_use_time, first_usage_date, first_usage_time, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW()) "); @@ -242,7 +242,7 @@ function importStandardKeyRow($row, $format) { try { // Check if key already exists - $stmt = $pdo->prepare("SELECT id, key_status FROM oem_keys WHERE product_key = ?"); + $stmt = $pdo->prepare("SELECT id, key_status FROM `" . t('oem_keys') . "` WHERE product_key = ?"); $stmt->execute([$product_key]); $existing = $stmt->fetch(PDO::FETCH_ASSOC); @@ -250,7 +250,7 @@ function importStandardKeyRow($row, $format) { // Update existing key if status changed if ($existing['key_status'] !== $key_status) { $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = ?, oem_identifier = ?, barcode = ?, updated_at = NOW() WHERE product_key = ? "); @@ -262,7 +262,7 @@ function importStandardKeyRow($row, $format) { } else { // Insert new key $stmt = $pdo->prepare(" - INSERT INTO oem_keys (product_key, oem_identifier, barcode, key_status, roll_serial, created_at) + INSERT INTO `" . t('oem_keys') . "` (product_key, oem_identifier, barcode, key_status, roll_serial, created_at) VALUES (?, ?, ?, ?, 'imported', NOW()) "); $stmt->execute([$product_key, $oem_identifier, $barcode, $key_status]); @@ -321,7 +321,7 @@ function importActivationAttempts($key_id, $row, $format) { if (!empty($attempt['attempted_date']) && !empty($attempt['technician_id'])) { try { $stmt = $pdo->prepare(" - INSERT INTO activation_attempts + INSERT INTO `" . t('activation_attempts') . "` (key_id, technician_id, order_number, attempt_number, attempt_result, attempted_date, attempted_time, attempted_at) VALUES (?, ?, ?, ?, ?, ?, ?, NOW()) diff --git a/FINAL_PRODUCTION_SYSTEM/functions/db-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/db-helpers.php new file mode 100644 index 0000000..30e6976 --- /dev/null +++ b/FINAL_PRODUCTION_SYSTEM/functions/db-helpers.php @@ -0,0 +1,37 @@ +prepare("SELECT * FROM integrations WHERE integration_key = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('integrations') . "` WHERE integration_key = ?"); $stmt->execute([$key]); $row = $stmt->fetch(); @@ -51,10 +51,10 @@ function updateIntegrationStatus(int $id, string $status, ?string $error = null) try { if ($error !== null) { - $stmt = $pdo->prepare("UPDATE integrations SET status = ?, last_error = ?, updated_at = NOW() WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('integrations') . "` SET status = ?, last_error = ?, updated_at = NOW() WHERE id = ?"); $stmt->execute([$status, $error, $id]); } else { - $stmt = $pdo->prepare("UPDATE integrations SET status = ?, updated_at = NOW() WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('integrations') . "` SET status = ?, updated_at = NOW() WHERE id = ?"); $stmt->execute([$status, $id]); } @@ -81,7 +81,7 @@ function dispatchIntegrationEvent(string $integrationKey, string $eventType, arr try { $stmt = $pdo->prepare(" - INSERT INTO integration_events (integration_id, event_type, payload, status, created_at) + INSERT INTO `" . t('integration_events') . "` (integration_id, event_type, payload, status, created_at) VALUES (?, ?, ?, 'pending', NOW()) "); $stmt->execute([ @@ -106,7 +106,7 @@ function dispatchEventToAll(string $eventType, array $payload): void { global $pdo; try { - $stmt = $pdo->query("SELECT integration_key FROM integrations WHERE enabled = 1"); + $stmt = $pdo->query("SELECT integration_key FROM `" . t('integrations') . "` WHERE enabled = 1"); $keys = $stmt->fetchAll(PDO::FETCH_COLUMN); foreach ($keys as $key) { @@ -124,7 +124,7 @@ function deliverIntegrationEvent(int $eventId, array $integration): void { global $pdo; try { - $stmt = $pdo->prepare("SELECT * FROM integration_events WHERE id = ?"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('integration_events') . "` WHERE id = ?"); $stmt->execute([$eventId]); $event = $stmt->fetch(); if (!$event) return; @@ -137,7 +137,7 @@ function deliverIntegrationEvent(int $eventId, array $integration): void { $handlerFile = dirname(__DIR__) . "/functions/integrations/{$key}-handler.php"; if (!file_exists($handlerFile)) { // No handler yet — mark as skipped - $stmt = $pdo->prepare("UPDATE integration_events SET status = 'skipped', processed_at = NOW(), error_message = 'No handler file' WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('integration_events') . "` SET status = 'skipped', processed_at = NOW(), error_message = 'No handler file' WHERE id = ?"); $stmt->execute([$eventId]); return; } @@ -146,7 +146,7 @@ function deliverIntegrationEvent(int $eventId, array $integration): void { $handlerFunc = 'handle_' . str_replace('-', '_', $key) . '_event'; if (!function_exists($handlerFunc)) { - $stmt = $pdo->prepare("UPDATE integration_events SET status = 'skipped', processed_at = NOW(), error_message = 'Handler function not found' WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('integration_events') . "` SET status = 'skipped', processed_at = NOW(), error_message = 'Handler function not found' WHERE id = ?"); $stmt->execute([$eventId]); return; } @@ -157,7 +157,7 @@ function deliverIntegrationEvent(int $eventId, array $integration): void { // Update event with result $status = ($result['success'] ?? false) ? 'sent' : 'failed'; $stmt = $pdo->prepare(" - UPDATE integration_events + UPDATE `" . t('integration_events') . "` SET status = ?, response_code = ?, response_body = ?, error_message = ?, processed_at = NOW() WHERE id = ? "); @@ -172,7 +172,7 @@ function deliverIntegrationEvent(int $eventId, array $integration): void { // Update integration status if ($status === 'sent') { updateIntegrationStatus($integration['id'], 'connected'); - $pdo->prepare("UPDATE integrations SET last_sync_at = NOW() WHERE id = ?")->execute([$integration['id']]); + $pdo->prepare("UPDATE `" . t('integrations') . "` SET last_sync_at = NOW() WHERE id = ?")->execute([$integration['id']]); } else { updateIntegrationStatus($integration['id'], 'error', $result['error'] ?? 'Delivery failed'); } @@ -180,7 +180,7 @@ function deliverIntegrationEvent(int $eventId, array $integration): void { } catch (Exception $e) { error_log("deliverIntegrationEvent($eventId) failed: " . $e->getMessage()); try { - $stmt = $pdo->prepare("UPDATE integration_events SET status = 'failed', processed_at = NOW(), error_message = ? WHERE id = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('integration_events') . "` SET status = 'failed', processed_at = NOW(), error_message = ? WHERE id = ?"); $stmt->execute([$e->getMessage(), $eventId]); } catch (PDOException $ex) { // Ignore @@ -201,7 +201,7 @@ function retryFailedEvents(string $integrationKey, int $limit = 50): array { try { $stmt = $pdo->prepare(" - SELECT id FROM integration_events + SELECT id FROM `" . t('integration_events') . "` WHERE integration_id = ? AND status IN ('failed', 'pending') ORDER BY created_at ASC LIMIT ? @@ -216,7 +216,7 @@ function retryFailedEvents(string $integrationKey, int $limit = 50): array { $retried++; // Check if it succeeded - $check = $pdo->prepare("SELECT status FROM integration_events WHERE id = ?"); + $check = $pdo->prepare("SELECT status FROM `" . t('integration_events') . "` WHERE id = ?"); $check->execute([$eid]); if ($check->fetchColumn() === 'sent') { $succeeded++; diff --git a/FINAL_PRODUCTION_SYSTEM/functions/key-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/key-helpers.php index ba37328..63d385f 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/key-helpers.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/key-helpers.php @@ -39,7 +39,7 @@ function allocateKeyAtomically($pdo, $technician_id, $order_number) { } $stmt = $pdo->prepare(" - SELECT * FROM oem_keys + SELECT * FROM `" . t('oem_keys') . "` WHERE key_status IN ('unused', 'retry') AND (fail_counter < " . MAX_KEY_FAIL_COUNTER . " OR key_status = 'unused') ORDER BY @@ -55,7 +55,7 @@ function allocateKeyAtomically($pdo, $technician_id, $order_number) { if ($key) { $stmt = $pdo->prepare(" - UPDATE oem_keys + UPDATE `" . t('oem_keys') . "` SET key_status = 'allocated', last_use_date = CURDATE(), last_use_time = CURTIME(), diff --git a/FINAL_PRODUCTION_SYSTEM/functions/license-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/license-helpers.php index 44c904f..9aa8877 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/license-helpers.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/license-helpers.php @@ -84,7 +84,7 @@ function generateInstanceId(PDO $pdo): string { // Get database creation timestamp (stable across restarts) try { - $stmt = $pdo->query("SELECT MIN(created_at) AS first_record FROM admin_users"); + $stmt = $pdo->query("SELECT MIN(created_at) AS first_record FROM `" . t('admin_users') . "`"); $row = $stmt->fetch(); $dbSeed = $row['first_record'] ?? date('Y-m-d'); } catch (Exception $e) { @@ -171,7 +171,7 @@ function createLicenseJwt(array $payload, string $secret = 'keygate-community-ve */ function getCurrentLicense(PDO $pdo): ?array { try { - $stmt = $pdo->query("SELECT * FROM license_info WHERE is_active = 1 ORDER BY id DESC LIMIT 1"); + $stmt = $pdo->query("SELECT * FROM `" . t('license_info') . "` WHERE is_active = 1 ORDER BY id DESC LIMIT 1"); return $stmt->fetch(PDO::FETCH_ASSOC) ?: null; } catch (Exception $e) { // Table may not exist yet (pre-migration) @@ -258,11 +258,11 @@ function registerLicense(PDO $pdo, string $licenseKey): array { $tierDef = LICENSE_TIERS[$tier]; // Deactivate any existing license - $pdo->exec("UPDATE license_info SET is_active = 0"); + $pdo->exec("UPDATE `" . t('license_info') . "` SET is_active = 0"); // Insert new license $stmt = $pdo->prepare(" - INSERT INTO license_info + INSERT INTO `" . t('license_info') . "` (license_key, instance_id, tier, licensed_to_email, licensed_to_name, max_technicians, max_keys, features, issued_at, expires_at, last_validated_at, validation_status, is_active) @@ -307,7 +307,7 @@ function isFeatureAvailable(PDO $pdo, string $feature): bool { */ function canAddTechnician(PDO $pdo): array { $license = getEffectiveLicense($pdo); - $stmt = $pdo->query("SELECT COUNT(*) FROM technicians WHERE status = 'active'"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('technicians') . "` WHERE status = 'active'"); $currentCount = (int)$stmt->fetchColumn(); if ($currentCount >= $license['max_technicians']) { @@ -328,7 +328,7 @@ function canAddTechnician(PDO $pdo): array { */ function canAddKeys(PDO $pdo, int $count = 1): array { $license = getEffectiveLicense($pdo); - $stmt = $pdo->query("SELECT COUNT(*) FROM oem_keys"); + $stmt = $pdo->query("SELECT COUNT(*) FROM `" . t('oem_keys') . "`"); $currentCount = (int)$stmt->fetchColumn(); if (($currentCount + $count) > $license['max_keys']) { diff --git a/FINAL_PRODUCTION_SYSTEM/functions/network-utils.php b/FINAL_PRODUCTION_SYSTEM/functions/network-utils.php index ec3e6bf..fe2e8f6 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/network-utils.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/network-utils.php @@ -21,14 +21,14 @@ function checkTrustedNetwork($ip, $checkUSBAuth = false) { // Check if network allows USB authentication $stmt = $pdo->prepare(" SELECT id, network_name, ip_range, bypass_2fa, allow_usb_auth - FROM trusted_networks + FROM `" . t('trusted_networks') . "` WHERE is_active = 1 AND allow_usb_auth = 1 "); } else { // Check if network allows 2FA bypass $stmt = $pdo->prepare(" SELECT id, network_name, ip_range, bypass_2fa, allow_usb_auth - FROM trusted_networks + FROM `" . t('trusted_networks') . "` WHERE is_active = 1 AND bypass_2fa = 1 "); } @@ -122,7 +122,7 @@ function logNetworkSecurityEvent($event_type, $ip_address, $network_id = null, $ try { $stmt = $pdo->prepare(" - INSERT INTO admin_activity_log ( + INSERT INTO `" . t('admin_activity_log') . "` ( admin_id, session_id, action, description, ip_address, user_agent, trusted_network_id ) VALUES ( diff --git a/FINAL_PRODUCTION_SYSTEM/functions/push-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/push-helpers.php index bcf23cd..2f2304f 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/push-helpers.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/push-helpers.php @@ -87,7 +87,7 @@ function getVapidKeys(): ?array { $keys = VAPID::createVapidKeys(); $stmt = $pdo->prepare(" - INSERT INTO system_config (config_key, config_value, description) + INSERT INTO `" . t('system_config') . "` (config_key, config_value, description) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE config_value = VALUES(config_value) "); @@ -129,11 +129,11 @@ function dispatchNotification(string $action, string $description, int $actorAdm // Get all admin IDs except the actor, who have this category enabled (or no preference row = default ON) $stmt = $pdo->prepare(" SELECT DISTINCT au.id, au.preferred_language - FROM admin_users au + FROM `" . t('admin_users') . "` au WHERE au.id != ? AND au.is_active = 1 AND NOT EXISTS ( - SELECT 1 FROM push_preferences pp + SELECT 1 FROM `" . t('push_preferences') . "` pp WHERE pp.admin_id = au.id AND pp.category = ? AND pp.enabled = 0 ) "); @@ -148,7 +148,7 @@ function dispatchNotification(string $action, string $description, int $actorAdm // Insert bell notifications for all recipients $insertStmt = $pdo->prepare(" - INSERT INTO notifications (admin_id, category, title_key, body, action_url) + INSERT INTO `" . t('notifications') . "` (admin_id, category, title_key, body, action_url) VALUES (?, ?, ?, ?, ?) "); foreach ($recipientIds as $adminId) { @@ -212,7 +212,7 @@ function dispatchNotification(string $action, string $description, int $actorAdm if ($report->isSubscriptionExpired()) { // Deactivate expired subscriptions $expiredEndpoint = $report->getRequest()->getUri()->__toString(); - $deactivateStmt = $pdo->prepare("UPDATE push_subscriptions SET is_active = 0 WHERE endpoint = ?"); + $deactivateStmt = $pdo->prepare("UPDATE `" . t('push_subscriptions') . "` SET is_active = 0 WHERE endpoint = ?"); $deactivateStmt->execute([$expiredEndpoint]); } } diff --git a/FINAL_PRODUCTION_SYSTEM/functions/qc-compliance.php b/FINAL_PRODUCTION_SYSTEM/functions/qc-compliance.php index 63f2d6a..eb339f5 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/qc-compliance.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/qc-compliance.php @@ -8,7 +8,7 @@ * Check if QC compliance system is enabled */ function qcIsEnabled(PDO $pdo): bool { - $stmt = $pdo->prepare("SELECT setting_value FROM qc_global_settings WHERE setting_key = 'qc_enabled' LIMIT 1"); + $stmt = $pdo->prepare("SELECT setting_value FROM `" . t('qc_global_settings') . "` WHERE setting_key = 'qc_enabled' LIMIT 1"); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); return $row && $row['setting_value'] === '1'; @@ -18,7 +18,7 @@ function qcIsEnabled(PDO $pdo): bool { * Return all global QC settings as key-value array */ function qcGetGlobalSettings(PDO $pdo): array { - $stmt = $pdo->query("SELECT setting_key, setting_value FROM qc_global_settings"); + $stmt = $pdo->query("SELECT setting_key, setting_value FROM `" . t('qc_global_settings') . "`"); $settings = []; foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $settings[$row['setting_key']] = $row['setting_value']; @@ -36,7 +36,7 @@ function qcAutoRegisterMotherboard(PDO $pdo, ?string $manufacturer, ?string $pro } // Check if already exists - $stmt = $pdo->prepare("SELECT id, known_bios_versions FROM qc_motherboard_registry WHERE manufacturer = ? AND product = ? LIMIT 1"); + $stmt = $pdo->prepare("SELECT id, known_bios_versions FROM `" . t('qc_motherboard_registry') . "` WHERE manufacturer = ? AND product = ? LIMIT 1"); $stmt->execute([$manufacturer, $product]); $existing = $stmt->fetch(PDO::FETCH_ASSOC); @@ -48,7 +48,7 @@ function qcAutoRegisterMotherboard(PDO $pdo, ?string $manufacturer, ?string $pro } $stmt = $pdo->prepare(" - UPDATE qc_motherboard_registry + UPDATE `" . t('qc_motherboard_registry') . "` SET times_seen = times_seen + 1, last_seen_at = NOW(), known_bios_versions = ? @@ -61,7 +61,7 @@ function qcAutoRegisterMotherboard(PDO $pdo, ?string $manufacturer, ?string $pro // Insert new motherboard $knownVersions = !empty($biosVersion) ? json_encode([$biosVersion]) : '[]'; $stmt = $pdo->prepare(" - INSERT INTO qc_motherboard_registry (manufacturer, product, known_bios_versions, first_seen_at, last_seen_at, times_seen) + INSERT INTO `" . t('qc_motherboard_registry') . "` (manufacturer, product, known_bios_versions, first_seen_at, last_seen_at, times_seen) VALUES (?, ?, ?, NOW(), NOW(), 1) "); $stmt->execute([$manufacturer, $product, $knownVersions]); @@ -89,7 +89,7 @@ function qcGetEffectiveRules(PDO $pdo, ?string $manufacturer, ?string $product, // Overlay product line enforcement (matched by order number pattern) if (!empty($orderNumber) && mb_strlen($orderNumber) <= 50) { - $stmt = $pdo->query("SELECT id, name, order_pattern, secure_boot_enforcement, bios_enforcement, hackbgrt_enforcement, partition_enforcement, missing_drivers_enforcement FROM product_lines WHERE is_active = 1 ORDER BY LENGTH(order_pattern) DESC"); + $stmt = $pdo->query("SELECT id, name, order_pattern, secure_boot_enforcement, bios_enforcement, hackbgrt_enforcement, partition_enforcement, missing_drivers_enforcement FROM `" . t('product_lines') . "` WHERE is_active = 1 ORDER BY LENGTH(order_pattern) DESC"); foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $line) { $pattern = $line['order_pattern'] ?? ''; if (!preg_match('/^[\p{L}\p{N}#*\-\s]+$/u', $pattern) || mb_strlen($pattern) > 50) continue; @@ -114,7 +114,7 @@ function qcGetEffectiveRules(PDO $pdo, ?string $manufacturer, ?string $product, // Overlay manufacturer defaults if (!empty($manufacturer)) { - $stmt = $pdo->prepare("SELECT * FROM qc_manufacturer_defaults WHERE manufacturer = ? LIMIT 1"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('qc_manufacturer_defaults') . "` WHERE manufacturer = ? LIMIT 1"); $stmt->execute([$manufacturer]); $mfr = $stmt->fetch(PDO::FETCH_ASSOC); if ($mfr) { @@ -129,7 +129,7 @@ function qcGetEffectiveRules(PDO $pdo, ?string $manufacturer, ?string $product, // Overlay model-specific overrides (non-NULL only) if (!empty($manufacturer) && !empty($product)) { - $stmt = $pdo->prepare("SELECT * FROM qc_motherboard_registry WHERE manufacturer = ? AND product = ? LIMIT 1"); + $stmt = $pdo->prepare("SELECT * FROM `" . t('qc_motherboard_registry') . "` WHERE manufacturer = ? AND product = ? LIMIT 1"); $stmt->execute([$manufacturer, $product]); $model = $stmt->fetch(PDO::FETCH_ASSOC); if ($model) { @@ -444,7 +444,7 @@ function qcCheckPartitionLayout(PDO $pdo, int $hardwareInfoId, string $orderNumb if (mb_strlen($orderNumber) > 50) { return null; } - $stmt = $pdo->query("SELECT id, name, order_pattern, enforcement_level FROM product_lines WHERE is_active = 1 ORDER BY LENGTH(order_pattern) DESC"); + $stmt = $pdo->query("SELECT id, name, order_pattern, enforcement_level FROM `" . t('product_lines') . "` WHERE is_active = 1 ORDER BY LENGTH(order_pattern) DESC"); $matchedLine = null; foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $line) { $pattern = $line['order_pattern'] ?? ''; @@ -537,7 +537,7 @@ function qcCheckPartitionLayout(PDO $pdo, int $hardwareInfoId, string $orderNumb } $stmt = $pdo->prepare(" SELECT id, name, disk_size_min_mb, disk_size_max_mb - FROM product_variants + FROM `" . t('product_variants') . "` WHERE line_id = ? AND is_active = 1 AND disk_size_min_mb <= ? AND disk_size_max_mb >= ? ORDER BY disk_size_min_mb DESC @@ -562,7 +562,7 @@ function qcCheckPartitionLayout(PDO $pdo, int $hardwareInfoId, string $orderNumb // 6. Store detected variant in hardware_info $stmt = $pdo->prepare(" - UPDATE hardware_info + UPDATE `" . t('hardware_info') . "` SET detected_variant_id = ?, detected_variant_name = ?, detected_line_name = ? WHERE id = ? "); @@ -570,7 +570,7 @@ function qcCheckPartitionLayout(PDO $pdo, int $hardwareInfoId, string $orderNumb // 7. Load expected partitions $stmt = $pdo->prepare(" - SELECT * FROM product_variant_partitions + SELECT * FROM `" . t('product_variant_partitions') . "` WHERE variant_id = ? ORDER BY partition_order "); @@ -659,7 +659,7 @@ function qcCheckPartitionLayout(PDO $pdo, int $hardwareInfoId, string $orderNumb } else { // Check global setting try { - $gStmt = $pdo->prepare("SELECT setting_value FROM qc_global_settings WHERE setting_key = 'max_unallocated_mb'"); + $gStmt = $pdo->prepare("SELECT setting_value FROM `" . t('qc_global_settings') . "` WHERE setting_key = 'max_unallocated_mb'"); $gStmt->execute(); $gVal = $gStmt->fetchColumn(); if ($gVal !== false && $gVal !== null && $gVal !== '') { @@ -714,7 +714,7 @@ function qcCheckPartitionLayout(PDO $pdo, int $hardwareInfoId, string $orderNumb */ function qcInsertResult(PDO $pdo, int $hardwareInfoId, string $orderNumber, array $check, ?int $registryId, bool $retroactive = false): void { $stmt = $pdo->prepare(" - INSERT INTO qc_compliance_results ( + INSERT INTO `" . t('qc_compliance_results') . "` ( hardware_info_id, order_number, check_type, check_result, enforcement_level, expected_value, actual_value, message, rule_source, motherboard_registry_id, is_retroactive, checked_at @@ -741,7 +741,7 @@ function qcInsertResult(PDO $pdo, int $hardwareInfoId, string $orderNumber, arra function qcHasBlockingIssues(PDO $pdo, int $hardwareInfoId): bool { $stmt = $pdo->prepare(" SELECT COUNT(*) as cnt - FROM qc_compliance_results + FROM `" . t('qc_compliance_results') . "` WHERE hardware_info_id = ? AND enforcement_level = 3 AND check_result = 'fail' @@ -809,7 +809,7 @@ function qcRecheckHistorical(PDO $pdo, ?string $manufacturer = null, ?string $pr $lastId = $hwId; // Delete existing compliance results for this record - $stmt2 = $pdo->prepare("DELETE FROM qc_compliance_results WHERE hardware_info_id = ?"); + $stmt2 = $pdo->prepare("DELETE FROM `" . t('qc_compliance_results') . "` WHERE hardware_info_id = ?"); $stmt2->execute([$hwId]); // Re-run checks @@ -853,7 +853,7 @@ function qcRunChecksRetroactive(PDO $pdo, int $hardwareInfoId, array $hw): array $orderNumber = $hw['order_number'] ?? ''; // Get registry ID (don't auto-register for retroactive) - $stmt = $pdo->prepare("SELECT id FROM qc_motherboard_registry WHERE manufacturer = ? AND product = ? LIMIT 1"); + $stmt = $pdo->prepare("SELECT id FROM `" . t('qc_motherboard_registry') . "` WHERE manufacturer = ? AND product = ? LIMIT 1"); $stmt->execute([$manufacturer, $product]); $reg = $stmt->fetch(PDO::FETCH_ASSOC); $registryId = $reg ? (int) $reg['id'] : null; diff --git a/FINAL_PRODUCTION_SYSTEM/functions/session-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/session-helpers.php index 8b382ed..9a1521f 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/session-helpers.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/session-helpers.php @@ -32,9 +32,9 @@ function validateSession($token) { try { $stmt = $pdo->prepare(" SELECT s.*, k.product_key, k.key_status, t.is_active as tech_active - FROM active_sessions s - LEFT JOIN oem_keys k ON s.key_id = k.id - LEFT JOIN technicians t ON s.technician_id = t.technician_id + FROM `" . t('active_sessions') . "` s + LEFT JOIN `" . t('oem_keys') . "` k ON s.key_id = k.id + LEFT JOIN `" . t('technicians') . "` t ON s.technician_id = t.technician_id WHERE s.session_token = ? AND s.is_active = 1 AND s.expires_at > NOW() @@ -54,7 +54,7 @@ function validateSession($token) { function cleanupExpiredSessions($pdo) { try { $stmt = $pdo->prepare(" - UPDATE active_sessions + UPDATE `" . t('active_sessions') . "` SET is_active = 0 WHERE expires_at < NOW() AND is_active = 1 LIMIT " . SESSION_CLEANUP_BATCH . " @@ -82,8 +82,8 @@ function getActiveSession($pdo, $technician_id) { $stmt = $pdo->prepare(" SELECT s.*, k.product_key, k.oem_identifier, k.key_status, k.fail_counter - FROM active_sessions s - LEFT JOIN oem_keys k ON s.key_id = k.id + FROM `" . t('active_sessions') . "` s + LEFT JOIN `" . t('oem_keys') . "` k ON s.key_id = k.id WHERE s.technician_id = ? AND s.is_active = 1 AND s.expires_at > NOW() diff --git a/FINAL_PRODUCTION_SYSTEM/functions/totp-helpers.php b/FINAL_PRODUCTION_SYSTEM/functions/totp-helpers.php index 8a6cd21..32bf5b9 100644 --- a/FINAL_PRODUCTION_SYSTEM/functions/totp-helpers.php +++ b/FINAL_PRODUCTION_SYSTEM/functions/totp-helpers.php @@ -39,7 +39,7 @@ function validateAdminApiSession(): array { function fetchTotpData(PDO $pdo, int $adminId): ?array { $stmt = $pdo->prepare(" SELECT id, totp_secret, totp_enabled, backup_codes - FROM admin_totp_secrets + FROM `" . t('admin_totp_secrets') . "` WHERE admin_id = ? "); $stmt->execute([$adminId]); @@ -78,7 +78,7 @@ function verifyTotpCode(PDO $pdo, int $adminId, string $code, array $totpData, b $backupCodes = array_values($backupCodes); $stmt = $pdo->prepare(" - UPDATE admin_totp_secrets + UPDATE `" . t('admin_totp_secrets') . "` SET backup_codes = ?, last_used_at = NOW() WHERE admin_id = ? "); @@ -92,7 +92,7 @@ function verifyTotpCode(PDO $pdo, int $adminId, string $code, array $totpData, b } else { $totp = TOTP::createFromSecret($totpData['totp_secret']); - $stmt = $pdo->query("SELECT config_value FROM system_config WHERE config_key = 'totp_window'"); + $stmt = $pdo->query("SELECT config_value FROM `" . t('system_config') . "` WHERE config_key = 'totp_window'"); $windowResult = $stmt->fetch(PDO::FETCH_ASSOC); $window = $windowResult ? (int)$windowResult['config_value'] : 1; @@ -100,7 +100,7 @@ function verifyTotpCode(PDO $pdo, int $adminId, string $code, array $totpData, b if ($result['verified']) { $stmt = $pdo->prepare(" - UPDATE admin_totp_secrets + UPDATE `" . t('admin_totp_secrets') . "` SET last_used_at = NOW() WHERE admin_id = ? "); @@ -117,7 +117,7 @@ function verifyTotpCode(PDO $pdo, int $adminId, string $code, array $totpData, b * @return array ['plain' => string[], 'hashed' => string[]] */ function generateBackupCodes(PDO $pdo): array { - $stmt = $pdo->query("SELECT config_value FROM system_config WHERE config_key = 'totp_backup_codes_count'"); + $stmt = $pdo->query("SELECT config_value FROM `" . t('system_config') . "` WHERE config_key = 'totp_backup_codes_count'"); $backupCountResult = $stmt->fetch(PDO::FETCH_ASSOC); $backupCodeCount = $backupCountResult ? (int)$backupCountResult['config_value'] : 10; diff --git a/FINAL_PRODUCTION_SYSTEM/install/ajax.php b/FINAL_PRODUCTION_SYSTEM/install/ajax.php index fedc2a5..a9cbf4c 100644 --- a/FINAL_PRODUCTION_SYSTEM/install/ajax.php +++ b/FINAL_PRODUCTION_SYSTEM/install/ajax.php @@ -469,13 +469,13 @@ function handleInstallDbInit() { } // Bootstrap schema_versions first (the tracking table for all later migrations). + // Run through installerRunSqlFile so the `#__` prefix substitution kicks in. $schemaFile = $sqlDir . '/schema_versions_migration.sql'; if (file_exists($schemaFile)) { - try { - $pdo->exec(file_get_contents($schemaFile)); - } catch (PDOException $e) { /* probably already exists */ } + installerRunSqlFile($pdo, file_get_contents($schemaFile)); // Best-effort; ignore errors. } + $svTable = '`' . installerT('schema_versions') . '`'; $list = []; foreach (installerMigrationList() as [$file, $version]) { $filePath = $sqlDir . '/' . $file; @@ -484,7 +484,7 @@ function handleInstallDbInit() { if ($exists) { try { - $stmt = $pdo->prepare("SELECT COUNT(*) AS c FROM schema_versions WHERE filename = ?"); + $stmt = $pdo->prepare("SELECT COUNT(*) AS c FROM {$svTable} WHERE filename = ?"); $stmt->execute([$file]); $applied = ((int)$stmt->fetchColumn()) > 0; } catch (PDOException $e) { /* table missing → not applied */ } @@ -532,9 +532,11 @@ function handleInstallDbStep() { return; } + $svTable = '`' . installerT('schema_versions') . '`'; + // Skip if already applied try { - $stmt = $pdo->prepare("SELECT COUNT(*) AS c FROM schema_versions WHERE filename = ?"); + $stmt = $pdo->prepare("SELECT COUNT(*) AS c FROM {$svTable} WHERE filename = ?"); $stmt->execute([$file]); if ((int)$stmt->fetchColumn() > 0) { echo json_encode(['file' => $file, 'success' => true, 'status' => 'skipped', 'message' => 'Already applied']); @@ -548,7 +550,7 @@ function handleInstallDbStep() { if ($result['ok']) { try { $checksum = hash('sha256', $sql); - $stmt = $pdo->prepare("INSERT IGNORE INTO schema_versions (version, filename, checksum) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT IGNORE INTO {$svTable} (version, filename, checksum) VALUES (?, ?, ?)"); $stmt->execute([$version, $file, $checksum]); } catch (PDOException $e) { /* ignore */ } @@ -566,7 +568,7 @@ function handleInstallDbStep() { if (preg_match('/Duplicate|already exists|1060|1061|1050|1062/i', $result['error'])) { try { $checksum = hash('sha256', $sql); - $stmt = $pdo->prepare("INSERT IGNORE INTO schema_versions (version, filename, checksum) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT IGNORE INTO {$svTable} (version, filename, checksum) VALUES (?, ?, ?)"); $stmt->execute([$version, $file, $checksum]); } catch (PDOException $e2) { /* ignore */ } @@ -602,12 +604,13 @@ function handleInstallDbAll() { return; } - // Bootstrap schema_versions + // Bootstrap schema_versions (run through installerRunSqlFile so prefix substitution applies) $schemaFile = $sqlDir . '/schema_versions_migration.sql'; if (file_exists($schemaFile)) { - try { $pdo->exec(file_get_contents($schemaFile)); } catch (PDOException $e) { /* ok */ } + installerRunSqlFile($pdo, file_get_contents($schemaFile)); } + $svTable = '`' . installerT('schema_versions') . '`'; $results = []; foreach (installerMigrationList() as $i => [$file, $version]) { if ($i === 0) { @@ -622,7 +625,7 @@ function handleInstallDbAll() { } try { - $stmt = $pdo->prepare("SELECT COUNT(*) AS c FROM schema_versions WHERE filename = ?"); + $stmt = $pdo->prepare("SELECT COUNT(*) AS c FROM {$svTable} WHERE filename = ?"); $stmt->execute([$file]); if ((int)$stmt->fetchColumn() > 0) { $results[] = ['file' => $file, 'status' => 'skipped', 'message' => 'Already applied']; @@ -636,14 +639,14 @@ function handleInstallDbAll() { if ($r['ok']) { try { $checksum = hash('sha256', $sql); - $stmt = $pdo->prepare("INSERT IGNORE INTO schema_versions (version, filename, checksum) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT IGNORE INTO {$svTable} (version, filename, checksum) VALUES (?, ?, ?)"); $stmt->execute([$version, $file, $checksum]); } catch (PDOException $e) { /* ignore */ } $results[] = ['file' => $file, 'status' => 'ok', 'message' => 'Applied (' . $r['stmts_run'] . ' statements)']; } elseif (preg_match('/Duplicate|already exists|1060|1061|1050|1062/i', $r['error'])) { try { $checksum = hash('sha256', $sql); - $stmt = $pdo->prepare("INSERT IGNORE INTO schema_versions (version, filename, checksum) VALUES (?, ?, ?)"); + $stmt = $pdo->prepare("INSERT IGNORE INTO {$svTable} (version, filename, checksum) VALUES (?, ?, ?)"); $stmt->execute([$version, $file, $checksum]); } catch (PDOException $e) { /* ignore */ } $results[] = ['file' => $file, 'status' => 'ok', 'message' => 'Applied (some objects already existed)']; @@ -675,6 +678,17 @@ function installerRunSqlFile(PDO $pdo, string $sql): array { $sql = preg_replace('/^\s*(START\s+TRANSACTION|BEGIN)\s*;\s*$/im', '', $sql); $sql = preg_replace('/^\s*COMMIT\s*;\s*$/im', '', $sql); + // Substitute table prefix sentinel `#__` with the configured prefix. + // Empty prefix → identical to pre-prefix schema. + $prefix = (string)($_SESSION['install_db']['prefix'] ?? ''); + $sql = str_replace('#__', $prefix, $sql); + + // Defense-in-depth: if substitution somehow missed and `#__` remains, + // abort loudly rather than send invalid SQL. + if (strpos($sql, '#__') !== false) { + return ['ok' => false, 'stmts_run' => 0, 'error' => 'Internal error: unsubstituted `#__` sentinel still present after prefix replacement.']; + } + $stmts = installerSplitSql($sql); $count = 0; foreach ($stmts as $stmt) { @@ -690,6 +704,16 @@ function installerRunSqlFile(PDO $pdo, string $sql): array { return ['ok' => true, 'stmts_run' => $count, 'error' => '']; } +/** + * Resolve the prefixed name for a logical table during installation. + * Mirrors functions/db-helpers.php t() but reads from $_SESSION since + * the installer runs before config.php exists. + */ +function installerT(string $name): string { + $prefix = (string)($_SESSION['install_db']['prefix'] ?? ''); + return $prefix . $name; +} + /** * Split a multi-statement SQL string into individual statements. * Respects backticks, single/double-quoted strings, line comments (-- ...), @@ -815,30 +839,33 @@ function handleCreateAdmin() { return; } + $adminTable = '`' . installerT('admin_users') . '`'; + $aclTable = '`' . installerT('acl_roles') . '`'; + try { // Check if admin already exists - $stmt = $pdo->prepare("SELECT id FROM admin_users WHERE username = ?"); + $stmt = $pdo->prepare("SELECT id FROM {$adminTable} WHERE username = ?"); $stmt->execute([$username]); if ($stmt->fetch()) { // Update existing $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]); - $stmt = $pdo->prepare("UPDATE admin_users SET password_hash = ?, full_name = ?, email = ?, role = 'super_admin', is_active = 1, must_change_password = 0, failed_login_attempts = 0, locked_until = NULL WHERE username = ?"); + $stmt = $pdo->prepare("UPDATE {$adminTable} SET password_hash = ?, full_name = ?, email = ?, role = 'super_admin', is_active = 1, must_change_password = 0, failed_login_attempts = 0, locked_until = NULL WHERE username = ?"); $stmt->execute([$hash, $fullName, $email, $username]); echo json_encode(['success' => true, 'message' => "Admin account '{$username}' updated."]); } else { // Create new $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]); - $stmt = $pdo->prepare("INSERT INTO admin_users (username, full_name, email, password_hash, role, is_active, must_change_password) VALUES (?, ?, ?, ?, 'super_admin', 1, 0)"); + $stmt = $pdo->prepare("INSERT INTO {$adminTable} (username, full_name, email, password_hash, role, is_active, must_change_password) VALUES (?, ?, ?, ?, 'super_admin', 1, 0)"); $stmt->execute([$username, $fullName, $email, $hash]); // Try to assign ACL role if table exists try { $adminId = $pdo->lastInsertId(); - $roleStmt = $pdo->prepare("SELECT id FROM acl_roles WHERE name = 'super_admin' LIMIT 1"); + $roleStmt = $pdo->prepare("SELECT id FROM {$aclTable} WHERE name = 'super_admin' LIMIT 1"); $roleStmt->execute(); $role = $roleStmt->fetch(PDO::FETCH_ASSOC); if ($role) { - $pdo->prepare("UPDATE admin_users SET custom_role_id = ? WHERE id = ?")->execute([$role['id'], $adminId]); + $pdo->prepare("UPDATE {$adminTable} SET custom_role_id = ? WHERE id = ?")->execute([$role['id'], $adminId]); } } catch (PDOException $e) { // ACL tables might not exist — that's fine @@ -873,7 +900,9 @@ function handleFinalize() { } // ── Write config.php ── - $configContent = generateConfig($host, $port, $user, $pass, $name, $timezone); + $prefix = (string)($_SESSION['install_db']['prefix'] ?? ''); + $charset = (string)($_SESSION['install_db']['charset'] ?? 'utf8mb4'); + $configContent = generateConfig($host, $port, $user, $pass, $name, $timezone, $prefix, $charset); $configPath = realpath(__DIR__ . '/..') . '/config.php'; if (file_put_contents($configPath, $configContent) === false) { @@ -888,6 +917,12 @@ function handleFinalize() { try { $pdo = getInstallerPdo(); if ($pdo) { + $tConfig = '`' . installerT('system_config') . '`'; + $tTech = '`' . installerT('technicians') . '`'; + $tAdmin = '`' . installerT('admin_users') . '`'; + $tTrustedN = '`' . installerT('trusted_networks') . '`'; + $tAdminIp = '`' . installerT('admin_ip_whitelist') . '`'; + $settings = [ 'system_name' => $systemName, 'server_url' => $serverUrl, @@ -895,13 +930,13 @@ function handleFinalize() { 'timezone' => $timezone, ]; foreach ($settings as $key => $value) { - $stmt = $pdo->prepare("INSERT INTO system_config (config_key, config_value, description) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)"); + $stmt = $pdo->prepare("INSERT INTO {$tConfig} (config_key, config_value, description) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)"); $stmt->execute([$key, $value, "Set by installer"]); } // Delete demo technician if it exists try { - $pdo->exec("DELETE FROM technicians WHERE technician_id = 'demo' AND notes LIKE '%Demo account%'"); + $pdo->exec("DELETE FROM {$tTech} WHERE technician_id = 'demo' AND notes LIKE '%Demo account%'"); } catch (PDOException $e) { /* ignore */ } // ── Auto-detect installer's network and add as trusted ── @@ -909,7 +944,7 @@ function handleFinalize() { $clientIp = getClientIp(); if ($clientIp && $clientIp !== 'unknown') { // Get admin ID for foreign key - $adminStmt = $pdo->prepare("SELECT id FROM admin_users WHERE username = ? LIMIT 1"); + $adminStmt = $pdo->prepare("SELECT id FROM {$tAdmin} WHERE username = ? LIMIT 1"); $adminStmt->execute([$adminUser]); $adminRow = $adminStmt->fetch(PDO::FETCH_ASSOC); $adminId = $adminRow ? $adminRow['id'] : null; @@ -920,7 +955,7 @@ function handleFinalize() { // Add to trusted_networks (for 2FA bypass + USB auth) try { $stmt = $pdo->prepare(" - INSERT INTO trusted_networks (network_name, ip_range, bypass_2fa, allow_usb_auth, description, created_by_admin_id) + INSERT INTO {$tTrustedN} (network_name, ip_range, bypass_2fa, allow_usb_auth, description, created_by_admin_id) VALUES (?, ?, 1, 1, ?, ?) "); $stmt->execute([ @@ -934,7 +969,7 @@ function handleFinalize() { // Add to admin_ip_whitelist (for admin panel access) try { $stmt = $pdo->prepare(" - INSERT INTO admin_ip_whitelist (ip_address, ip_range, description, created_by) + INSERT INTO {$tAdminIp} (ip_address, ip_range, description, created_by) VALUES (?, ?, ?, ?) "); $stmt->execute([ @@ -1144,9 +1179,20 @@ function calculateSubnet(string $ip, int $prefix = 24): string { /** * Generate the production config.php content */ -function generateConfig(string $host, string $port, string $user, string $pass, string $name, string $timezone): string { +function generateConfig( + string $host, + string $port, + string $user, + string $pass, + string $name, + string $timezone, + string $prefix = '', + string $charset = 'utf8mb4' +): string { // Escape single quotes in password for PHP string - $passEscaped = addcslashes($pass, "'\\"); + $passEscaped = addcslashes($pass, "'\\"); + $prefixEscaped = addcslashes($prefix, "'\\"); + $charsetEsc = preg_replace('/[^a-z0-9_]/', '', $charset) ?: 'utf8mb4'; return <<<'PHP_HEADER' '{$host}',\n" . " 'dbname' => '{$name}',\n" . " 'username' => '{$user}',\n" . " 'password' => '{$passEscaped}',\n" - . " 'charset' => 'utf8mb4',\n" + . " 'charset' => '{$charsetEsc}',\n" . " 'port' => {$port},\n" . "];\n\n" . <<<'PHP_BODY' @@ -1355,6 +1402,13 @@ function installerCheckIncompleteState(): void { $host = $hM[1]; $name = $nM[1]; $user = $uM[1]; $pass = $pM[1]; $port = (int)$portM[1]; if (strtolower($host) === 'localhost') $host = '127.0.0.1'; + // Read DB_PREFIX from config (empty for legacy installs). + $prefix = ''; + if (preg_match("/define\(\s*'DB_PREFIX'\s*,\s*'([^']*)'\s*\)/", $configSrc, $pxM)) { + $prefix = $pxM[1]; + } + $adminTable = $prefix . 'admin_users'; + try { $dsn = "mysql:host={$host};port={$port};dbname={$name};charset=utf8mb4"; $pdo = new PDO($dsn, $user, $pass, [ @@ -1363,15 +1417,15 @@ function installerCheckIncompleteState(): void { ]); // admin_users table missing → install was never completed. - $stmt = $pdo->query("SHOW TABLES LIKE 'admin_users'"); + $stmt = $pdo->query("SHOW TABLES LIKE " . $pdo->quote($adminTable)); if (!$stmt->fetch()) { - installerLog("auto-unlock: admin_users table missing — clearing install.lock"); + installerLog("auto-unlock: {$adminTable} missing — clearing install.lock"); @unlink($lockPath); return; } // admin_users empty → install was never completed. - $cnt = (int)$pdo->query("SELECT COUNT(*) FROM admin_users")->fetchColumn(); + $cnt = (int)$pdo->query("SELECT COUNT(*) FROM `{$adminTable}`")->fetchColumn(); if ($cnt === 0) { installerLog("auto-unlock: admin_users empty — clearing install.lock"); @unlink($lockPath); @@ -1447,17 +1501,19 @@ function handleHealth(): void { $expectTables = ['admin_users', 'oem_keys', 'technicians', 'system_config', 'schema_versions']; foreach ($expectTables as $t) { + $physical = installerT($t); try { - $stmt = $pdo->query("SHOW TABLES LIKE '" . str_replace("'", '', $t) . "'"); + $stmt = $pdo->query("SHOW TABLES LIKE " . $pdo->quote($physical)); $found = (bool)$stmt->fetch(); - $checks[] = ['label' => "Table {$t}", 'status' => $found ? 'pass' : 'fail']; + $checks[] = ['label' => "Table {$physical}", 'status' => $found ? 'pass' : 'fail']; } catch (PDOException $e) { - $checks[] = ['label' => "Table {$t}", 'status' => 'fail']; + $checks[] = ['label' => "Table {$physical}", 'status' => 'fail']; } } try { - $admins = (int)$pdo->query("SELECT COUNT(*) FROM admin_users")->fetchColumn(); + $adminTable = '`' . installerT('admin_users') . '`'; + $admins = (int)$pdo->query("SELECT COUNT(*) FROM {$adminTable}")->fetchColumn(); $checks[] = ['label' => 'Admin accounts', 'status' => $admins > 0 ? 'pass' : 'fail', 'value' => $admins]; } catch (PDOException $e) { $checks[] = ['label' => 'Admin accounts', 'status' => 'fail']; diff --git a/FINAL_PRODUCTION_SYSTEM/install/index.php b/FINAL_PRODUCTION_SYSTEM/install/index.php index f55d2e1..d7b7169 100644 --- a/FINAL_PRODUCTION_SYSTEM/install/index.php +++ b/FINAL_PRODUCTION_SYSTEM/install/index.php @@ -26,14 +26,20 @@ && preg_match("/'password'\s*=>\s*'([^']*)'/", $configSrc, $pM) && preg_match("/'port'\s*=>\s*(\d+)/", $configSrc, $portM)) { $autoHost = strtolower($hM[1]) === 'localhost' ? '127.0.0.1' : $hM[1]; + // Read DB_PREFIX from config (empty for legacy installs). + $autoPrefix = ''; + if (preg_match("/define\(\s*'DB_PREFIX'\s*,\s*'([^']*)'\s*\)/", $configSrc, $pxM)) { + $autoPrefix = $pxM[1]; + } + $autoAdminTable = $autoPrefix . 'admin_users'; try { $autoPdo = new PDO( "mysql:host={$autoHost};port={$portM[1]};dbname={$nM[1]};charset=utf8mb4", $uM[1], $pM[1], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 5] ); - $hasAdminTable = (bool) $autoPdo->query("SHOW TABLES LIKE 'admin_users'")->fetch(); - $adminCount = $hasAdminTable ? (int) $autoPdo->query("SELECT COUNT(*) FROM admin_users")->fetchColumn() : 0; + $hasAdminTable = (bool) $autoPdo->query("SHOW TABLES LIKE " . $autoPdo->quote($autoAdminTable))->fetch(); + $adminCount = $hasAdminTable ? (int) $autoPdo->query("SELECT COUNT(*) FROM `{$autoAdminTable}`")->fetchColumn() : 0; if (!$hasAdminTable || $adminCount === 0) { @unlink($lockFile); @file_put_contents( diff --git a/FINAL_PRODUCTION_SYSTEM/secure-admin.php b/FINAL_PRODUCTION_SYSTEM/secure-admin.php index f043af9..a91e547 100644 --- a/FINAL_PRODUCTION_SYSTEM/secure-admin.php +++ b/FINAL_PRODUCTION_SYSTEM/secure-admin.php @@ -39,7 +39,7 @@ function checkIPWhitelist() { // Get all active whitelist entries $stmt = $pdo->prepare(" - SELECT ip_address, ip_range FROM admin_ip_whitelist + SELECT ip_address, ip_range FROM `" . t('admin_ip_whitelist') . "` WHERE is_active = 1 "); $stmt->execute(); @@ -77,7 +77,7 @@ function checkIPWhitelist() { // Handle logout if (isset($_GET['logout'])) { if (isset($_SESSION['admin_token'])) { - $stmt = $pdo->prepare("UPDATE admin_sessions SET is_active = 0 WHERE session_token = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('admin_sessions') . "` SET is_active = 0 WHERE session_token = ?"); $stmt->execute([$_SESSION['admin_token']]); logAdminActivity($_SESSION['admin_id'], $_SESSION['session_id'], 'LOGOUT', 'User logout'); } diff --git a/FINAL_PRODUCTION_SYSTEM/setup/index.php b/FINAL_PRODUCTION_SYSTEM/setup/index.php index 6dcc95e..9d0e839 100644 --- a/FINAL_PRODUCTION_SYSTEM/setup/index.php +++ b/FINAL_PRODUCTION_SYSTEM/setup/index.php @@ -500,7 +500,7 @@ function setupAdminAccount() { $db['username'], $db['password']); $stmt = $pdo->prepare(" - INSERT INTO admin_users (username, full_name, email, password_hash, role, must_change_password) + INSERT INTO `" . t('admin_users') . "` (username, full_name, email, password_hash, role, must_change_password) VALUES (?, ?, ?, ?, 'super_admin', 0) "); $stmt->execute([$admin['username'], $admin['full_name'], $admin['email'], $admin['password']]); @@ -524,7 +524,7 @@ function applySystemConfiguration() { ['admin_ip_whitelist_enabled', $config['enable_ip_whitelist'] ? '1' : '0'], ]; - $stmt = $pdo->prepare("UPDATE system_config SET config_value = ? WHERE config_key = ?"); + $stmt = $pdo->prepare("UPDATE `" . t('system_config') . "` SET config_value = ? WHERE config_key = ?"); foreach ($configs as $cfg) { $stmt->execute([$cfg[1], $cfg[0]]); } diff --git a/tools/prefix-codemod.php b/tools/prefix-codemod.php new file mode 100644 index 0000000..06a932d --- /dev/null +++ b/tools/prefix-codemod.php @@ -0,0 +1,398 @@ + overrides default detection. Useful inside Docker where +// FINAL_PRODUCTION_SYSTEM lives at /var/www/html/activate, not next to tools/. +$customRoot = ''; +foreach ($argv as $i => $arg) { + if ($arg === '--root' && isset($argv[$i + 1])) { + $customRoot = $argv[$i + 1]; + break; + } + if (str_starts_with($arg, '--root=')) { + $customRoot = substr($arg, 7); + break; + } +} + +if ($customRoot !== '') { + $appRoot = realpath($customRoot); +} else { + $root = realpath(__DIR__ . '/..'); + $appRoot = $root . DIRECTORY_SEPARATOR . 'FINAL_PRODUCTION_SYSTEM'; +} +if (!is_dir($appRoot)) { + fwrite(STDERR, "FINAL_PRODUCTION_SYSTEM not found at {$appRoot}\n"); + exit(1); +} + +$dbDir = $appRoot . DIRECTORY_SEPARATOR . 'database'; + +// ── 1. Discover canonical table list ────────────────────────────── +$tables = discoverTables($dbDir); +sort($tables); +if (!$quiet) { + fwrite(STDOUT, "Discovered " . count($tables) . " tables.\n"); +} + +// Sort by length descending so longer names match before substring siblings +// (e.g. `admin_users` before `admin`). +usort($tables, fn($a, $b) => strlen($b) - strlen($a)); + +// Build deny list — never rewrite these even if they appear in SQL contexts. +// They are SQL keywords / column names that happen to look like table names. +$denyAlias = [ + 'config_value', // column in system_config + 'value', // generic column name + 'key', // SQL keyword + common column + 'name', // common column + 'role', // common column +]; +$tables = array_values(array_diff($tables, $denyAlias)); + +if (count($tables) < 5) { + fwrite(STDERR, "Refusing to run: only " . count($tables) . " tables discovered. Something is wrong.\n"); + exit(2); +} + +// ── 2. SQL pass ─────────────────────────────────────────────────── +$sqlFiles = glob($dbDir . '/*.sql'); +$sqlChanges = 0; +$sqlFilesChanged = []; + +foreach ($sqlFiles as $f) { + $orig = file_get_contents($f); + $new = rewriteSqlBody($orig, $tables); + if ($new !== $orig) { + $sqlChanges += substr_count($new, '#__') - substr_count($orig, '#__'); + $sqlFilesChanged[] = basename($f); + if ($apply) { + file_put_contents($f, $new); + } + } +} + +if (!$quiet) { + fwrite(STDOUT, "SQL: " . count($sqlFilesChanged) . " files changed, +{$sqlChanges} `#__` markers.\n"); +} + +// ── 3. PHP pass ─────────────────────────────────────────────────── +$phpFiles = collectPhpFiles($appRoot); +$phpChanges = 0; +$phpFilesChanged = []; + +foreach ($phpFiles as $f) { + $orig = file_get_contents($f); + $new = rewritePhpBody($orig, $tables); + if ($new !== $orig) { + $phpFilesChanged[] = str_replace($appRoot . DIRECTORY_SEPARATOR, '', $f); + $diffLines = countDiff($orig, $new); + $phpChanges += $diffLines; + if ($apply) { + file_put_contents($f, $new); + } + } +} + +if (!$quiet) { + fwrite(STDOUT, "PHP: " . count($phpFilesChanged) . " files changed, ~{$phpChanges} site rewrites.\n"); +} + +// ── 4. Verify pass (when --verify) ──────────────────────────────── +if ($verify) { + $stillBad = []; + foreach ($sqlFiles as $f) { + $body = file_get_contents($f); + foreach ($tables as $t) { + // Look for un-prefixed backticked refs. + // Pattern: `tablename` not preceded by `#__ + if (preg_match('/(?isFile()) continue; + if (substr($f->getFilename(), -4) !== '.php') continue; + $path = str_replace('\\', '/', $f->getPathname()); + foreach ($skip as $s) { + if (strpos($path, $s) !== false) continue 2; + } + $files[] = $f->getPathname(); + } + return $files; +} + +/** + * Rewrite SQL body: `tablename` → `#__tablename` for every canonical table. + * Idempotent: skips already-prefixed. + */ +function rewriteSqlBody(string $body, array $tables): string { + $kw = '(?:CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?|DROP\s+TABLE(?:\s+IF\s+EXISTS)?|ALTER\s+TABLE|INSERT\s+INTO|REPLACE\s+INTO|SELECT\s+(?:[^;]*?)FROM|UPDATE|DELETE\s+FROM|FROM|JOIN|REFERENCES|TRUNCATE(?:\s+TABLE)?|RENAME\s+TABLE|LOCK\s+TABLES|DESCRIBE|EXPLAIN)'; + + foreach ($tables as $t) { + // ── Pattern A: backticked refs ──────────────────────────── + // (?
' . __('keys.status') . '' . __('common.count') . '