diff --git a/Cargo.lock b/Cargo.lock index 4570051..9e35bb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -651,15 +651,17 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", - "windows-targets 0.48.5", + "wasm-bindgen", + "windows-targets 0.52.0", ] [[package]] @@ -1756,6 +1758,7 @@ dependencies = [ "async-trait", "axum 0.7.4", "barrel", + "chrono", "dotenvy", "dunce", "entity", diff --git a/Cargo.toml b/Cargo.toml index 311ff1b..b75f77d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,3 +53,4 @@ slug = "0.1.5" async-trait = "0.1.77" tracing = "0.1.40" tower-http = { version = "0.5.1", features = ["trace"] } +chrono = "0.4.38" diff --git a/src/admin_examples/file_repository.rs b/src/admin_examples/file_repository.rs index 517859e..5ee8d2b 100644 --- a/src/admin_examples/file_repository.rs +++ b/src/admin_examples/file_repository.rs @@ -1,15 +1,19 @@ use crate::admin::domain::*; use async_trait::async_trait; +use rear::admin::state::AdminRegistry; use serde_json::Value; +use std::path::PathBuf; struct FileRepository { - directory_path: String, + directory_path: PathBuf, } impl FileRepository { - pub fn new(folder: String) -> Self { + pub fn new(from_path: &str) -> Self { + + let proper_path = file_operations::get_proper_path(from_path); FileRepository { - directory_path: folder, + directory_path: proper_path, } } } @@ -36,8 +40,15 @@ impl AdminRepository for FileRepository { // GET on item collection. async fn list(&self, model: &RepositoryContext) -> RepositoryList { - if let Some(file_data) = file_operations::directory_info(&self.directory_path) { - return RepositoryList::List(file_data); + if let Ok(file_data) = file_operations::directory_info(&self.directory_path) { + let items: Vec = file_data.into_iter().map(|fields| { + RepositoryItem { + fields, + detail_url: None, // TODO: change the return type of directory_info into a struct, so we can access key. + change_url: None, + } + }).collect(); + return RepositoryList::List { values: items }; } RepositoryList::Empty } @@ -82,12 +93,12 @@ impl AdminRepository for FileRepository { } } -pub fn register(registry: &mut AdminRegistry, db: DatabaseConnection) { - let app_key = registry.register_app("Static"); - let repo = FileRepository::new(db); +pub fn register(registry: &mut AdminRegistry, path: &str) { + let app_key = registry.register_app("Files"); + let repo = FileRepository::new(path); let model_config = AdminModelConfig { app_key: app_key, - name: "User".to_owned(), + name: "Files".to_owned(), }; let model_result = registry.register_model(model_config, repo); match model_result { @@ -100,6 +111,15 @@ mod file_operations { use serde_json::{json, Value}; use std::fs; use std::path::Path; + use std::env; + use std::path::PathBuf; + use std::time::SystemTime; + use chrono::{DateTime, Utc, TimeZone}; + + fn system_time_to_iso_string(system_time: SystemTime) -> String { + let datetime: DateTime = system_time.into(); + datetime.to_rfc3339() + } fn get_metadata_as_json(path: &Path) -> Result> { let metadata = fs::metadata(path)?; @@ -118,8 +138,8 @@ mod file_operations { let is_symlink = file_type.is_symlink(); // Format times as strings if they exist - let modified_time_str = modified_time.map(|t| t.to_string()); - let created_time_str = created_time.map(|t| t.to_string()); + let modified_time_str = modified_time.map(|t| system_time_to_iso_string(t)); + let created_time_str = created_time.map(|t| system_time_to_iso_string(t)); Ok(json!({ "path": path.display().to_string(), @@ -132,12 +152,12 @@ mod file_operations { })) } - fn file_info(file_path: &str) -> Result> { - let path = Path::new(file_path); + pub fn file_info(file_path: &PathBuf) -> Result> { + let path = file_path.as_path(); get_metadata_as_json(path) } - fn directory_info(directory_path: &str) -> Result, Box> { + pub fn directory_info(directory_path: &PathBuf) -> Result, Box> { let entries = fs::read_dir(directory_path)?; let mut results = Vec::new(); @@ -151,4 +171,16 @@ mod file_operations { Ok(results) } + + pub fn get_proper_path(some_path: &str) -> PathBuf { + let path = Path::new(some_path); + if path.is_absolute() { + return path.to_path_buf(); + } else { + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into()); + let template_path = PathBuf::from(manifest_dir).join(path); + return template_path; + } + + } } diff --git a/src/admin_examples/mod.rs b/src/admin_examples/mod.rs index 7dd0ecf..7bc9f7c 100644 --- a/src/admin_examples/mod.rs +++ b/src/admin_examples/mod.rs @@ -1,3 +1,4 @@ pub mod empty_repository; pub mod static_repository; pub mod user_repository; +pub mod file_repository; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b9ad04f..89a5a19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod state; use crate::state::AppState; use admin_examples::static_repository; use admin_examples::user_repository; +use admin_examples::file_repository; use axum::{ body::Bytes, extract::MatchedPath, @@ -53,6 +54,7 @@ async fn main() { // Register Admin Apps static_repository::register(&mut admin); user_repository::register(&mut admin, db_connection); + file_repository::register(&mut admin, "static/admin"); // Create global Application State. let state: AppState = AppState {