feat(cli,webui): check file presence via HEAD, disable download button if necessary
parent
03e3aafd70
commit
0f17538307
|
@ -11,7 +11,7 @@ use actix_web::error::{
|
|||
};
|
||||
use actix_web::http::header::ContentDisposition;
|
||||
use actix_web::{
|
||||
delete, error, get, post, put, routes, web, Either, Error, HttpResponse, ResponseError,
|
||||
delete, error, get, head, post, put, routes, web, Either, Error, HttpResponse, ResponseError,
|
||||
};
|
||||
use actix_web::{http, Responder};
|
||||
use actix_web::{
|
||||
|
@ -215,6 +215,42 @@ pub async fn get_raw(
|
|||
}
|
||||
}
|
||||
|
||||
#[head("/api/raw/{hash}")]
|
||||
pub async fn head_raw(
|
||||
state: web::Data<State>,
|
||||
hash: web::Path<String>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let address =
|
||||
Address::decode(&b58_decode(hash.into_inner()).map_err(ErrorInternalServerError)?)
|
||||
.map_err(ErrorInternalServerError)?;
|
||||
if let Address::Hash(hash) = address {
|
||||
let hash = Arc::new(hash);
|
||||
|
||||
let _hash = hash.clone();
|
||||
let _store = state.store.clone();
|
||||
let blobs = web::block(move || _store.retrieve(_hash.as_ref()))
|
||||
.await?
|
||||
.map_err(ErrorInternalServerError)?;
|
||||
if let Some(blob) = blobs.get(0) {
|
||||
let file_path = blob.get_file_path();
|
||||
|
||||
let mut response = HttpResponse::NoContent();
|
||||
if let Some(mime_type) = tree_magic_mini::from_filepath(&file_path) {
|
||||
if let Ok(mime) = mime_type.parse::<mime::Mime>() {
|
||||
return Ok(response.content_type(mime).finish());
|
||||
}
|
||||
}
|
||||
return Ok(response.into());
|
||||
}
|
||||
|
||||
Err(error::ErrorNotFound("NOT FOUND"))
|
||||
} else {
|
||||
Err(ErrorBadRequest(
|
||||
"Address does not refer to a rawable object.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/api/thumb/{hash}")]
|
||||
pub async fn get_thumbnail(
|
||||
state: web::Data<State>,
|
||||
|
|
|
@ -48,6 +48,7 @@ where
|
|||
.wrap(actix_web::middleware::Logger::default().exclude("/api/jobs"))
|
||||
.service(routes::login)
|
||||
.service(routes::get_raw)
|
||||
.service(routes::head_raw)
|
||||
.service(routes::get_thumbnail)
|
||||
.service(routes::get_query)
|
||||
.service(routes::get_object)
|
||||
|
|
|
@ -39,8 +39,16 @@
|
|||
});
|
||||
});
|
||||
|
||||
// isFile
|
||||
$: isFile = $entityInfo?.t == "Hash";
|
||||
let hasFile = false;
|
||||
$: {
|
||||
if ($entityInfo?.t == "Hash") {
|
||||
fetch(api.getRaw(address), {
|
||||
method: "HEAD",
|
||||
}).then((response) => {
|
||||
hasFile = response.ok;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Identification
|
||||
let inferredIds: string[] = [];
|
||||
|
@ -166,7 +174,7 @@
|
|||
<HashBadge {address} />
|
||||
<div class="separator" />
|
||||
<div class="label" class:resolving title={displayLabel}>
|
||||
{#if banner && isFile}
|
||||
{#if banner && hasFile}
|
||||
<UpObjectLabel label={displayLabel} backpath={resolvedBackpath} />
|
||||
{:else if link}
|
||||
<UpLink to={{ entity: address }}>
|
||||
|
@ -193,18 +201,23 @@
|
|||
</UpLink>
|
||||
</div>
|
||||
{/if}
|
||||
{#if isFile}
|
||||
<div class="icon">
|
||||
{#if $entityInfo?.t == "Hash"}
|
||||
<div
|
||||
class="icon"
|
||||
title={hasFile
|
||||
? $i18n.t("Download as file")
|
||||
: $i18n.t("File not present in vault")}
|
||||
>
|
||||
<a
|
||||
class="link-button"
|
||||
class:disabled={!hasFile}
|
||||
href="{api.apiUrl}/raw/{address}"
|
||||
download={inferredIds[0]}
|
||||
title={$i18n.t("Download as file")}
|
||||
>
|
||||
<Icon name="download" />
|
||||
</a>
|
||||
</div>
|
||||
{#if $vaultInfo?.desktop}
|
||||
{#if $vaultInfo?.desktop && hasFile}
|
||||
<div class="icon">
|
||||
<IconButton
|
||||
name="window-alt"
|
||||
|
@ -325,4 +338,9 @@
|
|||
margin: 0.12rem;
|
||||
box-shadow: 0 0 0.1rem 0.11rem colors.$red;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue