mirror of
https://github.com/Jackzmc/storage.git
synced 2025-05-05 16:33:21 +00:00
Implement folder sorting
This commit is contained in:
parent
6eb900b814
commit
d1cf5d3038
5 changed files with 49 additions and 7 deletions
|
@ -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<String>,
|
||||
pub sort_descending: Option<bool>
|
||||
}
|
||||
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<Vec<FileEntry>, anyhow::Error> {
|
||||
pub async fn list_files(&self, rel_path: &PathBuf, options: ListOptions) -> Result<Vec<FileEntry>, 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> {
|
||||
|
|
|
@ -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("/<library_id>")]
|
||||
|
@ -30,7 +31,7 @@ pub(crate) async fn get_file(pool: &State<DB>, library_id: &str) -> Result<Optio
|
|||
pub(crate) async fn list_files(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<Json<Vec<FileEntry>>, 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(),
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
@ -55,7 +56,11 @@ pub async fn list_library_files(
|
|||
};
|
||||
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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<div class="field">
|
||||
<label class="label">Username / Email</label>
|
||||
<div class="control has-icons-left">
|
||||
<input required name="username" class="input {{#if errors.username}}is-danger{{/if}}" type="text" placeholder="Username or Email">
|
||||
<input autofocus required name="username" class="input {{#if errors.username}}is-danger{{/if}}" type="text" placeholder="Username or Email">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-user"></i>
|
||||
</span>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue