/**
  * @param AbstractRevision $revision Revision object
  * @param array $row Revision row
  * @param array $metadata;
  */
 public function onAfterInsert($revision, array $row, array $metadata)
 {
     global $wgRCFeeds;
     // No action on imported revisions
     if (isset($metadata['imported']) && $metadata['imported']) {
         return;
     }
     $action = $revision->getChangeType();
     $revisionId = $revision->getRevisionId()->getAlphadecimal();
     $timestamp = $revision->getRevisionId()->getTimestamp();
     /** @var Workflow $workflow */
     $workflow = $metadata['workflow'];
     $user = $revision->getUser();
     if (!$this->isAllowed($revision, $action)) {
         return;
     }
     $title = $this->getRcTitle($workflow, $revision->getChangeType());
     $attribs = array('rc_namespace' => $title->getNamespace(), 'rc_title' => $title->getDBkey(), 'rc_user' => $row['rev_user_id'], 'rc_user_text' => $this->usernames->get(wfWikiId(), $row['rev_user_id'], $row['rev_user_ip']), 'rc_type' => RC_FLOW, 'rc_source' => self::SRC_FLOW, 'rc_minor' => 0, 'rc_bot' => 0, 'rc_patrolled' => $user->isAllowed('autopatrol') ? 1 : 0, 'rc_old_len' => $revision->getPreviousContentLength(), 'rc_new_len' => $revision->getContentLength(), 'rc_this_oldid' => 0, 'rc_last_oldid' => 0, 'rc_log_type' => null, 'rc_params' => serialize(array('flow-workflow-change' => array('action' => $action, 'revision_type' => get_class($revision), 'revision' => $revisionId, 'workflow' => $workflow->getId()->getAlphadecimal()))), 'rc_cur_id' => 0, 'rc_comment' => '', 'rc_timestamp' => $timestamp, 'rc_deleted' => 0);
     $rc = $this->rcFactory->newFromRow((object) $attribs);
     $rc->save(true);
     // Insert into db
     $feeds = $wgRCFeeds;
     // Override the IRC formatter with our own formatter
     foreach (array_keys($feeds) as $name) {
         $feeds[$name]['original_formatter'] = $feeds[$name]['formatter'];
         $feeds[$name]['formatter'] = $this->ircFormatter;
     }
     // pre-load the irc formatter which will be triggered via hook
     $this->ircFormatter->associate($rc, array('revision' => $revision) + $metadata);
     // run the feeds/irc/etc external notifications
     $rc->notifyRCFeeds($feeds);
 }
 /**
  * @param string $type
  * @param AbstractRevision $object
  * @param array $metadata
  * @param array $params
  * @throws InvalidDataException
  */
 protected function notifyPostChange($type, $object, $metadata, array $params = array())
 {
     if (!isset($metadata['workflow'], $metadata['topic-title'])) {
         throw new InvalidDataException('Invalid metadata for revision ' . $object->getRevisionId()->getAlphadecimal(), 'missing-metadata');
     }
     $workflow = $metadata['workflow'];
     if (!$workflow instanceof Workflow) {
         throw new InvalidDataException('Workflow metadata is not a Workflow', 'missing-metadata');
     }
     $this->notificationController->notifyPostChange($type, $params + array('revision' => $object, 'title' => $workflow->getOwnerTitle(), 'topic-workflow' => $workflow, 'topic-title' => $metadata['topic-title']));
 }
 /**
  * @param AbstractRevision $revision
  * @return string
  */
 protected function decideContentFormat(AbstractRevision $revision)
 {
     if ($revision instanceof PostRevision && $revision->isTopicTitle()) {
         return 'plaintext';
     }
     $alpha = $revision->getRevisionId()->getAlphadecimal();
     if (isset($this->revisionContentFormat[$alpha])) {
         return $this->revisionContentFormat[$alpha];
     }
     return $this->contentFormat;
 }
 /**
  * @param string $action
  * @param AbstractRevision|null $parent
  * @param array $overrides
  * @return PostRevision
  */
 public function generateRevision($action, AbstractRevision $parent = null, array $overrides = array())
 {
     $overrides['rev_change_type'] = $action;
     if ($parent) {
         $overrides['rev_parent_id'] = $parent->getRevisionId()->getBinary();
         $overrides['tree_rev_descendant_id'] = $parent->getPostId()->getBinary();
         $overrides['rev_type_id'] = $parent->getPostId()->getBinary();
     }
     switch ($action) {
         case 'restore-post':
             $overrides += array('rev_mod_state' => $this->moderation[$action], 'rev_mod_user_id' => null, 'rev_mod_user_ip' => null, 'rev_mod_timestamp' => null, 'rev_mod_reason' => 'unit test');
             break;
         case 'hide-post':
         case 'delete-post':
         case 'suppress-post':
             $overrides += array('rev_mod_state' => $this->moderation[$action], 'rev_mod_user_id' => 1, 'rev_mod_user_ip' => null, 'rev_mod_timestamp' => wfTimestampNow(), 'rev_mod_reason' => 'unit test');
             break;
         default:
             // nothing special
             break;
     }
     $revision = $this->generateObject($overrides);
     $this->store($revision);
     return $revision;
 }
 /**
  * @param AbstractRevision $revision
  * @param Title|null $title
  * @param UUID $workflowId
  * @param UUID $oldRevId
  * @return Anchor
  * @throws FlowException When $revision is not PostRevision, Header or PostSummary
  */
 public function diffLink(AbstractRevision $revision, Title $title = null, UUID $workflowId, UUID $oldRevId = null)
 {
     if ($revision instanceof PostRevision) {
         return $this->diffPostLink($title, $workflowId, $revision->getRevisionId(), $oldRevId);
     } elseif ($revision instanceof Header) {
         return $this->diffHeaderLink($title, $workflowId, $revision->getRevisionId(), $oldRevId);
     } elseif ($revision instanceof PostSummary) {
         return $this->diffSummaryLink($title, $workflowId, $revision->getRevisionId(), $oldRevId);
     } else {
         throw new FlowException('Unknown revision type: ' . get_class($revision));
     }
 }
 /**
  * Given a certain revision, returns the next revision.
  *
  * @param AbstractRevision $revision
  * @return AbstractRevision|null null if there is no next revision
  */
 public function getNextRevision(AbstractRevision $revision)
 {
     // make sure all revisions have been loaded
     $this->getAllRevisions();
     // find requested id, based on given revision
     $ids = array_keys($this->revisions);
     $current = array_search($revision->getRevisionId()->getAlphadecimal(), $ids);
     $next = $current - 1;
     if ($next < 0) {
         return null;
     }
     return $this->getRevision(UUID::create($ids[$next]));
 }
 /**
  * @param AbstractRevision $revision
  * @return MWTimestamp
  * @throws Exception
  * @throws TimestampException
  * @throws \Flow\Exception\DataModelException
  */
 protected function getUpdateTimestamp(AbstractRevision $revision)
 {
     $timestamp = $revision->getRevisionId()->getTimestampObj();
     if (!$revision instanceof PostRevision) {
         return $timestamp;
     }
     foreach ($revision->getChildren() as $child) {
         // go recursive, find timestamp of most recent child post
         $comparison = $this->getUpdateTimestamp($child);
         $diff = $comparison->diff($timestamp);
         // invert will be 1 if the diff is a negative time period from
         // child timestamp ($comparison) to $timestamp, which means that
         // $comparison is more recent than our current $timestamp
         if ($diff->invert) {
             $timestamp = $comparison;
         }
     }
     return $timestamp;
 }
 /**
  * Build a stdClass object that contains all related data models necessary
  * for rendering a revision.
  *
  * @param AbstractRevision $revision
  * @param string $indexField The field used for pagination
  * @param FormatterRow|null Row to populate
  * @return FormatterRow
  * @throws FlowException
  */
 protected function buildResult(AbstractRevision $revision, $indexField, FormatterRow $row = null)
 {
     $uuid = $revision->getRevisionId();
     $timestamp = $uuid->getTimestamp();
     $workflow = $this->getWorkflow($revision);
     if (!$workflow) {
         throw new FlowException("could not locate workflow for revision " . $revision->getRevisionId()->getAlphadecimal());
     }
     $row = $row ?: new FormatterRow();
     $row->revision = $revision;
     if ($this->needsPreviousRevision($revision)) {
         $row->previousRevision = $this->getPreviousRevision($revision);
     }
     $row->currentRevision = $this->getCurrentRevision($revision);
     $row->workflow = $workflow;
     // some core classes that process this row before our formatter
     // require a specific field to handle pagination
     if (property_exists($row, $indexField)) {
         $row->{$indexField} = $timestamp;
     }
     if ($revision instanceof PostRevision) {
         $row->rootPost = $this->getRootPost($revision);
         $revision->setRootPost($row->rootPost);
         $row->isLastReply = $this->isLastReply($revision);
     }
     return $row;
 }