implement atom syndication
This commit is contained in:
parent
bc5ac494c6
commit
ab52991784
|
@ -94,6 +94,19 @@ dependencies = [
|
|||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -437,6 +450,72 @@ dependencies = [
|
|||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -498,6 +577,15 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -972,6 +1060,12 @@ dependencies = [
|
|||
"cxx-build",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -1377,6 +1471,12 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -1749,6 +1849,16 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -2179,6 +2289,7 @@ name = "site"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"atom_syndication",
|
||||
"chrono",
|
||||
"chrono-humanize",
|
||||
"listenbrainz",
|
||||
|
@ -2274,6 +2385,12 @@ version = "1.1.0"
|
|||
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"
|
||||
|
|
|
@ -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"
|
||||
|
|
9
TODO.md
9
TODO.md
|
@ -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
|
||||
|
|
16
src/error.rs
16
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)
|
||||
}
|
||||
}
|
||||
|
|
16
src/main.rs
16
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()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod article;
|
||||
mod note;
|
||||
pub mod syndication;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 199 B |
|
@ -166,6 +166,14 @@ footer {
|
|||
background-color: #0000;
|
||||
}
|
||||
|
||||
.small-badge,
|
||||
.small-badge * {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
/* homepage css */
|
||||
|
||||
#title {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue