headless_lms_server/controllers/main_frontend/
exercise_repositories.rs1use std::ops::Deref;
2
3use models::{
4 CourseOrExamId,
5 exercise_repositories::{ExerciseRepository, ExerciseRepositoryUpdate},
6};
7
8use crate::{domain, prelude::*};
9
10#[derive(Debug, Deserialize)]
11#[cfg_attr(feature = "ts_rs", derive(TS))]
12pub struct NewExerciseRepository {
13 course_id: Option<Uuid>,
14 exam_id: Option<Uuid>,
15 git_url: String,
16 public_key: Option<String>,
17 deploy_key: Option<String>,
18}
19
20#[instrument(skip(pool, file_store, app_conf))]
25async fn new(
26 pool: web::Data<PgPool>,
27 file_store: web::Data<dyn FileStore>,
28 repository: web::Json<NewExerciseRepository>,
29 user: AuthUser,
30 app_conf: web::Data<ApplicationConfiguration>,
31) -> ControllerResult<web::Json<Uuid>> {
32 let mut conn = pool.acquire().await?;
33 let course_or_exam_id =
34 CourseOrExamId::from_course_and_exam_ids(repository.course_id, repository.exam_id)?;
35 let token = authorize(
36 &mut conn,
37 Act::Edit,
38 Some(user.id),
39 Res::from_course_or_exam_id(course_or_exam_id),
40 )
41 .await?;
42 let new_repository_id = Uuid::new_v4();
44 models::exercise_repositories::new(
45 &mut conn,
46 new_repository_id,
47 course_or_exam_id,
48 &repository.git_url,
49 repository.public_key.as_deref(),
50 repository.deploy_key.as_deref(),
51 )
52 .await?;
53 actix_web::rt::spawn(async move {
55 let file_store = file_store;
56 if let Err(err) = domain::exercise_repositories::process(
57 &mut conn,
58 new_repository_id,
59 &repository.git_url,
60 repository.public_key.as_deref(),
61 repository.deploy_key.as_deref(),
62 file_store.as_ref(),
63 app_conf.as_ref(),
64 )
65 .await
66 {
67 tracing::error!("Error while processing repository {new_repository_id}: {err}");
68 }
69 });
70 token.authorized_ok(web::Json(new_repository_id))
71}
72
73#[instrument(skip(pool))]
77async fn get_for_course(
78 pool: web::Data<PgPool>,
79 course_id: web::Path<Uuid>,
80 user: Option<AuthUser>,
81) -> ControllerResult<web::Json<Vec<ExerciseRepository>>> {
82 let mut conn = pool.acquire().await?;
83 let token = authorize(
84 &mut conn,
85 Act::View,
86 user.map(|u| u.id),
87 Res::Course(*course_id),
88 )
89 .await?;
90 let repos = models::exercise_repositories::get_for_course_or_exam(
91 &mut conn,
92 CourseOrExamId::Course(*course_id),
93 )
94 .await?;
95 token.authorized_ok(web::Json(repos))
96}
97
98#[instrument(skip(pool))]
102async fn get_for_exam(
103 pool: web::Data<PgPool>,
104 exam_id: web::Path<Uuid>,
105 user: Option<AuthUser>,
106) -> ControllerResult<web::Json<Vec<ExerciseRepository>>> {
107 let mut conn = pool.acquire().await?;
108 let token = authorize(
109 &mut conn,
110 Act::View,
111 user.map(|u| u.id),
112 Res::Exam(*exam_id),
113 )
114 .await?;
115 let repos = models::exercise_repositories::get_for_course_or_exam(
116 &mut conn,
117 CourseOrExamId::Exam(*exam_id),
118 )
119 .await?;
120 token.authorized_ok(web::Json(repos))
121}
122
123#[instrument(skip(pool))]
127async fn delete(
128 pool: web::Data<PgPool>,
129 id: web::Path<Uuid>,
130 user: Option<AuthUser>,
131) -> ControllerResult<web::Json<bool>> {
132 let mut conn = pool.acquire().await?;
133 let repository = models::exercise_repositories::get(&mut conn, *id).await?;
134 let course_or_exam_id =
135 CourseOrExamId::from_course_and_exam_ids(repository.course_id, repository.exam_id)?;
136 let token = authorize(
137 &mut conn,
138 Act::Edit,
139 user.map(|u| u.id),
140 Res::from_course_or_exam_id(course_or_exam_id),
141 )
142 .await?;
143
144 let mut tx = conn.begin().await?;
145 models::repository_exercises::delete_from_repository(&mut tx, *id).await?;
146 models::exercise_repositories::delete(&mut tx, *id).await?;
147 tx.commit().await?;
148
149 token.authorized_ok(web::Json(true))
150}
151
152#[instrument(skip(pool))]
156async fn update(
157 pool: web::Data<PgPool>,
158 id: web::Path<Uuid>,
159 user: Option<AuthUser>,
160 update: web::Json<ExerciseRepositoryUpdate>,
161) -> ControllerResult<web::Json<bool>> {
162 let mut conn = pool.acquire().await?;
163 let repository = models::exercise_repositories::get(&mut conn, *id).await?;
164 let course_or_exam_id =
165 CourseOrExamId::from_course_and_exam_ids(repository.course_id, repository.exam_id)?;
166 let token = authorize(
167 &mut conn,
168 Act::Edit,
169 user.map(|u| u.id),
170 Res::from_course_or_exam_id(course_or_exam_id),
171 )
172 .await?;
173
174 models::exercise_repositories::update(&mut conn, *id, update.deref()).await?;
175 token.authorized_ok(web::Json(true))
176}
177
178pub fn _add_routes(cfg: &mut ServiceConfig) {
186 cfg.route("/new", web::post().to(new))
187 .route("/course/{course_id}", web::get().to(get_for_course))
188 .route("/exam/{exam_id}", web::get().to(get_for_exam))
189 .route("/{id}", web::delete().to(delete))
190 .route("/{id}", web::put().to(update));
191}