false, 'error'=>'Method not allowed']); exit; } if (!isset($_POST['run'])) { http_response_code(400); echo json_encode(['ok'=>false, 'error'=>'Missing run']); exit; } // Eingabe parsen $run = json_decode($_POST['run'], true, 512, JSON_THROW_ON_ERROR); // Optional: PDF speichern $savedPdf = null; if (isset($_FILES['pdf']) && $_FILES['pdf']['error'] === UPLOAD_ERR_OK) { $ext = '.pdf'; $fname = sprintf( 'QA-%s-%s-%s-%s%s', preg_replace('~[^a-zA-Z0-9_-]+~','_', $run['module'] ?? 'mod'), preg_replace('~[^a-zA-Z0-9_-]+~','_', $run['module_version'] ?? 'v'), preg_replace('~[^a-zA-Z0-9_-]+~','_', $run['pbx_version'] ?? 'pbx'), date('Ymd_His'), $ext ); $destDir = rtrim($pdf_storage_dir ?? (__DIR__ . '/../storage/reports'), '/'); if (!is_dir($destDir)) { @mkdir($destDir, 0775, true); } $dest = $destDir . '/' . $fname; if (!@move_uploaded_file($_FILES['pdf']['tmp_name'], $dest)) { $savedPdf = null; // PDF optional; DB-Export läuft trotzdem weiter } $savedPdf = $dest; } // DB verbinden $dsn = "mysql:host={$db_host};port={$db_port};dbname={$db_name};charset=utf8mb4"; $pdo = new PDO($dsn, $db_user, $db_pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]); // Schema sicherstellen (idempotent) $pdo->exec(" CREATE TABLE IF NOT EXISTS reports ( id BIGINT AUTO_INCREMENT PRIMARY KEY, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, module VARCHAR(255), module_version VARCHAR(100), pbx_version VARCHAR(100), olm_nummer VARCHAR(100), tester VARCHAR(255), docbee_url TEXT, summary VARCHAR(255), pdf_path TEXT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS steps ( id BIGINT AUTO_INCREMENT PRIMARY KEY, report_id BIGINT NOT NULL, step_index INT, step_id VARCHAR(50), title TEXT, expected TEXT, status ENUM('pass','fail','skip','na','') DEFAULT '', comment TEXT, evidence TEXT, group_title VARCHAR(255), group_index INT, CONSTRAINT fk_steps_report FOREIGN KEY (report_id) REFERENCES reports(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "); // Summary berechnen $total=0;$pass=0;$fail=0;$skip=0; foreach (($run['steps'] ?? []) as $s) { if (($s['kind'] ?? 'step') === 'step') { $total++; $st = $s['status'] ?? ''; if ($st==='pass') $pass++; elseif ($st==='fail') $fail++; elseif ($st==='skip') $skip++; } } $summary = sprintf('%d/%d pass, %d fail, %d skip', $pass, $total, $fail, $skip); // Report speichern $stmt = $pdo->prepare("INSERT INTO reports (module, module_version, pbx_version, olm_nummer, tester, docbee_url, summary, pdf_path) VALUES (:module, :module_version, :pbx_version, :olm_nummer, :tester, :docbee_url, :summary, :pdf_path)"); $stmt->execute([ ':module' => $run['module'] ?? null, ':module_version' => $run['module_version'] ?? null, ':pbx_version' => $run['pbx_version'] ?? null, ':olm_nummer' => $run['olm_nummer'] ?? null, ':tester' => $run['tester'] ?? null, ':docbee_url' => $run['docbee_url'] ?? null, ':summary' => $summary, ':pdf_path' => $savedPdf ]); $reportId = (int)$pdo->lastInsertId(); // Steps speichern $idx = 0; $gidx = -1; $currentGroup = null; $ins = $pdo->prepare("INSERT INTO steps (report_id, step_index, step_id, title, expected, status, comment, evidence, group_title, group_index) VALUES (:report_id,:step_index,:step_id,:title,:expected,:status,:comment,:evidence,:group_title,:group_index)"); foreach (($run['steps'] ?? []) as $s) { if (($s['kind'] ?? 'step') === 'group') { $currentGroup = $s['title'] ?? null; $gidx++; continue; } $idx++; // status normalisieren → ENUM-kompatibel $rawStatus = strtolower(trim((string)($s['status'] ?? ''))); $map = [ 'ok'=>'pass','passed'=>'pass','success'=>'pass','true'=>'pass','yes'=>'pass','✔'=>'pass','✓'=>'pass', 'ko'=>'fail','failed'=>'fail','error'=>'fail','✗'=>'fail','x'=>'fail', 'skipped'=>'skip', 'n/a'=>'na','not applicable'=>'na', 'block'=>'blocked','blocked'=>'blocked','⛔'=>'blocked' ]; $st = $map[$rawStatus] ?? (in_array($rawStatus, ['pass','fail','skip','na','blocked',''], true) ? $rawStatus : ''); // und beim Insert: // ':status' => $st, $st = $map[$rawStatus] ?? (in_array($rawStatus, ['pass','fail','skip','na',''], true) ? $rawStatus : ''); try { $ins->execute([ ':report_id' => $reportId, ':step_index' => $idx, ':step_id' => $s['id'] ?? null, ':title' => $s['title'] ?? null, ':expected' => $s['expected'] ?? null, ':status' => $st, ':comment' => $s['comment'] ?? null, ':evidence' => $s['evidence'] ?? null, ':group_title' => $currentGroup, ':group_index' => $gidx >= 0 ? $gidx : null, ]); } catch (PDOException $e) { if ($e->getCode() !== '01000') { throw $e; } // ENUM-Truncation-Warning ignorieren } } echo json_encode(['ok'=>true, 'report_id'=>$reportId, 'pdf_path'=>$savedPdf, 'summary'=>$summary]); } catch (Throwable $e) { http_response_code(500); echo json_encode(['ok'=>false, 'error'=>$e->getMessage()]); }