headless_lms_models/
exercise_repositories.rs

1use crate::prelude::*;
2
3#[derive(Debug, Serialize, sqlx::Type)]
4#[cfg_attr(feature = "ts_rs", derive(TS))]
5#[sqlx(type_name = "exercise_repository_status", rename_all = "kebab-case")]
6pub enum ExerciseRepositoryStatus {
7    Pending,
8    Success,
9    Failure,
10}
11
12#[derive(Debug, Serialize)]
13#[cfg_attr(feature = "ts_rs", derive(TS))]
14pub struct ExerciseRepository {
15    pub id: Uuid,
16    pub url: String,
17    pub course_id: Option<Uuid>,
18    pub exam_id: Option<Uuid>,
19    pub status: ExerciseRepositoryStatus,
20    pub error_message: Option<String>,
21}
22
23pub async fn get(conn: &mut PgConnection, id: Uuid) -> ModelResult<ExerciseRepository> {
24    let res = sqlx::query_as!(
25        ExerciseRepository,
26        r#"
27SELECT id,
28  url,
29  course_id,
30  exam_id,
31  status AS "status: ExerciseRepositoryStatus",
32  error_message
33FROM exercise_repositories
34WHERE id = $1
35  AND deleted_at IS NULL
36"#,
37        id
38    )
39    .fetch_one(conn)
40    .await?;
41    Ok(res)
42}
43
44pub async fn new(
45    conn: &mut PgConnection,
46    id: Uuid,
47    course_or_exam_id: CourseOrExamId,
48    url: &str,
49    public_key: Option<&str>,
50    deploy_key: Option<&str>,
51) -> ModelResult<()> {
52    let (course_id, exam_id) = course_or_exam_id.to_course_and_exam_ids();
53    sqlx::query!(
54        "
55INSERT INTO exercise_repositories (id, course_id, exam_id, url, public_key, deploy_key)
56VALUES ($1, $2, $3, $4, $5, $6)
57",
58        id,
59        course_id,
60        exam_id,
61        url,
62        public_key,
63        deploy_key
64    )
65    .execute(conn)
66    .await?;
67    Ok(())
68}
69
70pub async fn mark_success(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
71    sqlx::query!(
72        "
73UPDATE exercise_repositories
74SET status = 'success'
75WHERE id = $1
76",
77        id
78    )
79    .execute(conn)
80    .await?;
81    Ok(())
82}
83
84pub async fn mark_failure(
85    conn: &mut PgConnection,
86    id: Uuid,
87    error_message: &str,
88) -> ModelResult<()> {
89    sqlx::query!(
90        "
91UPDATE exercise_repositories
92SET status = 'failure',
93  error_message = $2
94WHERE id = $1
95",
96        id,
97        error_message
98    )
99    .execute(conn)
100    .await?;
101    Ok(())
102}
103
104pub async fn delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
105    sqlx::query!(
106        "
107UPDATE exercise_repositories
108SET deleted_at = now()
109WHERE id = $1
110AND deleted_at IS NULL
111",
112        id
113    )
114    .execute(conn)
115    .await?;
116    Ok(())
117}
118
119pub async fn get_for_course_or_exam(
120    conn: &mut PgConnection,
121    id: CourseOrExamId,
122) -> ModelResult<Vec<ExerciseRepository>> {
123    let (course_id, exam_id) = id.to_course_and_exam_ids();
124    let res = sqlx::query_as!(
125        ExerciseRepository,
126        r#"
127SELECT id,
128  url,
129  course_id,
130  exam_id,
131  status AS "status: ExerciseRepositoryStatus",
132  error_message
133FROM exercise_repositories
134WHERE (
135    course_id = $1
136    OR exam_id = $2
137  )
138  AND deleted_at IS NULL
139"#,
140        course_id,
141        exam_id
142    )
143    .fetch_all(conn)
144    .await?;
145    Ok(res)
146}
147
148#[derive(Debug, Deserialize)]
149pub struct ExerciseRepositoryUpdate {
150    pub url: String,
151}
152
153pub async fn update(
154    conn: &mut PgConnection,
155    id: Uuid,
156    update: &ExerciseRepositoryUpdate,
157) -> ModelResult<()> {
158    sqlx::query!(
159        "
160UPDATE exercise_repositories SET url = $1 WHERE id = $2
161",
162        update.url,
163        id
164    )
165    .execute(conn)
166    .await?;
167    Ok(())
168}