diff --git a/src/objs/library.rs b/src/objs/library.rs index 6d8d68e..a4a3747 100644 --- a/src/objs/library.rs +++ b/src/objs/library.rs @@ -1,7 +1,9 @@ +use std::cmp::Ordering; use std::fs::File; use std::io::BufReader; use std::path::PathBuf; -use anyhow::Error; +use anyhow::{anyhow, Error}; +use log::trace; use rocket::response::stream::ReaderStream; use rocket::serde::Serialize; use tokio::io::BufStream; @@ -17,6 +19,21 @@ pub struct Library { repo: RepoContainer, } +/// The direction of sort and the field to sort by +#[derive(PartialEq, Debug)] +pub struct ListOptions { + pub sort_field: Option, + pub sort_descending: Option +} +impl Default for ListOptions { + fn default() -> Self { + ListOptions { + sort_field: Some("name".to_string()), + sort_descending: Some(false), + } + } +} + impl Library { pub fn new(library_model: LibraryModel, repo: RepoContainer) -> Library { Library { @@ -49,9 +66,28 @@ impl Library { repo.backend.read_file(&self.model.id.to_string(), rel_path) } - pub async fn list_files(&self, rel_path: &PathBuf) -> Result, anyhow::Error> { + pub async fn list_files(&self, rel_path: &PathBuf, options: ListOptions) -> Result, anyhow::Error> { let repo = self.repo.read().await; - repo.backend.list_files(&self.model.id.to_string(), rel_path) + let mut list = repo.backend.list_files(&self.model.id.to_string(), rel_path)?; + let field = options.sort_field.unwrap_or("name".to_string()); + let descending = options.sort_descending.unwrap_or(false); + match field.as_str() { + "name" => list.sort_by(|a, b| { + if a._type == FileType::File && b._type != FileType::File { Ordering::Greater } + else if a._type != FileType::File && b._type == FileType::File { Ordering::Less } + else { a.path.cmp(&b.path) } + }), + "size" => list.sort_by(|a, b| { + if a._type == FileType::File && b._type != FileType::File { Ordering::Greater } + else if a._type != FileType::File && b._type == FileType::File { Ordering::Less } + else { a.size.cmp(&b.size) } + }), + _ => return Err(anyhow!("Unsupported field")) + } + if descending { + list.reverse(); + } + Ok(list) } pub async fn delete_file(&self, rel_path: &PathBuf) -> Result<(), anyhow::Error> { diff --git a/src/routes/api/library.rs b/src/routes/api/library.rs index 77ec866..861b91d 100644 --- a/src/routes/api/library.rs +++ b/src/routes/api/library.rs @@ -17,6 +17,7 @@ use crate::managers::libraries::LibraryManager; use crate::managers::repos::RepoManager; use crate::models::library::{LibraryModel, LibraryWithRepoModel}; use crate::models::user; +use crate::objs::library::ListOptions; use crate::storage::{FileEntry, FileType}; use crate::util::{JsonErrorResponse, ResponseError}; #[get("/")] @@ -30,7 +31,7 @@ pub(crate) async fn get_file(pool: &State, library_id: &str) -> Result>>, library_id: &str, path: &str) -> Result>, ResponseError> { let libs = libraries.lock().await; let library = libs.get(library_id).await?; - library.list_files(&PathBuf::from(path)).await + library.list_files(&PathBuf::from(path), ListOptions::default()).await .map(|files| Json(files)) .map_err(|e| ResponseError::InternalServerError(JsonErrorResponse { code: "STORAGE_ERROR".to_string(), diff --git a/src/routes/ui/auth/login.rs b/src/routes/ui/auth/login.rs index 5260a00..a57e525 100644 --- a/src/routes/ui/auth/login.rs +++ b/src/routes/ui/auth/login.rs @@ -90,7 +90,7 @@ pub async fn handler( let ctx = context! { route: route.uri.path(), csrf_token: csrf_token, - form: &Context::default(), + form: &form.context, return_to, meta: meta.inner() }; diff --git a/src/routes/ui/user.rs b/src/routes/ui/user.rs index 98303d9..33bb906 100644 --- a/src/routes/ui/user.rs +++ b/src/routes/ui/user.rs @@ -17,6 +17,7 @@ use tokio::sync::Mutex; use crate::consts::FILE_CONSTANTS; use crate::guards::{AuthUser}; use crate::managers::libraries::LibraryManager; +use crate::objs::library::ListOptions; use crate::routes::ui::auth; use crate::util::{JsonErrorResponse, ResponseError}; @@ -46,9 +47,20 @@ pub async fn list_library_files( sort_dir: Option, display: Option, ) -> Result { + let options = FileDisplayOptions { + // TODO: prevent bad values + // TODO: fix login errror msg -------_____------ + sort_key: validate_option(sort_key, FILE_CONSTANTS.sort_keys, "name"), + sort_dir: validate_option(sort_dir, &["asc", "desc"], "asc"), + display: validate_option(display, FILE_CONSTANTS.display_options, "list"), + }; let libs = libraries.lock().await; let library = libs.get(library_id).await?; - let files = library.list_files(&PathBuf::from(&path)).await + let list_options = ListOptions { + sort_field: Some(options.sort_key.clone()), + sort_descending: Some(options.sort_dir == "desc"), + }; + let files = library.list_files(&PathBuf::from(&path), list_options).await .map_err(|e| ResponseError::InternalServerError(JsonErrorResponse { code: "STORAGE_ERROR".to_string(), message: e.to_string(), @@ -82,13 +94,7 @@ pub async fn list_library_files( parent, path_segments: segments, // TODO: have struct? - options: FileDisplayOptions { - // TODO: prevent bad values - // TODO: fix login errror msg -------_____------ - sort_key: validate_option(sort_key, FILE_CONSTANTS.sort_keys, "name"), - sort_dir: validate_option(sort_dir, &["asc", "desc"], "asc"), - display: validate_option(display, FILE_CONSTANTS.display_options, "list"), - }, + options, DATA: FILE_CONSTANTS })) } diff --git a/src/storage.rs b/src/storage.rs index 6e8f16c..91cc881 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -19,7 +19,7 @@ pub enum StorageBackendMap { S3(S3Storage) } -#[derive(Debug, Serialize, Deserialize, FromFormField)] +#[derive(Debug, Serialize, Deserialize, FromFormField, PartialEq)] #[serde(rename_all = "lowercase")] pub enum FileType { File, diff --git a/templates/auth/login.html.hbs b/templates/auth/login.html.hbs index a585cb0..0ad8b67 100644 --- a/templates/auth/login.html.hbs +++ b/templates/auth/login.html.hbs @@ -24,7 +24,7 @@
- +