restructure api, import playlist from text file #195

This commit is contained in:
jb-alvarado 2022-10-02 21:43:35 +02:00
parent dcc4616421
commit ec4f5d2ac2
14 changed files with 154 additions and 114 deletions

2
Cargo.lock generated
View File

@ -949,7 +949,7 @@ dependencies = [
[[package]]
name = "ffplayout-api"
version = "0.6.3"
version = "0.7.0"
dependencies = [
"actix-files",
"actix-multipart",

View File

@ -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]

View File

@ -0,0 +1,2 @@
pub mod auth;
pub mod routes;

View File

@ -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<T> {
@ -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<User>) -> 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<User>) -> 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<User>) -> impl Responder {
#[get("/user")]
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
async fn get_user(user: web::ReqData<LoginUser>) -> Result<impl Responder, ServiceError> {
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<User>) -> Result<impl Responder, ServiceError> {
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<User>) -> Result<impl Responder, ServiceError>
#[get("/channel/{id}")]
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
async fn get_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
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<i64>) -> Result<impl Responder, ServiceError>
#[get("/channels")]
#[has_any_role("Role::Admin", type = "Role")]
async fn get_all_channels() -> Result<impl Responder, ServiceError> {
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<i64>,
data: web::Json<Channel>,
) -> Result<impl Responder, ServiceError> {
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<i64>,
_details: AuthDetails<Role>,
) -> Result<impl Responder, ServiceError> {
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<i64>,
data: web::Json<PlayoutConfig>,
) -> Result<impl Responder, ServiceError> {
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<i64>) -> Result<impl Responder, ServiceError> {
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<i64>,
data: web::Json<TextPreset>,
) -> Result<impl Responder, ServiceError> {
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<TextPreset>) -> Result<impl Responder, ServiceError> {
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<TextPreset>) -> Result<impl Responder, Servi
#[delete("/presets/{id}")]
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
async fn delete_preset(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
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<FileObj>,
) -> Result<HttpResponse, ServiceError> {
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: <TOKEN>'
/// -F "file=@list.m3u"
/// ```
#[put("/file/{id}/import/")]
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
async fn import_playlist(
id: web::Path<i64>,
payload: Multipart,
obj: web::Query<ImportObj>,
) -> Result<HttpResponse, ServiceError> {
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())
}

View File

@ -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<SqliteQueryResult, sqlx::Error> {
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<String>) -> Result<&'static str, Box<dyn std
.map(char::from)
.collect();
let instances = db_connection().await?;
let instances = connection().await?;
let url = match domain {
Some(d) => format!("http://{d}/live/stream.m3u8"),
@ -130,15 +127,15 @@ pub async fn db_init(domain: Option<String>) -> Result<&'static str, Box<dyn std
Ok("Database initialized!")
}
pub async fn db_connection() -> Result<Pool<Sqlite>, sqlx::Error> {
pub async fn connection() -> Result<Pool<Sqlite>, sqlx::Error> {
let db_path = db_path().unwrap();
let conn = SqlitePool::connect(&db_path).await?;
Ok(conn)
}
pub async fn db_global() -> Result<GlobalSettings, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_global() -> Result<GlobalSettings, sqlx::Error> {
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<GlobalSettings, sqlx::Error> {
Ok(result)
}
pub async fn db_get_channel(id: &i64) -> Result<Channel, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_channel(id: &i64) -> Result<Channel, sqlx::Error> {
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<Channel, sqlx::Error> {
Ok(result)
}
pub async fn db_get_all_channels() -> Result<Vec<Channel>, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_all_channels() -> Result<Vec<Channel>, sqlx::Error> {
let conn = connection().await?;
let query = "SELECT * FROM channels";
let mut results: Vec<Channel> = sqlx::query_as(query).fetch_all(&conn).await?;
conn.close().await;
@ -170,11 +167,8 @@ pub async fn db_get_all_channels() -> Result<Vec<Channel>, sqlx::Error> {
Ok(results)
}
pub async fn db_update_channel(
id: i64,
channel: Channel,
) -> Result<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn update_channel(id: i64, channel: Channel) -> Result<SqliteQueryResult, sqlx::Error> {
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<Channel, sqlx::Error> {
let conn = db_connection().await?;
pub async fn insert_channel(channel: Channel) -> Result<Channel, sqlx::Error> {
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<Channel, sqlx::Error> {
Ok(new_channel)
}
pub async fn db_delete_channel(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn delete_channel(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
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<SqliteQueryResult, sqlx::Erro
Ok(result)
}
pub async fn db_role(id: &i64) -> Result<String, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_role(id: &i64) -> Result<String, sqlx::Error> {
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<String, sqlx::Error> {
Ok(result.name)
}
pub async fn db_login(user: &str) -> Result<User, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_login(user: &str) -> Result<User, sqlx::Error> {
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<User, sqlx::Error> {
Ok(result)
}
pub async fn db_get_user(user: &str) -> Result<User, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_user(user: &str) -> Result<User, sqlx::Error> {
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<User, sqlx::Error> {
Ok(result)
}
pub async fn db_add_user(user: User) -> Result<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn insert_user(user: User) -> Result<SqliteQueryResult, sqlx::Error> {
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<SqliteQueryResult, sqlx::Error> {
Ok(result)
}
pub async fn db_update_user(id: i64, fields: String) -> Result<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn update_user(id: i64, fields: String) -> Result<SqliteQueryResult, sqlx::Error> {
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<SqliteQueryResult
Ok(result)
}
pub async fn db_get_presets(id: i64) -> Result<Vec<TextPreset>, sqlx::Error> {
let conn = db_connection().await?;
pub async fn select_presets(id: i64) -> Result<Vec<TextPreset>, sqlx::Error> {
let conn = connection().await?;
let query = "SELECT * FROM presets WHERE channel_id = $1";
let result: Vec<TextPreset> = 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<Vec<TextPreset>, sqlx::Error> {
Ok(result)
}
pub async fn db_update_preset(
id: &i64,
preset: TextPreset,
) -> Result<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn update_preset(id: &i64, preset: TextPreset) -> Result<SqliteQueryResult, sqlx::Error> {
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<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn insert_preset(preset: TextPreset) -> Result<SqliteQueryResult, sqlx::Error> {
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<SqliteQueryResult, sqlx
Ok(result)
}
pub async fn db_delete_preset(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
let conn = db_connection().await?;
pub async fn delete_preset(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
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;

View File

@ -0,0 +1,2 @@
pub mod handles;
pub mod models;

View File

@ -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"))
})

View File

@ -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<Channel, ServiceError> {
if !target_channel.service.starts_with("ffplayout@") {
@ -23,14 +20,14 @@ pub async fn create_channel(target_channel: Channel) -> Result<Channel, ServiceE
&target_channel.config_path,
)?;
let new_channel = db_add_channel(target_channel).await?;
let new_channel = handles::insert_channel(target_channel).await?;
control_service(new_channel.id, "enable").await?;
Ok(new_channel)
}
pub async fn delete_channel(id: i64) -> 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(())
}

View File

@ -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<Self, ServiceError> {
let channel = db_get_channel(&id).await?;
let channel = select_channel(&id).await?;
Ok(Self {
service: channel.service,

View File

@ -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<MoveObject
Err(ServiceError::InternalServerError)
}
pub async fn remove_file_or_folder(id: i64, source_path: &String) -> 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<PathBuf, ServiceError> {
async fn valid_path(id: i64, path: &str) -> Result<PathBuf, ServiceError> {
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<PathBuf, ServiceError> {
pub async fn upload(
id: i64,
mut payload: Multipart,
path: &String,
path: &str,
abs_path: bool,
) -> Result<HttpResponse, ServiceError> {
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()));

View File

@ -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<PlayoutConfig, Box<dyn Error>>
}
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<String, ServiceError> {
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() {

@ -1 +1 @@
Subproject commit 51719eb9c03d26da8ffac6a677d1c41b756bdf83
Subproject commit 0060d40b597a8e595a2dbef6e493821be2e7d12f