misuzu/public-legacy/forum/posting.php
flash 383e2ed0e0 Rewrote the user information class.
This one took multiple days and it pretty invasive into the core of Misuzu so issue might (will) arise, there's also some features that have gone temporarily missing in the mean time and some inefficiencies introduced that will be fixed again at a later time.
The old class isn't gone entirely because I still have to figure out what I'm gonna do about validation, but for the most part this knocks out one of the "layers of backwards compatibility", as I've been referring to it, and is moving us closer to a future where Flashii actually gets real updates.
If you run into anything that's broken and you're inhibited from reporting it through the forum, do it through chat or mail me at flashii-issues@flash.moe.
2023-08-02 22:12:47 +00:00

272 lines
8.8 KiB
PHP

<?php
namespace Misuzu;
use Misuzu\Parsers\Parser;
if(!$msz->isLoggedIn()) {
echo render_error(401);
return;
}
$currentUser = $msz->getActiveUser();
$currentUserId = $currentUser->getId();
if($msz->hasActiveBan()) {
echo render_error(403);
return;
}
$forumPostingModes = [
'create', 'edit', 'quote', 'preview',
];
if(!empty($_POST)) {
$mode = !empty($_POST['post']['mode']) && is_string($_POST['post']['mode']) ? $_POST['post']['mode'] : 'create';
$postId = !empty($_POST['post']['id']) && is_string($_POST['post']['id']) ? (int)$_POST['post']['id'] : 0;
$topicId = !empty($_POST['post']['topic']) && is_string($_POST['post']['topic']) ? (int)$_POST['post']['topic'] : 0;
$forumId = !empty($_POST['post']['forum']) && is_string($_POST['post']['forum']) ? (int)$_POST['post']['forum'] : 0;
} else {
$mode = !empty($_GET['m']) && is_string($_GET['m']) ? $_GET['m'] : 'create';
$postId = !empty($_GET['p']) && is_string($_GET['p']) ? (int)$_GET['p'] : 0;
$topicId = !empty($_GET['t']) && is_string($_GET['t']) ? (int)$_GET['t'] : 0;
$forumId = !empty($_GET['f']) && is_string($_GET['f']) ? (int)$_GET['f'] : 0;
}
if(!in_array($mode, $forumPostingModes, true)) {
echo render_error(400);
return;
}
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)) {
echo render_error(404);
return;
}
if(!empty($postId)) {
$post = forum_post_get($postId);
if(isset($post['topic_id'])) { // should automatic cross-quoting be a thing? if so, check if $topicId is < 1 first
$topicId = (int)$post['topic_id'];
}
}
if(!empty($topicId)) {
$topic = forum_topic_get($topicId);
if(isset($topic['forum_id'])) {
$forumId = (int)$topic['forum_id'];
}
}
if(!empty($forumId)) {
$forum = forum_get($forumId);
}
if(empty($forum)) {
echo render_error(404);
return;
}
$perms = forum_perms_get_user($forum['forum_id'], $currentUserId)[MSZ_FORUM_PERMS_GENERAL];
if($forum['forum_archived']
|| (!empty($topic['topic_locked']) && !perms_check($perms, MSZ_FORUM_PERM_LOCK_TOPIC))
|| !perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM | MSZ_FORUM_PERM_CREATE_POST)
|| (empty($topic) && !perms_check($perms, MSZ_FORUM_PERM_CREATE_TOPIC))) {
echo render_error(403);
return;
}
if(!forum_may_have_topics($forum['forum_type'])) {
echo render_error(400);
return;
}
$topicTypes = [];
if($mode === 'create' || $mode === 'edit') {
$topicTypes[MSZ_TOPIC_TYPE_DISCUSSION] = 'Normal discussion';
if(perms_check($perms, MSZ_FORUM_PERM_STICKY_TOPIC)) {
$topicTypes[MSZ_TOPIC_TYPE_STICKY] = 'Sticky topic';
}
if(perms_check($perms, MSZ_FORUM_PERM_ANNOUNCE_TOPIC)) {
$topicTypes[MSZ_TOPIC_TYPE_ANNOUNCEMENT] = 'Announcement';
}
if(perms_check($perms, MSZ_FORUM_PERM_GLOBAL_ANNOUNCE_TOPIC)) {
$topicTypes[MSZ_TOPIC_TYPE_GLOBAL_ANNOUNCEMENT] = 'Global Announcement';
}
}
// edit mode stuff
if($mode === 'edit') {
if(empty($post)) {
echo render_error(404);
return;
}
if(!perms_check($perms, $post['poster_id'] === $currentUserId ? MSZ_FORUM_PERM_EDIT_POST : MSZ_FORUM_PERM_EDIT_ANY_POST)) {
echo render_error(403);
return;
}
}
$notices = [];
if(!empty($_POST)) {
$topicTitle = $_POST['post']['title'] ?? '';
$postText = $_POST['post']['text'] ?? '';
$postParser = (int)($_POST['post']['parser'] ?? Parser::BBCODE);
$topicType = isset($_POST['post']['type']) ? (int)$_POST['post']['type'] : null;
$postSignature = isset($_POST['post']['signature']);
if(!CSRF::validateRequest()) {
$notices[] = 'Could not verify request.';
} else {
$isEditingTopic = empty($topic) || ($mode === 'edit' && $post['is_opening_post']);
if($mode === 'create') {
$timeoutCheck = max(1, forum_timeout($forumId, $currentUserId));
if($timeoutCheck < 5) {
$notices[] = sprintf("You're posting too quickly! Please wait %s seconds before posting again.", number_format($timeoutCheck));
$notices[] = "It's possible that your post went through successfully and you pressed the submit button twice by accident.";
}
}
if($isEditingTopic) {
$originalTopicTitle = $topic['topic_title'] ?? null;
$topicTitleChanged = $topicTitle !== $originalTopicTitle;
$originalTopicType = (int)($topic['topic_type'] ?? MSZ_TOPIC_TYPE_DISCUSSION);
$topicTypeChanged = $topicType !== null && $topicType !== $originalTopicType;
switch(forum_validate_title($topicTitle)) {
case 'too-short':
$notices[] = 'Topic title was too short.';
break;
case 'too-long':
$notices[] = 'Topic title was too long.';
break;
}
if($mode === 'create' && $topicType === null) {
$topicType = array_key_first($topicTypes);
} elseif(!array_key_exists($topicType, $topicTypes) && $topicTypeChanged) {
$notices[] = 'You are not allowed to set this topic type.';
}
}
if(!Parser::isValid($postParser)) {
$notices[] = 'Invalid parser selected.';
}
switch(forum_validate_post($postText)) {
case 'too-short':
$notices[] = 'Post content was too short.';
break;
case 'too-long':
$notices[] = 'Post content was too long.';
break;
}
if(empty($notices)) {
switch($mode) {
case 'create':
if(!empty($topic)) {
forum_topic_bump($topic['topic_id']);
} else {
$topicId = forum_topic_create(
$forum['forum_id'],
$currentUserId,
$topicTitle,
$topicType
);
}
$postId = forum_post_create(
$topicId,
$forum['forum_id'],
$currentUserId,
$_SERVER['REMOTE_ADDR'],
$postText,
$postParser,
$postSignature
);
forum_topic_mark_read($currentUserId, $topicId, $forum['forum_id']);
forum_count_increase($forum['forum_id'], empty($topic));
break;
case 'edit':
$markUpdated = $post['poster_id'] === $currentUserId
&& $post['post_created_unix'] < strtotime('-1 minutes')
&& $postText !== $post['post_text'];
if(!forum_post_update($postId, $_SERVER['REMOTE_ADDR'], $postText, $postParser, $postSignature, $markUpdated)) {
$notices[] = 'Post edit failed.';
}
if($isEditingTopic && ($topicTitleChanged || $topicTypeChanged)) {
if(!forum_topic_update($topicId, $topicTitle, $topicType)) {
$notices[] = 'Topic update failed.';
}
}
break;
}
if(empty($notices)) {
$redirect = url(empty($topic) ? 'forum-topic' : 'forum-post', [
'topic' => $topicId ?? 0,
'post' => $postId ?? 0,
'post_fragment' => 'p' . ($postId ?? 0),
]);
redirect($redirect);
return;
}
}
}
}
if(!empty($topic)) {
Template::set('posting_topic', $topic);
}
if($mode === 'edit') { // $post is pretty much sure to be populated at this point
Template::set('posting_post', $post);
}
$displayInfo = forum_posting_info($currentUserId);
Template::render('forum.posting', [
'posting_breadcrumbs' => forum_get_breadcrumbs($forumId),
'global_accent_colour' => forum_get_colour($forumId),
'posting_forum' => $forum,
'posting_info' => $displayInfo,
'posting_notices' => $notices,
'posting_mode' => $mode,
'posting_types' => $topicTypes,
'posting_defaults' => [
'title' => $topicTitle ?? null,
'type' => $topicType ?? null,
'text' => $postText ?? null,
'parser' => $postParser ?? null,
'signature' => $postSignature ?? null,
],
]);