headless_lms_server/controllers/main_frontend/
page_audio_files.rs1use std::path::Path;
4
5use futures::StreamExt;
6use models::page_audio_files::PageAudioFile;
7
8use crate::prelude::*;
9
10#[instrument(skip(request, payload, pool, file_store))]
25async fn set_page_audio(
26    request: HttpRequest,
27    mut payload: Multipart,
28    page_id: web::Path<Uuid>,
29    pool: web::Data<PgPool>,
30    user: AuthUser,
31    file_store: web::Data<dyn FileStore>,
32) -> ControllerResult<web::Json<bool>> {
33    let mut conn = pool.acquire().await?;
34    let page = models::pages::get_page(&mut conn, *page_id).await?;
35    if let Some(course_id) = page.course_id {
36        let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(course_id)).await?;
37
38        let field = match payload.next().await {
39            Some(Ok(field)) => field,
40            Some(Err(error)) => {
41                return Err(ControllerError::new(
42                    ControllerErrorType::InternalServerError,
43                    error.to_string(),
44                    None,
45                ));
46            }
47            None => {
48                return Err(ControllerError::new(
49                    ControllerErrorType::BadRequest,
50                    "Didn't upload any files",
51                    None,
52                ));
53            }
54        };
55
56        let mime_type = field
57            .content_type()
58            .map(|ct| ct.to_string())
59            .unwrap_or_else(|| "".to_string());
60
61        match mime_type.as_str() {
62            "audio/mpeg" | "audio/ogg" => {}
63            unsupported => {
64                return Err(ControllerError::new(
65                    ControllerErrorType::BadRequest,
66                    format!("Unsupported audio Mime type: {}", unsupported),
67                    None,
68                ));
69            }
70        };
71
72        let course = models::courses::get_course(&mut conn, page.course_id.unwrap()).await?;
73        let media_path = upload_field_from_cms(
74            request.headers(),
75            field,
76            StoreKind::Course(course.id),
77            file_store.as_ref(),
78            &mut conn,
79            user,
80        )
81        .await?;
82
83        models::page_audio_files::insert_page_audio(
84            &mut conn,
85            page.id,
86            &media_path.as_path().to_string_lossy(),
87            &mime_type,
88        )
89        .await?;
90
91        token.authorized_ok(web::Json(true))
92    } else {
93        Err(ControllerError::new(
94            ControllerErrorType::BadRequest,
95            "The page needs to be related to a course.".to_string(),
96            None,
97        ))
98    }
99}
100
101#[instrument(skip(pool, file_store))]
113async fn remove_page_audio(
114    page_audio_id: web::Path<Uuid>,
115    page_id: web::Path<Uuid>,
116    pool: web::Data<PgPool>,
117    user: AuthUser,
118    file_store: web::Data<dyn FileStore>,
119) -> ControllerResult<web::Json<()>> {
120    let mut conn = pool.acquire().await?;
121    let audio =
122        models::page_audio_files::get_page_audio_files_by_id(&mut conn, *page_audio_id).await?;
123    let page = models::pages::get_page(&mut conn, audio.page_id).await?;
124    if let Some(course_id) = page.course_id {
125        let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Course(course_id)).await?;
126
127        let path = models::page_audio_files::delete_page_audio(&mut conn, *page_audio_id).await?;
128        file_store.delete(Path::new(&path)).await.map_err(|_| {
129            ControllerError::new(
130                ControllerErrorType::BadRequest,
131                "Could not delete the file from the file store".to_string(),
132                None,
133            )
134        })?;
135        token.authorized_ok(web::Json(()))
136    } else {
137        Err(ControllerError::new(
138            ControllerErrorType::BadRequest,
139            "The page needs to be related to a course.".to_string(),
140            None,
141        ))
142    }
143}
144
145#[instrument(skip(app_conf))]
151
152async fn get_page_audio(
153    page_id: web::Path<Uuid>,
154    pool: web::Data<PgPool>,
155    user: AuthUser,
156    app_conf: web::Data<ApplicationConfiguration>,
157) -> ControllerResult<web::Json<Vec<PageAudioFile>>> {
158    let mut conn = pool.acquire().await?;
159    let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::Page(*page_id)).await?;
160
161    let mut page_audio_files =
162        models::page_audio_files::get_page_audio_files(&mut conn, *page_id).await?;
163
164    let base_url = &app_conf.base_url;
165    for audio in page_audio_files.iter_mut() {
166        audio.path = format!("{base_url}/api/v0/files/{}", audio.path);
167    }
168
169    token.authorized_ok(web::Json(page_audio_files))
170}
171
172pub fn _add_routes(cfg: &mut ServiceConfig) {
180    cfg.route("/{page_id}", web::post().to(set_page_audio))
181        .route("/{file_id}", web::delete().to(remove_page_audio))
182        .route("/{page_id}/files", web::get().to(get_page_audio));
183}