From 06db56e40820ec0067d18840648ee786163a3862 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sun, 25 Apr 2021 17:48:09 +0200 Subject: Implement a raw rendering mode for recursive folder download - Raw mode only displays file/folders and is more focused on computer processing - Display a banner in footer to recursively download the current folder with wget --- data/style.scss | 14 +++++++ src/auth.rs | 20 +++++++--- src/listing.rs | 7 ++++ src/renderer.rs | 118 +++++++++++++++++++++++++++++++++++++++++++++++++------- tests/raw.rs | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 20 deletions(-) create mode 100644 tests/raw.rs diff --git a/data/style.scss b/data/style.scss index 7e63751..5a05fe7 100644 --- a/data/style.scss +++ b/data/style.scss @@ -52,6 +52,20 @@ body { padding-top: 1.5rem; font-size: 0.7em; color: var(--footer_color); + + .downloadWget { + display: flex; + flex-direction: row; + justify-content: center; + flex-wrap: wrap; + .cmd { + margin: 0 0 auto; + padding-left: 5px; + + line-height: 13px; + font-family: monospace; + } + } } a { diff --git a/src/auth.rs b/src/auth.rs index 0d97f11..43aca17 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -42,7 +42,7 @@ pub struct RequiredAuth { } /// Return `true` if `basic_auth` is matches any of `required_auth` -pub fn match_auth(basic_auth: BasicAuthParams, required_auth: &[RequiredAuth]) -> bool { +pub fn match_auth(basic_auth: &BasicAuthParams, required_auth: &[RequiredAuth]) -> bool { required_auth .iter() .any(|RequiredAuth { username, password }| { @@ -74,6 +74,9 @@ pub fn get_hash(text: &str) -> Vec { hasher.update(text); hasher.finalize().to_vec() } +pub struct CurrentUser { + pub name: String, +} fn handle_auth(req: &HttpRequest) -> Result<(), ContextualError> { let required_auth = &req.app_data::().unwrap().auth; @@ -85,7 +88,12 @@ fn handle_auth(req: &HttpRequest) -> Result<(), ContextualError> { match BasicAuthParams::try_from_request(req) { Ok(cred) => match match_auth(cred, required_auth) { - true => Ok(()), + true => { + req.extensions_mut().insert(CurrentUser { + name: cred_params.username, + }); + Ok(()) + }, false => Err(ContextualError::InvalidHttpCredentials), }, Err(_) => Err(ContextualError::RequireHttpCredentials), @@ -173,7 +181,7 @@ mod tests { ) { assert_eq!( match_auth( - BasicAuthParams { + &BasicAuthParams { username: param_username.to_owned(), password: param_password.to_owned(), }, @@ -214,7 +222,7 @@ mod tests { password: &str, ) { assert!(match_auth( - BasicAuthParams { + &BasicAuthParams { username: username.to_owned(), password: password.to_owned(), }, @@ -225,7 +233,7 @@ mod tests { #[rstest] fn test_multiple_auth_wrong_username(account_sample: Vec) { assert_eq!(match_auth( - BasicAuthParams { + &BasicAuthParams { username: "unregistered user".to_owned(), password: "pwd0".to_owned(), }, @@ -248,7 +256,7 @@ mod tests { password: &str, ) { assert_eq!(match_auth( - BasicAuthParams { + &BasicAuthParams { username: username.to_owned(), password: password.to_owned(), }, diff --git a/src/listing.rs b/src/listing.rs index b2730de..b00a671 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -12,6 +12,7 @@ use std::time::SystemTime; use strum_macros::{Display, EnumString}; use crate::archive::ArchiveMethod; +use crate::auth::CurrentUser; use crate::errors::{self, ContextualError}; use crate::renderer; use percent_encode_sets::PATH_SEGMENT; @@ -32,6 +33,7 @@ pub struct QueryParameters { pub path: Option, pub sort: Option, pub order: Option, + pub raw: Option, qrcode: Option, download: Option, } @@ -152,6 +154,9 @@ pub fn directory_listing( dir: &actix_files::Directory, req: &HttpRequest, ) -> io::Result { + let extensions = req.extensions(); + let current_user: Option<&CurrentUser> = extensions.get::(); + use actix_web::dev::BodyEncoding; let conf = req.app_data::().unwrap(); let serve_path = req.path(); @@ -387,6 +392,7 @@ pub fn extract_query_parameters(req: &HttpRequest) -> QueryParameters { sort: query.sort, order: query.order, download: query.download, + raw: query.raw, qrcode: query.qrcode.to_owned(), path: query.path.clone(), }, @@ -397,6 +403,7 @@ pub fn extract_query_parameters(req: &HttpRequest) -> QueryParameters { sort: None, order: None, download: None, + raw: None, qrcode: None, path: None, } diff --git a/src/renderer.rs b/src/renderer.rs index d1821dd..ac6b640 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -17,6 +17,7 @@ pub fn page( breadcrumbs: Vec, encoded_dir: &str, conf: &MiniserveConfig, + current_user: Option<&CurrentUser>, ) -> Markup { let upload_route = match conf.random_route { Some(ref random_route) => format!("/{}/upload", random_route), @@ -80,7 +81,7 @@ pub fn page( // wrapped in span so the text doesn't shift slightly when it turns into a link span { bdi { (el.name) } } } @else { - a href=(parametrized_link(&el.link, sort_method, sort_order)) { + a href=(parametrized_link(&el.link, sort_method, sort_order, false)) { bdi { (el.name) } } } @@ -120,22 +121,63 @@ pub fn page( tr { td colspan="3" { span.root-chevron { (chevron_left()) } - a.root href=(parametrized_link("../", sort_method, sort_order)) { + a.root href=(parametrized_link("../", sort_method, sort_order, false)) { "Parent directory" } } } } @for entry in entries { - (entry_row(entry, sort_method, sort_order)) + (entry_row(entry, sort_method, sort_order, false)) } } } a.back href="#top" { (arrow_up()) } - @if !conf.hide_version_footer { - (version_footer()) + div.footer { + (wget_download(&title_path, current_user)) + @if !conf.hide_version_footer { + (version_footer()) + } + } + } + } + } + } +} +/// Renders the file listing +#[allow(clippy::too_many_arguments)] +pub fn raw( + entries: Vec, + is_root: bool, + sort_method: Option, + sort_order: Option, +) -> Markup { + html! { + (DOCTYPE) + html { + body { + table { + thead { + th.name { "Name" } + th.size { "Size" } + th.date { "Last modification" } + } + tbody { + @if !is_root { + tr { + td colspan="3" { + a.root href=(parametrized_link("../", sort_method, sort_order, true)) { + ".." + } + } + } + } + @for entry in entries { + (entry_row(entry, sort_method, sort_order, true)) + } +>>>>>>> 2949329 (Implement a raw rendering mode for recursive folder download) } } } @@ -146,12 +188,36 @@ pub fn page( // Partial: version footer fn version_footer() -> Markup { html! { - p.footer { - (format!("{}/{}", crate_name!(), crate_version!())) - } + div.version { + (format!("{}/{}", crate_name!(), crate_version!())) + } } } +fn wget_download(title_path: &str, current_user: Option<&CurrentUser>) -> Markup { + let count = { + let count_slashes = title_path.matches('/').count(); + if count_slashes > 0 { + count_slashes - 1 + } else { + 0 + } + }; + + let user_params = if let Some(user) = current_user { + format!(" --ask-password --user {}", user.name) + } else { + "".to_string() + }; + + return html! { + div.downloadWget { + p { "Download folder:" } + div.cmd { (format!("wget -r -c -nH -np --cut-dirs={} -R \"index.html*\"{} \"http://{}/?raw=true\"", count, user_params, title_path)) } + } + }; +} + /// Build the action of the upload form fn build_upload_action( upload_route: &str, @@ -232,7 +298,7 @@ fn archive_button( } else { format!( "{}&download={}", - parametrized_link("", sort_method, sort_order,), + parametrized_link("", sort_method, sort_order, false), archive_method ) }; @@ -260,14 +326,19 @@ fn parametrized_link( link: &str, sort_method: Option, sort_order: Option, + raw: bool, ) -> String { + if raw { + return format!("{}?raw=true", make_link_with_trailing_slash(link)); + } + if let Some(method) = sort_method { if let Some(order) = sort_order { let parametrized_link = format!( "{}?sort={}&order={}", make_link_with_trailing_slash(link), method, - order + order, ); return parametrized_link; @@ -315,6 +386,7 @@ fn entry_row( entry: Entry, sort_method: Option, sort_order: Option, + raw: bool, ) -> Markup { html! { tr { @@ -322,7 +394,7 @@ fn entry_row( p { @if entry.is_dir() { @if let Some(symlink_dest) = entry.symlink_info { - a.symlink href=(parametrized_link(&entry.link, sort_method, sort_order)) { + a.symlink href=(parametrized_link(&entry.link, sort_method, sort_order, raw)) { (entry.name) "/" span.symlink-symbol { } a.directory {(symlink_dest) "/"} @@ -345,9 +417,11 @@ fn entry_row( } } - @if let Some(size) = entry.size { - span.mobile-info.size { - (size) + @if !raw { + @if let Some(size) = entry.size { + span.mobile-info.size { + (size) + } } } } @@ -477,6 +551,15 @@ pub fn render_error( conf: &MiniserveConfig, return_address: &str, ) -> Markup { +<<<<<<< HEAD +======= + let link = if has_referer { + return_address.to_string() + } else { + parametrized_link(return_address, sort_method, sort_order, false) + }; + +>>>>>>> 2949329 (Implement a raw rendering mode for recursive folder download) html! { (DOCTYPE) html { @@ -508,8 +591,15 @@ pub fn render_error( } } } +<<<<<<< HEAD @if !conf.hide_version_footer { (version_footer()) +======= + @if !hide_version_footer { + p.footer { + (version_footer()) + } +>>>>>>> 2949329 (Implement a raw rendering mode for recursive folder download) } } } diff --git a/tests/raw.rs b/tests/raw.rs new file mode 100644 index 0000000..5c2227b --- /dev/null +++ b/tests/raw.rs @@ -0,0 +1,103 @@ +mod fixtures; +mod utils; + +use crate::fixtures::TestServer; +use assert_cmd::prelude::*; +use assert_fs::fixture::TempDir; +use fixtures::{port, server, tmpdir, Error}; +use pretty_assertions::assert_eq; +use reqwest::blocking::Client; +use rstest::rstest; +use select::document::Document; +use select::predicate::Class; +use select::predicate::Name; +use std::process::{Command, Stdio}; +use std::thread::sleep; +use std::time::Duration; + +#[rstest] +/// The ui displays the correct wget command to download the folder recursively +fn ui_displays_wget_element(server: TestServer) -> Result<(), Error> { + let client = Client::new(); + + let body = client.get(server.url()).send()?.error_for_status()?; + let parsed = Document::from_read(body)?; + let wget_url = parsed + .find(Class("downloadWget")) + .next() + .unwrap() + .find(Class("cmd")) + .next() + .unwrap() + .text(); + assert_eq!( + wget_url, + format!( + "wget -r -c -nH -np --cut-dirs=0 -R \"index.html*\" \"{}?raw=true\"", + server.url() + ) + ); + + let body = client + .get(format!("{}/very/deeply/nested/", server.url())) + .send()? + .error_for_status()?; + let parsed = Document::from_read(body)?; + let wget_url = parsed + .find(Class("downloadWget")) + .next() + .unwrap() + .find(Class("cmd")) + .next() + .unwrap() + .text(); + assert_eq!( + wget_url, + format!( + "wget -r -c -nH -np --cut-dirs=2 -R \"index.html*\" \"{}very/deeply/nested/?raw=true\"", + server.url() + ) + ); + + Ok(()) +} + +#[rstest] +/// All hrefs in raw mode are links to directories or files & directories end with ?raw=true +fn raw_mode_links_to_directories_end_with_raw_true(server: TestServer) -> Result<(), Error> { + fn verify_a_tags(parsed: Document) { + // Ensure all links end with ?raw=true or are files + for node in parsed.find(Name("a")) { + let class = node.attr("class").unwrap(); + + if class == "root" || class == "directory" { + assert!(node.attr("href").unwrap().ends_with("?raw=true")); + } else if class == "file" { + assert!(true); + } else { + println!( + "This node is a link and neither of class directory, root or file: {:?}", + node + ); + assert!(false); + } + } + } + + let urls = [ + format!("{}?raw=true", server.url()), + format!("{}very?raw=true", server.url()), + format!("{}very/deeply/?raw=true", server.url()), + format!("{}very/deeply/nested?raw=true", server.url()), + ]; + + let client = Client::new(); + // Ensure the links to the archives are not present + for url in urls.iter() { + let body = client.get(url).send()?.error_for_status()?; + let parsed = Document::from_read(body)?; + verify_a_tags(parsed); + } + + Ok(()) +} -- cgit v1.2.3 From b94bb361e30e90656edfce5f9a63d41452ba100f Mon Sep 17 00:00:00 2001 From: jikstra Date: Thu, 2 Sep 2021 15:33:58 +0200 Subject: Fix rebase --- src/auth.rs | 4 ++-- src/listing.rs | 1 + src/renderer.rs | 37 ++++++++++++++++--------------------- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index 43aca17..efdeefb 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -87,10 +87,10 @@ fn handle_auth(req: &HttpRequest) -> Result<(), ContextualError> { } match BasicAuthParams::try_from_request(req) { - Ok(cred) => match match_auth(cred, required_auth) { + Ok(cred) => match match_auth(&cred, required_auth) { true => { req.extensions_mut().insert(CurrentUser { - name: cred_params.username, + name: cred.username }); Ok(()) }, diff --git a/src/listing.rs b/src/listing.rs index b00a671..c1c9597 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -379,6 +379,7 @@ pub fn directory_listing( breadcrumbs, &encoded_dir, conf, + current_user ) .into_string(), ), diff --git a/src/renderer.rs b/src/renderer.rs index ac6b640..b18ac07 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -6,6 +6,7 @@ use maud::{html, Markup, PreEscaped, DOCTYPE}; use std::time::SystemTime; use strum::IntoEnumIterator; +use crate::auth::CurrentUser; use crate::listing::{Breadcrumb, Entry, QueryParameters, SortingMethod, SortingOrder}; use crate::{archive::ArchiveMethod, MiniserveConfig}; @@ -19,11 +20,19 @@ pub fn page( conf: &MiniserveConfig, current_user: Option<&CurrentUser>, ) -> Markup { + // If query_params.raw is true, we want render a minimal directory listing + if query_params.raw.is_some() && query_params.raw.unwrap() == true { + return raw(entries, is_root); + } + let upload_route = match conf.random_route { Some(ref random_route) => format!("/{}/upload", random_route), None => "/upload".to_string(), }; let (sort_method, sort_order) = (query_params.sort, query_params.order); + + + let upload_action = build_upload_action(&upload_route, encoded_dir, sort_method, sort_order); let title_path = breadcrumbs @@ -31,6 +40,8 @@ pub fn page( .map(|el| el.name.clone()) .collect::>() .join("/"); + + html! { (DOCTYPE) @@ -150,9 +161,7 @@ pub fn page( #[allow(clippy::too_many_arguments)] pub fn raw( entries: Vec, - is_root: bool, - sort_method: Option, - sort_order: Option, + is_root: bool ) -> Markup { html! { (DOCTYPE) @@ -168,16 +177,15 @@ pub fn raw( @if !is_root { tr { td colspan="3" { - a.root href=(parametrized_link("../", sort_method, sort_order, true)) { + a.root href=(parametrized_link("../", None, None, true)) { ".." } } } } @for entry in entries { - (entry_row(entry, sort_method, sort_order, true)) + (entry_row(entry, None, None, true)) } ->>>>>>> 2949329 (Implement a raw rendering mode for recursive folder download) } } } @@ -400,7 +408,7 @@ fn entry_row( a.directory {(symlink_dest) "/"} } }@else { - a.directory href=(parametrized_link(&entry.link, sort_method, sort_order)) { + a.directory href=(parametrized_link(&entry.link, sort_method, sort_order, raw)) { (entry.name) "/" } } @@ -551,15 +559,6 @@ pub fn render_error( conf: &MiniserveConfig, return_address: &str, ) -> Markup { -<<<<<<< HEAD -======= - let link = if has_referer { - return_address.to_string() - } else { - parametrized_link(return_address, sort_method, sort_order, false) - }; - ->>>>>>> 2949329 (Implement a raw rendering mode for recursive folder download) html! { (DOCTYPE) html { @@ -591,15 +590,11 @@ pub fn render_error( } } } -<<<<<<< HEAD @if !conf.hide_version_footer { - (version_footer()) -======= - @if !hide_version_footer { p.footer { (version_footer()) } ->>>>>>> 2949329 (Implement a raw rendering mode for recursive folder download) + } } } -- cgit v1.2.3 From a6f1ee7769fc3617a13d183295c6e681d896a309 Mon Sep 17 00:00:00 2001 From: jikstra Date: Thu, 2 Sep 2021 15:41:54 +0200 Subject: Fix tests --- tests/raw.rs | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/raw.rs b/tests/raw.rs index 5c2227b..57d1436 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -3,8 +3,7 @@ mod utils; use crate::fixtures::TestServer; use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, server, tmpdir, Error}; +use fixtures::{server, Error}; use pretty_assertions::assert_eq; use reqwest::blocking::Client; use rstest::rstest; @@ -68,36 +67,40 @@ fn raw_mode_links_to_directories_end_with_raw_true(server: TestServer) -> Result fn verify_a_tags(parsed: Document) { // Ensure all links end with ?raw=true or are files for node in parsed.find(Name("a")) { - let class = node.attr("class").unwrap(); - - if class == "root" || class == "directory" { - assert!(node.attr("href").unwrap().ends_with("?raw=true")); - } else if class == "file" { - assert!(true); - } else { - println!( - "This node is a link and neither of class directory, root or file: {:?}", - node - ); - assert!(false); + if let Some(class) = node.attr("class") { + if class == "root" || class == "directory" { + assert!(node.attr("href").unwrap().ends_with("?raw=true")); + } else if class == "file" { + assert!(true); + } else { + println!( + "This node is a link and neither of class directory, root or file: {:?}", + node + ); + assert!(false); + } } } } let urls = [ format!("{}?raw=true", server.url()), - format!("{}very?raw=true", server.url()), + format!("{}very/?raw=true", server.url()), format!("{}very/deeply/?raw=true", server.url()), - format!("{}very/deeply/nested?raw=true", server.url()), + format!("{}very/deeply/nested/?raw=true", server.url()), ]; + let client = Client::new(); // Ensure the links to the archives are not present for url in urls.iter() { + let body = client.get(url).send()?.error_for_status()?; + let body = client.get(url).send()?.error_for_status()?; let parsed = Document::from_read(body)?; verify_a_tags(parsed); } + Ok(()) } -- cgit v1.2.3 From 680b0d001d58a32b0caac3263103dbd9ddb5fe84 Mon Sep 17 00:00:00 2001 From: jikstra Date: Thu, 2 Sep 2021 15:50:35 +0200 Subject: cargo fmt & cargo clippy --- src/auth.rs | 4 ++-- src/listing.rs | 2 +- src/renderer.rs | 17 +++++------------ tests/raw.rs | 8 +++----- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index efdeefb..82b407c 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -90,10 +90,10 @@ fn handle_auth(req: &HttpRequest) -> Result<(), ContextualError> { Ok(cred) => match match_auth(&cred, required_auth) { true => { req.extensions_mut().insert(CurrentUser { - name: cred.username + name: cred.username, }); Ok(()) - }, + } false => Err(ContextualError::InvalidHttpCredentials), }, Err(_) => Err(ContextualError::RequireHttpCredentials), diff --git a/src/listing.rs b/src/listing.rs index c1c9597..20768f1 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -379,7 +379,7 @@ pub fn directory_listing( breadcrumbs, &encoded_dir, conf, - current_user + current_user, ) .into_string(), ), diff --git a/src/renderer.rs b/src/renderer.rs index b18ac07..45cb145 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -21,18 +21,16 @@ pub fn page( current_user: Option<&CurrentUser>, ) -> Markup { // If query_params.raw is true, we want render a minimal directory listing - if query_params.raw.is_some() && query_params.raw.unwrap() == true { + if query_params.raw.is_some() && query_params.raw.unwrap() { return raw(entries, is_root); } - + let upload_route = match conf.random_route { Some(ref random_route) => format!("/{}/upload", random_route), None => "/upload".to_string(), }; let (sort_method, sort_order) = (query_params.sort, query_params.order); - - - + let upload_action = build_upload_action(&upload_route, encoded_dir, sort_method, sort_order); let title_path = breadcrumbs @@ -40,8 +38,6 @@ pub fn page( .map(|el| el.name.clone()) .collect::>() .join("/"); - - html! { (DOCTYPE) @@ -159,10 +155,7 @@ pub fn page( } /// Renders the file listing #[allow(clippy::too_many_arguments)] -pub fn raw( - entries: Vec, - is_root: bool -) -> Markup { +pub fn raw(entries: Vec, is_root: bool) -> Markup { html! { (DOCTYPE) html { @@ -594,7 +587,7 @@ pub fn render_error( p.footer { (version_footer()) } - + } } } diff --git a/tests/raw.rs b/tests/raw.rs index 57d1436..6e0c2a0 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -73,12 +73,12 @@ fn raw_mode_links_to_directories_end_with_raw_true(server: TestServer) -> Result } else if class == "file" { assert!(true); } else { - println!( + println!( "This node is a link and neither of class directory, root or file: {:?}", node ); assert!(false); - } + } } } } @@ -90,17 +90,15 @@ fn raw_mode_links_to_directories_end_with_raw_true(server: TestServer) -> Result format!("{}very/deeply/nested/?raw=true", server.url()), ]; - let client = Client::new(); // Ensure the links to the archives are not present for url in urls.iter() { let body = client.get(url).send()?.error_for_status()?; - + let body = client.get(url).send()?.error_for_status()?; let parsed = Document::from_read(body)?; verify_a_tags(parsed); } - Ok(()) } -- cgit v1.2.3 From 71ba52ec5dc84591ead1ac64e584f990b7d66615 Mon Sep 17 00:00:00 2001 From: jikstra Date: Fri, 10 Sep 2021 15:51:08 +0200 Subject: Apply requested changes --- data/style.scss | 2 +- src/renderer.rs | 4 ++-- tests/raw.rs | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/data/style.scss b/data/style.scss index 5a05fe7..8bdd5d7 100644 --- a/data/style.scss +++ b/data/style.scss @@ -53,7 +53,7 @@ body { font-size: 0.7em; color: var(--footer_color); - .downloadWget { + .downloadDirectory { display: flex; flex-direction: row; justify-content: center; diff --git a/src/renderer.rs b/src/renderer.rs index 45cb145..c0a243e 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -153,8 +153,8 @@ pub fn page( } } } + /// Renders the file listing -#[allow(clippy::too_many_arguments)] pub fn raw(entries: Vec, is_root: bool) -> Markup { html! { (DOCTYPE) @@ -212,7 +212,7 @@ fn wget_download(title_path: &str, current_user: Option<&CurrentUser>) -> Markup }; return html! { - div.downloadWget { + div.downloadDirectory { p { "Download folder:" } div.cmd { (format!("wget -r -c -nH -np --cut-dirs={} -R \"index.html*\"{} \"http://{}/?raw=true\"", count, user_params, title_path)) } } diff --git a/tests/raw.rs b/tests/raw.rs index 6e0c2a0..55003be 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -93,8 +93,6 @@ fn raw_mode_links_to_directories_end_with_raw_true(server: TestServer) -> Result let client = Client::new(); // Ensure the links to the archives are not present for url in urls.iter() { - let body = client.get(url).send()?.error_for_status()?; - let body = client.get(url).send()?.error_for_status()?; let parsed = Document::from_read(body)?; verify_a_tags(parsed); -- cgit v1.2.3 From 7eacf516639a70647e2c91687feeb4a92fdda355 Mon Sep 17 00:00:00 2001 From: jikstra Date: Fri, 10 Sep 2021 16:15:20 +0200 Subject: Align download directory hint properly --- data/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/style.scss b/data/style.scss index 9115c0e..e398c9e 100644 --- a/data/style.scss +++ b/data/style.scss @@ -59,7 +59,7 @@ body { justify-content: center; flex-wrap: wrap; .cmd { - margin: 0 0 auto; + margin: 0; padding-left: 5px; line-height: 13px; -- cgit v1.2.3 From 40c112afe8b883e1e59aa475257edcf21a527d89 Mon Sep 17 00:00:00 2001 From: jikstra Date: Fri, 10 Sep 2021 16:15:26 +0200 Subject: Fix tests --- tests/raw.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/raw.rs b/tests/raw.rs index 55003be..ed46314 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -22,7 +22,7 @@ fn ui_displays_wget_element(server: TestServer) -> Result<(), Error> { let body = client.get(server.url()).send()?.error_for_status()?; let parsed = Document::from_read(body)?; let wget_url = parsed - .find(Class("downloadWget")) + .find(Class("downloadDirectory")) .next() .unwrap() .find(Class("cmd")) @@ -43,7 +43,7 @@ fn ui_displays_wget_element(server: TestServer) -> Result<(), Error> { .error_for_status()?; let parsed = Document::from_read(body)?; let wget_url = parsed - .find(Class("downloadWget")) + .find(Class("downloadDirectory")) .next() .unwrap() .find(Class("cmd")) -- cgit v1.2.3 From 45650ea93b723db551fec8c77fbac5065c7659a6 Mon Sep 17 00:00:00 2001 From: jikstra Date: Fri, 10 Sep 2021 16:23:26 +0200 Subject: Implement --show-wget-footer argument --- src/args.rs | 4 ++++ src/config.rs | 4 ++++ src/renderer.rs | 6 ++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/args.rs b/src/args.rs index ff8d92b..c610bbe 100644 --- a/src/args.rs +++ b/src/args.rs @@ -142,6 +142,10 @@ pub struct CliArgs { #[clap(short = 'F', long = "hide-version-footer")] pub hide_version_footer: bool, + /// If enabled, display a wget command to recursively download the current directory + #[clap(short = 'W', long = "show-wget-footer")] + pub show_wget_footer: bool, + /// Generate completion file for a shell #[clap(long = "print-completions", value_name = "shell", possible_values = &Shell::variants())] pub print_completions: Option, diff --git a/src/config.rs b/src/config.rs index 86fe314..ce4e5d7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -101,6 +101,9 @@ pub struct MiniserveConfig { /// If enabled, version footer is hidden pub hide_version_footer: bool, + /// If enabled, display a wget command to recursively download the current directory + pub show_wget_footer: bool, + /// If set, use provided rustls config for TLS #[cfg(feature = "tls")] pub tls_rustls_config: Option, @@ -192,6 +195,7 @@ impl MiniserveConfig { header: args.header, show_symlink_info: args.show_symlink_info, hide_version_footer: args.hide_version_footer, + show_wget_footer: args.show_wget_footer, tls_rustls_config: tls_rustls_server_config, }) } diff --git a/src/renderer.rs b/src/renderer.rs index c0a243e..3c2d008 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -143,7 +143,9 @@ pub fn page( (arrow_up()) } div.footer { - (wget_download(&title_path, current_user)) + @if conf.show_wget_footer { + (wget_footer(&title_path, current_user)) + } @if !conf.hide_version_footer { (version_footer()) } @@ -195,7 +197,7 @@ fn version_footer() -> Markup { } } -fn wget_download(title_path: &str, current_user: Option<&CurrentUser>) -> Markup { +fn wget_footer(title_path: &str, current_user: Option<&CurrentUser>) -> Markup { let count = { let count_slashes = title_path.matches('/').count(); if count_slashes > 0 { -- cgit v1.2.3 From da591fc995ea0189694d1f6e306d23105fa6cfc5 Mon Sep 17 00:00:00 2001 From: jikstra Date: Fri, 10 Sep 2021 16:45:45 +0200 Subject: Remove unused imports and files --- tests/raw.rs | 4 ---- tests/utils/mod.rs | 12 ------------ 2 files changed, 16 deletions(-) delete mode 100644 tests/utils/mod.rs diff --git a/tests/raw.rs b/tests/raw.rs index ed46314..ea9b3a6 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -2,7 +2,6 @@ mod fixtures; mod utils; use crate::fixtures::TestServer; -use assert_cmd::prelude::*; use fixtures::{server, Error}; use pretty_assertions::assert_eq; use reqwest::blocking::Client; @@ -10,9 +9,6 @@ use rstest::rstest; use select::document::Document; use select::predicate::Class; use select::predicate::Name; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; #[rstest] /// The ui displays the correct wget command to download the folder recursively diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs deleted file mode 100644 index b724945..0000000 --- a/tests/utils/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -use select::document::Document; -use select::node::Node; -use select::predicate::Name; -use select::predicate::Predicate; - -/// Return the href attribute content for the closest anchor found by `text`. -pub fn get_link_from_text(document: &Document, text: &str) -> Option { - let a_elem = document - .find(Name("a").and(|x: &Node| x.children().any(|x| x.text() == text))) - .next()?; - Some(a_elem.attr("href")?.to_string()) -} -- cgit v1.2.3 From aed508732a9d9b9e27e301e2934af6917df3e6e1 Mon Sep 17 00:00:00 2001 From: jikstra Date: Fri, 10 Sep 2021 23:34:25 +0200 Subject: Fix tests --- tests/raw.rs | 4 ++-- tests/utils/mod.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/utils/mod.rs diff --git a/tests/raw.rs b/tests/raw.rs index ea9b3a6..0aca2ed 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -12,7 +12,7 @@ use select::predicate::Name; #[rstest] /// The ui displays the correct wget command to download the folder recursively -fn ui_displays_wget_element(server: TestServer) -> Result<(), Error> { +fn ui_displays_wget_element(#[with(&["-W"])] server: TestServer) -> Result<(), Error> { let client = Client::new(); let body = client.get(server.url()).send()?.error_for_status()?; @@ -59,7 +59,7 @@ fn ui_displays_wget_element(server: TestServer) -> Result<(), Error> { #[rstest] /// All hrefs in raw mode are links to directories or files & directories end with ?raw=true -fn raw_mode_links_to_directories_end_with_raw_true(server: TestServer) -> Result<(), Error> { +fn raw_mode_links_to_directories_end_with_raw_true(#[with(&["-W"])] server: TestServer) -> Result<(), Error> { fn verify_a_tags(parsed: Document) { // Ensure all links end with ?raw=true or are files for node in parsed.find(Name("a")) { diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs new file mode 100644 index 0000000..b724945 --- /dev/null +++ b/tests/utils/mod.rs @@ -0,0 +1,12 @@ +use select::document::Document; +use select::node::Node; +use select::predicate::Name; +use select::predicate::Predicate; + +/// Return the href attribute content for the closest anchor found by `text`. +pub fn get_link_from_text(document: &Document, text: &str) -> Option { + let a_elem = document + .find(Name("a").and(|x: &Node| x.children().any(|x| x.text() == text))) + .next()?; + Some(a_elem.attr("href")?.to_string()) +} -- cgit v1.2.3 From 726411a1d9a605d159a6f3b1c64f761573a91895 Mon Sep 17 00:00:00 2001 From: jikstra Date: Sat, 11 Sep 2021 14:04:32 +0200 Subject: cargo fmt --- tests/raw.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/raw.rs b/tests/raw.rs index 0aca2ed..82a1eee 100644 --- a/tests/raw.rs +++ b/tests/raw.rs @@ -59,7 +59,9 @@ fn ui_displays_wget_element(#[with(&["-W"])] server: TestServer) -> Result<(), E #[rstest] /// All hrefs in raw mode are links to directories or files & directories end with ?raw=true -fn raw_mode_links_to_directories_end_with_raw_true(#[with(&["-W"])] server: TestServer) -> Result<(), Error> { +fn raw_mode_links_to_directories_end_with_raw_true( + #[with(&["-W"])] server: TestServer, +) -> Result<(), Error> { fn verify_a_tags(parsed: Document) { // Ensure all links end with ?raw=true or are files for node in parsed.find(Name("a")) { -- cgit v1.2.3