41 lines
2.8 KiB
PHP
41 lines
2.8 KiB
PHP
<?php
|
|
require __DIR__.'/includes/candidate.php'; $p=candidate();
|
|
if($_SERVER['REQUEST_METHOD']!=='POST') cgo('home.php');
|
|
cverify();
|
|
$action=$_POST['action']??'submit'; $json=$action!=='submit';
|
|
function exam_reply($data,$status=200) { http_response_code($status); header('Content-Type: application/json'); echo json_encode($data); exit; }
|
|
$phase=(int)($_POST['phase']??0);
|
|
if(!isset(CPHASES[$phase])) { if($json) exam_reply(['error'=>'Fase tidak valid.'],400); cgo('home.php'); }
|
|
cdb()->begin_transaction();
|
|
try {
|
|
$current=cq('SELECT level FROM in_daper WHERE id=? FOR UPDATE','i',[(int)$p['id']])->get_result()->fetch_assoc();
|
|
$attempt=exam_find((int)$p['id'],$phase);
|
|
if(!$attempt || $attempt['status']!=='active' || (int)$current['level']!==$phase-1) {
|
|
cdb()->rollback(); if($json) exam_reply(['closed'=>true,'redirect'=>'home.php'],409); cgo('home.php');
|
|
}
|
|
if(!hash_equals($attempt['active_token'],(string)($_POST['attempt_token']??''))) {
|
|
exam_event($attempt,'stale_tab'); cdb()->commit();
|
|
if($json) exam_reply(['stale'=>true,'error'=>'Halaman ini sudah digantikan tab atau sesi lain. Muat ulang untuk melanjutkan.'],409);
|
|
$_SESSION['error']='Halaman tes sudah digantikan tab atau sesi lain. Buka kembali fase aktif.'; cgo('home.php');
|
|
}
|
|
if(time()>=(int)$attempt['deadline']) {
|
|
exam_finalize($attempt,json_decode($attempt['answers_json'],true),true); cdb()->commit();
|
|
$_SESSION['success']='Waktu fase '.$phase.' habis. Hanya draft yang diterima sebelum deadline yang disimpan.';
|
|
if($json) exam_reply(['closed'=>true,'redirect'=>'home.php']); cgo('home.php');
|
|
}
|
|
if($action==='event') { exam_event($attempt,(string)($_POST['event']??'')); cdb()->commit(); exam_reply(['ok'=>true,'remaining'=>max(0,(int)$attempt['deadline']-time())]); }
|
|
if(!in_array($action,['save','submit'],true)) throw new InvalidArgumentException('Aksi tidak valid.');
|
|
$answers=exam_answers($attempt,$_POST['answers']??[]);
|
|
if($action==='save') {
|
|
cq('UPDATE rec_exam_attempt SET answers_json=? WHERE id=?','si',[json_encode($answers,JSON_UNESCAPED_UNICODE),(int)$attempt['id']]); cdb()->commit();
|
|
exam_reply(['ok'=>true,'remaining'=>max(0,(int)$attempt['deadline']-time())]);
|
|
}
|
|
exam_finalize($attempt,$answers); cdb()->commit(); $_SESSION['level']=$phase;
|
|
$_SESSION['success']=$phase===4?'Seluruh fase berhasil dikirim. Terima kasih telah mengikuti psikotest Nurinda.':'Jawaban fase '.$phase.' tersimpan. Silakan lanjutkan ke fase berikutnya.';
|
|
} catch(InvalidArgumentException $error) {
|
|
cdb()->rollback(); if($json) exam_reply(['error'=>$error->getMessage()],422); $_SESSION['error']=$error->getMessage();
|
|
} catch(Throwable $error) {
|
|
cdb()->rollback(); error_log($error->getMessage()); if($json) exam_reply(['error'=>'Sinkronisasi gagal. Coba kembali.'],503); $_SESSION['error']='Jawaban belum tersimpan. Buka kembali fase aktif untuk melanjutkan.';
|
|
}
|
|
cgo('home.php');
|