1use crate::prelude::*;
4
5use headless_lms_models::chatbot_configurations::ChatbotConfiguration;
6use models::{
7 course_instances::CourseInstance,
8 courses::Course,
9 pages::{Page, PageVisibility},
10 partner_block::PartnersBlock,
11 peer_or_self_review_configs::{self, CmsPeerOrSelfReviewConfiguration},
12 peer_or_self_review_questions::normalize_cms_peer_or_self_review_questions,
13};
14
15use crate::prelude::models::course_modules::CourseModule;
16use models::research_forms::{
17 NewResearchForm, NewResearchFormQuestion, ResearchForm, ResearchFormQuestion,
18};
19
20#[instrument(skip(pool))]
24async fn get_course_by_id(
25 path: web::Path<Uuid>,
26 pool: web::Data<PgPool>,
27 user: AuthUser,
28) -> ControllerResult<web::Json<Course>> {
29 let course_id = path.into_inner();
30 let mut conn = pool.acquire().await?;
31 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Course(course_id)).await?;
32 let course = models::courses::get_course(&mut conn, course_id).await?;
33 token.authorized_ok(web::Json(course))
34}
35
36#[instrument(skip(payload, request, pool, file_store, app_conf))]
52async fn add_media(
53 course_id: web::Path<Uuid>,
54 payload: Multipart,
55 request: HttpRequest,
56 pool: web::Data<PgPool>,
57 user: AuthUser,
58 file_store: web::Data<dyn FileStore>,
59 app_conf: web::Data<ApplicationConfiguration>,
60) -> ControllerResult<web::Json<UploadResult>> {
61 let mut conn = pool.acquire().await?;
62 let course = models::courses::get_course(&mut conn, *course_id).await?;
63 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(course.id)).await?;
64
65 let media_path = upload_file_from_cms(
66 request.headers(),
67 payload,
68 StoreKind::Course(course.id),
69 file_store.as_ref(),
70 &mut conn,
71 user,
72 )
73 .await?;
74 let download_url = file_store.get_download_url(media_path.as_path(), app_conf.as_ref());
75
76 token.authorized_ok(web::Json(UploadResult { url: download_url }))
77}
78
79#[instrument(skip(pool))]
80async fn get_course_default_peer_or_self_review_configuration(
81 course_id: web::Path<Uuid>,
82 user: AuthUser,
83 pool: web::Data<PgPool>,
84) -> ControllerResult<web::Json<CmsPeerOrSelfReviewConfiguration>> {
85 let mut conn = pool.acquire().await?;
86 let token = authorize(
87 &mut conn,
88 Act::Teach,
89 Some(user.id),
90 Res::Course(*course_id),
91 )
92 .await?;
93
94 let peer_or_self_review_config =
95 models::peer_or_self_review_configs::get_course_default_cms_peer_review(
96 &mut conn, *course_id,
97 )
98 .await?;
99
100 let peer_or_self_review_questions =
101 models::peer_or_self_review_questions::get_course_default_cms_peer_or_self_review_questions(
102 &mut conn,
103 peer_or_self_review_config.id,
104 )
105 .await?;
106
107 token.authorized_ok(web::Json(CmsPeerOrSelfReviewConfiguration {
108 peer_or_self_review_config,
109 peer_or_self_review_questions,
110 }))
111}
112
113#[instrument(skip(pool))]
114async fn put_course_default_peer_or_self_review_configuration(
115 course_id: web::Path<Uuid>,
116 user: AuthUser,
117 pool: web::Data<PgPool>,
118 payload: web::Json<CmsPeerOrSelfReviewConfiguration>,
119) -> ControllerResult<web::Json<CmsPeerOrSelfReviewConfiguration>> {
120 let mut conn = pool.acquire().await?;
121 let token = authorize(
122 &mut conn,
123 Act::Teach,
124 Some(user.id),
125 Res::Course(*course_id),
126 )
127 .await?;
128 let mut config = payload.0;
129 normalize_cms_peer_or_self_review_questions(&mut config.peer_or_self_review_questions);
130 let cms_peer_or_self_review_configuration =
131 peer_or_self_review_configs::upsert_course_default_cms_peer_review_and_questions(
132 &mut conn, &config,
133 )
134 .await?;
135 token.authorized_ok(web::Json(cms_peer_or_self_review_configuration))
136}
137
138#[instrument(skip(pool))]
142async fn get_all_pages(
143 course_id: web::Path<Uuid>,
144 pool: web::Data<PgPool>,
145 user: AuthUser,
146) -> ControllerResult<web::Json<Vec<Page>>> {
147 let mut conn = pool.acquire().await?;
148 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
149
150 let res = models::pages::get_all_by_course_id_and_visibility(
151 &mut conn,
152 *course_id,
153 PageVisibility::Any,
154 )
155 .await?;
156
157 token.authorized_ok(web::Json(res))
158}
159
160#[instrument(skip(pool, payload))]
165async fn upsert_course_research_form(
166 payload: web::Json<NewResearchForm>,
167 pool: web::Data<PgPool>,
168 course_id: web::Path<Uuid>,
169 user: AuthUser,
170) -> ControllerResult<web::Json<ResearchForm>> {
171 let mut conn = pool.acquire().await?;
172
173 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::GlobalPermissions).await?;
174 let new_research_form = payload;
175 let res = models::research_forms::upsert_research_form(
176 &mut conn,
177 PKeyPolicy::Generate,
178 &new_research_form,
179 )
180 .await?;
181
182 token.authorized_ok(web::Json(res))
183}
184
185#[instrument(skip(pool))]
189async fn get_research_form_with_course_id(
190 course_id: web::Path<Uuid>,
191 user: AuthUser,
192 pool: web::Data<PgPool>,
193) -> ControllerResult<web::Json<Option<ResearchForm>>> {
194 let mut conn = pool.acquire().await?;
195
196 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::GlobalPermissions).await?;
197 let res = models::research_forms::get_research_form_with_course_id(&mut conn, *course_id)
198 .await
199 .optional()?;
200
201 token.authorized_ok(web::Json(res))
202}
203
204#[instrument(skip(pool, payload))]
209async fn upsert_course_research_form_questions(
210 payload: web::Json<Vec<NewResearchFormQuestion>>,
211 pool: web::Data<PgPool>,
212 course_id: web::Path<Uuid>,
213 user: AuthUser,
214) -> ControllerResult<web::Json<Vec<ResearchFormQuestion>>> {
215 let mut conn = pool.acquire().await?;
216
217 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::GlobalPermissions).await?;
218
219 let res = models::research_forms::upsert_research_form_questions(&mut conn, &payload).await?;
220
221 token.authorized_ok(web::Json(res))
222}
223
224#[instrument(skip(pool))]
229async fn get_course_modules(
230 course_id: web::Path<Uuid>,
231 user: AuthUser,
232 pool: web::Data<PgPool>,
233) -> ControllerResult<web::Json<Vec<CourseModule>>> {
234 let mut conn = pool.acquire().await?;
235 let course_modules = models::course_modules::get_by_course_id(&mut conn, *course_id).await?;
236 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
237 token.authorized_ok(web::Json(course_modules))
238}
239
240#[instrument(skip(pool))]
244async fn get_course_instances(
245 course_id: web::Path<Uuid>,
246 user: AuthUser,
247 pool: web::Data<PgPool>,
248) -> ControllerResult<web::Json<Vec<CourseInstance>>> {
249 let mut conn = pool.acquire().await?;
250 let instances =
251 models::course_instances::get_course_instances_for_course(&mut conn, *course_id).await?;
252 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
253 token.authorized_ok(web::Json(instances))
254}
255
256#[instrument(skip(payload, pool))]
260async fn post_partners_block(
261 path: web::Path<Uuid>,
262 payload: web::Json<Option<serde_json::Value>>,
263 pool: web::Data<PgPool>,
264 user: AuthUser,
265) -> ControllerResult<web::Json<()>> {
266 let course_id = path.into_inner();
267
268 let content = payload.into_inner();
269 let mut conn = pool.acquire().await?;
270 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Course(course_id)).await?;
271
272 models::partner_block::upsert_partner_block(&mut conn, course_id, content).await?;
273
274 token.authorized_ok(web::Json(()))
275}
276
277#[instrument(skip(pool))]
281async fn get_partners_block(
282 path: web::Path<Uuid>,
283 user: AuthUser,
284 pool: web::Data<PgPool>,
285) -> ControllerResult<web::Json<PartnersBlock>> {
286 let course_id = path.into_inner();
287 let mut conn = pool.acquire().await?;
288 let token = skip_authorize();
289
290 let course_exists = models::partner_block::check_if_course_exists(&mut conn, course_id).await?;
292
293 let partner_block = if course_exists {
294 models::partner_block::get_partner_block(&mut conn, course_id).await?
296 } else {
297 let empty_content: Option<serde_json::Value> = Some(serde_json::Value::Array(vec![]));
299
300 models::partner_block::upsert_partner_block(&mut conn, course_id, empty_content).await?
302 };
303
304 token.authorized_ok(web::Json(partner_block))
305}
306
307#[instrument(skip(pool))]
311async fn delete_partners_block(
312 path: web::Path<Uuid>,
313 pool: web::Data<PgPool>,
314 user: AuthUser,
315) -> ControllerResult<web::Json<PartnersBlock>> {
316 let course_id = path.into_inner();
317 let mut conn = pool.acquire().await?;
318 let token = authorize(
319 &mut conn,
320 Act::UsuallyUnacceptableDeletion,
321 Some(user.id),
322 Res::Course(course_id),
323 )
324 .await?;
325 let deleted_partners_block =
326 models::partner_block::delete_partner_block(&mut conn, course_id).await?;
327
328 token.authorized_ok(web::Json(deleted_partners_block))
329}
330
331#[instrument(skip(pool))]
335async fn get_course_nondefault_chatbot_configurations(
336 path: web::Path<Uuid>,
337 pool: web::Data<PgPool>,
338 user: AuthUser,
339) -> ControllerResult<web::Json<Vec<ChatbotConfiguration>>> {
340 let course_id = path.into_inner();
341 let mut conn = pool.acquire().await?;
342 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Course(course_id)).await?;
343 let course_chatbot_configurations =
344 models::chatbot_configurations::get_enabled_nondefault_for_course(&mut conn, course_id)
345 .await?;
346 token.authorized_ok(web::Json(course_chatbot_configurations))
347}
348
349pub fn _add_routes(cfg: &mut ServiceConfig) {
357 cfg.route("/{course_id}", web::get().to(get_course_by_id))
358 .route("/{course_id}/upload", web::post().to(add_media))
359 .route(
360 "/{course_id}/default-peer-review",
361 web::get().to(get_course_default_peer_or_self_review_configuration),
362 )
363 .route(
364 "/{course_id}/default-peer-review",
365 web::put().to(put_course_default_peer_or_self_review_configuration),
366 )
367 .route("/{course_id}/pages", web::get().to(get_all_pages))
368 .route(
369 "/{courseId}/research-consent-form-questions",
370 web::put().to(upsert_course_research_form_questions),
371 )
372 .route(
373 "/{course_id}/research-consent-form",
374 web::get().to(get_research_form_with_course_id),
375 )
376 .route(
377 "/{course_id}/research-consent-form",
378 web::put().to(upsert_course_research_form),
379 )
380 .route(
381 "/{course_id}/partners-block",
382 web::post().to(post_partners_block),
383 )
384 .route(
385 "/{course_id}/partners-block",
386 web::get().to(get_partners_block),
387 )
388 .route(
389 "/{course_id}/partners-block",
390 web::delete().to(delete_partners_block),
391 )
392 .route("/{course_id}/modules", web::get().to(get_course_modules))
393 .route(
394 "/{course_id}/course-instances",
395 web::get().to(get_course_instances),
396 )
397 .route(
398 "/{course_id}/nondefault-chatbot-configurations",
399 web::get().to(get_course_nondefault_chatbot_configurations),
400 );
401}