/** * Get the IContextSource in use here * @return IContextSource */ public final function getContext() { if ($this->context instanceof IContextSource) { return $this->context; } return $this->page->getContext(); }
/** * Get the IContextSource in use here * @return IContextSource */ final public function getContext() { if ( $this->context instanceof IContextSource ) { return $this->context; } else if ( $this->page instanceof Article ) { // NOTE: $this->page can be a WikiPage, which does not have a context. wfDebug( __METHOD__ . ': no context known, falling back to Article\'s context.' ); return $this->page->getContext(); } wfWarn( __METHOD__ . ': no context known, falling back to RequestContext::getMain().' ); return RequestContext::getMain(); }
/** * Display a message * * @param Article &$article * @param boolean $outputDone * @param boolean $useParserCache * * @return true */ public static function onArticleViewHeader(Article &$article, &$outputDone, &$useParserCache) { global $wgOut; $title = $article->getTitle(); if (!ApprovedRevs::isAssignedToProject($title)) { return true; } $user = $article->getContext()->getUser(); $banner = self::showProjectBanner($title, $user); if (!is_null($banner)) { $wgOut->addModuleStyles('ext.wrApprovedRevs.main'); $wgOut->addHTML($banner); } return true; }
/** * Log stuff to EventLogging's Schema:Edit - see https://meta.wikimedia.org/wiki/Schema:Edit * If you don't have EventLogging installed, does nothing. * * @param string $action * @param Article $article Which article (with full context, page, title, etc.) * @param array $data Data to log for this action * @return bool Whether the event was logged or not. */ public static function doEventLogging($action, $article, $data = array()) { global $wgVersion; if (!class_exists('EventLogging')) { return false; } $user = $article->getContext()->getUser(); $page = $article->getPage(); $title = $article->getTitle(); $data = array('action' => $action, 'version' => 1, 'editor' => 'wikitext', 'platform' => 'desktop', 'integration' => 'page', 'page.length' => -1, 'page.id' => $page->getId(), 'page.title' => $title->getPrefixedText(), 'page.ns' => $title->getNamespace(), 'page.revid' => $page->getRevision() ? $page->getRevision()->getId() : 0, 'user.id' => $user->getId(), 'user.editCount' => $user->getEditCount() ?: 0, 'mediawiki.version' => $wgVersion) + $data; if ($user->isAnon()) { $data['user.class'] = 'IP'; } return EventLogging::logEvent('Edit', 11448630, $data); }
function __construct(Article $article) { // Set instance variables. $this->mArticle = $article; $this->mTitle = $article->getTitle(); $this->mApplicableTypes = $this->mTitle->getRestrictionTypes(); $this->mContext = $article->getContext(); // Check if the form should be disabled. // If it is, the form will be available in read-only to show levels. $this->mPermErrors = $this->mTitle->getUserPermissionsErrors('protect', $this->mContext->getUser(), $this->mContext->getRequest()->wasPosted() ? 'secure' : 'full'); if (wfReadOnly()) { $this->mPermErrors[] = ['readonlytext', wfReadOnlyReason()]; } $this->disabled = $this->mPermErrors != []; $this->disabledAttrib = $this->disabled ? ['disabled' => 'disabled'] : []; $this->loadData(); }
/** * @depends testAutoMerge */ public function testCheckDirectEditingDisallowed_forNonTextContent() { $title = Title::newFromText('Dummy:NonTextPageForEditPage'); $page = WikiPage::factory($title); $article = new Article($title); $article->getContext()->setTitle($title); $ep = new EditPage($article); $ep->setContextTitle($title); $user = $GLOBALS['wgUser']; $edit = ['wpTextbox1' => serialize('non-text content'), 'wpEditToken' => $user->getEditToken(), 'wpEdittime' => '', 'wpStarttime' => wfTimestampNow()]; $req = new FauxRequest($edit, true); $ep->importFormData($req); $this->setExpectedException('MWException', 'This content model is not supported: testing'); $ep->internalAttemptSave($result, false); }
/** * Show "your edit contains spam" page with your diff and text * * @param $match Text which triggered one or more filters */ public function spamPageWithContent($match = false) { global $wgOut; $this->textbox2 = $this->textbox1; $wgOut->prepareErrorPage(wfMessage('spamprotectiontitle')); $wgOut->addHTML('<div id="spamprotected">'); $wgOut->addWikiMsg('spamprotectiontext'); if ($match) { $wgOut->addWikiMsg('spamprotectionmatch', wfEscapeWikiText($match)); } $wgOut->addHTML('</div>'); $wgOut->wrapWikiMsg('<h2>$1</h2>', "yourdiff"); $de = new DifferenceEngine($this->mArticle->getContext()); $de->setText($this->getCurrentText(), $this->textbox2); $de->showDiff(wfMsg("storedversion"), wfMsgExt('yourtext', 'parseinline')); $wgOut->wrapWikiMsg('<h2>$1</h2>', "yourtext"); $this->showTextbox2(); $wgOut->addReturnTo($this->getContextTitle(), array('action' => 'edit')); }
/** * Performs an edit and checks the result. * * @param string|Title $title The title of the page to edit * @param string|null $baseText Some text to create the page with before attempting the edit. * @param User|string|null $user The user to perform the edit as. * @param array $edit An array of request parameters used to define the edit to perform. * Some well known fields are: * * wpTextbox1: the text to submit * * wpSummary: the edit summary * * wpEditToken: the edit token (will be inserted if not provided) * * wpEdittime: timestamp of the edit's base revision (will be inserted * if not provided) * * wpStarttime: timestamp when the edit started (will be inserted if not provided) * * wpSectionTitle: the section to edit * * wpMinorEdit: mark as minor edit * * wpWatchthis: whether to watch the page * @param int|null $expectedCode The expected result code (EditPage::AS_XXX constants). * Set to null to skip the check. * @param string|null $expectedText The text expected to be on the page after the edit. * Set to null to skip the check. * @param string|null $message An optional message to show along with any error message. * * @return WikiPage The page that was just edited, useful for getting the edit's rev_id, etc. */ protected function assertEdit($title, $baseText, $user = null, array $edit, $expectedCode = null, $expectedText = null, $message = null) { if (is_string($title)) { $ns = $this->getDefaultWikitextNS(); $title = Title::newFromText($title, $ns); } $this->assertNotNull($title); if (is_string($user)) { $user = User::newFromName($user); if ($user->getId() === 0) { $user->addToDatabase(); } } $page = WikiPage::factory($title); if ($baseText !== null) { $content = ContentHandler::makeContent($baseText, $title); $page->doEditContent($content, "base text for test"); $this->forceRevisionDate($page, '20120101000000'); //sanity check $page->clear(); $currentText = ContentHandler::getContentText($page->getContent()); # EditPage rtrim() the user input, so we alter our expected text # to reflect that. $this->assertEditedTextEquals($baseText, $currentText); } if ($user == null) { $user = $GLOBALS['wgUser']; } else { $this->setMwGlobals('wgUser', $user); } if (!isset($edit['wpEditToken'])) { $edit['wpEditToken'] = $user->getEditToken(); } if (!isset($edit['wpEdittime'])) { $edit['wpEdittime'] = $page->exists() ? $page->getTimestamp() : ''; } if (!isset($edit['wpStarttime'])) { $edit['wpStarttime'] = wfTimestampNow(); } $req = new FauxRequest($edit, true); // session ?? $article = new Article($title); $article->getContext()->setTitle($title); $ep = new EditPage($article); $ep->setContextTitle($title); $ep->importFormData($req); $bot = isset($edit['bot']) ? (bool) $edit['bot'] : false; // this is where the edit happens! // Note: don't want to use EditPage::AttemptSave, because it messes with $wgOut // and throws exceptions like PermissionsError $status = $ep->internalAttemptSave($result, $bot); if ($expectedCode !== null) { // check edit code $this->assertEquals($expectedCode, $status->value, "Expected result code mismatch. {$message}"); } $page = WikiPage::factory($title); if ($expectedText !== null) { // check resulting page text $content = $page->getContent(); $text = ContentHandler::getContentText($content); # EditPage rtrim() the user input, so we alter our expected text # to reflect that. $this->assertEditedTextEquals($expectedText, $text, "Expected article text mismatch. {$message}"); } return $page; }
/** * Get the rendered text for previewing. * @throws MWException * @return string */ function getPreviewText() { global $wgOut, $wgUser, $wgRawHtml, $wgLang; global $wgAllowUserCss, $wgAllowUserJs; wfProfileIn(__METHOD__); if ($wgRawHtml && !$this->mTokenOk) { // Could be an offsite preview attempt. This is very unsafe if // HTML is enabled, as it could be an attack. $parsedNote = ''; if ($this->textbox1 !== '') { // Do not put big scary notice, if previewing the empty // string, which happens when you initially edit // a category page, due to automatic preview-on-open. $parsedNote = $wgOut->parse("<div class='previewnote'>" . wfMessage('session_fail_preview_html')->text() . "</div>", true, true); } wfProfileOut(__METHOD__); return $parsedNote; } $note = ''; try { $content = $this->toEditContent($this->textbox1); $previewHTML = ''; if (!wfRunHooks('AlternateEditPreview', array($this, &$content, &$previewHTML, &$this->mParserOutput))) { wfProfileOut(__METHOD__); return $previewHTML; } # provide a anchor link to the editform $continueEditing = '<span class="mw-continue-editing">' . '[[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' . wfMessage('continue-editing')->text() . ']]</span>'; if ($this->mTriedSave && !$this->mTokenOk) { if ($this->mTokenOkExceptSuffix) { $note = wfMessage('token_suffix_mismatch')->plain(); } else { $note = wfMessage('session_fail_preview')->plain(); } } elseif ($this->incompleteForm) { $note = wfMessage('edit_form_incomplete')->plain(); } else { $note = wfMessage('previewnote')->plain() . ' ' . $continueEditing; } $parserOptions = $this->mArticle->makeParserOptions($this->mArticle->getContext()); $parserOptions->setEditSection(false); $parserOptions->setIsPreview(true); $parserOptions->setIsSectionPreview(!is_null($this->section) && $this->section !== ''); # don't parse non-wikitext pages, show message about preview if ($this->mTitle->isCssJsSubpage() || $this->mTitle->isCssOrJsPage()) { if ($this->mTitle->isCssJsSubpage()) { $level = 'user'; } elseif ($this->mTitle->isCssOrJsPage()) { $level = 'site'; } else { $level = false; } if ($content->getModel() == CONTENT_MODEL_CSS) { $format = 'css'; if ($level === 'user' && !$wgAllowUserCss) { $format = false; } } elseif ($content->getModel() == CONTENT_MODEL_JAVASCRIPT) { $format = 'js'; if ($level === 'user' && !$wgAllowUserJs) { $format = false; } } else { $format = false; } # Used messages to make sure grep find them: # Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview if ($level && $format) { $note = "<div id='mw-{$level}{$format}preview'>" . wfMessage("{$level}{$format}preview")->text() . ' ' . $continueEditing . "</div>"; } } # If we're adding a comment, we need to show the # summary as the headline if ($this->section === "new" && $this->summary !== "") { $content = $content->addSectionHeader($this->summary); } $hook_args = array($this, &$content); ContentHandler::runLegacyHooks('EditPageGetPreviewText', $hook_args); wfRunHooks('EditPageGetPreviewContent', $hook_args); $parserOptions->enableLimitReport(); # For CSS/JS pages, we should have called the ShowRawCssJs hook here. # But it's now deprecated, so never mind $content = $content->preSaveTransform($this->mTitle, $wgUser, $parserOptions); $parserOutput = $content->getParserOutput($this->getArticle()->getTitle(), null, $parserOptions); $previewHTML = $parserOutput->getText(); $this->mParserOutput = $parserOutput; $wgOut->addParserOutputMetadata($parserOutput); if (count($parserOutput->getWarnings())) { $note .= "\n\n" . implode("\n\n", $parserOutput->getWarnings()); } } catch (MWContentSerializationException $ex) { $m = wfMessage('content-failed-to-parse', $this->contentModel, $this->contentFormat, $ex->getMessage()); $note .= "\n\n" . $m->parse(); $previewHTML = ''; } if ($this->isConflict) { $conflict = '<h2 id="mw-previewconflict">' . wfMessage('previewconflict')->escaped() . "</h2>\n"; } else { $conflict = '<hr />'; } $previewhead = "<div class='previewnote'>\n" . '<h2 id="mw-previewheader">' . wfMessage('preview')->escaped() . "</h2>" . $wgOut->parse($note, true, true) . $conflict . "</div>\n"; $pageViewLang = $this->mTitle->getPageViewLanguage(); $attribs = array('lang' => $pageViewLang->getHtmlCode(), 'dir' => $pageViewLang->getDir(), 'class' => 'mw-content-' . $pageViewLang->getDir()); $previewHTML = Html::rawElement('div', $attribs, $previewHTML); wfProfileOut(__METHOD__); return $previewhead . $previewHTML . $this->previewTextAfterContent; }
/** * Hook used to determine if current user should be given the edit interface * for a page. * * @todo Not clear if this is the best hook to use. onBeforePageDisplay * doesn't have easy access to oldid * * @param $output OutputPage */ public static function onArticleViewHeader(Article $article) { $title = $article->getTitle(); $context = $article->getContext(); $user = $context->getUser(); $output = $context->getOutput(); $action = $context->getRequest()->getVal('action', 'view'); // @todo Does not trigger on perma-link to current revision // not sure if that's a desired behaviour or not. if ($title->getContentModel() === __CLASS__ && $action === 'view' && $title->getArticleId() !== 0 && $article->getOldID() === 0 && $title->userCan('edit', $user, 'quick')) { $output->addJsConfigVars('wgEnableCollaborationKitListEdit', true); /* Disabling until JavaScript module is updated. $output->addModules( 'ext.CollaborationKit.list.edit' ); */ $output->preventClickjacking(); } }
/** * Returns an array of html code of the following buttons: * save, diff, preview and live * * @param int $tabindex Current tabindex * * @return array */ public function getEditButtons(&$tabindex) { $buttons = []; $labelAsPublish = $this->mArticle->getContext()->getConfig()->get('EditSubmitButtonLabelPublish'); // Can't use $this->isNew as that's also true if we're adding a new section to an extant page if ($labelAsPublish) { $buttonLabelKey = !$this->mTitle->exists() ? 'publishpage' : 'publishchanges'; } else { $buttonLabelKey = !$this->mTitle->exists() ? 'savearticle' : 'savechanges'; } $buttonLabel = $this->context->msg($buttonLabelKey)->text(); $attribs = ['id' => 'wpSave', 'name' => 'wpSave', 'tabindex' => ++$tabindex] + Linker::tooltipAndAccesskeyAttribs('save'); $buttons['save'] = Html::submitButton($buttonLabel, $attribs, ['mw-ui-progressive']); ++$tabindex; // use the same for preview and live preview $attribs = ['id' => 'wpPreview', 'name' => 'wpPreview', 'tabindex' => $tabindex] + Linker::tooltipAndAccesskeyAttribs('preview'); $buttons['preview'] = Html::submitButton($this->context->msg('showpreview')->text(), $attribs); $buttons['live'] = ''; $attribs = ['id' => 'wpDiff', 'name' => 'wpDiff', 'tabindex' => ++$tabindex] + Linker::tooltipAndAccesskeyAttribs('diff'); $buttons['diff'] = Html::submitButton($this->context->msg('showdiff')->text(), $attribs); Hooks::run('EditPageBeforeEditButtons', [&$this, &$buttons, &$tabindex]); return $buttons; }
public static function onShowMissingArticle(Article $article) { if ($article->getPage()->getContentModel() !== CONTENT_MODEL_FLOW_BOARD) { return true; } if ($article->getTitle()->getNamespace() === NS_TOPIC) { // @todo pretty message about invalid workflow throw new FlowException('Non-existent topic'); } $emptyContent = ContentHandler::getForModelID(CONTENT_MODEL_FLOW_BOARD)->makeEmptyContent(); $parserOutput = $emptyContent->getParserOutput($article->getTitle()); $article->getContext()->getOutput()->addParserOutput($parserOutput); return false; }
/** * The ArticleViewHeader hook, used to alter the headers before the rest * of the data is loaded. * * Note: this is not called when the Edit, Diff or History pages are loaded. * * @param Article $article pointer to the Article Object from the hook * @param boolean $outputDone pointer to variable that indicates that * the output should be terminated * @param boolean $pcache pointer to variable that indicates whether the parser * cache should try retrieving the cached results * * @return boolean indicating success to the caller */ public function onArticleViewHeader(&$article, &$outputDone, &$pcache) { // avoid processing Mementos for nonexistent pages // if we're an article, do memento processing, otherwise don't worry // if we're a diff page, Memento doesn't make sense if ($article->getTitle()->isKnown()) { $this->oldIDSet = $article->getOldID() != 0; $revision = $article->getRevisionFetched(); // avoid processing Mementos for bad revisions, // let MediaWiki handle that case instead if (is_object($revision)) { $this->articleDatetime = $revision->getTimestamp(); $db = wfGetDB(DB_SLAVE); $oldID = $article->getOldID(); $request = $article->getContext()->getRequest(); $this->mementoResource = MementoResource::mementoPageResourceFactory($db, $article, $oldID); $this->mementoResource->alterHeaders(); } } return true; }
/** * Get the rendered text for previewing. * @return string */ function getPreviewText() { global $wgOut, $wgUser, $wgParser, $wgRawHtml, $wgLang; wfProfileIn(__METHOD__); if ($wgRawHtml && !$this->mTokenOk) { // Could be an offsite preview attempt. This is very unsafe if // HTML is enabled, as it could be an attack. $parsedNote = ''; if ($this->textbox1 !== '') { // Do not put big scary notice, if previewing the empty // string, which happens when you initially edit // a category page, due to automatic preview-on-open. $parsedNote = $wgOut->parse("<div class='previewnote'>" . wfMessage('session_fail_preview_html')->text() . "</div>", true, true); } wfProfileOut(__METHOD__); return $parsedNote; } if ($this->mTriedSave && !$this->mTokenOk) { if ($this->mTokenOkExceptSuffix) { $note = wfMessage('token_suffix_mismatch')->plain(); } else { $note = wfMessage('session_fail_preview')->plain(); } } elseif ($this->incompleteForm) { $note = wfMessage('edit_form_incomplete')->plain(); } else { $note = wfMessage('previewnote')->plain() . ' [[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' . wfMessage('continue-editing')->text() . ']]'; } $parserOptions = $this->mArticle->makeParserOptions($this->mArticle->getContext()); $parserOptions->setEditSection(false); $parserOptions->setIsPreview(true); $parserOptions->setIsSectionPreview(!is_null($this->section) && $this->section !== ''); # don't parse non-wikitext pages, show message about preview if ($this->mTitle->isCssJsSubpage() || !$this->mTitle->isWikitextPage()) { if ($this->mTitle->isCssJsSubpage()) { $level = 'user'; } elseif ($this->mTitle->isCssOrJsPage()) { $level = 'site'; } else { $level = false; } # Used messages to make sure grep find them: # Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview $class = 'mw-code'; if ($level) { if (preg_match("/\\.css\$/", $this->mTitle->getText())) { $previewtext = "<div id='mw-{$level}csspreview'>\n" . wfMessage("{$level}csspreview")->text() . "\n</div>"; $class .= " mw-css"; } elseif (preg_match("/\\.js\$/", $this->mTitle->getText())) { $previewtext = "<div id='mw-{$level}jspreview'>\n" . wfMessage("{$level}jspreview")->text() . "\n</div>"; $class .= " mw-js"; } else { throw new MWException('A CSS/JS (sub)page but which is not css nor js!'); } $parserOutput = $wgParser->parse($previewtext, $this->mTitle, $parserOptions); $previewHTML = $parserOutput->getText(); } else { $previewHTML = ''; } $previewHTML .= "<pre class=\"{$class}\" dir=\"ltr\">\n" . htmlspecialchars($this->textbox1) . "\n</pre>\n"; } else { $toparse = $this->textbox1; # If we're adding a comment, we need to show the # summary as the headline if ($this->section == "new" && $this->summary != "") { $toparse = wfMessage('newsectionheaderdefaultlevel', $this->summary)->inContentLanguage()->text() . "\n\n" . $toparse; } wfRunHooks('EditPageGetPreviewText', array($this, &$toparse)); $toparse = $wgParser->preSaveTransform($toparse, $this->mTitle, $wgUser, $parserOptions); $parserOutput = $wgParser->parse($toparse, $this->mTitle, $parserOptions); $rt = Title::newFromRedirectArray($this->textbox1); if ($rt) { $previewHTML = $this->mArticle->viewRedirect($rt, false); } else { $previewHTML = $parserOutput->getText(); } $this->mParserOutput = $parserOutput; $wgOut->addParserOutputNoText($parserOutput); if (count($parserOutput->getWarnings())) { $note .= "\n\n" . implode("\n\n", $parserOutput->getWarnings()); } } if ($this->isConflict) { $conflict = '<h2 id="mw-previewconflict">' . wfMessage('previewconflict')->escaped() . "</h2>\n"; } else { $conflict = '<hr />'; } $previewhead = "<div class='previewnote'>\n" . '<h2 id="mw-previewheader">' . wfMessage('preview')->escaped() . "</h2>" . $wgOut->parse($note, true, true) . $conflict . "</div>\n"; $pageLang = $this->mTitle->getPageLanguage(); $attribs = array('lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(), 'class' => 'mw-content-' . $pageLang->getDir()); $previewHTML = Html::rawElement('div', $attribs, $previewHTML); wfProfileOut(__METHOD__); return $previewhead . $previewHTML . $this->previewTextAfterContent; }