Skip to main content

headless_lms_server/controllers/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 chrono::NaiveDate;
8
9use crate::prelude::*;
10
11use super::world::RealisationKind;
12
13/// Namespaces every derived id, so the same inputs reproduce the same id across restarts and CI runs.
14const MOCK_NAMESPACE: Uuid = Uuid::from_u128(0x005c_07a2_0001_4a5e_9e6e_c0de_0000_0001);
15
16pub fn person_id(student_number: &str) -> String {
17    format!("hy-hlo-{student_number}")
18}
19
20pub fn course_unit_id(course_code: &str) -> String {
21    format!("hy-CU-{course_code}")
22}
23
24pub fn assessment_item_id(course_code: &str, kind: RealisationKind) -> String {
25    format!("hy-AI-{course_code}-{}", kind.as_str())
26}
27
28/// Per (course, kind) rather than per student: a realisation is a shared teaching event whose roster
29/// `list-by-course` returns.
30pub fn realisation_id(course_code: &str, kind: RealisationKind) -> String {
31    format!(
32        "hy-opt-cur-{}-{}",
33        course_code.to_lowercase(),
34        kind.as_str()
35    )
36}
37
38pub fn enrolment_id(student_number: &str, kind: RealisationKind) -> String {
39    derived(
40        "otm",
41        &format!("enrolment|{student_number}|{}", kind.as_str()),
42    )
43}
44
45/// Per (student, course, kind): a person enrolled in more than one realisation of the same kind at
46/// once needs an id `enrolment_id` cannot give them, since that one is keyed on (student, kind) alone.
47pub fn enrolment_id_for_course(
48    student_number: &str,
49    course_code: &str,
50    kind: RealisationKind,
51) -> String {
52    derived(
53        "otm",
54        &format!("enrolment|{student_number}|{course_code}|{}", kind.as_str()),
55    )
56}
57
58pub fn study_right_id(student_number: &str, kind: RealisationKind) -> String {
59    derived(
60        "otm",
61        &format!("study-right|{student_number}|{}", kind.as_str()),
62    )
63}
64
65pub fn product_id(course_code: &str) -> String {
66    derived("otm", &format!("product|{course_code}"))
67}
68
69pub fn product_access_token(product_id: &str) -> String {
70    derived("token", &format!("access-token|{product_id}"))
71}
72
73/// `attempt` distinguishes a legitimate re-submission from a replay of the same attempt, which
74/// reproduces the id.
75#[allow(clippy::too_many_arguments)]
76pub fn submitted_attainment_id(
77    student_number: &str,
78    course_code: &str,
79    enrolment_id: &str,
80    attainment_date: NaiveDate,
81    grade_scale_id: &str,
82    grade_id: &str,
83    credits: f64,
84    attempt: u32,
85) -> String {
86    derived(
87        "hy-kur",
88        &format!(
89            "submission|{student_number}|{course_code}|{enrolment_id}|{attainment_date}|{grade_scale_id}|{grade_id}|{credits}|{attempt}"
90        ),
91    )
92}
93
94pub fn final_attainment_id(submitted_attainment_id: &str) -> String {
95    derived("otm", &format!("attainment|{submitted_attainment_id}"))
96}
97
98pub fn pushed_attainment_id(student_number: &str, course_code: &str, grade_id: &str) -> String {
99    derived(
100        "otm",
101        &format!("existing-attainment|{student_number}|{course_code}|{grade_id}"),
102    )
103}
104
105fn derived(prefix: &str, name: &str) -> String {
106    format!(
107        "{prefix}-{}",
108        Uuid::new_v5(&MOCK_NAMESPACE, name.as_bytes())
109    )
110}