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 = CourseOrExamId::from(repository.course_id, repository.exam_id)?;
34 let token = authorize(
35 &mut conn,
36 Act::Edit,
37 Some(user.id),
38 Res::from_course_or_exam_id(course_or_exam_id),
39 )
40 .await?;
41 let new_repository_id = Uuid::new_v4();
43 models::exercise_repositories::new(
44 &mut conn,
45 new_repository_id,
46 course_or_exam_id,
47 &repository.git_url,
48 repository.public_key.as_deref(),
49 repository.deploy_key.as_deref(),
50 )
51 .await?;
52 actix_web::rt::spawn(async move {
54 let file_store = file_store;
55 if let Err(err) = domain::exercise_repositories::process(
56 &mut conn,
57 new_repository_id,
58 &repository.git_url,
59 repository.public_key.as_deref(),
60 repository.deploy_key.as_deref(),
61 file_store.as_ref(),
62 app_conf.as_ref(),
63 )
64 .await
65 {
66 tracing::error!("Error while processing repository {new_repository_id}: {err}");
67 }
68 });
69 token.authorized_ok(web::Json(new_repository_id))
70}
71
72#[instrument(skip(pool))]
76async fn get_for_course(
77 pool: web::Data<PgPool>,
78 course_id: web::Path<Uuid>,
79 user: Option<AuthUser>,
80) -> ControllerResult<web::Json<Vec<ExerciseRepository>>> {
81 let mut conn = pool.acquire().await?;
82 let token = authorize(
83 &mut conn,
84 Act::View,
85 user.map(|u| u.id),
86 Res::Course(*course_id),
87 )
88 .await?;
89 let repos = models::exercise_repositories::get_for_course_or_exam(
90 &mut conn,
91 CourseOrExamId::Course(*course_id),
92 )
93 .await?;
94 token.authorized_ok(web::Json(repos))
95}
96
97#[instrument(skip(pool))]
101async fn get_for_exam(
102 pool: web::Data<PgPool>,
103 exam_id: web::Path<Uuid>,
104 user: Option<AuthUser>,
105) -> ControllerResult<web::Json<Vec<ExerciseRepository>>> {
106 let mut conn = pool.acquire().await?;
107 let token = authorize(
108 &mut conn,
109 Act::View,
110 user.map(|u| u.id),
111 Res::Exam(*exam_id),
112 )
113 .await?;
114 let repos = models::exercise_repositories::get_for_course_or_exam(
115 &mut conn,
116 CourseOrExamId::Exam(*exam_id),
117 )
118 .await?;
119 token.authorized_ok(web::Json(repos))
120}
121
122#[instrument(skip(pool))]
126async fn delete(
127 pool: web::Data<PgPool>,
128 id: web::Path<Uuid>,
129 user: Option<AuthUser>,
130) -> ControllerResult<web::Json<bool>> {
131 let mut conn = pool.acquire().await?;
132 let repository = models::exercise_repositories::get(&mut conn, *id).await?;
133 let course_or_exam_id = CourseOrExamId::from(repository.course_id, repository.exam_id)?;
134 let token = authorize(
135 &mut conn,
136 Act::Edit,
137 user.map(|u| u.id),
138 Res::from_course_or_exam_id(course_or_exam_id),
139 )
140 .await?;
141
142 let mut tx = conn.begin().await?;
143 models::repository_exercises::delete_from_repository(&mut tx, *id).await?;
144 models::exercise_repositories::delete(&mut tx, *id).await?;
145 tx.commit().await?;
146
147 token.authorized_ok(web::Json(true))
148}
149
150#[instrument(skip(pool))]
154async fn update(
155 pool: web::Data<PgPool>,
156 id: web::Path<Uuid>,
157 user: Option<AuthUser>,
158 update: web::Json<ExerciseRepositoryUpdate>,
159) -> ControllerResult<web::Json<bool>> {
160 let mut conn = pool.acquire().await?;
161 let repository = models::exercise_repositories::get(&mut conn, *id).await?;
162 let course_or_exam_id = CourseOrExamId::from(repository.course_id, repository.exam_id)?;
163 let token = authorize(
164 &mut conn,
165 Act::Edit,
166 user.map(|u| u.id),
167 Res::from_course_or_exam_id(course_or_exam_id),
168 )
169 .await?;
170
171 models::exercise_repositories::update(&mut conn, *id, update.deref()).await?;
172 token.authorized_ok(web::Json(true))
173}
174
175pub fn _add_routes(cfg: &mut ServiceConfig) {
183 cfg.route("/new", web::post().to(new))
184 .route("/course/{course_id}", web::get().to(get_for_course))
185 .route("/exam/{exam_id}", web::get().to(get_for_exam))
186 .route("/{id}", web::delete().to(delete))
187 .route("/{id}", web::put().to(update));
188}