Skip to main content

headless_lms_models/
course_module_suotar_configurations.rs

1use utoipa::ToSchema;
2
3use crate::prelude::*;
4
5#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
6pub struct CourseModuleSuotarConfiguration {
7    pub id: Uuid,
8    pub created_at: DateTime<Utc>,
9    pub updated_at: DateTime<Utc>,
10    pub deleted_at: Option<DateTime<Utc>>,
11    pub course_module_id: Uuid,
12    pub open_university_product_id: Option<String>,
13    /// `None` means derive the grade scale from the completion.
14    pub grade_scale_id: Option<String>,
15    pub paused_at: Option<DateTime<Utc>>,
16    pub paused_by_user_id: Option<Uuid>,
17    pub pause_reason: Option<String>,
18    pub config_checked_at: Option<DateTime<Utc>>,
19    /// `None` means never checked, which is not the same as a failed check.
20    pub course_code_resolves: Option<bool>,
21    pub product_token_found: Option<bool>,
22    pub config_check_message: Option<String>,
23}
24
25/// Writes the module's Suotar configuration, creating the row if the module has none. The pause and
26/// config-check columns are left alone; their writers are separate.
27///
28/// Resurrects a soft-deleted row rather than inserting beside it: `ON CONFLICT` can only infer
29/// against `uq_course_module_suotar_configurations`, which is keyed on `course_module_id` alone.
30pub async fn upsert(
31    conn: &mut PgConnection,
32    course_module_id: Uuid,
33    open_university_product_id: Option<&str>,
34    grade_scale_id: Option<&str>,
35) -> ModelResult<CourseModuleSuotarConfiguration> {
36    let res = sqlx::query_as!(
37        CourseModuleSuotarConfiguration,
38        r#"
39INSERT INTO course_module_suotar_configurations (
40    course_module_id,
41    open_university_product_id,
42    grade_scale_id
43  )
44VALUES ($1, $2, $3) ON CONFLICT (course_module_id) DO
45UPDATE
46SET open_university_product_id = $2,
47  grade_scale_id = $3,
48  deleted_at = NULL
49RETURNING *
50        "#,
51        course_module_id,
52        open_university_product_id,
53        grade_scale_id,
54    )
55    .fetch_one(conn)
56    .await?;
57    Ok(res)
58}