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)