1use std::sync::Arc;
4
5use models::{
6 page_history::PageHistory,
7 pages::{HistoryRestoreData, NewPage, Page, PageDetailsUpdate, PageInfo},
8};
9use utoipa::OpenApi;
10
11use crate::{
12 domain::{
13 models_requests::{self, JwtKey},
14 request_id::RequestId,
15 },
16 prelude::*,
17};
18
19#[derive(OpenApi)]
20#[openapi(paths(
21 post_new_page,
22 delete_page,
23 get_page_info,
24 update_page_details,
25 history,
26 history_count,
27 restore,
28 get_all_pages_by_course_id
29))]
30pub(crate) struct MainFrontendPagesApiDoc;
31
32#[instrument(skip(pool, app_conf))]
62#[utoipa::path(
63 post,
64 path = "",
65 operation_id = "createPage",
66 tag = "pages",
67 request_body = NewPage,
68 responses(
69 (status = 200, description = "Created page", body = Page)
70 )
71)]
72async fn post_new_page(
73 request_id: RequestId,
74 payload: web::Json<NewPage>,
75 pool: web::Data<PgPool>,
76 app_conf: web::Data<ApplicationConfiguration>,
77 user: AuthUser,
78 jwt_key: web::Data<JwtKey>,
79) -> ControllerResult<web::Json<Page>> {
80 let mut conn = pool.acquire().await?;
81 let new_page = payload.0;
82 let course_id = new_page.course_id.ok_or_else(|| {
83 ControllerError::new(
84 ControllerErrorType::BadRequest,
85 "Cannot create a new page without a course id".to_string(),
86 None,
87 )
88 })?;
89 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(course_id)).await?;
90
91 let page = models::pages::insert_new_content_page(
92 &mut conn,
93 new_page,
94 user.id,
95 models_requests::make_spec_fetcher(
96 app_conf.base_url.clone(),
97 request_id.0,
98 Arc::clone(&jwt_key),
99 ),
100 models_requests::fetch_service_info,
101 )
102 .await?;
103 token.authorized_ok(web::Json(page))
104}
105
106#[instrument(skip(pool))]
115#[utoipa::path(
116 delete,
117 path = "/{page_id}",
118 operation_id = "deletePage",
119 tag = "pages",
120 params(
121 ("page_id" = Uuid, Path, description = "Page id")
122 ),
123 responses(
124 (status = 200, description = "Deleted page", body = Page)
125 )
126)]
127async fn delete_page(
128 page_id: web::Path<Uuid>,
129 pool: web::Data<PgPool>,
130 user: AuthUser,
131) -> ControllerResult<web::Json<Page>> {
132 let mut conn = pool.acquire().await?;
133 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
134 let deleted_page =
135 models::pages::delete_page_and_exercises(&mut conn, *page_id, user.id).await?;
136
137 token.authorized_ok(web::Json(deleted_page))
138}
139
140#[instrument(skip(pool))]
144#[utoipa::path(
145 get,
146 path = "/{page_id}/history",
147 operation_id = "getPageHistory",
148 tag = "pages",
149 params(
150 ("page_id" = Uuid, Path, description = "Page id"),
151 ("page" = Option<i64>, Query, description = "Page number"),
152 ("limit" = Option<i64>, Query, description = "Page size")
153 ),
154 responses(
155 (status = 200, description = "Page history entries", body = Vec<PageHistory>)
156 )
157)]
158async fn history(
159 pool: web::Data<PgPool>,
160 page_id: web::Path<Uuid>,
161 pagination: web::Query<Pagination>,
162 user: AuthUser,
163) -> ControllerResult<web::Json<Vec<PageHistory>>> {
164 let mut conn = pool.acquire().await?;
165 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Page(*page_id)).await?;
166
167 let res = models::page_history::history(&mut conn, *page_id, *pagination).await?;
168
169 token.authorized_ok(web::Json(res))
170}
171
172#[instrument(skip(pool))]
176#[utoipa::path(
177 get,
178 path = "/{page_id}/history_count",
179 operation_id = "getPageHistoryCount",
180 tag = "pages",
181 params(
182 ("page_id" = Uuid, Path, description = "Page id")
183 ),
184 responses(
185 (status = 200, description = "Page history count", body = i64)
186 )
187)]
188async fn history_count(
189 pool: web::Data<PgPool>,
190 page_id: web::Path<Uuid>,
191 user: AuthUser,
192) -> ControllerResult<web::Json<i64>> {
193 let mut conn = pool.acquire().await?;
194 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Page(*page_id)).await?;
195 let res = models::page_history::history_count(&mut conn, *page_id).await?;
196
197 token.authorized_ok(web::Json(res))
198}
199
200#[instrument(skip(pool, app_conf))]
205#[utoipa::path(
206 post,
207 path = "/{page_id}/restore",
208 operation_id = "restorePageHistory",
209 tag = "pages",
210 params(
211 ("page_id" = Uuid, Path, description = "Page id")
212 ),
213 request_body = HistoryRestoreData,
214 responses(
215 (status = 200, description = "Restored history id", body = Uuid)
216 )
217)]
218async fn restore(
219 request_id: RequestId,
220 pool: web::Data<PgPool>,
221 page_id: web::Path<Uuid>,
222 restore_data: web::Json<HistoryRestoreData>,
223 app_conf: web::Data<ApplicationConfiguration>,
224 user: AuthUser,
225 jwt_key: web::Data<JwtKey>,
226) -> ControllerResult<web::Json<Uuid>> {
227 let mut conn = pool.acquire().await?;
228 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
229 let res = models::pages::restore(
230 &mut conn,
231 *page_id,
232 restore_data.history_id,
233 user.id,
234 models_requests::make_spec_fetcher(
235 app_conf.base_url.clone(),
236 request_id.0,
237 Arc::clone(&jwt_key),
238 ),
239 models_requests::fetch_service_info,
240 )
241 .await?;
242
243 token.authorized_ok(web::Json(res))
244}
245
246#[utoipa::path(
252 get,
253 path = "/{page_id}/info",
254 operation_id = "getPageInfo",
255 tag = "pages",
256 params(
257 ("page_id" = Uuid, Path, description = "Page id")
258 ),
259 responses(
260 (status = 200, description = "Page info", body = PageInfo)
261 )
262)]
263async fn get_page_info(
264 page_id: web::Path<Uuid>,
265 pool: web::Data<PgPool>,
266 user: AuthUser,
267) -> ControllerResult<web::Json<PageInfo>> {
268 let mut conn = pool.acquire().await?;
269 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
270
271 let page_info = models::pages::get_page_info(&mut conn, *page_id).await?;
272
273 token.authorized_ok(web::Json(page_info))
274}
275
276#[instrument(skip(pool))]
280#[utoipa::path(
281 put,
282 path = "/{page_id}/page-details",
283 operation_id = "updatePageDetails",
284 tag = "pages",
285 params(
286 ("page_id" = Uuid, Path, description = "Page id")
287 ),
288 request_body = PageDetailsUpdate,
289 responses(
290 (status = 200, description = "Updated page details", body = bool)
291 )
292)]
293async fn update_page_details(
294 page_id: web::Path<Uuid>,
295 payload: web::Json<PageDetailsUpdate>,
296 pool: web::Data<PgPool>,
297 user: AuthUser,
298) -> ControllerResult<web::Json<bool>> {
299 let mut conn = pool.acquire().await?;
300
301 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
302
303 models::pages::update_page_details(&mut conn, *page_id, &payload).await?;
304 token.authorized_ok(web::Json(true))
305}
306
307#[utoipa::path(
311 get,
312 path = "/{course_id}/all-course-pages-for-course",
313 operation_id = "getCoursePages",
314 tag = "pages",
315 params(
316 ("course_id" = Uuid, Path, description = "Course id")
317 ),
318 responses(
319 (status = 200, description = "Course pages", body = Vec<Page>)
320 )
321)]
322async fn get_all_pages_by_course_id(
323 course_id: web::Path<Uuid>,
324 pool: web::Data<PgPool>,
325 user: AuthUser,
326) -> ControllerResult<web::Json<Vec<Page>>> {
327 let mut conn = pool.acquire().await?;
328 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(*course_id)).await?;
329
330 let mut pages = models::pages::get_pages_by_course_id(&mut conn, *course_id).await?;
331
332 pages.sort_by(|a, b| a.order_number.cmp(&b.order_number));
333
334 token.authorized_ok(web::Json(pages))
335}
336
337pub fn _add_routes(cfg: &mut ServiceConfig) {
345 cfg.route("", web::post().to(post_new_page))
346 .route("/{page_id}", web::delete().to(delete_page))
347 .route("/{page_id}/info", web::get().to(get_page_info))
348 .route(
349 "/{page_id}/page-details",
350 web::put().to(update_page_details),
351 )
352 .route("/{page_id}/history", web::get().to(history))
353 .route("/{page_id}/history_count", web::get().to(history_count))
354 .route("/{page_id}/restore", web::post().to(restore))
355 .route(
356 "/{course_id}/all-course-pages-for-course",
357 web::get().to(get_all_pages_by_course_id),
358 );
359}