diff --git a/crates/app/src/public/css/style.css b/crates/app/src/public/css/style.css index 0603ee1..f592c77 100644 --- a/crates/app/src/public/css/style.css +++ b/crates/app/src/public/css/style.css @@ -1250,32 +1250,3 @@ details.accordion .inner { .CodeMirror-focused .CodeMirror-placeholder { opacity: 50%; } - -.CodeMirror-gutters { - border-color: var(--color-super-lowered) !important; - background-color: var(--color-lowered) !important; -} - -.CodeMirror-hints { - background: var(--color-raised) !important; - box-shadow: var(--shadow-x-offset) var(--shadow-y-offset) var(--shadow-size) - var(--color-shadow); - border-radius: var(--radius) !important; - padding: var(--pad-1) !important; - border-color: var(--color-super-lowered) !important; -} - -.CodeMirror-hints li { - color: var(--color-text-raised) !important; - border-radius: var(--radius) !important; - transition: - background 0.15s, - color 0.15s; - font-size: 10px; - padding: calc(var(--pad-1) / 2) var(--pad-2); -} - -.CodeMirror-hints li.CodeMirror-hint-active { - background-color: var(--color-primary) !important; - color: var(--color-text-primary) !important; -} diff --git a/crates/app/src/public/html/components.lisp b/crates/app/src/public/html/components.lisp index 2726b26..75a24ef 100644 --- a/crates/app/src/public/html/components.lisp +++ b/crates/app/src/public/html/components.lisp @@ -1928,7 +1928,7 @@ (text "{%- endif %}") ; note listings - (text "{% for note in notes %} {% if not view_mode or note.title != \"journal.css\" -%}") + (text "{% for note in notes %}") (div ("class" "flex flex-row gap-1") (a @@ -1958,6 +1958,6 @@ (icon (text "trash")) (str (text "general:action.delete"))))) (text "{%- endif %}")) - (text "{%- endif %} {% endfor %}")) + (text "{% endfor %}")) (text "{%- endif %}") (text "{%- endmacro %}") diff --git a/crates/app/src/public/html/journals/app.lisp b/crates/app/src/public/html/journals/app.lisp index 012909d..267541a 100644 --- a/crates/app/src/public/html/journals/app.lisp +++ b/crates/app/src/public/html/journals/app.lisp @@ -2,27 +2,6 @@ (text "{% if journal -%}") (title (text "{{ journal.title }}")) (text "{% else %}") (title (text "Journals - {{ config.name }}")) (text "{%- endif %}") (link ("rel" "stylesheet") ("data-turbo-temporary" "true") ("href" "/css/chats.css?v=tetratto-{{ random_cache_breaker }}")) -(style - (text "html, body { - overflow: hidden auto !important; - } - - .sidebar { - position: sticky; - top: 42px; - } - - @media screen and (max-width: 900px) { - .sidebar { - position: absolute; - top: unset; - } - - body.sidebars_shown { - overflow: hidden !important; - } - }")) - (text "{% if view_mode and journal and is_editor -%} {% if note -%}") ; redirect to note (meta ("http-equiv" "refresh") ("content" "0; url=/@{{ user.username }}/{{ journal.title }}/{{ note.title }}")) @@ -30,11 +9,6 @@ ; redirect to journal homepage (meta ("http-equiv" "refresh") ("content" "0; url=/@{{ user.username }}/{{ journal.title }}")) (text "{%- endif %} {%- endif %}") - -(text "{% if view_mode and journal -%}") -; add journal css -(link ("rel" "stylesheet") ("data-turbo-temporary" "true") ("href" "/api/v1/journals/{{ journal.id }}/journal.css?v=tetratto-{{ random_cache_breaker }}")) -(text "{%- endif %}") (text "{% endblock %} {% block body %} {{ macros::nav(selected=\"journals\") }}") (text "{% if not view_mode -%}") (nav @@ -89,19 +63,17 @@ ("href" "/api/v1/auth/user/find/{{ journal.owner }}") (text "{{ components::avatar(username=journal.owner, selector_type=\"id\", size=\"18px\") }}")) - (text "{% if (view_mode and owner) or not view_mode -%}") (a ("class" "flush") - ("href" "{% if view_mode -%} /@{{ owner.username }}/{{ journal.title }} {%- else -%} /journals/{{ journal.id }}/0 {%- endif %}") + ("href" "{% if view_mode -%} /@{{ owner.username }}/{{ journal.title }}/index {%- else -%} /journals/{{ journal.id }}/0 {%- endif %}") (b (text "{{ journal.title }}"))) - (text "{%- endif %}") (text "{% if note -%}") (span (text "/")) (b (text "{{ note.title }}")) (text "{%- endif %}")) - (text "{% if user and user.id == journal.owner and (not note or note.title != \"journal.css\") -%}") + (text "{% if user and user.id == journal.owner -%}") (div ("class" "pillmenu") (a @@ -111,7 +83,7 @@ (icon (text "pencil"))) (a ("class" "{% if view_mode -%}active{%- endif %}") - ("href" "/@{{ user.username }}/{{ journal.title }}{% if note -%} /{{ note.title }} {%- endif %}") + ("href" "/@{{ user.username }}/{{ journal.title }}/{% if note -%} {{ note.title }} {%- else -%} index {%- endif %}") (icon (text "eye")))) (text "{%- endif %}")) (text "{%- endif %}") @@ -124,7 +96,6 @@ ("class" "card w-full flex flex-col gap-2") (h3 (str (text "journals:label.welcome"))) (span (str (text "journals:label.select_a_journal"))) - (span ("class" "mobile") (str (text "journals:label.mobile_click_my_journals"))) (button ("onclick" "create_journal()") (icon (text "plus")) @@ -209,36 +180,10 @@ ; import codemirror (script ("src" "https://unpkg.com/codemirror@5.39.2/lib/codemirror.js") ("data-turbo-temporary" "true")) (script ("src" "https://unpkg.com/codemirror@5.39.2/addon/display/placeholder.js") ("data-turbo-temporary" "true")) + (script ("src" "https://unpkg.com/codemirror@5.39.2/mode/markdown/markdown.js") ("data-turbo-temporary" "true")) (link ("rel" "stylesheet") ("href" "https://unpkg.com/codemirror@5.39.2/lib/codemirror.css") ("data-turbo-temporary" "true")) - (text "{% if note.title == \"journal.css\" -%}") - ; css editor - (script ("src" "https://unpkg.com/codemirror@5.39.2/addon/edit/closebrackets.js") ("data-turbo-temporary" "true")) - (script ("src" "https://unpkg.com/codemirror@5.39.2/addon/hint/css-hint.js") ("data-turbo-temporary" "true")) - (script ("src" "https://unpkg.com/codemirror@5.39.2/addon/hint/show-hint.js") ("data-turbo-temporary" "true")) - (script ("src" "https://unpkg.com/codemirror@5.39.2/addon/lint/css-lint.js") ("data-turbo-temporary" "true")) - (script ("src" "https://unpkg.com/codemirror@5.39.2/mode/css/css.js") ("data-turbo-temporary" "true")) - (link ("rel" "stylesheet") ("href" "https://unpkg.com/codemirror@5.39.2/addon/hint/show-hint.css") ("data-turbo-temporary" "true")) - (link ("rel" "stylesheet") ("href" "https://unpkg.com/codemirror@5.39.2/addon/lint/lint.css") ("data-turbo-temporary" "true")) - - (style - (text ".CodeMirror { - font-family: monospace !important; - font-size: 16px; - border: solid 1px var(--color-super-lowered); - border-radius: var(--radius); - } - - .CodeMirror-line { - padding-left: 5px !important; - }")) - (text "{% else %}") - ; markdown editor - (script ("src" "https://unpkg.com/codemirror@5.39.2/mode/markdown/markdown.js") ("data-turbo-temporary" "true")) - (text "{%- endif %}") - ; tab bar - (text "{% if note.title != \"journal.css\" -%}") (div ("class" "pillmenu") (a @@ -253,7 +198,6 @@ ("data-tab-button" "preview") ("data-turbo" "false") (str (text "journals:label.preview_pane")))) - (text "{%- endif %}") ; tabs (div @@ -277,15 +221,10 @@ (script ("id" "editor_content") ("type" "text/markdown") (text "{{ note.content|remove_script_tags|safe }}")) (script (text "setTimeout(() => { - if (!document.getElementById(\"preview_tab\").shadowRoot) { - document.getElementById(\"preview_tab\").attachShadow({ mode: \"open\" }); - } - globalThis.editor = CodeMirror(document.getElementById(\"editor_tab\"), { value: document.getElementById(\"editor_content\").innerHTML, - mode: \"{% if note.title == 'journal.css' -%} css {%- else -%} markdown {%- endif %}\", + mode: \"markdown\", lineWrapping: true, - lineNumbers: \"{{ note.title }}\" === \"journal.css\", autoCloseBrackets: true, autofocus: true, viewportMargin: Number.POSITIVE_INFINITY, @@ -293,8 +232,7 @@ highlightFormatting: false, fencedCodeBlockHighlighting: false, xml: false, - smartIndent: true, - indentUnit: 4, + smartIndent: false, placeholder: `# {{ note.title }}`, extraKeys: { Home: \"goLineLeft\", @@ -305,15 +243,6 @@ }, }); - editor.on(\"keydown\", (cm, e) => { - if (e.key.length > 1) { - // ignore all keys that aren't a letter - return; - } - - CodeMirror.showHint(cm, CodeMirror.hint.css); - }); - document.querySelector(\"[data-tab-button=editor]\").addEventListener(\"click\", async (e) => { e.preventDefault(); trigger(\"atto::hooks::tabs:switch\", [\"editor\"]); @@ -333,10 +262,7 @@ }) ).text(); - const preview_token = window.crypto.randomUUID(); - document.getElementById(\"preview_tab\").shadowRoot.innerHTML = `${res}`; + document.getElementById(\"preview_tab\").innerHTML = res; trigger(\"atto::hooks::tabs:switch\", [\"preview\"]); }); }, 150);")) @@ -346,34 +272,7 @@ ("class" "flex flex-col gap-2 card") (text "{{ note.content|markdown|safe }}")) - (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 %}")) + (span (text "Last updated: ") (span ("class" "date") (text "{{ note.edited }}"))) (text "{%- endif %}") (text "{%- endif %}"))) (style @@ -433,7 +332,7 @@ }, body: JSON.stringify({ title, - content: title === \"journal.css\" ? `/* ${title} */\\n` : `# ${title}`, + content: `# ${title}`, journal: \"{{ selected_journal }}\", }), }) @@ -532,8 +431,8 @@ globalThis.change_journal_privacy = async (e) => { e.preventDefault(); - const selected = e.target.selectedOptions[0]; - fetch(\"/api/v1/journals/{% if journal -%} {{ journal.id }} {%- else -%} {{ selected_journal }} {%- endif %}/privacy\", { + const selected = event.target.selectedOptions[0]; + fetch(\"/api/v1/journals/{{ selected_journal }}/privacy\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", diff --git a/crates/app/src/public/html/profile/posts.lisp b/crates/app/src/public/html/profile/posts.lisp index 06aca2f..0c9d79a 100644 --- a/crates/app/src/public/html/profile/posts.lisp +++ b/crates/app/src/public/html/profile/posts.lisp @@ -44,10 +44,9 @@ ("ui_ident" "io_data_load") (div ("ui_ident" "io_data_marker")))) -(text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { - trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?user_id={{ profile.id }}&tag={{ tag }}&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); + trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?user_id={{ profile.id }}&tag={{ tag }}&page=\", Number.parseInt(\"{{ page }}\") - 1]); });")) (text "{% endblock %}") diff --git a/crates/app/src/public/html/profile/settings.lisp b/crates/app/src/public/html/profile/settings.lisp index 268dfef..8be4836 100644 --- a/crates/app/src/public/html/profile/settings.lisp +++ b/crates/app/src/public/html/profile/settings.lisp @@ -564,14 +564,14 @@ (li (text "Use custom CSS on your profile")) (li - (text "Use community emojis outside of + (text "Ability to use community emojis outside of their community")) (li - (text "Upload and use gif emojis")) + (text "Ability to upload and use gif emojis")) (li (text "Create infinite stack timelines")) (li - (text "Upload images to posts")) + (text "Ability to upload images to posts")) (li (text "Save infinite post drafts")) (li @@ -579,7 +579,7 @@ (li (text "Ability to create forges")) (li - (text "Create more than 1 app")) + (text "Ability to create more than 1 app")) (li (text "Create up to 10 stack blocks")) (li @@ -587,9 +587,7 @@ (li (text "Increased proxied image size")) (li - (text "Create infinite journals")) - (li - (text "Create infinite notes in each journal"))) + (text "Create infinite journals"))) (a ("href" "{{ config.stripe.payment_link }}?client_reference_id={{ user.id }}") ("class" "button") @@ -1403,11 +1401,6 @@ \"Hides dislikes on all posts. Users will also no longer be able to dislike your posts.\", \"text\", ], - [ - [\"paged_timelines\", \"Make timelines paged instead of infinitely scrolled\"], - \"{{ profile.settings.paged_timelines }}\", - \"checkbox\", - ], [[], \"Fun\", \"title\"], [ [\"disable_gpa_fun\", \"Disable GPA\"], diff --git a/crates/app/src/public/html/stacks/feed.lisp b/crates/app/src/public/html/stacks/feed.lisp index 5002856..5698065 100644 --- a/crates/app/src/public/html/stacks/feed.lisp +++ b/crates/app/src/public/html/stacks/feed.lisp @@ -83,10 +83,9 @@ ("ui_ident" "io_data_load") (div ("ui_ident" "io_data_marker"))) - (text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { - trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?stack_id={{ stack.id }}&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); + trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?stack_id={{ stack.id }}&page=\", Number.parseInt(\"{{ page }}\") - 1]); });")) (text "{%- endif %}")))) diff --git a/crates/app/src/public/html/timelines/all.lisp b/crates/app/src/public/html/timelines/all.lisp index 7cced78..c38dd88 100644 --- a/crates/app/src/public/html/timelines/all.lisp +++ b/crates/app/src/public/html/timelines/all.lisp @@ -33,10 +33,9 @@ ("ui_ident" "io_data_load") (div ("ui_ident" "io_data_marker")))) -(text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { - trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=AllPosts&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); + trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=AllPosts&page=\", Number.parseInt(\"{{ page }}\") - 1]); });")) (text "{% endblock %}") diff --git a/crates/app/src/public/html/timelines/following.lisp b/crates/app/src/public/html/timelines/following.lisp index ef23a55..b1759e4 100644 --- a/crates/app/src/public/html/timelines/following.lisp +++ b/crates/app/src/public/html/timelines/following.lisp @@ -11,10 +11,9 @@ ("ui_ident" "io_data_load") (div ("ui_ident" "io_data_marker")))) -(text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { - trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=FollowingPosts&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); + trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=FollowingPosts&page=\", Number.parseInt(\"{{ page }}\") - 1]); });")) (text "{% endblock %}") diff --git a/crates/app/src/public/html/timelines/home.lisp b/crates/app/src/public/html/timelines/home.lisp index 5a5658b..e398615 100644 --- a/crates/app/src/public/html/timelines/home.lisp +++ b/crates/app/src/public/html/timelines/home.lisp @@ -31,10 +31,9 @@ (div ("ui_ident" "io_data_marker"))) (text "{%- endif %}")) -(text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { - trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=MyCommunities&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); + trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=MyCommunities&page=\", Number.parseInt(\"{{ page }}\") - 1]); });")) (text "{% endblock %}") diff --git a/crates/app/src/public/html/timelines/popular.lisp b/crates/app/src/public/html/timelines/popular.lisp index d0223df..6d26f3d 100644 --- a/crates/app/src/public/html/timelines/popular.lisp +++ b/crates/app/src/public/html/timelines/popular.lisp @@ -11,10 +11,9 @@ ("ui_ident" "io_data_load") (div ("ui_ident" "io_data_marker")))) -(text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { - trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=PopularPosts&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); + trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=PopularPosts&page=\", Number.parseInt(\"{{ page }}\") - 1]); });")) (text "{% endblock %}") diff --git a/crates/app/src/public/html/timelines/swiss_army.lisp b/crates/app/src/public/html/timelines/swiss_army.lisp index 23243ce..eb722c9 100644 --- a/crates/app/src/public/html/timelines/swiss_army.lisp +++ b/crates/app/src/public/html/timelines/swiss_army.lisp @@ -30,7 +30,3 @@ (str (text "chats:label.go_back"))) (text "{%- endif %}")) (text "{%- endif %}") - -(text "{% if paginated -%}") -(text "{{ components::pagination(page=page, items=list|length) }}") -(text "{%- endif %}") diff --git a/crates/app/src/public/js/atto.js b/crates/app/src/public/js/atto.js index 835f76e..6c30428 100644 --- a/crates/app/src/public/js/atto.js +++ b/crates/app/src/public/js/atto.js @@ -1141,7 +1141,7 @@ ${option.input_element_type === "textarea" ? `${option.value}` : ""} }, ); - self.define("io_data_load", (_, tmpl, page, paginated_mode = false) => { + self.define("io_data_load", (_, tmpl, page) => { self.IO_DATA_MARKER = document.querySelector( "[ui_ident=io_data_marker]", ); @@ -1164,16 +1164,7 @@ ${option.input_element_type === "textarea" ? `${option.value}` : ""} self.IO_DATA_PAGE = page; self.IO_DATA_SEEN_IDS = []; - if (!paginated_mode) { - self.IO_DATA_OBSERVER.observe(self.IO_DATA_MARKER); - } else { - // immediately load first page - self.IO_DATA_TMPL = self.IO_DATA_TMPL.replace("&page=", ""); - self.IO_DATA_TMPL += `&paginated=true&page=`; - self.io_load_data(); - } - - self.IO_PAGINATED = paginated_mode; + self.IO_DATA_OBSERVER.observe(self.IO_DATA_MARKER); }); self.define("io_load_data", async () => { diff --git a/crates/app/src/routes/api/v1/auth/images.rs b/crates/app/src/routes/api/v1/auth/images.rs index e177db7..e062be1 100644 --- a/crates/app/src/routes/api/v1/auth/images.rs +++ b/crates/app/src/routes/api/v1/auth/images.rs @@ -213,7 +213,7 @@ pub async fn upload_avatar_request( if mime == "image/gif" { // gif image, don't encode if img.0.len() > MAXIMUM_GIF_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("gif".to_string()).into()); } std::fs::write(&path, img.0).unwrap(); @@ -226,7 +226,7 @@ pub async fn upload_avatar_request( // check file size if img.0.len() > MAXIMUM_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("image".to_string()).into()); } // upload image @@ -314,7 +314,7 @@ pub async fn upload_banner_request( if mime == "image/gif" { // gif image, don't encode if img.0.len() > MAXIMUM_GIF_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("gif".to_string()).into()); } std::fs::write(&path, img.0).unwrap(); @@ -327,7 +327,7 @@ pub async fn upload_banner_request( // check file size if img.0.len() > MAXIMUM_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("image".to_string()).into()); } // upload image diff --git a/crates/app/src/routes/api/v1/communities/images.rs b/crates/app/src/routes/api/v1/communities/images.rs index 3ddee00..464dede 100644 --- a/crates/app/src/routes/api/v1/communities/images.rs +++ b/crates/app/src/routes/api/v1/communities/images.rs @@ -136,7 +136,7 @@ pub async fn upload_avatar_request( // check file size if img.0.len() > MAXIMUM_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("image".to_string()).into()); } // upload image @@ -191,7 +191,7 @@ pub async fn upload_banner_request( // check file size if img.0.len() > MAXIMUM_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("image".to_string()).into()); } // upload image diff --git a/crates/app/src/routes/api/v1/communities/posts.rs b/crates/app/src/routes/api/v1/communities/posts.rs index 7bf4bf3..81a1fae 100644 --- a/crates/app/src/routes/api/v1/communities/posts.rs +++ b/crates/app/src/routes/api/v1/communities/posts.rs @@ -133,7 +133,7 @@ pub async fn create_request( // check sizes for img in &images { if img.len() > MAXIMUM_FILE_SIZE { - return Json(Error::FileTooLarge.into()); + return Json(Error::DataTooLong("image".to_string()).into()); } } diff --git a/crates/app/src/routes/api/v1/journals.rs b/crates/app/src/routes/api/v1/journals.rs index de6d501..97f8c9b 100644 --- a/crates/app/src/routes/api/v1/journals.rs +++ b/crates/app/src/routes/api/v1/journals.rs @@ -9,14 +9,11 @@ use crate::{ routes::api::v1::{UpdateJournalPrivacy, CreateJournal, UpdateJournalTitle}, State, }; -use tetratto_core::{ - database::NAME_REGEX, - model::{ - journals::{Journal, JournalPrivacyPermission}, - oauth, - permissions::FinePermission, - ApiReturn, Error, - }, +use tetratto_core::model::{ + journals::{Journal, JournalPrivacyPermission}, + oauth, + permissions::FinePermission, + ApiReturn, Error, }; pub async fn get_request( @@ -49,20 +46,6 @@ pub async fn get_request( }) } -pub async fn get_css_request( - Path(id): Path, - Extension(data): Extension, -) -> impl IntoResponse { - let data = &(data.read().await).0; - - let note = match data.get_note_by_journal_title(id, "journal.css").await { - Ok(x) => x, - Err(e) => return ([("Content-Type", "text/plain")], format!("/* {e} */")), - }; - - ([("Content-Type", "text/css")], note.content) -} - pub async fn list_request(jar: CookieJar, Extension(data): Extension) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadJournals) { @@ -116,17 +99,7 @@ pub async fn update_title_request( None => return Json(Error::NotAllowed.into()), }; - props.title = props.title.replace(" ", "_").to_lowercase(); - - // 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()); - } + props.title = props.title.replace(" ", "_"); // make sure this title isn't already in use if data diff --git a/crates/app/src/routes/api/v1/mod.rs b/crates/app/src/routes/api/v1/mod.rs index 9217437..f16b1ed 100644 --- a/crates/app/src/routes/api/v1/mod.rs +++ b/crates/app/src/routes/api/v1/mod.rs @@ -551,7 +551,6 @@ pub fn routes() -> Router { .route("/journals", post(journals::create_request)) .route("/journals/{id}", get(journals::get_request)) .route("/journals/{id}", delete(journals::delete_request)) - .route("/journals/{id}/journal.css", get(journals::get_css_request)) .route("/journals/{id}/title", post(journals::update_title_request)) .route( "/journals/{id}/privacy", diff --git a/crates/app/src/routes/api/v1/notes.rs b/crates/app/src/routes/api/v1/notes.rs index faf1bec..45c4a74 100644 --- a/crates/app/src/routes/api/v1/notes.rs +++ b/crates/app/src/routes/api/v1/notes.rs @@ -10,15 +10,12 @@ use crate::{ routes::api::v1::{CreateNote, RenderMarkdown, UpdateNoteContent, UpdateNoteTitle}, State, }; -use tetratto_core::{ - database::NAME_REGEX, - model::{ - journals::{JournalPrivacyPermission, Note}, - oauth, - permissions::FinePermission, - uploads::CustomEmoji, - ApiReturn, Error, - }, +use tetratto_core::model::{ + journals::{JournalPrivacyPermission, Note}, + oauth, + permissions::FinePermission, + uploads::CustomEmoji, + ApiReturn, Error, }; pub async fn get_request( @@ -138,17 +135,7 @@ pub async fn update_title_request( Err(e) => return Json(e.into()), }; - props.title = props.title.replace(" ", "_").to_lowercase(); - - // 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()); - } + props.title = props.title.replace(" ", "_"); // make sure this title isn't already in use if data diff --git a/crates/app/src/routes/pages/journals.rs b/crates/app/src/routes/pages/journals.rs index 1f03dd7..f631826 100644 --- a/crates/app/src/routes/pages/journals.rs +++ b/crates/app/src/routes/pages/journals.rs @@ -116,7 +116,7 @@ pub async fn view_request( } // if we don't have a selected journal, we shouldn't be here probably - if selected_journal.is_empty() | (selected_note == "journal.css") { + if selected_journal.is_empty() { return Err(Html( render_error(Error::NotAllowed, &jar, &data, &user).await, )); @@ -207,81 +207,3 @@ pub async fn view_request( // return Ok(Html(data.1.render("journals/app.html", &context).unwrap())) } - -/// `/@{owner}/{journal}` -pub async fn index_view_request( - jar: CookieJar, - Extension(data): Extension, - Path((owner, selected_journal)): Path<(String, String)>, -) -> impl IntoResponse { - let data = data.read().await; - let user = match get_user_from_token!(jar, data.0) { - Some(ua) => Some(ua), - None => None, - }; - - // get owner - let owner = match data.0.get_user_by_username(&owner).await { - Ok(ua) => ua, - Err(e) => { - return Err(Html(render_error(e, &jar, &data, &user).await)); - } - }; - - check_user_blocked_or_private!(user, owner, data, jar); - - // get journal and check privacy settings - let journal = match data - .0 - .get_journal_by_owner_title(owner.id, &selected_journal) - .await - { - Ok(p) => p, - Err(e) => { - return Err(Html(render_error(e, &jar, &data, &user).await)); - } - }; - - if journal.privacy == JournalPrivacyPermission::Private { - if let Some(ref user) = user { - if user.id != journal.owner { - return Err(Html( - render_error(Error::NotAllowed, &jar, &data, &Some(user.to_owned())).await, - )); - } - } else { - return Err(Html( - render_error(Error::NotAllowed, &jar, &data, &user).await, - )); - } - } - - // ... - let notes = match data.0.get_notes_by_journal(journal.id).await { - Ok(p) => Some(p), - Err(e) => { - return Err(Html(render_error(e, &jar, &data, &user).await)); - } - }; - - let lang = get_lang!(jar, data.0); - let mut context = initial_context(&data.0.0.0, lang, &user).await; - - if selected_journal.is_empty() { - context.insert("selected_journal", &0); - } else { - context.insert("selected_journal", &selected_journal); - } - - context.insert("selected_note", &0); - context.insert("journal", &journal); - - context.insert("owner", &owner); - context.insert("notes", ¬es); - - context.insert("view_mode", &true); - context.insert("is_editor", &false); - - // return - Ok(Html(data.1.render("journals/app.html", &context).unwrap())) -} diff --git a/crates/app/src/routes/pages/misc.rs b/crates/app/src/routes/pages/misc.rs index 8b76292..3ff3f0d 100644 --- a/crates/app/src/routes/pages/misc.rs +++ b/crates/app/src/routes/pages/misc.rs @@ -576,8 +576,6 @@ pub struct TimelineQuery { pub user_id: usize, #[serde(default)] pub tag: String, - #[serde(default)] - pub paginated: bool, } /// `/_swiss_army_timeline` @@ -699,7 +697,6 @@ pub async fn swiss_army_timeline_request( context.insert("list", &list); context.insert("page", &req.page); - context.insert("paginated", &req.paginated); Ok(Html( data.1 .render("timelines/swiss_army.html", &context) diff --git a/crates/app/src/routes/pages/mod.rs b/crates/app/src/routes/pages/mod.rs index 2eaeca2..2177d94 100644 --- a/crates/app/src/routes/pages/mod.rs +++ b/crates/app/src/routes/pages/mod.rs @@ -134,7 +134,7 @@ pub fn routes() -> Router { // journals .route("/journals", get(journals::redirect_request)) .route("/journals/{journal}/{note}", get(journals::app_request)) - .route("/@{owner}/{journal}", get(journals::index_view_request)) + .route("/@{owner}/{journal}", get(journals::view_request)) .route("/@{owner}/{journal}/{note}", get(journals::view_request)) } diff --git a/crates/core/src/database/journals.rs b/crates/core/src/database/journals.rs index a4a0d00..4602b6b 100644 --- a/crates/core/src/database/journals.rs +++ b/crates/core/src/database/journals.rs @@ -1,10 +1,9 @@ use oiseau::{cache::Cache, query_row}; use crate::{ - database::common::NAME_REGEX, model::{ auth::User, - journals::{Journal, JournalPrivacyPermission}, permissions::FinePermission, + journals::{Journal, JournalPrivacyPermission}, Error, Result, }, }; @@ -70,7 +69,7 @@ impl DataManager { Ok(res.unwrap()) } - const MAXIMUM_FREE_JOURNALS: usize = 5; + const MAXIMUM_FREE_JOURNALS: usize = 15; /// Create a new journal in the database. /// @@ -84,19 +83,7 @@ impl DataManager { return Err(Error::DataTooLong("title".to_string())); } - data.title = data.title.replace(" ", "_").to_lowercase(); - - // 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(), - )); - } + data.title = data.title.replace(" ", "_"); // make sure this title isn't already in use if self diff --git a/crates/core/src/database/mod.rs b/crates/core/src/database/mod.rs index a00fde9..e56bc93 100644 --- a/crates/core/src/database/mod.rs +++ b/crates/core/src/database/mod.rs @@ -30,4 +30,3 @@ 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 ea7da45..d46394b 100644 --- a/crates/core/src/database/notes.rs +++ b/crates/core/src/database/notes.rs @@ -1,5 +1,4 @@ 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}; @@ -65,8 +64,6 @@ impl DataManager { Ok(res.unwrap()) } - const MAXIMUM_FREE_NOTES_PER_JOURNAL: usize = 10; - /// Create a new note in the database. /// /// # Arguments @@ -85,33 +82,7 @@ impl DataManager { return Err(Error::DataTooLong("content".to_string())); } - data.title = data.title.replace(" ", "_").to_lowercase(); - - // check number of notes - let owner = self.get_user_by_id(data.owner).await?; - - if !owner.permissions.check(FinePermission::SUPPORTER) { - let journals = self.get_notes_by_journal(data.owner).await?; - - if journals.len() >= Self::MAXIMUM_FREE_NOTES_PER_JOURNAL { - return Err(Error::MiscError( - "You already have the maximum number of notes you can have in this journal" - .to_string(), - )); - } - } - - // 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(), - )); - } + data.title = data.title.replace(" ", "_"); // make sure this title isn't already in use if self diff --git a/crates/core/src/model/auth.rs b/crates/core/src/model/auth.rs index bc8b13f..8c12f76 100644 --- a/crates/core/src/model/auth.rs +++ b/crates/core/src/model/auth.rs @@ -231,9 +231,6 @@ pub struct UserSettings { /// A list of strings the user has muted. #[serde(default)] pub muted: Vec, - /// If timelines are paged instead of infinitely scrolled. - #[serde(default)] - pub paged_timelines: bool, } fn mime_avif() -> String { @@ -335,7 +332,7 @@ impl User { // parse for char in input.chars() { - if ((char == '\\') | (char == '/')) && !escape { + if (char == '\\') && !escape { escape = true; continue; } diff --git a/crates/core/src/model/mod.rs b/crates/core/src/model/mod.rs index 62f26a3..c50ea7c 100644 --- a/crates/core/src/model/mod.rs +++ b/crates/core/src/model/mod.rs @@ -41,7 +41,6 @@ pub enum Error { AlreadyAuthenticated, DataTooLong(String), DataTooShort(String), - FileTooLarge, UsernameInUse, TitleInUse, QuestionsDisabled, @@ -63,7 +62,6 @@ impl Display for Error { Self::AlreadyAuthenticated => "Already authenticated".to_string(), Self::DataTooLong(name) => format!("Given {name} is too long!"), Self::DataTooShort(name) => format!("Given {name} is too short!"), - Self::FileTooLarge => "Given file is too large".to_string(), Self::UsernameInUse => "Username in use".to_string(), Self::TitleInUse => "Title in use".to_string(), Self::QuestionsDisabled => "You are not allowed to ask questions there".to_string(),