From 899f517859fe2d2981ec5214892c1af966358c6a Mon Sep 17 00:00:00 2001 From: "Jakob L. Kreuze" Date: Mon, 25 May 2020 18:32:15 -0400 Subject: Implement posts endpoint. --- Cargo.lock | 77 ++++++++++++++++++++++++++++++++++++++++++++++----------- Cargo.toml | 3 +++ src/database.rs | 38 ++++++++++++++-------------- src/main.rs | 50 +++++++++++++++++++++++++++++++------ 4 files changed, 127 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42fe9d5..6178093 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,6 +84,9 @@ dependencies = [ "rocket", "rocket_contrib", "rusqlite", + "serde", + "serde_derive", + "serde_json", ] [[package]] @@ -262,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7" dependencies = [ "devise_core", - "quote", + "quote 0.6.13", ] [[package]] @@ -272,9 +275,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487" dependencies = [ "bitflags", - "proc-macro2", - "quote", - "syn", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] @@ -807,9 +810,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336db4a192cc7f54efeb0c4e11a9245394824cc3bcbd37ba3ff51240c35d7a6e" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", "version_check 0.1.5", "yansi 0.4.0", ] @@ -844,7 +847,16 @@ version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid", + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" +dependencies = [ + "unicode-xid 0.2.0", ] [[package]] @@ -853,7 +865,16 @@ version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" dependencies = [ - "proc-macro2", + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +dependencies = [ + "proc-macro2 1.0.17", ] [[package]] @@ -939,7 +960,7 @@ dependencies = [ "devise", "glob", "indexmap", - "quote", + "quote 0.6.13", "rocket_http", "version_check 0.9.2", "yansi 0.5.0", @@ -972,7 +993,7 @@ dependencies = [ "smallvec", "state", "time", - "unicode-xid", + "unicode-xid 0.1.0", ] [[package]] @@ -1041,6 +1062,17 @@ version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +[[package]] +name = "serde_derive" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +dependencies = [ + "proc-macro2 1.0.17", + "quote 1.0.6", + "syn 1.0.25", +] + [[package]] name = "serde_json" version = "1.0.53" @@ -1082,9 +1114,20 @@ version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14a640819f79b72a710c0be059dce779f9339ae046c8bef12c361d56702146f" +dependencies = [ + "proc-macro2 1.0.17", + "quote 1.0.6", + "unicode-xid 0.2.0", ] [[package]] @@ -1168,6 +1211,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + [[package]] name = "untrusted" version = "0.6.2" diff --git a/Cargo.toml b/Cargo.toml index 629f2e3..9a47e7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ rusqlite = "0.21.0" image = "0.23.4" rocket = "0.4.4" rocket_contrib = "0.4.4" +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" [[bin]] name = "birka-cli" diff --git a/src/database.rs b/src/database.rs index d27646b..7b69a21 100644 --- a/src/database.rs +++ b/src/database.rs @@ -26,9 +26,9 @@ pub struct TagDatabase(Connection); /// Tag query with a sense of "state" for pagination. #[derive(Debug)] pub struct Query<'a> { - tags: &'a [&'a str], - last_id: Option, - limit: Option, + pub tags: &'a [&'a str], + pub last_id: Option, + pub limit: Option, } impl TagDatabase { @@ -144,6 +144,22 @@ impl TagDatabase { Ok(()) } + /// Return the tags for the image specified by `image_id`. + pub fn tags_for_image(&self, image_id: i64) -> Result> { + Ok(self + .0 + .prepare( + "SELECT tags.name, COUNT(mapping.tag) as tag_count + FROM mapping + INNER JOIN images ON images.id = ? + INNER JOIN tags + GROUP BY tags.name;", + )? + .query_map(params![image_id], |row| row.get(0))? + .filter_map(|tag| tag.ok()) + .collect()) + } + /// Return the intersection of the sets of images matching each of `tags`. pub fn query(&self, q: Query) -> Result> { let ids: Vec = q @@ -257,22 +273,6 @@ mod tests { tb.initialize_tables()?; Ok(tb) } - - /// Return the tags for the image specified by `image_id`. - pub fn tags_for_image(&self, image_id: i64) -> Result> { - Ok(self - .0 - .prepare( - "SELECT tags.name, COUNT(mapping.tag) as tag_count - FROM mapping - INNER JOIN images ON images.id = ? - INNER JOIN tags - GROUP BY tags.name;", - )? - .query_map(params![image_id], |row| row.get(0))? - .filter_map(|tag| tag.ok()) - .collect()) - } } #[test] diff --git a/src/main.rs b/src/main.rs index b5665b9..a4f5946 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,30 +24,59 @@ extern crate image; extern crate rocket; #[macro_use] extern crate rocket_contrib; +#[macro_use] +extern crate serde_derive; mod database; -use database::TagDatabase; +use database::{Query, TagDatabase}; use image::{GenericImageView, ImageFormat}; +use rocket::State; use rocket_contrib::json::{Json, JsonValue}; use std::env; use std::fs; use std::fs::File; use std::os::unix::fs::symlink; use std::path::Path; +use std::sync::Mutex; #[get("/")] -fn index() -> &'static str { +fn index(tb: State>) -> &'static str { "Hello, world!" } +#[derive(Serialize)] +struct ImageResult { + filename: String, + tags: Vec, +} + #[get("/posts?")] -fn posts(tags: String) -> Json> { - let tags: Vec = tags.split(",").map(|s| s.into()).collect(); - Json(tags) +fn posts(tb: State>, tags: String) -> Json> { + let tb = tb.inner().lock().unwrap(); + + let tags = tags.split(",").collect::>(); + let results = tb + .query(Query { + tags: &tags[..], + last_id: Some(0), + limit: Some(50), + }) + .unwrap(); + + Json( + results + .iter() + .map(|image| ImageResult { + filename: image.filename.clone(), + tags: tb.tags_for_image(image.id).unwrap(), + }) + .collect(), + ) } -fn create_image_directory() { +/// Maybe initialize the directory for storing image symlinks and thumbnails. +fn create_image_directory() -> TagDatabase { let bin = env::current_exe().unwrap(); let image_dir = bin.parent().unwrap().join("image/"); fs::create_dir(&image_dir).ok(); @@ -72,9 +101,14 @@ fn create_image_directory() { .unwrap(); } } + + tb } fn main() { - create_image_directory(); - rocket::ignite().mount("/", routes![index, posts]).launch(); + let tb = create_image_directory(); + rocket::ignite() + .manage(Mutex::new(tb)) + .mount("/", routes![index, posts]) + .launch(); } -- cgit v1.3