Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Pub/Controller/Post.php
<?php

namespace XF\Pub\Controller;

use
XF\Mvc\ParameterBag;

class
Post extends AbstractController
{
    public function
actionIndex(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

        return
$this->redirectPermanently($this->plugin('XF:Thread')->getPostLink($post));
    }

    public function
actionShow(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

       
$thread = $post->Thread;
       
$typeHandler = $thread->TypeHandler;

       
$viewParams = [
           
'post' => $post,
           
'thread' => $thread,
           
'forum' => $thread->Forum,
           
'canInlineMod' => $post->canUseInlineModeration(),

           
'isPinnedFirstPost' => $post->isFirstPost() && $typeHandler->isFirstPostPinned($thread),
           
'templateOverrides' => $typeHandler->getThreadViewTemplateOverrides($thread)
        ];
        return
$this->view('XF:Post\Show', 'post', $viewParams);
    }

   
/**
     * @param \XF\Entity\Post $post
     *
     * @return \XF\Service\Post\Editor
     */
   
protected function setupPostEdit(\XF\Entity\Post $post)
    {
       
$message = $this->plugin('XF:Editor')->fromInput('message');

       
/** @var \XF\Service\Post\Editor $editor */
       
$editor = $this->service('XF:Post\Editor', $post);
        if (
$post->canEditSilently())
        {
           
$silentEdit = $this->filter('silent', 'bool');
            if (
$silentEdit)
            {
               
$editor->logEdit(false);
                if (
$this->filter('clear_edit', 'bool'))
                {
                   
$post->last_edit_date = 0;
                }
            }
        }
       
$editor->setMessage($message);

       
$forum = $post->Thread->Forum;
        if (
$forum->canUploadAndManageAttachments())
        {
           
$editor->setAttachmentHash($this->filter('attachment_hash', 'str'));
        }

        if (
$this->filter('author_alert', 'bool') && $post->canSendModeratorActionAlert())
        {
           
$editor->setSendAlert(true, $this->filter('author_alert_reason', 'str'));
        }

        return
$editor;
    }

   
/**
     * @param \XF\Entity\Thread $thread
     * @param array $threadChanges Returns a list of whether certain important thread fields are changed
     *
     * @return \XF\Service\Thread\Editor
     */
   
protected function setupFirstPostThreadEdit(\XF\Entity\Thread $thread, &$threadChanges)
    {
       
/** @var \XF\Service\Thread\Editor $threadEditor */
       
$threadEditor = $this->service('XF:Thread\Editor', $thread);

        if (
$thread->isPrefixEditable())
        {
           
$prefixId = $this->filter('prefix_id', 'uint');
            if (
$prefixId != $thread->prefix_id && !$thread->Forum->isPrefixUsable($prefixId))
            {
               
$prefixId = 0; // not usable, just blank it out
           
}
           
$threadEditor->setPrefix($prefixId);
        }

       
$threadEditor->setTitle($this->filter('title', 'str'));

       
$customFields = $this->filter('custom_fields', 'array');
       
$threadEditor->setCustomFields($customFields);

       
$threadEditor->setDiscussionTypeData($this->request);

       
$threadChanges = [
           
'title' => $thread->isChanged(['title', 'prefix_id']),
           
'customFields' => $thread->isChanged('custom_fields')
        ];

        return
$threadEditor;
    }

    protected function
finalizePostEdit(\XF\Service\Post\Editor $editor, \XF\Service\Thread\Editor $threadEditor = null)
    {

    }

    public function
actionEdit(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id, ['Thread.Prefix']);
        if (!
$post->canEdit($error))
        {
            return
$this->noPermission($error);
        }

       
$thread = $post->Thread;

        if (
$this->isPost())
        {
           
$editor = $this->setupPostEdit($post);
           
$editor->checkForSpam();

            if (
$post->isFirstPost() && $thread->canEdit())
            {
               
$threadEditor = $this->setupFirstPostThreadEdit($thread, $threadChanges);
               
$editor->setThreadEditor($threadEditor);
            }
            else
            {
               
$threadEditor = null;
               
$threadChanges = [];
            }

            if (!
$editor->validate($errors))
            {
                return
$this->error($errors);
            }

           
$editor->save();

           
$this->finalizePostEdit($editor, $threadEditor);

            if (
$this->filter('_xfWithData', 'bool') && $this->filter('_xfInlineEdit', 'bool'))
            {
               
$threadPlugin = $this->plugin('XF:Thread');
               
$threadPlugin->fetchExtraContentForPostsFullView([$post->post_id => $post], $thread);

               
$typeHandler = $thread->TypeHandler;

               
$viewParams = [
                   
'post' => $post,
                   
'thread' => $thread,
                   
'isPinnedFirstPost' => $post->isFirstPost() && $typeHandler->isFirstPostPinned($thread),
                   
'templateOverrides' => $typeHandler->getThreadViewTemplateOverrides($thread)
                ];

               
$reply = $this->view('XF:Post\EditNewPost', 'post_edit_new_post', $viewParams);
               
$reply->setJsonParams([
                   
'message' => \XF::phrase('your_changes_have_been_saved'),
                   
'threadChanges' => $threadChanges
               
]);
                return
$reply;
            }
            else
            {
                return
$this->redirect($this->buildLink('posts', $post));
            }
        }
        else
        {
           
/** @var \XF\Entity\Forum $forum */
           
$forum = $post->Thread->Forum;
            if (
$forum->canUploadAndManageAttachments())
            {
               
/** @var \XF\Repository\Attachment $attachmentRepo */
               
$attachmentRepo = $this->repository('XF:Attachment');
               
$attachmentData = $attachmentRepo->getEditorData('post', $post);
            }
            else
            {
               
$attachmentData = null;
            }

           
$prefix = $thread->Prefix;
           
$prefixes = $forum->getUsablePrefixes($prefix);

           
$viewParams = [
               
'post' => $post,
               
'thread' => $thread,
               
'forum' => $forum,
               
'prefixes' => $prefixes,
               
'attachmentData' => $attachmentData,
               
'quickEdit' => $this->filter('_xfWithData', 'bool')
            ];
            return
$this->view('XF:Post\Edit', 'post_edit', $viewParams);
        }
    }

    public function
actionPreview(ParameterBag $params)
    {
       
$this->assertPostOnly();

       
$post = $this->assertViewablePost($params->post_id);
        if (!
$post->canEdit($error))
        {
            return
$this->noPermission($error);
        }

       
$thread = $post->Thread;

       
$editor = $this->setupPostEdit($post);

        if (!
$editor->validate($errors))
        {
            return
$this->error($errors);
        }

       
$attachments = [];
       
$tempHash = $this->filter('attachment_hash', 'str');

        if (
$thread->Forum->canUploadAndManageAttachments())
        {
           
/** @var \XF\Repository\Attachment $attachmentRepo */
           
$attachmentRepo = $this->repository('XF:Attachment');
           
$attachmentData = $attachmentRepo->getEditorData('post', $post, $tempHash);
           
$attachments = $attachmentData['attachments'];
        }

        return
$this->plugin('XF:BbCodePreview')->actionPreview(
           
$post->message, 'post', $post->User, $attachments, $thread->canViewAttachments()
        );
    }

    public function
actionDelete(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);
        if (!
$post->canDelete('soft', $error))
        {
            return
$this->noPermission($error);
        }

        if (
$this->isPost())
        {
           
$type = $this->filter('hard_delete', 'bool') ? 'hard' : 'soft';
           
$reason = $this->filter('reason', 'str');

            if (!
$post->canDelete($type, $error))
            {
                return
$this->noPermission($error);
            }

           
/** @var \XF\Entity\Thread $thread */
           
$thread = $post->Thread;

           
/** @var \XF\Service\Post\Deleter $deleter */
           
$deleter = $this->service('XF:Post\Deleter', $post);

            if (
$this->filter('author_alert', 'bool') && $post->canSendModeratorActionAlert())
            {
               
$deleter->setSendAlert(true, $this->filter('author_alert_reason', 'str'));
            }

           
$deleter->delete($type, $reason);

           
$this->plugin('XF:InlineMod')->clearIdFromCookie('post', $post->post_id);

            if (
$deleter->wasThreadDeleted())
            {
               
$this->plugin('XF:InlineMod')->clearIdFromCookie('thread', $post->thread_id);

                return
$this->redirect(
                   
$thread && $thread->Forum
                       
? $this->buildLink('forums', $thread->Forum)
                        :
$this->buildLink('index')
                );
            }
            else
            {
                return
$this->redirect(
                   
$this->getDynamicRedirect($this->buildLink('threads', $thread), false)
                );
            }
        }
        else
        {
           
$viewParams = [
               
'post' => $post,
               
'thread' => $post->Thread,
               
'forum' => $post->Thread->Forum
           
];
            return
$this->view('XF:Post\Delete', 'post_delete', $viewParams);
        }
    }

    public function
actionUndelete(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

       
/** @var \XF\ControllerPlugin\Undelete $plugin */
       
$plugin = $this->plugin('XF:Undelete');
        return
$plugin->actionUndelete(
           
$post,
           
$this->buildLink('posts/undelete', $post),
           
$post->getContentUrl(),
           
$post->getContentTitle('undelete'),
           
'message_state'
       
);
    }

    public function
actionIp(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);
       
$breadcrumbs = $post->Thread->getBreadcrumbs();

       
/** @var \XF\ControllerPlugin\Ip $ipPlugin */
       
$ipPlugin = $this->plugin('XF:Ip');
        return
$ipPlugin->actionIp($post, $breadcrumbs);
    }

    public function
actionReport(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);
        if (!
$post->canReport($error))
        {
            return
$this->noPermission($error);
        }

       
/** @var \XF\ControllerPlugin\Report $reportPlugin */
       
$reportPlugin = $this->plugin('XF:Report');
        return
$reportPlugin->actionReport(
           
'post', $post,
           
$this->buildLink('posts/report', $post),
           
$this->buildLink('posts', $post)
        );
    }

    public function
actionQuote(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);
        if (!
$post->Thread->canReply($error) && !$post->Thread->canReplyPreReg())
        {
            return
$this->noPermission($error);
        }

        return
$this->plugin('XF:Quote')->actionQuote($post, 'post');
    }

    public function
actionHistory(ParameterBag $params)
    {
        return
$this->rerouteController('XF:EditHistory', 'index', [
           
'content_type' => 'post',
           
'content_id' => $params->post_id
       
]);
    }

    public function
actionBookmark(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

       
/** @var \XF\ControllerPlugin\Bookmark $bookmarkPlugin */
       
$bookmarkPlugin = $this->plugin('XF:Bookmark');

        return
$bookmarkPlugin->actionBookmark(
           
$post, $this->buildLink('posts/bookmark', $post)
        );
    }

    public function
actionReact(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

       
/** @var \XF\ControllerPlugin\Reaction $reactionPlugin */
       
$reactionPlugin = $this->plugin('XF:Reaction');
        return
$reactionPlugin->actionReactSimple($post, 'posts');
    }

    public function
actionReactions(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

       
$breadcrumbs = $post->Thread->getBreadcrumbs();
       
$title = \XF::phrase('members_who_reacted_to_message_x', ['position' => ($post->position + 1)]);

       
/** @var \XF\ControllerPlugin\Reaction $reactionPlugin */
       
$reactionPlugin = $this->plugin('XF:Reaction');
        return
$reactionPlugin->actionReactions(
           
$post,
           
'posts/reactions',
           
$title, $breadcrumbs
       
);
    }

    public function
actionVote(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

       
/** @var \XF\ControllerPlugin\ContentVote $votePlugin */
       
$votePlugin = $this->plugin('XF:ContentVote');

        return
$votePlugin->actionVote(
           
$post,
           
$this->buildLink('posts', $post),
           
$this->buildLink('posts/vote', $post)
        );
    }

    public function
actionMarkSolution(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

        if (!
$post->canMarkAsQuestionSolution($error))
        {
            return
$this->noPermission($error);
        }

       
$thread = $post->Thread;
       
$existingSolution = $thread->Question->Solution ?? null;

        if (!
$existingSolution)
        {
           
$type = 'add';
        }
        else if (
$post->post_id == $existingSolution->post_id)
        {
           
$type = 'remove';
        }
        else
        {
           
$type = 'replace';
        }

       
// for replacement cases, we want to force an explicit confirmation, even if receiving a post request
        // (which might come from JS)

       
if (
           
$this->isPost()
            && (
$type != 'replace' || $this->filter('confirm', 'bool'))
        )
        {
           
/** @var \XF\Service\ThreadQuestion\MarkSolution $markSolution */
           
$markSolution = $this->service('XF:ThreadQuestion\MarkSolution', $thread);

            if (
$type == 'remove')
            {
               
$markSolution->unmarkSolution();
               
$switchKey = 'removed';
            }
            else
            {
               
$markSolution->markSolution($post);
               
$switchKey = $existingSolution ? "replaced:{$existingSolution->post_id}" : 'marked';
            }

           
$reply = $this->redirect($this->buildLink('posts', $post));
           
$reply->setJsonParam('switchKey', $switchKey);

            return
$reply;
        }
        else
        {
           
$viewParams = [
               
'post' => $post,
               
'thread' => $thread,
               
'existingSolution' => $existingSolution,
               
'type' => $type
           
];
            return
$this->view('XF:Post\MarkSolution', 'post_mark_solution', $viewParams);
        }
    }

    public function
actionWarn(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);

        if (!
$post->canWarn($error))
        {
            return
$this->noPermission($error);
        }

       
$breadcrumbs = $post->Thread->getBreadcrumbs();

       
/** @var \XF\ControllerPlugin\Warn $warnPlugin */
       
$warnPlugin = $this->plugin('XF:Warn');
        return
$warnPlugin->actionWarn(
           
'post', $post,
           
$this->buildLink('posts/warn', $post),
           
$breadcrumbs
       
);
    }

    public function
actionShare(ParameterBag $params)
    {
       
$post = $this->assertViewablePost($params->post_id);
       
$thread = $post->Thread;

       
/** @var \XF\ControllerPlugin\Share $sharePlugin */
       
$sharePlugin = $this->plugin('XF:Share');
        return
$sharePlugin->actionTooltip(
           
$post->isFirstPost()
                ?
$this->buildLink('canonical:threads', $thread)
                :
$this->buildLink('canonical:threads/post', $thread, ['post_id' => $post->post_id]),
           
$post->isFirstPost()
                ? \
XF::phrase('thread_x', ['title' => $thread->title])
                : \
XF::phrase('post_in_thread_x', ['title' => $thread->title]),
           
$post->isFirstPost()
                ? \
XF::phrase('share_this_thread')
                : \
XF::phrase('share_this_post')
        );
    }

   
/**
     * @param $postId
     * @param array $extraWith
     *
     * @return \XF\Entity\Post
     *
     * @throws \XF\Mvc\Reply\Exception
     */
   
protected function assertViewablePost($postId, array $extraWith = [])
    {
       
$visitor = \XF::visitor();
       
$extraWith[] = 'Thread';
       
$extraWith[] = 'Thread.Forum';
       
$extraWith[] = 'Thread.Forum.Node';
       
$extraWith[] = 'Thread.Forum.Node.Permissions|' . $visitor->permission_combination_id;

       
/** @var \XF\Entity\Post $post */
       
$post = $this->em()->find('XF:Post', $postId, $extraWith);
        if (!
$post)
        {
            throw
$this->exception($this->notFound(\XF::phrase('requested_post_not_found')));
        }
        if (!
$post->canView($error))
        {
            throw
$this->exception($this->noPermission($error));
        }

       
$this->plugin('XF:Node')->applyNodeContext($post->Thread->Forum->Node);

        return
$post;
    }

   
/**
     * @return \XF\Repository\Thread
     */
   
protected function getThreadRepo()
    {
        return
$this->repository('XF:Thread');
    }

   
/**
     * @return \XF\Repository\Post
     */
   
protected function getPostRepo()
    {
        return
$this->repository('XF:Post');
    }

    public static function
getActivityDetails(array $activities)
    {
        return
self::getActivityDetailsForContent(
           
$activities, \XF::phrase('viewing_thread'), 'post_id',
            function(array
$ids)
            {
               
$posts = \XF::em()->findByIds(
                   
'XF:Post',
                   
$ids,
                    [
'Thread', 'Thread.Forum', 'Thread.Forum.Node', 'Thread.Forum.Node.Permissions|' . \XF::visitor()->permission_combination_id]
                );

               
$router = \XF::app()->router('public');
               
$data = [];

                foreach (
$posts->filterViewable() AS $id => $post)
                {
                   
$data[$id] = [
                       
'title' => $post->Thread->title,
                       
'url' => $router->buildLink('threads', $post->Thread)
                    ];
                }

                return
$data;
            }
        );
    }
}