headless_lms_models/
suspected_cheaters.rs

1use crate::prelude::*;
2
3#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
4#[cfg_attr(feature = "ts_rs", derive(TS))]
5pub struct SuspectedCheaters {
6    pub id: Uuid,
7    pub user_id: Uuid,
8    pub course_id: Uuid,
9    pub created_at: DateTime<Utc>,
10    pub deleted_at: Option<DateTime<Utc>>,
11    pub updated_at: Option<DateTime<Utc>>,
12    pub total_duration_seconds: Option<i32>,
13    pub total_points: i32,
14    pub is_archived: Option<bool>,
15}
16
17#[derive(Debug, Serialize, Deserialize)]
18#[cfg_attr(feature = "ts_rs", derive(TS))]
19pub struct ThresholdData {
20    pub points: i32,
21    pub duration_seconds: Option<i32>,
22}
23
24#[derive(Debug, Serialize, Deserialize)]
25#[cfg_attr(feature = "ts_rs", derive(TS))]
26pub struct DeletedSuspectedCheater {
27    pub id: i32,
28    pub count: i32,
29}
30
31#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
32#[cfg_attr(feature = "ts_rs", derive(TS))]
33pub struct Threshold {
34    pub id: Uuid,
35    pub course_id: Uuid,
36    pub created_at: DateTime<Utc>,
37    pub updated_at: DateTime<Utc>,
38    pub deleted_at: Option<DateTime<Utc>>,
39    pub points: i32,
40    pub duration_seconds: Option<i32>,
41}
42
43pub async fn insert(
44    conn: &mut PgConnection,
45    user_id: Uuid,
46    course_id: Uuid,
47    total_duration_seconds: Option<i32>,
48    total_points: i32,
49) -> ModelResult<()> {
50    sqlx::query!(
51        "
52    INSERT INTO suspected_cheaters (
53      user_id,
54      total_duration_seconds,
55      total_points,
56      course_id
57    )
58    VALUES ($1, $2, $3, $4)
59      ",
60        user_id,
61        total_duration_seconds,
62        total_points,
63        course_id
64    )
65    .execute(conn)
66    .await?;
67    Ok(())
68}
69
70pub async fn insert_thresholds(
71    conn: &mut PgConnection,
72    course_id: Uuid,
73    duration_seconds: Option<i32>,
74    points: i32,
75) -> ModelResult<Threshold> {
76    let threshold = sqlx::query_as!(
77        Threshold,
78        "
79        INSERT INTO cheater_thresholds (
80            course_id,
81            duration_seconds,
82            points
83        )
84        VALUES ($1, $2, $3)
85        ON CONFLICT (course_id)
86        DO UPDATE SET
87            duration_seconds = EXCLUDED.duration_seconds,
88            points = EXCLUDED.points
89        RETURNING *
90        ",
91        course_id,
92        duration_seconds,
93        points,
94    )
95    .fetch_one(conn)
96    .await?;
97
98    Ok(threshold)
99}
100
101pub async fn update_thresholds_by_point(
102    conn: &mut PgConnection,
103    course_id: Uuid,
104    points: i32,
105) -> ModelResult<()> {
106    sqlx::query!(
107        "
108      UPDATE cheater_thresholds
109      SET points = $2
110      WHERE course_id = $1
111    ",
112        course_id,
113        points
114    )
115    .execute(conn)
116    .await?;
117    Ok(())
118}
119
120pub async fn get_thresholds_by_id(
121    conn: &mut PgConnection,
122    course_id: Uuid,
123) -> ModelResult<Threshold> {
124    let thresholds = sqlx::query_as!(
125        Threshold,
126        "
127      SELECT id,
128      course_id,
129      duration_seconds,
130      points,
131      created_at,
132      updated_at,
133      deleted_at
134      FROM cheater_thresholds
135      WHERE course_id = $1
136      AND deleted_at IS NULL;
137    ",
138        course_id
139    )
140    .fetch_one(conn)
141    .await?;
142    Ok(thresholds)
143}
144
145pub async fn archive_suspected_cheater(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
146    sqlx::query!(
147        "
148      UPDATE suspected_cheaters
149      SET is_archived = TRUE
150      WHERE user_id = $1
151    ",
152        id
153    )
154    .execute(conn)
155    .await?;
156    Ok(())
157}
158
159pub async fn approve_suspected_cheater(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
160    sqlx::query!(
161        "
162      UPDATE suspected_cheaters
163      SET is_archived = FALSE
164      WHERE user_id = $1
165    ",
166        id
167    )
168    .execute(conn)
169    .await?;
170    Ok(())
171}
172
173pub async fn get_suspected_cheaters_by_id(
174    conn: &mut PgConnection,
175    id: Uuid,
176) -> ModelResult<SuspectedCheaters> {
177    let cheaters = sqlx::query_as!(
178        SuspectedCheaters,
179        "
180      SELECT *
181      FROM suspected_cheaters
182      WHERE user_id = $1
183      AND deleted_at IS NULL;
184    ",
185        id
186    )
187    .fetch_one(conn)
188    .await?;
189    Ok(cheaters)
190}
191
192pub async fn get_all_suspected_cheaters_in_course(
193    conn: &mut PgConnection,
194    course_id: Uuid,
195    archive: bool,
196) -> ModelResult<Vec<SuspectedCheaters>> {
197    let cheaters = sqlx::query_as!(
198        SuspectedCheaters,
199        "
200SELECT *
201FROM suspected_cheaters
202WHERE course_id = $1
203    AND is_archived = $2
204    AND deleted_at IS NULL;
205    ",
206        course_id,
207        archive
208    )
209    .fetch_all(conn)
210    .await?;
211    Ok(cheaters)
212}