2020-07-13 02:04:38 +00:00
|
|
|
use crate::{post::Post, signalboost::Person};
|
2020-07-12 18:42:09 +00:00
|
|
|
use anyhow::Result;
|
2020-07-14 19:16:52 +00:00
|
|
|
use atom_syndication as atom;
|
2020-07-13 00:11:26 +00:00
|
|
|
use comrak::{markdown_to_html, ComrakOptions};
|
2020-07-12 18:42:09 +00:00
|
|
|
use serde::Deserialize;
|
2020-07-12 23:26:53 +00:00
|
|
|
use std::{fs, path::PathBuf};
|
2020-07-12 18:42:09 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Deserialize)]
|
|
|
|
pub struct Config {
|
2020-07-13 00:11:26 +00:00
|
|
|
#[serde(rename = "clackSet")]
|
2020-07-12 18:42:09 +00:00
|
|
|
clack_set: Vec<String>,
|
2020-07-13 00:11:26 +00:00
|
|
|
signalboost: Vec<Person>,
|
2020-07-12 18:42:09 +00:00
|
|
|
port: u16,
|
2020-07-13 00:11:26 +00:00
|
|
|
#[serde(rename = "resumeFname")]
|
2020-07-12 23:26:53 +00:00
|
|
|
resume_fname: PathBuf,
|
2020-07-12 18:42:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-12 23:30:01 +00:00
|
|
|
pub fn markdown(inp: &str) -> String {
|
|
|
|
let mut options = ComrakOptions::default();
|
|
|
|
|
|
|
|
options.extension.autolink = true;
|
|
|
|
options.extension.table = true;
|
|
|
|
options.extension.description_lists = true;
|
|
|
|
options.extension.superscript = true;
|
|
|
|
options.extension.strikethrough = true;
|
|
|
|
options.extension.footnotes = true;
|
|
|
|
|
|
|
|
options.render.unsafe_ = true;
|
|
|
|
|
|
|
|
markdown_to_html(inp, &options)
|
|
|
|
}
|
|
|
|
|
2020-07-16 14:14:10 +00:00
|
|
|
async fn patrons() -> Result<Option<patreon::Users>> {
|
|
|
|
use patreon::*;
|
|
|
|
let creds: Credentials = envy::prefixed("PATREON_").from_env().unwrap();
|
|
|
|
let cli = Client::new(creds);
|
|
|
|
|
|
|
|
if let Ok(camp) = cli.campaign().await {
|
|
|
|
let id = camp.data[0].id.clone();
|
|
|
|
if let Ok(users) = cli.pledges(id).await {
|
|
|
|
Ok(Some(users))
|
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-14 17:27:52 +00:00
|
|
|
pub const ICON: &'static str = "https://christine.website/static/img/avatar.png";
|
|
|
|
|
2020-07-12 18:42:09 +00:00
|
|
|
pub struct State {
|
|
|
|
pub cfg: Config,
|
|
|
|
pub signalboost: Vec<Person>,
|
2020-07-12 23:26:53 +00:00
|
|
|
pub resume: String,
|
2020-07-13 02:04:38 +00:00
|
|
|
pub blog: Vec<Post>,
|
|
|
|
pub gallery: Vec<Post>,
|
|
|
|
pub talks: Vec<Post>,
|
|
|
|
pub everything: Vec<Post>,
|
2020-07-14 17:27:52 +00:00
|
|
|
pub jf: jsonfeed::Feed,
|
2020-07-14 19:16:52 +00:00
|
|
|
pub rf: rss::Channel,
|
|
|
|
pub af: atom::Feed,
|
2020-07-16 11:30:57 +00:00
|
|
|
pub sitemap: Vec<u8>,
|
2020-07-16 14:14:10 +00:00
|
|
|
pub patrons: Option<patreon::Users>,
|
2020-07-12 18:42:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-16 14:14:10 +00:00
|
|
|
pub async fn init(cfg: PathBuf) -> Result<State> {
|
2020-07-13 00:11:26 +00:00
|
|
|
let cfg: Config = serde_dhall::from_file(cfg).parse()?;
|
|
|
|
let sb = cfg.signalboost.clone();
|
2020-07-12 23:26:53 +00:00
|
|
|
let resume = fs::read_to_string(cfg.resume_fname.clone())?;
|
2020-07-12 23:30:01 +00:00
|
|
|
let resume: String = markdown(&resume);
|
2020-07-13 02:04:38 +00:00
|
|
|
let blog = crate::post::load("blog")?;
|
|
|
|
let gallery = crate::post::load("gallery")?;
|
|
|
|
let talks = crate::post::load("talks")?;
|
|
|
|
let mut everything: Vec<Post> = vec![];
|
|
|
|
|
|
|
|
{
|
|
|
|
let blog = blog.clone();
|
|
|
|
let gallery = gallery.clone();
|
|
|
|
let talks = talks.clone();
|
|
|
|
everything.extend(blog.iter().cloned());
|
|
|
|
everything.extend(gallery.iter().cloned());
|
|
|
|
everything.extend(talks.iter().cloned());
|
|
|
|
};
|
|
|
|
|
|
|
|
everything.sort();
|
|
|
|
everything.reverse();
|
2020-07-12 18:42:09 +00:00
|
|
|
|
2020-07-14 19:16:52 +00:00
|
|
|
let mut ri: Vec<rss::Item> = vec![];
|
|
|
|
let mut ai: Vec<atom::Entry> = vec![];
|
|
|
|
|
2020-07-14 17:27:52 +00:00
|
|
|
let mut jfb = jsonfeed::Feed::builder()
|
|
|
|
.title("Christine Dodrill's Blog")
|
|
|
|
.description("My blog posts and rants about various technology things.")
|
|
|
|
.author(
|
|
|
|
jsonfeed::Author::new()
|
|
|
|
.name("Christine Dodrill")
|
|
|
|
.url("https://christine.website")
|
|
|
|
.avatar(ICON),
|
|
|
|
)
|
|
|
|
.feed_url("https://christine.website/blog.json")
|
|
|
|
.user_comment("This is a JSON feed of my blogposts. For more information read: https://jsonfeed.org/version/1")
|
2020-07-15 02:27:35 +00:00
|
|
|
.home_page_url("https://christine.website")
|
2020-07-14 17:27:52 +00:00
|
|
|
.icon(ICON)
|
|
|
|
.favicon(ICON);
|
|
|
|
|
|
|
|
for post in &everything {
|
|
|
|
let post = post.clone();
|
2020-07-14 19:16:52 +00:00
|
|
|
jfb = jfb.item(post.clone().into());
|
|
|
|
ri.push(post.clone().into());
|
|
|
|
ai.push(post.clone().into());
|
2020-07-14 17:27:52 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 19:16:52 +00:00
|
|
|
let af = {
|
|
|
|
let mut af = atom::FeedBuilder::default();
|
|
|
|
af.title("Christine Dodrill's Blog");
|
|
|
|
af.id("https://christine.website/blog");
|
|
|
|
af.generator({
|
|
|
|
let mut generator = atom::Generator::default();
|
|
|
|
generator.set_value(env!("CARGO_PKG_NAME"));
|
|
|
|
generator.set_version(env!("CARGO_PKG_VERSION").to_string());
|
|
|
|
generator.set_uri("https://github.com/Xe/site".to_string());
|
|
|
|
|
|
|
|
generator
|
|
|
|
});
|
|
|
|
af.entries(ai);
|
|
|
|
|
|
|
|
af.build().unwrap()
|
|
|
|
};
|
|
|
|
|
|
|
|
let rf = {
|
|
|
|
let mut rf = rss::ChannelBuilder::default();
|
|
|
|
rf.title("Christine Dodrill's Blog");
|
|
|
|
rf.link("https://christine.website/blog");
|
|
|
|
rf.generator(crate::APPLICATION_NAME.to_string());
|
|
|
|
rf.items(ri);
|
|
|
|
|
|
|
|
rf.build().unwrap()
|
|
|
|
};
|
|
|
|
|
2020-07-16 11:30:57 +00:00
|
|
|
let mut sm: Vec<u8> = vec![];
|
|
|
|
let smw = sitemap::writer::SiteMapWriter::new(&mut sm);
|
|
|
|
let mut urlwriter = smw.start_urlset()?;
|
|
|
|
for url in &[
|
|
|
|
"https://christine.website/resume",
|
|
|
|
"https://christine.website/contact",
|
|
|
|
"https://christine.website/",
|
|
|
|
"https://christine.website/blog",
|
|
|
|
"https://christine.website/signalboost",
|
|
|
|
] {
|
|
|
|
urlwriter.url(*url)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for post in &everything {
|
|
|
|
urlwriter.url(format!("https://christine.website/{}", post.link))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
urlwriter.end()?;
|
|
|
|
|
2020-07-12 18:42:09 +00:00
|
|
|
Ok(State {
|
|
|
|
cfg: cfg,
|
|
|
|
signalboost: sb,
|
2020-07-12 23:26:53 +00:00
|
|
|
resume: resume,
|
2020-07-13 02:04:38 +00:00
|
|
|
blog: blog,
|
|
|
|
gallery: gallery,
|
|
|
|
talks: talks,
|
|
|
|
everything: everything,
|
2020-07-14 17:27:52 +00:00
|
|
|
jf: jfb.build(),
|
2020-07-14 19:16:52 +00:00
|
|
|
af: af,
|
|
|
|
rf: rf,
|
2020-07-16 11:30:57 +00:00
|
|
|
sitemap: sm,
|
2020-07-16 14:14:10 +00:00
|
|
|
patrons: patrons().await?,
|
2020-07-12 18:42:09 +00:00
|
|
|
})
|
|
|
|
}
|
2020-07-13 02:04:38 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use anyhow::Result;
|
2020-07-16 14:14:10 +00:00
|
|
|
#[tokio::test]
|
|
|
|
async fn init() -> Result<()> {
|
|
|
|
super::init("./config.dhall".into()).await?;
|
2020-07-13 02:04:38 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|