feat: mentions in lives_with and text_body fields
Some checks failed
/ integration-test--firefox (push) Failing after 3m7s
Some checks failed
/ integration-test--firefox (push) Failing after 3m7s
This commit is contained in:
parent
fd5f1899c1
commit
d42adbe274
10 changed files with 369 additions and 200 deletions
|
|
@ -1,15 +1,12 @@
|
|||
use chrono::NaiveDate;
|
||||
use maud::{Markup, PreEscaped, html};
|
||||
use regex::Regex;
|
||||
use maud::{Markup, html};
|
||||
use serde_json::json;
|
||||
use sqlx::sqlite::{SqlitePool, SqliteRow};
|
||||
use sqlx::{FromRow, Row};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use super::contact::MentionTrie;
|
||||
use crate::AppError;
|
||||
use crate::db::DbId;
|
||||
use crate::switchboard::{MentionHost, MentionHostType};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JournalEntry {
|
||||
|
|
@ -18,84 +15,19 @@ pub struct JournalEntry {
|
|||
pub date: NaiveDate,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, FromRow)]
|
||||
pub struct Mention {
|
||||
pub entry_id: DbId,
|
||||
pub url: String,
|
||||
pub input_text: String,
|
||||
pub byte_range_start: u32,
|
||||
pub byte_range_end: u32,
|
||||
impl<'a> Into<MentionHost<'a>> for &'a JournalEntry {
|
||||
fn into(self) -> MentionHost<'a> {
|
||||
MentionHost {
|
||||
entity_id: self.id,
|
||||
entity_type: MentionHostType::JournalEntry as DbId,
|
||||
input: &self.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JournalEntry {
|
||||
pub fn extract_mentions(&self, trie: &MentionTrie) -> HashSet<Mention> {
|
||||
let name_re = Regex::new(r"\[\[(.+?)\]\]").unwrap();
|
||||
name_re
|
||||
.captures_iter(&self.value)
|
||||
.map(|caps| {
|
||||
let range = caps.get_match().range();
|
||||
trie.get(&caps[1]).map(|url| Mention {
|
||||
entry_id: self.id,
|
||||
url: url.to_string(),
|
||||
input_text: caps[1].to_string(),
|
||||
byte_range_start: u32::try_from(range.start).unwrap(),
|
||||
byte_range_end: u32::try_from(range.end).unwrap(),
|
||||
})
|
||||
})
|
||||
.filter(|o| o.is_some())
|
||||
.map(|o| o.unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn insert_mentions(
|
||||
&self,
|
||||
trie: Arc<RwLock<MentionTrie>>,
|
||||
pool: &SqlitePool,
|
||||
) -> Result<HashSet<Mention>, AppError> {
|
||||
let mentions = {
|
||||
let trie = trie.read().unwrap();
|
||||
self.extract_mentions(&trie)
|
||||
};
|
||||
|
||||
for mention in &mentions {
|
||||
sqlx::query!(
|
||||
"insert into journal_mentions(
|
||||
entry_id, url, input_text,
|
||||
byte_range_start, byte_range_end
|
||||
) values ($1, $2, $3, $4, $5)",
|
||||
mention.entry_id,
|
||||
mention.url,
|
||||
mention.input_text,
|
||||
mention.byte_range_start,
|
||||
mention.byte_range_end
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(mentions)
|
||||
}
|
||||
|
||||
pub async fn to_html(&self, pool: &SqlitePool) -> Result<Markup, AppError> {
|
||||
// important to sort desc so that changing contents early in the string
|
||||
// doesn't break inserting mentions at byte offsets further in
|
||||
let mentions: Vec<Mention> = sqlx::query_as(
|
||||
"select * from journal_mentions
|
||||
where entry_id = $1 order by byte_range_start desc",
|
||||
)
|
||||
.bind(self.id)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
let mut value = self.value.clone();
|
||||
for mention in mentions {
|
||||
tracing::debug!("url ({})", mention.url);
|
||||
value.replace_range(
|
||||
(mention.byte_range_start as usize)..(mention.byte_range_end as usize),
|
||||
&format!("[{}]({})", mention.input_text, mention.url),
|
||||
);
|
||||
}
|
||||
|
||||
let rendered = Into::<MentionHost>::into(self).format_pool(pool).await?;
|
||||
let entry_url = format!("/journal_entry/{}", self.id);
|
||||
let date = self.date.to_string();
|
||||
|
||||
|
|
@ -103,7 +35,7 @@ impl JournalEntry {
|
|||
.entry {
|
||||
.view ":class"="{ hide: edit }" {
|
||||
.date { (date) }
|
||||
.content { (PreEscaped(markdown::to_html(&value))) }
|
||||
.content { (rendered) }
|
||||
}
|
||||
form .edit ":class"="{ hide: !edit }" x-data=(json!({ "date": date, "initial_date": date, "value": self.value, "initial_value": self.value })) {
|
||||
input name="date" x-model="date";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue