From d9f35594e7c0a2689d4974ec34c111de11927bbe Mon Sep 17 00:00:00 2001 From: flashwave <me@flash.moe> Date: Sat, 8 Feb 2025 17:51:18 +0000 Subject: [PATCH] Changed internal parser selection value from integers to a string enum. --- assets/misuzu.js/forum/editor.jsx | 33 ++++++------ assets/misuzu.js/messages/messages.js | 12 ++--- assets/misuzu.js/parsing.js | 7 +-- ...2_08_153444_new_parsing_method_storage.php | 54 +++++++++++++++++++ public-legacy/forum/posting.php | 46 ++++++++-------- public-legacy/profile.php | 10 ++-- public-legacy/settings/data.php | 6 +-- src/Forum/ForumPostInfo.php | 12 ++--- src/Forum/ForumPostsData.php | 44 +++++++++++---- src/Info/InfoRoutes.php | 4 +- src/Messages/MessageInfo.php | 12 ++--- src/Messages/MessagesData.php | 41 ++++++++++---- src/Messages/MessagesRoutes.php | 26 ++++----- src/News/NewsRoutes.php | 4 +- src/Parsers/Parser.php | 45 ---------------- src/Parsers/Parsers.php | 21 ++++++++ src/Parsers/TextFormat.php | 8 +++ src/TemplatingExtension.php | 14 +++-- src/Users/UserInfo.php | 22 ++++---- src/Users/UsersData.php | 38 ++++++------- templates/_layout/input.twig | 4 +- templates/changelog/change.twig | 2 +- templates/forum/macros.twig | 4 +- templates/forum/posting.twig | 5 +- templates/home/landing.twig | 2 +- templates/manage/users/note.twig | 2 +- templates/manage/users/notes.twig | 4 +- templates/messages/compose.twig | 4 +- templates/messages/thread.twig | 4 +- templates/news/macros.twig | 4 +- templates/profile/index.twig | 8 +-- tools/cron | 12 ++--- 32 files changed, 301 insertions(+), 213 deletions(-) create mode 100644 database/2025_02_08_153444_new_parsing_method_storage.php delete mode 100644 src/Parsers/Parser.php create mode 100644 src/Parsers/Parsers.php create mode 100644 src/Parsers/TextFormat.php diff --git a/assets/misuzu.js/forum/editor.jsx b/assets/misuzu.js/forum/editor.jsx index d0719538..22e58528 100644 --- a/assets/misuzu.js/forum/editor.jsx +++ b/assets/misuzu.js/forum/editor.jsx @@ -55,17 +55,16 @@ const MszForumEditor = function(form) { uploadElemProgressText.textContent = ''; const insertTheLinkIntoTheBoxEx2 = () => { - const parserMode = parseInt(parserElem.value); let insertText = location.protocol + fileInfo.url; - if(parserMode == 1) { // bbcode + if(parserElem.value == 'bb') { // bbcode if(fileInfo.isImage()) insertText = `[img]${fileInfo.url}[/img]`; else if(fileInfo.isAudio()) insertText = `[audio]${fileInfo.url}[/audio]`; else if(fileInfo.isVideo()) insertText = `[video]${fileInfo.url}[/video]`; - } else if(parserMode == 2) { // markdown + } else if(parserElem.value == 'md') { // markdown if(fileInfo.isMedia()) insertText = ``; } @@ -181,13 +180,16 @@ const MszForumEditor = function(form) { const renderPreview = async (parser, text) => { if(typeof text !== 'string') return ''; + if(typeof parser !== 'string') + return ''; const formData = new FormData; - formData.append('post[mode]', 'preview'); - formData.append('post[text]', text); - formData.append('post[parser]', parseInt(parser)); + formData.append('preview', '1'); + formData.append('text', text); + formData.append('format', parser); - return (await $xhr.post('/forum/posting.php', { authed: true }, formData)).body; + const { body } = await $xhr.post('/forum/posting.php', { authed: true }, formData); + return body; }; const previewBtn = <button class="input__button" type="button" value="preview">Preview</button>; @@ -200,8 +202,8 @@ const MszForumEditor = function(form) { modeElem.textContent = modeElem.dataset.original; modeElem.dataset.original = null; } else { - const postText = textElem.value, - postParser = parseInt(parserElem.value); + const postText = textElem.value; + const postParser = parserElem.value; if(lastPostText === postText && lastPostParser === postParser) { previewElem.removeAttribute('hidden'); @@ -223,7 +225,7 @@ const MszForumEditor = function(form) { MszShowMessageBox('Failed to render preview.'); }) .then(body => { - previewElem.classList.toggle('markdown', postParser === 2); + previewElem.classList.toggle('markdown', postParser === 'md'); lastPostText = postText; lastPostParser = postParser; @@ -248,28 +250,27 @@ const MszForumEditor = function(form) { switchButtons(parserElem.value); parserElem.addEventListener('change', () => { - const postParser = parseInt(parserElem.value); - switchButtons(postParser); + switchButtons(parserElem.value); if(previewElem.hasAttribute('hidden')) return; // dunno if this would even be possible, but ech - if(postParser === lastPostParser) + if(parserElem.value === lastPostParser) return; parserElem.setAttribute('disabled', 'disabled'); previewBtn.setAttribute('disabled', 'disabled'); previewBtn.classList.add('input__button--busy'); - renderPreview(postParser, lastPostText) + renderPreview(parserElem.value, lastPostText) .catch(() => { previewElem.innerHTML = ''; MszShowMessageBox('Failed to render preview.'); }) .then(body => { - previewElem.classList.add('markdown', postParser === 2); - lastPostParser = postParser; + previewElem.classList.add('markdown', parserElem.value === 'md'); + lastPostParser = parserElem.value; previewElem.innerHTML = body; MszEmbed.handle($queryAll('.js-msz-embed-media')); diff --git a/assets/misuzu.js/messages/messages.js b/assets/misuzu.js/messages/messages.js index 597af8ec..cc4025c5 100644 --- a/assets/misuzu.js/messages/messages.js +++ b/assets/misuzu.js/messages/messages.js @@ -29,11 +29,11 @@ const MszMessages = () => { return false; }; - const msgsCreate = async (title, text, parser, draft, recipient, replyTo) => { + const msgsCreate = async (title, text, format, draft, recipient, replyTo) => { const formData = new FormData; formData.append('title', title); formData.append('body', text); - formData.append('parser', parser); + formData.append('format', format); formData.append('draft', draft); formData.append('recipient', recipient); formData.append('reply', replyTo); @@ -45,11 +45,11 @@ const MszMessages = () => { return body; }; - const msgsUpdate = async (messageId, title, text, parser, draft) => { + const msgsUpdate = async (messageId, title, text, format, draft) => { const formData = new FormData; formData.append('title', title); formData.append('body', text); - formData.append('parser', parser); + formData.append('format', format); formData.append('draft', draft); const { body } = await $xhr.post(`/messages/${encodeURIComponent(messageId)}`, { type: 'json', csrf: true }, formData); @@ -139,14 +139,14 @@ const MszMessages = () => { form.message, form.title, form.body, - form.parser, + form.format, form.draft ); } else { result = await msgsCreate( form.title, form.body, - form.parser, + form.format, form.draft, form.recipient, form.reply || '' diff --git a/assets/misuzu.js/parsing.js b/assets/misuzu.js/parsing.js index d4fc08f2..9b8efb3d 100644 --- a/assets/misuzu.js/parsing.js +++ b/assets/misuzu.js/parsing.js @@ -36,12 +36,9 @@ const MszParsing = (() => { ]; const getTagsFor = parser => { - if(typeof parser !== 'number') - parser = parseInt(parser); - - if(parser === 1) + if(parser === 'bb') return bbTags; - if(parser === 2) + if(parser === 'md') return mdTags; return []; diff --git a/database/2025_02_08_153444_new_parsing_method_storage.php b/database/2025_02_08_153444_new_parsing_method_storage.php new file mode 100644 index 00000000..9d492278 --- /dev/null +++ b/database/2025_02_08_153444_new_parsing_method_storage.php @@ -0,0 +1,54 @@ +<?php +use Index\Db\DbConnection; +use Index\Db\Migration\DbMigration; + +final class NewParsingMethodStorage_20250208_153444 implements DbMigration { + public function migrate(DbConnection $conn): void { + // msz_forum_posts + $conn->execute(<<<SQL + ALTER TABLE msz_forum_posts + ADD COLUMN post_text_format ENUM('','bb','md') NOT NULL DEFAULT '' AFTER post_text, + ADD INDEX posts_text_format_index (post_text_format); + SQL); + $conn->execute(<<<SQL + UPDATE msz_forum_posts + SET post_text_format = IF(post_parse = 2, 'md', IF(post_parse = 1, 'bb', '')); + SQL); + $conn->execute(<<<SQL + ALTER TABLE msz_forum_posts + DROP COLUMN post_parse, + DROP INDEX posts_parse_index; + SQL); + + // msz_messages + $conn->execute(<<<SQL + ALTER TABLE msz_messages + ADD COLUMN msg_body_format ENUM('','bb','md') NOT NULL DEFAULT '' AFTER msg_body; + SQL); + $conn->execute(<<<SQL + UPDATE msz_messages + SET msg_body_format = IF(msg_parser = 2, 'md', IF(msg_parser = 1, 'bb', '')); + SQL); + $conn->execute(<<<SQL + ALTER TABLE msz_messages + DROP COLUMN msg_parser; + SQL); + + // msz_users + $conn->execute(<<<SQL + ALTER TABLE msz_users + ADD COLUMN user_about_content_format ENUM('','bb','md') NOT NULL DEFAULT '' AFTER user_about_content, + ADD COLUMN user_signature_content_format ENUM('','bb','md') NOT NULL DEFAULT '' AFTER user_signature_content; + SQL); + $conn->execute(<<<SQL + UPDATE msz_users + SET user_about_content_format = IF(user_about_parser = 2, 'md', IF(user_about_parser = 1, 'bb', '')), + user_signature_content_format = IF(user_signature_parser = 2, 'md', IF(user_signature_parser = 1, 'bb', '')); + SQL); + $conn->execute(<<<SQL + ALTER TABLE msz_users + DROP COLUMN user_about_parser, + DROP COLUMN user_signature_parser; + SQL); + } +} diff --git a/public-legacy/forum/posting.php b/public-legacy/forum/posting.php index 410806a0..58f24a73 100644 --- a/public-legacy/forum/posting.php +++ b/public-legacy/forum/posting.php @@ -4,7 +4,7 @@ namespace Misuzu; use stdClass; use RuntimeException; use Misuzu\Forum\{ForumCategoryInfo,ForumPostInfo,ForumTopicInfo}; -use Misuzu\Parsers\Parser; +use Misuzu\Parsers\{Parsers,TextFormat}; use Index\XDateTime; use Carbon\CarbonImmutable; @@ -19,8 +19,23 @@ $currentUserId = $currentUser->id; if($msz->usersCtx->hasActiveBan($currentUser)) Template::throwError(403); +if(filter_has_var(INPUT_POST, 'preview')) { + header('Content-Type: text/plain; charset=utf-8'); + + $text = (string)filter_input(INPUT_POST, 'text'); + $format = TextFormat::tryFrom((string)filter_input(INPUT_POST, 'format')); + if($format === null) { + http_response_code(400); + return; + } + + http_response_code(200); + echo Parsers::instance($format)->parseText(htmlspecialchars($text)); + return; +} + $forumPostingModes = [ - 'create', 'edit', 'quote', 'preview', + 'create', 'edit', 'quote', ]; if(!empty($_POST)) { @@ -38,22 +53,6 @@ if(!empty($_POST)) { if(!in_array($mode, $forumPostingModes, true)) Template::throwError(400); -if($mode === 'preview') { - header('Content-Type: text/plain; charset=utf-8'); - - $postText = (string)($_POST['post']['text']); - $postParser = (int)($_POST['post']['parser']); - - if(!Parser::isValid($postParser)) { - http_response_code(400); - return; - } - - http_response_code(200); - echo Parser::instance($postParser)->parseText(htmlspecialchars($postText)); - return; -} - if(empty($postId) && empty($topicId) && empty($forumId)) Template::throwError(404); @@ -144,7 +143,7 @@ $notices = []; if(!empty($_POST)) { $topicTitle = $_POST['post']['title'] ?? ''; $postText = $_POST['post']['text'] ?? ''; - $postParser = (int)($_POST['post']['parser'] ?? Parser::BBCODE); + $postParser = TextFormat::tryFrom((string)($_POST['post']['parser'] ?? '')) ?? TextFormat::BBCode; $topicType = isset($_POST['post']['type']) ? $_POST['post']['type'] : null; $postSignature = isset($_POST['post']['signature']); @@ -192,9 +191,6 @@ if(!empty($_POST)) { } } - if(!Parser::isValid($postParser)) - $notices[] = 'Invalid parser selected.'; - $postTextLengths = $cfg->getValues([ ['forum.post.minLength:i', 1], ['forum.post.maxLength:i', 60000], @@ -245,7 +241,7 @@ if(!empty($_POST)) { (string)$postId, remoteAddr: $_SERVER['REMOTE_ADDR'], body: $postText, - bodyParser: $postParser, + bodyFormat: $postParser, displaySignature: $postSignature, bumpEdited: $markUpdated ); @@ -294,9 +290,9 @@ if($mode === 'edit') { // $post is pretty much sure to be populated at this poin try { $lastPostInfo = $msz->forumCtx->posts->getPost(userInfo: $currentUser, getLast: true, deleted: false); - $selectedParser = $lastPostInfo->parser; + $selectedParser = $lastPostInfo->bodyFormat; } catch(RuntimeException $ex) { - $selectedParser = Parser::BBCODE; + $selectedParser = TextFormat::BBCode; } Template::render('forum.posting', [ diff --git a/public-legacy/profile.php b/public-legacy/profile.php index 22915836..6d10a53a 100644 --- a/public-legacy/profile.php +++ b/public-legacy/profile.php @@ -5,7 +5,7 @@ use stdClass; use InvalidArgumentException; use RuntimeException; use Index\ByteFormat; -use Misuzu\Parsers\Parser; +use Misuzu\Parsers\TextFormat; use Misuzu\Users\{User,UsersContext}; use Misuzu\Users\Assets\UserAvatarAsset; use Misuzu\Users\Assets\UserBackgroundAsset; @@ -141,11 +141,11 @@ if($isEditing) { $notices[] = 'You\'re not allowed to edit your about page.'; } else { $aboutText = (string)($_POST['about']['text'] ?? ''); - $aboutParse = (int)($_POST['about']['parser'] ?? Parser::PLAIN); + $aboutParse = TextFormat::tryFrom((string)($_POST['about']['parser'] ?? '')) ?? TextFormat::Plain; $aboutValid = $msz->usersCtx->users->validateProfileAbout($aboutParse, $aboutText); if($aboutValid === '') - $msz->usersCtx->users->updateUser($userInfo, aboutBody: $aboutText, aboutBodyParser: $aboutParse); + $msz->usersCtx->users->updateUser($userInfo, aboutBody: $aboutText, aboutBodyFormat: $aboutParse); else $notices[] = $msz->usersCtx->users->validateProfileAboutText($aboutValid); } @@ -156,11 +156,11 @@ if($isEditing) { $notices[] = 'You\'re not allowed to edit your forum signature.'; } else { $sigText = (string)($_POST['signature']['text'] ?? ''); - $sigParse = (int)($_POST['signature']['parser'] ?? Parser::PLAIN); + $sigParse = TextFormat::tryFrom((string)($_POST['signature']['parser'] ?? '') ?? TextFormat::Plain; $sigValid = $msz->usersCtx->users->validateForumSignature($sigParse, $sigText); if($sigValid === '') - $msz->usersCtx->users->updateUser($userInfo, signatureBody: $sigText, signatureBodyParser: $sigParse); + $msz->usersCtx->users->updateUser($userInfo, signatureBody: $sigText, signatureBodyFormat: $sigParse); else $notices[] = $msz->usersCtx->users->validateForumSignatureText($sigValid); } diff --git a/public-legacy/settings/data.php b/public-legacy/settings/data.php index 84ebcd98..2b4cd89a 100644 --- a/public-legacy/settings/data.php +++ b/public-legacy/settings/data.php @@ -133,12 +133,12 @@ if(isset($_POST['action']) && is_string($_POST['action'])) { $tmpFiles[] = db_to_zip($archive, $userInfo, 'comments_categories', ['category_id:s', 'category_name:s', 'user_id:s:n', 'category_created:t', 'category_locked:t:n'], 'user_id'); $tmpFiles[] = db_to_zip($archive, $userInfo, 'comments_posts', ['comment_id:s', 'category_id:s', 'user_id:s:n', 'comment_reply_to:s:n', 'comment_text:s', 'comment_created:t', 'comment_pinned:t:n', 'comment_edited:t:n', 'comment_deleted:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'comments_votes', ['comment_id:s', 'user_id:s', 'comment_vote:i']); - $tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_posts', ['post_id:s', 'topic_id:s', 'forum_id:s', 'user_id:s:n', 'post_remote_addr:a', 'post_text:s', 'post_parse:i', 'post_display_signature:b', 'post_created:t', 'post_edited:t:n', 'post_deleted:t:n']); + $tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_posts', ['post_id:s', 'topic_id:s', 'forum_id:s', 'user_id:s:n', 'post_remote_addr:a', 'post_text:s', 'post_text_format:s', 'post_display_signature:b', 'post_created:t', 'post_edited:t:n', 'post_deleted:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics', ['topic_id:s', 'forum_id:s', 'user_id:s:n', 'topic_type:i', 'topic_title:s', 'topic_count_views:i', 'topic_created:t', 'topic_bumped:t', 'topic_deleted:t:n', 'topic_locked:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics_redirects', ['topic_id:s', 'user_id:s:n', 'redir_url:s', 'redir_created:t']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics_track', ['user_id:s', 'topic_id:s', 'forum_id:s', 'track_last_read:t']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'login_attempts', ['attempt_id:s', 'user_id:s:n', 'attempt_success:b', 'attempt_remote_addr:a', 'attempt_country:s', 'attempt_created:t', 'attempt_user_agent:s']); - $tmpFiles[] = db_to_zip($archive, $userInfo, 'messages', ['msg_id:s', 'msg_owner_id:s', 'msg_author_id:s:n', 'msg_recipient_id:s:n', 'msg_reply_to:s:n', 'msg_title:s', 'msg_body:s', 'msg_parser:i', 'msg_created:t', 'msg_sent:t:n', 'msg_read:t:n', 'msg_deleted:t:n'], 'msg_owner_id'); + $tmpFiles[] = db_to_zip($archive, $userInfo, 'messages', ['msg_id:s', 'msg_owner_id:s', 'msg_author_id:s:n', 'msg_recipient_id:s:n', 'msg_reply_to:s:n', 'msg_title:s', 'msg_body:s', 'msg_body_format:s', 'msg_created:t', 'msg_sent:t:n', 'msg_read:t:n', 'msg_deleted:t:n'], 'msg_owner_id'); $tmpFiles[] = db_to_zip($archive, $userInfo, 'news_posts', ['post_id:s', 'category_id:s', 'user_id:s:n', 'comment_section_id:s:n', 'post_featured:b', 'post_title:s', 'post_text:s', 'post_scheduled:t', 'post_created:t', 'post_updated:t', 'post_deleted:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'oauth2_access', ['acc_id:s', 'app_id:s', 'user_id:s:n', 'acc_token:n', 'acc_scope:s', 'acc_created:t', 'acc_expires:t']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'oauth2_authorise', ['auth_id:s', 'app_id:s', 'user_id:s', 'uri_id:s', 'auth_challenge_code:n', 'auth_challenge_method:s', 'auth_scope:s', 'auth_code:n', 'auth_created:t', 'auth_expires:t']); @@ -148,7 +148,7 @@ if(isset($_POST['action']) && is_string($_POST['action'])) { $tmpFiles[] = db_to_zip($archive, $userInfo, 'perms_calculated', ['user_id:s:n', 'forum_id:s:n', 'perms_category:s', 'perms_calculated:i']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'profile_fields_values', ['field_id:s', 'user_id:s', 'format_id:s', 'field_value:s']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'sessions', ['session_id:s', 'user_id:s', 'session_key:n', 'session_remote_addr_first:a', 'session_remote_addr_last:a:n', 'session_user_agent:s', 'session_country:s', 'session_expires:t', 'session_expires_bump:b', 'session_created:t', 'session_active:t:n']); - $tmpFiles[] = db_to_zip($archive, $userInfo, 'users', ['user_id:s', 'user_name:s', 'user_password:n', 'user_email:s', 'user_remote_addr_first:a', 'user_remote_addr_last:a', 'user_super:b', 'user_country:s', 'user_colour:i:n', 'user_created:t', 'user_active:t:n', 'user_deleted:t:n', 'user_display_role_id:s:n', 'user_about_content:s:n', 'user_about_parser:i', 'user_signature_content:s:n', 'user_signature_parser:i', 'user_background_settings:i:n', 'user_title:s:n']); + $tmpFiles[] = db_to_zip($archive, $userInfo, 'users', ['user_id:s', 'user_name:s', 'user_password:n', 'user_email:s', 'user_remote_addr_first:a', 'user_remote_addr_last:a', 'user_super:b', 'user_country:s', 'user_colour:i:n', 'user_created:t', 'user_active:t:n', 'user_deleted:t:n', 'user_display_role_id:s:n', 'user_about_content:s:n', 'user_about_content_format:s', 'user_signature_content:s:n', 'user_signature_content_format:s', 'user_background_settings:i:n', 'user_title:s:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_bans', ['ban_id:s', 'user_id:s', 'mod_id:n', 'ban_severity:i', 'ban_reason_public:s', 'ban_reason_private:s', 'ban_created:t', 'ban_expires:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_birthdates', ['user_id:s', 'birth_year:i:n', 'birth_month:i', 'birth_day:i']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_password_resets', ['reset_id:s', 'user_id:s', 'reset_remote_addr:a', 'reset_requested:t', 'reset_code:n']); diff --git a/src/Forum/ForumPostInfo.php b/src/Forum/ForumPostInfo.php index 33e72b8d..bc0c32c8 100644 --- a/src/Forum/ForumPostInfo.php +++ b/src/Forum/ForumPostInfo.php @@ -1,10 +1,10 @@ <?php namespace Misuzu\Forum; -use Misuzu\Parsers\Parser; use Carbon\CarbonImmutable; use Index\XDateTime; use Index\Db\DbResult; +use Misuzu\Parsers\TextFormat; class ForumPostInfo { public function __construct( @@ -14,7 +14,7 @@ class ForumPostInfo { public private(set) ?string $userId, public private(set) string $remoteAddress, public private(set) string $body, - public private(set) int $parser, + public private(set) TextFormat $bodyFormat, public private(set) bool $shouldDisplaySignature, public private(set) int $createdTime, public private(set) ?int $editedTime, @@ -29,7 +29,7 @@ class ForumPostInfo { userId: $result->getStringOrNull(3), remoteAddress: $result->getString(4), body: $result->getString(5), - parser: $result->getInteger(6), + bodyFormat: TextFormat::tryFrom($result->getString(6)) ?? TextFormat::Plain, shouldDisplaySignature: $result->getBoolean(7), createdTime: $result->getInteger(8), editedTime: $result->getIntegerOrNull(9), @@ -38,15 +38,15 @@ class ForumPostInfo { } public bool $isBodyPlain { - get => $this->parser === Parser::PLAIN; + get => $this->bodyFormat === TextFormat::Plain; } public bool $isBodyBBCode { - get => $this->parser === Parser::BBCODE; + get => $this->bodyFormat === TextFormat::BBCode; } public bool $isBodyMarkdown { - get => $this->parser === Parser::MARKDOWN; + get => $this->bodyFormat === TextFormat::Markdown; } public CarbonImmutable $createdAt { diff --git a/src/Forum/ForumPostsData.php b/src/Forum/ForumPostsData.php index 82b4285c..65fb6389 100644 --- a/src/Forum/ForumPostsData.php +++ b/src/Forum/ForumPostsData.php @@ -7,6 +7,7 @@ use stdClass; use Carbon\CarbonImmutable; use Index\Db\{DbConnection,DbStatementCache,DbTools}; use Misuzu\Pagination; +use Misuzu\Parsers\TextFormat; use Misuzu\Users\UserInfo; class ForumPostsData { @@ -131,7 +132,16 @@ class ForumPostsData { $hasPagination = $pagination !== null; $args = 0; - $query = 'SELECT post_id, topic_id, forum_id, user_id, INET6_NTOA(post_remote_addr), post_text, post_parse, post_display_signature, UNIX_TIMESTAMP(post_created), UNIX_TIMESTAMP(post_edited), UNIX_TIMESTAMP(post_deleted) FROM msz_forum_posts'; + $query = <<<SQL + SELECT post_id, topic_id, forum_id, user_id, + INET6_NTOA(post_remote_addr), + post_text, post_text_format, + post_display_signature, + UNIX_TIMESTAMP(post_created), + UNIX_TIMESTAMP(post_edited), + UNIX_TIMESTAMP(post_deleted) + FROM msz_forum_posts + SQL; if($hasCategoryInfo) { ++$args; if(is_array($categoryInfo)) @@ -207,7 +217,16 @@ class ForumPostsData { throw new InvalidArgumentException('At least one of the four first arguments must be specified.'); $values = []; - $query = 'SELECT post_id, topic_id, forum_id, user_id, INET6_NTOA(post_remote_addr), post_text, post_parse, post_display_signature, UNIX_TIMESTAMP(post_created), UNIX_TIMESTAMP(post_edited), UNIX_TIMESTAMP(post_deleted) FROM msz_forum_posts'; + $query = <<<SQL + SELECT post_id, topic_id, forum_id, user_id, + INET6_NTOA(post_remote_addr), + post_text, post_text_format, + post_display_signature, + UNIX_TIMESTAMP(post_created), + UNIX_TIMESTAMP(post_edited), + UNIX_TIMESTAMP(post_deleted) + FROM msz_forum_posts + SQL; if($hasPostId) { $query .= ' WHERE post_id = ?'; $values[] = $postId; @@ -265,7 +284,7 @@ class ForumPostsData { UserInfo|string|null $userInfo, string $remoteAddr, string $body, - int $bodyParser, + TextFormat|string $bodyFormat, bool $displaySignature, ForumCategoryInfo|string|null $categoryInfo = null ): ForumPostInfo { @@ -281,13 +300,20 @@ class ForumPostsData { if($userInfo instanceof UserInfo) $userInfo = $userInfo->id; - $stmt = $this->cache->get('INSERT INTO msz_forum_posts (topic_id, forum_id, user_id, post_remote_addr, post_text, post_parse, post_display_signature) VALUES (?, ?, ?, INET6_ATON(?), ?, ?, ?)'); + if(is_string($bodyFormat)) + $bodyFormat = TextFormat::from($bodyFormat); + + $stmt = $this->cache->get(<<<SQL + INSERT INTO msz_forum_posts ( + topic_id, forum_id, user_id, post_remote_addr, post_text, post_text_format, post_display_signature + ) VALUES (?, ?, ?, INET6_ATON(?), ?, ?, ?) + SQL); $stmt->nextParameter($topicInfo); $stmt->nextParameter($categoryInfo); $stmt->nextParameter($userInfo); $stmt->nextParameter($remoteAddr); $stmt->nextParameter($body); - $stmt->nextParameter($bodyParser); + $stmt->nextParameter($bodyFormat->value); $stmt->nextParameter($displaySignature ? 1 : 0); $stmt->execute(); @@ -298,7 +324,7 @@ class ForumPostsData { ForumPostInfo|string $postInfo, ?string $remoteAddr = null, ?string $body = null, - ?int $bodyParser = null, + TextFormat|string|null $bodyFormat = null, ?bool $displaySignature = null, bool $bumpEdited = true ): void { @@ -318,9 +344,9 @@ class ForumPostsData { $values[] = $body; } - if($bodyParser !== null) { - $fields[] = 'post_parse = ?'; - $values[] = $bodyParser; + if($bodyFormat !== null) { + $fields[] = 'post_text_format = ?'; + $values[] = is_string($bodyFormat) ? TextFormat::from($bodyFormat)->value : $bodyFormat->value; } if($displaySignature !== null) { diff --git a/src/Info/InfoRoutes.php b/src/Info/InfoRoutes.php index 0e82130b..f500964a 100644 --- a/src/Info/InfoRoutes.php +++ b/src/Info/InfoRoutes.php @@ -5,7 +5,7 @@ use Index\Http\{HttpRequest,HttpResponseBuilder}; use Index\Http\Routing\{HttpGet,RouteHandler,RouteHandlerCommon}; use Index\Urls\{UrlFormat,UrlSource,UrlSourceCommon}; use Misuzu\Template; -use Misuzu\Parsers\Parser; +use Misuzu\Parsers\{Parsers,TextFormat}; class InfoRoutes implements RouteHandler, UrlSource { use RouteHandlerCommon, UrlSourceCommon; @@ -116,7 +116,7 @@ class InfoRoutes implements RouteHandler, UrlSource { if($titleFormat !== '') $title = sprintf($titleFormat, $title); - $body = Parser::instance(Parser::MARKDOWN)->parseText($body); + $body = Parsers::instance(TextFormat::Markdown)->parseText($body); return Template::renderRaw('info.view', [ 'document' => [ diff --git a/src/Messages/MessageInfo.php b/src/Messages/MessageInfo.php index f5f1d520..f5fed639 100644 --- a/src/Messages/MessageInfo.php +++ b/src/Messages/MessageInfo.php @@ -1,9 +1,9 @@ <?php namespace Misuzu\Messages; -use Misuzu\Parsers\Parser; use Carbon\CarbonImmutable; use Index\Db\DbResult; +use Misuzu\Parsers\TextFormat; class MessageInfo { public function __construct( @@ -14,7 +14,7 @@ class MessageInfo { public private(set) ?string $replyToId, public private(set) string $title, public private(set) string $body, - public private(set) int $parser, + public private(set) TextFormat $bodyFormat, public private(set) int $createdTime, public private(set) ?int $sentTime, public private(set) ?int $readTime, @@ -30,7 +30,7 @@ class MessageInfo { replyToId: $result->getStringOrNull(4), title: $result->getString(5), body: $result->getString(6), - parser: $result->getInteger(7), + bodyFormat: TextFormat::tryFrom($result->getString(7)) ?? TextFormat::Plain, createdTime: $result->getInteger(8), sentTime: $result->getIntegerOrNull(9), readTime: $result->getIntegerOrNull(10), @@ -39,15 +39,15 @@ class MessageInfo { } public bool $isBodyPlain { - get => $this->parser === Parser::PLAIN; + get => $this->bodyFormat === TextFormat::Plain; } public bool $isBodyBBCode { - get => $this->parser === Parser::BBCODE; + get => $this->bodyFormat === TextFormat::BBCode; } public bool $isBodyMarkdown { - get => $this->parser === Parser::MARKDOWN; + get => $this->bodyFormat === TextFormat::Markdown; } public CarbonImmutable $createdAt { diff --git a/src/Messages/MessagesData.php b/src/Messages/MessagesData.php index e218b669..b6a649af 100644 --- a/src/Messages/MessagesData.php +++ b/src/Messages/MessagesData.php @@ -6,6 +6,7 @@ use RuntimeException; use DateTimeInterface; use Index\Db\{DbConnection,DbStatementCache,DbTools}; use Misuzu\Pagination; +use Misuzu\Parsers\TextFormat; use Misuzu\Users\UserInfo; class MessagesData { @@ -104,7 +105,13 @@ class MessagesData { $hasPagination = $pagination !== null; $args = 0; - $query = 'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, FROM_BASE64(msg_title), FROM_BASE64(msg_body), msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages'; + $query = <<<SQL + SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, + FROM_BASE64(msg_title), FROM_BASE64(msg_body), msg_body_format, + UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), + UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) + FROM msz_messages + SQL; if($hasOwnerInfo) { ++$args; $query .= ' WHERE msg_owner_id = ?'; @@ -160,7 +167,14 @@ class MessagesData { bool $useReplyTo = false ): MessageInfo { $stmt = $this->cache->get(sprintf( - 'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, FROM_BASE64(msg_title), FROM_BASE64(msg_body), msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages WHERE msg_id = %s AND msg_owner_id = ?', + <<<SQL + SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, + FROM_BASE64(msg_title), FROM_BASE64(msg_body), msg_body_format, + UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), + UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) + FROM msz_messages + WHERE msg_id = %s AND msg_owner_id = ? + SQL, !$useReplyTo || $messageInfoOrId instanceof MessageInfo ? '?' : '(SELECT msg_reply_to FROM msz_messages WHERE msg_id = ?)' )); @@ -185,12 +199,21 @@ class MessagesData { UserInfo|string|null $recipientInfo, string $title, string $body, - int $parser, + TextFormat|string $bodyFormat, MessageInfo|string|null $replyTo = null, DateTimeInterface|int|null $sentAt = null, DateTimeInterface|int|null $readAt = null ): MessageInfo { - $stmt = $this->cache->get('INSERT INTO msz_messages (msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, msg_sent, msg_read) VALUES (?, ?, ?, ?, ?, TO_BASE64(?), TO_BASE64(?), ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))'); + if(is_string($bodyFormat)) + $bodyFormat = TextFormat::from($bodyFormat); + + $stmt = $this->cache->get(<<<SQL + INSERT INTO msz_messages ( + msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, + msg_title, msg_body, msg_body_format, + msg_sent, msg_read + ) VALUES (?, ?, ?, ?, ?, TO_BASE64(?), TO_BASE64(?), ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?)) + SQL); $stmt->nextParameter($messageId); $stmt->nextParameter($ownerInfo instanceof UserInfo ? $ownerInfo->id : $ownerInfo); $stmt->nextParameter($authorInfo instanceof UserInfo ? $authorInfo->id : $authorInfo); @@ -198,7 +221,7 @@ class MessagesData { $stmt->nextParameter($replyTo instanceof MessageInfo ? $replyTo->id : $replyTo); $stmt->nextParameter($title); $stmt->nextParameter($body); - $stmt->nextParameter($parser); + $stmt->nextParameter($bodyFormat->value); $stmt->nextParameter($sentAt instanceof DateTimeInterface ? (int)$sentAt->format('U') : $sentAt); $stmt->nextParameter($readAt instanceof DateTimeInterface ? (int)$readAt->format('U') : $readAt); $stmt->execute(); @@ -211,7 +234,7 @@ class MessagesData { MessageInfo|string|null $messageInfo = null, ?string $title = null, ?string $body = null, - ?int $parser = null, + TextFormat|string|null $bodyFormat = null, DateTimeInterface|int|null|false $sentAt = false, DateTimeInterface|int|null|false $readAt = false ): void { @@ -240,9 +263,9 @@ class MessagesData { $setValues[] = $body; } - if($parser !== null) { - $setQuery[] = 'msg_parser = ?'; - $setValues[] = $parser; + if($bodyFormat !== null) { + $setQuery[] = 'msg_body_format = ?'; + $setValues[] = is_string($bodyFormat) ? TextFormat::from($bodyFormat)->value : $bodyFormat->value; } if($sentAt !== false) { diff --git a/src/Messages/MessagesRoutes.php b/src/Messages/MessagesRoutes.php index fec94943..f0da0f1d 100644 --- a/src/Messages/MessagesRoutes.php +++ b/src/Messages/MessagesRoutes.php @@ -12,7 +12,7 @@ use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler,RouteHandle use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon}; use Misuzu\{CSRF,Pagination,Perm,Template}; use Misuzu\Auth\AuthInfo; -use Misuzu\Parsers\Parser; +use Misuzu\Parsers\TextFormat; use Misuzu\Perms\PermissionsData; use Misuzu\Users\{UsersContext,UserInfo}; @@ -295,12 +295,12 @@ class MessagesRoutes implements RouteHandler, UrlSource { } /** @return ?array{error: array{name: string, text: string, args?: scalar[]}} */ - private function checkMessageFields(string $title, string $body, int $parser): ?array { - if(!Parser::isValid($parser)) + private function checkMessageFields(string $title, string $body, ?TextFormat $format): ?array { + if($format === null) return [ 'error' => [ - 'name' => 'msgs:invalid_parser', - 'text' => 'Invalid parser selected.', + 'name' => 'msgs:invalid_format', + 'text' => 'Invalid format selected.', ], ]; @@ -368,10 +368,10 @@ class MessagesRoutes implements RouteHandler, UrlSource { $replyTo = (string)$request->content->getParam('reply'); $title = (string)$request->content->getParam('title'); $body = (string)$request->content->getParam('body'); - $parser = (int)$request->content->getParam('parser', FILTER_SANITIZE_NUMBER_INT); + $format = TextFormat::tryFrom((string)$request->content->getParam('format')); $draft = !empty($request->content->getParam('draft')); - $error = $this->checkMessageFields($title, $body, $parser); + $error = $this->checkMessageFields($title, $body, $format); if($error !== null) return $error; @@ -433,7 +433,7 @@ class MessagesRoutes implements RouteHandler, UrlSource { recipientInfo: $recipientInfo, title: $title, body: $body, - parser: $parser, + bodyFormat: $format, replyTo: $replyToInfo, sentAt: $sentAt ); @@ -447,7 +447,7 @@ class MessagesRoutes implements RouteHandler, UrlSource { recipientInfo: $recipientInfo, title: $title, body: $body, - parser: $parser, + bodyFormat: $format, replyTo: $replyToInfo, sentAt: $sentAt ); @@ -470,10 +470,10 @@ class MessagesRoutes implements RouteHandler, UrlSource { $title = (string)$request->content->getParam('title'); $body = (string)$request->content->getParam('body'); - $parser = (int)$request->content->getParam('parser', FILTER_SANITIZE_NUMBER_INT); + $format = TextFormat::tryFrom((string)$request->content->getParam('format')); $draft = !empty($request->content->getParam('draft')); - $error = $this->checkMessageFields($title, $body, $parser); + $error = $this->checkMessageFields($title, $body, $format); if($error !== null) return $error; @@ -526,7 +526,7 @@ class MessagesRoutes implements RouteHandler, UrlSource { messageInfo: $messageInfo, title: $title, body: $body, - parser: $parser, + bodyFormat: $format, sentAt: $sentAt, ); @@ -539,7 +539,7 @@ class MessagesRoutes implements RouteHandler, UrlSource { recipientInfo: $messageInfo->recipientId, title: $title, body: $body, - parser: $parser, + bodyFormat: $format, replyTo: $messageInfo->replyToId, sentAt: $sentAt ); diff --git a/src/News/NewsRoutes.php b/src/News/NewsRoutes.php index 6343348b..5a32c9a9 100644 --- a/src/News/NewsRoutes.php +++ b/src/News/NewsRoutes.php @@ -10,7 +10,7 @@ use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon}; use Misuzu\{Pagination,SiteInfo,Template}; use Misuzu\Auth\AuthInfo; use Misuzu\Comments\{CommentsData,CommentsCategory,CommentsEx}; -use Misuzu\Parsers\Parser; +use Misuzu\Parsers\{Parsers,TextFormat}; use Misuzu\Users\{UsersContext,UserInfo}; class NewsRoutes implements RouteHandler, UrlSource { @@ -210,7 +210,7 @@ class NewsRoutes implements RouteHandler, UrlSource { $userInfo = $post['user']; $item->title = $postInfo->title; - $item->description = Parser::instance(Parser::MARKDOWN)->parseText($postInfo->body); + $item->description = Parsers::instance(TextFormat::Markdown)->parseText($postInfo->body); $item->createdAt = $postInfo->createdTime; $item->contentUrl = $siteUrl . $this->urls->format('news-post', ['post' => $postInfo->id]); $item->commentsUrl = $siteUrl . $this->urls->format('news-post-comments', ['post' => $postInfo->id]); diff --git a/src/Parsers/Parser.php b/src/Parsers/Parser.php deleted file mode 100644 index 02586858..00000000 --- a/src/Parsers/Parser.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -namespace Misuzu\Parsers; - -use InvalidArgumentException; -use Misuzu\Parsers\BBCode\BBCodeParser; - -final class Parser { - public const PLAIN = 0; - public const BBCODE = 1; - public const MARKDOWN = 2; - - private const PARSERS = [ - self::PLAIN => PlainParser::class, - self::BBCODE => BBCodeParser::class, - self::MARKDOWN => MarkdownParser::class, - ]; - public const NAMES = [ - self::PLAIN => 'Plain text', - self::BBCODE => 'BB Code', - self::MARKDOWN => 'Markdown', - ]; - - /** @var array<int, ParserInterface> */ - private static $instances = []; - - public static function isValid(int $parser): bool { - return array_key_exists($parser, self::PARSERS); - } - - public static function name(int $parser): string { - return self::isValid($parser) ? self::NAMES[$parser] : ''; - } - - public static function instance(int $parser): ParserInterface { - if(!self::isValid($parser)) - throw new InvalidArgumentException('Invalid parser.'); - - if(!isset(self::$instances[$parser])) { - $className = self::PARSERS[$parser]; - self::$instances[$parser] = new $className; - } - - return self::$instances[$parser]; - } -} diff --git a/src/Parsers/Parsers.php b/src/Parsers/Parsers.php new file mode 100644 index 00000000..c0d4498e --- /dev/null +++ b/src/Parsers/Parsers.php @@ -0,0 +1,21 @@ +<?php +namespace Misuzu\Parsers; + +final class Parsers { + /** @var array<int, ParserInterface> */ + private static array $instances = []; + + public static function instance(TextFormat|string $format): ParserInterface { + if(is_string($format)) + $format = TextFormat::from($format); + + if(!array_key_exists($format->value, self::$instances)) + self::$instances[$format->value] = match($format) { + TextFormat::Plain => new PlainParser, + TextFormat::BBCode => new BBCode\BBCodeParser, + TextFormat::Markdown => new MarkdownParser, + }; + + return self::$instances[$format->value]; + } +} diff --git a/src/Parsers/TextFormat.php b/src/Parsers/TextFormat.php new file mode 100644 index 00000000..ead63aae --- /dev/null +++ b/src/Parsers/TextFormat.php @@ -0,0 +1,8 @@ +<?php +namespace Misuzu\Parsers; + +enum TextFormat: string { + case Plain = ''; + case BBCode = 'bb'; + case Markdown = 'md'; +} diff --git a/src/TemplatingExtension.php b/src/TemplatingExtension.php index 19e1c297..f4c91de5 100644 --- a/src/TemplatingExtension.php +++ b/src/TemplatingExtension.php @@ -2,10 +2,10 @@ namespace Misuzu; use DateTimeInterface; +use Carbon\CarbonImmutable; use Misuzu\MisuzuContext; use Misuzu\Tools; -use Misuzu\Parsers\Parser; -use Carbon\CarbonImmutable; +use Misuzu\Parsers\{Parsers,TextFormat}; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; use Twig\TwigFunction; @@ -22,7 +22,8 @@ final class TemplatingExtension extends AbstractExtension { public function getFilters() { return [ new TwigFilter('country_name', Tools::countryName(...)), - new TwigFilter('parse_text', fn(string $text, int $parser): string => Parser::instance($parser)->parseText($text)), + new TwigFilter('parse_text', fn(string $text, TextFormat|string $parser): string => Parsers::instance($parser)->parseText($text)), + new TwigFilter('parse_md', fn(string $text): string => Parsers::instance(TextFormat::Markdown)->parseText($text)), new TwigFilter('time_format', $this->timeFormat(...)), ]; } @@ -41,6 +42,13 @@ final class TemplatingExtension extends AbstractExtension { new TwigFunction('msz_header_menu', $this->getHeaderMenu(...)), new TwigFunction('msz_user_menu', $this->getUserMenu(...)), new TwigFunction('msz_manage_menu', $this->getManageMenu(...)), + new TwigFunction('parser_options', function() { + return [ + TextFormat::Plain->value => 'Plain text', + TextFormat::BBCode->value => 'BB Code', + TextFormat::Markdown->value => 'Markdown', + ]; + }), ]; } diff --git a/src/Users/UserInfo.php b/src/Users/UserInfo.php index 7909e50b..201d964a 100644 --- a/src/Users/UserInfo.php +++ b/src/Users/UserInfo.php @@ -1,10 +1,10 @@ <?php namespace Misuzu\Users; -use Misuzu\Parsers\Parser; use Carbon\CarbonImmutable; use Index\Colour\Colour; use Index\Db\DbResult; +use Misuzu\Parsers\TextFormat; class UserInfo { public function __construct( @@ -22,9 +22,9 @@ class UserInfo { public private(set) ?int $deletedTime, public private(set) ?string $displayRoleId, public private(set) ?string $aboutBody, - public private(set) int $aboutBodyParser, + public private(set) TextFormat $aboutBodyFormat, public private(set) ?string $signatureBody, - public private(set) int $signatureBodyParser, + public private(set) TextFormat $signatureBodyFormat, public private(set) ?int $backgroundSettings, public private(set) ?string $title, ) {} @@ -45,9 +45,9 @@ class UserInfo { deletedTime: $result->getIntegerOrNull(11), displayRoleId: $result->getStringOrNull(12), aboutBody: $result->getStringOrNull(13), - aboutBodyParser: $result->getInteger(14), + aboutBodyFormat: TextFormat::tryFrom($result->getString(14)) ?? TextFormat::Plain, signatureBody: $result->getStringOrNull(15), - signatureBodyParser: $result->getInteger(16), + signatureBodyFormat: TextFormat::tryFrom($result->getString(16)) ?? TextFormat::Plain, backgroundSettings: $result->getIntegerOrNull(17), title: $result->getString(18), ); @@ -90,26 +90,26 @@ class UserInfo { } public bool $isAboutBodyPlain { - get => $this->aboutBodyParser === Parser::PLAIN; + get => $this->aboutBodyFormat === TextFormat::Plain; } public bool $isAboutBodyBBCode { - get => $this->aboutBodyParser === Parser::BBCODE; + get => $this->aboutBodyFormat === TextFormat::BBCode; } public bool $isAboutBodyMarkdown { - get => $this->aboutBodyParser === Parser::MARKDOWN; + get => $this->aboutBodyFormat === TextFormat::Markdown; } public bool $isSignatureBodyPlain { - get => $this->signatureBodyParser === Parser::PLAIN; + get => $this->signatureBodyFormat === TextFormat::Plain; } public bool $isSignatureBodyBBCode { - get => $this->signatureBodyParser === Parser::BBCODE; + get => $this->signatureBodyFormat === TextFormat::BBCode; } public bool $isSignatureBodyMarkdown { - get => $this->signatureBodyParser === Parser::MARKDOWN; + get => $this->signatureBodyFormat === TextFormat::Markdown; } } diff --git a/src/Users/UsersData.php b/src/Users/UsersData.php index d58ce9e7..c98d0c41 100644 --- a/src/Users/UsersData.php +++ b/src/Users/UsersData.php @@ -9,7 +9,7 @@ use Index\Colour\Colour; use Index\Db\{DbConnection,DbStatementCache,DbTools}; use Misuzu\Pagination; use Misuzu\Tools; -use Misuzu\Parsers\Parser; +use Misuzu\Parsers\Parsers; class UsersData { private DbStatementCache $cache; @@ -177,8 +177,8 @@ class UsersData { UNIX_TIMESTAMP(u.user_active), UNIX_TIMESTAMP(u.user_deleted), u.user_display_role_id, - u.user_about_content, u.user_about_parser, - u.user_signature_content, u.user_signature_parser, + u.user_about_content, u.user_about_content_format, + u.user_signature_content, u.user_signature_content_format, u.user_background_settings, u.user_title FROM msz_users AS u SQL; @@ -286,8 +286,8 @@ class UsersData { UNIX_TIMESTAMP(user_active), UNIX_TIMESTAMP(user_deleted), user_display_role_id, - user_about_content, user_about_parser, - user_signature_content, user_signature_parser, + user_about_content, user_about_content_format, + user_signature_content, user_signature_content_format, user_background_settings, user_title FROM msz_users SQL; @@ -358,9 +358,9 @@ class UsersData { ?Colour $colour = null, RoleInfo|string|null $displayRoleInfo = null, ?string $aboutBody = null, - ?int $aboutBodyParser = null, + ?int $aboutBodyFormat = null, ?string $signatureBody = null, - ?int $signatureBodyParser = null, + ?int $signatureBodyFormat = null, ?int $backgroundSettings = null, ?string $title = null ): void { @@ -408,24 +408,24 @@ class UsersData { $values[] = $displayRoleInfo; } - if($aboutBody !== null && $aboutBodyParser !== null) { - if(self::validateProfileAbout($aboutBodyParser, $aboutBody) !== '') - throw new InvalidArgumentException('$aboutBody and $aboutBodyParser contain invalid data!'); + if($aboutBody !== null && $aboutBodyFormat !== null) { + if(self::validateProfileAbout($aboutBodyFormat, $aboutBody) !== '') + throw new InvalidArgumentException('$aboutBody and $aboutBodyFormat contain invalid data!'); $fields[] = 'user_about_content = ?'; $values[] = $aboutBody; - $fields[] = 'user_about_parser = ?'; - $values[] = $aboutBodyParser; + $fields[] = 'user_about_content_format = ?'; + $values[] = $aboutBodyFormat; } - if($signatureBody !== null && $signatureBodyParser !== null) { - if(self::validateForumSignature($signatureBodyParser, $signatureBody) !== '') - throw new InvalidArgumentException('$signatureBody and $signatureBodyParser contain invalid data!'); + if($signatureBody !== null && $signatureBodyFormat !== null) { + if(self::validateForumSignature($signatureBodyFormat, $signatureBody) !== '') + throw new InvalidArgumentException('$signatureBody and $signatureBodyFormat contain invalid data!'); $fields[] = 'user_signature_content = ?'; $values[] = $signatureBody; - $fields[] = 'user_signature_parser = ?'; - $values[] = $signatureBodyParser; + $fields[] = 'user_signature_content_format = ?'; + $values[] = $signatureBodyFormat; } if($backgroundSettings !== null) { @@ -710,7 +710,7 @@ class UsersData { } public static function validateProfileAbout(int $parser, string $text): string { - if(!Parser::isValid($parser)) + if(!Parsers::isValid($parser)) return 'parser'; $length = strlen($text); @@ -730,7 +730,7 @@ class UsersData { } public static function validateForumSignature(int $parser, string $text): string { - if(!Parser::isValid($parser)) + if(!Parsers::isValid($parser)) return 'parser'; $length = strlen($text); diff --git a/templates/_layout/input.twig b/templates/_layout/input.twig index 13f2f3ff..27f60d27 100644 --- a/templates/_layout/input.twig +++ b/templates/_layout/input.twig @@ -85,7 +85,7 @@ {% macro input_select_option(value, key, selected) %} {% apply spaceless %} - <option{% if key|length > 0 %} value="{{ key }}"{% endif %}{% if selected %} selected{% endif %}> + <option{% if key is not null %} value="{{ key }}"{% endif %}{% if selected %} selected{% endif %}> {{ value }} </option> {% endapply %} @@ -101,7 +101,7 @@ {% endfor %}> {% for key, value in options %} {% set option_value = value_name|length > 0 ? value[value_name] : value %} - {% set option_key = only_values ? '' : (key_name|length > 0 ? value[key_name] : key) %} + {% set option_key = only_values ? null : (key_name|length > 0 ? value[key_name] : key) %} {{ input_select_option(option_value, option_key, option_key|default(option_value) == selected) }} {% endfor %} </select> diff --git a/templates/changelog/change.twig b/templates/changelog/change.twig index 5455b446..cecb46e3 100644 --- a/templates/changelog/change.twig +++ b/templates/changelog/change.twig @@ -60,7 +60,7 @@ <h1>{{ title }}</h1> {% if change_info.body is not empty %} - {{ change_info.body|escape|parse_text(2)|raw }} + {{ change_info.body|escape|parse_md|raw }} {% else %} <p>This change has no additional notes.</p> {% endif %} diff --git a/templates/forum/macros.twig b/templates/forum/macros.twig index c0aef375..49acd475 100644 --- a/templates/forum/macros.twig +++ b/templates/forum/macros.twig @@ -466,7 +466,7 @@ {% set post_edited = post.info.editedTime %} {% set post_is_deleted = post.info.deleted %} {% set post_is_op = post.isOriginalPost %} - {% set post_body = post.info.body|escape|parse_text(post.info.parser) %} + {% set post_body = post.info.body|escape|parse_text(post.info.bodyFormat) %} {% set post_is_markdown = post.info.isBodyMarkdown %} {% set post_show_signature = post.info.shouldDisplaySignature %} {% set post_can_be_deleted = post.info.canBeDeleted %} @@ -482,7 +482,7 @@ {% set author_created = post.user.createdTime %} {% set author_posts_count = post.postsCount %} {% set author_is_op = post.isOriginalPoster %} - {% set signature_body = post.user.signatureBody|default('')|escape|parse_text(post.user.signatureBodyParser) %} + {% set signature_body = post.user.signatureBody|default('')|escape|parse_text(post.user.signatureBodyFormat) %} {% set signature_is_markdown = post.user.isSignatureBodyMarkdown %} {% endif %} diff --git a/templates/forum/posting.twig b/templates/forum/posting.twig index af330ef8..e56cbf22 100644 --- a/templates/forum/posting.twig +++ b/templates/forum/posting.twig @@ -80,9 +80,8 @@ <div class="forum__post__options"> <div class="forum__post__settings"> {{ input_select( - 'post[parser]', - constant('\\Misuzu\\Parsers\\Parser::NAMES'), - posting_defaults.parser|default(posting_post.info.parser|default(posting_user_preferred_parser)), + 'post[parser]', parser_options(), + posting_defaults.parser|default(posting_post.info.bodyFormat|default(posting_user_preferred_parser)).value, null, null, false, 'forum__post__dropdown js-forum-posting-parser' ) }} {% if is_opening and posting_types|length > 1 %} diff --git a/templates/home/landing.twig b/templates/home/landing.twig index 9ffcef4b..59908cad 100644 --- a/templates/home/landing.twig +++ b/templates/home/landing.twig @@ -169,7 +169,7 @@ {% for post in featured_news %} <div class="landingv2-news-post markdown"> <h1>{{ post.title }}</h1> - <p>{{ post.firstParagraph|escape|parse_text(2)|raw }}</p> + <p>{{ post.firstParagraph|escape|parse_md|raw }}</p> <div class="landingv2-news-post-options"> <a href="{{ url('news-post', {'post': post.id}) }}" class="landingv2-news-post-option">Continue reading</a> | <time datetime="{{ post.createdTime|date('c') }}" title="{{ post.createdTime|date('r') }}">{{ post.createdTime|time_format }}</time> diff --git a/templates/manage/users/note.twig b/templates/manage/users/note.twig index 9160d8e3..89145f78 100644 --- a/templates/manage/users/note.twig +++ b/templates/manage/users/note.twig @@ -57,7 +57,7 @@ {% if not note_new and note_info.body is not empty %} <div class="manage__note__body markdown manage__note--viewing"> - {{ note_info.body|escape|parse_text(2)|raw }} + {{ note_info.body|escape|parse_md|raw }} </div> {% else %} <div class="manage__note__nobody manage__note--viewing"> diff --git a/templates/manage/users/notes.twig b/templates/manage/users/notes.twig index c0f8d510..2b18958f 100644 --- a/templates/manage/users/notes.twig +++ b/templates/manage/users/notes.twig @@ -71,9 +71,9 @@ {% if note.info.body is not empty %} <div class="manage__notes__item__body markdown"> {% if notes_filtering %} - {{ note.info.body|escape|parse_text(2)|raw }} + {{ note.info.body|escape|parse_md|raw }} {% else %} - {{ note.info.firstParagraph|escape|parse_text(2)|raw }} + {{ note.info.firstParagraph|escape|parse_md|raw }} {% endif %} </div> {% else %} diff --git a/templates/messages/compose.twig b/templates/messages/compose.twig index e32b206d..9977f765 100644 --- a/templates/messages/compose.twig +++ b/templates/messages/compose.twig @@ -28,7 +28,7 @@ <div class="warning"> <div class="warning__content"> - <p>UI is VERY not final. It will be not awful before 2025 I promise for real this time!!!</p> + <p>UI is VERY not final. It will be not awful before <del>2025</del> 2026 I promise for real this time!!!</p> <p>I need to clean up a lot of code first because a lot of things are specifically written for the forum editor and it will become a big mess otherwise.</p> </div> </div> @@ -54,7 +54,7 @@ <div class="messages-reply-actions js-messages-reply-actions" hidden></div> <div class="messages-reply-options"> <div class="messages-reply-settings"> - {{ input_select('parser', constant('\\Misuzu\\Parsers\\Parser::NAMES'), '1', null, null, null, 'js-messages-reply-parser') }} + {{ input_select('format', parser_options(), 'bb', null, null, null, 'js-messages-reply-parser') }} </div> <div class="messages-reply-buttons"> <button class="input__button js-messages-reply-save" name="draft" value="1">Save draft</button> diff --git a/templates/messages/thread.twig b/templates/messages/thread.twig index 6443e974..229f8963 100644 --- a/templates/messages/thread.twig +++ b/templates/messages/thread.twig @@ -92,7 +92,7 @@ <div class="messages-message-subject"> <h1>{{ message.info.title }}</h1> </div> - <div class="messages-message-body{% if message.info.isBodyMarkdown %} markdown{% endif %}">{{ message.info.body|escape|parse_text(message.info.parser)|raw }}</div> + <div class="messages-message-body{% if message.info.isBodyMarkdown %} markdown{% endif %}">{{ message.info.body|escape|parse_text(message.info.bodyFormat)|raw }}</div> </article> {% if can_send_messages %} @@ -127,7 +127,7 @@ <div class="messages-reply-actions js-messages-reply-actions" hidden></div> <div class="messages-reply-options"> <div class="messages-reply-settings"> - {{ input_select('parser', constant('\\Misuzu\\Parsers\\Parser::NAMES'), draft_info.parser|default('1'), null, null, null, 'js-messages-reply-parser') }} + {{ input_select('format', parser_options(), draft_info.bodyFormat.value|default('bb'), null, null, null, 'js-messages-reply-parser') }} </div> <div class="messages-reply-buttons"> <button class="input__button js-messages-reply-save" name="draft" value="1">Save draft</button> diff --git a/templates/news/macros.twig b/templates/news/macros.twig index eca74d4a..23af4ea6 100644 --- a/templates/news/macros.twig +++ b/templates/news/macros.twig @@ -36,7 +36,7 @@ </div> <div class="news__preview__content markdown"> <div class="news__preview__text"> - {{ post.post.firstParagraph|escape|parse_text(2)|raw }} + {{ post.post.firstParagraph|escape|parse_md|raw }} </div> <div class="news__preview__links"> <a href="{{ url('news-post', {'post': post.post.id}) }}" class="news__preview__link">Continue reading</a> @@ -91,7 +91,7 @@ <div class="news__post__text markdown"> <h1>{{ post.title }}</h1> - {{ post.body|escape|parse_text(2)|raw }} + {{ post.body|escape|parse_md|raw }} </div> </div> {% endmacro %} diff --git a/templates/profile/index.twig b/templates/profile/index.twig index adaa190e..889809b3 100644 --- a/templates/profile/index.twig +++ b/templates/profile/index.twig @@ -266,12 +266,12 @@ {% if profile_is_editing %} <div class="profile__signature__editor"> - {{ input_select('about[parser]', constant('\\Misuzu\\Parsers\\Parser::NAMES'), profile_user.aboutBodyParser, '', '', false, 'profile__about__select') }} + {{ input_select('about[parser]', parser_options(), profile_user.aboutBodyFormat.value, '', '', false, 'profile__about__select') }} <textarea name="about[text]" class="input__textarea profile__about__text" id="about-textarea">{{ profile_user.aboutBody }}</textarea> </div> {% else %} <div class="profile__about__content{% if profile_is_editing %} profile__about__content--edit{% elseif profile_user.isAboutBodyMarkdown %} markdown{% endif %}"> - {{ profile_user.aboutBody|escape|parse_text(profile_user.aboutBodyParser)|raw }} + {{ profile_user.aboutBody|escape|parse_text(profile_user.aboutBodyFormat)|raw }} </div> {% endif %} </div> @@ -283,12 +283,12 @@ {% if profile_is_editing %} <div class="profile__signature__editor"> - {{ input_select('signature[parser]', constant('\\Misuzu\\Parsers\\Parser::NAMES'), profile_user.signatureBodyParser, '', '', false, 'profile__signature__select') }} + {{ input_select('signature[parser]', parser_options(), profile_user.signatureBodyFormat.value, '', '', false, 'profile__signature__select') }} <textarea name="signature[text]" class="input__textarea profile__signature__text" id="signature-textarea">{{ profile_user.signatureBody }}</textarea> </div> {% else %} <div class="profile__signature__content{% if profile_is_editing %} profile__signature__content--edit{% elseif profile_user.isSignatureBodyMarkdown %} markdown{% endif %}"> - {{ profile_user.signatureBody|escape|parse_text(profile_user.signatureBodyParser)|raw }} + {{ profile_user.signatureBody|escape|parse_text(profile_user.signatureBodyFormat)|raw }} </div> {% endif %} </div> diff --git a/tools/cron b/tools/cron index e1983430..0d28187f 100755 --- a/tools/cron +++ b/tools/cron @@ -113,9 +113,9 @@ msz_sched_task_func('Resync statistics counters.', true, function() use ($msz) { 'forum:posts:visible' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_deleted IS NULL', 'forum:posts:deleted' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_deleted IS NOT NULL', 'forum:posts:edited' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_edited IS NOT NULL', - 'forum:posts:parse:plain' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_parse = 0', - 'forum:posts:parse:bbcode' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_parse = 1', - 'forum:posts:parse:markdown' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_parse = 2', + 'forum:posts:parse:plain' => "SELECT COUNT(*) FROM msz_forum_posts WHERE post_text_format = ''", + 'forum:posts:parse:bbcode' => "SELECT COUNT(*) FROM msz_forum_posts WHERE post_text_format = 'bb'", + 'forum:posts:parse:markdown' => "SELECT COUNT(*) FROM msz_forum_posts WHERE post_text_format = 'md'", 'forum:posts:signature' => 'SELECT COUNT(*) FROM msz_forum_posts WHERE post_display_signature <> 0', 'forum:topics:total' => 'SELECT COUNT(*) FROM msz_forum_topics', 'forum:topics:type:normal' => 'SELECT COUNT(*) FROM msz_forum_topics WHERE topic_type = 0', @@ -141,9 +141,9 @@ msz_sched_task_func('Resync statistics counters.', true, function() use ($msz) { 'pms:msgs:drafts' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_sent IS NULL', 'pms:msgs:unread' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_read IS NULL', 'pms:msgs:deleted' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_deleted IS NOT NULL', - 'pms:msgs:plain' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_parser = 0', - 'pms:msgs:bbcode' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_parser = 1', - 'pms:msgs:markdown' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_parser = 2', + 'pms:msgs:plain' => "SELECT COUNT(*) FROM msz_messages WHERE msg_body_format = ''", + 'pms:msgs:bbcode' => "SELECT COUNT(*) FROM msz_messages WHERE msg_body_format = 'bb'", + 'pms:msgs:markdown' => "SELECT COUNT(*) FROM msz_messages WHERE msg_body_format = 'md'", ]; foreach($stats as $name => $query) {