headless_lms_server/controllers/cms/
exams.rs1use models::exams::{ExamInstructions, ExamInstructionsUpdate};
4use utoipa::OpenApi;
5
6use crate::prelude::*;
7
8#[derive(OpenApi)]
9#[openapi(paths(add_media, get_exam_instructions, update_exam_instructions))]
10pub(crate) struct CmsExamsApiDoc;
11
12#[utoipa::path(
28 post,
29 path = "/{exam_id}/upload",
30 operation_id = "uploadCmsExamMedia",
31 tag = "cms_exams",
32 params(
33 ("exam_id" = Uuid, Path, description = "Exam id")
34 ),
35 request_body(
36 content = String,
37 content_type = "multipart/form-data"
38 ),
39 responses(
40 (status = 200, description = "Uploaded media result", body = UploadResult)
41 )
42)]
43#[instrument(skip(payload, request, file_store, app_conf))]
44async fn add_media(
45 pool: web::Data<PgPool>,
46 exam_id: web::Path<Uuid>,
47 payload: Multipart,
48 request: HttpRequest,
49 user: AuthUser,
50 file_store: web::Data<dyn FileStore>,
51 app_conf: web::Data<ApplicationConfiguration>,
52) -> ControllerResult<web::Json<UploadResult>> {
53 let mut conn = pool.acquire().await?;
54 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Exam(*exam_id)).await?;
55 let media_path = upload_file_from_cms(
56 request.headers(),
57 payload,
58 StoreKind::Exam(*exam_id),
59 file_store.as_ref(),
60 &mut conn,
61 user,
62 )
63 .await?;
64 let download_url = file_store.get_download_url(media_path.as_path(), app_conf.as_ref());
65
66 token.authorized_ok(web::Json(UploadResult { url: download_url }))
67}
68
69#[instrument(skip(pool))]
73#[utoipa::path(
74 get,
75 path = "/{exam_id}/edit",
76 operation_id = "getCmsExamInstructions",
77 tag = "cms_exams",
78 params(
79 ("exam_id" = Uuid, Path, description = "Exam id")
80 ),
81 responses(
82 (status = 200, description = "Exam instructions", body = ExamInstructions)
83 )
84)]
85async fn get_exam_instructions(
86 pool: web::Data<PgPool>,
87 exam_id: web::Path<Uuid>,
88 user: AuthUser,
89) -> ControllerResult<web::Json<ExamInstructions>> {
90 let mut conn = pool.acquire().await?;
91 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Exam(*exam_id)).await?;
92 let exam_instructions_data =
93 models::exams::get_exam_instructions_data(&mut conn, *exam_id).await?;
94
95 token.authorized_ok(web::Json(exam_instructions_data))
96}
97
98#[instrument(skip(pool, payload))]
110#[utoipa::path(
111 put,
112 path = "/{exam_id}/edit",
113 operation_id = "updateCmsExamInstructions",
114 tag = "cms_exams",
115 params(
116 ("exam_id" = Uuid, Path, description = "Exam id")
117 ),
118 request_body = ExamInstructionsUpdate,
119 responses(
120 (status = 200, description = "Updated exam instructions", body = ExamInstructions)
121 )
122)]
123async fn update_exam_instructions(
124 payload: web::Json<ExamInstructionsUpdate>,
125 pool: web::Data<PgPool>,
126 exam_id: web::Path<Uuid>,
127 user: AuthUser,
128) -> ControllerResult<web::Json<ExamInstructions>> {
129 let mut conn = pool.acquire().await?;
130
131 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Exam(*exam_id)).await?;
132 let instructions_update = payload.0;
133 let saved_instructions =
134 models::exams::update_exam_instructions(&mut conn, *exam_id, instructions_update).await?;
135
136 token.authorized_ok(web::Json(saved_instructions))
137}
138
139pub fn _add_routes(cfg: &mut ServiceConfig) {
147 cfg.route("/{exam_id}/upload", web::post().to(add_media))
148 .route("/{exam_id}/edit", web::get().to(get_exam_instructions))
149 .route("/{exam_id}/edit", web::put().to(update_exam_instructions));
150}