diff options
-rw-r--r-- | Cargo.lock | 85 | ||||
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/archive.rs | 80 | ||||
-rw-r--r-- | src/listing.rs | 73 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/renderer.rs | 35 |
6 files changed, 247 insertions, 32 deletions
@@ -7,7 +7,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "actix_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -35,7 +35,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -64,7 +64,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -243,7 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -478,6 +478,16 @@ dependencies = [ ] [[package]] +name = "filetime" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "flate2" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -532,7 +542,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -570,7 +580,7 @@ name = "http" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -752,10 +762,12 @@ dependencies = [ "actix-web 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", "alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "chrono-humanize 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "maud 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "nanoid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -763,6 +775,8 @@ dependencies = [ "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1138,6 +1152,14 @@ dependencies = [ ] [[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "resolv-conf" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1344,6 +1366,30 @@ dependencies = [ ] [[package]] +name = "tar" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempfile" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "term" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1393,7 +1439,7 @@ name = "tokio" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1416,7 +1462,7 @@ name = "tokio-codec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1454,7 +1500,7 @@ name = "tokio-io" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1505,7 +1551,7 @@ name = "tokio-tcp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1546,7 +1592,7 @@ name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1560,7 +1606,7 @@ name = "tokio-uds" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1825,6 +1871,14 @@ dependencies = [ ] [[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "yansi" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1851,7 +1905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" "checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" @@ -1878,6 +1932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" "checksum flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2291c165c8e703ee54ef3055ad6188e3d51108e2ded18e9f2476e774fc5ad3d4" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -1955,6 +2010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" @@ -1982,6 +2038,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum tar 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "904b43da53c99b929c4484fa281e5535f2eb86b3040de3e3e5b69708e2a8bd65" +"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" @@ -2031,4 +2089,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" "checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" "checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" @@ -37,3 +37,7 @@ chrono = "0.4.6" chrono-humanize = "0.0.11" maud = { version = "0.20.0", features = ["actix-web"] } serde = { version = "1.0.89", features = ["derive"] } +tar = "0.4" +tempfile = "3.0.7" +bytes = "0.4.12" +futures = "0.1.25"
\ No newline at end of file diff --git a/src/archive.rs b/src/archive.rs new file mode 100644 index 0000000..cc39207 --- /dev/null +++ b/src/archive.rs @@ -0,0 +1,80 @@ +use bytes::Bytes; +use serde::Deserialize; +use std::fs::{File, OpenOptions}; +use std::io::Read; +use std::path::PathBuf; +use tar::Builder; +use tempfile::tempdir; + +#[derive(Debug)] +pub enum CompressionError { + IOError(std::io::Error), + NoneError(std::option::NoneError), +} + +impl From<std::option::NoneError> for CompressionError { + fn from(err: std::option::NoneError) -> CompressionError { + CompressionError::NoneError(err) + } +} + +impl From<std::io::Error> for CompressionError { + fn from(err: std::io::Error) -> CompressionError { + CompressionError::IOError(err) + } +} + +/// Available compression methods +#[derive(Debug, Deserialize, Clone)] +pub enum CompressionMethod { + /// ZIP + #[serde(alias = "targz")] + TarGz, +} + +impl CompressionMethod { + pub fn to_string(&self) -> String { + match &self { + CompressionMethod::TarGz => "targz", + } + .to_string() + } + + pub fn extension(&self) -> String { + match &self { + CompressionMethod::TarGz => "tar.gz", + } + .to_string() + } +} + +pub fn create_archive_file( + method: &CompressionMethod, + dir: &PathBuf, +) -> Result<(String, usize, Bytes), CompressionError> { + match method { + CompressionMethod::TarGz => tgz_compress(&dir), + } +} + +fn tgz_compress(dir: &PathBuf) -> Result<(String, usize, Bytes), CompressionError> { + let src_dir = dir.display().to_string(); + let inner_folder = dir.file_name()?.to_str()?; + let dst_filename = format!("{}.tar", inner_folder); + let tmp_dir = tempdir()?; + + let dst_filepath = tmp_dir.path().join(dst_filename.clone()); + let tar_file = File::create(&dst_filepath)?; + let mut tar_builder = Builder::new(&tar_file); + tar_builder.append_dir_all(inner_folder, src_dir)?; + tar_builder.finish()?; + + let mut tar_file = OpenOptions::new().read(true).open(&dst_filepath)?; + let mut contents = Vec::new(); + let content_length = tar_file.read_to_end(&mut contents).unwrap(); + + let mut data = Bytes::new(); + data.extend_from_slice(&contents); + + Ok((dst_filename, content_length, data)) +} diff --git a/src/listing.rs b/src/listing.rs index 57bef17..565b5bf 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -1,12 +1,15 @@ -use actix_web::{fs, FromRequest, HttpRequest, HttpResponse, Query, Result}; +use actix_web::{fs, http, Body, FromRequest, HttpRequest, HttpResponse, Query, Result}; use bytesize::ByteSize; +use futures::stream::once; use htmlescape::encode_minimal as escape_html_entity; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use serde::Deserialize; use std::io; use std::path::Path; use std::time::SystemTime; +use yansi::Paint; +use crate::archive; use crate::renderer; /// Query parameters @@ -14,6 +17,7 @@ use crate::renderer; struct QueryParameters { sort: Option<SortingMethod>, order: Option<SortingOrder>, + download: Option<archive::CompressionMethod>, } /// Available sorting methods @@ -134,11 +138,16 @@ pub fn directory_listing<S>( let is_root = base.parent().is_none() || req.path() == random_route; let page_parent = base.parent().map(|p| p.display().to_string()); - let (sort_method, sort_order) = if let Ok(query) = Query::<QueryParameters>::extract(req) { - (query.sort.clone(), query.order.clone()) - } else { - (None, None) - }; + let (sort_method, sort_order, download) = + if let Ok(query) = Query::<QueryParameters>::extract(req) { + ( + query.sort.clone(), + query.order.clone(), + query.download.clone(), + ) + } else { + (None, None, None) + }; let mut entries: Vec<Entry> = Vec::new(); @@ -218,17 +227,43 @@ pub fn directory_listing<S>( } } - Ok(HttpResponse::Ok() - .content_type("text/html; charset=utf-8") - .body( - renderer::page( - &title, - entries, - is_root, - page_parent, - sort_method, - sort_order, - ) - .into_string(), - )) + if let Some(compression_method) = &download { + match archive::create_archive_file(&compression_method, &dir.path) { + Ok((filename, content_length, content)) => Ok(HttpResponse::Ok() + .content_type("application/tar") + .content_length(content_length as u64) + .header("Content-Transfer-Encoding", "binary") + .header( + "Content-Disposition", + format!("attachment; filename={:?}", filename), + ) + .chunked() + .body(Body::Streaming(Box::new(once(Ok(content)))))), + Err(err) => { + println!( + "{error} an error occured while compressing {folder}: {err:?}", + error = Paint::red("error:").bold(), + folder = dir.path.display(), + err = err + ); + Ok(HttpResponse::Ok() + .status(http::StatusCode::INTERNAL_SERVER_ERROR) + .body("")) + } + } + } else { + Ok(HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body( + renderer::page( + &title, + entries, + is_root, + page_parent, + sort_method, + sort_order, + ) + .into_string(), + )) + } } diff --git a/src/main.rs b/src/main.rs index b15088c..9f2cacf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![feature(proc_macro_hygiene)] +#![feature(try_trait)] use actix_web::{fs, middleware, server, App}; use clap::crate_version; @@ -9,6 +10,7 @@ use std::thread; use std::time::Duration; use yansi::{Color, Paint}; +mod archive; mod args; mod auth; mod listing; diff --git a/src/renderer.rs b/src/renderer.rs index 89a9248..b83a67c 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,6 +3,7 @@ use chrono_humanize::{Accuracy, HumanTime, Tense}; use maud::{html, Markup, PreEscaped, DOCTYPE}; use std::time::SystemTime; +use crate::archive; use crate::listing; /// Renders the file listing @@ -19,6 +20,9 @@ pub fn page( body { span #top { } h1 { (page_title) } + div.download { + (archive_button(archive::CompressionMethod::TarGz)) + } table { thead { th { (build_link("name", "Name", &sort_method, &sort_order)) } @@ -50,6 +54,18 @@ pub fn page( } } +/// Partial: archive button +fn archive_button(compress_method: archive::CompressionMethod) -> Markup { + let link = format!("?download={}", compress_method.to_string()); + let text = format!("Download .{}", compress_method.extension()); + + html! { + a href=(link) { + (text) + } + } +} + /// Partial: table header link fn build_link( name: &str, @@ -259,6 +275,25 @@ fn css() -> Markup { color: #3498db; text-decoration: none; } + .download { + display: flex; + justify-content: flex-end; + padding: 0.125rem; + } + .download a, .download a:visited { + color: #3498db; + } + .download a { + background: #efefef; + padding: 0.5rem; + border-radius: 0.2rem; + } + .download a:hover { + background: #deeef7a6; + } + .download a:not(:last-of-type) { + margin-right: 1rem; + } @media (max-width: 600px) { h1 { font-size: 1.375em; |