From ce874e1d30142cda0be4b7636f9457cee8582d70 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Wed, 25 Oct 2023 22:52:03 -0400 Subject: [PATCH 1/3] Fix the form to string conversion and set up the Delete form --- file-service/src/html.rs | 2 +- file-service/src/pages.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/file-service/src/html.rs b/file-service/src/html.rs index 5f5e2cd..1be10bc 100644 --- a/file-service/src/html.rs +++ b/file-service/src/html.rs @@ -74,7 +74,7 @@ impl Html for Form { None => "".to_owned(), }; format!( - "
\n", + "\n{elements}\n
\n", path = self.path, method = self.method, encoding = encoding, diff --git a/file-service/src/pages.rs b/file-service/src/pages.rs index e68aabe..589f6b7 100644 --- a/file-service/src/pages.rs +++ b/file-service/src/pages.rs @@ -106,9 +106,8 @@ pub fn thumbnail(info: &FileInfo) -> Container { ) .with_html( Form::new() - .with_path(&format!("/{}", *info.id)) + .with_path(&format!("/delete/{}", *info.id)) .with_method("post") - .with_html(Input::new("hidden", "_method").with_value("delete")) .with_html(Button::new("Delete")), ), ) -- 2.44.1 From 79490338577805a73fd6592dfa1a8462c47a9168 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Wed, 25 Oct 2023 22:54:05 -0400 Subject: [PATCH 2/3] Add the handler to delete a file --- file-service/src/handlers.rs | 19 +++++++++++++++++++ file-service/src/lib.rs | 4 ++-- file-service/src/main.rs | 18 +++++++++++++++--- file-service/src/store/mod.rs | 35 +++++++++++++++++++++++++++++++---- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/file-service/src/handlers.rs b/file-service/src/handlers.rs index d28623b..dd77780 100644 --- a/file-service/src/handlers.rs +++ b/file-service/src/handlers.rs @@ -134,6 +134,25 @@ pub async fn handle_upload( } } +pub async fn handle_delete( + app: App, + token: SessionToken, + id: FileId, +) -> Result, Error> { + match app.validate_session(token).await { + Ok(Some(_)) => match app.delete_file(id).await { + Ok(_) => Response::builder() + .header("location", "/") + .status(StatusCode::SEE_OTHER) + .body("".to_owned()), + Err(_) => unimplemented!(), + }, + _ => Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body("".to_owned()), + } +} + fn serve_file( info: FileInfo, file: F, diff --git a/file-service/src/lib.rs b/file-service/src/lib.rs index a19f54c..0325109 100644 --- a/file-service/src/lib.rs +++ b/file-service/src/lib.rs @@ -1,6 +1,6 @@ mod store; pub use store::{ - AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store, - Username, WriteFileError, + AuthDB, AuthError, AuthToken, DeleteFileError, FileHandle, FileId, FileInfo, ReadFileError, + SessionToken, Store, Username, WriteFileError, }; diff --git a/file-service/src/main.rs b/file-service/src/main.rs index 88b69cc..c9d70df 100644 --- a/file-service/src/main.rs +++ b/file-service/src/main.rs @@ -1,7 +1,7 @@ extern crate log; use cookie::Cookie; -use handlers::{file, handle_auth, handle_css, handle_upload, thumbnail}; +use handlers::{file, handle_auth, handle_css, handle_delete, handle_upload, thumbnail}; use std::{ collections::{HashMap, HashSet}, convert::Infallible, @@ -19,8 +19,8 @@ mod pages; const MAX_UPLOAD: u64 = 15 * 1024 * 1024; pub use file_service::{ - AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store, - Username, WriteFileError, + AuthDB, AuthError, AuthToken, DeleteFileError, FileHandle, FileId, FileInfo, ReadFileError, + SessionToken, Store, Username, WriteFileError, }; pub use handlers::handle_index; @@ -64,6 +64,11 @@ impl App { ) -> Result { self.store.write().await.add_file(filename, content) } + + pub async fn delete_file(&self, id: FileId) -> Result<(), DeleteFileError> { + self.store.write().await.delete_file(&id)?; + Ok(()) + } } fn with_app(app: App) -> impl Filter + Clone { @@ -134,6 +139,12 @@ pub async fn main() { .and(warp::multipart::form().max_length(MAX_UPLOAD)) .then(handle_upload); + let delete_via_form = warp::path!("delete" / String) + .and(warp::post()) + .and(with_app(app.clone())) + .and(with_session()) + .then(|id, app, token| handle_delete(app, token, FileId::from(id))); + let thumbnail = warp::path!(String / "tn") .and(warp::get()) .and(warp::header::optional::("if-none-match")) @@ -150,6 +161,7 @@ pub async fn main() { root.or(styles) .or(auth) .or(upload_via_form) + .or(delete_via_form) .or(thumbnail) .or(file) .with(log), diff --git a/file-service/src/store/mod.rs b/file-service/src/store/mod.rs index 5f07644..1f7ad05 100644 --- a/file-service/src/store/mod.rs +++ b/file-service/src/store/mod.rs @@ -53,9 +53,6 @@ pub enum ReadFileError { #[error("permission denied")] PermissionDenied, - #[error("invalid path")] - InvalidPath, - #[error("JSON error")] JSONError(#[from] serde_json::error::Error), @@ -63,6 +60,36 @@ pub enum ReadFileError { IOError(#[from] std::io::Error), } +#[derive(Debug, Error)] +pub enum DeleteFileError { + #[error("file not found")] + FileNotFound(PathBuf), + + #[error("metadata path is not a file")] + NotAFile, + + #[error("cannot read metadata")] + PermissionDenied, + + #[error("invalid metadata path")] + MetadataParseError(serde_json::error::Error), + + #[error("IO error")] + IOError(#[from] std::io::Error), +} + +impl From for DeleteFileError { + fn from(err: ReadFileError) -> Self { + match err { + ReadFileError::FileNotFound(path) => DeleteFileError::FileNotFound(path), + ReadFileError::NotAFile => DeleteFileError::NotAFile, + ReadFileError::PermissionDenied => DeleteFileError::PermissionDenied, + ReadFileError::JSONError(err) => DeleteFileError::MetadataParseError(err), + ReadFileError::IOError(err) => DeleteFileError::IOError(err), + } + } +} + #[derive(Debug, Error)] pub enum AuthError { #[error("authentication token is duplicated")] @@ -369,7 +396,7 @@ impl Store { FileHandle::load(id, &self.files_root) } - pub fn delete_file(&mut self, id: &FileId) -> Result<(), WriteFileError> { + pub fn delete_file(&mut self, id: &FileId) -> Result<(), DeleteFileError> { let handle = FileHandle::load(id, &self.files_root)?; handle.delete(); Ok(()) -- 2.44.1 From d878f4e82c6f802be0d909df1f505345e8729332 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 26 Oct 2023 00:19:13 -0400 Subject: [PATCH 3/3] Resolve more linting issues --- file-service/src/html.rs | 30 ------------------------------ file-service/src/pages.rs | 2 +- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/file-service/src/html.rs b/file-service/src/html.rs index 1be10bc..ce58e15 100644 --- a/file-service/src/html.rs +++ b/file-service/src/html.rs @@ -137,11 +137,6 @@ impl Input { self } - pub fn with_value(mut self, val: &str) -> Self { - self.value = Some(val.to_owned()); - self - } - pub fn with_attributes<'a>( mut self, values: impl IntoIterator, @@ -156,31 +151,6 @@ impl Input { } } -#[derive(Clone, Debug)] -pub struct Label { - target: String, - text: String, -} - -impl Label { - pub fn new(target: &str, text: &str) -> Self { - Self { - target: target.to_owned(), - text: text.to_owned(), - } - } -} - -impl Html for Label { - fn to_html_string(&self) -> String { - format!( - "", - target = self.target, - text = self.text - ) - } -} - #[derive(Clone, Debug)] pub struct Button { ty: Option, diff --git a/file-service/src/pages.rs b/file-service/src/pages.rs index 589f6b7..d6a2074 100644 --- a/file-service/src/pages.rs +++ b/file-service/src/pages.rs @@ -92,7 +92,7 @@ pub fn thumbnail(info: &FileInfo) -> Container { format!("/{}", *info.id), Container::default() .with_attributes([("class", "thumbnail")]) - .with_image(&format!("{}/tn", *info.id), "test data") + .with_image(format!("{}/tn", *info.id), "test data") .to_html_string(), ), ) -- 2.44.1