From 8521db333bf52954854f7aecf40f6759dcfafe38 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Fri, 22 Sep 2023 00:38:26 -0400 Subject: [PATCH] Set up the delete route Sets up the delete route, including post-delete redirect back to the root. Also adds logging. Delete does not actually delete things yet. --- Cargo.lock | 60 +++++++++++++++++++++++++++++++++++ file-service/Cargo.toml | 2 ++ file-service/src/html.rs | 66 +++++++++++++++++++++++++++++---------- file-service/src/main.rs | 59 ++++++++++++++++++++++++---------- file-service/src/pages.rs | 47 +++++++++++++++++----------- 5 files changed, 182 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a473bb..42f19e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -611,6 +611,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log 0.4.20", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -695,12 +708,14 @@ dependencies = [ "http", "image 0.23.14", "iron", + "log 0.4.20", "logger", "mime 0.3.17", "mime_guess 2.0.4", "mustache", "orizentic", "params", + "pretty_env_logger", "router", "serde 1.0.188", "serde_json", @@ -1515,6 +1530,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.10.16" @@ -1729,6 +1750,17 @@ dependencies = [ "url 1.7.2", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix", + "windows-sys", +] + [[package]] name = "itertools" version = "0.10.5" @@ -2616,6 +2648,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log 0.4.20", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3417,6 +3459,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -4086,6 +4137,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/file-service/Cargo.toml b/file-service/Cargo.toml index 0afba1a..6baf42a 100644 --- a/file-service/Cargo.toml +++ b/file-service/Cargo.toml @@ -27,3 +27,5 @@ thiserror = "1.0.20" tokio = { version = "1", features = [ "full" ] } uuid = { version = "0.4", features = [ "serde", "v4" ] } warp = { version = "0.3" } +pretty_env_logger = { version = "0.5" } +log = { version = "0.4" } diff --git a/file-service/src/html.rs b/file-service/src/html.rs index 02cffd3..b11881b 100644 --- a/file-service/src/html.rs +++ b/file-service/src/html.rs @@ -2,6 +2,7 @@ use build_html::{self, Html, HtmlContainer}; #[derive(Clone, Debug)] pub struct Form { + path: String, method: String, encoding: Option, elements: String, @@ -10,12 +11,18 @@ pub struct Form { impl Form { pub fn new() -> Self { Self { + path: "/".to_owned(), method: "get".to_owned(), encoding: None, elements: "".to_owned(), } } + pub fn with_path(mut self, path: &str) -> Self { + self.path = path.to_owned(); + self + } + pub fn with_method(mut self, method: &str) -> Self { self.method = method.to_owned(); self @@ -30,11 +37,12 @@ impl Form { impl Html for Form { fn to_html_string(&self) -> String { let encoding = match self.encoding { - Some(ref encoding) => format!("encoding={encoding}", encoding = encoding), + Some(ref encoding) => format!("encoding=\"{encoding}\"", encoding = encoding), None => format!(""), }; format!( - "
\n{elements}\n
\n", + "
\n{elements}\n
\n", + path = self.path, method = self.method, encoding = encoding, elements = self.elements.to_html_string() @@ -52,36 +60,58 @@ impl HtmlContainer for Form { pub struct Input { ty: String, name: String, - id: String, + id: Option, value: Option, + content: Option, } impl Html for Input { fn to_html_string(&self) -> String { + let id = match self.id { + Some(ref id) => format!("id=\"{}\"", id), + None => "".to_owned(), + }; + let value = match self.value { + Some(ref value) => format!("value=\"{}\"", value), + None => "".to_owned(), + }; + format!( - "{value}\n", + "{content}\n", ty = self.ty, name = self.name, - id = self.id, - value = self.value.clone().unwrap_or("".to_owned()), + id = id, + value = value, + content = self.content.clone().unwrap_or("".to_owned()), ) } } impl Input { - pub fn new(ty: &str, name: &str, id: &str) -> Self { + pub fn new(ty: &str, name: &str) -> Self { Self { ty: ty.to_owned(), name: name.to_owned(), - id: id.to_owned(), + id: None, value: None, + content: None, } } + pub fn with_id(mut self, val: &str) -> Self { + self.id = Some(val.to_owned()); + self + } + pub fn with_value(mut self, val: &str) -> Self { self.value = Some(val.to_owned()); self } + + pub fn with_content(mut self, val: &str) -> Self { + self.content = Some(val.to_owned()); + self + } } #[derive(Clone, Debug)] @@ -111,25 +141,29 @@ impl Html for Label { #[derive(Clone, Debug)] pub struct Button { - name: String, - text: String, + name: Option, + label: String, } impl Button { - pub fn new(name: &str, text: &str) -> Self { + pub fn new(label: &str) -> Self { Self { - name: name.to_owned(), - text: text.to_owned(), + name: None, + label: label.to_owned(), } } } impl Html for Button { fn to_html_string(&self) -> String { + let name = match self.name { + Some(ref name) => format!("name={}", name), + None => "".to_owned(), + }; format!( - "", - name = self.name, - text = self.text + "", + name = name, + label = self.label ) } } diff --git a/file-service/src/main.rs b/file-service/src/main.rs index 14ccb28..efb3dbb 100644 --- a/file-service/src/main.rs +++ b/file-service/src/main.rs @@ -6,11 +6,15 @@ use iron::prelude::*; use iron::response::BodyReader; use iron::status; */ +#[macro_use] +extern crate log; + use http::status::StatusCode; // use mustache::{compile_path, Template}; // use orizentic::{Permissions, ResourceName, Secret}; use build_html::Html; use std::{ + collections::HashMap, io::Read, net::{IpAddr, Ipv4Addr, SocketAddr}, path::Path, @@ -254,21 +258,6 @@ pub async fn main() { let mut router = Router::new(); - router.get( - "/:id", - files::GetFileHandler { - app: app.clone(), - template: compile_path("templates/file.html").expect("the template to compile"), - }, - "get-file-page", - ); - - router.get( - "/:id/raw", - files::GetHandler { app: app.clone() }, - "get-file", - ); - router.post("/", files::PostHandler { app: app.clone() }, "upload-file"); router.delete( @@ -301,13 +290,18 @@ pub async fn main() { .await; */ + pretty_env_logger::init(); + let app = Arc::new(RwLock::new(App::new(Path::new( &std::env::var("FILE_SHARE_DIR").unwrap(), )))); - let root = warp::path!().map({ + let log = warp::log("file_service"); + + let root = warp::path!().and(warp::get()).map({ let app = app.clone(); move || { + info!("root handler"); warp::http::Response::builder() .header("content-type", "text/html") .status(StatusCode::OK) @@ -315,7 +309,20 @@ pub async fn main() { } }); + let post_handler = warp::path!(String) + .and(warp::post()) + .and(warp::filters::body::form()) + .map(|id: String, form: HashMap| { + info!("post_delete {}", id); + info!("form: {:?}", form); + warp::http::Response::builder() + .header("location", "/") + .status(StatusCode::SEE_OTHER) + .body(vec![]) + }); + let thumbnail = warp::path!(String / "tn") + .and(warp::get()) .and(warp::header::optional::("if-none-match")) .map({ let app = app.clone(); @@ -332,6 +339,7 @@ pub async fn main() { }); let file = warp::path!(String) + .and(warp::get()) .and(warp::header::optional::("if-none-match")) .map({ let app = app.clone(); @@ -343,7 +351,24 @@ pub async fn main() { } }); - let server = warp::serve(root.or(file).or(thumbnail)); + let upload = warp::path!().and(warp::post()).map(|| { + println!("upload"); + warp::reply() + }); + + let delete = warp::path!(String).and(warp::delete()).map(|id: String| { + println!("delete {}", id); + warp::reply() + }); + + let server = warp::serve( + root.or(post_handler) + .or(file) + .or(thumbnail) + .or(upload) + .or(delete) + .with(log), + ); server .run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8002)) .await; diff --git a/file-service/src/pages.rs b/file-service/src/pages.rs index 12a92e1..790b644 100644 --- a/file-service/src/pages.rs +++ b/file-service/src/pages.rs @@ -11,30 +11,39 @@ pub fn index(files: Vec>) -> build_html::HtmlPage { .with_encoding("multipart/form-data") .with_container( Container::new(ContainerType::Div) - .with_html(Input::new("file", "file", "file-selector-input")) + .with_html(Input::new("file", "file")) .with_html(Label::new("for-selector-input", "Select a file")), ) - .with_html(Button::new("upload", "Upload file")), + .with_html(Button::new("Upload file")), ); for file in files { - let mut container = - Container::new(ContainerType::Div).with_attributes(vec![("class", "file")]); - match file { - Ok(file) => { - let tn = Container::new(ContainerType::Div) - .with_attributes(vec![("class", "thumbnail")]) - .with_link( - format!("/{}", file.info().id), - Image::new(&format!("{}/tn", file.info().id)).to_html_string(), - ); - container.add_html(tn); - } - Err(err) => { - container.add_paragraph(format!("{:?}", err)); - } - } - page.add_container(container); + let container = match file { + Ok(ref file) => thumbnail(file).with_html( + Form::new() + .with_path(&format!("/{}", file.info().id)) + .with_method("post") + .with_html(Input::new("hidden", "_method").with_value("delete")) + .with_html(Button::new("Delete")), + ), + + Err(err) => Container::new(ContainerType::Div) + .with_attributes(vec![("class", "file")]) + .with_paragraph(format!("{:?}", err)), + }; + page.add_container(container) } page } + +pub fn thumbnail(file: &File) -> Container { + let mut container = Container::new(ContainerType::Div).with_attributes(vec![("class", "file")]); + let tn = Container::new(ContainerType::Div) + .with_attributes(vec![("class", "thumbnail")]) + .with_link( + format!("/{}", file.info().id), + Image::new(&format!("{}/tn", file.info().id)).to_html_string(), + ); + container.add_html(tn); + container +}