headless_lms_server/controllers/cms/
pages.rs

1//! Controllers for requests starting with `/api/v0/cms/pages`.
2
3use models::{
4    CourseOrExamId,
5    page_history::HistoryChangeReason,
6    pages::{
7        CmsPageUpdate, ContentManagementPage, PageInfo, PageNavigationInformation, PageUpdateArgs,
8    },
9};
10
11use crate::{
12    domain::{
13        models_requests::{self, JwtKey},
14        request_id::RequestId,
15    },
16    prelude::*,
17};
18
19/**
20GET `/api/v0/cms/pages/:page_id` - Get a page with exercises and exercise tasks by id.
21
22Request: `GET /api/v0/cms/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02`
23*/
24#[instrument(skip(pool))]
25async fn get_page(
26    page_id: web::Path<Uuid>,
27    pool: web::Data<PgPool>,
28    user: AuthUser,
29) -> ControllerResult<web::Json<ContentManagementPage>> {
30    let mut conn = pool.acquire().await?;
31    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
32
33    let cms_page = models::pages::get_page_with_exercises(&mut conn, *page_id).await?;
34    token.authorized_ok(web::Json(cms_page))
35}
36
37/**
38GET `/api/v0/cms/pages/:page_id/info` - Get a pages's course id, course name, organization slug
39
40Request: `GET /api/v0/cms/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02/info`
41*/
42async fn get_page_info(
43    page_id: web::Path<Uuid>,
44    pool: web::Data<PgPool>,
45    user: AuthUser,
46) -> ControllerResult<web::Json<PageInfo>> {
47    let mut conn = pool.acquire().await?;
48    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
49
50    let cms_page_info = models::pages::get_page_info(&mut conn, *page_id).await?;
51    token.authorized_ok(web::Json(cms_page_info))
52}
53
54/**
55PUT `/api/v0/cms/pages/:page_id` - Update a page by id.
56
57Please note that this endpoint will change all the exercise and exercise task ids you've created. Make sure the use the updated ids from the response object.
58
59If optional property front_page_of_chapter_id is set, this page will become the front page of the specified course part.
60
61# Example: OUTDATED
62
63Request:
64
65```http
66PUT /api/v0/cms/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02 HTTP/1.1
67Content-Type: application/json
68
69{
70  "content": [{"type": "x"}],
71  "url_path": "/part-1/hello-world",
72  "title": "Hello world!",
73  "chapter_id": "2495ffa3-7ea9-4615-baa5-828023688c79"
74}
75```
76*/
77
78#[instrument(skip(pool, app_conf))]
79async fn update_page(
80    request_id: RequestId,
81    payload: web::Json<CmsPageUpdate>,
82    page_id: web::Path<Uuid>,
83    pool: web::Data<PgPool>,
84    jwt_key: web::Data<JwtKey>,
85    app_conf: web::Data<ApplicationConfiguration>,
86    user: AuthUser,
87) -> ControllerResult<web::Json<ContentManagementPage>> {
88    let mut conn = pool.acquire().await?;
89    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
90
91    let cms_page_update = payload.0;
92    let course_or_exam_id = models::pages::get_course_and_exam_id(&mut conn, *page_id).await?;
93    let is_exam_page = matches!(course_or_exam_id, CourseOrExamId::Exam(_));
94    let saved = models::pages::update_page(
95        &mut conn,
96        PageUpdateArgs {
97            page_id: *page_id,
98            author: user.id,
99            cms_page_update,
100            retain_ids: false,
101            history_change_reason: HistoryChangeReason::PageSaved,
102            is_exam_page,
103        },
104        models_requests::make_spec_fetcher(
105            app_conf.base_url.clone(),
106            request_id.0,
107            jwt_key.into_inner(),
108        ),
109        models_requests::fetch_service_info,
110    )
111    .await?;
112    token.authorized_ok(web::Json(saved))
113}
114
115/**
116GET /api/v0/cms/pages/:page_id/page-navigation - tells what's the next page, previous page, and the chapter front page given a page id.
117*/
118#[instrument(skip(pool))]
119async fn get_page_navigation(
120    page_id: web::Path<Uuid>,
121    pool: web::Data<PgPool>,
122) -> ControllerResult<web::Json<PageNavigationInformation>> {
123    let mut conn = pool.acquire().await?;
124    let token = skip_authorize();
125    let res = models::pages::get_page_navigation_data(&mut conn, *page_id).await?;
126
127    token.authorized_ok(web::Json(res))
128}
129/**
130Add a route for each controller in this module.
131
132The name starts with an underline in order to appear before other functions in the module documentation.
133
134We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
135*/
136pub fn _add_routes(cfg: &mut ServiceConfig) {
137    cfg.route("/{page_id}", web::get().to(get_page))
138        .route("/{page_id}/info", web::get().to(get_page_info))
139        .route(
140            "/{page_id}/page-navigation",
141            web::get().to(get_page_navigation),
142        )
143        .route("/{page_id}", web::put().to(update_page));
144}