diff --git a/Cargo.lock b/Cargo.lock index 165d68c..b4a84a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,7 +28,7 @@ checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" [[package]] name = "arse" -version = "0.10.1" +version = "0.11.0" dependencies = [ "anyhow", "clap", @@ -38,6 +38,7 @@ dependencies = [ "pulldown-cmark", "rand", "routerify", + "rss", "serde", "simplelog", "tempfile", @@ -46,6 +47,18 @@ dependencies = [ "toml", ] +[[package]] +name = "atom_syndication" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5016bf52ff4f3ed28bf3ec1fed96b53daf4b137d5e6b9f97a8cfae7b57a3a2" +dependencies = [ + "chrono", + "derive_builder", + "diligent-date-parser", + "quick-xml", +] + [[package]] name = "atty" version = "0.2.14" @@ -155,7 +168,7 @@ dependencies = [ "ansi_term", "atty", "bitflags", - "strsim", + "strsim 0.8.0", "textwrap", "unicode-width", "vec_map", @@ -171,6 +184,66 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_builder" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" +dependencies = [ + "darling", + "derive_builder_core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "deunicode" version = "0.4.3" @@ -186,6 +259,24 @@ dependencies = [ "generic-array", ] +[[package]] +name = "diligent-date-parser" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37ea528f01b8bfca1f71bcd06a8e6c898bf8fdfbf24dd9dbc7fb49338ed6d84" +dependencies = [ + "chrono", +] + +[[package]] +name = "encoding_rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" +dependencies = [ + "cfg-if", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -386,6 +477,12 @@ dependencies = [ "want", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "ignore" version = "0.4.18" @@ -664,6 +761,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "quick-xml" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26aab6b48e2590e4a64d1ed808749ba06257882b461d01ca71baeb747074a6dd" +dependencies = [ + "encoding_rs", + "memchr", +] + [[package]] name = "quote" version = "1.0.9" @@ -761,6 +868,17 @@ dependencies = [ "regex", ] +[[package]] +name = "rss" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e70d6ae72f8a4333af8ce9dce58942020528430eb0d46ee2fcb5e8d4d16377" +dependencies = [ + "atom_syndication", + "derive_builder", + "quick-xml", +] + [[package]] name = "ryu" version = "1.0.5" @@ -882,6 +1000,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + [[package]] name = "syn" version = "1.0.73" diff --git a/Cargo.toml b/Cargo.toml index e75bafc..86183d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arse" -version = "0.10.1" +version = "0.11.0" authors = ["Anthony Martinez"] edition = "2018" license = "MIT OR Apache-2.0" @@ -22,6 +22,7 @@ log = "0.4" pulldown-cmark = { version = "0.8", default-features = false, features = ["simd"] } rand = "0.8" routerify = "2" +rss = "1" serde = { version = "1", features = ["derive"] } simplelog = "0.10.0" tera = "1" diff --git a/README.md b/README.md index 41223de..97346d7 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ The following elements are available within the Tera context for rendering: - [x] Support custom bind address and port - [x] Support favicons - [x] Support a special `gallery` topic -- [ ] Support RSS feeds +- [x] Support RSS feeds ### License diff --git a/src/render.rs b/src/render.rs index 03de5d4..3ef0bef 100644 --- a/src/render.rs +++ b/src/render.rs @@ -19,8 +19,8 @@ use super::{Context, Result}; use log::{debug, trace}; use pulldown_cmark::{Parser, html}; -use tera::Tera; -use tera::Context as TemplateContext; +use rss::{Channel, ChannelBuilder, Item, ItemBuilder}; +use tera::{Tera, Context as TemplateContext}; /// Static defaults for the rendering engine. mod default; @@ -162,7 +162,41 @@ impl Engine { Ok(html_output) } + + /// Generates an RSS feed of + pub(crate) fn rss(&self) -> Result { + debug!("Rendering RSS Feed"); + let site = &self.app.site; + let items = Self::rss_items(&self)?; + let channel = ChannelBuilder::default() + .title(&site.name) + .link("stuff") // TODO: add an item to config::Site to hold the domain name + .description(format!("{} RSS Feed", &site.name)) + .items(items) + .build() + .unwrap(); + + Ok(channel.to_string()) + } + + fn rss_items(&self) -> Result> { + // TODO: Actually implement this in a meangingful way + /* + Need to loop across the topics and their contents and build Item + entities to push into a vector. Probably need to also get post + modification times. + + Need to come up with some way to define the title/description. + */ + let item1 = Item::default(); + + let item2 = Item::default(); + + let items = vec![item1, item2]; + Ok(items) + } } + #[cfg(test)] mod tests { use super::*; diff --git a/src/routes.rs b/src/routes.rs index 91cfdc4..69e7c66 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -30,6 +30,7 @@ pub(crate) fn router(engine: Arc) -> Router { .data(engine) .get("/static/:fname", static_assets) .get("/favicon.ico", favicon) + .get("/rss", rss_handler) .get("/:topic", topic_handler) .get("/:topic/ext/:fname", topic_assets) .get("/:topic/posts/:post", post_handler) @@ -56,6 +57,15 @@ async fn index_handler(req: Request) -> Result> { topic_posts(engine.clone(), "main".to_owned()).await } +/// Handler for "/rss" +async fn rss_handler(req: Request) -> Result> { + let engine = req.data::>().unwrap(); + info!("Handling request to '/rss'"); + // TODO: call a rss function on Engine + + Ok(Response::new(Body::from("TEMPORARY"))) +} + /// Handler for "/:topic" async fn topic_handler(req: Request) -> Result> { let engine = req.data::>().unwrap();