292 lines
12 KiB
PHP
292 lines
12 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../common.php';
|
|
require_once __DIR__ . '/../db_init.php';
|
|
|
|
header('Content-Type: application/json; charset=UTF-8');
|
|
|
|
$tokenRec = require_valid_token();
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
|
|
$validTypes = ['question', 'answer_option', 'string', 'language'];
|
|
|
|
switch ($method) {
|
|
|
|
case 'GET':
|
|
// GET ?languages=1 -> list all languages
|
|
if (isset($_GET['languages'])) {
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
|
$rows = $pdo->query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC);
|
|
qdb_discard($tmpDb, $lockFp);
|
|
echo json_encode(["success" => true, "languages" => $rows]);
|
|
break;
|
|
}
|
|
|
|
// GET ?questionnaireID=X -> batch: all keys + all translations for a questionnaire
|
|
$qnID = $_GET['questionnaireID'] ?? '';
|
|
if ($qnID) {
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
|
|
|
$languages = $pdo->query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Question keys + translations
|
|
$qStmt = $pdo->prepare("
|
|
SELECT q.questionID, q.defaultText, q.configJson
|
|
FROM question q WHERE q.questionnaireID = :id ORDER BY q.orderIndex
|
|
");
|
|
$qStmt->execute([':id' => $qnID]);
|
|
$dbQuestions = $qStmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$entries = [];
|
|
$stringKeys = [];
|
|
|
|
foreach ($dbQuestions as $dbQ) {
|
|
$entries[] = [
|
|
'key' => $dbQ['defaultText'],
|
|
'type' => 'question',
|
|
'entityId' => $dbQ['questionID'],
|
|
];
|
|
|
|
// Answer option keys
|
|
$aoStmt = $pdo->prepare("
|
|
SELECT answerOptionID, defaultText FROM answer_option
|
|
WHERE questionID = :qid ORDER BY orderIndex
|
|
");
|
|
$aoStmt->execute([':qid' => $dbQ['questionID']]);
|
|
foreach ($aoStmt->fetchAll(PDO::FETCH_ASSOC) as $ao) {
|
|
$entries[] = [
|
|
'key' => $ao['defaultText'],
|
|
'type' => 'answer_option',
|
|
'entityId' => $ao['answerOptionID'],
|
|
];
|
|
}
|
|
|
|
// String keys from configJson
|
|
$config = json_decode($dbQ['configJson'] ?: '{}', true) ?: [];
|
|
foreach (['textKey','textKey1','textKey2','hint','hint1','hint2'] as $field) {
|
|
if (!empty($config[$field])) $stringKeys[$config[$field]] = true;
|
|
}
|
|
if (!empty($config['symptoms']) && is_array($config['symptoms'])) {
|
|
foreach ($config['symptoms'] as $s) $stringKeys[$s] = true;
|
|
}
|
|
}
|
|
|
|
foreach (array_keys($stringKeys) as $sk) {
|
|
$entries[] = [
|
|
'key' => $sk,
|
|
'type' => 'string',
|
|
'entityId' => $sk,
|
|
];
|
|
}
|
|
|
|
// Fetch all existing translations for these entities
|
|
$translations = [];
|
|
|
|
// question translations
|
|
$qIds = array_filter(array_map(fn($e) => $e['type'] === 'question' ? $e['entityId'] : null, $entries));
|
|
if ($qIds) {
|
|
$ph = implode(',', array_fill(0, count($qIds), '?'));
|
|
$stmt = $pdo->prepare("SELECT questionID AS entityId, languageCode, text FROM question_translation WHERE questionID IN ($ph)");
|
|
$stmt->execute(array_values($qIds));
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$translations[$r['entityId']][$r['languageCode']] = $r['text'];
|
|
}
|
|
}
|
|
|
|
// answer_option translations
|
|
$aoIds = array_filter(array_map(fn($e) => $e['type'] === 'answer_option' ? $e['entityId'] : null, $entries));
|
|
if ($aoIds) {
|
|
$ph = implode(',', array_fill(0, count($aoIds), '?'));
|
|
$stmt = $pdo->prepare("SELECT answerOptionID AS entityId, languageCode, text FROM answer_option_translation WHERE answerOptionID IN ($ph)");
|
|
$stmt->execute(array_values($aoIds));
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$translations[$r['entityId']][$r['languageCode']] = $r['text'];
|
|
}
|
|
}
|
|
|
|
// string translations
|
|
$sKeys = array_filter(array_map(fn($e) => $e['type'] === 'string' ? $e['entityId'] : null, $entries));
|
|
if ($sKeys) {
|
|
$ph = implode(',', array_fill(0, count($sKeys), '?'));
|
|
$stmt = $pdo->prepare("SELECT stringKey AS entityId, languageCode, text FROM string_translation WHERE stringKey IN ($ph)");
|
|
$stmt->execute(array_values($sKeys));
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$translations[$r['entityId']][$r['languageCode']] = $r['text'];
|
|
}
|
|
}
|
|
|
|
// Attach translations to entries
|
|
foreach ($entries as &$e) {
|
|
$e['translations'] = $translations[$e['entityId']] ?? (object)[];
|
|
}
|
|
unset($e);
|
|
|
|
qdb_discard($tmpDb, $lockFp);
|
|
echo json_encode([
|
|
"success" => true,
|
|
"languages" => $languages,
|
|
"entries" => $entries,
|
|
]);
|
|
break;
|
|
}
|
|
|
|
// Original single-entity fetch
|
|
$type = $_GET['type'] ?? '';
|
|
$id = $_GET['id'] ?? '';
|
|
if (!in_array($type, $validTypes, true) || (!$id && $type !== 'string')) {
|
|
http_response_code(400);
|
|
echo json_encode(["error" => "type (question|answer_option|string) and id required"]);
|
|
exit;
|
|
}
|
|
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
|
if ($type === 'question') {
|
|
$stmt = $pdo->prepare("SELECT languageCode, text FROM question_translation WHERE questionID = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
} elseif ($type === 'answer_option') {
|
|
$stmt = $pdo->prepare("SELECT languageCode, text FROM answer_option_translation WHERE answerOptionID = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
} else {
|
|
if ($id) {
|
|
$stmt = $pdo->prepare("SELECT stringKey, languageCode, text FROM string_translation WHERE stringKey = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
} else {
|
|
$stmt = $pdo->query("SELECT stringKey, languageCode, text FROM string_translation ORDER BY stringKey, languageCode");
|
|
}
|
|
}
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
qdb_discard($tmpDb, $lockFp);
|
|
echo json_encode(["success" => true, "translations" => $rows]);
|
|
break;
|
|
|
|
case 'PUT':
|
|
require_role(['admin', 'supervisor'], $tokenRec);
|
|
$body = json_decode(file_get_contents('php://input'), true);
|
|
$type = $body['type'] ?? '';
|
|
|
|
// Language management
|
|
if ($type === 'language') {
|
|
$lang = trim($body['languageCode'] ?? '');
|
|
$name = trim($body['name'] ?? '');
|
|
if (!$lang) {
|
|
http_response_code(400);
|
|
echo json_encode(["error" => "languageCode required"]);
|
|
exit;
|
|
}
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
|
try {
|
|
$pdo->prepare("INSERT INTO language (languageCode, name) VALUES (:lc, :n)
|
|
ON CONFLICT(languageCode) DO UPDATE SET name = excluded.name")
|
|
->execute([':lc' => $lang, ':n' => $name]);
|
|
qdb_save($tmpDb, $lockFp);
|
|
echo json_encode(["success" => true]);
|
|
} catch (Throwable $e) {
|
|
qdb_discard($tmpDb, $lockFp);
|
|
http_response_code(500);
|
|
error_log($e->getMessage());
|
|
echo json_encode(["error" => "Server error"]);
|
|
}
|
|
break;
|
|
}
|
|
|
|
$id = $body['id'] ?? '';
|
|
$lang = trim($body['languageCode'] ?? '');
|
|
$text = $body['text'] ?? '';
|
|
if (!in_array($type, $validTypes, true) || !$id || !$lang) {
|
|
http_response_code(400);
|
|
echo json_encode(["error" => "type, id, and languageCode required"]);
|
|
exit;
|
|
}
|
|
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
|
try {
|
|
if ($type === 'question') {
|
|
$pdo->prepare("INSERT INTO question_translation (questionID, languageCode, text)
|
|
VALUES (:id, :lang, :t)
|
|
ON CONFLICT(questionID, languageCode) DO UPDATE SET text = excluded.text")
|
|
->execute([':id' => $id, ':lang' => $lang, ':t' => $text]);
|
|
} elseif ($type === 'answer_option') {
|
|
$pdo->prepare("INSERT INTO answer_option_translation (answerOptionID, languageCode, text)
|
|
VALUES (:id, :lang, :t)
|
|
ON CONFLICT(answerOptionID, languageCode) DO UPDATE SET text = excluded.text")
|
|
->execute([':id' => $id, ':lang' => $lang, ':t' => $text]);
|
|
} else {
|
|
$pdo->prepare("INSERT INTO string_translation (stringKey, languageCode, text)
|
|
VALUES (:id, :lang, :t)
|
|
ON CONFLICT(stringKey, languageCode) DO UPDATE SET text = excluded.text")
|
|
->execute([':id' => $id, ':lang' => $lang, ':t' => $text]);
|
|
}
|
|
qdb_save($tmpDb, $lockFp);
|
|
echo json_encode(["success" => true]);
|
|
} catch (Throwable $e) {
|
|
qdb_discard($tmpDb, $lockFp);
|
|
http_response_code(500);
|
|
error_log($e->getMessage());
|
|
echo json_encode(["error" => "Server error"]);
|
|
}
|
|
break;
|
|
|
|
case 'DELETE':
|
|
require_role(['admin', 'supervisor'], $tokenRec);
|
|
$body = json_decode(file_get_contents('php://input'), true);
|
|
$type = $body['type'] ?? '';
|
|
|
|
// Language deletion
|
|
if ($type === 'language') {
|
|
$lang = trim($body['languageCode'] ?? '');
|
|
if (!$lang) {
|
|
http_response_code(400);
|
|
echo json_encode(["error" => "languageCode required"]);
|
|
exit;
|
|
}
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
|
try {
|
|
$pdo->prepare("DELETE FROM language WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
|
$pdo->prepare("DELETE FROM question_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
|
$pdo->prepare("DELETE FROM answer_option_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
|
$pdo->prepare("DELETE FROM string_translation WHERE languageCode = :lc")->execute([':lc' => $lang]);
|
|
qdb_save($tmpDb, $lockFp);
|
|
echo json_encode(["success" => true]);
|
|
} catch (Throwable $e) {
|
|
qdb_discard($tmpDb, $lockFp);
|
|
http_response_code(500);
|
|
error_log($e->getMessage());
|
|
echo json_encode(["error" => "Server error"]);
|
|
}
|
|
break;
|
|
}
|
|
|
|
$id = $body['id'] ?? '';
|
|
$lang = trim($body['languageCode'] ?? '');
|
|
if (!in_array($type, $validTypes, true) || !$id || !$lang) {
|
|
http_response_code(400);
|
|
echo json_encode(["error" => "type, id, and languageCode required"]);
|
|
exit;
|
|
}
|
|
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(true);
|
|
try {
|
|
if ($type === 'question') {
|
|
$pdo->prepare("DELETE FROM question_translation WHERE questionID = :id AND languageCode = :lang")
|
|
->execute([':id' => $id, ':lang' => $lang]);
|
|
} elseif ($type === 'answer_option') {
|
|
$pdo->prepare("DELETE FROM answer_option_translation WHERE answerOptionID = :id AND languageCode = :lang")
|
|
->execute([':id' => $id, ':lang' => $lang]);
|
|
} else {
|
|
$pdo->prepare("DELETE FROM string_translation WHERE stringKey = :id AND languageCode = :lang")
|
|
->execute([':id' => $id, ':lang' => $lang]);
|
|
}
|
|
qdb_save($tmpDb, $lockFp);
|
|
echo json_encode(["success" => true]);
|
|
} catch (Throwable $e) {
|
|
qdb_discard($tmpDb, $lockFp);
|
|
http_response_code(500);
|
|
error_log($e->getMessage());
|
|
echo json_encode(["error" => "Server error"]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
http_response_code(405);
|
|
echo json_encode(["error" => "Method not allowed"]);
|
|
}
|