diff options
author | cel 🌸 <cel@blos.sm> | 2023-06-22 21:37:10 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-06-22 21:37:10 +0100 |
commit | ab529917847641190f21129804bbda1784b4f998 (patch) | |
tree | dfdd39286d330dd62339ade0499471b70187ae04 | |
parent | bc5ac494c6162743810b9aeb1cda4f22d94a486a (diff) | |
download | blossom-ab529917847641190f21129804bbda1784b4f998.tar.gz blossom-ab529917847641190f21129804bbda1784b4f998.tar.bz2 blossom-ab529917847641190f21129804bbda1784b4f998.zip |
implement atom syndication
-rw-r--r-- | Cargo.lock | 117 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | TODO.md | 9 | ||||
-rw-r--r-- | src/error.rs | 16 | ||||
-rw-r--r-- | src/main.rs | 16 | ||||
-rw-r--r-- | src/posts/mod.rs | 1 | ||||
-rw-r--r-- | src/posts/syndication.rs | 96 | ||||
-rw-r--r-- | static/atombadge.png | bin | 0 -> 4767 bytes | |||
-rw-r--r-- | static/atomfeed.gif | bin | 0 -> 199 bytes | |||
-rw-r--r-- | static/style.css | 8 | ||||
-rw-r--r-- | templates/base.html.tera | 3 | ||||
-rw-r--r-- | templates/contact.html.tera | 3 | ||||
-rw-r--r-- | templates/home.html.tera | 4 | ||||
-rw-r--r-- | templates/latestposts.html.tera | 2 |
14 files changed, 268 insertions, 8 deletions
@@ -95,6 +95,19 @@ dependencies = [ ] [[package]] +name = "atom_syndication" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca96cb38e3d8236f1573a84bbc55e130bd1ae07df770e36d0cf221ea7a50e36c" +dependencies = [ + "chrono", + "derive_builder", + "diligent-date-parser", + "never", + "quick-xml", +] + +[[package]] name = "atomic" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -438,6 +451,72 @@ dependencies = [ ] [[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.107", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.107", +] + +[[package]] name = "derive_deref" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -499,6 +578,15 @@ dependencies = [ ] [[package]] +name = "diligent-date-parser" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6cf7fe294274a222363f84bcb63cdea762979a0443b4cf1f4f8fd17c86b1182" +dependencies = [ + "chrono", +] + +[[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -973,6 +1061,12 @@ dependencies = [ ] [[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] name = "idna" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1378,6 +1472,12 @@ dependencies = [ ] [[package]] +name = "never" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" + +[[package]] name = "normpath" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1750,6 +1850,16 @@ dependencies = [ ] [[package]] +name = "quick-xml" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "encoding_rs", + "memchr", +] + +[[package]] name = "quote" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2179,6 +2289,7 @@ name = "site" version = "0.1.0" dependencies = [ "async-trait", + "atom_syndication", "chrono", "chrono-humanize", "listenbrainz", @@ -2275,6 +2386,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] name = "subtle" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -23,3 +23,4 @@ markdown = "1.0.0-alpha.10" async-trait = "0.1.68" toml = "0.7.4" tokio-stream = { version = "0.1.14", features = ["fs"] } +atom_syndication = "0.12.1" @@ -1,8 +1,17 @@ +# TODO: + [x] make sure posts are organised in date order +[x] atom feed [x] tags [ ] multiple tag UI +[ ] more badges +[ ] site translations [ ] comments [ ] clean up spaghetti +[ ] brush font PLZ +[ ] deploy database yum +[ ] visitor counter +[ ] guestbook badges to steal: [x] keith diff --git a/src/error.rs b/src/error.rs index eb6f6e6..42c01b1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,5 @@ +use std::string::FromUtf8Error; + use rocket::{http::Status, Responder}; #[derive(Responder, Debug)] @@ -8,6 +10,8 @@ pub enum BlossomError { Chrono(Status, #[response(ignore)] chrono::ParseError), Io(Status, #[response(ignore)] std::io::Error), Deserialization(Status, #[response(ignore)] toml::de::Error), + Syndicator(Status, #[response(ignore)] atom_syndication::Error), + Utf8Conversion(Status, #[response(ignore)] FromUtf8Error), NotFound(Status), NoMetadata(Status), Unimplemented(Status), @@ -48,3 +52,15 @@ impl From<toml::de::Error> for BlossomError { BlossomError::Deserialization(Status::new(500), e) } } + +impl From<atom_syndication::Error> for BlossomError { + fn from(e: atom_syndication::Error) -> Self { + BlossomError::Syndicator(Status::new(500), e) + } +} + +impl From<FromUtf8Error> for BlossomError { + fn from(e: FromUtf8Error) -> Self { + BlossomError::Utf8Conversion(Status::new(500), e) + } +} diff --git a/src/main.rs b/src/main.rs index 40f546d..844f3aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,9 @@ mod skweets; use std::borrow::Cow; use std::collections::HashSet; +use atom_syndication::Feed; use rocket::fs::{relative, FileServer}; -use rocket::http::Status; +use rocket::http::{ContentType, Status}; use rocket::{Request, State}; use rocket_dyn_templates::{context, Template}; @@ -87,6 +88,17 @@ async fn blog(filter: Vec<String>) -> Result<Template> { )) } +#[get("/feed")] +async fn feed() -> Result<(Status, (ContentType, String))> { + let posts = posts::get_blogposts().await?; + let feed = posts::syndication::atom(posts).await; + let feed: String = String::from_utf8(feed.write_to(Vec::new())?)?; + Ok(( + Status::new(200), + (ContentType::new("application", "atom+xml"), feed), + )) +} + #[get("/contact")] async fn contact() -> Template { Template::render("contact", context! {}) @@ -130,7 +142,7 @@ async fn main() -> std::result::Result<(), rocket::Error> { .attach(Template::custom(|engines| { engines.tera.autoescape_on(vec![]); })) - .mount("/", routes![home, contact, blog, blogpost, plants]) + .mount("/", routes![home, contact, blog, blogpost, feed, plants]) .register("/", catchers![catcher]) .mount("/", FileServer::from(relative!("static"))) .launch() diff --git a/src/posts/mod.rs b/src/posts/mod.rs index 2dc5c4b..7f8e6c4 100644 --- a/src/posts/mod.rs +++ b/src/posts/mod.rs @@ -1,5 +1,6 @@ mod article; mod note; +pub mod syndication; use std::collections::HashSet; diff --git a/src/posts/syndication.rs b/src/posts/syndication.rs new file mode 100644 index 0000000..f6f0b17 --- /dev/null +++ b/src/posts/syndication.rs @@ -0,0 +1,96 @@ +use atom_syndication::{Category, Content, Entry, Feed, Generator, Link, Person, Text, TextType}; + +use super::{Article, Post}; + +pub async fn atom(posts: Vec<Post<Article>>) -> Feed { + let me = Person { + name: "cel".into(), + email: Some("cel@blos.sm".into()), + uri: Some("https://blos.sm".into()), + }; + let mut authors = Vec::new(); + authors.push(me); + let link = Link { + href: "https://blos.sm/feed".into(), + rel: "self".into(), + hreflang: Some("en".into()), + mime_type: Some("application/atom+xml".into()), + title: Some("atom feed".into()), + length: None, + }; + let mut links = Vec::new(); + links.push(link); + let mut feed = Feed { + title: Text { + value: "cel's site".into(), + base: None, + lang: Some("en".into()), + r#type: TextType::Text, + }, + id: "https://blos.sm".into(), + updated: posts[0].created_at.into(), + authors: authors.clone(), + categories: Vec::new(), + contributors: authors.clone(), + generator: Some(Generator { + value: "blos.sm".into(), + uri: Some("https://bunny.garden/cel/blos.sm".into()), + version: None, + }), + icon: Some("/icon.png".into()), + links: links.clone(), + logo: Some("/logo.png".into()), + rights: None, + subtitle: None, + entries: Vec::new(), + base: Some("https://blos.sm".into()), + lang: Some("en".into()), + ..Default::default() + }; + for mut post in posts { + post.render().await.unwrap_or_default(); + let mut id = String::from("https://blos.sm/blog/"); + id.push_str(&post.data.name); + let categories = post + .tags + .into_iter() + .map(|tag| Category { + term: tag.clone(), + scheme: None, + label: Some(tag.clone()), + }) + .collect(); + let entry = Entry { + title: Text { + value: post.subject.unwrap_or_default(), + base: None, + lang: Some("en".into()), + r#type: TextType::Text, + }, + id: id.clone(), + updated: if let Some(updated_at) = post.updated_at { + updated_at.into() + } else { + post.created_at.into() + }, + authors: authors.clone(), + categories, + contributors: authors.clone(), + links: links.clone(), + published: Some(post.created_at.into()), + rights: None, + source: None, + summary: None, + content: Some(Content { + base: None, + lang: Some("en".into()), + value: post.render, + src: Some(id), + content_type: Some("html".to_string()), + }), + ..Default::default() + }; + feed.entries.push(entry); + } + feed +} diff --git a/static/atombadge.png b/static/atombadge.png Binary files differnew file mode 100644 index 0000000..db1cabf --- /dev/null +++ b/static/atombadge.png diff --git a/static/atomfeed.gif b/static/atomfeed.gif Binary files differnew file mode 100644 index 0000000..680f096 --- /dev/null +++ b/static/atomfeed.gif diff --git a/static/style.css b/static/style.css index bf3f649..67cd922 100644 --- a/static/style.css +++ b/static/style.css @@ -166,6 +166,14 @@ footer { background-color: #0000; } +.small-badge, +.small-badge * { + padding: 0; + border: 0; + margin: 0; + font-size: 0; +} + /* homepage css */ #title { diff --git a/templates/base.html.tera b/templates/base.html.tera index 8008b27..5ac5757 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -40,7 +40,7 @@ <li><a class="{% block nav_blog %}{% endblock %}" style="font-family: Sligoil" href="/blog">girlblog</a></li> <li><a class="{% block nav_projects %}{% endblock %}" style="font-family: 'DeGerm LoCase';" href="/projects">projetos</a></li> <li><a class="{% block nav_sound %}{% endblock %}" style="font-family: 'kirieji'" href="/sound">音</a></li> - <li><a class="{% block nav_listens %}{% endblock %}" style="font-family: 'Almendra Display'; font-weight: 900;" href="https://listenbrainz.org/celblossom">écoute</a></li> + <li><a class="{% block nav_listens %}{% endblock %}" style="font-family: 'Almendra Display'; font-weight: 900;" href="https://listenbrainz.org/user/celblossom">écoute</a></li> <li><a href="https://bimbo.video/a/cel" style="font-family: 'Mon Hugo In'">video</a></li> <li><a href="https://weirdstar.stream" style="font-family: id_kana018" >🔴ライブ</a></li> <li><a class="{% block nav_pix %}{% endblock %}" style="font-family: Minecraftia" href="/pix">pix</a></li> @@ -70,6 +70,7 @@ </main> <footer class="panel"> + <a class="badge" href="https://blos.sm"><img src="https://blos.sm/badges/cel.png"></a> <a class="badge" href="https://skinnyver.se"><img src="https://skinnyver.se/instance/skinnyversebadge.png"></a> <img class="badge" src="/badges/mothracompat.gif"> <img class="badge" src="/badges/flexbox.png"> diff --git a/templates/contact.html.tera b/templates/contact.html.tera index 1930756..5fd37b0 100644 --- a/templates/contact.html.tera +++ b/templates/contact.html.tera @@ -15,9 +15,8 @@ <div class="content panel h-card" rel="author"> <h1 class="p-name">cel</h1> - <h3>pronouns: <a class="u-url" rel="me" href="https://en.pronouns.page/@celblossom"><span class="p-x-pronoun-nominative">she</span>/<span class="p-x-pronoun-accusative">her</span></a></h3> - <ul> + <li><h3>pronouns: <span class="p-x-pronoun-nominative">she</span>/<span class="p-x-pronoun-accusative">her</span></h3></li> <li>email: <a class="u-email" href="mailto:cel@blos.sm">cel@blos.sm</a> <a href="cel.asc" class="u-key" rel="pgpkey">pgp key</a></li> <li>xmpp: <a class="u-impp" href="xmpp:cel@blos.sm?message">cel@blos.sm</a></li> <li>fedi: <a class="u-url" rel="me" href="https://skinnyver.se/cel">cel@skinnyver.se</a></li> diff --git a/templates/home.html.tera b/templates/home.html.tera index cb7fe08..1a2a453 100644 --- a/templates/home.html.tera +++ b/templates/home.html.tera @@ -30,10 +30,10 @@ <div class="panel content"> <h2>hallo i am celeste welcome 2 my site 🌟</h2> - <p>this is where i dump everything</p> + <p>this is where i do the posting</p> <p>i wish u a wonderful day</p> <br> - <img src="https://s3.eu-west-1.wasabisys.com/skinnyverse/f28c467a-0ee1-4d49-a638-08a010fd9927/quinntyping.png"> + <img src="/quinntyping.png"> <p>perpetually under construction</p> <img style="border: 0;" src="/barraconstruction.gif"> </div> diff --git a/templates/latestposts.html.tera b/templates/latestposts.html.tera index 8ab5406..5aab5cb 100644 --- a/templates/latestposts.html.tera +++ b/templates/latestposts.html.tera @@ -1,5 +1,5 @@ <div class="panel" id="posts"> - <h2>latest posts <!--<a class="badge" href="/feed.xml"><img class="badge" src="/rssbadge.png" alt="rss newsfeed"></a>--></h2> + <h2>latest posts <a class="small-badge" href="/feed"><img class="small-badge" src="/atombadge.png" alt="atom newsfeed"></a></h2> <table id="post-list"> {% for blogpost in blogposts %} <tr> |