use crate::storage::Storage;
use heed::types::{SerdeRmp, Str};
use heed::{Database, RoTxn};
use nostr::{Timestamp, Url};
use serde::{Deserialize, Serialize};
use std::error::Error;
use chrono::{DateTime, Utc};
#[derive(Debug, Serialize, Deserialize)]
pub struct LongFormNoteDraft<'a> {
#[serde(borrow)]
pub body: Vec<&'a str>,
pub title: Option<&'a str>,
pub summary: Option<&'a str>,
pub image: Option<Url>,
pub ts_created: u64,
pub ts_first_published: Option<u64>,
pub datetime_created: DateTime<Utc>,
pub datetime_expires: Option<DateTime<Utc>>,
pub datetime_autopublish: Option<DateTime<Utc>>,
pub attachments: Vec<&'a str>,
}
type LongFormDraftsDatabase<'a> =
Database<Str, SerdeRmp<LongFormNoteDraft<'a>>>;
const DB_NAME: &str = "lf_note_drafts";
impl Storage {
fn lf_drafts_db(
&self,
) -> Result<LongFormDraftsDatabase<'_>, Box<dyn Error + Send + Sync>> {
let rtxn = self.get_read_txn()?;
self.env
.open_database(&rtxn, Some(DB_NAME))?
.ok_or(Box::from("Failed to open long-form drafts db"))
}
pub fn create_lf_drafts_db(
&self,
) -> Result<LongFormDraftsDatabase<'_>, Box<dyn Error + Send + Sync>> {
let mut wtxn = self.env.write_txn()?;
let db: LongFormDraftsDatabase =
self.env.create_database(&mut wtxn, Some(DB_NAME))?;
wtxn.commit()?;
Ok(db)
}
pub fn lf_draft_new(
&self,
id: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let db = self.lf_drafts_db()?;
let mut wtxn = self.env.write_txn()?;
let draft = LongFormNoteDraft {
body: Vec::new(),
title: None,
summary: None,
image: None,
ts_created: Timestamp::now().as_secs(),
ts_first_published: None,
datetime_created: Utc::now(),
datetime_expires: None,
datetime_autopublish: None,
attachments: Vec::new(),
};
db.put(&mut wtxn, id, &draft)?;
wtxn.commit()?;
Ok(())
}
pub fn lf_draft_store(
&self,
id: &str,
draft: LongFormNoteDraft,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let db = self.lf_drafts_db()?;
let mut wtxn = self.env.write_txn()?;
db.put(&mut wtxn, id, &draft)?;
wtxn.commit()?;
Ok(())
}
pub fn lf_draft_append_gemtext(
&self,
id: &str,
gemtext: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let db = self.lf_drafts_db()?;
let mut rtxn = self.env.read_txn()?;
let mut draft = self.lf_draft_get(id, &mut rtxn)?;
draft.body.extend(gemtext.lines());
let mut wtxn = self.env.write_txn()?;
db.put(&mut wtxn, id, &draft)?;
wtxn.commit()?;
Ok(())
}
pub fn lf_draft_delete_last(
&self,
id: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let db = self.lf_drafts_db()?;
let mut rtxn = self.env.read_txn()?;
let mut draft = self.lf_draft_get(id, &mut rtxn)?;
if !draft.body.is_empty() {
let len = draft.body.len() - 1;
draft.body.truncate(len);
let mut wtxn = self.env.write_txn()?;
db.put(&mut wtxn, id, &draft)?;
wtxn.commit()?;
}
Ok(())
}
pub fn lf_draft_get_content(
&self,
id: &str,
) -> Result<String, Box<dyn Error + Send + Sync>> {
let rtxn = self.env.read_txn()?;
match self.lf_drafts_db()?.get(&rtxn, id)? {
Some(draft) => {
let content = draft.body.join("\n");
Ok(content)
}
None => Err(Box::from("Cannot get draft")),
}
}
pub fn lf_draft_get<'c>(
&'c self,
id: &str,
rtxn: &'c mut RoTxn,
) -> Result<LongFormNoteDraft<'c>, Box<dyn Error + Send + Sync>> {
self.lf_drafts_db()?
.get(rtxn, id)?
.ok_or(Box::from("Cannot find draft"))
}
}