headless_lms_server/controllers/cms/
pages.rs1use models::{
4 CourseOrExamId,
5 page_history::HistoryChangeReason,
6 pages::{
7 CmsPageUpdate, ContentManagementPage, PageInfo, PageNavigationInformation, PageUpdateArgs,
8 PageVisibility,
9 },
10};
11
12use crate::{
13 domain::{
14 models_requests::{self, JwtKey},
15 request_id::RequestId,
16 },
17 prelude::*,
18};
19use utoipa::OpenApi;
20
21#[derive(OpenApi)]
22#[openapi(paths(get_page, get_page_info, update_page, get_page_navigation))]
23pub(crate) struct CmsPagesApiDoc;
24
25#[instrument(skip(pool))]
31#[utoipa::path(
32 get,
33 path = "/{page_id}",
34 operation_id = "getCmsPage",
35 tag = "cms_pages",
36 params(
37 ("page_id" = Uuid, Path, description = "Page id")
38 ),
39 responses(
40 (status = 200, description = "CMS page with exercises and peer review data", body = ContentManagementPage)
41 )
42)]
43async fn get_page(
44 page_id: web::Path<Uuid>,
45 pool: web::Data<PgPool>,
46 user: AuthUser,
47) -> ControllerResult<web::Json<ContentManagementPage>> {
48 let mut conn = pool.acquire().await?;
49 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
50
51 let cms_page = models::pages::get_page_with_exercises(&mut conn, *page_id).await?;
52 token.authorized_ok(web::Json(cms_page))
53}
54
55#[utoipa::path(
61 get,
62 path = "/{page_id}/info",
63 operation_id = "getCmsPageInfo",
64 tag = "cms_pages",
65 params(
66 ("page_id" = Uuid, Path, description = "Page id")
67 ),
68 responses(
69 (status = 200, description = "Page info", body = PageInfo)
70 )
71)]
72async fn get_page_info(
73 page_id: web::Path<Uuid>,
74 pool: web::Data<PgPool>,
75 user: AuthUser,
76) -> ControllerResult<web::Json<PageInfo>> {
77 let mut conn = pool.acquire().await?;
78 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
79
80 let cms_page_info = models::pages::get_page_info(&mut conn, *page_id).await?;
81 token.authorized_ok(web::Json(cms_page_info))
82}
83
84#[instrument(skip(pool, app_conf))]
109#[utoipa::path(
110 put,
111 path = "/{page_id}",
112 operation_id = "updateCmsPage",
113 tag = "cms_pages",
114 params(
115 ("page_id" = Uuid, Path, description = "Page id")
116 ),
117 request_body = CmsPageUpdate,
118 responses(
119 (status = 200, description = "Updated CMS page", body = ContentManagementPage)
120 )
121)]
122async fn update_page(
123 request_id: RequestId,
124 payload: web::Json<CmsPageUpdate>,
125 page_id: web::Path<Uuid>,
126 pool: web::Data<PgPool>,
127 jwt_key: web::Data<JwtKey>,
128 app_conf: web::Data<ApplicationConfiguration>,
129 user: AuthUser,
130) -> ControllerResult<web::Json<ContentManagementPage>> {
131 let mut conn = pool.acquire().await?;
132 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
133
134 let cms_page_update = payload.0;
135 let course_or_exam_id = models::pages::get_course_and_exam_id(&mut conn, *page_id).await?;
136 let is_exam_page = matches!(course_or_exam_id, CourseOrExamId::Exam(_));
137 let (expected_course_id, expected_exam_id) = match course_or_exam_id {
138 CourseOrExamId::Course(course_id) => (Some(course_id), None),
139 CourseOrExamId::Exam(exam_id) => (None, Some(exam_id)),
140 };
141 let saved = models::pages::update_by_id_in_parent_context(
142 &mut conn,
143 PageUpdateArgs {
144 page_id: *page_id,
145 author: user.id,
146 cms_page_update,
147 retain_ids: false,
148 history_change_reason: HistoryChangeReason::PageSaved,
149 is_exam_page,
150 },
151 expected_course_id,
152 expected_exam_id,
153 models_requests::make_spec_fetcher(
154 app_conf.base_url.clone(),
155 request_id.0,
156 jwt_key.into_inner(),
157 ),
158 models_requests::fetch_service_info,
159 )
160 .await?;
161 token.authorized_ok(web::Json(saved))
162}
163
164#[instrument(skip(pool))]
168#[utoipa::path(
169 get,
170 path = "/{page_id}/page-navigation",
171 operation_id = "getCmsPageNavigation",
172 tag = "cms_pages",
173 params(
174 ("page_id" = Uuid, Path, description = "Page id")
175 ),
176 responses(
177 (status = 200, description = "Page navigation", body = PageNavigationInformation)
178 )
179)]
180async fn get_page_navigation(
181 page_id: web::Path<Uuid>,
182 pool: web::Data<PgPool>,
183) -> ControllerResult<web::Json<PageNavigationInformation>> {
184 let mut conn = pool.acquire().await?;
185 let token = skip_authorize();
186 let res =
187 models::pages::get_page_navigation_data(&mut conn, *page_id, PageVisibility::Any).await?;
188
189 token.authorized_ok(web::Json(res))
190}
191pub fn _add_routes(cfg: &mut ServiceConfig) {
199 cfg.route("/{page_id}", web::get().to(get_page))
200 .route("/{page_id}/info", web::get().to(get_page_info))
201 .route(
202 "/{page_id}/page-navigation",
203 web::get().to(get_page_navigation),
204 )
205 .route("/{page_id}", web::put().to(update_page));
206}