Skip to main content

headless_lms_models/
credit_registration_enrolment_check_signals.rs

1//! Visits to the registration page and check requests, per completion, kept whether or not the
2//! completion has a ledger row or a linked student number yet. A row that starts waiting for an
3//! enrolment takes its group from these; see
4//! [`crate::library::credit_registration::preconditions`].
5
6use crate::library::credit_registration::enrolment_check_schedule::EnrolmentCheckSource;
7use crate::prelude::*;
8
9/// Records a visit and returns when the one before it was, if any.
10pub async fn record_visit(
11    conn: &mut PgConnection,
12    course_module_completion_id: Uuid,
13) -> ModelResult<Option<DateTime<Utc>>> {
14    let previous = sqlx::query_scalar!(
15        r#"
16WITH previous AS (
17  SELECT last_visited_at
18  FROM credit_registration_enrolment_check_signals
19  WHERE course_module_completion_id = $1
20    AND deleted_at IS NULL
21  FOR UPDATE
22),
23recorded AS (
24  INSERT INTO credit_registration_enrolment_check_signals (
25      course_module_completion_id,
26      last_visited_at
27    )
28  VALUES ($1, now()) ON CONFLICT (course_module_completion_id, deleted_at) DO
29  UPDATE
30  SET last_visited_at = now()
31)
32SELECT last_visited_at
33FROM previous
34        "#,
35        course_module_completion_id,
36    )
37    .fetch_optional(conn)
38    .await?
39    .flatten();
40    Ok(previous)
41}
42
43/// Records a check request. `source` is who asked: the student, a teacher, or a link made from a
44/// roster mail.
45pub async fn record_check_request(
46    conn: &mut PgConnection,
47    course_module_completion_id: Uuid,
48    source: EnrolmentCheckSource,
49) -> ModelResult<()> {
50    sqlx::query!(
51        r#"
52INSERT INTO credit_registration_enrolment_check_signals (
53    course_module_completion_id,
54    last_check_requested_at,
55    check_request_source
56  )
57VALUES ($1, now(), $2) ON CONFLICT (course_module_completion_id, deleted_at) DO
58UPDATE
59SET last_check_requested_at = now(),
60  check_request_source = EXCLUDED.check_request_source
61        "#,
62        course_module_completion_id,
63        source as EnrolmentCheckSource,
64    )
65    .execute(conn)
66    .await?;
67    Ok(())
68}
69
70/// Records a check request from a link made off a roster mail for every live push-path completion
71/// the user has on the course, and returns those completions.
72pub async fn record_account_link_for_course(
73    conn: &mut PgConnection,
74    user_id: Uuid,
75    course_id: Uuid,
76) -> ModelResult<Vec<Uuid>> {
77    let res = sqlx::query_scalar!(
78        r#"
79INSERT INTO credit_registration_enrolment_check_signals (
80    course_module_completion_id,
81    last_check_requested_at,
82    check_request_source
83  )
84SELECT cmc.id,
85  now(),
86  'account_link'
87FROM course_module_completions cmc
88WHERE cmc.user_id = $1
89  AND cmc.course_id = $2
90  AND cmc.register_credits_via_suotar
91  AND cmc.deleted_at IS NULL ON CONFLICT (course_module_completion_id, deleted_at) DO
92UPDATE
93SET last_check_requested_at = now(),
94  check_request_source = EXCLUDED.check_request_source
95RETURNING course_module_completion_id
96        "#,
97        user_id,
98        course_id,
99    )
100    .fetch_all(conn)
101    .await?;
102    Ok(res)
103}