From cb65d8084f64554df3edd01c4d3068987f79fbcc Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 4 Jul 2022 17:59:22 +0200 Subject: [PATCH] prepare for version 0.4.0 - error type NoContent - file list with duration info - fix sort - simplify upload - file extension without dot - add queries to the routes --- Cargo.lock | 2 +- ffplayout-api/Cargo.toml | 2 +- ffplayout-api/src/utils/errors.rs | 4 +++ ffplayout-api/src/utils/files.rs | 52 +++++++++++++++++++---------- ffplayout-api/src/utils/handles.rs | 2 +- ffplayout-api/src/utils/playlist.rs | 9 +++-- ffplayout-api/src/utils/routes.rs | 50 +++++++++++++++++---------- lib/src/utils/mod.rs | 2 +- 8 files changed, 80 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7633e0a0..751cecc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1027,7 +1027,7 @@ dependencies = [ [[package]] name = "ffplayout-api" -version = "0.3.3" +version = "0.4.0" dependencies = [ "actix-multipart", "actix-web", diff --git a/ffplayout-api/Cargo.toml b/ffplayout-api/Cargo.toml index 11946a38..4ef87a66 100644 --- a/ffplayout-api/Cargo.toml +++ b/ffplayout-api/Cargo.toml @@ -4,7 +4,7 @@ description = "Rest API for ffplayout" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.3.3" +version = "0.4.0" edition = "2021" [dependencies] diff --git a/ffplayout-api/src/utils/errors.rs b/ffplayout-api/src/utils/errors.rs index 65294a62..a559ad75 100644 --- a/ffplayout-api/src/utils/errors.rs +++ b/ffplayout-api/src/utils/errors.rs @@ -14,6 +14,9 @@ pub enum ServiceError { #[display(fmt = "Unauthorized")] Unauthorized, + + #[display(fmt = "NoContent: {}", _0)] + NoContent(String), } // impl ResponseError trait allows to convert our errors into http responses with appropriate data @@ -26,6 +29,7 @@ impl ResponseError for ServiceError { ServiceError::BadRequest(ref message) => HttpResponse::BadRequest().json(message), ServiceError::Conflict(ref message) => HttpResponse::Conflict().json(message), ServiceError::Unauthorized => HttpResponse::Unauthorized().json("No Permission!"), + ServiceError::NoContent(ref message) => HttpResponse::NoContent().json(message), } } } diff --git a/ffplayout-api/src/utils/files.rs b/ffplayout-api/src/utils/files.rs index 0b01fb8b..1c831cbd 100644 --- a/ffplayout-api/src/utils/files.rs +++ b/ffplayout-api/src/utils/files.rs @@ -10,14 +10,14 @@ use serde::{Deserialize, Serialize}; use simplelog::*; use crate::utils::{errors::ServiceError, playout_config}; -use ffplayout_lib::utils::file_extension; +use ffplayout_lib::utils::{file_extension, MediaProbe}; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct PathObject { pub source: String, parent: Option, folders: Option>, - files: Option>, + files: Option>, } impl PathObject { @@ -37,6 +37,12 @@ pub struct MoveObject { target: String, } +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct VideoFile { + name: String, + duration: f64, +} + /// Normalize absolut path /// /// This function takes care, that it is not possible to break out from root_path. @@ -91,7 +97,9 @@ pub async fn browser(id: i64, path_obj: &PathObject) -> Result Result Result<(), Err(ServiceError::InternalServerError) } -async fn valid_path(id: i64, path: &String) -> Result<(), ServiceError> { +async fn valid_path(id: i64, path: &String) -> Result { let (config, _) = playout_config(&id).await?; let (test_path, _, _) = norm_abs_path(&config.storage.path, path); @@ -248,10 +266,14 @@ async fn valid_path(id: i64, path: &String) -> Result<(), ServiceError> { return Err(ServiceError::BadRequest("Target folder not exists!".into())); } - Ok(()) + Ok(test_path) } -pub async fn upload(id: i64, mut payload: Multipart) -> Result { +pub async fn upload( + id: i64, + mut payload: Multipart, + path: &String, +) -> Result { while let Some(mut field) = payload.try_next().await? { let content_disposition = field.content_disposition(); debug!("{content_disposition}"); @@ -260,16 +282,12 @@ pub async fn upload(id: i64, mut payload: Multipart) -> Result Result<&'static str, Box> { INSERT INTO global(secret) VALUES($1); INSERT INTO settings(channel_name, preview_url, config_path, extra_extensions, timezone, service) VALUES('Channel 1', 'http://localhost/live/preview.m3u8', - '/etc/ffplayout/ffplayout.yml', '.jpg,.jpeg,.png', 'UTC', 'ffplayout.service'); + '/etc/ffplayout/ffplayout.yml', 'jpg,jpeg,png', 'UTC', 'ffplayout.service'); INSERT INTO roles(name) VALUES('admin'), ('user'), ('guest'); INSERT INTO presets(name, text, x, y, fontsize, line_spacing, fontcolor, box, boxcolor, boxborderw, alpha, channel_id) VALUES('Default', 'Wellcome to ffplayout messenger!', '(w-text_w)/2', '(h-text_h)/2', '24', '4', '#ffffff@0xff', '0', '#000000@0x80', '4', '1.0', '1'), diff --git a/ffplayout-api/src/utils/playlist.rs b/ffplayout-api/src/utils/playlist.rs index 9f828024..e3cee065 100644 --- a/ffplayout-api/src/utils/playlist.rs +++ b/ffplayout-api/src/utils/playlist.rs @@ -37,11 +37,10 @@ pub async fn read_playlist(id: i64, date: String) -> Result Ok(p), + Err(e) => Err(ServiceError::NoContent(e.to_string())), + } } pub async fn write_playlist(id: i64, json_data: JsonPlaylist) -> Result { diff --git a/ffplayout-api/src/utils/routes.rs b/ffplayout-api/src/utils/routes.rs index 3221ee11..899d6491 100644 --- a/ffplayout-api/src/utils/routes.rs +++ b/ffplayout-api/src/utils/routes.rs @@ -7,7 +7,7 @@ use argon2::{ password_hash::{rand_core::OsRng, PasswordHash, SaltString}, Argon2, PasswordHasher, PasswordVerifier, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use simplelog::*; use crate::utils::{ @@ -41,6 +41,18 @@ struct UserObj { user: Option, } +#[derive(Debug, Deserialize, Serialize)] +pub struct DateObj { + #[serde(default)] + date: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct FileObj { + #[serde(default)] + path: String, +} + /// curl -X POST http://127.0.0.1:8080/auth/login/ -H "Content-Type: application/json" \ /// -d '{"username": "", "password": "" }' #[post("/auth/login/")] @@ -396,14 +408,15 @@ pub async fn process_control( /// /// ---------------------------------------------------------------------------- -/// curl -X GET http://localhost:8080/api/playlist/1/2022-06-20 +/// curl -X GET http://localhost:8080/api/playlist/1?date=2022-06-20 /// --header 'Content-Type: application/json' --header 'Authorization: ' -#[get("/playlist/{id}/{date}")] +#[get("/playlist/{id}")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] pub async fn get_playlist( - params: web::Path<(i64, String)>, + id: web::Path, + obj: web::Query, ) -> Result { - match read_playlist(params.0, params.1.clone()).await { + match read_playlist(*id, obj.date.clone()).await { Ok(playlist) => Ok(web::Json(playlist)), Err(e) => Err(e), } @@ -455,14 +468,13 @@ pub async fn del_playlist( /// /// ---------------------------------------------------------------------------- -#[get("/log/{req:.*}")] +#[get("/log/{id}")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] -pub async fn get_log(req: web::Path) -> Result { - let mut segments = req.split('/'); - let id: i64 = segments.next().unwrap_or_default().parse().unwrap_or(0); - let date = segments.next().unwrap_or_default(); - - read_log_file(&id, date).await +pub async fn get_log( + id: web::Path, + log: web::Query, +) -> Result { + read_log_file(&id, &log.date).await } /// ---------------------------------------------------------------------------- @@ -511,10 +523,10 @@ pub async fn move_rename( } } -/// curl -X DELETE http://localhost:8080/api/file/1/remove/ +/// curl -X POST http://localhost:8080/api/file/1/remove/ /// --header 'Content-Type: application/json' --header 'Authorization: ' /// -d '{"source": ""}' -#[delete("/file/{id}/remove/")] +#[post("/file/{id}/remove/")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] pub async fn remove( id: web::Path, @@ -526,8 +538,12 @@ pub async fn remove( } } -#[post("/file/{id}/upload/")] +#[put("/file/{id}/upload/")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] -async fn save_file(id: web::Path, payload: Multipart) -> Result { - upload(*id, payload).await +async fn save_file( + id: web::Path, + payload: Multipart, + obj: web::Query, +) -> Result { + upload(*id, payload, &obj.path).await } diff --git a/lib/src/utils/mod.rs b/lib/src/utils/mod.rs index 19e2fca1..872758f4 100644 --- a/lib/src/utils/mod.rs +++ b/lib/src/utils/mod.rs @@ -152,7 +152,7 @@ pub struct MediaProbe { } impl MediaProbe { - fn new(input: &str) -> Self { + pub fn new(input: &str) -> Self { let probe = ffprobe(input); let mut a_stream = vec![]; let mut v_stream = vec![];