feat: support delete operation

This commit is contained in:
sigoden 2022-05-26 19:52:54 +08:00
parent 78e7daf7cc
commit dd888f1ae8
4 changed files with 74 additions and 21 deletions

View 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")

View 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;
}
padding-right: 1em;
}

View file

@ -103,17 +103,41 @@
}
}
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() {
@ -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", `<th class="cell-actions">Actions</th>`);
document.getElementById("file").addEventListener("change", e => {
const files = e.target.files;
for (const file of files) {

View 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 =