}
}
- 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) {
}
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 {
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));
};
}
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)),
}
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)),
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?;
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 =