further enhanced error handling + added retries in case of parallel writes

This commit is contained in:
2026-06-03 17:27:51 +02:00
parent d0daa7e937
commit fc84d55bd6
21 changed files with 184 additions and 383 deletions

View File

@ -26,15 +26,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_error('BAD_REQUEST', 'Unknown query', 400);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('analytics GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Analytics'), 500);
qdb_handler_fail($e, 'Analytics', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -50,15 +42,7 @@ case 'PUT':
qdb_save($tmpDb, $lockFp);
json_success(['clientCode' => $clientCode, 'note' => $note]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('analytics PUT: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Save note'), 500);
qdb_handler_fail($e, 'Save follow-up note', null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -29,15 +29,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['answerOptions' => $options]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('answer_options GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load answer options'), 500);
qdb_handler_fail($e, 'Load answer options', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -56,7 +48,7 @@ case 'POST':
$order = (int)($body['orderIndex'] ?? 0);
$nextQ = trim($body['nextQuestionId'] ?? '');
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$chk = $pdo->prepare('SELECT 1 FROM question WHERE questionID = :id');
$chk->execute([':id' => $qID]);
@ -86,9 +78,7 @@ case 'POST':
'translations' => [],
]]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Answer options', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -100,7 +90,7 @@ case 'PUT':
}
$id = $body['answerOptionID'];
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$existing = $pdo->prepare('SELECT * FROM answer_option WHERE answerOptionID = :id');
$existing->execute([':id' => $id]);
@ -140,9 +130,7 @@ case 'PUT':
'nextQuestionId' => $nextQ,
]]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Answer options', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -154,7 +142,7 @@ case 'DELETE':
}
$id = $body['answerOptionID'];
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$pdo->exec('PRAGMA foreign_keys = OFF;');
$pdo->beginTransaction();
@ -166,12 +154,7 @@ case 'DELETE':
qdb_save($tmpDb, $lockFp);
json_success(['deleted' => true]);
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Delete answer option', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -181,7 +164,7 @@ case 'PATCH':
if (empty($body['questionID']) || !is_array($body['order'] ?? null)) {
json_error('MISSING_FIELDS', 'questionID and order[] required', 400);
}
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$stmt = $pdo->prepare('UPDATE answer_option SET orderIndex = :o WHERE answerOptionID = :id AND questionID = :qid');
foreach ($body['order'] as $idx => $aoid) {
@ -190,9 +173,7 @@ case 'PATCH':
qdb_save($tmpDb, $lockFp);
json_success(['reordered' => true]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Answer options', null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -254,18 +254,7 @@ if ($method === 'POST') {
json_success(['submitted' => true, 'sumPoints' => $sumPoints]);
} catch (Throwable $e) {
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('app_questionnaires POST: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Submit'), 500);
qdb_handler_fail($e, 'Submit questionnaire', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
}

View File

@ -9,7 +9,7 @@ switch ($method) {
case 'GET':
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
[$pdo, $tmpDb, $lockFp] = qdb_open_read_or_fail();
if ($callerRole === 'admin') {
$coaches = $pdo->query(
@ -44,9 +44,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['coaches' => $coaches, 'clients' => $clients]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'assignments', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -61,7 +59,7 @@ case 'POST':
if (!is_array($clientCodes)) $clientCodes = [$clientCodes];
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
if ($callerRole === 'supervisor') {
$chk = $pdo->prepare("SELECT coachID FROM coach WHERE coachID = :cid AND supervisorID = :sid");
@ -92,10 +90,7 @@ case 'POST':
json_success(['assigned' => $count]);
} catch (Throwable $e) {
if (isset($pdo) && $pdo->inTransaction()) $pdo->rollBack();
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'assignments', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -16,7 +16,7 @@ case 'auth/login':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
[$pdo, $tmpDb, $lockFp] = qdb_open_read_or_fail();
$stmt = $pdo->prepare(
"SELECT userID, passwordHash, role, entityID, mustChangePassword
FROM users WHERE username = :u"
@ -80,9 +80,7 @@ case 'auth/login':
}
json_success($loginData);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'auth', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -117,7 +115,7 @@ case 'auth/change-password':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
$stmt = $pdo->prepare(
"SELECT userID, passwordHash, role, entityID FROM users WHERE username = :u"
@ -165,9 +163,7 @@ case 'auth/change-password':
'role' => $user['role'],
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'auth', null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -9,7 +9,7 @@ switch ($method) {
case 'GET':
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
[$pdo, $tmpDb, $lockFp] = qdb_open_read_or_fail();
$clientCode = trim((string)($_GET['clientCode'] ?? ''));
if ($clientCode !== '' && !empty($_GET['detail'])) {
@ -39,9 +39,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['clients' => $clients]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'clients', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -55,7 +53,7 @@ case 'POST':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
// Validate coach exists and caller is allowed to assign to them
if ($callerRole === 'supervisor') {
@ -83,9 +81,7 @@ case 'POST':
qdb_save($tmpDb, $lockFp);
json_success(['clientCode' => $clientCode, 'coachID' => $coachID]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'clients', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -98,7 +94,7 @@ case 'DELETE':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
// Verify the client exists and the caller can see it (RBAC)
[$clause, $params] = rbac_client_filter($tokenRec, 'cl');
@ -122,10 +118,7 @@ case 'DELETE':
qdb_save($tmpDb, $lockFp);
json_success([]);
} catch (Throwable $e) {
if (isset($pdo) && $pdo->inTransaction()) $pdo->rollBack();
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'clients', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -25,13 +25,5 @@ try {
qdb_discard($tmpDb, $lockFp);
json_success(['coaches' => $coaches]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('coaches GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load coaches'), 500);
qdb_handler_fail($e, 'Load coaches', null, $tmpDb ?? null, $lockFp ?? null);
}

View File

@ -16,7 +16,7 @@ $body = read_json_body();
$action = trim((string)($body['action'] ?? 'import'));
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
if ($action === 'remove') {
$result = qdb_remove_dev_test_data($pdo, [
@ -43,20 +43,11 @@ try {
qdb_save($tmpDb, $lockFp);
json_success($result);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
$labels = [
'remove' => 'Remove',
'wipeExceptAdmins' => 'Wipe',
'import' => 'Import',
'remove' => 'Remove dev data',
'wipeExceptAdmins' => 'Wipe database',
'import' => 'Import dev fixture',
];
$label = $labels[$action ?? 'import'] ?? 'Operation';
error_log("dev fixture $label: " . $e->getMessage());
require_once __DIR__ . '/../lib/errors.php';
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
error_log("dev fixture $label: " . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, $label), 500);
$label = $labels[$action ?? 'import'] ?? 'Dev fixture';
qdb_handler_fail($e, $label, $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}

View File

@ -22,15 +22,7 @@ if (!empty($_GET['bundle'])) {
echo json_encode($bundle, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
exit;
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('export bundle: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Export'), 500);
qdb_handler_fail($e, 'Export questionnaires bundle', null, $tmpDb ?? null, $lockFp ?? null);
}
}
@ -53,15 +45,7 @@ if (!empty($_GET['exportAll'])) {
@unlink($zipPath);
exit;
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('export exportAll: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Export'), 500);
qdb_handler_fail($e, 'Export responses ZIP', null, $tmpDb ?? null, $lockFp ?? null);
}
}
@ -112,13 +96,5 @@ $filename = $safeName . '_v' . $questionnaire['version'] . '.csv';
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo qdb_export_rows_to_csv_string($rows, qdb_export_current_csv_fallback_header($resultColumns));
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('export csv: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Export'), 500);
qdb_handler_fail($e, 'Export CSV', null, $tmpDb ?? null, $lockFp ?? null);
}

View File

@ -12,12 +12,7 @@ if (!$token) {
try {
token_revoke($token);
} catch (Throwable $e) {
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('logout: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Logout'), 500);
qdb_handler_fail($e, 'Logout');
}
json_success(['loggedOut' => true]);

View File

@ -40,15 +40,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['questionnaires' => $rows, 'categoryKeys' => $categoryKeys]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('questionnaires GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load questionnaires'), 500);
qdb_handler_fail($e, 'Load questionnaires', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -59,7 +51,7 @@ case 'POST':
if (($body['action'] ?? '') === 'updateConditionMessageLabel') {
$messageKey = trim((string)($body['messageKey'] ?? ''));
$germanLabel = (string)($body['germanLabel'] ?? '');
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
qdb_set_app_string_german_label($pdo, $messageKey, $germanLabel);
qdb_save($tmpDb, $lockFp);
@ -68,9 +60,7 @@ case 'POST':
'germanLabel' => trim($germanLabel),
]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log('updateConditionMessageLabel: ' . $e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Update condition message label', null, $tmpDb, $lockFp);
}
break;
}
@ -78,7 +68,7 @@ case 'POST':
if (($body['action'] ?? '') === 'updateCategoryLabel') {
$categoryKey = trim((string)($body['categoryKey'] ?? ''));
$germanLabel = (string)($body['germanLabel'] ?? '');
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$stringKey = qdb_set_category_german_label($pdo, $categoryKey, $germanLabel);
qdb_save($tmpDb, $lockFp);
@ -88,9 +78,7 @@ case 'POST':
'germanLabel' => trim($germanLabel),
]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log('updateCategoryLabel: ' . $e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Update category label', null, $tmpDb, $lockFp);
}
break;
}
@ -100,15 +88,13 @@ case 'POST':
if ($categoryKey === '') {
json_error('INVALID_FIELD', 'categoryKey is required', 400);
}
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$cleared = qdb_delete_category_key($pdo, $categoryKey);
qdb_save($tmpDb, $lockFp);
json_success(['deleted' => $categoryKey, 'questionnairesCleared' => $cleared]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log('deleteCategoryKey: ' . $e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Delete category key', null, $tmpDb, $lockFp);
}
break;
}
@ -119,7 +105,7 @@ case 'POST':
json_error('MISSING_FIELDS', 'bundle object is required', 400);
}
$replaceIfExists = !empty($body['replaceIfExists']);
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$pdo->exec('PRAGMA foreign_keys = OFF;');
$result = qdb_import_questionnaires_bundle($pdo, $bundle, $replaceIfExists);
@ -127,14 +113,7 @@ case 'POST':
qdb_save($tmpDb, $lockFp);
json_success($result);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log('importBundle: ' . $e->getMessage());
require_once __DIR__ . '/../lib/errors.php';
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
error_log('importBundle: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Import'), 500);
qdb_handler_fail($e, 'Import questionnaires', null, $tmpDb, $lockFp);
}
break;
}
@ -150,7 +129,7 @@ case 'POST':
$showPts = (int)($body['showPoints'] ?? 0);
$condJson = $body['conditionJson'] ?? '{}';
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
if ($order === 0) {
$order = (int)$pdo->query("SELECT COALESCE(MAX(orderIndex),0)+1 FROM questionnaire")->fetchColumn();
@ -170,9 +149,7 @@ case 'POST':
'conditionJson' => $condJson, 'questionCount' => 0,
]]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Create questionnaire', null, $tmpDb, $lockFp);
}
break;
@ -184,7 +161,7 @@ case 'PUT':
}
$id = $body['questionnaireID'];
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$existing = $pdo->prepare('SELECT * FROM questionnaire WHERE questionnaireID = :id');
$existing->execute([':id' => $id]);
@ -217,9 +194,7 @@ case 'PUT':
'orderIndex' => $order, 'showPoints' => $showPts, 'conditionJson' => $condJson,
]]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Update questionnaire', null, $tmpDb, $lockFp);
}
break;
@ -231,7 +206,7 @@ case 'DELETE':
}
$id = $body['questionnaireID'];
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$pdo->exec('PRAGMA foreign_keys = OFF;');
$pdo->beginTransaction();
@ -260,12 +235,7 @@ case 'DELETE':
qdb_save($tmpDb, $lockFp);
json_success([]);
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Delete questionnaire', $pdo, $tmpDb, $lockFp);
}
break;

View File

@ -46,15 +46,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['questions' => $questions]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('questions GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load questions'), 500);
qdb_handler_fail($e, 'Load questions', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -79,7 +71,7 @@ case 'POST':
$body['noteAfter'] ?? ($cfg['noteAfter'] ?? null)
);
$configJson = json_encode($config, JSON_UNESCAPED_UNICODE);
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$chk = $pdo->prepare("SELECT 1 FROM questionnaire WHERE questionnaireID = :id");
$chk->execute([':id' => $qnID]);
@ -117,9 +109,7 @@ case 'POST':
'configJson' => $configJson, 'answerOptions' => [], 'translations' => [],
]]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Questions', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -130,7 +120,7 @@ case 'PUT':
json_error('BAD_REQUEST', 'questionID is required', 400);
}
$id = $body['questionID'];
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$existing = $pdo->prepare("SELECT * FROM question WHERE questionID = :id");
$existing->execute([':id' => $id]);
@ -171,9 +161,7 @@ case 'PUT':
'configJson' => $configJson,
]]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Questions', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -184,7 +172,7 @@ case 'DELETE':
json_error('BAD_REQUEST', 'questionID is required', 400);
}
$id = $body['questionID'];
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$pdo->exec("PRAGMA foreign_keys = OFF;");
$pdo->beginTransaction();
@ -202,12 +190,7 @@ case 'DELETE':
qdb_save($tmpDb, $lockFp);
json_success(['deleted' => true]);
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Delete question', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -259,15 +242,7 @@ case 'PATCH':
qdb_save($tmpDb, $lockFp);
json_success(['reordered' => true]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('questions PATCH: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Reorder questions'), 500);
qdb_handler_fail($e, 'Reorder questions', null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -120,13 +120,5 @@ if (!empty($questionIDs) && !empty($clients)) {
'clients' => $clients,
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('results GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load results'), 500);
qdb_handler_fail($e, 'Load results', null, $tmpDb ?? null, $lockFp ?? null);
}

View File

@ -34,15 +34,7 @@ if (($rec['userID'] ?? '') !== '') {
$username = $row !== false ? (string)$row : '';
qdb_discard($tmpDb, $lockFp);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('session username lookup: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Session check'), 500);
qdb_handler_fail($e, 'Session check', null, $tmpDb ?? null, $lockFp ?? null);
}
}

View File

@ -15,15 +15,7 @@ case 'GET':
$bundle = qdb_export_translations_bundle($pdo);
qdb_discard($tmpDb, $lockFp);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations exportBundle: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Export'), 500);
qdb_handler_fail($e, 'Export translations', null, $tmpDb ?? null, $lockFp ?? null);
}
$filename = 'translations_bundle_' . date('Y-m-d_His') . '.json';
@ -41,15 +33,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['languages' => $rows]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations languages: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load languages'), 500);
qdb_handler_fail($e, 'Load languages', null, $tmpDb ?? null, $lockFp ?? null);
}
}
@ -102,15 +86,7 @@ case 'GET':
'sourceLanguage' => QDB_SOURCE_LANGUAGE,
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations all: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load translations'), 500);
qdb_handler_fail($e, 'Load translations', null, $tmpDb ?? null, $lockFp ?? null);
}
}
@ -146,15 +122,7 @@ case 'GET':
'sourceLanguage' => QDB_SOURCE_LANGUAGE,
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations questionnaire: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load translations'), 500);
qdb_handler_fail($e, 'Load translations', null, $tmpDb ?? null, $lockFp ?? null);
}
}
@ -192,15 +160,7 @@ case 'GET':
qdb_discard($tmpDb, $lockFp);
json_success(['translations' => $rows]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations GET: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Load translations'), 500);
qdb_handler_fail($e, 'Load translations', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -212,20 +172,13 @@ case 'POST':
if (!is_array($bundle)) {
json_error('MISSING_FIELDS', 'bundle object is required', 400);
}
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$result = qdb_import_translations_bundle($pdo, $bundle);
qdb_save($tmpDb, $lockFp);
json_success($result);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log('translations importBundle: ' . $e->getMessage());
require_once __DIR__ . '/../lib/errors.php';
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
error_log('translations importBundle: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Import'), 500);
qdb_handler_fail($e, 'Import translations', null, $tmpDb, $lockFp);
}
break;
}
@ -243,7 +196,7 @@ case 'PUT':
if (!$lang) {
json_error('MISSING_FIELDS', 'languageCode required', 400);
}
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
if ($lang === QDB_SOURCE_LANGUAGE) {
qdb_ensure_source_language($pdo);
@ -255,9 +208,7 @@ case 'PUT':
qdb_save($tmpDb, $lockFp);
json_success([]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Save language', null, $tmpDb, $lockFp);
}
break;
}
@ -280,15 +231,7 @@ case 'PUT':
qdb_save($tmpDb, $lockFp);
json_success([]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations PUT: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Save translation'), 500);
qdb_handler_fail($e, 'Save translation', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -305,7 +248,7 @@ case 'DELETE':
if ($lang === QDB_SOURCE_LANGUAGE) {
json_error('BAD_REQUEST', 'German (de) cannot be removed', 400);
}
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
try {
$pdo->prepare("DELETE FROM language WHERE languageCode = :lc")->execute([':lc' => $lang]);
$pdo->prepare("DELETE FROM question_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
@ -314,9 +257,7 @@ case 'DELETE':
qdb_save($tmpDb, $lockFp);
json_success([]);
} catch (Throwable $e) {
qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'Delete language', null, $tmpDb, $lockFp);
}
break;
}
@ -349,15 +290,7 @@ case 'DELETE':
qdb_save($tmpDb, $lockFp);
json_success([]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) {
qdb_discard($tmpDb, $lockFp);
}
if (function_exists('qdb_api_log_note_exception')) {
qdb_api_log_note_exception($e);
}
require_once __DIR__ . '/../lib/errors.php';
error_log('translations DELETE: ' . $e->getMessage());
json_error('SERVER_ERROR', qdb_public_error_message($e, 'Delete translation'), 500);
qdb_handler_fail($e, 'Delete translation', null, $tmpDb ?? null, $lockFp ?? null);
}
break;

View File

@ -9,7 +9,7 @@ switch ($method) {
case 'GET':
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
[$pdo, $tmpDb, $lockFp] = qdb_open_read_or_fail();
if ($callerRole === 'admin') {
$users = $pdo->query(
@ -53,9 +53,7 @@ case 'GET':
'callerRole' => $callerRole,
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'users', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -88,7 +86,7 @@ case 'POST':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
$chk = $pdo->prepare("SELECT userID FROM users WHERE username = :u");
$chk->execute([':u' => $username]);
@ -142,7 +140,7 @@ case 'POST':
$svUsername = null;
if ($role === 'coach') {
[$pdo2, $tmp2, $lk2] = qdb_open(false);
[$pdo2, $tmp2, $lk2] = qdb_open_read_or_fail();
$svr = $pdo2->prepare("SELECT username FROM supervisor WHERE supervisorID = :sid");
$svr->execute([':sid' => $supervisorID]);
$svUsername = $svr->fetchColumn() ?: null;
@ -161,10 +159,7 @@ case 'POST':
'createdAt' => $now,
]);
} catch (Throwable $e) {
if (isset($pdo) && $pdo->inTransaction()) $pdo->rollBack();
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'users', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -187,7 +182,7 @@ case 'PATCH':
$mustChange = isset($body['mustChangePassword']) ? (int)(bool)$body['mustChangePassword'] : 1;
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
$row = $pdo->prepare(
"SELECT u.userID, u.username, u.role, u.entityID, c.supervisorID
@ -242,10 +237,8 @@ case 'PATCH':
'mustChangePassword' => $mustChange,
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
}
qdb_handler_fail($e, 'users', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
}
@ -260,7 +253,7 @@ case 'PATCH':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
$row = $pdo->prepare(
"SELECT u.userID, u.username, u.role, u.entityID, c.supervisorID
@ -308,9 +301,7 @@ case 'PATCH':
'supervisorUsername' => $svUsername,
]);
} catch (Throwable $e) {
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'users', null, $tmpDb ?? null, $lockFp ?? null);
}
break;
@ -326,7 +317,7 @@ case 'DELETE':
}
try {
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
[$pdo, $tmpDb, $lockFp] = qdb_open_write_or_fail();
$row = $pdo->prepare("SELECT role, entityID FROM users WHERE userID = :uid");
$row->execute([':uid' => $targetUserID]);
@ -368,10 +359,7 @@ case 'DELETE':
json_success([]);
} catch (Throwable $e) {
if (isset($pdo) && $pdo->inTransaction()) $pdo->rollBack();
if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp);
error_log($e->getMessage());
json_error('SERVER_ERROR', 'Server error', 500);
qdb_handler_fail($e, 'users', $pdo ?? null, $tmpDb ?? null, $lockFp ?? null);
}
break;