diff options
| author | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2020-05-26 19:46:20 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2020-05-26 19:46:20 -0400 |
| commit | 433c5fa1c56bee5a9032380a3c9a339869a47d16 (patch) | |
| tree | c6ed8b5722b969abbf3239450466d4933dac039d | |
| parent | a932889c9a01537a53e9c587e13e25843744b6f0 (diff) | |
Implement initial templating.
| -rw-r--r-- | Cargo.lock | 155 | ||||
| -rw-r--r-- | Cargo.toml | 6 | ||||
| -rw-r--r-- | src/main.rs | 64 | ||||
| -rw-r--r-- | static/css/style.css | 20 | ||||
| -rw-r--r-- | templates/index.hbs | 36 |
5 files changed, 276 insertions, 5 deletions
@@ -7,6 +7,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" [[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + +[[package]] name = "anyhow" version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -119,6 +128,27 @@ dependencies = [ ] [[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -318,6 +348,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" [[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -413,6 +449,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] +name = "handlebars" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" +dependencies = [ + "lazy_static", + "log 0.4.8", + "pest", + "pest_derive", + "quick-error", + "regex", + "serde", + "serde_json", + "walkdir", +] + +[[package]] name = "hermit-abi" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -622,6 +675,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" [[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -824,6 +883,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2 1.0.17", + "quote 1.0.6", + "syn 1.0.25", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] + +[[package]] name = "pkg-config" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -860,6 +962,12 @@ dependencies = [ ] [[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] name = "quote" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -919,6 +1027,24 @@ dependencies = [ ] [[package]] +name = "regex" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" + +[[package]] name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -972,6 +1098,8 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a10e7471279bc2d4a21b6fddd9589016bb119e6fbb547b216dd54ef237f28341" dependencies = [ + "glob", + "handlebars", "log 0.4.8", "notify", "rocket", @@ -1085,6 +1213,18 @@ dependencies = [ ] [[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1131,6 +1271,15 @@ dependencies = [ ] [[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] name = "tiff" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1179,6 +1328,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" [[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -17,11 +17,15 @@ rusqlite = "0.21.0" # Until RFC #2887 is merged, image and rocket are deps of the CLI tool as well. image = "0.23.4" rocket = "0.4.4" -rocket_contrib = "0.4.4" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" +[dependencies.rocket_contrib] +version = "0.4.4" +default-features = false +features = ["handlebars_templates", "json", "serve"] + [[bin]] name = "birka-cli" path = "src/birka-cli.rs" diff --git a/src/main.rs b/src/main.rs index f82f07b..6eb939f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,9 @@ use database::{hash_file, Query, TagDatabase}; use image::ImageFormat; use rocket::{Data, State}; use rocket_contrib::json::Json; +use rocket_contrib::serve::StaticFiles; +use rocket_contrib::templates::Template; +use std::collections::HashMap; use std::env; use std::fs; use std::fs::File; @@ -59,13 +62,48 @@ impl DatabaseConnection { } #[get("/")] -fn index(tb: SiteState) -> &'static str { - "Hello, world!" +fn index() -> Template { + let context = HashMap::<&str, &str>::new(); + Template::render("index", &context) +} + +#[get("/posts?<tags>")] +fn display_posts(conn: SiteState, tags: String) -> Template { + #[derive(Serialize)] + struct TagResult { + name: String, + count: i64, + } + + #[derive(Serialize)] + struct Asdf { + tags: Vec<TagResult>, + images: Vec<ImageResult>, + } + + let tag_results = { + let tb = &conn.inner().lock().unwrap().tb; + tb.top_tags(20) + .unwrap() + .iter() + .map(|tup| TagResult { + name: tup.1.clone(), + count: tup.0, + }) + .collect() + }; + let images = get_posts(conn, tags).into_inner(); + let context = Asdf { + tags: tag_results, + images, + }; + Template::render("index", context) } #[derive(Serialize)] struct ImageResult { filename: String, + thumb_filename: String, tags: Vec<String>, } @@ -87,6 +125,7 @@ fn get_posts(conn: SiteState, tags: String) -> Json<Vec<ImageResult>> { .iter() .map(|image| ImageResult { filename: image.filename.clone(), + thumb_filename: thumb_filename(&image.filename), tags: tb.tags_for_image(image.id).unwrap(), }) .collect(), @@ -105,6 +144,18 @@ fn put_posts(conn: SiteState, filename: String, data: Data) -> Json<&str> { Json("uploaded!") } +fn thumb_filename(filename: &str) -> String { + String::from(format!( + "{}_thumb.png", + // Strip extension. + if let Some(n) = filename.rfind('.') { + &filename[..n] + } else { + &filename[..] + } + )) +} + /// Maybe initialize the directory for storing image symlinks and thumbnails. fn create_image_directory(conn: &DatabaseConnection) { fs::create_dir(&conn.image_dir).ok(); @@ -115,7 +166,7 @@ fn create_image_directory(conn: &DatabaseConnection) { symlink(&src, &dst).ok(); let stem = Path::new(&dst).file_stem().unwrap().to_str().unwrap(); - let thumb_path = format!("{}_thumb.png", stem); + let thumb_path = format!("{}/{}", conn.image_dir, thumb_filename(&stem)); let thumb_path = Path::new(&thumb_path); if !thumb_path.exists() { @@ -130,9 +181,14 @@ fn create_image_directory(conn: &DatabaseConnection) { fn main() { let conn = DatabaseConnection::new().unwrap(); + let image_dir = conn.image_dir.clone(); create_image_directory(&conn); rocket::ignite() + .attach(Template::fairing()) .manage(Mutex::new(conn)) - .mount("/", routes![index, get_posts]) + .mount("/public", StaticFiles::from("./static/")) + .mount("/image", StaticFiles::from(image_dir)) + .mount("/", routes![index, display_posts]) + .mount("/api", routes![get_posts, put_posts]) .launch(); } diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000..f50fa36 --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,20 @@ +body { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 10px; + grid-auto-rows: minmax(50px, auto); +} + +header { + grid-column: 1 / 3; + grid-row: 1; +} + +aside { + grid-column: 1; + grid-row: 2; +} + +main { + grid-column: 2 /3; + grid-row: 2 diff --git a/templates/index.hbs b/templates/index.hbs new file mode 100644 index 0000000..f0d6d91 --- /dev/null +++ b/templates/index.hbs @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> + <title>Hello, world!</title> + <link rel="stylesheet" type="text/css" href="/public/css/style.css"> + <meta charset="UTF-8"> +</head> +<body> + <header> + <h1>бирка-тян</h1> + </header> + <main> + {{#each images}} + <img src="/image/{{thumb_filename}}"> + {{/each}} + </main> + <aside id="tag-view"> + <section id="search"> + <h2>Search</h2> + <form id="search-box" method="GET" action="/posts"> + <input id="tags" name="tags" type="text" autocomplete="off"> + <button id="search-box-submit" type="submit">Search</button> + </form> + </section> + + <section id="search"> + <h2>Tags</h2> + <ul> + {{#each tags}} + <li><a href="/posts?tags={{ name }}">{{ name }}</a> {{ count }}</li> + {{/each}} + </ul> + </section> + </aside> +</body> +</html> |