feat(cli,webui): check file presence via HEAD, disable download button if necessary

refactor/addresses-js
Tomáš Mládek 2023-11-23 22:17:37 +01:00
parent 03e3aafd70
commit 0f17538307
3 changed files with 63 additions and 8 deletions

View File

@ -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>,

View File

@ -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)

View File

@ -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>