added categoryKey to questionnaire schema and updated related functions for questionnaire handling; enhanced API to fetch client answers
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
* GET ?id=<questionnaireID> -> single questionnaire in app JSON format
|
||||
* GET ?translations=1 -> global app UI strings only (not questionnaire content); **no auth** (login screen).
|
||||
* GET ?clients=1 -> list of clients assigned to the authenticated coach
|
||||
* GET ?clientCode=X&answers=1 -> all completed questionnaire answers for one client (encrypted)
|
||||
* POST -> submit interview answers for a client (coach / supervisor / admin).
|
||||
* Re-posting the same clientCode + questionnaireID updates answers in place (re-edit).
|
||||
* Sensitive POST/GET ?clients=1 bodies use encrypted payloads (HKDF from Bearer token).
|
||||
@ -69,12 +70,15 @@ if ($method === 'POST') {
|
||||
);
|
||||
$qRows->execute([':qn' => $qnID]);
|
||||
$shortIdMap = []; // shortId -> fullQuestionID
|
||||
$shortIdToType = []; // shortId -> layout type
|
||||
$freeTextMaxLen = []; // fullQuestionID -> maxLength
|
||||
$symptomParentMap = qdb_glass_symptom_parent_map($pdo, $qnID);
|
||||
foreach ($qRows->fetchAll(PDO::FETCH_ASSOC) as $qRow) {
|
||||
$fullId = $qRow['questionID'];
|
||||
$parts = explode('__', $fullId);
|
||||
$shortIdMap[end($parts)] = $fullId;
|
||||
$short = end($parts);
|
||||
$shortIdMap[$short] = $fullId;
|
||||
$shortIdToType[$short] = $qRow['type'] ?? '';
|
||||
if (($qRow['type'] ?? '') === 'free_text') {
|
||||
$cfg = json_decode($qRow['configJson'] ?? '{}', true) ?: [];
|
||||
$freeTextMaxLen[$fullId] = max(1, min((int)($cfg['maxLength'] ?? 500), 10000));
|
||||
@ -111,6 +115,9 @@ if ($method === 'POST') {
|
||||
answeredAt = excluded.answeredAt
|
||||
");
|
||||
|
||||
require_once __DIR__ . '/../lib/app_answers.php';
|
||||
$answers = qdb_group_app_submit_answers($answers, $shortIdToType, $symptomParentMap);
|
||||
|
||||
foreach ($answers as $a) {
|
||||
$shortId = trim($a['questionID'] ?? '');
|
||||
if ($shortId === '') continue;
|
||||
@ -149,6 +156,13 @@ if ($method === 'POST') {
|
||||
$opt = $optionMap[$fullQID][(string)$optionKey];
|
||||
$answerOptionID = $opt['answerOptionID'];
|
||||
$sumPoints += $opt['points'];
|
||||
} elseif (($shortIdToType[$shortId] ?? '') === 'multi_check_box_question'
|
||||
&& $freeTextValue !== null && $freeTextValue !== '') {
|
||||
foreach (qdb_decode_multi_check_values($freeTextValue) as $mk) {
|
||||
if (isset($optionMap[$fullQID][$mk])) {
|
||||
$sumPoints += $optionMap[$fullQID][$mk]['points'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$answerInsert->execute([
|
||||
@ -218,6 +232,34 @@ if ($method !== 'GET') {
|
||||
$qnID = $_GET['id'] ?? '';
|
||||
$translations = $_GET['translations'] ?? '';
|
||||
$fetchClients = $_GET['clients'] ?? '';
|
||||
$fetchAnswers = $_GET['answers'] ?? '';
|
||||
$clientCode = trim($_GET['clientCode'] ?? '');
|
||||
|
||||
if ($fetchAnswers) {
|
||||
require_role(['admin', 'supervisor', 'coach'], $tokenRec);
|
||||
if ($clientCode === '') {
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
json_error('MISSING_PARAM', 'clientCode query param required', 400);
|
||||
}
|
||||
|
||||
[$rbacClause, $rbacParams] = rbac_client_filter($tokenRec, 'cl');
|
||||
$clStmt = $pdo->prepare(
|
||||
"SELECT cl.clientCode FROM client cl WHERE cl.clientCode = :cc AND ($rbacClause)"
|
||||
);
|
||||
$clStmt->execute(array_merge([':cc' => $clientCode], $rbacParams));
|
||||
if (!$clStmt->fetch()) {
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
json_error('NOT_FOUND', 'Client not found or not authorized', 404);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../lib/app_answers.php';
|
||||
$questionnaires = qdb_export_app_client_answers_bundle($pdo, $clientCode);
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
json_success_sensitive([
|
||||
'clientCode' => $clientCode,
|
||||
'questionnaires' => $questionnaires,
|
||||
], $tokenRec['_token']);
|
||||
}
|
||||
|
||||
if ($fetchClients) {
|
||||
require_role(['coach'], $tokenRec);
|
||||
@ -364,7 +406,7 @@ if ($qnID) {
|
||||
|
||||
// Default: ordered questionnaire list
|
||||
$rows = $pdo->query("
|
||||
SELECT questionnaireID, name, showPoints, conditionJson
|
||||
SELECT questionnaireID, name, showPoints, conditionJson, categoryKey
|
||||
FROM questionnaire
|
||||
WHERE state = 'active'
|
||||
ORDER BY orderIndex
|
||||
@ -372,12 +414,17 @@ $rows = $pdo->query("
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $r) {
|
||||
$list[] = [
|
||||
$item = [
|
||||
'id' => $r['questionnaireID'],
|
||||
'name' => $r['name'],
|
||||
'showPoints' => (bool)(int)$r['showPoints'],
|
||||
'condition' => json_decode($r['conditionJson'], true) ?: new stdClass(),
|
||||
];
|
||||
$cat = trim($r['categoryKey'] ?? '');
|
||||
if ($cat !== '') {
|
||||
$item['categoryKey'] = $cat;
|
||||
}
|
||||
$list[] = $item;
|
||||
}
|
||||
|
||||
qdb_discard($tmpDb, $lockFp);
|
||||
|
||||
Reference in New Issue
Block a user