Skip to content

Commit 98767c2

Browse files
authored
feat: resolve with query params (#189)
* feat: resolve with query params * fix: clippy issues * feat: support for sorting by name and size * fix: clippy warnings
1 parent 863c903 commit 98767c2

File tree

4 files changed

+78
-25
lines changed

4 files changed

+78
-25
lines changed

src/addon/file_server/directory_entry.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub struct DirectoryEntry {
99
pub(crate) display_name: String,
1010
pub(crate) is_dir: bool,
1111
pub(crate) size: String,
12+
pub(crate) len: u64,
1213
pub(crate) entry_path: String,
1314
pub(crate) created_at: String,
1415
pub(crate) updated_at: String,
@@ -67,4 +68,6 @@ pub struct DirectoryIndex {
6768
/// Directory listing entry
6869
pub(crate) entries: Vec<DirectoryEntry>,
6970
pub(crate) breadcrumbs: Vec<BreadcrumbItem>,
71+
pub(crate) sort_by_name: bool,
72+
pub(crate) sort_by_size: bool,
7073
}

src/addon/file_server/mod.rs

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::utils::url_encode::{decode_uri, encode_uri, PERCENT_ENCODE_SET};
2323

2424
use self::directory_entry::{BreadcrumbItem, DirectoryEntry, DirectoryIndex};
2525
use self::http_utils::{make_http_file_response, CacheControlDirective};
26+
use self::query_params::{QueryParams, SortBy};
2627

2728
/// Explorer's Handlebars template filename
2829
const EXPLORER_TEMPLATE: &str = "explorer";
@@ -60,22 +61,22 @@ impl<'a> FileServer {
6061
Arc::new(handlebars)
6162
}
6263

63-
fn parse_path(req_uri: &str) -> Result<PathBuf> {
64+
fn parse_path(req_uri: &str) -> Result<(PathBuf, Option<QueryParams>)> {
6465
let uri = Uri::from_str(req_uri)?;
6566
let uri_parts = uri.into_parts();
6667

6768
if let Some(path_and_query) = uri_parts.path_and_query {
6869
let path = path_and_query.path();
69-
let _queries = if let Some(query_str) = path_and_query.query() {
70-
Some(query_params::QueryParams::from_str(query_str)?)
70+
let query_params = if let Some(query_str) = path_and_query.query() {
71+
Some(QueryParams::from_str(query_str)?)
7172
} else {
7273
None
7374
};
7475

75-
return Ok(decode_uri(path));
76+
return Ok((decode_uri(path), query_params));
7677
}
7778

78-
Ok(PathBuf::from_str("/")?)
79+
Ok((PathBuf::from_str("/")?, None))
7980
}
8081

8182
/// Resolves a HTTP Request to a file or directory.
@@ -105,11 +106,13 @@ impl<'a> FileServer {
105106
pub async fn resolve(&self, req_path: String) -> Result<Response<Body>> {
106107
use std::io::ErrorKind;
107108

108-
let path = FileServer::parse_path(req_path.as_str())?;
109+
let (path, query_params) = FileServer::parse_path(req_path.as_str())?;
109110

110111
match self.scoped_file_system.resolve(path).await {
111112
Ok(entry) => match entry {
112-
Entry::Directory(dir) => self.render_directory_index(dir.path()).await,
113+
Entry::Directory(dir) => {
114+
self.render_directory_index(dir.path(), query_params).await
115+
}
113116
Entry::File(file) => {
114117
make_http_file_response(*file, CacheControlDirective::MaxAge(2500)).await
115118
}
@@ -134,8 +137,13 @@ impl<'a> FileServer {
134137
/// Indexes the directory by creating a `DirectoryIndex`. Such `DirectoryIndex`
135138
/// is used to build the Handlebars "Explorer" template using the Handlebars
136139
/// engine and builds an HTTP Response containing such file
137-
async fn render_directory_index(&self, path: PathBuf) -> Result<Response<Body>> {
138-
let directory_index = FileServer::index_directory(self.root_dir.clone(), path)?;
140+
async fn render_directory_index(
141+
&self,
142+
path: PathBuf,
143+
query_params: Option<QueryParams>,
144+
) -> Result<Response<Body>> {
145+
let directory_index =
146+
FileServer::index_directory(self.root_dir.clone(), path, query_params)?;
139147
let html = self
140148
.handlebars
141149
.render(EXPLORER_TEMPLATE, &directory_index)
@@ -204,7 +212,11 @@ impl<'a> FileServer {
204212

205213
/// Creates a `DirectoryIndex` with the provided `root_dir` and `path`
206214
/// (HTTP Request URI)
207-
fn index_directory(root_dir: PathBuf, path: PathBuf) -> Result<DirectoryIndex> {
215+
fn index_directory(
216+
root_dir: PathBuf,
217+
path: PathBuf,
218+
query_params: Option<QueryParams>,
219+
) -> Result<DirectoryIndex> {
208220
let breadcrumbs = FileServer::breadcrumbs_from_path(&root_dir, &path)?;
209221
let entries = read_dir(path).context("Unable to read directory")?;
210222
let mut directory_entries: Vec<DirectoryEntry> = Vec::new();
@@ -231,17 +243,47 @@ impl<'a> FileServer {
231243
.to_string(),
232244
is_dir: metadata.is_dir(),
233245
size: format_bytes(metadata.len() as f64),
246+
len: metadata.len(),
234247
entry_path: FileServer::make_dir_entry_link(&root_dir, &entry.path()),
235248
created_at,
236249
updated_at,
237250
});
238251
}
239252

253+
if let Some(query_params) = query_params {
254+
if let Some(sort_by) = query_params.sort_by {
255+
match sort_by {
256+
SortBy::Name => {
257+
directory_entries.sort_by_key(|entry| entry.display_name.clone());
258+
259+
return Ok(DirectoryIndex {
260+
entries: directory_entries,
261+
breadcrumbs,
262+
sort_by_name: true,
263+
sort_by_size: false,
264+
});
265+
}
266+
SortBy::Size => {
267+
directory_entries.sort_by_key(|entry| entry.len);
268+
269+
return Ok(DirectoryIndex {
270+
entries: directory_entries,
271+
breadcrumbs,
272+
sort_by_name: false,
273+
sort_by_size: true,
274+
});
275+
}
276+
}
277+
}
278+
}
279+
240280
directory_entries.sort();
241281

242282
Ok(DirectoryIndex {
243283
entries: directory_entries,
244284
breadcrumbs,
285+
sort_by_name: false,
286+
sort_by_size: false,
245287
})
246288
}
247289

@@ -301,7 +343,7 @@ mod tests {
301343
];
302344

303345
for (idx, req_uri) in have.iter().enumerate() {
304-
let sanitized_path = FileServer::parse_path(req_uri).unwrap();
346+
let sanitized_path = FileServer::parse_path(req_uri).unwrap().0;
305347
let wanted_path = PathBuf::from_str(want[idx]).unwrap();
306348

307349
assert_eq!(sanitized_path, wanted_path);

src/addon/file_server/query_params.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use anyhow::Error;
2+
use serde::Serialize;
23
use std::str::FromStr;
34

4-
#[derive(Debug, PartialEq, Eq)]
5-
enum SortBy {
5+
#[derive(Debug, Eq, PartialEq, Serialize)]
6+
pub enum SortBy {
67
Name,
8+
Size,
79
}
810

911
impl FromStr for SortBy {
@@ -15,14 +17,15 @@ impl FromStr for SortBy {
1517

1618
match lower {
1719
"name" => Ok(SortBy::Name),
20+
"size" => Ok(SortBy::Size),
1821
_ => Err(Error::msg("Value doesnt correspond")),
1922
}
2023
}
2124
}
2225

2326
#[derive(Debug, Default, PartialEq, Eq)]
2427
pub struct QueryParams {
25-
sort_by: Option<SortBy>,
28+
pub(crate) sort_by: Option<SortBy>,
2629
}
2730

2831
impl FromStr for QueryParams {

src/addon/file_server/template/explorer.hbs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,20 @@
2828
min-width: var(--min-width);
2929
overflow-y: auto;
3030
padding: 0;
31-
padding-bottom: 2rem;
3231
width: 95%;
3332
}
3433
3534
#explorer .hrow {
3635
background-color: #FFFFFF;
3736
border-bottom: 1px solid #DDDDDD;
38-
position: -webkit-sticky;
39-
position: sticky;
40-
top: 0;
4137
}
4238
4339
#explorer .hrow .hcol {
4440
border-right: 1px solid #DDDDDD;
4541
box-sizing: border-box;
46-
padding: .3rem .35rem;
42+
color: #000000;
43+
padding: .3rem;
44+
text-decoration: none;
4745
}
4846
4947
#explorer .brow, .bcol {
@@ -65,7 +63,6 @@
6563
6664
#explorer .hcol:nth-child(2), #explorer .bcol:nth-child(2) {
6765
/* Name Column */
68-
overflow: hidden;
6966
text-overflow: ellipsis;
7067
white-space: nowrap;
7168
width: 300px;
@@ -188,11 +185,19 @@
188185
<main>
189186
<ul id="explorer">
190187
<li class="hrow">
191-
<span class="hcol icon-col">&nbsp;</span>
192-
<span class="hcol">Name</span>
193-
<span class="hcol">Size</span>
194-
<span class="hcol">Date created</span>
195-
<span class="hcol">Date modified</span>
188+
<span class="hcol icon-col"></span>
189+
{{#if sort_by_name}}
190+
<a class="hcol" href="?sort_by=">Name&nbsp;↓</a>
191+
{{else}}
192+
<a class="hcol" href="?sort_by=name">Name</a>
193+
{{/if}}
194+
{{#if sort_by_size}}
195+
<a class="hcol" href="?sort_by=">Size&nbsp;↓</a>
196+
{{else}}
197+
<a class="hcol" href="?sort_by=size">Size</a>
198+
{{/if}}
199+
<a class="hcol">Date created</a>
200+
<a class="hcol">Date modified</a>
196201
</li>
197202
{{#each entries}}
198203
<li class="brow">

0 commit comments

Comments
 (0)