Add image view page, improve opengraph

This commit is contained in:
asonix 2020-12-03 13:40:16 -06:00
parent 1a1d280bac
commit 34b6623593
10 changed files with 139 additions and 27 deletions

View file

@ -96,6 +96,17 @@ impl Config {
url.to_string()
}
fn view_url(&self, size: Option<u64>, name: &str) -> String {
let mut url = self.domain.clone();
if let Some(size) = size {
url.set_path(&format!("view/{}/{}", size, name));
} else {
url.set_path(&format!("view/{}", name));
}
url.to_string()
}
fn thumbnails_url(&self, name: &str) -> String {
let mut url = self.domain.clone();
url.set_path("/thumbnails");
@ -158,6 +169,14 @@ impl Images {
fn is_ok(&self) -> bool {
self.files().is_some()
}
fn message(&self) -> &'static str {
if self.is_ok() {
"Images Uploaded"
} else {
"Image Upload Failed"
}
}
}
#[derive(Debug, serde::Deserialize)]
@ -179,6 +198,10 @@ impl Image {
CONFIG.thumbnails_url(&self.file)
}
fn view(&self, size: Option<u64>) -> String {
CONFIG.view_url(size, &self.file)
}
fn thumb(&self, size: u64, filetype: FileType) -> String {
CONFIG.thumbnail_url(size, &self.file, filetype)
}
@ -322,6 +345,62 @@ async fn image(
Ok(client_res.body(BodyStream::new(res)))
}
async fn view_original(
file: web::Path<String>,
client: web::Data<Client>,
) -> Result<HttpResponse, Error> {
let file = file.into_inner();
let url = CONFIG.upstream_image_url(&file);
let res = client.get(url).send().await?;
if res.status() == StatusCode::NOT_FOUND {
return Ok(to_404());
}
let image = Image {
file,
delete_token: String::new(),
};
let mut cursor = Cursor::new(vec![]);
self::templates::view(&mut cursor, image, None)?;
Ok(HttpResponse::Ok()
.content_type(mime::TEXT_HTML.essence_str())
.body(cursor.into_inner()))
}
async fn view(
parts: web::Path<(u64, String)>,
client: web::Data<Client>,
) -> Result<HttpResponse, Error> {
let (size, file) = parts.into_inner();
if !valid_thumbnail_size(size) {
return Ok(to_404());
}
let url = CONFIG.upstream_image_url(&file);
let res = client.get(url).send().await?;
if res.status() == StatusCode::NOT_FOUND {
return Ok(to_404());
}
let image = Image {
file,
delete_token: String::new(),
};
let mut cursor = Cursor::new(vec![]);
self::templates::view(&mut cursor, image, Some(size))?;
Ok(HttpResponse::Ok()
.content_type(mime::TEXT_HTML.essence_str())
.body(cursor.into_inner()))
}
async fn thumbnail(
parts: web::Path<(u64, FileType, String)>,
req: HttpRequest,
@ -460,6 +539,8 @@ async fn main() -> Result<(), anyhow::Error> {
.service(web::resource("/upload").route(web::post().to(upload)))
.service(web::resource("/image/{filename}").route(web::get().to(full_res)))
.service(web::resource("thumbnails").route(web::get().to(thumbs)))
.service(web::resource("/view/{size}/{filename}").route(web::get().to(view)))
.service(web::resource("/view/{filename}").route(web::get().to(view_original)))
.service(
web::resource("/thumb/{size}/{filetype}/{filename}")
.route(web::get().to(thumbnail)),

View file

@ -3,7 +3,7 @@
@(image: &Image)
@:layout_html({
@:layout_html("Confirm Delete", Some(&format!("Delete {} from pict-rs", image.filename())), {
<title>Confirm Delete</title>
<link rel="stylesheet" href="@crate::statics(&images_css.name)" type="text/css" />
}, {

View file

@ -2,9 +2,7 @@
@(filename: &str)
@:layout_html({
<title>Deleted @filename</title>
}, {
@:layout_html(&format!("Deleted {}", filename), None, {}, {
<section>
<article>
<h3>Deleted @filename</h3>

View file

@ -2,9 +2,7 @@
@(msg: &str)
@:layout_html({
<title>Error</title>
}, {
@:layout_html("Error", None, {}, {
<section>
<article>
<h3>There was an error processing your request</h3>

View file

@ -3,12 +3,7 @@
@(images: Images)
@:layout_html({
@if images.is_ok() {
<title>Images Uploaded</title>
} else {
<title>Image Upload Failed</title>
}
@:layout_html(images.message(), None, {
<link rel="stylesheet" href="@crate::statics(&images_css.name)" type="text/css" />
}, {
<section>
@ -32,11 +27,11 @@
<p>
Link:<br />
<a
href="@image.link()"
href="@image.view(None)"
target="_blank"
rel="noopener noreferrer"
>
@image.link()
@image.view(None)
</a>
</p>
<p>

View file

@ -2,8 +2,7 @@
@(endpoint: &str, name: &str)
@:layout_html({
<title>Upload images</title>
@:layout_html("Upload Images", None, {
<link rel="stylesheet" href="@crate::statics(&form_css.name)" type="text/css" />
<script src="@crate::statics(&form_js.name)" type="text/javascript"></script>
}, {

View file

@ -1,6 +1,6 @@
@use super::statics::{layout_css, favicon_ico};
@(head: Content, body: Content)
@(title: &str, description: Option<&str>, head: Content, body: Content)
<!DOCTYPE html>
@ -8,9 +8,14 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>@title</title>
<link rel="stylesheet" href="@crate::statics(&layout_css.name)" type="text/css" />
<meta property="og:title" content="A simple image host" />
<meta property="og:description" content="Upload and share image files" />
<meta property="og:title" content="@title" />
@if let Some(description) = description {
<meta property="og:description" content="@description" />
} else {
<meta property="og:description" content="Upload and share image files" />
}
<meta property="og:type" content="website" />
<link rel="shortcut icon" type="image/png" href="@crate::statics(&favicon_ico.name)">
@:head()

View file

@ -2,8 +2,7 @@
@()
@:layout_html({
<title>Not Found</title>
@:layout_html("Not Found", None, {
<link rel="stylesheet" href="@crate::statics(&not_found_css.name)" type="text/css" />
}, {
<section>

View file

@ -3,8 +3,10 @@
@(image: Image, sizes: &[u64])
@:layout_html({
<title>Thumbnails</title>
@:layout_html("Thumbnails", Some(&format!("Thumbnails for {}", image.filename())), {
<meta property="og:image" content="@image.link()" />
<meta property="og:url" content="@image.link()" />
<meta property="og:image:alt" content="Image: @image.filename()" />
<link rel="stylesheet" href="@crate::statics(&images_css.name)" type="text/css" />
}, {
<section>
@ -14,7 +16,7 @@
<ul>
<li>
<article>
<p>Original File:<br /><a href="@image.link()">@image.link()</a></p>
<p>Original File:<br /><a href="@image.view(None)">@image.view(None)</a></p>
</article>
</li>
@for size in sizes {
@ -27,11 +29,11 @@
<p>@size x @size</p>
<p>
<a
href="@image.thumb(*size, FileType::Jpg)"
href="@image.view(Some(*size))"
target="_blank"
rel="noopener noreferrer"
>
@image.thumb(*size, FileType::Jpg)
@image.view(Some(*size))
</a>
</p>
</article>

35
templates/view.rs.html Normal file
View file

@ -0,0 +1,35 @@
@use super::{layout_html, return_home_html, statics::images_css};
@use crate::{Image, FileType};
@(image: Image, size: Option<u64>)
@:layout_html(&format!("Image: {}", image.filename()), Some("An image hosted on pict-rs"), {
<link rel="stylesheet" href="@crate::statics(&images_css.name)" type="text/css" />
@if let Some(size) = size {
<meta property="og:image" content="@image.thumb(size, FileType::Jpg)" />
<meta property="og:url" content="@image.view(Some(size))" />
<meta property="og:image:type" content="image/jpg" />
} else {
<meta property="og:image" content="@image.link()" />
<meta property="og:url" content="@image.view(None)" />
}
<meta property="og:image:alt" content="Image: @image.filename()" />
}, {
<section>
<article>
<div>
@if let Some(size) = size {
<picture>
<source type="image/webp" srcset="@image.thumb(size, FileType::Webp)" />
<img src="@image.thumb(size, FileType::Jpg)" alt="@image.filename()" title="@image.filename()" />
</picture>
<p><a href="@image.thumb(size, FileType::Jpg)">Direct Link</a></p>
} else {
<img src="@image.link()" alt="@image.filename()" title="@image.filename()" />
<p><a href="@image.link()">Direct Link</a></p>
}
</div>
</article>
@:return_home_html()
</section>
})