diff options
| author | Xe Iaso <me@christine.website> | 2022-07-10 20:29:07 +0000 |
|---|---|---|
| committer | Xe Iaso <me@christine.website> | 2022-07-10 20:29:07 +0000 |
| commit | 55bf7e4cb403566d7172ef69b8f2f7393ac8627d (patch) | |
| tree | 7b3682e19c97672245cbb97e6c1d1069e812fd8b /src/handlers/notes.rs | |
| parent | b32f5a25afb7b9901476164663c1b7099dcec7a8 (diff) | |
| download | xesite-55bf7e4cb403566d7172ef69b8f2f7393ac8627d.tar.xz xesite-55bf7e4cb403566d7172ef69b8f2f7393ac8627d.zip | |
basic notes support
Signed-off-by: Xe Iaso <me@christine.website>
Diffstat (limited to 'src/handlers/notes.rs')
| -rw-r--r-- | src/handlers/notes.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/handlers/notes.rs b/src/handlers/notes.rs new file mode 100644 index 0000000..feb2129 --- /dev/null +++ b/src/handlers/notes.rs @@ -0,0 +1,161 @@ +use crate::templates; +use axum::{extract::Path, response::Html, Json}; +use chrono::prelude::*; +use maud::{html, Markup, PreEscaped}; +use rusqlite::params; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Note { + pub id: u64, + pub content: String, + pub content_html: String, + pub created_at: DateTime<Utc>, + pub updated_at: Option<DateTime<Utc>>, + pub deleted_at: Option<DateTime<Utc>>, + pub reply_to: Option<String>, +} + +impl Note { + pub fn to_html(&self) -> Markup { + html! { + article."h-entry" { + time."dt-published" datetime=(self.created_at) { + {(self.detrytemci())} + } + a href={"/notes/" (self.id)} { + "🔗" + } + + @if let Some(reply_to) = &self.reply_to { + p { + "In reply to " + a href=(reply_to) {(reply_to)} + "." + } + } + + div."e-content" { + (PreEscaped(self.content_html.clone())) + } + } + } + } + + pub fn detrytemci(&self) -> String { + self.created_at.format("M%m %d %Y %M:%H").to_string() + } +} + +impl Into<xe_jsonfeed::Item> for Note { + fn into(self) -> xe_jsonfeed::Item { + let url = format!("https://xeiaso.net/note/{}", self.id); + let mut builder = xe_jsonfeed::Item::builder() + .content_html(self.content_html) + .id(url.clone()) + .url(url.clone()) + .date_published(self.created_at.to_rfc3339()) + .author( + xe_jsonfeed::Author::new() + .name("Xe Iaso") + .url("https://xeiaso.net") + .avatar("https://xeiaso.net/static/img/avatar.png"), + ); + + if let Some(updated_at) = self.updated_at { + builder = builder.date_modified(updated_at.to_rfc3339()); + } + + builder.build().unwrap() + } +} + +#[instrument(err)] +pub async fn index() -> super::Result { + let conn = crate::establish_connection()?; + + let mut stmt = conn.prepare("SELECT id, content, content_html, created_at, updated_at, deleted_at, reply_to FROM notes ORDER BY id DESC LIMIT 25")?; + let notes = stmt + .query_map(params![], |row| { + Ok(Note { + id: row.get(0)?, + content: row.get(1)?, + content_html: row.get(2)?, + created_at: row.get(3)?, + updated_at: row.get(4)?, + deleted_at: row.get(5)?, + reply_to: row.get(6)?, + }) + })? + .filter(Result::is_ok) + .map(Result::unwrap) + .collect::<Vec<Note>>(); + + let mut result: Vec<u8> = vec![]; + templates::notesindex_html(&mut result, notes)?; + Ok(Html(result)) +} + +#[instrument(err)] +pub async fn feed() -> super::Result<Json<xe_jsonfeed::Feed>> { + let conn = crate::establish_connection()?; + + let mut stmt = conn.prepare("SELECT id, content, content_html, created_at, updated_at, deleted_at, reply_to FROM notes ORDER BY id DESC LIMIT 25")?; + let notes = stmt + .query_map(params![], |row| { + Ok(Note { + id: row.get(0)?, + content: row.get(1)?, + content_html: row.get(2)?, + created_at: row.get(3)?, + updated_at: row.get(4)?, + deleted_at: row.get(5)?, + reply_to: row.get(6)?, + }) + })? + .filter(Result::is_ok) + .map(Result::unwrap) + .collect::<Vec<Note>>(); + + let mut feed = xe_jsonfeed::Feed::builder() + .author( + xe_jsonfeed::Author::new() + .name("Xe Iaso") + .url("https://xeiaso.net") + .avatar("https://xeiaso.net/static/img/avatar.png"), + ) + .description("Short posts that aren't to the same quality level as mainline blogposts") + .feed_url("https://xeiaso.net/notes.json") + .title("Xe's Notes"); + + for note in notes { + feed = feed.item(note.into()); + } + + Ok(Json(feed.build())) +} + +#[instrument(err)] +pub async fn view(Path(id): Path<u64>) -> super::Result { + let conn = crate::establish_connection()?; + + let mut stmt = conn.prepare( + "SELECT id, content, content_html, created_at, updated_at, deleted_at, reply_to FROM notes WHERE id = ?1" + )?; + + let note = stmt.query_row(params![id], |row| { + Ok(Note { + id: row.get(0)?, + content: row.get(1)?, + content_html: row.get(2)?, + created_at: row.get(3)?, + updated_at: row.get(4)?, + deleted_at: row.get(5)?, + reply_to: row.get(6)?, + }) + })?; + + let mut result: Vec<u8> = vec![]; + templates::notepost_html(&mut result, note)?; + Ok(Html(result)) +} |
