extended metadata on questionnaires
Some checks failed
PHPUnit / test (push) Has been cancelled

This commit is contained in:
2026-07-01 09:13:32 +02:00
parent e589b46a8a
commit 13119f300a
4 changed files with 78 additions and 13 deletions

View File

@ -13,7 +13,7 @@ if (defined('QDB_TEST_UPLOADS')) {
define('QDB_LOCK', QDB_UPLOADS_DIR . '/.qdb_lock');
}
define('QDB_SCHEMA', __DIR__ . '/schema.sql');
define('QDB_VERSION', 14);
define('QDB_VERSION', 15);
function qdb_table_exists(PDO $pdo, string $table): bool {
$stmt = $pdo->prepare(
@ -107,6 +107,33 @@ function qdb_apply_migrations(PDO $pdo, string $schemaSql): bool {
$pdo->exec("ALTER TABLE questionnaire_submission ADD COLUMN structureSnapshotJson TEXT NOT NULL DEFAULT '{}'");
$changed = true;
}
if (!qdb_column_exists($pdo, 'questionnaire_submission', 'programCycleNumber')) {
$pdo->exec('ALTER TABLE questionnaire_submission ADD COLUMN programCycleNumber INTEGER');
$changed = true;
}
if (!qdb_column_exists($pdo, 'questionnaire_submission', 'programSessionID')) {
$pdo->exec('ALTER TABLE questionnaire_submission ADD COLUMN programSessionID TEXT');
$changed = true;
}
if (!qdb_column_exists($pdo, 'questionnaire_submission', 'programSessionNumber')) {
$pdo->exec('ALTER TABLE questionnaire_submission ADD COLUMN programSessionNumber INTEGER');
$changed = true;
}
}
if (qdb_table_exists($pdo, 'completed_questionnaire')) {
if (!qdb_column_exists($pdo, 'completed_questionnaire', 'programCycleNumber')) {
$pdo->exec('ALTER TABLE completed_questionnaire ADD COLUMN programCycleNumber INTEGER');
$changed = true;
}
if (!qdb_column_exists($pdo, 'completed_questionnaire', 'programSessionID')) {
$pdo->exec('ALTER TABLE completed_questionnaire ADD COLUMN programSessionID TEXT');
$changed = true;
}
if (!qdb_column_exists($pdo, 'completed_questionnaire', 'programSessionNumber')) {
$pdo->exec('ALTER TABLE completed_questionnaire ADD COLUMN programSessionNumber INTEGER');
$changed = true;
}
}
if (qdb_table_exists($pdo, 'questionnaire_structure_snapshot')

View File

@ -95,6 +95,16 @@ if ($method === 'POST') {
$startedAt = isset($body['startedAt']) ? (int)$body['startedAt'] : null;
$completedAt = isset($body['completedAt']) ? (int)$body['completedAt'] : null;
$programCycleNumber = isset($body['programCycleNumber']) ? (int)$body['programCycleNumber'] : null;
$programSessionID = isset($body['programSessionID'])
? trim((string)$body['programSessionID'])
: null;
if ($programSessionID === '') {
$programSessionID = null;
}
$programSessionNumber = isset($body['programSessionNumber'])
? (int)$body['programSessionNumber']
: null;
try {
$opened = qdb_open_write_or_fail();
@ -297,14 +307,21 @@ if ($method === 'POST') {
: qdb_compute_questionnaire_score($pdo, $clientCode, $qnID);
$pdo->prepare("
INSERT INTO completed_questionnaire (clientCode, questionnaireID, assignedByCoach, status, startedAt, completedAt, sumPoints)
VALUES (:cc, :qn, :abc, 'completed', :sa, :ca, :sp)
INSERT INTO completed_questionnaire (
clientCode, questionnaireID, assignedByCoach, status,
startedAt, completedAt, sumPoints,
programCycleNumber, programSessionID, programSessionNumber
)
VALUES (:cc, :qn, :abc, 'completed', :sa, :ca, :sp, :pcn, :psid, :psn)
ON CONFLICT(clientCode, questionnaireID) DO UPDATE SET
assignedByCoach = excluded.assignedByCoach,
status = 'completed',
startedAt = COALESCE(excluded.startedAt, startedAt),
completedAt = excluded.completedAt,
sumPoints = excluded.sumPoints
sumPoints = excluded.sumPoints,
programCycleNumber = COALESCE(excluded.programCycleNumber, programCycleNumber),
programSessionID = COALESCE(excluded.programSessionID, programSessionID),
programSessionNumber = COALESCE(excluded.programSessionNumber, programSessionNumber)
")->execute([
':cc' => $clientCode,
':qn' => $qnID,
@ -312,6 +329,9 @@ if ($method === 'POST') {
':sa' => $startedAt,
':ca' => $completedAt,
':sp' => $sumPoints,
':pcn' => $programCycleNumber,
':psid'=> $programSessionID,
':psn' => $programSessionNumber,
]);
require_once __DIR__ . '/../lib/submissions.php';
@ -326,7 +346,11 @@ if ($method === 'POST') {
$assignedByCoach,
$submitRev,
$submitManifest,
array_keys($submittedQuestionIds)
array_keys($submittedQuestionIds),
null,
$programCycleNumber,
$programSessionID,
$programSessionNumber
);
qdb_recompute_profile_scores_for_client($pdo, $clientCode, $qnID);

View File

@ -131,7 +131,10 @@ function qdb_record_submission_after_submit(
int $structureRevision = 1,
?array $structureManifest = null,
?array $questionIdsToCopy = null,
?int $submittedAt = null
?int $submittedAt = null,
?int $programCycleNumber = null,
?string $programSessionID = null,
?int $programSessionNumber = null
): string {
$version = qdb_next_submission_version($pdo, $clientCode, $questionnaireID);
$submissionID = bin2hex(random_bytes(16));
@ -155,11 +158,13 @@ function qdb_record_submission_after_submit(
submissionID, clientCode, questionnaireID, version, submittedAt,
submittedByUserID, submittedByRole, assignedByCoach,
status, startedAt, completedAt, sumPoints,
programCycleNumber, programSessionID, programSessionNumber,
structureRevision, structureSnapshotJson
) VALUES (
:sid, :cc, :qn, :ver, :sat,
:uid, :role, :abc,
:st, :sa, :ca, :sp,
:pcn, :psid, :psn,
:srev, :snap
)'
)->execute([
@ -175,6 +180,9 @@ function qdb_record_submission_after_submit(
':sa' => $startedAt,
':ca' => $completedAt,
':sp' => $sumPoints,
':pcn' => $programCycleNumber,
':psid' => $programSessionID,
':psn' => $programSessionNumber,
':srev' => max(1, $structureRevision),
':snap' => $snapshotJson,
]);

View File

@ -111,6 +111,9 @@ CREATE TABLE IF NOT EXISTS completed_questionnaire (
startedAt INTEGER,
completedAt INTEGER,
sumPoints INTEGER,
programCycleNumber INTEGER,
programSessionID TEXT,
programSessionNumber INTEGER,
PRIMARY KEY (clientCode, questionnaireID),
FOREIGN KEY(clientCode) REFERENCES client(clientCode),
FOREIGN KEY(questionnaireID) REFERENCES questionnaire(questionnaireID),
@ -168,6 +171,9 @@ CREATE TABLE IF NOT EXISTS questionnaire_submission (
startedAt INTEGER,
completedAt INTEGER,
sumPoints INTEGER,
programCycleNumber INTEGER,
programSessionID TEXT,
programSessionNumber INTEGER,
structureRevision INTEGER NOT NULL DEFAULT 1,
structureSnapshotJson TEXT NOT NULL DEFAULT '{}',
FOREIGN KEY(clientCode) REFERENCES client(clientCode),