headless_lms_server/controllers/cms/
courses.rs1use crate::prelude::*;
4
5use models::{
6 course_instances::CourseInstance,
7 pages::{Page, PageVisibility},
8 partner_block::PartnersBlock,
9 peer_or_self_review_configs::{self, CmsPeerOrSelfReviewConfiguration},
10 peer_or_self_review_questions::normalize_cms_peer_or_self_review_questions,
11};
12
13use crate::prelude::models::course_modules::CourseModule;
14use models::research_forms::{
15 NewResearchForm, NewResearchFormQuestion, ResearchForm, ResearchFormQuestion,
16};
17
18#[instrument(skip(payload, request, pool, file_store, app_conf))]
34async fn add_media(
35 course_id: web::Path<Uuid>,
36 payload: Multipart,
37 request: HttpRequest,
38 pool: web::Data<PgPool>,
39 user: AuthUser,
40 file_store: web::Data<dyn FileStore>,
41 app_conf: web::Data<ApplicationConfiguration>,
42) -> ControllerResult<web::Json<UploadResult>> {
43 let mut conn = pool.acquire().await?;
44 let course = models::courses::get_course(&mut conn, *course_id).await?;
45 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(course.id)).await?;
46
47 let media_path = upload_file_from_cms(
48 request.headers(),
49 payload,
50 StoreKind::Course(course.id),
51 file_store.as_ref(),
52 &mut conn,
53 user,
54 )
55 .await?;
56 let download_url = file_store.get_download_url(media_path.as_path(), app_conf.as_ref());
57
58 token.authorized_ok(web::Json(UploadResult { url: download_url }))
59}
60
61#[instrument(skip(pool))]
62async fn get_course_default_peer_or_self_review_configuration(
63 course_id: web::Path<Uuid>,
64 user: AuthUser,
65 pool: web::Data<PgPool>,
66) -> ControllerResult<web::Json<CmsPeerOrSelfReviewConfiguration>> {
67 let mut conn = pool.acquire().await?;
68 let token = authorize(
69 &mut conn,
70 Act::Teach,
71 Some(user.id),
72 Res::Course(*course_id),
73 )
74 .await?;
75
76 let peer_or_self_review_config =
77 models::peer_or_self_review_configs::get_course_default_cms_peer_review(
78 &mut conn, *course_id,
79 )
80 .await?;
81
82 let peer_or_self_review_questions =
83 models::peer_or_self_review_questions::get_course_default_cms_peer_or_self_review_questions(
84 &mut conn,
85 peer_or_self_review_config.id,
86 )
87 .await?;
88
89 token.authorized_ok(web::Json(CmsPeerOrSelfReviewConfiguration {
90 peer_or_self_review_config,
91 peer_or_self_review_questions,
92 }))
93}
94
95#[instrument(skip(pool))]
96async fn put_course_default_peer_or_self_review_configuration(
97 course_id: web::Path<Uuid>,
98 user: AuthUser,
99 pool: web::Data<PgPool>,
100 payload: web::Json<CmsPeerOrSelfReviewConfiguration>,
101) -> ControllerResult<web::Json<CmsPeerOrSelfReviewConfiguration>> {
102 let mut conn = pool.acquire().await?;
103 let token = authorize(
104 &mut conn,
105 Act::Teach,
106 Some(user.id),
107 Res::Course(*course_id),
108 )
109 .await?;
110 let mut config = payload.0;
111 normalize_cms_peer_or_self_review_questions(&mut config.peer_or_self_review_questions);
112 let cms_peer_or_self_review_configuration =
113 peer_or_self_review_configs::upsert_course_default_cms_peer_review_and_questions(
114 &mut conn, &config,
115 )
116 .await?;
117 token.authorized_ok(web::Json(cms_peer_or_self_review_configuration))
118}
119
120#[instrument(skip(pool))]
124async fn get_all_pages(
125 course_id: web::Path<Uuid>,
126 pool: web::Data<PgPool>,
127 user: AuthUser,
128) -> ControllerResult<web::Json<Vec<Page>>> {
129 let mut conn = pool.acquire().await?;
130 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
131
132 let res = models::pages::get_all_by_course_id_and_visibility(
133 &mut conn,
134 *course_id,
135 PageVisibility::Any,
136 )
137 .await?;
138
139 token.authorized_ok(web::Json(res))
140}
141
142#[instrument(skip(pool, payload))]
147async fn upsert_course_research_form(
148 payload: web::Json<NewResearchForm>,
149 pool: web::Data<PgPool>,
150 course_id: web::Path<Uuid>,
151 user: AuthUser,
152) -> ControllerResult<web::Json<ResearchForm>> {
153 let mut conn = pool.acquire().await?;
154
155 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::GlobalPermissions).await?;
156 let new_research_form = payload;
157 let res = models::research_forms::upsert_research_form(
158 &mut conn,
159 PKeyPolicy::Generate,
160 &new_research_form,
161 )
162 .await?;
163
164 token.authorized_ok(web::Json(res))
165}
166
167#[instrument(skip(pool))]
171async fn get_research_form_with_course_id(
172 course_id: web::Path<Uuid>,
173 user: AuthUser,
174 pool: web::Data<PgPool>,
175) -> ControllerResult<web::Json<Option<ResearchForm>>> {
176 let mut conn = pool.acquire().await?;
177
178 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::GlobalPermissions).await?;
179 let res = models::research_forms::get_research_form_with_course_id(&mut conn, *course_id)
180 .await
181 .optional()?;
182
183 token.authorized_ok(web::Json(res))
184}
185
186#[instrument(skip(pool, payload))]
191async fn upsert_course_research_form_questions(
192 payload: web::Json<Vec<NewResearchFormQuestion>>,
193 pool: web::Data<PgPool>,
194 course_id: web::Path<Uuid>,
195 user: AuthUser,
196) -> ControllerResult<web::Json<Vec<ResearchFormQuestion>>> {
197 let mut conn = pool.acquire().await?;
198
199 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::GlobalPermissions).await?;
200
201 let res = models::research_forms::upsert_research_form_questions(&mut conn, &payload).await?;
202
203 token.authorized_ok(web::Json(res))
204}
205
206#[instrument(skip(pool))]
211async fn get_course_modules(
212 course_id: web::Path<Uuid>,
213 user: AuthUser,
214 pool: web::Data<PgPool>,
215) -> ControllerResult<web::Json<Vec<CourseModule>>> {
216 let mut conn = pool.acquire().await?;
217 let course_modules = models::course_modules::get_by_course_id(&mut conn, *course_id).await?;
218 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
219 token.authorized_ok(web::Json(course_modules))
220}
221
222#[instrument(skip(pool))]
226async fn get_course_instances(
227 course_id: web::Path<Uuid>,
228 user: AuthUser,
229 pool: web::Data<PgPool>,
230) -> ControllerResult<web::Json<Vec<CourseInstance>>> {
231 let mut conn = pool.acquire().await?;
232 let instances =
233 models::course_instances::get_course_instances_for_course(&mut conn, *course_id).await?;
234 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
235 token.authorized_ok(web::Json(instances))
236}
237
238#[instrument(skip(payload, pool))]
242async fn post_partners_block(
243 path: web::Path<Uuid>,
244 payload: web::Json<Option<serde_json::Value>>,
245 pool: web::Data<PgPool>,
246 user: AuthUser,
247) -> ControllerResult<web::Json<()>> {
248 let course_id = path.into_inner();
249
250 let content = payload.into_inner();
251 let mut conn = pool.acquire().await?;
252 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Course(course_id)).await?;
253
254 models::partner_block::upsert_partner_block(&mut conn, course_id, content).await?;
255
256 token.authorized_ok(web::Json(()))
257}
258
259#[instrument(skip(pool))]
263async fn get_partners_block(
264 path: web::Path<Uuid>,
265 user: AuthUser,
266 pool: web::Data<PgPool>,
267) -> ControllerResult<web::Json<PartnersBlock>> {
268 let course_id = path.into_inner();
269 let mut conn = pool.acquire().await?;
270 let token = skip_authorize();
271
272 let course_exists = models::partner_block::check_if_course_exists(&mut conn, course_id).await?;
274
275 let partner_block = if course_exists {
276 models::partner_block::get_partner_block(&mut conn, course_id).await?
278 } else {
279 let empty_content: Option<serde_json::Value> = Some(serde_json::Value::Array(vec![]));
281
282 models::partner_block::upsert_partner_block(&mut conn, course_id, empty_content).await?
284 };
285
286 token.authorized_ok(web::Json(partner_block))
287}
288
289#[instrument(skip(pool))]
293async fn delete_partners_block(
294 path: web::Path<Uuid>,
295 pool: web::Data<PgPool>,
296 user: AuthUser,
297) -> ControllerResult<web::Json<PartnersBlock>> {
298 let course_id = path.into_inner();
299 let mut conn = pool.acquire().await?;
300 let token = authorize(
301 &mut conn,
302 Act::UsuallyUnacceptableDeletion,
303 Some(user.id),
304 Res::Course(course_id),
305 )
306 .await?;
307 let deleted_partners_block =
308 models::partner_block::delete_partner_block(&mut conn, course_id).await?;
309
310 token.authorized_ok(web::Json(deleted_partners_block))
311}
312
313pub fn _add_routes(cfg: &mut ServiceConfig) {
321 cfg.route("/{course_id}/upload", web::post().to(add_media))
322 .route(
323 "/{course_id}/default-peer-review",
324 web::get().to(get_course_default_peer_or_self_review_configuration),
325 )
326 .route(
327 "/{course_id}/default-peer-review",
328 web::put().to(put_course_default_peer_or_self_review_configuration),
329 )
330 .route("/{course_id}/pages", web::get().to(get_all_pages))
331 .route(
332 "/{courseId}/research-consent-form-questions",
333 web::put().to(upsert_course_research_form_questions),
334 )
335 .route(
336 "/{course_id}/research-consent-form",
337 web::get().to(get_research_form_with_course_id),
338 )
339 .route(
340 "/{course_id}/research-consent-form",
341 web::put().to(upsert_course_research_form),
342 )
343 .route(
344 "/{course_id}/partners-block",
345 web::post().to(post_partners_block),
346 )
347 .route(
348 "/{course_id}/partners-block",
349 web::get().to(get_partners_block),
350 )
351 .route(
352 "/{course_id}/partners-block",
353 web::delete().to(delete_partners_block),
354 )
355 .route("/{course_id}/modules", web::get().to(get_course_modules))
356 .route(
357 "/{course_id}/course-instances",
358 web::get().to(get_course_instances),
359 );
360}