diff --git a/src/objs/library.rs b/src/objs/library.rs index 69ca2a7..6d8d68e 100644 --- a/src/objs/library.rs +++ b/src/objs/library.rs @@ -3,12 +3,13 @@ use std::io::BufReader; use std::path::PathBuf; use anyhow::Error; use rocket::response::stream::ReaderStream; +use rocket::serde::Serialize; use tokio::io::BufStream; use crate::managers::repos::RepoContainer; use crate::{models, DB}; use crate::models::library::LibraryModel; use crate::models::repo::RepoModel; -use crate::storage::FileEntry; +use crate::storage::{FileEntry, FileType}; use crate::util::{JsonErrorResponse, ResponseError}; pub struct Library { @@ -33,6 +34,11 @@ impl Library { repo.backend.get_read_stream(&self.model.id.to_string(), rel_path) } + pub async fn touch_file(&self, rel_path: &PathBuf, file_type: FileType) -> Result<(), anyhow::Error> { + let mut repo = self.repo.read().await; + repo.backend.touch_file(&self.model.id.to_string(), rel_path, file_type) + } + pub async fn write_file(&self, rel_path: &PathBuf, contents: &[u8]) -> Result<(), anyhow::Error> { let mut repo = self.repo.read().await; repo.backend.write_file(&self.model.id.to_string(), rel_path, contents) diff --git a/src/routes/api/library.rs b/src/routes/api/library.rs index 9a0afd1..77ec866 100644 --- a/src/routes/api/library.rs +++ b/src/routes/api/library.rs @@ -6,6 +6,7 @@ use rocket::fs::TempFile; use rocket::http::Status; use rocket::response::status; use rocket::serde::json::Json; +use rocket::serde::Serialize; use sqlx::{query, Postgres}; use sqlx::types::{Uuid}; use tokio::io::AsyncReadExt; @@ -16,7 +17,7 @@ use crate::managers::libraries::LibraryManager; use crate::managers::repos::RepoManager; use crate::models::library::{LibraryModel, LibraryWithRepoModel}; use crate::models::user; -use crate::storage::FileEntry; +use crate::storage::{FileEntry, FileType}; use crate::util::{JsonErrorResponse, ResponseError}; #[get("/")] pub(crate) async fn get_file(pool: &State, library_id: &str) -> Result>, ResponseError> { @@ -37,6 +38,18 @@ pub(crate) async fn list_files(libraries: &State>>, li })) } + +#[post("//touch?&")] +pub(crate) async fn touch_files(libraries: &State>>, library_id: &str, path: &str, file_type: FileType) -> Result<(), ResponseError> { + let libs = libraries.lock().await; + let library = libs.get(library_id).await?; + library.touch_file(&PathBuf::from(path), file_type).await + .map_err(|e| ResponseError::InternalServerError(JsonErrorResponse { + code: "STORAGE_ERROR".to_string(), + message: e.to_string(), + })) +} + #[get("//files/download?")] pub(crate) async fn download_file(libraries: &State>>, library_id: &str, path: &str) -> Result, ResponseError> { let libs = libraries.lock().await; diff --git a/src/storage.rs b/src/storage.rs index a86212a..738a67c 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -61,7 +61,7 @@ pub fn get_backend(storage_type: &str, settings: &JsonValue) -> Result Result; - + fn touch_file(&self, library_id: &str, rel_path: &PathBuf, file_type: FileType) -> Result<(), anyhow::Error>; fn write_file(&self, library_id: &str, rel_path: &PathBuf, contents: &[u8]) -> Result<(), anyhow::Error>; fn read_file(&self, library_id: &str, rel_path: &PathBuf) -> Result>, anyhow::Error>; diff --git a/src/storage/local.rs b/src/storage/local.rs index 78cf3ba..cf377cf 100644 --- a/src/storage/local.rs +++ b/src/storage/local.rs @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf}; use anyhow::{anyhow, Error}; use log::debug; use sqlx::types::JsonValue; -use crate::storage::{FileEntry, StorageBackend}; +use crate::storage::{FileEntry, FileType, StorageBackend}; pub struct LocalStorage { folder_root: PathBuf @@ -36,17 +36,25 @@ fn get_path(folder_root: &PathBuf, library_id: &str, mut path: &Path) -> Result< Ok(path) } impl StorageBackend for LocalStorage { - - fn get_read_stream(&self, library_id: &str, rel_path: &PathBuf,) -> Result, Error> { + fn touch_file(&self, library_id: &str, rel_path: &PathBuf, file_type: FileType) -> Result<(), anyhow::Error> { let path = get_path(&self.folder_root, library_id, rel_path)?; - let file = File::open(path)?; - Ok(BufReader::new(file)) + match file_type { + FileType::File => { + // open and close file + File::open(path).map_err(|e| anyhow!(e))?; + } + FileType::Folder => { + std::fs::create_dir_all(path).map_err(|e| anyhow!(e))?; + } + _ => return Err(anyhow!("Unsupported")) + } + Ok(()) } - fn write_file(&self, library_id: &str, rel_path: &PathBuf, contents: &[u8]) -> Result<(), Error> { let path = get_path(&self.folder_root, library_id, rel_path)?; std::fs::write(path, contents).map_err(|e| anyhow!(e)) } + fn read_file(&self, library_id: &str, rel_path: &PathBuf) -> Result>, Error> { let path = get_path(&self.folder_root, library_id, rel_path)?; match std::fs::read(path) { @@ -55,7 +63,6 @@ impl StorageBackend for LocalStorage { Err(e) => Err(anyhow!(e)), } } - fn list_files(&self, library_id: &str, rel_path: &PathBuf) -> Result, Error> { let path = get_path(&self.folder_root, library_id, rel_path)?; Ok(std::fs::read_dir(path)? @@ -73,14 +80,20 @@ impl StorageBackend for LocalStorage { .collect()) } - fn delete_file(&self, library_id: &str, rel_path: &PathBuf) -> Result<(), Error> { - let path = get_path(&self.folder_root, library_id, rel_path)?; - // TODO: check if folder? - std::fs::remove_file(path).map_err(|e| anyhow!(e)) - } + fn delete_file(&self, library_id: &str, rel_path: &PathBuf) -> Result<(), Error> { + let path = get_path(&self.folder_root, library_id, rel_path)?; + // TODO: check if folder? + std::fs::remove_file(path).map_err(|e| anyhow!(e)) + } fn move_file(&self, library_id: &str, rel_path: &PathBuf, new_rel_path: &PathBuf) -> Result<(), Error> { let path = get_path(&self.folder_root, library_id, rel_path)?; std::fs::rename(path, new_rel_path).map_err(|e| anyhow!(e)) } + + fn get_read_stream(&self, library_id: &str, rel_path: &PathBuf,) -> Result, Error> { + let path = get_path(&self.folder_root, library_id, rel_path)?; + let file = File::open(path)?; + Ok(BufReader::new(file)) + } } \ No newline at end of file diff --git a/static/css/main.css b/static/css/main.css index c71c05d..c4bd409 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -78,4 +78,8 @@ tr.file-list td.filecell-label a { } .login-bg { background-image: linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%); -} \ No newline at end of file +} + +.readyhidden, *[x-cloak] { + display: none; +} diff --git a/static/js/add_button.js b/static/js/add_button.js index c7605d4..9969a8e 100644 --- a/static/js/add_button.js +++ b/static/js/add_button.js @@ -1,6 +1,16 @@ document.addEventListener('DOMContentLoaded', () => { - const addDropdown = document.getElementById("add-dropdown") - addDropdown.classList.remove("is-hidden") + document.querySelector("#file-checkbox-all").addEventListener("input", (e) => { + const checked = e.target.checked + console.log("checked", checked) + document.querySelectorAll(".file-checkbox").forEach(el => { + el.checked = checked + }) + }) + + const readyhiddenItems = document.getElementsByClassName("readyhidden"); + for (let i = 0; i < readyhiddenItems.length; i++) { + readyhiddenItems.item(i).classList.remove("readyhidden") + } document.getElementById("modal-prompt-form") @@ -72,4 +82,4 @@ async function touchSubmit(event) { } function upload(type) { -} \ No newline at end of file +} diff --git a/templates/layouts/default.html.hbs b/templates/layouts/default.html.hbs index 45a8500..1c75d2d 100644 --- a/templates/layouts/default.html.hbs +++ b/templates/layouts/default.html.hbs @@ -17,4 +17,7 @@ {{> @partial-block }} + {{#if has-scripts}} + {{> scripts}} + {{/if}} diff --git a/templates/libraries.html.hbs b/templates/libraries.html.hbs index 199a779..70910c6 100644 --- a/templates/libraries.html.hbs +++ b/templates/libraries.html.hbs @@ -1,28 +1,8 @@ -{{#> layouts/main }} -
- +{{#> layouts/main has-scripts=1 }} +
-