This repository has been archived on 2021-07-02. You can view files and clone it, but cannot push or open issues or pull requests.
chie/public/topic.php

278 lines
13 KiB
PHP

<?php
require_once '../startup.php';
include_once '_category.php';
include_once '_topics.php';
include_once '_posts.php';
include_once '_user.php';
include_once '_track.php';
$topicId = isset($_GET['id']) && is_string($_GET['id']) && ctype_digit($_GET['id']) ? (int)$_GET['id'] : 0;
$topicInfo = topic_info($topicId);
if(empty($topicInfo['topic_bumped'])) {
die_ex('Topic not found.', 404);
}
$categoryInfo = category_info($topicInfo['cat_id']);
$isFeatureReqs = $categoryInfo['cat_variation'] == 1;
$userInfo = user_info(current_user_id());
$userActive = !empty($userInfo);
$isLocked = !empty($topicInfo['topic_locked']);
$isResolved = !empty($topicInfo['topic_resolved']);
$isConfirmed = !empty($topicInfo['topic_confirmed']);
$canLock = $userActive && $userInfo['user_moderator'];
$canResolve = $userActive && ($userInfo['user_moderator'] || (!$isLocked && $isFeatureReqs == 0 && $userInfo['user_id'] == $topicInfo['user_id']));
$canConfirm = $userActive && !$isResolved && $userInfo['user_moderator'];
if(isset($_GET['m']) && is_string($_GET['m'])) {
if(CSRF::verify()) {
switch($_GET['m']) {
case 'resolve':
if(!$canResolve)
die_ex('You aren\'t allowed to mark this topic as resolved.', 403);
if($isResolved)
die_ex('This topic is already marked as resolved.', 400);
$eventType = FMF_POST_TYPE_RESOLVE;
mark_topic_resolved($topicInfo['topic_id'], true);
$satoriMsg = "[b]forum.flash.moe[/b]: [url=https://forum.flash.moe/user/{$userInfo['user_id']}][b]{$userInfo['user_login']}[/b][/url] marked [url=https://forum.flash.moe/topic/{$topicId}][b]{$topicInfo['topic_title']}[/b][/url] as [b]resolved[/b].";
break;
case 'unresolve':
if(!$canResolve)
die_ex('You aren\'t allowed to mark this topic as unresolved.', 403);
if(!$isResolved)
die_ex('This topic is already marked as unresolved.', 400);
$eventType = FMF_POST_TYPE_UNRESOLVED;
$eventBump = true;
mark_topic_resolved($topicInfo['topic_id'], false);
$satoriMsg = "[b]forum.flash.moe[/b]: [url=https://forum.flash.moe/user/{$userInfo['user_id']}][b]{$userInfo['user_login']}[/b][/url] marked [url=https://forum.flash.moe/topic/{$topicId}][b]{$topicInfo['topic_title']}[/b][/url] as [b]unresolved[/b].";
break;
case 'confirm':
if(!$canConfirm)
die_ex('You aren\'t allowed to mark this topic as confirmed.', 403);
if($isResolved)
die_ex('This topic has been marked as resolved and doesn\'t need to be confirmed anymore.', 400);
if($isConfirmed)
die_ex('This topic is already marked as confirmed.', 400);
$eventType = FMF_POST_TYPE_CONFIRMED;
$eventBump = true;
mark_topic_confirmed($topicInfo['topic_id'], true);
$satoriMsg = "[b]forum.flash.moe[/b]: [url=https://forum.flash.moe/user/{$userInfo['user_id']}][b]{$userInfo['user_login']}[/b][/url] marked [url=https://forum.flash.moe/topic/{$topicId}][b]{$topicInfo['topic_title']}[/b][/url] as [b]confirmed[/b].";
break;
case 'unconfirm':
if(!$canConfirm)
die_ex('You aren\'t allowed to mark this topic as unconfirmed.', 403);
if($isResolved)
die_ex('This topic has been marked as resolved, you can\'t revoke confirmations anymore.', 400);
if(!$isConfirmed)
die_ex('This topic is not confirmed.', 400);
$eventType = FMF_POST_TYPE_UNCONFIRMED;
$eventBump = true;
mark_topic_confirmed($topicInfo['topic_id'], false);
$satoriMsg = "[b]forum.flash.moe[/b]: [url=https://forum.flash.moe/user/{$userInfo['user_id']}][b]{$userInfo['user_login']}[/b][/url] marked [url=https://forum.flash.moe/topic/{$topicId}][b]{$topicInfo['topic_title']}[/b][/url] as [b]unconfirmed[/b].";
break;
case 'lock':
if(!$canLock)
die_ex('You aren\'t allowed to lock this topic.', 403);
if($isLocked)
die_ex('This topic is already locked.', 400);
$eventType = FMF_POST_TYPE_LOCKED;
lock_topic($topicInfo['topic_id'], true);
break;
case 'unlock':
if(!$canLock)
die_ex('You aren\'t allowed to unlock this topic.', 403);
if(!$isLocked)
die_ex('This topic is already unlocked.', 400);
$eventType = FMF_POST_TYPE_UNLOCKED;
lock_topic($topicInfo['topic_id'], false);
break;
default:
die_ex('Unknown action.', 404);
break;
}
if(isset($eventType))
create_topic_event($topicInfo['cat_id'], $topicInfo['topic_id'], $userInfo['user_id'], $eventType, $eventData ?? null);
if(isset($eventBump))
topic_bump($topicInfo['topic_id']);
}
if(defined('SATORI_SECRET') && !empty($satoriMsg)) {
$sock = @fsockopen(SATORI_HOST, SATORI_PORT, $errno, $errstr, 2);
if($sock) {
fwrite($sock, chr(0xF) . hash_hmac('sha256', $satoriMsg, SATORI_SECRET) . $satoriMsg . chr(0xF));
fflush($sock);
fclose($sock);
}
}
header('Location: /topic/'. $topicInfo['topic_id']);
return;
}
if($userActive)
update_track($userInfo['user_id'], $topicInfo['topic_id'], $topicInfo['cat_id']);
$title = $topicInfo['topic_title'];
$posts = posts_in_topic($topicInfo['topic_id']);
include FMF_LAYOUT . '/header.php';
$breadcrumbs = '<a href="/">forum.flash.moe</a> &raquo; ';
$breadcrumbs_arr = category_breadcrumbs($topicInfo['cat_id'], false);
foreach($breadcrumbs_arr as $breadcrumb) {
$breadcrumbs .= sprintf('<a href="/category/%d">%s</a> &raquo; ', $breadcrumb['cat_id'], $breadcrumb['cat_name']);
}
echo $breadcrumbs;
$topicButtons = '<div class="topic-btns">';
if(!$isLocked || $canLock) {
$topicButtons .= '<a href="/topic/'. $topicInfo['topic_id'] .'/reply">Reply</a>';
}
if($canResolve) {
$topicButtons .= '<a href="/topic/'. $topicInfo['topic_id'] .'/'. ($isResolved ? 'unresolve' : 'resolve') .'?_csrf='. CSRF::token() .'">'. ($isResolved ? 'Reopen' : ($isFeatureReqs ? 'Mark Implemented' : 'Mark Resolved')) .'</a>';
}
if($canConfirm) {
$topicButtons .= '<a href="/topic/'. $topicInfo['topic_id'] .'/'. ($isConfirmed ? 'unconfirm' : 'confirm') .'?_csrf='. CSRF::token() .'">'. ($isConfirmed ? ($isFeatureReqs ? 'Revoke Accept' : 'Revoke Confirmation') : ($isFeatureReqs ? 'Accept for implementation' : 'Confirm')) .'</a>';
}
if($canLock) {
$topicButtons .= '<a href="/topic/'. $topicInfo['topic_id'] .'/'. ($isLocked ? 'unlock' : 'lock') .'?_csrf='. CSRF::token() .'">'. ($isLocked ? 'Unlock' : 'Lock') .'</a>';
}
$topicButtons .= '</div>';
?>
<h3 class="forum-title"><?=htmlentities($topicInfo['topic_title']);?></h3>
<?php
echo $topicButtons;
if($isLocked) {
?>
<div class="notice">
This topic was <b>locked</b> on <b><time datetime="<?=date('c', $topicInfo['topic_locked']);?>"><?=date(FMF_DATE_FORMAT, $topicInfo['topic_locked']);?></time></b>.
</div>
<?php
}
if($isResolved) {
?>
<div class="notice">
This topic was marked <b>resolved</b> on <b><time datetime="<?=date('c', $topicInfo['topic_resolved']);?>"><?=date(FMF_DATE_FORMAT, $topicInfo['topic_resolved']);?></time></b>.
</div>
<?php
}
foreach($posts as $post) {
$authorInfo = user_info($post['user_id']);
if($post['post_type'] == FMF_POST_TYPE_MESSAGE) {
?>
<div class="post<?=(empty($post['post_deleted']) ? '' : ' post-deleted')?>" id="p<?=$post['post_id'];?>">
<?php if(empty($post['post_deleted'])) { ?>
<div class="post-details">
<a class="post-username" href="/user/<?=($authorInfo['user_id'] ?? 0);?>"><?=($authorInfo['user_login'] ?? 'Deleted User');?></a>
<img class="post-avatar" src="<?=user_gravatar($authorInfo['user_id'] ?? null);?>" alt="<?=($authorInfo['user_login'] ?? 'Deleted User');?>"/>
<div class="post-permalink-wrap">
<a class="post-permalink" href="/post/<?=$post['post_id'];?>"><time class="post-time" datetime="<?=date('c', $post['post_created']);?>"><?=date(FMF_DATE_FORMAT, $post['post_created']);?></time></a>
</div>
</div>
<?php } ?>
<div class="post-text">
<?php if(empty($post['post_deleted'])) { ?>
<div class="post-text-inner">
<?=(new Parsedown)->setSafeMode(true)->text($post['post_text']);?>
</div>
<div class="post-footer">
<div class="post-edited">
<?php if(!empty($post['post_edited'])) { ?>
Last edited: <time datetime="<?=date('c', $post['post_edited']);?>"><?=date(FMF_DATE_FORMAT, $post['post_edited']);?></time>
<?php } ?>
</div>
<div class="post-options">
<?php if($userActive && ($userInfo['user_moderator'] || $userInfo['user_id'] === $post['user_id'])) { ?>
<a href="/post/<?=$post['post_id'];?>/edit">Edit</a>
<a href="/post/<?=$post['post_id'];?>?m=delete&amp;_csrf=<?=CSRF::token();?>">Delete</a>
<?php } ?>
<?php if(!empty($post['user_id']) && $userActive && $userInfo['user_moderator']) { ?>
<a href="/post/<?=$post['post_id'];?>?m=anonymize&amp;_csrf=<?=CSRF::token();?>">Strip User ID</a>
<?php } ?>
</div>
</div>
<?php } else { ?>
<div class="post-text-inner">
<a href="/post/<?=$post['post_id'];?>">#<?=$post['post_id'];?></a>: <code>deleted</code>
<?php if($userActive && $userInfo['user_moderator']) { ?>
(<a href="/post/<?=$post['post_id'];?>?m=restore&amp;_csrf=<?=CSRF::token();?>">Restore</a>)
<?php } ?>
</div>
<?php } ?>
</div>
</div>
<?php
} else {
unset($eventHtml);
switch($post['post_type']) {
default:
$eventMessages = [
FMF_POST_TYPE_RESOLVE => '<a href="/user/:user_id">:username</a> has marked this ' . ($isFeatureReqs ? 'request as <b>implemented</b>.' : 'topic as <b>resolved</b>.'),
FMF_POST_TYPE_LOCKED => '<a href="/user/:user_id">:username</a> has <b>locked</b> this conversation.',
FMF_POST_TYPE_UNLOCKED => '<a href="/user/:user_id">:username</a> has <b>unlocked</b> this conversation.',
FMF_POST_TYPE_UNRESOLVED => '<a href="/user/:user_id">:username</a> has marked this ' . ($isFeatureReqs ? 'request as <b>unimplemented</b>.' : 'marked this topic as <b>unresolved</b>.'),
FMF_POST_TYPE_CONFIRMED => '<a href="/user/:user_id">:username</a> has ' . ($isFeatureReqs ? 'marked this request for <b>implementation</b>.' : '<b>confirmed</b> this topic.'),
FMF_POST_TYPE_UNCONFIRMED => '<a href="/user/:user_id">:username</a> has ' . ($isFeatureReqs ? '<b>revoked implementation confirmation</b> for this request.' : '<b>revoked the confirmation</b> from this topic.'),
];
$eventMessage = $eventMessages[$post['post_type']] ?? '<a href="/user/:user_id">:username</a> did something.';
break;
}
if(isset($eventMessage)) {
$eventMessage = strtr($eventMessage, [
':user_id' => $authorInfo['user_id'] ?? 0,
':username' => $authorInfo['user_login'] ?? 'Deleted User',
]);
}
if(!isset($eventHtml)) {
$eventHtml = sprintf(
'<div class="event-msg"><img class="event-avatar" src="%s" alt="%s"/><div class="event-msg-text">%s</div><a class="event-permalink" href="/post/%d"><time class="event-time" datetime="%s">%s</time></a></div>',
user_gravatar($authorInfo['user_id'] ?? null, 20),
($authorInfo['user_login'] ?? 'Deleted User'),
$eventMessage ?? 'Missing event description.',
$post['post_id'],
date('c', $post['post_created']),
date(FMF_DATE_FORMAT, $post['post_created'])
);
}
?>
<div class="event" id="p<?=$post['post_id'];?>">
<?=$eventHtml;?>
</div>
<?php
}
}
echo $topicButtons;
echo $breadcrumbs . $topicInfo['topic_title'];
include FMF_LAYOUT . '/footer.php';