headless_lms_server/controllers/cms/
exams.rs

1//! Controllers for requests starting with `/api/v0/cms/organizations`.
2
3use models::exams::{ExamInstructions, ExamInstructionsUpdate};
4
5use crate::prelude::*;
6
7/**
8POST `/api/v0/cms/exams/:exam_id/upload` - Uploads a media (image, audio, file) for the course from Gutenberg page edit.
9
10Put the the contents of the media in a form and add a content type header multipart/form-data.
11# Example
12
13Request:
14```http
15POST /api/v0/cms/pages/d86cf910-4d26-40e9-8c9c-1cc35294fdbb/upload HTTP/1.1
16Content-Type: multipart/form-data
17
18BINARY_DATA
19```
20*/
21
22#[instrument(skip(payload, request, file_store, app_conf))]
23async fn add_media(
24    pool: web::Data<PgPool>,
25    exam_id: web::Path<Uuid>,
26    payload: Multipart,
27    request: HttpRequest,
28    user: AuthUser,
29    file_store: web::Data<dyn FileStore>,
30    app_conf: web::Data<ApplicationConfiguration>,
31) -> ControllerResult<web::Json<UploadResult>> {
32    let mut conn = pool.acquire().await?;
33    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Exam(*exam_id)).await?;
34    let media_path = upload_file_from_cms(
35        request.headers(),
36        payload,
37        StoreKind::Exam(*exam_id),
38        file_store.as_ref(),
39        &mut conn,
40        user,
41    )
42    .await?;
43    let download_url = file_store.get_download_url(media_path.as_path(), app_conf.as_ref());
44
45    token.authorized_ok(web::Json(UploadResult { url: download_url }))
46}
47
48/**
49GET `/api/v0/cms/exams/:exam_id/edit` - Get the exam instructions for Gutenberg Editor.
50*/
51#[instrument(skip(pool))]
52async fn get_exam_instructions(
53    pool: web::Data<PgPool>,
54    exam_id: web::Path<Uuid>,
55    user: AuthUser,
56) -> ControllerResult<web::Json<ExamInstructions>> {
57    let mut conn = pool.acquire().await?;
58    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Exam(*exam_id)).await?;
59    let exam_instructions_data =
60        models::exams::get_exam_instructions_data(&mut conn, *exam_id).await?;
61
62    token.authorized_ok(web::Json(exam_instructions_data))
63}
64
65/**
66PUT `/api/v0/cms/exams/:exam_id/edit` - Insert new instructions from Gutenberg editor.
67
68# Example
69
70Request:
71```http
72PUT /api/v0/cms/exams/d86cf910-4d26-40e9-8c9c-1cc35294fdbb/edit HTTP/1.1
73```
74*/
75
76#[instrument(skip(pool, payload))]
77async fn update_exam_instructions(
78    payload: web::Json<ExamInstructionsUpdate>,
79    pool: web::Data<PgPool>,
80    exam_id: web::Path<Uuid>,
81    user: AuthUser,
82) -> ControllerResult<web::Json<ExamInstructions>> {
83    let mut conn = pool.acquire().await?;
84
85    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Exam(*exam_id)).await?;
86    let instructions_update = payload.0;
87    let saved_instructions =
88        models::exams::update_exam_instructions(&mut conn, *exam_id, instructions_update).await?;
89
90    token.authorized_ok(web::Json(saved_instructions))
91}
92
93/**
94Add a route for each controller in this module.
95
96The name starts with an underline in order to appear before other functions in the module documentation.
97
98We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
99*/
100pub fn _add_routes(cfg: &mut ServiceConfig) {
101    cfg.route("/{exam_id}/upload", web::post().to(add_media))
102        .route("/{exam_id}/edit", web::get().to(get_exam_instructions))
103        .route("/{exam_id}/edit", web::put().to(update_exam_instructions));
104}