headless_lms_models/
offered_answers_to_peer_review_temporary.rs

1use rand::Rng;
2
3use crate::{exercise_slide_submissions::ExerciseSlideSubmission, prelude::*};
4
5/// Returns an exercise slide submission id that has been given to be reviewed by the student within the hour.
6/// Does not return submissions that no longer need peer review.
7pub async fn try_to_restore_previously_given_exercise_slide_submission(
8    conn: &mut PgConnection,
9    exercise_id: Uuid,
10    user_id: Uuid,
11    course_instance_id: Uuid,
12) -> ModelResult<Option<ExerciseSlideSubmission>> {
13    // Sometimes clean up the table to keep the table small and fast
14    if rand::rng().random_range(0..10) == 0 {
15        delete_expired_records(&mut *conn).await?;
16    }
17
18    let res = sqlx::query!(
19        "
20SELECT exercise_slide_submission_id
21FROM offered_answers_to_peer_review_temporary
22WHERE exercise_id = $1
23  AND user_id = $2
24  AND course_instance_id = $3
25  AND created_at > now() - '1 hour'::interval
26  ",
27        exercise_id,
28        user_id,
29        course_instance_id,
30    )
31    .fetch_optional(&mut *conn)
32    .await?;
33
34    if let Some(res) = res {
35        // In order to return the saved submission, it needs to have a peer review queue entry and the entry must not have received enough peer reviews.
36        match crate::peer_review_queue_entries::get_by_receiving_peer_reviews_exercise_slide_submission_id(&mut *conn, res.exercise_slide_submission_id).await.optional()? { Some(peer_review_queue_entry) => {
37          if peer_review_queue_entry.received_enough_peer_reviews || peer_review_queue_entry.removed_from_queue_for_unusual_reason || peer_review_queue_entry.deleted_at.is_some() {
38            return Ok(None);
39          }
40        } _ => {
41          return Ok(None)
42        }}
43
44        let ess = crate::exercise_slide_submissions::get_by_id(
45            &mut *conn,
46            res.exercise_slide_submission_id,
47        )
48        .await?;
49
50        if ess.deleted_at.is_some() {
51            return Ok(None);
52        }
53        return Ok(Some(ess));
54    }
55    Ok(None)
56}
57
58/// Returns an exercise slide submission id that has been given to be reviewed by the student within the hour.
59pub async fn save_given_exercise_slide_submission(
60    conn: &mut PgConnection,
61    exercise_slide_submission_id: Uuid,
62    exercise_id: Uuid,
63    user_id: Uuid,
64    course_instance_id: Uuid,
65) -> ModelResult<()> {
66    let _res = sqlx::query!(
67        "
68INSERT INTO offered_answers_to_peer_review_temporary (
69    exercise_slide_submission_id,
70    user_id,
71    course_instance_id,
72    exercise_id
73  )
74VALUES ($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT offered_answers_to_peer_review_temporary_pkey DO
75UPDATE
76SET exercise_slide_submission_id = $1,
77  user_id = $2,
78  course_instance_id = $3,
79  exercise_id = $4,
80  created_at = now()
81",
82        exercise_slide_submission_id,
83        user_id,
84        course_instance_id,
85        exercise_id,
86    )
87    .execute(&mut *conn)
88    .await?;
89
90    Ok(())
91}
92
93/// For clearing the table after the user has given a peer review so that they can receive a new submission to be reviewed
94pub async fn delete_saved_submissions_for_user(
95    conn: &mut PgConnection,
96    exercise_id: Uuid,
97    user_id: Uuid,
98) -> ModelResult<()> {
99    info!("Deleting expired records from offered_answers_to_peer_review_temporary");
100    let _res = sqlx::query!(
101        "
102DELETE FROM offered_answers_to_peer_review_temporary
103WHERE exercise_id = $1
104  AND user_id = $2
105",
106        exercise_id,
107        user_id
108    )
109    .execute(&mut *conn)
110    .await?;
111    Ok(())
112}
113
114/// Deletes entries older than 1 hour -- for keeping the table small and fast
115async fn delete_expired_records(conn: &mut PgConnection) -> ModelResult<()> {
116    info!("Deleting expired records from offered_answers_to_peer_review_temporary");
117    let _res = sqlx::query!(
118        "
119DELETE FROM offered_answers_to_peer_review_temporary
120WHERE created_at < now() - '1 hour'::interval
121"
122    )
123    .execute(&mut *conn)
124    .await?;
125    Ok(())
126}