]> OzVa Git service - ozva-cloud/commitdiff
feat: support delete operation
authorsigoden <sigoden@gmail.com>
Thu, 26 May 2022 11:52:54 +0000 (19:52 +0800)
committersigoden <sigoden@gmail.com>
Thu, 26 May 2022 11:52:54 +0000 (19:52 +0800)
src/args.rs
src/index.css
src/index.html
src/server.rs

index 4fdeba8f9b5200d8683676707d689b63dcdc0b59..2448ae6902984ab2502f7573db12e2c0ffbb4b3d 100644 (file)
@@ -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")
index f59b195d3b38558a03caea346c6bae754ae7c7ab..76acb01457e4a08b602c2868afc08e4d33090e36 100644 (file)
@@ -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;
+}
index 31748715c461fe472a84b52745603cd5b20f412a..d77b8a0680ac328d1dee5edbe1dd2cb5d5309865 100644 (file)
       }
     }
 
-    function addFile(file) {
+    function addPath(file, index) {
+      const actionTd = file.name === ".." || readonly ? "" : `
+      <td class="cell-actions">
+        <div onclick="deletePath(${index})" class="delete-btn" id="deleteBtn${index}" title="Delete ${file.name}">
+          <svg width="18" height="18" viewBox="0 0 40 40"><path d="M28,40H11.8c-3.3,0-5.9-2.7-5.9-5.9V16c0-0.6,0.4-1,1-1s1,0.4,1,1v18.1c0,2.2,1.8,3.9,3.9,3.9H28c2.2,0,3.9-1.8,3.9-3.9V16   c0-0.6,0.4-1,1-1s1,0.4,1,1v18.1C33.9,37.3,31.2,40,28,40z"/></g><g><path d="M33.3,4.9h-7.6C25.2,2.1,22.8,0,19.9,0s-5.3,2.1-5.8,4.9H6.5c-2.3,0-4.1,1.8-4.1,4.1S4.2,13,6.5,13h26.9   c2.3,0,4.1-1.8,4.1-4.1S35.6,4.9,33.3,4.9z M19.9,2c1.8,0,3.3,1.2,3.7,2.9h-7.5C16.6,3.2,18.1,2,19.9,2z M33.3,11H6.5   c-1.1,0-2.1-0.9-2.1-2.1c0-1.1,0.9-2.1,2.1-2.1h26.9c1.1,0,2.1,0.9,2.1,2.1C35.4,10.1,34.5,11,33.3,11z"/></g><g><path d="M12.9,35.1c-0.6,0-1-0.4-1-1V17.4c0-0.6,0.4-1,1-1s1,0.4,1,1v16.7C13.9,34.6,13.4,35.1,12.9,35.1z"/></g><g><path d="M26.9,35.1c-0.6,0-1-0.4-1-1V17.4c0-0.6,0.4-1,1-1s1,0.4,1,1v16.7C27.9,34.6,27.4,35.1,26.9,35.1z"/></g><g><path d="M19.9,35.1c-0.6,0-1-0.4-1-1V17.4c0-0.6,0.4-1,1-1s1,0.4,1,1v16.7C20.9,34.6,20.4,35.1,19.9,35.1z"/></svg>
+        </div>
+      </td>`
+
       $tbody.insertAdjacentHTML("beforeend", `
-  <tr>
+  <tr id="addPath${index}">
     <td class="path cell-name">
       <div>${getSvg(file.path_type)}</div>
       <a href="${encodeURI(file.path)}" title="${file.name}">${file.name}</a>
     </td>
     <td class="cell-mtime">${formatMtime(file.mtime)}</td>
     <td class="cell-size">${formatSize(file.size)}</td>
-  </tr>
-`)
+    ${actionTd}
+  </tr>`)
+    }
+
+    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() {
     }
 
 
+
     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", `<th class="cell-actions">Actions</th>`);
         document.getElementById("file").addEventListener("change", e => {
           const files = e.target.files;
           for (const file of files) {
index 663a77e3cbf90728a9c7e0057d7b81abd5bd1152..45ac63ad9530fb8368fd181f7c54d19f6451f2ba 100644 (file)
@@ -60,6 +60,12 @@ impl InnerService {
     }
 
     pub async fn handle(self: Arc<Self>, req: Request) -> Result<Response, hyper::Error> {
+        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<Response> {
-        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<Response> {
-        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<Response> {
+        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<Response> {
         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 =