headless_lms_server/controllers/main_frontend/
pages.rs

1//! Controllers for requests starting with `/api/v0/main-frontend/pages`.
2
3use std::sync::Arc;
4
5use models::{
6    page_history::PageHistory,
7    pages::{HistoryRestoreData, NewPage, Page, PageDetailsUpdate, PageInfo},
8};
9
10use crate::{
11    domain::{
12        models_requests::{self, JwtKey},
13        request_id::RequestId,
14    },
15    prelude::*,
16};
17
18/**
19POST `/api/v0/main-frontend/pages` - Create a new page.
20
21Please 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.
22
23If optional property front_page_of_chapter_id is set, this page will become the front page of the specified course part.
24
25# Example:
26
27Request:
28```http
29POST /api/v0/main-frontend/pages HTTP/1.1
30Content-Type: application/json
31
32{
33  "content": [
34    {
35      "type": "x",
36      "id": "2a4e517d-a7d2-4d82-89fb-a1333d8d01d1"
37    }
38  ],
39  "url_path": "/part-2/best-page",
40  "title": "Hello world!",
41  "course_id": "10363c5b-82b4-4121-8ef1-bae8fb42a5ce",
42  "chapter_id": "2495ffa3-7ea9-4615-baa5-828023688c79"
43}
44```
45*/
46
47#[instrument(skip(pool, app_conf))]
48async fn post_new_page(
49    request_id: RequestId,
50    payload: web::Json<NewPage>,
51    pool: web::Data<PgPool>,
52    app_conf: web::Data<ApplicationConfiguration>,
53    user: AuthUser,
54    jwt_key: web::Data<JwtKey>,
55) -> ControllerResult<web::Json<Page>> {
56    let mut conn = pool.acquire().await?;
57    let new_page = payload.0;
58    let course_id = new_page.course_id.ok_or_else(|| {
59        ControllerError::new(
60            ControllerErrorType::BadRequest,
61            "Cannot create a new page without a course id".to_string(),
62            None,
63        )
64    })?;
65    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(course_id)).await?;
66
67    let page = models::pages::insert_new_content_page(
68        &mut conn,
69        new_page,
70        user.id,
71        models_requests::make_spec_fetcher(
72            app_conf.base_url.clone(),
73            request_id.0,
74            Arc::clone(&jwt_key),
75        ),
76        models_requests::fetch_service_info,
77    )
78    .await?;
79    token.authorized_ok(web::Json(page))
80}
81
82/**
83DELETE `/api/v0/main-frontend/pages/:page_id` - Delete a page, related exercises, and related exercise tasks by id.
84
85
86# Example
87
88Request: `DELETE /api/v0/main-frontend/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02`
89*/
90#[instrument(skip(pool))]
91async fn delete_page(
92    page_id: web::Path<Uuid>,
93    pool: web::Data<PgPool>,
94    user: AuthUser,
95) -> ControllerResult<web::Json<Page>> {
96    let mut conn = pool.acquire().await?;
97    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
98    let deleted_page =
99        models::pages::delete_page_and_exercises(&mut conn, *page_id, user.id).await?;
100
101    token.authorized_ok(web::Json(deleted_page))
102}
103
104/**
105GET /api/v0/main-frontend/pages/:page_id/history
106*/
107#[instrument(skip(pool))]
108async fn history(
109    pool: web::Data<PgPool>,
110    page_id: web::Path<Uuid>,
111    pagination: web::Query<Pagination>,
112    user: AuthUser,
113) -> ControllerResult<web::Json<Vec<PageHistory>>> {
114    let mut conn = pool.acquire().await?;
115    let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Page(*page_id)).await?;
116
117    let res = models::page_history::history(&mut conn, *page_id, *pagination).await?;
118
119    token.authorized_ok(web::Json(res))
120}
121
122/**
123GET /api/v0/main-frontend/pages/:page_id/history_count
124*/
125#[instrument(skip(pool))]
126async fn history_count(
127    pool: web::Data<PgPool>,
128    page_id: web::Path<Uuid>,
129    user: AuthUser,
130) -> ControllerResult<web::Json<i64>> {
131    let mut conn = pool.acquire().await?;
132    let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Page(*page_id)).await?;
133    let res = models::page_history::history_count(&mut conn, *page_id).await?;
134
135    token.authorized_ok(web::Json(res))
136}
137
138/**
139POST /api/v0/main-frontend/pages/:page_id/restore
140*/
141
142#[instrument(skip(pool, app_conf))]
143async fn restore(
144    request_id: RequestId,
145    pool: web::Data<PgPool>,
146    page_id: web::Path<Uuid>,
147    restore_data: web::Json<HistoryRestoreData>,
148    app_conf: web::Data<ApplicationConfiguration>,
149    user: AuthUser,
150    jwt_key: web::Data<JwtKey>,
151) -> ControllerResult<web::Json<Uuid>> {
152    let mut conn = pool.acquire().await?;
153    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
154    let res = models::pages::restore(
155        &mut conn,
156        *page_id,
157        restore_data.history_id,
158        user.id,
159        models_requests::make_spec_fetcher(
160            app_conf.base_url.clone(),
161            request_id.0,
162            Arc::clone(&jwt_key),
163        ),
164        models_requests::fetch_service_info,
165    )
166    .await?;
167
168    token.authorized_ok(web::Json(res))
169}
170
171/**
172GET `/api/v0/main-fronted/pages/:page_id/info` - Get a pages's course id, course name, organization slug
173
174Request: `GET /api/v0/cms/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02/info`
175*/
176async fn get_page_info(
177    page_id: web::Path<Uuid>,
178    pool: web::Data<PgPool>,
179    user: AuthUser,
180) -> ControllerResult<web::Json<PageInfo>> {
181    let mut conn = pool.acquire().await?;
182    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
183
184    let page_info = models::pages::get_page_info(&mut conn, *page_id).await?;
185
186    token.authorized_ok(web::Json(page_info))
187}
188
189/**
190POST `/api/v0/main-frontend/pages/:page_id/page-details` - Update pages title and url_path.
191*/
192#[instrument(skip(pool))]
193async fn update_page_details(
194    page_id: web::Path<Uuid>,
195    payload: web::Json<PageDetailsUpdate>,
196    pool: web::Data<PgPool>,
197    user: AuthUser,
198) -> ControllerResult<web::Json<bool>> {
199    let mut conn = pool.acquire().await?;
200
201    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
202
203    models::pages::update_page_details(&mut conn, *page_id, &payload).await?;
204    token.authorized_ok(web::Json(true))
205}
206
207/**
208GET `/api/v0/main-frontend/pages/:course_id/all-course-pages-for-course` - Get all pages of a course
209*/
210async fn get_all_pages_by_course_id(
211    course_id: web::Path<Uuid>,
212    pool: web::Data<PgPool>,
213    user: AuthUser,
214) -> ControllerResult<web::Json<Vec<Page>>> {
215    let mut conn = pool.acquire().await?;
216    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
217
218    let mut pages = models::pages::get_pages_by_course_id(&mut conn, *course_id).await?;
219
220    pages.sort_by(|a, b| a.order_number.cmp(&b.order_number));
221
222    token.authorized_ok(web::Json(pages))
223}
224
225/**
226Add a route for each controller in this module.
227
228The name starts with an underline in order to appear before other functions in the module documentation.
229
230We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
231*/
232pub fn _add_routes(cfg: &mut ServiceConfig) {
233    cfg.route("", web::post().to(post_new_page))
234        .route("/{page_id}", web::delete().to(delete_page))
235        .route("/{page_id}/info", web::get().to(get_page_info))
236        .route(
237            "/{page_id}/page-details",
238            web::put().to(update_page_details),
239        )
240        .route("/{page_id}/history", web::get().to(history))
241        .route("/{page_id}/history_count", web::get().to(history_count))
242        .route("/{history_id}/restore", web::post().to(restore))
243        .route(
244            "/{course_id}/all-course-pages-for-course",
245            web::get().to(get_all_pages_by_course_id),
246        );
247}