add: journal note tags and directories

This commit is contained in:
trisua 2025-06-21 19:44:28 -04:00
parent a37312fecf
commit af6fbdf04e
16 changed files with 722 additions and 78 deletions

View file

@ -3,5 +3,6 @@ CREATE TABLE IF NOT EXISTS journals (
created BIGINT NOT NULL,
owner BIGINT NOT NULL,
title TEXT NOT NULL,
privacy TEXT NOT NULL
privacy TEXT NOT NULL,
dirs TEXT NOT NUll
)

View file

@ -5,5 +5,7 @@ CREATE TABLE IF NOT EXISTS notes (
title TEXT NOT NULL,
journal BIGINT NOT NULL,
content TEXT NOT NULL,
edited BIGINT NOT NULL
edited BIGINT NOT NULL,
dir BIGINT NOT NULL,
tags TEXT NOT NULL
)

View file

@ -20,6 +20,7 @@ impl DataManager {
owner: get!(x->2(i64)) as usize,
title: get!(x->3(String)),
privacy: serde_json::from_str(&get!(x->4(String))).unwrap(),
dirs: serde_json::from_str(&get!(x->5(String))).unwrap(),
}
}
@ -128,13 +129,14 @@ impl DataManager {
let res = execute!(
&conn,
"INSERT INTO journals VALUES ($1, $2, $3, $4, $5)",
"INSERT INTO journals VALUES ($1, $2, $3, $4, $5, $6)",
params![
&(data.id as i64),
&(data.created as i64),
&(data.owner as i64),
&data.title,
&serde_json::to_string(&data.privacy).unwrap(),
&serde_json::to_string(&data.dirs).unwrap(),
]
);
@ -183,4 +185,5 @@ impl DataManager {
auto_method!(update_journal_title(&str)@get_journal_by_id:MANAGE_JOURNALS -> "UPDATE journals SET title = $1 WHERE id = $2" --cache-key-tmpl="atto.journal:{}");
auto_method!(update_journal_privacy(JournalPrivacyPermission)@get_journal_by_id:MANAGE_JOURNALS -> "UPDATE journals SET privacy = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.journal:{}");
auto_method!(update_journal_dirs(Vec<(usize, usize, String)>)@get_journal_by_id:MANAGE_JOURNALS -> "UPDATE journals SET dirs = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.journal:{}");
}

View file

@ -15,6 +15,8 @@ impl DataManager {
journal: get!(x->4(i64)) as usize,
content: get!(x->5(String)),
edited: get!(x->6(i64)) as usize,
dir: get!(x->7(i64)) as usize,
tags: serde_json::from_str(&get!(x->8(String))).unwrap(),
}
}
@ -65,6 +67,31 @@ impl DataManager {
Ok(res.unwrap())
}
/// Get all notes by journal with the given tag.
///
/// # Arguments
/// * `id` - the ID of the journal to fetch notes for
/// * `tag`
pub async fn get_notes_by_journal_tag(&self, id: usize, tag: &str) -> Result<Vec<Note>> {
let conn = match self.0.connect().await {
Ok(c) => c,
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
};
let res = query_rows!(
&conn,
"SELECT * FROM notes WHERE journal = $1 AND tags::jsonb ? $2 ORDER BY edited DESC",
params![&(id as i64), tag],
|x| { Self::get_note_from_row(x) }
);
if res.is_err() {
return Err(Error::GeneralNotFound("note".to_string()));
}
Ok(res.unwrap())
}
const MAXIMUM_FREE_NOTES_PER_JOURNAL: usize = 10;
/// Create a new note in the database.
@ -137,7 +164,7 @@ impl DataManager {
let res = execute!(
&conn,
"INSERT INTO notes VALUES ($1, $2, $3, $4, $5, $6, $7)",
"INSERT INTO notes VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
params![
&(data.id as i64),
&(data.created as i64),
@ -146,6 +173,8 @@ impl DataManager {
&(data.journal as i64),
&data.content,
&(data.edited as i64),
&(data.dir as i64),
&serde_json::to_string(&data.tags).unwrap(),
]
);
@ -181,7 +210,45 @@ impl DataManager {
Ok(())
}
/// Delete all notes by dir ID.
///
/// # Arguments
/// * `journal`
/// * `dir`
pub async fn delete_notes_by_journal_dir(
&self,
journal: usize,
dir: usize,
user: &User,
) -> Result<()> {
let journal = self.get_journal_by_id(journal).await?;
if journal.owner != user.id && !user.permissions.check(FinePermission::MANAGE_NOTES) {
return Err(Error::NotAllowed);
}
// ...
let conn = match self.0.connect().await {
Ok(c) => c,
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
};
let res = execute!(
&conn,
"DELETE FROM notes WHERE dir = $1 AND journal = $2 ORDER BY edited DESC",
&[&(dir as i64), &(journal.id as i64)]
);
if let Err(e) = res {
return Err(Error::DatabaseError(e.to_string()));
}
Ok(())
}
auto_method!(update_note_title(&str)@get_note_by_id:MANAGE_NOTES -> "UPDATE notes SET title = $1 WHERE id = $2" --cache-key-tmpl="atto.note:{}");
auto_method!(update_note_content(&str)@get_note_by_id:MANAGE_NOTES -> "UPDATE notes SET content = $1 WHERE id = $2" --cache-key-tmpl="atto.note:{}");
auto_method!(update_note_dir(i64)@get_note_by_id:MANAGE_NOTES -> "UPDATE notes SET dir = $1 WHERE id = $2" --cache-key-tmpl="atto.note:{}");
auto_method!(update_note_tags(Vec<String>)@get_note_by_id:MANAGE_NOTES -> "UPDATE notes SET tags = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.note:{}");
auto_method!(update_note_edited(i64) -> "UPDATE notes SET edited = $1 WHERE id = $2" --cache-key-tmpl="atto.note:{}");
}

View file

@ -22,6 +22,10 @@ pub struct Journal {
pub owner: usize,
pub title: String,
pub privacy: JournalPrivacyPermission,
/// An array of directories notes can be placed in.
///
/// `Vec<(id, parent id, name)>`
pub dirs: Vec<(usize, usize, String)>,
}
impl Journal {
@ -33,6 +37,7 @@ impl Journal {
owner,
title,
privacy: JournalPrivacyPermission::default(),
dirs: Vec::new(),
}
}
}
@ -49,6 +54,12 @@ pub struct Note {
pub journal: usize,
pub content: String,
pub edited: usize,
/// The "id" of the directoryy this note is in.
///
/// Directories are held in the journal in the `dirs` column.
pub dir: usize,
/// An array of tags associated with the note.
pub tags: Vec<String>,
}
impl Note {
@ -64,6 +75,8 @@ impl Note {
journal,
content,
edited: created,
dir: 0,
tags: Vec::new(),
}
}
}