fix: exam report targets and objectives
Pipeline / check (pull_request) Successful in 2m43s
Pipeline / docs (pull_request) Skipped
Pipeline / nightly (pull_request) Skipped
Pipeline / release (pull_request) Skipped

This commit is contained in:
2026-09-22 00:39:22 -04:00
parent cfe8a3216c
commit d3f21e913b
5 changed files with 233 additions and 131 deletions
+29 -14
View File
@@ -321,8 +321,8 @@ pub fn student_value(diagnostic: &StudentDiagnostic, config: &RenderConfig) -> V
value.insert_some("position", question.position.map(|p| Value::Int(p as i64)));
value.insert_some("level", question.level.map(|l| Value::Int(l as i64)));
value.insert(
"objectives",
Value::Array(question.objectives.iter().map(Value::str).collect()),
"targets",
Value::Array(question.targets.iter().map(Value::str).collect()),
);
value.insert_some("correct", question.correct.map(Value::Bool));
value.insert("credit", Value::Float(question.credit));
@@ -330,13 +330,28 @@ pub fn student_value(diagnostic: &StudentDiagnostic, config: &RenderConfig) -> V
value.insert("dropped", Value::Bool(question.dropped));
value.insert("blank", Value::Bool(question.blank));
value.insert_some("class-rate", question.class_rate.map(Value::Float));
// Both tiers, as a list of pairs: the target says what this
// question asked, the objective says which row of the table
// above it counted toward. `objective` is absent when the
// tagged id is an objective with no targets, so the template
// does not print one sentence twice.
value.insert(
"objective-texts",
"measured",
Value::Array(
question
.objective_texts
.measured
.iter()
.map(|text| markup_value(text, content))
.map(|m| {
let mut pair = Value::dict();
pair.insert_some(
"objective",
m.objective
.as_ref()
.map(|text| markup_value(text, content)),
);
pair.insert("target", markup_value(&m.target, content));
pair
})
.collect(),
),
);
@@ -412,7 +427,7 @@ pub fn student_value(diagnostic: &StudentDiagnostic, config: &RenderConfig) -> V
value.insert("lecture", Value::str(&lecture.lecture));
value.insert("title", Value::str(&lecture.title));
value.insert_some("url", lecture.url.as_ref().map(Value::str));
value.insert("objectives-missed", Value::Int(lecture.n_objectives as i64));
value.insert("targets-missed", Value::Int(lecture.n_targets as i64));
value.insert("questions-missed", Value::Int(lecture.n_questions as i64));
value.insert(
"questions",
@@ -435,10 +450,10 @@ pub fn student_value(diagnostic: &StudentDiagnostic, config: &RenderConfig) -> V
),
);
value.insert(
"objectives",
"targets",
Value::Array(
lecture
.objectives
.targets
.iter()
.map(|text| markup_value(text, content))
.collect(),
@@ -783,9 +798,9 @@ fn triage_value(row: &crate::diagnostic::TriageRow, content: bool) -> Value {
value.insert_some("point-biserial", row.point_biserial.map(Value::Float));
value.insert_some("discrimination", row.discrimination.map(Value::Float));
value.insert(
"objectives",
"targets",
Value::Array(
row.objectives
row.targets
.iter()
.map(|text| markup_value(text, content))
.collect(),
@@ -844,14 +859,14 @@ fn cohort_question_value(question: &CohortQuestionRow, content: bool) -> Value {
value.insert_some("item", question.item.as_ref().map(Value::str));
value.insert_some("level", question.level.map(|l| Value::Int(l as i64)));
value.insert(
"objectives",
Value::Array(question.objectives.iter().map(Value::str).collect()),
"targets",
Value::Array(question.targets.iter().map(Value::str).collect()),
);
value.insert(
"objective-texts",
"target-texts",
Value::Array(
question
.objective_texts
.target_texts
.iter()
.map(|text| markup_value(text, content))
.collect(),