diff --git a/crates/app/src/public/html/journals/app.lisp b/crates/app/src/public/html/journals/app.lisp index 267541a..4a3ccbd 100644 --- a/crates/app/src/public/html/journals/app.lisp +++ b/crates/app/src/public/html/journals/app.lisp @@ -272,7 +272,34 @@ ("class" "flex flex-col gap-2 card") (text "{{ note.content|markdown|safe }}")) - (span (text "Last updated: ") (span ("class" "date") (text "{{ note.edited }}"))) + (div + ("class" "flex w-full justify-between gap-2") + (span (text "Last updated: ") (span ("class" "date") (text "{{ note.edited }}"))) + (text "{% if user and user.id == owner.id -%}") + (button + ("class" "small") + ("onclick" "{% if journal.privacy == \"Public\" -%} + trigger('atto::copy_text', ['{{ config.host }}/@{{ owner.username }}/{{ journal.title }}/{{ note.title }}']) + {%- else -%} + prompt_make_public(); + trigger('atto::copy_text', ['{{ config.host }}/@{{ owner.username }}/{{ journal.title }}/{{ note.title }}']) + {%- endif %}") + (icon (text "share")) + (str (text "general:label.share"))) + + (script + (text "globalThis.prompt_make_public = async () => { + if ( + !(await trigger(\"atto::confirm\", [ + \"Would you like to make this journal public? This is required for others to view this note.\", + ])) + ) { + return; + } + + change_journal_privacy({ target: { selectedOptions: [{ value: \"Public\" }] }, preventDefault: () => {} }); + }")) + (text "{%- endif %}")) (text "{%- endif %}") (text "{%- endif %}"))) (style @@ -431,8 +458,8 @@ globalThis.change_journal_privacy = async (e) => { e.preventDefault(); - const selected = event.target.selectedOptions[0]; - fetch(\"/api/v1/journals/{{ selected_journal }}/privacy\", { + const selected = e.target.selectedOptions[0]; + fetch(\"/api/v1/journals/{% if journal -%} {{ journal.id }} {%- else -%} {{ selected_journal }} {%- endif %}/privacy\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", diff --git a/crates/app/src/routes/api/v1/journals.rs b/crates/app/src/routes/api/v1/journals.rs index 97f8c9b..0cf3617 100644 --- a/crates/app/src/routes/api/v1/journals.rs +++ b/crates/app/src/routes/api/v1/journals.rs @@ -9,11 +9,14 @@ use crate::{ routes::api::v1::{UpdateJournalPrivacy, CreateJournal, UpdateJournalTitle}, State, }; -use tetratto_core::model::{ - journals::{Journal, JournalPrivacyPermission}, - oauth, - permissions::FinePermission, - ApiReturn, Error, +use tetratto_core::{ + database::NAME_REGEX, + model::{ + journals::{Journal, JournalPrivacyPermission}, + oauth, + permissions::FinePermission, + ApiReturn, Error, + }, }; pub async fn get_request( @@ -101,6 +104,16 @@ pub async fn update_title_request( props.title = props.title.replace(" ", "_"); + // check name + let regex = regex::RegexBuilder::new(NAME_REGEX) + .multi_line(true) + .build() + .unwrap(); + + if regex.captures(&props.title).is_some() { + return Json(Error::MiscError("This title contains invalid characters".to_string()).into()); + } + // make sure this title isn't already in use if data .get_journal_by_owner_title(user.id, &props.title) diff --git a/crates/app/src/routes/api/v1/notes.rs b/crates/app/src/routes/api/v1/notes.rs index 45c4a74..41ab1f9 100644 --- a/crates/app/src/routes/api/v1/notes.rs +++ b/crates/app/src/routes/api/v1/notes.rs @@ -10,12 +10,15 @@ use crate::{ routes::api::v1::{CreateNote, RenderMarkdown, UpdateNoteContent, UpdateNoteTitle}, State, }; -use tetratto_core::model::{ - journals::{JournalPrivacyPermission, Note}, - oauth, - permissions::FinePermission, - uploads::CustomEmoji, - ApiReturn, Error, +use tetratto_core::{ + database::NAME_REGEX, + model::{ + journals::{JournalPrivacyPermission, Note}, + oauth, + permissions::FinePermission, + uploads::CustomEmoji, + ApiReturn, Error, + }, }; pub async fn get_request( @@ -137,6 +140,16 @@ pub async fn update_title_request( props.title = props.title.replace(" ", "_"); + // check name + let regex = regex::RegexBuilder::new(NAME_REGEX) + .multi_line(true) + .build() + .unwrap(); + + if regex.captures(&props.title).is_some() { + return Json(Error::MiscError("This title contains invalid characters".to_string()).into()); + } + // make sure this title isn't already in use if data .get_note_by_journal_title(note.journal, &props.title) diff --git a/crates/core/src/database/journals.rs b/crates/core/src/database/journals.rs index 4602b6b..5979347 100644 --- a/crates/core/src/database/journals.rs +++ b/crates/core/src/database/journals.rs @@ -1,9 +1,10 @@ use oiseau::{cache::Cache, query_row}; use crate::{ + database::common::NAME_REGEX, model::{ auth::User, - permissions::FinePermission, journals::{Journal, JournalPrivacyPermission}, + permissions::FinePermission, Error, Result, }, }; @@ -85,6 +86,18 @@ impl DataManager { data.title = data.title.replace(" ", "_"); + // check name + let regex = regex::RegexBuilder::new(NAME_REGEX) + .multi_line(true) + .build() + .unwrap(); + + if regex.captures(&data.title).is_some() { + return Err(Error::MiscError( + "This title contains invalid characters".to_string(), + )); + } + // make sure this title isn't already in use if self .get_journal_by_owner_title(data.owner, &data.title) diff --git a/crates/core/src/database/mod.rs b/crates/core/src/database/mod.rs index e56bc93..a00fde9 100644 --- a/crates/core/src/database/mod.rs +++ b/crates/core/src/database/mod.rs @@ -30,3 +30,4 @@ mod userblocks; mod userfollows; pub use drivers::DataManager; +pub use common::NAME_REGEX; diff --git a/crates/core/src/database/notes.rs b/crates/core/src/database/notes.rs index d46394b..377fa6e 100644 --- a/crates/core/src/database/notes.rs +++ b/crates/core/src/database/notes.rs @@ -1,4 +1,5 @@ use oiseau::cache::Cache; +use crate::database::common::NAME_REGEX; use crate::model::{auth::User, journals::Note, permissions::FinePermission, Error, Result}; use crate::{auto_method, DataManager}; use oiseau::{execute, get, params, query_row, query_rows, PostgresRow}; @@ -84,6 +85,18 @@ impl DataManager { data.title = data.title.replace(" ", "_"); + // check name + let regex = regex::RegexBuilder::new(NAME_REGEX) + .multi_line(true) + .build() + .unwrap(); + + if regex.captures(&data.title).is_some() { + return Err(Error::MiscError( + "This title contains invalid characters".to_string(), + )); + } + // make sure this title isn't already in use if self .get_note_by_journal_title(data.journal, &data.title)