diff --git a/.gitignore b/.gitignore index 2ad4d82..a24d764 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ aws/playbooks/hosts ts/dist/ ts/node_modules/ .vscode/settings.json +api/.vscode/settings.json diff --git a/api/src/admin/apikey.rs b/api/src/admin/apikey.rs index fd1ac5a..4393422 100644 --- a/api/src/admin/apikey.rs +++ b/api/src/admin/apikey.rs @@ -5,7 +5,12 @@ use rocket::http::Status; use crate::db::{self, DB_PATH}; pub struct ApiKey { + // These are used by rocket's driver code/decl macros however cargo + // is not able to check those as the code is generated at compile time. + // The dead code thing is just to stifle pointless warnings + #[allow(dead_code)] uid: String, + #[allow(dead_code)] key: String } diff --git a/api/src/admin/mod.rs b/api/src/admin/mod.rs index 6c2e7d5..29d2863 100644 --- a/api/src/admin/mod.rs +++ b/api/src/admin/mod.rs @@ -2,15 +2,21 @@ mod apikey; mod response; +mod util; use std::collections::HashMap; +use std::io::Result; +use std::fs; +use std::path::{Path, PathBuf}; + +use rocket::data::{Data, ToByteUnit}; +use rocket::serde::json::Json; +use rocket_dyn_templates::Template; +use response::{bad_request, ok}; + use apikey::ApiKey; use response::ActionResponse; -use rocket::serde::json::Json; - - - -use rocket_dyn_templates::Template; +use crate::common::get_clips_dir; #[get("/dashboard")] pub async fn login_dashboard() -> Template { @@ -22,18 +28,35 @@ pub async fn login_dashboard() -> Template { #[post("/dashboard")] pub async fn dashboard(_key: ApiKey) -> Json { - // API Key auth'd for us so we don't need to bother checking, - // this just serves to confirm the credentials are correct - Json(ActionResponse("ok")) + // Assuming the api key check doesn't fail we can reply with Ok + // at the application level + ok() } -#[post("/upload-video?&")] -async fn updload_video(_key: ApiKey, category: String, filename: String) -> &'static str { - todo!() +#[post("/upload-video//", data = "")] +pub async fn updload_video(_key: ApiKey, category: PathBuf, filename: PathBuf, data: Data<'_>) +-> Result> { + // filenames must have a basename .len of at least 1 + '.' + extension + // Valid file extensions are mkv|mp4|webm + + if util::valid_filename(&filename) == false { + return Ok(bad_request(Some("Invalid filename(s)"))); + } + + let clips = get_clips_dir(); + fs::create_dir_all(Path::new(&clips).join(&category))?; + + let filepath = Path::new(&clips).join(category).join(filename); + data.open(200.megabytes()).into_file(filepath).await?; + Ok(ok()) } -#[delete("/remove-video?&")] -async fn remove_video(_key: ApiKey, category: String, filename: String) -> &'static str { - todo!() +#[delete("/remove-video//")] +pub async fn remove_video(_key: ApiKey, category: PathBuf, filename: PathBuf) +-> Result> { + let clips = get_clips_dir(); + let path = Path::new(&clips).join(&category).join(&filename); + fs::remove_file(path)?; + Ok(ok()) } diff --git a/api/src/main.rs b/api/src/main.rs index cff6f78..b09ce17 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -35,7 +35,9 @@ async fn main() { .mount("/video", routes![video::get_video]) // videos .mount("/admin", routes![ admin::login_dashboard, - admin::dashboard + admin::dashboard, + admin::updload_video, + admin::remove_video ]) .attach(Template::fairing()) .launch().await;