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}