From ec4f5d2ac23718aa6c3fc23f698f34a2e31b326b Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sun, 2 Oct 2022 21:43:35 +0200 Subject: [PATCH] restructure api, import playlist from text file #195 --- Cargo.lock | 2 +- ffplayout-api/Cargo.toml | 2 +- ffplayout-api/src/{utils => api}/auth.rs | 0 ffplayout-api/src/api/mod.rs | 2 + ffplayout-api/src/{utils => api}/routes.rs | 90 +++++++++++++++------- ffplayout-api/src/{utils => db}/handles.rs | 79 +++++++++---------- ffplayout-api/src/db/mod.rs | 2 + ffplayout-api/src/{utils => db}/models.rs | 0 ffplayout-api/src/main.rs | 21 ++--- ffplayout-api/src/utils/channels.rs | 15 ++-- ffplayout-api/src/utils/control.rs | 5 +- ffplayout-api/src/utils/files.rs | 29 ++++--- ffplayout-api/src/utils/mod.rs | 19 ++--- ffplayout-frontend | 2 +- 14 files changed, 154 insertions(+), 114 deletions(-) rename ffplayout-api/src/{utils => api}/auth.rs (100%) create mode 100644 ffplayout-api/src/api/mod.rs rename ffplayout-api/src/{utils => api}/routes.rs (90%) rename ffplayout-api/src/{utils => db}/handles.rs (84%) create mode 100644 ffplayout-api/src/db/mod.rs rename ffplayout-api/src/{utils => db}/models.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e7623dcc..da8e810d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -949,7 +949,7 @@ dependencies = [ [[package]] name = "ffplayout-api" -version = "0.6.3" +version = "0.7.0" dependencies = [ "actix-files", "actix-multipart", diff --git a/ffplayout-api/Cargo.toml b/ffplayout-api/Cargo.toml index 28d4e881..5f44c3ab 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.6.3" +version = "0.7.0" edition = "2021" [dependencies] diff --git a/ffplayout-api/src/utils/auth.rs b/ffplayout-api/src/api/auth.rs similarity index 100% rename from ffplayout-api/src/utils/auth.rs rename to ffplayout-api/src/api/auth.rs diff --git a/ffplayout-api/src/api/mod.rs b/ffplayout-api/src/api/mod.rs new file mode 100644 index 00000000..474f258a --- /dev/null +++ b/ffplayout-api/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod auth; +pub mod routes; diff --git a/ffplayout-api/src/utils/routes.rs b/ffplayout-api/src/api/routes.rs similarity index 90% rename from ffplayout-api/src/utils/routes.rs rename to ffplayout-api/src/api/routes.rs index da750d4c..e389886d 100644 --- a/ffplayout-api/src/utils/routes.rs +++ b/ffplayout-api/src/api/routes.rs @@ -8,7 +8,7 @@ /// /// For all endpoints an (Bearer) authentication is required.\ /// `{id}` represent the channel id, and at default is 1. -use std::collections::HashMap; +use std::{collections::HashMap, env, fs, path::Path}; use actix_multipart::Multipart; use actix_web::{delete, get, http::StatusCode, patch, post, put, web, HttpResponse, Responder}; @@ -20,8 +20,12 @@ use argon2::{ use serde::{Deserialize, Serialize}; use simplelog::*; +use crate::auth::{create_jwt, Claims}; +use crate::db::{ + handles, + models::{Channel, LoginUser, TextPreset, User}, +}; use crate::utils::{ - auth::{create_jwt, Claims}, channels::{create_channel, delete_channel}, control::{control_service, control_state, media_info, send_message, Process}, errors::ServiceError, @@ -29,16 +33,10 @@ use crate::utils::{ browser, create_directory, remove_file_or_folder, rename_file, upload, MoveObject, PathObject, }, - handles::{ - db_add_preset, db_add_user, db_delete_preset, db_get_all_channels, db_get_channel, - db_get_presets, db_get_user, db_login, db_role, db_update_channel, db_update_preset, - db_update_user, - }, - models::{Channel, LoginUser, TextPreset, User}, playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist}, - read_log_file, read_playout_config, Role, + playout_config, read_log_file, read_playout_config, Role, }; -use ffplayout_lib::utils::{JsonPlaylist, PlayoutConfig}; +use ffplayout_lib::utils::{import::import_file, JsonPlaylist, PlayoutConfig}; #[derive(Serialize)] struct ResponseObj { @@ -60,11 +58,19 @@ pub struct DateObj { } #[derive(Debug, Deserialize, Serialize)] -pub struct FileObj { +struct FileObj { #[serde(default)] path: String, } +#[derive(Debug, Deserialize, Serialize)] +pub struct ImportObj { + #[serde(default)] + file: String, + #[serde(default)] + date: String, +} + /// #### User Handling /// /// **Login** @@ -85,7 +91,7 @@ pub struct FileObj { /// ``` #[post("/auth/login/")] pub async fn login(credentials: web::Json) -> impl Responder { - match db_login(&credentials.username).await { + match handles::select_login(&credentials.username).await { Ok(mut user) => { let pass = user.password.clone(); let hash = PasswordHash::new(&pass).unwrap(); @@ -96,7 +102,7 @@ pub async fn login(credentials: web::Json) -> impl Responder { .verify_password(credentials.password.as_bytes(), &hash) .is_ok() { - let role = db_role(&user.role_id.unwrap_or_default()) + let role = handles::select_role(&user.role_id.unwrap_or_default()) .await .unwrap_or_else(|_| "guest".to_string()); let claims = Claims::new(user.id, user.username.clone(), role.clone()); @@ -147,7 +153,7 @@ pub async fn login(credentials: web::Json) -> impl Responder { #[get("/user")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] async fn get_user(user: web::ReqData) -> Result { - match db_get_user(&user.username).await { + match handles::select_user(&user.username).await { Ok(user) => Ok(web::Json(user)), Err(e) => { error!("{e}"); @@ -189,7 +195,7 @@ async fn update_user( fields.push_str(format!("password = '{}', salt = '{salt}'", password_hash).as_str()); } - if db_update_user(user.id, fields).await.is_ok() { + if handles::update_user(user.id, fields).await.is_ok() { return Ok("Update Success"); }; @@ -209,7 +215,7 @@ async fn update_user( #[post("/user/")] #[has_any_role("Role::Admin", type = "Role")] async fn add_user(data: web::Json) -> Result { - match db_add_user(data.into_inner()).await { + match handles::insert_user(data.into_inner()).await { Ok(_) => Ok("Add User Success"), Err(e) => { error!("{e}"); @@ -242,7 +248,7 @@ async fn add_user(data: web::Json) -> Result #[get("/channel/{id}")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] async fn get_channel(id: web::Path) -> Result { - if let Ok(channel) = db_get_channel(&id).await { + if let Ok(channel) = handles::select_channel(&id).await { return Ok(web::Json(channel)); } @@ -257,7 +263,7 @@ async fn get_channel(id: web::Path) -> Result #[get("/channels")] #[has_any_role("Role::Admin", type = "Role")] async fn get_all_channels() -> Result { - if let Ok(channel) = db_get_all_channels().await { + if let Ok(channel) = handles::select_all_channels().await { return Ok(web::Json(channel)); } @@ -278,7 +284,10 @@ async fn patch_channel( id: web::Path, data: web::Json, ) -> Result { - if db_update_channel(*id, data.into_inner()).await.is_ok() { + if handles::update_channel(*id, data.into_inner()) + .await + .is_ok() + { return Ok("Update Success"); }; @@ -333,7 +342,7 @@ async fn get_playout_config( id: web::Path, _details: AuthDetails, ) -> Result { - if let Ok(channel) = db_get_channel(&id).await { + if let Ok(channel) = handles::select_channel(&id).await { if let Ok(config) = read_playout_config(&channel.config_path) { return Ok(web::Json(config)); } @@ -354,7 +363,7 @@ async fn update_playout_config( id: web::Path, data: web::Json, ) -> Result { - if let Ok(channel) = db_get_channel(&id).await { + if let Ok(channel) = handles::select_channel(&id).await { if let Ok(f) = std::fs::OpenOptions::new() .write(true) .truncate(true) @@ -384,7 +393,7 @@ async fn update_playout_config( #[get("/presets/{id}")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] async fn get_presets(id: web::Path) -> Result { - if let Ok(presets) = db_get_presets(*id).await { + if let Ok(presets) = handles::select_presets(*id).await { return Ok(web::Json(presets)); } @@ -405,7 +414,7 @@ async fn update_preset( id: web::Path, data: web::Json, ) -> Result { - if db_update_preset(&id, data.into_inner()).await.is_ok() { + if handles::update_preset(&id, data.into_inner()).await.is_ok() { return Ok("Update Success"); } @@ -423,7 +432,7 @@ async fn update_preset( #[post("/presets/")] #[has_any_role("Role::Admin", "Role::User", type = "Role")] async fn add_preset(data: web::Json) -> Result { - if db_add_preset(data.into_inner()).await.is_ok() { + if handles::insert_preset(data.into_inner()).await.is_ok() { return Ok("Add preset Success"); } @@ -439,7 +448,7 @@ async fn add_preset(data: web::Json) -> Result) -> Result { - if db_delete_preset(&id).await.is_ok() { + if handles::delete_preset(&id).await.is_ok() { return Ok("Delete preset Success"); } @@ -763,5 +772,34 @@ async fn save_file( payload: Multipart, obj: web::Query, ) -> Result { - upload(*id, payload, &obj.path).await + upload(*id, payload, &obj.path, false).await +} + +/// **Import playlist** +/// +/// Import text/m3u file and convert it to a playlist +/// lines with leading "#" will be ignore +/// +/// ```BASH +/// curl -X POST http://127.0.0.1:8787/api/file/1/import/ -H 'Authorization: ' +/// -F "file=@list.m3u" +/// ``` +#[put("/file/{id}/import/")] +#[has_any_role("Role::Admin", "Role::User", type = "Role")] +async fn import_playlist( + id: web::Path, + payload: Multipart, + obj: web::Query, +) -> Result { + let file = Path::new(&obj.file).file_name().unwrap_or_default(); + let path = env::temp_dir().join(&file).to_string_lossy().to_string(); + let (config, _) = playout_config(&id).await?; + let channel = handles::select_channel(&id).await?; + + upload(*id, payload, &path, true).await?; + import_file(&config, &obj.date, Some(channel.name), &path)?; + + fs::remove_file(path)?; + + Ok(HttpResponse::Ok().into()) } diff --git a/ffplayout-api/src/utils/handles.rs b/ffplayout-api/src/db/handles.rs similarity index 84% rename from ffplayout-api/src/utils/handles.rs rename to ffplayout-api/src/db/handles.rs index f505b5de..dc1927f1 100644 --- a/ffplayout-api/src/utils/handles.rs +++ b/ffplayout-api/src/db/handles.rs @@ -7,11 +7,8 @@ use rand::{distributions::Alphanumeric, Rng}; use simplelog::*; use sqlx::{migrate::MigrateDatabase, sqlite::SqliteQueryResult, Pool, Sqlite, SqlitePool}; -use crate::utils::{ - db_path, local_utc_offset, - models::{Channel, TextPreset, User}, - GlobalSettings, -}; +use crate::db::models::{Channel, TextPreset, User}; +use crate::utils::{db_path, local_utc_offset, GlobalSettings}; #[derive(Debug, sqlx::FromRow)] struct Role { @@ -19,7 +16,7 @@ struct Role { } async fn create_schema() -> Result { - let conn = db_connection().await?; + let conn = connection().await?; let query = "PRAGMA foreign_keys = ON; CREATE TABLE IF NOT EXISTS global ( @@ -96,7 +93,7 @@ pub async fn db_init(domain: Option) -> Result<&'static str, Box format!("http://{d}/live/stream.m3u8"), @@ -130,15 +127,15 @@ pub async fn db_init(domain: Option) -> Result<&'static str, Box Result, sqlx::Error> { +pub async fn connection() -> Result, sqlx::Error> { let db_path = db_path().unwrap(); let conn = SqlitePool::connect(&db_path).await?; Ok(conn) } -pub async fn db_global() -> Result { - let conn = db_connection().await?; +pub async fn select_global() -> Result { + let conn = connection().await?; let query = "SELECT secret FROM global WHERE id = 1"; let result: GlobalSettings = sqlx::query_as(query).fetch_one(&conn).await?; conn.close().await; @@ -146,8 +143,8 @@ pub async fn db_global() -> Result { Ok(result) } -pub async fn db_get_channel(id: &i64) -> Result { - let conn = db_connection().await?; +pub async fn select_channel(id: &i64) -> Result { + let conn = connection().await?; let query = "SELECT * FROM channels WHERE id = $1"; let mut result: Channel = sqlx::query_as(query).bind(id).fetch_one(&conn).await?; conn.close().await; @@ -157,8 +154,8 @@ pub async fn db_get_channel(id: &i64) -> Result { Ok(result) } -pub async fn db_get_all_channels() -> Result, sqlx::Error> { - let conn = db_connection().await?; +pub async fn select_all_channels() -> Result, sqlx::Error> { + let conn = connection().await?; let query = "SELECT * FROM channels"; let mut results: Vec = sqlx::query_as(query).fetch_all(&conn).await?; conn.close().await; @@ -170,11 +167,8 @@ pub async fn db_get_all_channels() -> Result, sqlx::Error> { Ok(results) } -pub async fn db_update_channel( - id: i64, - channel: Channel, -) -> Result { - let conn = db_connection().await?; +pub async fn update_channel(id: i64, channel: Channel) -> Result { + let conn = connection().await?; let query = "UPDATE channels SET name = $2, preview_url = $3, config_path = $4, extra_extensions = $5 WHERE id = $1"; let result: SqliteQueryResult = sqlx::query(query) @@ -190,8 +184,8 @@ pub async fn db_update_channel( Ok(result) } -pub async fn db_add_channel(channel: Channel) -> Result { - let conn = db_connection().await?; +pub async fn insert_channel(channel: Channel) -> Result { + let conn = connection().await?; let query = "INSERT INTO channels (name, preview_url, config_path, extra_extensions, service) VALUES($1, $2, $3, $4, $5)"; let result = sqlx::query(query) @@ -211,8 +205,8 @@ pub async fn db_add_channel(channel: Channel) -> Result { Ok(new_channel) } -pub async fn db_delete_channel(id: &i64) -> Result { - let conn = db_connection().await?; +pub async fn delete_channel(id: &i64) -> Result { + let conn = connection().await?; let query = "DELETE FROM channels WHERE id = $1"; let result: SqliteQueryResult = sqlx::query(query).bind(id).execute(&conn).await?; @@ -221,8 +215,8 @@ pub async fn db_delete_channel(id: &i64) -> Result Result { - let conn = db_connection().await?; +pub async fn select_role(id: &i64) -> Result { + let conn = connection().await?; let query = "SELECT name FROM roles WHERE id = $1"; let result: Role = sqlx::query_as(query).bind(id).fetch_one(&conn).await?; conn.close().await; @@ -230,8 +224,8 @@ pub async fn db_role(id: &i64) -> Result { Ok(result.name) } -pub async fn db_login(user: &str) -> Result { - let conn = db_connection().await?; +pub async fn select_login(user: &str) -> Result { + let conn = connection().await?; let query = "SELECT id, mail, username, password, salt, role_id FROM user WHERE username = $1"; let result: User = sqlx::query_as(query).bind(user).fetch_one(&conn).await?; conn.close().await; @@ -239,8 +233,8 @@ pub async fn db_login(user: &str) -> Result { Ok(result) } -pub async fn db_get_user(user: &str) -> Result { - let conn = db_connection().await?; +pub async fn select_user(user: &str) -> Result { + let conn = connection().await?; let query = "SELECT id, mail, username, role_id FROM user WHERE username = $1"; let result: User = sqlx::query_as(query).bind(user).fetch_one(&conn).await?; conn.close().await; @@ -248,8 +242,8 @@ pub async fn db_get_user(user: &str) -> Result { Ok(result) } -pub async fn db_add_user(user: User) -> Result { - let conn = db_connection().await?; +pub async fn insert_user(user: User) -> Result { + let conn = connection().await?; let salt = SaltString::generate(&mut OsRng); let password_hash = Argon2::default() .hash_password(user.password.clone().as_bytes(), &salt) @@ -270,8 +264,8 @@ pub async fn db_add_user(user: User) -> Result { Ok(result) } -pub async fn db_update_user(id: i64, fields: String) -> Result { - let conn = db_connection().await?; +pub async fn update_user(id: i64, fields: String) -> Result { + let conn = connection().await?; let query = format!("UPDATE user SET {fields} WHERE id = $1"); let result: SqliteQueryResult = sqlx::query(&query).bind(id).execute(&conn).await?; conn.close().await; @@ -279,8 +273,8 @@ pub async fn db_update_user(id: i64, fields: String) -> Result Result, sqlx::Error> { - let conn = db_connection().await?; +pub async fn select_presets(id: i64) -> Result, sqlx::Error> { + let conn = connection().await?; let query = "SELECT * FROM presets WHERE channel_id = $1"; let result: Vec = sqlx::query_as(query).bind(id).fetch_all(&conn).await?; conn.close().await; @@ -288,11 +282,8 @@ pub async fn db_get_presets(id: i64) -> Result, sqlx::Error> { Ok(result) } -pub async fn db_update_preset( - id: &i64, - preset: TextPreset, -) -> Result { - let conn = db_connection().await?; +pub async fn update_preset(id: &i64, preset: TextPreset) -> Result { + let conn = connection().await?; let query = "UPDATE presets SET name = $1, text = $2, x = $3, y = $4, fontsize = $5, line_spacing = $6, fontcolor = $7, alpha = $8, box = $9, boxcolor = $10, boxborderw = 11 WHERE id = $12"; @@ -316,8 +307,8 @@ pub async fn db_update_preset( Ok(result) } -pub async fn db_add_preset(preset: TextPreset) -> Result { - let conn = db_connection().await?; +pub async fn insert_preset(preset: TextPreset) -> Result { + let conn = connection().await?; let query = "INSERT INTO presets (channel_id, name, text, x, y, fontsize, line_spacing, fontcolor, alpha, box, boxcolor, boxborderw) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)"; @@ -341,8 +332,8 @@ pub async fn db_add_preset(preset: TextPreset) -> Result Result { - let conn = db_connection().await?; +pub async fn delete_preset(id: &i64) -> Result { + let conn = connection().await?; let query = "DELETE FROM presets WHERE id = $1;"; let result: SqliteQueryResult = sqlx::query(query).bind(id).execute(&conn).await?; conn.close().await; diff --git a/ffplayout-api/src/db/mod.rs b/ffplayout-api/src/db/mod.rs new file mode 100644 index 00000000..bec83121 --- /dev/null +++ b/ffplayout-api/src/db/mod.rs @@ -0,0 +1,2 @@ +pub mod handles; +pub mod models; diff --git a/ffplayout-api/src/utils/models.rs b/ffplayout-api/src/db/models.rs similarity index 100% rename from ffplayout-api/src/utils/models.rs rename to ffplayout-api/src/db/models.rs diff --git a/ffplayout-api/src/main.rs b/ffplayout-api/src/main.rs index 2b651475..349d1394 100644 --- a/ffplayout-api/src/main.rs +++ b/ffplayout-api/src/main.rs @@ -9,21 +9,23 @@ use actix_web_httpauth::middleware::HttpAuthentication; use clap::Parser; use simplelog::*; +pub mod api; +pub mod db; pub mod utils; -use utils::{ - args_parse::Args, - auth, db_path, init_config, - models::LoginUser, +use api::{ + auth, routes::{ add_channel, add_dir, add_preset, add_user, control_playout, del_playlist, delete_preset, file_browser, gen_playlist, get_all_channels, get_channel, get_log, get_playlist, - get_playout_config, get_presets, get_user, login, media_current, media_last, media_next, - move_rename, patch_channel, process_control, remove, remove_channel, save_file, - save_playlist, send_text_message, update_playout_config, update_preset, update_user, + get_playout_config, get_presets, get_user, import_playlist, login, media_current, + media_last, media_next, move_rename, patch_channel, process_control, remove, + remove_channel, save_file, save_playlist, send_text_message, update_playout_config, + update_preset, update_user, }, - run_args, Role, }; +use db::models::LoginUser; +use utils::{args_parse::Args, db_path, init_config, run_args, Role}; use ffplayout_lib::utils::{init_logging, PlayoutConfig}; @@ -118,7 +120,8 @@ async fn main() -> std::io::Result<()> { .service(add_dir) .service(move_rename) .service(remove) - .service(save_file), + .service(save_file) + .service(import_playlist), ) .service(Files::new("/", public_path()).index_file("index.html")) }) diff --git a/ffplayout-api/src/utils/channels.rs b/ffplayout-api/src/utils/channels.rs index 9c6c145b..29deb4bc 100644 --- a/ffplayout-api/src/utils/channels.rs +++ b/ffplayout-api/src/utils/channels.rs @@ -2,12 +2,9 @@ use std::fs; use simplelog::*; -use crate::utils::{ - control::control_service, - errors::ServiceError, - handles::{db_add_channel, db_delete_channel, db_get_channel}, - models::Channel, -}; +use crate::utils::{control::control_service, errors::ServiceError}; + +use crate::db::{handles, models::Channel}; pub async fn create_channel(target_channel: Channel) -> Result { if !target_channel.service.starts_with("ffplayout@") { @@ -23,14 +20,14 @@ pub async fn create_channel(target_channel: Channel) -> Result Result<(), ServiceError> { - let channel = db_get_channel(&id).await?; + let channel = handles::select_channel(&id).await?; control_service(channel.id, "stop").await?; control_service(channel.id, "disable").await?; @@ -38,7 +35,7 @@ pub async fn delete_channel(id: i64) -> Result<(), ServiceError> { error!("{e}"); }; - db_delete_channel(&id).await?; + handles::delete_channel(&id).await?; Ok(()) } diff --git a/ffplayout-api/src/utils/control.rs b/ffplayout-api/src/utils/control.rs index 692d43aa..4175ed4f 100644 --- a/ffplayout-api/src/utils/control.rs +++ b/ffplayout-api/src/utils/control.rs @@ -6,7 +6,8 @@ use reqwest::{ }; use serde::{Deserialize, Serialize}; -use crate::utils::{errors::ServiceError, handles::db_get_channel, playout_config}; +use crate::db::handles::select_channel; +use crate::utils::{errors::ServiceError, playout_config}; use ffplayout_lib::vec_strings; #[derive(Debug, Deserialize, Serialize, Clone)] @@ -56,7 +57,7 @@ struct SystemD { impl SystemD { async fn new(id: i64) -> Result { - let channel = db_get_channel(&id).await?; + let channel = select_channel(&id).await?; Ok(Self { service: channel.service, diff --git a/ffplayout-api/src/utils/files.rs b/ffplayout-api/src/utils/files.rs index 3672990f..1371b3ce 100644 --- a/ffplayout-api/src/utils/files.rs +++ b/ffplayout-api/src/utils/files.rs @@ -47,9 +47,9 @@ pub struct VideoFile { /// /// This function takes care, that it is not possible to break out from root_path. /// It also gives alway a relative path back. -fn norm_abs_path(root_path: &String, input_path: &String) -> (PathBuf, String, String) { - let mut path = PathBuf::from(root_path.clone()); - let path_relative = RelativePath::new(&root_path) +fn norm_abs_path(root_path: &str, input_path: &str) -> (PathBuf, String, String) { + let mut path = PathBuf::from(root_path); + let path_relative = RelativePath::new(root_path) .normalize() .to_string() .replace("../", ""); @@ -57,7 +57,11 @@ fn norm_abs_path(root_path: &String, input_path: &String) -> (PathBuf, String, S .normalize() .to_string() .replace("../", ""); - let path_suffix = path.file_name().unwrap().to_string_lossy().to_string(); + let path_suffix = path + .file_name() + .unwrap_or_default() + .to_string_lossy() + .to_string(); if input_path.starts_with(root_path) || source_relative.starts_with(&path_relative) { source_relative = source_relative @@ -225,7 +229,7 @@ pub async fn rename_file(id: i64, move_object: &MoveObject) -> Result Result<(), ServiceError> { +pub async fn remove_file_or_folder(id: i64, source_path: &str) -> Result<(), ServiceError> { let (config, _) = playout_config(&id).await?; let (source, _, _) = norm_abs_path(&config.storage.path, source_path); @@ -258,7 +262,7 @@ pub async fn remove_file_or_folder(id: i64, source_path: &String) -> Result<(), Err(ServiceError::InternalServerError) } -async fn valid_path(id: i64, path: &String) -> Result { +async fn valid_path(id: i64, path: &str) -> Result { let (config, _) = playout_config(&id).await?; let (test_path, _, _) = norm_abs_path(&config.storage.path, path); @@ -272,7 +276,8 @@ async fn valid_path(id: i64, path: &String) -> Result { pub async fn upload( id: i64, mut payload: Multipart, - path: &String, + path: &str, + abs_path: bool, ) -> Result { while let Some(mut field) = payload.try_next().await? { let content_disposition = field.content_disposition(); @@ -286,8 +291,14 @@ pub async fn upload( .get_filename() .map_or_else(|| rand_string.to_string(), sanitize_filename::sanitize); - let target_path = valid_path(id, path).await?; - let filepath = target_path.join(filename); + let filepath; + + if abs_path { + filepath = PathBuf::from(path); + } else { + let target_path = valid_path(id, path).await?; + filepath = target_path.join(filename); + } if filepath.is_file() { return Err(ServiceError::BadRequest("Target already exists!".into())); diff --git a/ffplayout-api/src/utils/mod.rs b/ffplayout-api/src/utils/mod.rs index e60ed063..6d8bf335 100644 --- a/ffplayout-api/src/utils/mod.rs +++ b/ffplayout-api/src/utils/mod.rs @@ -12,22 +12,17 @@ use rpassword::read_password; use simplelog::*; pub mod args_parse; -pub mod auth; pub mod channels; pub mod control; pub mod errors; pub mod files; -pub mod handles; -pub mod models; pub mod playlist; -pub mod routes; -use crate::utils::{ - args_parse::Args, - errors::ServiceError, - handles::{db_add_user, db_get_channel, db_global, db_init}, +use crate::db::{ + handles::{db_init, insert_user, select_channel, select_global}, models::{Channel, User}, }; +use crate::utils::{args_parse::Args, errors::ServiceError}; use ffplayout_lib::utils::PlayoutConfig; #[derive(Clone, Eq, PartialEq)] @@ -54,7 +49,7 @@ pub struct GlobalSettings { impl GlobalSettings { async fn new() -> Self { - let global_settings = db_global(); + let global_settings = select_global(); match global_settings.await { Ok(g) => g, @@ -165,7 +160,7 @@ pub async fn run_args(mut args: Args) -> Result<(), i32> { token: None, }; - if let Err(e) = db_add_user(user).await { + if let Err(e) = insert_user(user).await { error!("{e}"); return Err(1); }; @@ -186,7 +181,7 @@ pub fn read_playout_config(path: &str) -> Result> } pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Channel), ServiceError> { - if let Ok(channel) = db_get_channel(channel_id).await { + if let Ok(channel) = select_channel(channel_id).await { if let Ok(config) = read_playout_config(&channel.config_path.clone()) { return Ok((config, channel)); } @@ -198,7 +193,7 @@ pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Channel) } pub async fn read_log_file(channel_id: &i64, date: &str) -> Result { - if let Ok(channel) = db_get_channel(channel_id).await { + if let Ok(channel) = select_channel(channel_id).await { let mut date_str = "".to_string(); if !date.is_empty() { diff --git a/ffplayout-frontend b/ffplayout-frontend index 51719eb9..0060d40b 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit 51719eb9c03d26da8ffac6a677d1c41b756bdf83 +Subproject commit 0060d40b597a8e595a2dbef6e493821be2e7d12f