Add PNG download of QR-Code

This commit is contained in:
Dietrich 2021-02-07 17:49:13 +01:00
parent b7f7c429de
commit 325cdfc9d4
Signed by: dietrich
GPG Key ID: 9F3C20C0F85DF67C
5 changed files with 270 additions and 19 deletions

224
Cargo.lock generated
View File

@ -304,6 +304,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aead"
version = "0.3.2"
@ -475,7 +481,7 @@ dependencies = [
"addr2line",
"cfg-if 1.0.0",
"libc",
"miniz_oxide",
"miniz_oxide 0.4.3",
"object",
"rustc-demangle",
]
@ -606,6 +612,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a4bad0c5981acc24bc09e532f35160f952e35422603f0563cd7a73c2c2e65a0"
[[package]]
name = "byteorder"
version = "1.4.2"
@ -663,6 +675,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "checked_int_cast"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919"
[[package]]
name = "chrono"
version = "0.4.19"
@ -731,6 +749,12 @@ dependencies = [
"bitflags",
]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "const_fn"
version = "0.4.5"
@ -781,6 +805,41 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
dependencies = [
"cfg-if 1.0.0",
"const_fn",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard 1.1.0",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
@ -811,6 +870,16 @@ dependencies = [
"cipher",
]
[[package]]
name = "deflate"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
dependencies = [
"adler32",
"byteorder",
]
[[package]]
name = "derive-error-chain"
version = "0.10.1"
@ -1029,7 +1098,7 @@ dependencies = [
"cfg-if 1.0.0",
"crc32fast",
"libc",
"miniz_oxide",
"miniz_oxide 0.4.3",
]
[[package]]
@ -1229,6 +1298,16 @@ dependencies = [
"polyval",
]
[[package]]
name = "gif"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02efba560f227847cb41463a7395c514d127d4f74fff12ef0137fff1b84b96c4"
dependencies = [
"color_quant",
"weezl",
]
[[package]]
name = "gimli"
version = "0.23.0"
@ -1417,6 +1496,25 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "image"
version = "0.23.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "293f07a1875fa7e9c5897b51aa68b2d8ed8271b87e1a44cb64b9c3d98aabbc0d"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"gif",
"jpeg-decoder",
"num-iter",
"num-rational",
"num-traits",
"png",
"scoped_threadpool",
"tiff",
]
[[package]]
name = "indexmap"
version = "1.6.1"
@ -1472,6 +1570,15 @@ dependencies = [
"libc",
]
[[package]]
name = "jpeg-decoder"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
dependencies = [
"rayon",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -1577,6 +1684,15 @@ version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "memoffset"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
dependencies = [
"autocfg 1.0.1",
]
[[package]]
name = "mime"
version = "0.3.16"
@ -1593,6 +1709,15 @@ dependencies = [
"unicase",
]
[[package]]
name = "miniz_oxide"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
dependencies = [
"adler32",
]
[[package]]
name = "miniz_oxide"
version = "0.4.3"
@ -1676,6 +1801,28 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
dependencies = [
"autocfg 1.0.1",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [
"autocfg 1.0.1",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
@ -1878,6 +2025,18 @@ version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "png"
version = "0.16.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
dependencies = [
"bitflags",
"crc32fast",
"deflate",
"miniz_oxide 0.3.7",
]
[[package]]
name = "polyval"
version = "0.4.5"
@ -1926,10 +2085,14 @@ dependencies = [
]
[[package]]
name = "qrcodegen"
version = "1.6.0"
name = "qrcode"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24ea38b2345f15533e6668104bec0136883404287e095f15f9ea2522e2b4b6c"
checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f"
dependencies = [
"checked_int_cast",
"image",
]
[[package]]
name = "quick-error"
@ -2161,6 +2324,31 @@ dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rayon"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
dependencies = [
"autocfg 1.0.1",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "rdrand"
version = "0.4.0"
@ -2265,6 +2453,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
[[package]]
name = "scopeguard"
version = "0.3.3"
@ -2407,8 +2601,9 @@ dependencies = [
"diesel_codegen",
"dotenv",
"env_logger 0.8.2",
"image",
"log",
"qrcodegen",
"qrcode",
"serde",
"tera",
]
@ -2649,6 +2844,17 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "tiff"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437"
dependencies = [
"jpeg-decoder",
"miniz_oxide 0.4.3",
"weezl",
]
[[package]]
name = "time"
version = "0.1.43"
@ -3071,6 +3277,12 @@ version = "0.2.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
[[package]]
name = "weezl"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a32b378380f4e9869b22f0b5177c68a5519f03b3454fde0b291455ddbae266c"
[[package]]
name = "which"
version = "2.0.1"

View File

@ -20,7 +20,8 @@ chrono = { version = "0.4", features = ["serde"] }
argonautica = "0.2"
env_logger = "0.8"
log = "0.4"
qrcodegen = "1.6"
qrcode = "0.12"
image = "0.23"
[build-dependencies]
actix-web-static-files = "3"

View File

@ -126,6 +126,10 @@ async fn main() -> std::io::Result<()> {
web::scope("/view")
.route("/{redirect_id}", web::get().to(views::view_link)),
)
.service(
web::scope("/download")
.route("/png/{redirect_id}", web::get().to(views::download_png)),
)
// login to the admin area
.route("/login/", web::get().to(views::login))
.route("/login/", web::post().to(views::process_login)),

View File

@ -2,22 +2,23 @@ use std::time::SystemTime;
use actix_identity::Identity;
use crate::ServerError;
use actix_web::{
http::header::{CacheControl, CacheDirective, Expires},
http::header::{CacheControl, CacheDirective, ContentType, Expires},
web, HttpResponse,
};
use qrcodegen::{QrCode, QrCodeEcc};
use crate::ServerError;
use super::forms::LinkForm;
use super::models::{Link, LoginUser, NewLink, NewUser, User};
use argonautica::Verifier;
use diesel::sqlite::SqliteConnection;
use diesel::{prelude::*, result::Error::NotFound};
use dotenv::dotenv;
use image::{DynamicImage, ImageOutputFormat, Luma};
use qrcode::render::svg;
use qrcode::QrCode;
use tera::{Context, Tera};
use super::forms::LinkForm;
use super::models::{Link, LoginUser, NewLink, NewUser, User};
fn establish_connection() -> Result<SqliteConnection, ServerError> {
dotenv().ok();
@ -82,9 +83,13 @@ pub(crate) async fn view_link(
.filter(code.eq(&link_id.0))
.first::<Link>(&connection)?;
let qr =
QrCode::encode_text(&format!("http://fhs.li/{}", &link_id.0), QrCodeEcc::Low).unwrap();
let svg = qr.to_svg_string(4);
let qr = QrCode::new(&format!("http://fhs.li/{}", &link_id.0)).unwrap();
let svg = qr
.render()
.min_dimensions(200, 200)
.dark_color(svg::Color("#000000"))
.light_color(svg::Color("#ffffff"))
.build();
let mut data = Context::new();
data.insert("name", &id);
@ -102,6 +107,30 @@ pub(crate) async fn view_link(
}
}
pub(crate) async fn download_png(
id: Identity,
link_id: web::Path<String>,
) -> Result<HttpResponse, ServerError> {
if let Some(_id) = id.identity() {
use super::schema::links::dsl::{code, links};
let connection = establish_connection()?;
if let Ok(_link) = links.filter(code.eq(&link_id.0)).first::<Link>(&connection) {
let qr = QrCode::new(&format!("http://fhs.li/{}", &link_id)).unwrap();
let png = qr.render::<Luma<u8>>().quiet_zone(false).build();
let mut temporary_data = std::io::Cursor::new(Vec::new());
DynamicImage::ImageLuma8(png)
.write_to(&mut temporary_data, ImageOutputFormat::Png)
.unwrap();
let image_data = temporary_data.into_inner();
Ok(HttpResponse::Ok().set(ContentType::png()).body(image_data))
} else {
Ok(redirect_builder("/admin/index/"))
}
} else {
Ok(redirect_builder("/admin/login/"))
}
}
pub(crate) async fn signup(
tera: web::Data<Tera>,
id: Identity,

View File

@ -1,7 +1,7 @@
{% extends "admin.html" %}
{% block admin %}
<h1>The Link {{ link.code }}</h1>
<h1>{{ link.title }}</h1>
<table>
<tr>
<td>Beschreibung:</td>
@ -21,7 +21,12 @@
</tr>
<tr>
<td>QR-Code</td>
<td>{{ qr | safe }}</td>
<td><a href="/admin/download/png/{{ link.code }}" download="{{ link.title | slugify }}.png">
{{ qr | trim_start_matches(pat=
'.*?>')
| safe }}
</a>
</td>
</tr>
<tr>
<td></td>