headless_lms_models/
user_course_instance_exercise_service_variables.rs1use std::collections::HashMap;
2
3use crate::{
4 exercise_tasks::ExerciseTask,
5 prelude::*,
6 user_exercise_states::{CourseInstanceOrExamId, UserExerciseState},
7};
8
9#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
10#[cfg_attr(feature = "ts_rs", derive(TS))]
11pub struct UserCourseInstanceExerciseServiceVariable {
12 pub id: Uuid,
13 pub created_at: DateTime<Utc>,
14 pub updated_at: DateTime<Utc>,
15 pub deleted_at: Option<DateTime<Utc>>,
16 pub exercise_service_slug: String,
17 pub user_id: Uuid,
18 pub course_instance_id: Option<Uuid>,
19 pub exam_id: Option<Uuid>,
20 pub variable_key: String,
21 pub variable_value: serde_json::Value,
22}
23
24pub(crate) async fn get_all_variables_for_user_and_course_instance_or_exam(
25 conn: &mut PgConnection,
26 user_id: Uuid,
27 instance_or_exam_id: CourseInstanceOrExamId,
28) -> ModelResult<Vec<UserCourseInstanceExerciseServiceVariable>> {
29 let (course_instance_id, exam_id) = instance_or_exam_id.to_instance_and_exam_ids();
30 let res = sqlx::query_as!(
31 UserCourseInstanceExerciseServiceVariable,
32 r#"
33SELECT *
34FROM user_course_instance_exercise_service_variables
35WHERE deleted_at IS NULL
36 AND user_id = $1
37 AND (course_instance_id = $2 OR course_instance_id IS NULL)
38 AND (exam_id = $3 OR exam_id IS NULL);
39 "#,
40 user_id,
41 course_instance_id,
42 exam_id
43 )
44 .fetch_all(conn)
45 .await?;
46 Ok(res)
47}
48
49pub async fn get_all_user_variables_for_user_and_course_instance_and_exercise_type(
50 conn: &mut PgConnection,
51 user_id: Uuid,
52 course_instance_id: Uuid,
53 exercise_type: &str,
54) -> ModelResult<Vec<UserCourseInstanceExerciseServiceVariable>> {
55 let res = sqlx::query_as!(
56 UserCourseInstanceExerciseServiceVariable,
57 r#"
58SELECT *
59FROM user_course_instance_exercise_service_variables
60WHERE deleted_at IS NULL
61 AND user_id = $1
62 AND course_instance_id = $2
63 AND exercise_service_slug = $3;
64 "#,
65 user_id,
66 course_instance_id,
67 exercise_type
68 )
69 .fetch_all(conn)
70 .await?;
71 Ok(res)
72}
73
74pub(crate) async fn insert_after_exercise_task_graded(
75 conn: &mut PgConnection,
76 set_user_variables: &Option<HashMap<String, serde_json::Value>>,
77 exercise_task: &ExerciseTask,
78 user_exercise_state: &UserExerciseState,
79) -> ModelResult<()> {
80 if let Some(set_user_variables) = set_user_variables {
81 for (k, v) in set_user_variables {
82 sqlx::query!(
83 r#"
84INSERT INTO user_course_instance_exercise_service_variables (
85 exercise_service_slug,
86 user_id,
87 course_instance_id,
88 exam_id,
89 variable_key,
90 variable_value
91 )
92VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (
93 variable_key,
94 user_id,
95 course_instance_id,
96 exercise_service_slug,
97 exam_id,
98 deleted_at
99 ) DO
100UPDATE
101SET variable_value = $6;
102 "#,
103 exercise_task.exercise_type,
104 user_exercise_state.user_id,
105 user_exercise_state.course_instance_id,
106 user_exercise_state.exam_id,
107 k,
108 v
109 )
110 .execute(&mut *conn)
111 .await?;
112 }
113 Ok(())
114 } else {
115 Ok(())
116 }
117}