headless_lms_models/
exercise_reset_logs.rs1use crate::prelude::*;
2use sqlx::PgConnection;
3
4#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
5#[cfg_attr(feature = "ts_rs", derive(TS))]
6pub struct ExerciseResetLog {
7 pub id: Uuid,
8 pub reset_by: Uuid,
9 pub reset_by_first_name: Option<String>,
10 pub reset_by_last_name: Option<String>,
11 pub reset_for: Uuid,
12 pub exercise_id: Uuid,
13 pub exercise_name: String,
14 pub course_id: Uuid,
15 pub reset_at: DateTime<Utc>,
16 pub created_at: DateTime<Utc>,
17 pub updated_at: DateTime<Utc>,
18 pub deleted_at: Option<DateTime<Utc>>,
19}
20
21pub async fn log_exercise_reset(
23 tx: &mut PgConnection,
24 reset_by: Uuid,
25 user_id: Uuid,
26 exercise_ids: &[Uuid],
27 course_id: Uuid,
28) -> Result<(), sqlx::Error> {
29 sqlx::query!(
30 r#"
31INSERT INTO exercise_reset_logs (
32 reset_by,
33 reset_for,
34 exercise_id,
35 course_id,
36 reset_at
37 )
38SELECT $1,
39 $2,
40 unnest($3::uuid []),
41 $4,
42 NOW()
43 "#,
44 reset_by,
45 user_id,
46 &exercise_ids,
47 course_id
48 )
49 .execute(&mut *tx)
50 .await?;
51
52 Ok(())
53}
54
55pub async fn get_exercise_reset_logs_for_user(
56 conn: &mut PgConnection,
57 user_id: Uuid,
58) -> ModelResult<Vec<ExerciseResetLog>> {
59 let result = sqlx::query_as!(
60 ExerciseResetLog,
61 r#"
62SELECT erl.id,
63 erl.reset_by,
64 ud.first_name AS reset_by_first_name,
65 ud.last_name AS reset_by_last_name,
66 erl.reset_for,
67 erl.exercise_id,
68 e.name AS exercise_name,
69 erl.course_id,
70 erl.reset_at,
71 erl.created_at,
72 erl.updated_at,
73 erl.deleted_at
74FROM exercise_reset_logs erl
75 JOIN exercises e ON erl.exercise_id = e.id
76 JOIN user_details ud ON erl.reset_by = ud.user_id
77WHERE erl.reset_for = $1
78ORDER BY erl.reset_at DESC"#,
79 user_id
80 )
81 .fetch_all(&mut *conn)
82 .await?;
83
84 Ok(result)
85}