WIP basic news thread rendering

This commit is contained in:
Bill Thiede 2024-07-21 12:50:21 -07:00
parent 65fcbd4b77
commit 6fae9cd018
3 changed files with 72 additions and 5 deletions

6
server/sql/thread.sql Normal file
View File

@ -0,0 +1,6 @@
SELECT
*
FROM
post
WHERE
uid = $1

View File

@ -243,15 +243,21 @@ impl QueryRoot {
} }
async fn thread<'ctx>(&self, ctx: &Context<'ctx>, thread_id: String) -> Result<Thread, Error> { async fn thread<'ctx>(&self, ctx: &Context<'ctx>, thread_id: String) -> Result<Thread, Error> {
let nm = ctx.data_unchecked::<Notmuch>(); let nm = ctx.data_unchecked::<Notmuch>();
let pool = ctx.data_unchecked::<PgPool>();
let debug_content_tree = ctx let debug_content_tree = ctx
.look_ahead() .look_ahead()
.field("messages") .field("messages")
.field("body") .field("body")
.field("contentTree") .field("contentTree")
.exists(); .exists();
// TODO: look at thread_id and conditionally load newsreader
if newsreader::is_newsreader_thread(&thread_id) {
Ok(newsreader::thread(pool, thread_id).await?)
} else {
Ok(nm::thread(nm, thread_id, debug_content_tree).await?) Ok(nm::thread(nm, thread_id, debug_content_tree).await?)
} }
} }
}
pub struct Mutation; pub struct Mutation;
#[Object] #[Object]

View File

@ -5,16 +5,21 @@ use log::info;
use sqlx::postgres::PgPool; use sqlx::postgres::PgPool;
const TAG_PREFIX: &'static str = "News/"; const TAG_PREFIX: &'static str = "News/";
const THREAD_PREFIX: &'static str = "news:";
use crate::{ use crate::{
error, error::ServerError,
graphql::{Tag, ThreadSummary}, graphql::{Body, Email, Html, Message, Tag, Thread, ThreadSummary},
}; };
pub fn is_newsreader_search(query: &str) -> bool { pub fn is_newsreader_search(query: &str) -> bool {
query.contains(TAG_PREFIX) query.contains(TAG_PREFIX)
} }
pub fn is_newsreader_thread(query: &str) -> bool {
query.starts_with(THREAD_PREFIX)
}
pub async fn search( pub async fn search(
pool: &PgPool, pool: &PgPool,
after: Option<String>, after: Option<String>,
@ -54,7 +59,7 @@ pub async fn search(
vec!["unread".to_string(), site.clone()] vec!["unread".to_string(), site.clone()]
}; };
ThreadSummary { ThreadSummary {
thread: format!("news:{}", r.uid), thread: format!("{THREAD_PREFIX}{}", r.uid),
timestamp: r timestamp: r
.date .date
.expect("post missing date") .expect("post missing date")
@ -84,7 +89,7 @@ pub async fn search(
.await .await
} }
pub async fn tags(pool: &PgPool, needs_unread: bool) -> Result<Vec<Tag>, error::ServerError> { pub async fn tags(pool: &PgPool, needs_unread: bool) -> Result<Vec<Tag>, ServerError> {
// TODO: write separate query for needs_unread. // TODO: write separate query for needs_unread.
let tags = sqlx::query_file!("sql/tags.sql").fetch_all(pool).await?; let tags = sqlx::query_file!("sql/tags.sql").fetch_all(pool).await?;
let tags = tags let tags = tags
@ -105,3 +110,53 @@ pub async fn tags(pool: &PgPool, needs_unread: bool) -> Result<Vec<Tag>, error::
.collect(); .collect();
Ok(tags) Ok(tags)
} }
pub async fn thread(pool: &PgPool, thread_id: String) -> Result<Thread, ServerError> {
let id = thread_id
.strip_prefix(THREAD_PREFIX)
.expect("news thread doesn't start with '{THREAD_PREFIX}'")
.to_string();
let r = sqlx::query_file!("sql/thread.sql", id)
.fetch_one(pool)
.await?;
let site = r.site.unwrap_or("NO SITE".to_string());
let tags = if r.is_read.unwrap_or(false) {
vec![site.clone()]
} else {
vec!["unread".to_string(), site.clone()]
};
let body = Body::Html(Html {
html: r.summary.unwrap_or("NO SUMMARY".to_string()),
content_tree: "".to_string(),
});
let title = r.title.unwrap_or("NO TITLE".to_string());
let from = Some(Email {
name: Some(site.clone()),
addr: r.link,
});
Ok(Thread {
thread_id,
subject: title.clone(),
messages: vec![Message {
id,
// TODO: join with feed for pretty site name
from,
to: Vec::new(),
cc: Vec::new(),
subject: Some(title),
timestamp: Some(
r.date
.expect("post missing date")
.assume_utc()
.unix_timestamp(),
),
headers: Vec::new(),
body,
path: "".to_string(),
attachments: Vec::new(),
tags,
}],
})
}