Skip to main content

headless_lms_server/mock_suotar/
ids.rs

1//! Default identifier derivations for the simulated world. Every control upsert may pass an id
2//! verbatim instead, and the seed does for anything a spec asserts on.
3//!
4//! `derived` never formats a student number into the id: these reach the audited call log and the
5//! event details, where the scrubber's free-text scan only redacts bare digit runs.
6
7use crate::prelude::*;
8
9use super::world::RealisationKind;
10
11/// Namespaces every derived id, so the same inputs reproduce the same id across restarts and CI runs.
12const MOCK_NAMESPACE: Uuid = Uuid::from_u128(0x005c_07a2_0001_4a5e_9e6e_c0de_0000_0001);
13
14pub fn person_id(student_number: &str) -> String {
15    format!("hy-hlo-{student_number}")
16}
17
18pub fn course_unit_id(course_code: &str) -> String {
19    format!("hy-CU-{course_code}")
20}
21
22pub fn assessment_item_id(course_code: &str, kind: RealisationKind) -> String {
23    format!("hy-AI-{course_code}-{}", kind.as_str())
24}
25
26/// Per (course, kind) rather than per student: a realisation is a shared teaching event whose roster
27/// `list-by-course` returns.
28pub fn realisation_id(course_code: &str, kind: RealisationKind) -> String {
29    format!(
30        "hy-opt-cur-{}-{}",
31        course_code.to_lowercase(),
32        kind.as_str()
33    )
34}
35
36/// Per (student, course, kind): one person may hold enrolments of the same kind on several courses.
37pub fn enrolment_id(student_number: &str, course_code: &str, kind: RealisationKind) -> String {
38    derived(
39        "otm-enrolment",
40        &format!("enrolment|{student_number}|{course_code}|{}", kind.as_str()),
41    )
42}
43
44/// Suotar reads an enrolment's kind off this id: `avoin` in it means open university.
45pub fn study_right_id(student_number: &str, kind: RealisationKind) -> String {
46    let prefix = match kind {
47        RealisationKind::Degree => "otm-degree-sr",
48        RealisationKind::OpenUniversity => "otm-avoin-sr",
49    };
50    derived(
51        prefix,
52        &format!("study-right|{student_number}|{}", kind.as_str()),
53    )
54}
55
56/// Random like Suotar's own, so a resubmission of the same completion gets a new id.
57pub fn submitted_attainment_id() -> String {
58    format!("hy-kur-{}", Uuid::new_v4())
59}
60
61pub fn final_attainment_id(submitted_attainment_id: &str) -> String {
62    derived(
63        "otm-attainment",
64        &format!("attainment|{submitted_attainment_id}"),
65    )
66}
67
68pub fn pushed_attainment_id(student_number: &str, course_code: &str, grade_id: &str) -> String {
69    derived(
70        "otm-attainment",
71        &format!("existing-attainment|{student_number}|{course_code}|{grade_id}"),
72    )
73}
74
75fn derived(prefix: &str, name: &str) -> String {
76    format!(
77        "{prefix}-{}",
78        Uuid::new_v5(&MOCK_NAMESPACE, name.as_bytes())
79    )
80}