headless_lms_server/controllers/main_frontend/
exercise_services.rs1use headless_lms_models::{ModelError, exercise_service_info::fetch_and_upsert_service_info};
4use models::exercise_services::{ExerciseService, ExerciseServiceNewOrUpdate};
5use utoipa::{OpenApi, ToSchema};
6
7use crate::{domain::models_requests, prelude::*};
8
9#[derive(OpenApi)]
13#[openapi(paths(
14 delete_exercise_service,
15 add_exercise_service,
16 get_exercise_service_by_id,
17 get_exercise_services,
18 update_exercise_service
19))]
20pub(crate) struct MainFrontendExerciseServicesApiDoc;
21
22#[utoipa::path(
23 delete,
24 path = "/{exercise_service_id}",
25 operation_id = "deleteExerciseService",
26 tag = "exercise_services",
27 params(
28 ("exercise_service_id" = Uuid, Path, description = "Exercise service id")
29 ),
30 responses(
31 (status = 200, description = "Deleted exercise service", body = ExerciseService)
32 )
33)]
34#[instrument(skip(pool))]
35async fn delete_exercise_service(
36 exercise_service_id: web::Path<Uuid>,
37 pool: web::Data<PgPool>,
38 user: AuthUser,
39) -> ControllerResult<web::Json<ExerciseService>> {
40 let mut conn = pool.acquire().await?;
41 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::ExerciseService).await?;
42
43 let deleted =
44 models::exercise_services::delete_exercise_service(&mut conn, *exercise_service_id).await?;
45
46 token.authorized_ok(web::Json(deleted))
47}
48
49#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
50
51pub struct ExerciseServiceWithError {
52 exercise_service: ExerciseService,
53 service_info_error: Option<String>,
54}
55
56#[utoipa::path(
60 post,
61 path = "/",
62 operation_id = "createExerciseService",
63 tag = "exercise_services",
64 request_body = ExerciseServiceNewOrUpdate,
65 responses(
66 (status = 200, description = "Created exercise service", body = ExerciseServiceWithError)
67 )
68)]
69#[instrument(skip(pool))]
70async fn add_exercise_service(
71 pool: web::Data<PgPool>,
72 user: AuthUser,
73 payload: web::Json<ExerciseServiceNewOrUpdate>,
74) -> ControllerResult<web::Json<ExerciseServiceWithError>> {
75 let mut conn = pool.acquire().await?;
76 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::ExerciseService).await?;
77
78 let exercise_service = payload.0;
79 let exercise_service =
80 models::exercise_services::insert_exercise_service(&mut conn, &exercise_service).await?;
81
82 let exercise_service_with_error =
83 try_to_get_exercise_service_info(&mut conn, exercise_service).await?;
84 token.authorized_ok(web::Json(exercise_service_with_error))
85}
86
87#[utoipa::path(
91 get,
92 path = "/{exercise_service_id}",
93 operation_id = "getExerciseServiceById",
94 tag = "exercise_services",
95 params(
96 ("exercise_service_id" = Uuid, Path, description = "Exercise service id")
97 ),
98 responses(
99 (status = 200, description = "Exercise service", body = ExerciseService)
100 )
101)]
102#[instrument(skip(pool))]
103async fn get_exercise_service_by_id(
104 exercise_service_id: web::Path<Uuid>,
105 pool: web::Data<PgPool>,
106 user: AuthUser,
107) -> ControllerResult<web::Json<ExerciseService>> {
108 let mut conn = pool.acquire().await?;
109 let exercise_service =
110 models::exercise_services::get_exercise_service(&mut conn, *exercise_service_id).await?;
111
112 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::ExerciseService).await?;
113 token.authorized_ok(web::Json(exercise_service))
114}
115
116#[utoipa::path(
120 get,
121 path = "/",
122 operation_id = "getExerciseServices",
123 tag = "exercise_services",
124 responses(
125 (status = 200, description = "Exercise services", body = Vec<ExerciseService>)
126 )
127)]
128#[instrument(skip(pool))]
129async fn get_exercise_services(
130 pool: web::Data<PgPool>,
131 user: AuthUser,
132) -> ControllerResult<web::Json<Vec<ExerciseService>>> {
133 let mut conn = pool.acquire().await?;
134 let exercise_services = models::exercise_services::get_exercise_services(&mut conn).await?;
135
136 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::ExerciseService).await?;
137 token.authorized_ok(web::Json(exercise_services))
138}
139
140#[utoipa::path(
144 put,
145 path = "/{exercise_service_id}",
146 operation_id = "updateExerciseService",
147 tag = "exercise_services",
148 params(
149 ("exercise_service_id" = Uuid, Path, description = "Exercise service id")
150 ),
151 request_body = ExerciseServiceNewOrUpdate,
152 responses(
153 (status = 200, description = "Updated exercise service", body = ExerciseServiceWithError)
154 )
155)]
156#[instrument(skip(pool))]
157async fn update_exercise_service(
158 payload: web::Json<ExerciseServiceNewOrUpdate>,
159 exercise_service_id: web::Path<Uuid>,
160 pool: web::Data<PgPool>,
161 user: AuthUser,
162) -> ControllerResult<web::Json<ExerciseServiceWithError>> {
163 let mut conn = pool.acquire().await?;
164 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::ExerciseService).await?;
165
166 let updated_exercise_service = payload.0;
167 let updated_service = models::exercise_services::update_exercise_service(
168 &mut conn,
169 *exercise_service_id,
170 &updated_exercise_service,
171 )
172 .await?;
173
174 let exercise_service_with_error =
175 try_to_get_exercise_service_info(&mut conn, updated_service).await?;
176 token.authorized_ok(web::Json(exercise_service_with_error))
177}
178
179async fn try_to_get_exercise_service_info(
180 conn: &mut PgConnection,
181 exercise_service: ExerciseService,
182) -> Result<ExerciseServiceWithError, ModelError> {
183 let service_info_error = if let Err(err) = fetch_and_upsert_service_info(
185 conn,
186 &exercise_service,
187 models_requests::fetch_service_info_fast,
188 )
189 .await
190 {
191 tracing::warn!(
192 "Failed to get exercise service info for new exercise service {}: {err}",
193 exercise_service.name
194 );
195 Some(err.to_string())
196 } else {
197 None
198 };
199
200 let with_error = ExerciseServiceWithError {
201 exercise_service,
202 service_info_error,
203 };
204 Ok(with_error)
205}
206
207pub fn _add_routes(cfg: &mut ServiceConfig) {
215 cfg.route("/", web::post().to(add_exercise_service))
216 .route("/", web::get().to(get_exercise_services))
217 .route(
218 "/{exercise_service_id}",
219 web::delete().to(delete_exercise_service),
220 )
221 .route(
222 "/{exercise_service_id}",
223 web::put().to(update_exercise_service),
224 )
225 .route(
226 "/{exercise_service_id}",
227 web::get().to(get_exercise_service_by_id),
228 );
229}