/** * @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; }