protected function processParam($event, $param, $message, $user) { $extra = $event->getExtra(); if ($param === 'subject') { if (isset($extra['topic-title']) && $extra['topic-title']) { $this->processParamEscaped($message, trim($extra['topic-title'])); } else { $message->params(''); } } elseif ($param === 'commentText') { if (isset($extra['content']) && $extra['content']) { // @todo assumes content is html, make explicit $message->params(Utils::htmlToPlaintext($extra['content'], 200)); } else { $message->params(''); } } elseif ($param === 'post-permalink') { $anchor = $this->getPostLinkAnchor($event, $user); if ($anchor) { $message->params($anchor->getFullUrl()); } else { $message->params(''); } } elseif ($param === 'topic-permalink') { // link to individual new-topic if (isset($extra['topic-workflow'])) { $title = Workflow::getFromTitleCache(wfWikiId(), NS_TOPIC, $extra['topic-workflow']->getAlphadecimal()); } else { $title = $event->getTitle(); } $anchor = $this->getUrlGenerator()->workflowLink($title, $extra['topic-workflow']); $anchor->query['fromnotif'] = 1; $message->params($anchor->getFullUrl()); } elseif ($param === 'new-topics-permalink') { // link to board sorted by newest topics $anchor = $this->getUrlGenerator()->boardLink($event->getTitle(), 'newest'); $anchor->query['fromnotif'] = 1; $message->params($anchor->getFullUrl()); } elseif ($param == 'flow-title') { $title = $event->getTitle(); if ($title) { $formatted = $this->formatTitle($title); } else { $formatted = $this->getMessage('echo-no-title')->text(); } $message->params($formatted); } elseif ($param == 'old-subject') { $this->processParamEscaped($message, trim($extra['old-subject'])); } elseif ($param == 'new-subject') { $this->processParamEscaped($message, trim($extra['new-subject'])); } else { parent::processParam($event, $param, $message, $user); } }
/** * @param FormatterRow $row With properties workflow, revision, previous_revision * @param IContextSource $ctx * @return string|false HTML for contributions entry, or false on failure * @throws FlowException */ public function format(FormatterRow $row, IContextSource $ctx) { $this->serializer->setIncludeHistoryProperties(true); $data = $this->serializer->formatApi($row, $ctx, 'contributions'); if (!$data) { return false; } $charDiff = ChangesList::showCharacterDifference($data['size']['old'], $data['size']['new']); $separator = $this->changeSeparator(); $links = array(); $links[] = $this->getDiffAnchor($data['links'], $ctx); $links[] = $this->getHistAnchor($data['links'], $ctx); $description = $this->formatDescription($data, $ctx); // Put it all together return $this->formatTimestamp($data) . ' ' . $this->formatAnchorsAsPipeList($links, $ctx) . $separator . $charDiff . $separator . $this->getTitleLink($data, $row, $ctx) . (Utils::htmlToPlaintext($description) ? $separator . $description : '') . $this->getHideUnhide($data, $row, $ctx); }
/** * @param RecentChangesRow $row * @param IContextSource $ctx * @param bool $linkOnly * @return string|false Output line, or false on failure * @throws FlowException */ public function format(RecentChangesRow $row, IContextSource $ctx, $linkOnly = false) { $this->serializer->setIncludeHistoryProperties(true); $this->serializer->setIncludeContent(false); $data = $this->serializer->formatApi($row, $ctx, 'recentchanges'); if (!$data) { return false; } if ($linkOnly) { return $this->getTitleLink($data, $row, $ctx); } // The ' . . ' text between elements $separator = $this->changeSeparator(); $links = array(); $links[] = $this->getDiffAnchor($data['links'], $ctx); $links[] = $this->getHistAnchor($data['links'], $ctx); $description = $this->formatDescription($data, $ctx); $unpatrolledFlag = ''; if (ChangesList::isUnpatrolled($row->recentChange, $ctx->getUser())) { $unpatrolledFlag = ChangesList::flag('unpatrolled') . ' '; } return $this->formatAnchorsAsPipeList($links, $ctx) . $separator . $unpatrolledFlag . $this->getTitleLink($data, $row, $ctx) . $ctx->msg('semicolon-separator')->escaped() . ' ' . $this->formatTimestamp($data, 'time') . $separator . ChangesList::showCharacterDifference($data['size']['old'], $data['size']['new'], $ctx) . (Utils::htmlToPlaintext($description) ? $separator . $description : '') . $this->getEditSummary($row, $ctx, $data); }
/** * Mimic Echo parameter formatting * * @param string $param The requested i18n parameter * @param AbstractRevision|AbstractRevision[] $revision The revision or * revisions to format or an array of revisions * @param UUID $workflowId The UUID of the workflow $revision belongs tow * @param IContextSource $ctx * @param FormatterRow|null $row * @return mixed A valid parameter for a core Message instance. These * parameters will be used with Message::parse * @throws FlowException */ public function processParam($param, $revision, UUID $workflowId, IContextSource $ctx, FormatterRow $row = null) { switch ($param) { case 'creator-text': if ($revision instanceof PostRevision) { return $this->usernames->getFromTuple($revision->getCreatorTuple()); } else { return ''; } case 'user-text': return $this->usernames->getFromTuple($revision->getUserTuple()); case 'user-links': return Message::rawParam($this->templating->getUserLinks($revision)); case 'summary': if (!$this->permissions->isAllowed($revision, 'view')) { return ''; } /* * Fetch in HTML; unparsed wikitext in summary is pointless. * Larger-scale wikis will likely also store content in html, so no * Parsoid roundtrip is needed then (and if it *is*, it'll already * be needed to render Flow discussions, so this is manageable) */ $content = $this->templating->getContent($revision, 'fixed-html'); // strip html tags and decode to plaintext $content = Utils::htmlToPlaintext($content, 140, $ctx->getLanguage()); return Message::plaintextParam($content); case 'wikitext': if (!$this->permissions->isAllowed($revision, 'view')) { return ''; } $content = $this->templating->getContent($revision, 'wikitext'); // This must be escaped and marked raw to prevent special chars in // content, like $1, from changing the i18n result return Message::plaintextParam($content); // This is potentially two networked round trips, much too expensive for // the rendering loop // This is potentially two networked round trips, much too expensive for // the rendering loop case 'prev-wikitext': if ($revision->isFirstRevision()) { return ''; } if ($row === null) { $previousRevision = $revision->getCollection()->getPrevRevision($revision); } else { $previousRevision = $row->previousRevision; } if (!$previousRevision) { return ''; } if (!$this->permissions->isAllowed($previousRevision, 'view')) { return ''; } $content = $this->templating->getContent($previousRevision, 'wikitext'); return Message::plaintextParam($content); case 'workflow-url': return $this->urlGenerator->workflowLink(null, $workflowId)->getFullUrl(); case 'post-url': if (!$revision instanceof PostRevision) { throw new FlowException('Expected PostRevision but received' . get_class($revision)); } return $this->urlGenerator->postLink(null, $workflowId, $revision->getPostId())->getFullUrl(); case 'moderated-reason': // don-t parse wikitext in the moderation reason return Message::plaintextParam($revision->getModeratedReason()); case 'topic-of-post': if (!$revision instanceof PostRevision) { throw new FlowException('Expected PostRevision but received ' . get_class($revision)); } $root = $revision->getRootPost(); if (!$this->permissions->isAllowed($root, 'view')) { return ''; } $content = $this->templating->getContent($root, 'wikitext'); return Message::plaintextParam($content); case 'post-of-summary': if (!$revision instanceof PostSummary) { throw new FlowException('Expected PostSummary but received ' . get_class($revision)); } /** @var PostRevision $post */ $post = $revision->getCollection()->getPost()->getLastRevision(); if (!$this->permissions->isAllowed($post, 'view')) { return ''; } if ($post->isTopicTitle()) { return Message::plaintextParam($this->templating->getContent($post, 'wikitext')); } else { return Message::rawParam($this->templating->getContent($post, 'fixed-html')); } case 'bundle-count': return Message::numParam(count($revision)); default: wfWarn(__METHOD__ . ': Unknown formatter parameter: ' . $param); return ''; } }
/** * Called when a new Post is added, whether it be a new topic or a reply. * Do not call directly, use notifyPostChange for new replies. * @param array $data Associative array of parameters, all required: * * title: Title for the page on which the new Post sits. * * user: User who created the new Post. * * post: The Post that was created. * * topic-title: The title for the Topic. * @return array Array of created EchoEvent objects. * @throws FlowException When $data contains unexpected types/values */ protected function notifyNewPost($data) { // Handle mentions. $newRevision = $data['post']; if ($newRevision !== null && !$newRevision instanceof PostRevision) { throw new FlowException('Expected PostRevision but received ' . get_class($newRevision)); } $topicRevision = $data['topic-title']; if (!$topicRevision instanceof PostRevision) { throw new FlowException('Expected PostRevision but received ' . get_class($topicRevision)); } $title = $data['title']; if (!$title instanceof \Title) { throw new FlowException('Expected Title but received ' . get_class($title)); } $user = $data['user']; $topicWorkflow = $data['topic-workflow']; if (!$topicWorkflow instanceof Workflow) { throw new FlowException('Expected Workflow but received ' . get_class($topicWorkflow)); } $events = array(); $mentionedUsers = $newRevision ? $this->getMentionedUsers($newRevision, $title) : array(); if (!$topicRevision instanceof PostRevision) { throw new FlowException('Expected PostRevision but received: ' . get_class($topicRevision)); } if (count($mentionedUsers)) { $events[] = EchoEvent::create(array('type' => 'flow-mention', 'title' => $title, 'extra' => array('content' => $newRevision ? Utils::htmlToPlaintext($newRevision->getContent(), 200, $this->language) : null, 'topic-title' => $this->language->truncate(trim($topicRevision->getContent('wikitext')), 200), 'post-id' => $newRevision ? $newRevision->getPostId() : null, 'mentioned-users' => $mentionedUsers, 'topic-workflow' => $topicWorkflow->getId(), 'target-page' => $topicWorkflow->getArticleTitle()->getArticleID(), 'reply-to' => isset($data['reply-to']) ? $data['reply-to'] : null), 'agent' => $user)); } return $events; }
/** * The native LogFormatter::getActionText provides no clean way of handling * the Flow action text in a plain text format (e.g. as used by CheckUser) * * @return string */ public function getActionText() { $text = $this->getActionMessage(); return $this->plaintext ? Utils::htmlToPlaintext($text) : $text; }