From dd888f1ae85f20ef58ce8710229f71e4dea942de Mon Sep 17 00:00:00 2001 From: sigoden Date: Thu, 26 May 2022 19:52:54 +0800 Subject: [PATCH] feat: support delete operation --- src/args.rs | 1 + src/index.css | 20 ++++++++++++++++---- src/index.html | 38 ++++++++++++++++++++++++++++++++------ src/server.rs | 36 +++++++++++++++++++++++++----------- 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/args.rs b/src/args.rs index 4fdeba8..2448ae6 100644 --- a/src/args.rs +++ b/src/args.rs @@ -34,6 +34,7 @@ fn app() -> clap::Command<'static> { .long("readonly") .help("Only serve static files, no operations like upload and delete"); + let arg_auth = Arg::new("auth") .short('a') .long("auth") diff --git a/src/index.css b/src/index.css index f59b195..76acb01 100644 --- a/src/index.css +++ b/src/index.css @@ -59,14 +59,26 @@ html { } .main .cell-name { - max-width: 300px; + width: 300px; +} + +.main .cell-mtime { + width: 150px; + padding-left: 1em; } .main .cell-size { text-align: right; - width: 80px; + width: 100px; + padding-left: 1em; } +.main .cell-actions { + width: 100px; + padding-left: 1em; +} + + .path svg { height: 100%; fill: rgba(3,47,98,0.5); @@ -98,5 +110,5 @@ html { } .uploader { - padding-right: 2em; -} \ No newline at end of file + padding-right: 1em; +} diff --git a/src/index.html b/src/index.html index 3174871..d77b8a0 100644 --- a/src/index.html +++ b/src/index.html @@ -103,17 +103,41 @@ } } - function addFile(file) { + function addPath(file, index) { + const actionTd = file.name === ".." || readonly ? "" : ` + +
+ +
+ ` + $tbody.insertAdjacentHTML("beforeend", ` - +
${getSvg(file.path_type)}
${file.name} ${formatMtime(file.mtime)} ${formatSize(file.size)} - -`) + ${actionTd} + `) + } + + async function deletePath(index) { + const file = paths[index]; + if (!file) return; + try { + const res = await fetch(encodeURI(file.path), { + method: "DELETE", + }); + if (res.status !== 200) { + const text = await res.text(); + throw new Error(text); + } + document.getElementById(`addPath${index}`).remove(); + } catch (err) { + alert(`Failed to delete ${file.name}, ${err.message}`); + } } function addUploadControl() { @@ -164,11 +188,13 @@ } + document.addEventListener('DOMContentLoaded', () => { addBreadcrumb(breadcrumb); - paths.forEach(file => addFile(file)); - if (readonly) { + paths.forEach((file, index) => addPath(file, index)); + if (!readonly) { addUploadControl(); + document.querySelector(".main thead tr").insertAdjacentHTML("beforeend", `Actions`); document.getElementById("file").addEventListener("change", e => { const files = e.target.files; for (const file of files) { diff --git a/src/server.rs b/src/server.rs index 663a77e..45ac63a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -60,6 +60,12 @@ impl InnerService { } pub async fn handle(self: Arc, req: Request) -> Result { + if !self.auth_guard(&req).unwrap_or_default() { + let mut res = status_code!(StatusCode::UNAUTHORIZED); + res.headers_mut().insert("WWW-Authenticate" , HeaderValue::from_static("Basic")); + return Ok(res) + } + let res = if req.method() == Method::GET { self.handle_static(req).await } else if req.method() == Method::PUT { @@ -67,6 +73,8 @@ impl InnerService { return Ok(status_code!(StatusCode::FORBIDDEN)); } self.handle_upload(req).await + } else if req.method() == Method::DELETE { + self.handle_delete(req).await } else { return Ok(status_code!(StatusCode::NOT_FOUND)); }; @@ -74,11 +82,6 @@ impl InnerService { } async fn handle_static(&self, req: Request) -> BoxResult { - if !self.auth_guard(&req).unwrap_or_default() { - let mut res = status_code!(StatusCode::UNAUTHORIZED); - res.headers_mut().insert("WWW-Authenticate" , HeaderValue::from_static("Basic")); - return Ok(res) - } let path = match self.get_file_path(req.uri().path())? { Some(path) => path, None => return Ok(status_code!(StatusCode::FORBIDDEN)), @@ -96,11 +99,6 @@ impl InnerService { } async fn handle_upload(&self, mut req: Request) -> BoxResult { - if !self.auth_guard(&req).unwrap_or_default() { - let mut res = status_code!(StatusCode::UNAUTHORIZED); - res.headers_mut().insert("WWW-Authenticate" , HeaderValue::from_static("Basic")); - return Ok(res) - } let path = match self.get_file_path(req.uri().path())? { Some(path) => path, None => return Ok(status_code!(StatusCode::FORBIDDEN)), @@ -125,6 +123,22 @@ impl InnerService { return Ok(status_code!(StatusCode::OK)); } + async fn handle_delete(&self, req: Request) -> BoxResult { + let path = match self.get_file_path(req.uri().path())? { + Some(path) => path, + None => return Ok(status_code!(StatusCode::FORBIDDEN)), + }; + + let meta = fs::metadata(&path).await?; + if meta.is_file() { + fs::remove_file(path).await?; + } else { + fs::remove_dir_all(path).await?; + } + Ok(status_code!(StatusCode::OK)) + + } + async fn handle_send_dir(&self, path: &Path) -> BoxResult { let base_path = &self.args.path; let mut rd = fs::read_dir(path).await?; @@ -179,7 +193,7 @@ impl InnerService { paths.sort_unstable(); let breadcrumb = self.get_breadcrumb(path); - let data = SendDirData { breadcrumb, paths, readonly: !self.args.readonly }; + let data = SendDirData { breadcrumb, paths, readonly: self.args.readonly }; let data = serde_json::to_string(&data).unwrap(); let mut output =