/**
  * Gets the root post ID for a given PostRevision
  * @param  PostRevision $revision The revision to get the root post ID for.
  * @return UUID                   The UUID for the root post.
  * @throws \MWException
  */
 protected function getRootPostId(PostRevision $revision)
 {
     $postId = $revision->getPostId();
     if ($revision->isTopicTitle()) {
         return $postId;
     } elseif (isset($this->rootPostIdCache[$postId->getAlphadecimal()])) {
         return $this->rootPostIdCache[$postId->getAlphadecimal()];
     } else {
         throw new \MWException("Unable to find root post ID for post " . $postId->getAlphadecimal());
     }
 }
 /**
  * Saves a PostRevision to storage.
  * Be sure to add the required tables to $tablesUsed and add @group Database
  * to the class' phpDoc.
  *
  * @param PostRevision $revision
  */
 protected function store(PostRevision $revision)
 {
     if ($revision->isTopicTitle()) {
         $root = $revision;
     } else {
         /** @var PostCollection $parentCollection */
         $parentCollection = PostCollection::newFromId($revision->getReplyToId());
         $root = $parentCollection->getRoot()->getLastRevision();
     }
     $topicWorkflow = $this->workflows[$root->getCollectionId()->getAlphadecimal()];
     $boardWorkflow = Container::get('factory.loader.workflow')->createWorkflowLoader($topicWorkflow->getOwnerTitle())->getWorkflow();
     $metadata = array('workflow' => $topicWorkflow, 'board-workflow' => $boardWorkflow);
     // check if this topic (+ workflow + board workflow + board page) have
     // already been inserted or do so now
     $found = $this->getStorage()->find('TopicListEntry', array('topic_id' => $topicWorkflow->getId()));
     if (!$found) {
         $title = $boardWorkflow->getOwnerTitle();
         $user = User::newFromName('127.0.0.1', false);
         /** @var OccupationController $occupationController */
         $occupationController = Container::get('occupation_controller');
         // make sure user has rights to create board
         $user->mRights = array_merge($user->getRights(), array('flow-create-board'));
         $occupationController->allowCreation($title, $user);
         $occupationController->ensureFlowRevision(new \Article($title), $boardWorkflow);
         $topicListEntry = TopicListEntry::create($boardWorkflow, $topicWorkflow);
         $this->getStorage()->put($boardWorkflow, $metadata);
         $this->getStorage()->put($topicWorkflow, $metadata);
         $this->getStorage()->put($topicListEntry, $metadata);
     }
     $this->getStorage()->put($revision, $metadata);
     /** @var SplQueue $deferredQueue */
     $deferredQueue = Container::get('deferred_queue');
     while (!$deferredQueue->isEmpty()) {
         try {
             DeferredUpdates::addCallableUpdate($deferredQueue->dequeue());
             // doing updates 1 by 1 so an exception doesn't break others in
             // the queue
             DeferredUpdates::doUpdates();
         } catch (\MWException $e) {
             // ignoring exceptions for now, not all are phpunit-proof yet
         }
     }
     // save for removal at end of tests
     $this->revisions[] = $revision;
 }
 protected function doModerate(PostRevision $post)
 {
     if ($this->submitted['moderationState'] === AbstractRevision::MODERATED_LOCKED && $post->isModerated()) {
         $this->addError('moderate', $this->context->msg('flow-error-lock-moderated-post'));
         return;
     }
     // Moderation state supplied in request parameters
     $moderationState = isset($this->submitted['moderationState']) ? $this->submitted['moderationState'] : null;
     // $moderationState should be a string like 'restore', 'suppress', etc.  The exact strings allowed
     // are checked below with $post->isValidModerationState(), but this is checked first otherwise
     // a blank string would restore a post(due to AbstractRevision::MODERATED_NONE === '').
     if (!$moderationState) {
         $this->addError('moderate', $this->context->msg('flow-error-invalid-moderation-state'));
         return;
     }
     /*
      * BC: 'suppress' used to be called 'censor', 'lock' was 'close' &
      * 'unlock' was 'reopen'
      */
     $bc = array('censor' => AbstractRevision::MODERATED_SUPPRESSED, 'close' => AbstractRevision::MODERATED_LOCKED, 'reopen' => 'un' . AbstractRevision::MODERATED_LOCKED);
     $moderationState = str_replace(array_keys($bc), array_values($bc), $moderationState);
     // these all just mean set to no moderation, it returns a post to unmoderated status
     $allowedRestoreAliases = array('unlock', 'unhide', 'undelete', 'unsuppress', 'reopen');
     if (in_array($moderationState, $allowedRestoreAliases)) {
         $moderationState = 'restore';
     }
     // By allowing the moderationState to be sourced from $this->submitted['moderationState']
     // we no longer have a unique action name for use with the permissions system.  This rebuilds
     // an action name. e.x. restore-post, restore-topic, suppress-topic, etc.
     $action = $moderationState . ($post->isTopicTitle() ? "-topic" : "-post");
     if ($moderationState === 'restore') {
         $newState = AbstractRevision::MODERATED_NONE;
     } else {
         $newState = $moderationState;
     }
     if (!$post->isValidModerationState($newState)) {
         $this->addError('moderate', $this->context->msg('flow-error-invalid-moderation-state'));
         return;
     }
     if (!$this->permissions->isAllowed($post, $action)) {
         $this->addError('permissions', $this->getDisallowedErrorMessage($post));
         return;
     }
     if (trim($this->submitted['reason']) === '') {
         $this->addError('moderate', $this->context->msg('flow-error-invalid-moderation-reason'));
         return;
     }
     $reason = $this->submitted['reason'];
     $this->newRevision = $post->moderate($this->context->getUser(), $newState, $action, $reason);
     if (!$this->newRevision) {
         $this->addError('moderate', $this->context->msg('flow-error-not-allowed'));
         return;
     }
 }