예제 #1
0
 /**
  * Get the formatter output for the given input data
  * @param array $params Query parameters
  * @param array $data Data to encode
  * @param string $class Printer class to use instead of the normal one
  * @return string
  * @throws Exception
  */
 protected function encodeData(array $params, array $data, $class = null)
 {
     $context = new RequestContext();
     $context->setRequest(new FauxRequest($params, true));
     $main = new ApiMain($context);
     if ($class !== null) {
         $main->getModuleManager()->addModule($this->printerName, 'format', $class);
     }
     $result = $main->getResult();
     $result->addArrayType(null, 'default');
     foreach ($data as $k => $v) {
         $result->addValue(null, $k, $v);
     }
     $printer = $main->createPrinterByName($this->printerName);
     $printer->initPrinter();
     $printer->execute();
     ob_start();
     try {
         $printer->closePrinter();
         return ob_get_clean();
     } catch (Exception $ex) {
         ob_end_clean();
         throw $ex;
     }
 }
 /**
  * @dataProvider provideGetDesktopUrl
  * @param string $class
  * @param string $subPage
  * @param array $params
  * @param string|null $expected
  */
 public function testGetDesktopUrl($class, $subPage, array $params, $expected)
 {
     $context = new RequestContext();
     $context->setRequest(new FauxRequest($params));
     $page = new $class();
     $page->setContext($context);
     $this->assertEquals($expected, $page->getDesktopUrl($subPage));
 }
 function setUp()
 {
     $this->page = new MIMESearchPage();
     $context = new RequestContext();
     $context->setTitle(Title::makeTitle(NS_SPECIAL, 'MIMESearch'));
     $context->setRequest(new FauxRequest());
     $this->page->setContext($context);
     parent::setUp();
 }
예제 #4
0
 public function testHandleNormalization()
 {
     $context = new RequestContext();
     $context->setRequest(new FauxRequest(['titles' => "a|B|å"]));
     $main = new ApiMain($context);
     $pageSet = new ApiPageSet($main);
     $pageSet->execute();
     $this->assertSame([0 => ['A' => -1, 'B' => -2, 'Å' => -3]], $pageSet->getAllTitlesByNamespace());
     $this->assertSame([['fromencoded' => true, 'from' => 'a%CC%8A', 'to' => 'å'], ['fromencoded' => false, 'from' => 'a', 'to' => 'A'], ['fromencoded' => false, 'from' => 'å', 'to' => 'Å']], $pageSet->getNormalizedTitlesAsResult());
 }
 /** helper to test SpecialRecentchanges::buildMainQueryConds() */
 private function assertConditions($expected, $requestOptions = null, $message = '')
 {
     $context = new RequestContext();
     $context->setRequest(new FauxRequest($requestOptions));
     # setup the rc object
     $this->rc = new SpecialRecentChanges();
     $this->rc->setContext($context);
     $formOptions = $this->rc->setup(null);
     #  Filter out rc_timestamp conditions which depends on the test runtime
     # This condition is not needed as of march 2, 2011 -- hashar
     # @todo FIXME: Find a way to generate the correct rc_timestamp
     $queryConditions = array_filter($this->rc->buildMainQueryConds($formOptions), 'SpecialRecentchangesTest::filterOutRcTimestampCondition');
     $this->assertEquals($expected, $queryConditions, $message);
 }
예제 #6
0
 /**
  * @covers MWDebug::appendDebugInfoToApiResult
  */
 public function testAppendDebugInfoToApiResultXmlFormat()
 {
     $request = $this->newApiRequest(['action' => 'help', 'format' => 'xml'], '/api.php?action=help&format=xml');
     $context = new RequestContext();
     $context->setRequest($request);
     $apiMain = new ApiMain($context);
     $result = new ApiResult($apiMain);
     MWDebug::appendDebugInfoToApiResult($context, $result);
     $this->assertInstanceOf('ApiResult', $result);
     $data = $result->getResultData();
     $expectedKeys = ['mwVersion', 'phpEngine', 'phpVersion', 'gitRevision', 'gitBranch', 'gitViewUrl', 'time', 'log', 'debugLog', 'queries', 'request', 'memory', 'memoryPeak', 'includes', '_element'];
     foreach ($expectedKeys as $expectedKey) {
         $this->assertArrayHasKey($expectedKey, $data['debuginfo'], "debuginfo has {$expectedKey}");
     }
     $xml = ApiFormatXml::recXmlPrint('help', $data);
     // exception not thrown
     $this->assertInternalType('string', $xml);
 }
예제 #7
0
 protected function createPageSetWithRedirect()
 {
     $target = Title::makeTitle(NS_MAIN, 'UTRedirectTarget');
     $sourceA = Title::makeTitle(NS_MAIN, 'UTRedirectSourceA');
     $sourceB = Title::makeTitle(NS_MAIN, 'UTRedirectSourceB');
     self::editPage('UTRedirectTarget', 'api page set test');
     self::editPage('UTRedirectSourceA', '#REDIRECT [[UTRedirectTarget]]');
     self::editPage('UTRedirectSourceB', '#REDIRECT [[UTRedirectTarget]]');
     $request = new FauxRequest(array('redirects' => 1));
     $context = new RequestContext();
     $context->setRequest($request);
     $main = new ApiMain($context);
     $pageSet = new ApiPageSet($main);
     $pageSet->setGeneratorData($sourceA, array('index' => 1));
     $pageSet->setGeneratorData($sourceB, array('index' => 3));
     $pageSet->populateFromTitles(array($sourceA, $sourceB));
     return array($target, $pageSet);
 }
 /**
  * Make sure a nickname which is longer than $wgMaxSigChars
  * is not throwing a fatal error.
  *
  * Test specifications by Alexandre "ialex" Emsenhuber.
  * @todo give this test a real name explaining what is being tested here
  */
 public function testBug41337()
 {
     // Set a low limit
     $this->setMwGlobals('wgMaxSigChars', 2);
     $user = $this->getMock('User');
     $user->expects($this->any())->method('isAnon')->will($this->returnValue(false));
     # Yeah foreach requires an array, not NULL =(
     $user->expects($this->any())->method('getEffectiveGroups')->will($this->returnValue([]));
     # The mocked user has a long nickname
     $user->expects($this->any())->method('getOption')->will($this->returnValueMap([['nickname', null, false, 'superlongnickname']]));
     # Forge a request to call the special page
     $context = new RequestContext();
     $context->setRequest(new FauxRequest());
     $context->setUser($user);
     $context->setTitle(Title::newFromText('Test'));
     # Do the call, should not spurt a fatal error.
     $special = new SpecialPreferences();
     $special->setContext($context);
     $this->assertNull($special->execute([]));
 }
예제 #9
0
 /**
  * @covers SpecialSearch::load
  * @dataProvider provideSearchOptionsTests
  * @param $requested Array Request parameters. For example array( 'ns5' => true, 'ns6' => true). NULL to use default options.
  * @param $userOptions Array User options to test with. For example array('searchNs5' => 1 );. NULL to use default options.
  * @param $expectedProfile An expected search profile name
  * @param $expectedNs Array Expected namespaces
  */
 function testProfileAndNamespaceLoading($requested, $userOptions, $expectedProfile, $expectedNS, $message = 'Profile name and namespaces mismatches!')
 {
     $context = new RequestContext();
     $context->setUser($this->newUserWithSearchNS($userOptions));
     /*
     		$context->setRequest( new FauxRequest( array(
     			'ns5'=>true,
     			'ns6'=>true,
     		) ));
     */
     $context->setRequest(new FauxRequest($requested));
     $search = new SpecialSearch();
     $search->setContext($context);
     $search->load();
     /**
      * Verify profile name and namespace in the same assertion to make
      * sure we will be able to fully compare the above code. PHPUnit stop
      * after an assertion fail.
      */
     $this->assertEquals(array('ProfileName' => $expectedProfile, 'Namespaces' => $expectedNS), array('ProfileName' => $search->getProfile(), 'Namespaces' => $search->getNamespaces()), $message);
 }
 public function testPrependHtmlForViewActionOnly()
 {
     $context = new \RequestContext();
     $context->setRequest(new \FauxRequest(array('action' => 'view'), true));
     $htmlBreadcrumbLinksBuilder = $this->getMockBuilder('\\SBL\\HtmlBreadcrumbLinksBuilder')->disableOriginalConstructor()->getMock();
     $htmlBreadcrumbLinksBuilder->expects($this->once())->method('buildBreadcrumbs')->will($this->returnSelf());
     $language = $this->getMockBuilder('\\Language')->disableOriginalConstructor()->getMock();
     $title = $this->getMockBuilder('\\Title')->disableOriginalConstructor()->getMock();
     $title->expects($this->once())->method('isKnown')->will($this->returnValue(true));
     $title->expects($this->once())->method('isSpecialPage')->will($this->returnValue(false));
     $title->expects($this->once())->method('getPageLanguage')->will($this->returnValue($language));
     $output = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $output->expects($this->once())->method('prependHTML');
     $output->expects($this->once())->method('getContext')->will($this->returnValue($context));
     $output->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $instance = new SkinTemplateOutputModifier($htmlBreadcrumbLinksBuilder);
     $this->assertTrue($instance->modifyOutput($output));
     $template = new \stdClass();
     $template->data = array();
     $instance->modifyTemplate($template);
     $this->assertEmpty($template->data['subtitle']);
 }
예제 #11
0
 /**
  * Just like executePath() except it returns the HTML instead of outputting it
  * Returns false if there was no such special page, or a title object if it was
  * a redirect.
  *
  * Also saves the current $wgTitle, $wgOut, and $wgRequest variables so that
  * the special page will get the context it'd expect on a normal request,
  * and then restores them to their previous values after.
  *
  * @param $title Title
  *
  * @return String: HTML fragment
  */
 static function capturePath(&$title)
 {
     global $wgOut, $wgTitle, $wgRequest;
     $oldTitle = $wgTitle;
     $oldOut = $wgOut;
     $oldRequest = $wgRequest;
     // Don't want special pages interpreting ?feed=atom parameters.
     $wgRequest = new FauxRequest(array());
     $context = new RequestContext();
     $context->setTitle($title);
     $context->setRequest($wgRequest);
     $wgOut = $context->getOutput();
     $ret = self::executePath($title, $context, true);
     if ($ret === true) {
         $ret = $wgOut->getHTML();
     }
     $wgTitle = $oldTitle;
     $wgOut = $oldOut;
     $wgRequest = $oldRequest;
     return $ret;
 }
 public function outputDataProvider()
 {
     $language = Language::factory('en');
     $title = MockTitle::buildMockForMainNamespace(__METHOD__ . 'mock-subject');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $subject = DIWikiPage::newFromTitle($title);
     $semanticData = $this->getMockBuilder('\\SMW\\SemanticData')->disableOriginalConstructor()->getMock();
     $semanticData->expects($this->atLeastOnce())->method('getSubject')->will($this->returnValue($subject));
     $semanticData->expects($this->atLeastOnce())->method('hasVisibleProperties')->will($this->returnValue(true));
     $semanticData->expects($this->atLeastOnce())->method('getPropertyValues')->will($this->returnValue(array(DIWikiPage::newFromTitle($title))));
     $semanticData->expects($this->atLeastOnce())->method('getProperties')->will($this->returnValue(array(new DIProperty(__METHOD__ . 'property'))));
     $store = $this->getMockBuilder('\\SMW\\Store')->disableOriginalConstructor()->getMockForAbstractClass();
     #0 Factbox build, being visible
     $title = MockTitle::buildMock(__METHOD__ . 'title-being-visible');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10001));
     $title->expects($this->atLeastOnce())->method('getLatestRevID')->will($this->returnValue(10001));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'smwgShowFactbox' => SMW_FACTBOX_NONEMPTY, 'outputPage' => $outputPage, 'store' => $store, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => $subject->getDBKey()));
     #1 Factbox build, being visible, using WebRequest oldid
     $title = MockTitle::buildMock(__METHOD__ . 'title-with-oldid');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10002));
     $title->expects($this->atLeastOnce())->method('getLatestRevID')->will($this->returnValue(10002));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $context = new \RequestContext();
     $context->setRequest(new \FauxRequest(array('oldid' => 9001), true));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue($context));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'smwgShowFactbox' => SMW_FACTBOX_NONEMPTY, 'outputPage' => $outputPage, 'store' => $store, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => $subject->getDBKey()));
     #2 Factbox is expected not to be visible
     $title = MockTitle::buildMock(__METHOD__ . 'title-ns-disabled');
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10003));
     $title->expects($this->atLeastOnce())->method('getLatestRevID')->will($this->returnValue(10003));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => false), 'smwgShowFactbox' => SMW_FACTBOX_HIDDEN, 'outputPage' => $outputPage, 'store' => $store, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => null));
     #3 No semantic data
     $title = MockTitle::buildMock(__METHOD__ . 'title-empty-semanticdata');
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10004));
     $title->expects($this->atLeastOnce())->method('getLatestRevID')->will($this->returnValue(10004));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $semanticData = $this->getMockBuilder('\\SMW\\SemanticData')->disableOriginalConstructor()->getMock();
     $semanticData->expects($this->atLeastOnce())->method('isEmpty')->will($this->returnValue(true));
     $store = $this->getMockBuilder('\\SMW\\Store')->disableOriginalConstructor()->getMockForAbstractClass();
     $store->expects($this->atLeastOnce())->method('getSemanticData')->will($this->returnValue($semanticData));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'smwgShowFactbox' => SMW_FACTBOX_NONEMPTY, 'outputPage' => $outputPage, 'store' => $store, 'parserOutput' => $this->makeParserOutput(null)), array('text' => null));
     // #4 SpecialPage
     $title = MockTitle::buildMock(__METHOD__ . 'title-specialpage');
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('isSpecialPage')->will($this->returnValue(true));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $store = $this->getMockBuilder('\\SMW\\Store')->disableOriginalConstructor()->getMockForAbstractClass();
     $store->expects($this->atLeastOnce())->method('getSemanticData')->will($this->returnValue($semanticData));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'smwgShowFactbox' => SMW_FACTBOX_NONEMPTY, 'outputPage' => $outputPage, 'store' => $store, 'parserOutput' => $this->makeParserOutput(null)), array('text' => ''));
     // #5 does not exist
     $title = MockTitle::buildMock(__METHOD__ . 'title-not-exists');
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(false));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $store = $this->getMockBuilder('\\SMW\\Store')->disableOriginalConstructor()->getMockForAbstractClass();
     $store->expects($this->atLeastOnce())->method('getSemanticData')->will($this->returnValue($semanticData));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'smwgShowFactbox' => SMW_FACTBOX_NONEMPTY, 'outputPage' => $outputPage, 'store' => $store, 'parserOutput' => $this->makeParserOutput(null)), array('text' => ''));
     return $provider;
 }
예제 #13
0
 /**
  * Return the text of a template, after recursively
  * replacing any variables or templates within the template.
  *
  * @param array $piece The parts of the template
  *  $piece['title']: the title, i.e. the part before the |
  *  $piece['parts']: the parameter array
  *  $piece['lineStart']: whether the brace was at the start of a line
  * @param PPFrame $frame The current frame, contains template arguments
  * @throws MWException
  * @return string The text of the template
  * @private
  */
 function braceSubstitution($piece, $frame)
 {
     wfProfileIn(__METHOD__);
     wfProfileIn(__METHOD__ . '-setup');
     # Flags
     $found = false;
     # $text has been filled
     $nowiki = false;
     # wiki markup in $text should be escaped
     $isHTML = false;
     # $text is HTML, armour it against wikitext transformation
     $forceRawInterwiki = false;
     # Force interwiki transclusion to be done in raw mode not rendered
     $isChildObj = false;
     # $text is a DOM node needing expansion in a child frame
     $isLocalObj = false;
     # $text is a DOM node needing expansion in the current frame
     # Title object, where $text came from
     $title = false;
     # $part1 is the bit before the first |, and must contain only title characters.
     # Various prefixes will be stripped from it later.
     $titleWithSpaces = $frame->expand($piece['title']);
     $part1 = trim($titleWithSpaces);
     $titleText = false;
     # Original title text preserved for various purposes
     $originalTitle = $part1;
     # $args is a list of argument nodes, starting from index 0, not including $part1
     # @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object
     $args = null == $piece['parts'] ? array() : $piece['parts'];
     wfProfileOut(__METHOD__ . '-setup');
     $titleProfileIn = null;
     // profile templates
     # SUBST
     wfProfileIn(__METHOD__ . '-modifiers');
     if (!$found) {
         $substMatch = $this->mSubstWords->matchStartAndRemove($part1);
         # Possibilities for substMatch: "subst", "safesubst" or FALSE
         # Decide whether to expand template or keep wikitext as-is.
         if ($this->ot['wiki']) {
             if ($substMatch === false) {
                 $literal = true;
                 # literal when in PST with no prefix
             } else {
                 $literal = false;
                 # expand when in PST with subst: or safesubst:
             }
         } else {
             if ($substMatch == 'subst') {
                 $literal = true;
                 # literal when not in PST with plain subst:
             } else {
                 $literal = false;
                 # expand when not in PST with safesubst: or no prefix
             }
         }
         if ($literal) {
             $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args);
             $isLocalObj = true;
             $found = true;
         }
     }
     # Variables
     if (!$found && $args->getLength() == 0) {
         $id = $this->mVariables->matchStartToEnd($part1);
         if ($id !== false) {
             $text = $this->getVariableValue($id, $frame);
             if (MagicWord::getCacheTTL($id) > -1) {
                 $this->mOutput->updateCacheExpiry(MagicWord::getCacheTTL($id));
             }
             $found = true;
         }
     }
     # MSG, MSGNW and RAW
     if (!$found) {
         # Check for MSGNW:
         $mwMsgnw = MagicWord::get('msgnw');
         if ($mwMsgnw->matchStartAndRemove($part1)) {
             $nowiki = true;
         } else {
             # Remove obsolete MSG:
             $mwMsg = MagicWord::get('msg');
             $mwMsg->matchStartAndRemove($part1);
         }
         # Check for RAW:
         $mwRaw = MagicWord::get('raw');
         if ($mwRaw->matchStartAndRemove($part1)) {
             $forceRawInterwiki = true;
         }
     }
     wfProfileOut(__METHOD__ . '-modifiers');
     # Parser functions
     if (!$found) {
         wfProfileIn(__METHOD__ . '-pfunc');
         $colonPos = strpos($part1, ':');
         if ($colonPos !== false) {
             $func = substr($part1, 0, $colonPos);
             $funcArgs = array(trim(substr($part1, $colonPos + 1)));
             for ($i = 0; $i < $args->getLength(); $i++) {
                 $funcArgs[] = $args->item($i);
             }
             try {
                 $result = $this->callParserFunction($frame, $func, $funcArgs);
             } catch (Exception $ex) {
                 wfProfileOut(__METHOD__ . '-pfunc');
                 wfProfileOut(__METHOD__);
                 throw $ex;
             }
             # The interface for parser functions allows for extracting
             # flags into the local scope. Extract any forwarded flags
             # here.
             extract($result);
         }
         wfProfileOut(__METHOD__ . '-pfunc');
     }
     # Finish mangling title and then check for loops.
     # Set $title to a Title object and $titleText to the PDBK
     if (!$found) {
         $ns = NS_TEMPLATE;
         # Split the title into page and subpage
         $subpage = '';
         $relative = $this->maybeDoSubpageLink($part1, $subpage);
         if ($part1 !== $relative) {
             $part1 = $relative;
             $ns = $this->mTitle->getNamespace();
         }
         $title = Title::newFromText($part1, $ns);
         if ($title) {
             $titleText = $title->getPrefixedText();
             # Check for language variants if the template is not found
             if ($this->getConverterLanguage()->hasVariants() && $title->getArticleID() == 0) {
                 $this->getConverterLanguage()->findVariantLink($part1, $title, true);
             }
             # Do recursion depth check
             $limit = $this->mOptions->getMaxTemplateDepth();
             if ($frame->depth >= $limit) {
                 $found = true;
                 $text = '<span class="error">' . wfMessage('parser-template-recursion-depth-warning')->numParams($limit)->inContentLanguage()->text() . '</span>';
             }
         }
     }
     # Load from database
     if (!$found && $title) {
         if (!Profiler::instance()->isPersistent()) {
             # Too many unique items can kill profiling DBs/collectors
             $titleProfileIn = __METHOD__ . "-title-" . $title->getPrefixedDBkey();
             wfProfileIn($titleProfileIn);
             // template in
         }
         wfProfileIn(__METHOD__ . '-loadtpl');
         if (!$title->isExternal()) {
             if ($title->isSpecialPage() && $this->mOptions->getAllowSpecialInclusion() && $this->ot['html']) {
                 // Pass the template arguments as URL parameters.
                 // "uselang" will have no effect since the Language object
                 // is forced to the one defined in ParserOptions.
                 $pageArgs = array();
                 for ($i = 0; $i < $args->getLength(); $i++) {
                     $bits = $args->item($i)->splitArg();
                     if (strval($bits['index']) === '') {
                         $name = trim($frame->expand($bits['name'], PPFrame::STRIP_COMMENTS));
                         $value = trim($frame->expand($bits['value']));
                         $pageArgs[$name] = $value;
                     }
                 }
                 // Create a new context to execute the special page
                 $context = new RequestContext();
                 $context->setTitle($title);
                 $context->setRequest(new FauxRequest($pageArgs));
                 $context->setUser($this->getUser());
                 $context->setLanguage($this->mOptions->getUserLangObj());
                 $ret = SpecialPageFactory::capturePath($title, $context);
                 if ($ret) {
                     $text = $context->getOutput()->getHTML();
                     $this->mOutput->addOutputPageMetadata($context->getOutput());
                     $found = true;
                     $isHTML = true;
                     $this->disableCache();
                 }
             } elseif (MWNamespace::isNonincludable($title->getNamespace())) {
                 $found = false;
                 # access denied
                 wfDebug(__METHOD__ . ": template inclusion denied for " . $title->getPrefixedDBkey() . "\n");
             } else {
                 list($text, $title) = $this->getTemplateDom($title);
                 if ($text !== false) {
                     $found = true;
                     $isChildObj = true;
                 }
             }
             # If the title is valid but undisplayable, make a link to it
             if (!$found && ($this->ot['html'] || $this->ot['pre'])) {
                 $text = "[[:{$titleText}]]";
                 $found = true;
             }
         } elseif ($title->isTrans()) {
             # Interwiki transclusion
             if ($this->ot['html'] && !$forceRawInterwiki) {
                 $text = $this->interwikiTransclude($title, 'render');
                 $isHTML = true;
             } else {
                 $text = $this->interwikiTransclude($title, 'raw');
                 # Preprocess it like a template
                 $text = $this->preprocessToDom($text, self::PTD_FOR_INCLUSION);
                 $isChildObj = true;
             }
             $found = true;
         }
         # Do infinite loop check
         # This has to be done after redirect resolution to avoid infinite loops via redirects
         if (!$frame->loopCheck($title)) {
             $found = true;
             $text = '<span class="error">' . wfMessage('parser-template-loop-warning', $titleText)->inContentLanguage()->text() . '</span>';
             wfDebug(__METHOD__ . ": template loop broken at '{$titleText}'\n");
         }
         wfProfileOut(__METHOD__ . '-loadtpl');
     }
     # If we haven't found text to substitute by now, we're done
     # Recover the source wikitext and return it
     if (!$found) {
         $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args);
         if ($titleProfileIn) {
             wfProfileOut($titleProfileIn);
             // template out
         }
         wfProfileOut(__METHOD__);
         return array('object' => $text);
     }
     # Expand DOM-style return values in a child frame
     if ($isChildObj) {
         # Clean up argument array
         $newFrame = $frame->newChild($args, $title);
         if ($nowiki) {
             $text = $newFrame->expand($text, PPFrame::RECOVER_ORIG);
         } elseif ($titleText !== false && $newFrame->isEmpty()) {
             # Expansion is eligible for the empty-frame cache
             if (isset($this->mTplExpandCache[$titleText])) {
                 $text = $this->mTplExpandCache[$titleText];
             } else {
                 $text = $newFrame->expand($text);
                 $this->mTplExpandCache[$titleText] = $text;
             }
         } else {
             # Uncached expansion
             $text = $newFrame->expand($text);
         }
     }
     if ($isLocalObj && $nowiki) {
         $text = $frame->expand($text, PPFrame::RECOVER_ORIG);
         $isLocalObj = false;
     }
     if ($titleProfileIn) {
         wfProfileOut($titleProfileIn);
         // template out
     }
     # Replace raw HTML by a placeholder
     if ($isHTML) {
         $text = $this->insertStripItem($text);
     } elseif ($nowiki && ($this->ot['html'] || $this->ot['pre'])) {
         # Escape nowiki-style return values
         $text = wfEscapeWikiText($text);
     } elseif (is_string($text) && !$piece['lineStart'] && preg_match('/^(?:{\\||:|;|#|\\*)/', $text)) {
         # Bug 529: if the template begins with a table or block-level
         # element, it should be treated as beginning a new line.
         # This behavior is somewhat controversial.
         $text = "\n" . $text;
     }
     if (is_string($text) && !$this->incrementIncludeSize('post-expand', strlen($text))) {
         # Error, oversize inclusion
         if ($titleText !== false) {
             # Make a working, properly escaped link if possible (bug 23588)
             $text = "[[:{$titleText}]]";
         } else {
             # This will probably not be a working link, but at least it may
             # provide some hint of where the problem is
             preg_replace('/^:/', '', $originalTitle);
             $text = "[[:{$originalTitle}]]";
         }
         $text .= $this->insertStripItem('<!-- WARNING: template omitted, post-expand include size too large -->');
         $this->limitationWarn('post-expand-template-inclusion');
     }
     if ($isLocalObj) {
         $ret = array('object' => $text);
     } else {
         $ret = array('text' => $text);
     }
     wfProfileOut(__METHOD__);
     return $ret;
 }
예제 #14
0
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) {
         $this->dieUsageMsg('missingtext');
     }
     $pageObj = $this->getTitleOrPageId($params);
     $titleObj = $pageObj->getTitle();
     $apiResult = $this->getResult();
     if ($params['redirect']) {
         if ($params['prependtext'] === null && $params['appendtext'] === null && $params['section'] !== 'new') {
             $this->dieUsage('You have attempted to edit using the "redirect"-following' . ' mode, which must be used in conjuction with section=new, prependtext' . ', or appendtext.', 'redirect-appendonly');
         }
         if ($titleObj->isRedirect()) {
             $oldTitle = $titleObj;
             $titles = Revision::newFromTitle($oldTitle, false, Revision::READ_LATEST)->getContent(Revision::FOR_THIS_USER, $user)->getRedirectChain();
             // array_shift( $titles );
             $redirValues = array();
             /** @var $newTitle Title */
             foreach ($titles as $id => $newTitle) {
                 if (!isset($titles[$id - 1])) {
                     $titles[$id - 1] = $oldTitle;
                 }
                 $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText());
                 $titleObj = $newTitle;
             }
             ApiResult::setIndexedTagName($redirValues, 'r');
             $apiResult->addValue(null, 'redirects', $redirValues);
             // Since the page changed, update $pageObj
             $pageObj = WikiPage::factory($titleObj);
         }
     }
     if (!isset($params['contentmodel']) || $params['contentmodel'] == '') {
         $contentHandler = $pageObj->getContentHandler();
     } else {
         $contentHandler = ContentHandler::getForModelID($params['contentmodel']);
     }
     $name = $titleObj->getPrefixedDBkey();
     $model = $contentHandler->getModelID();
     if ($contentHandler->supportsDirectApiEditing() === false) {
         $this->dieUsage("Direct editing via API is not supported for content model {$model} used by {$name}", 'no-direct-editing');
     }
     if (!isset($params['contentformat']) || $params['contentformat'] == '') {
         $params['contentformat'] = $contentHandler->getDefaultFormat();
     }
     $contentFormat = $params['contentformat'];
     if (!$contentHandler->isSupportedFormat($contentFormat)) {
         $this->dieUsage("The requested format {$contentFormat} is not supported for content model " . " {$model} used by {$name}", 'badformat');
     }
     if ($params['createonly'] && $titleObj->exists()) {
         $this->dieUsageMsg('createonly-exists');
     }
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg('nocreate-missing');
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $user);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $user));
     }
     if (count($errors)) {
         if (is_array($errors[0])) {
             switch ($errors[0][0]) {
                 case 'blockedtext':
                     $this->dieUsage('You have been blocked from editing', 'blocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())));
                     break;
                 case 'autoblockedtext':
                     $this->dieUsage('Your IP address has been blocked automatically, because it was used by a blocked user', 'autoblocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())));
                     break;
                 default:
                     $this->dieUsageMsg($errors[0]);
             }
         } else {
             $this->dieUsageMsg($errors[0]);
         }
     }
     $toMD5 = $params['text'];
     if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) {
         $content = $pageObj->getContent();
         if (!$content) {
             if ($titleObj->getNamespace() == NS_MEDIAWIKI) {
                 # If this is a MediaWiki:x message, then load the messages
                 # and return the message value for x.
                 $text = $titleObj->getDefaultMessageText();
                 if ($text === false) {
                     $text = '';
                 }
                 try {
                     $content = ContentHandler::makeContent($text, $this->getTitle());
                 } catch (MWContentSerializationException $ex) {
                     $this->dieUsage($ex->getMessage(), 'parseerror');
                     return;
                 }
             } else {
                 # Otherwise, make a new empty content.
                 $content = $contentHandler->makeEmptyContent();
             }
         }
         // @todo Add support for appending/prepending to the Content interface
         if (!$content instanceof TextContent) {
             $mode = $contentHandler->getModelID();
             $this->dieUsage("Can't append to pages using content model {$mode}", 'appendnotsupported');
         }
         if (!is_null($params['section'])) {
             if (!$contentHandler->supportsSections()) {
                 $modelName = $contentHandler->getModelID();
                 $this->dieUsage("Sections are not supported for this content model: {$modelName}.", 'sectionsnotsupported');
             }
             if ($params['section'] == 'new') {
                 // DWIM if they're trying to prepend/append to a new section.
                 $content = null;
             } else {
                 // Process the content for section edits
                 $section = $params['section'];
                 $content = $content->getSection($section);
                 if (!$content) {
                     $this->dieUsage("There is no section {$section}.", 'nosuchsection');
                 }
             }
         }
         if (!$content) {
             $text = '';
         } else {
             $text = $content->serialize($contentFormat);
         }
         $params['text'] = $params['prependtext'] . $text . $params['appendtext'];
         $toMD5 = $params['prependtext'] . $params['appendtext'];
     }
     if ($params['undo'] > 0) {
         if ($params['undoafter'] > 0) {
             if ($params['undo'] < $params['undoafter']) {
                 list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']);
             }
             $undoafterRev = Revision::newFromId($params['undoafter']);
         }
         $undoRev = Revision::newFromId($params['undo']);
         if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undo']));
         }
         if ($params['undoafter'] == 0) {
             $undoafterRev = $undoRev->getPrevious();
         }
         if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undoafter']));
         }
         if ($undoRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText()));
         }
         if ($undoafterRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText()));
         }
         $newContent = $contentHandler->getUndoContent($pageObj->getRevision(), $undoRev, $undoafterRev);
         if (!$newContent) {
             $this->dieUsageMsg('undo-failure');
         }
         $params['text'] = $newContent->serialize($params['contentformat']);
         // If no summary was given and we only undid one rev,
         // use an autosummary
         if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) {
             $params['summary'] = wfMessage('undo-summary')->params($params['undo'], $undoRev->getUserText())->inContentLanguage()->text();
         }
     }
     // See if the MD5 hash checks out
     if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) {
         $this->dieUsageMsg('hashcheckfailed');
     }
     // EditPage wants to parse its stuff from a WebRequest
     // That interface kind of sucks, but it's workable
     $requestArray = array('wpTextbox1' => $params['text'], 'format' => $contentFormat, 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => true, 'wpIgnoreBlankArticle' => true, 'wpIgnoreSelfRedirect' => true, 'bot' => $params['bot']);
     if (!is_null($params['summary'])) {
         $requestArray['wpSummary'] = $params['summary'];
     }
     if (!is_null($params['sectiontitle'])) {
         $requestArray['wpSectionTitle'] = $params['sectiontitle'];
     }
     // TODO: Pass along information from 'undoafter' as well
     if ($params['undo'] > 0) {
         $requestArray['wpUndidRevision'] = $params['undo'];
     }
     // Watch out for basetimestamp == '' or '0'
     // It gets treated as NOW, almost certainly causing an edit conflict
     if ($params['basetimestamp'] !== null && (bool) $this->getMain()->getVal('basetimestamp')) {
         $requestArray['wpEdittime'] = $params['basetimestamp'];
     } else {
         $requestArray['wpEdittime'] = $pageObj->getTimestamp();
     }
     if ($params['starttimestamp'] !== null) {
         $requestArray['wpStarttime'] = $params['starttimestamp'];
     } else {
         $requestArray['wpStarttime'] = wfTimestampNow();
         // Fake wpStartime
     }
     if ($params['minor'] || !$params['notminor'] && $user->getOption('minordefault')) {
         $requestArray['wpMinoredit'] = '';
     }
     if ($params['recreate']) {
         $requestArray['wpRecreate'] = '';
     }
     if (!is_null($params['section'])) {
         $section = $params['section'];
         if (!preg_match('/^((T-)?\\d+|new)$/', $section)) {
             $this->dieUsage("The section parameter must be a valid section id or 'new'", "invalidsection");
         }
         $content = $pageObj->getContent();
         if ($section !== '0' && $section != 'new' && (!$content || !$content->getSection($section))) {
             $this->dieUsage("There is no section {$section}.", 'nosuchsection');
         }
         $requestArray['wpSection'] = $params['section'];
     } else {
         $requestArray['wpSection'] = '';
     }
     $watch = $this->getWatchlistValue($params['watchlist'], $titleObj);
     // Deprecated parameters
     if ($params['watch']) {
         $this->logFeatureUsage('action=edit&watch');
         $watch = true;
     } elseif ($params['unwatch']) {
         $this->logFeatureUsage('action=edit&unwatch');
         $watch = false;
     }
     if ($watch) {
         $requestArray['wpWatchthis'] = '';
     }
     // Apply change tags
     if (count($params['tags'])) {
         if ($user->isAllowed('applychangetags')) {
             $requestArray['wpChangeTags'] = implode(',', $params['tags']);
         } else {
             $this->dieUsage('You don\'t have permission to set change tags.', 'taggingnotallowed');
         }
     }
     // Pass through anything else we might have been given, to support extensions
     // This is kind of a hack but it's the best we can do to make extensions work
     $requestArray += $this->getRequest()->getValues();
     global $wgTitle, $wgRequest;
     $req = new DerivativeRequest($this->getRequest(), $requestArray, true);
     // Some functions depend on $wgTitle == $ep->mTitle
     // TODO: Make them not or check if they still do
     $wgTitle = $titleObj;
     $articleContext = new RequestContext();
     $articleContext->setRequest($req);
     $articleContext->setWikiPage($pageObj);
     $articleContext->setUser($this->getUser());
     /** @var $articleObject Article */
     $articleObject = Article::newFromWikiPage($pageObj, $articleContext);
     $ep = new EditPage($articleObject);
     $ep->setApiEditOverride(true);
     $ep->setContextTitle($titleObj);
     $ep->importFormData($req);
     $content = $ep->textbox1;
     // The following is needed to give the hook the full content of the
     // new revision rather than just the current section. (Bug 52077)
     if (!is_null($params['section']) && $contentHandler->supportsSections() && $titleObj->exists()) {
         // If sectiontitle is set, use it, otherwise use the summary as the section title (for
         // backwards compatibility with old forms/bots).
         if ($ep->sectiontitle !== '') {
             $sectionTitle = $ep->sectiontitle;
         } else {
             $sectionTitle = $ep->summary;
         }
         $contentObj = $contentHandler->unserializeContent($content, $contentFormat);
         $fullContentObj = $articleObject->replaceSectionContent($params['section'], $contentObj, $sectionTitle);
         if ($fullContentObj) {
             $content = $fullContentObj->serialize($contentFormat);
         } else {
             // This most likely means we have an edit conflict which means that the edit
             // wont succeed anyway.
             $this->dieUsageMsg('editconflict');
         }
     }
     // Run hooks
     // Handle APIEditBeforeSave parameters
     $r = array();
     if (!Hooks::run('APIEditBeforeSave', array($ep, $content, &$r))) {
         if (count($r)) {
             $r['result'] = 'Failure';
             $apiResult->addValue(null, $this->getModuleName(), $r);
             return;
         }
         $this->dieUsageMsg('hookaborted');
     }
     // Do the actual save
     $oldRevId = $articleObject->getRevIdFetched();
     $result = null;
     // Fake $wgRequest for some hooks inside EditPage
     // @todo FIXME: This interface SUCKS
     $oldRequest = $wgRequest;
     $wgRequest = $req;
     $status = $ep->attemptSave($result);
     $wgRequest = $oldRequest;
     switch ($status->value) {
         case EditPage::AS_HOOK_ERROR:
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             if (isset($status->apiHookResult)) {
                 $r = $status->apiHookResult;
                 $r['result'] = 'Failure';
                 $apiResult->addValue(null, $this->getModuleName(), $r);
                 return;
             } else {
                 $this->dieUsageMsg('hookaborted');
             }
         case EditPage::AS_PARSE_ERROR:
             $this->dieUsage($status->getMessage(), 'parseerror');
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             $this->dieUsageMsg('noimageredirect-anon');
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             $this->dieUsageMsg('noimageredirect-logged');
         case EditPage::AS_SPAM_ERROR:
             $this->dieUsageMsg(array('spamdetected', $result['spam']));
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $this->dieUsage('You have been blocked from editing', 'blocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())));
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
         case EditPage::AS_CONTENT_TOO_BIG:
             $this->dieUsageMsg(array('contenttoobig', $this->getConfig()->get('MaxArticleSize')));
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             $this->dieUsageMsg('noedit-anon');
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $this->dieUsageMsg('noedit');
         case EditPage::AS_READ_ONLY_PAGE:
             $this->dieReadOnly();
         case EditPage::AS_RATE_LIMITED:
             $this->dieUsageMsg('actionthrottledtext');
         case EditPage::AS_ARTICLE_WAS_DELETED:
             $this->dieUsageMsg('wasdeleted');
         case EditPage::AS_NO_CREATE_PERMISSION:
             $this->dieUsageMsg('nocreate-loggedin');
         case EditPage::AS_NO_CHANGE_CONTENT_MODEL:
             $this->dieUsageMsg('cantchangecontentmodel');
         case EditPage::AS_BLANK_ARTICLE:
             $this->dieUsageMsg('blankpage');
         case EditPage::AS_CONFLICT_DETECTED:
             $this->dieUsageMsg('editconflict');
         case EditPage::AS_TEXTBOX_EMPTY:
             $this->dieUsageMsg('emptynewsection');
         case EditPage::AS_CHANGE_TAG_ERROR:
             $this->dieStatus($status);
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             $r['new'] = true;
             // fall-through
         // fall-through
         case EditPage::AS_SUCCESS_UPDATE:
             $r['result'] = 'Success';
             $r['pageid'] = intval($titleObj->getArticleID());
             $r['title'] = $titleObj->getPrefixedText();
             $r['contentmodel'] = $articleObject->getContentModel();
             $newRevId = $articleObject->getLatest();
             if ($newRevId == $oldRevId) {
                 $r['nochange'] = true;
             } else {
                 $r['oldrevid'] = intval($oldRevId);
                 $r['newrevid'] = intval($newRevId);
                 $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $pageObj->getTimestamp());
             }
             break;
         case EditPage::AS_SUMMARY_NEEDED:
             // Shouldn't happen since we set wpIgnoreBlankSummary, but just in case
             $this->dieUsageMsg('summaryrequired');
         case EditPage::AS_END:
         default:
             // $status came from WikiPage::doEdit()
             $errors = $status->getErrorsArray();
             $this->dieUsageMsg($errors[0]);
             // TODO: Add new errors to message map
             break;
     }
     $apiResult->addValue(null, $this->getModuleName(), $r);
 }
 public function outputDataProvider()
 {
     $text = __METHOD__ . 'text-0';
     #0 Retrive content from outputPage property
     $title = MockTitle::buildMock(__METHOD__ . 'from-property');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10001));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->mSMWFactboxText = $text;
     $skin = $this->getMockBuilder('\\Skin')->disableOriginalConstructor()->getMock();
     $skin->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue(null));
     $skin->expects($this->atLeastOnce())->method('getOutput')->will($this->returnValue($outputPage));
     $skin->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('skin' => $skin), array('text' => $text));
     #1 Retrive content from cache
     $title = MockTitle::buildMock(__METHOD__ . 'from-cache');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10002));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $text = __METHOD__ . 'text-1';
     $skin = $this->getMockBuilder('\\Skin')->disableOriginalConstructor()->getMock();
     $skin->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $skin->expects($this->atLeastOnce())->method('getOutput')->will($this->returnValue($outputPage));
     $skin->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('skin' => $skin, 'text' => $text, 'title' => $outputPage->getTitle()), array('text' => $text));
     // #2 Special page
     $text = __METHOD__ . 'text-2';
     $title = MockTitle::buildMock(__METHOD__ . 'specialpage');
     $title->expects($this->atLeastOnce())->method('isSpecialPage')->will($this->returnValue(true));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->mSMWFactboxText = $text;
     $skin = $this->getMockBuilder('\\Skin')->disableOriginalConstructor()->getMock();
     $skin->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $skin->expects($this->atLeastOnce())->method('getOutput')->will($this->returnValue($outputPage));
     $skin->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('skin' => $skin, 'text' => $text), array('text' => ''));
     // #3 "edit" request
     $text = __METHOD__ . 'text-3';
     $title = MockTitle::buildMock(__METHOD__ . 'edit-request');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(10003));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->mSMWFactboxText = $text;
     $skin = $this->getMockBuilder('\\Skin')->disableOriginalConstructor()->getMock();
     $skin->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $skin->expects($this->atLeastOnce())->method('getOutput')->will($this->returnValue($outputPage));
     $context = new \RequestContext();
     $context->setRequest(new \FauxRequest(array('action' => 'edit'), true));
     $skin->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue($context));
     $provider[] = array(array('skin' => $skin, 'text' => $text), array('text' => $text));
     // #4 "delete" request
     $text = __METHOD__ . 'text-4';
     $title = MockTitle::buildMock(__METHOD__ . 'delete-request');
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $skin = $this->getMockBuilder('\\Skin')->disableOriginalConstructor()->getMock();
     $skin->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $skin->expects($this->atLeastOnce())->method('getOutput')->will($this->returnValue($outputPage));
     $context = new \RequestContext();
     $context->setRequest(new \FauxRequest(array('action' => 'delete'), true));
     $skin->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue($context));
     $provider[] = array(array('skin' => $skin, 'text' => $text), array('text' => ''));
     return $provider;
 }
    public function testRedirectToSpecialPageDoesntTriggerNotices()
    {
        $props = array('lastmodified', 'lastmodifiedby', 'revision', 'id', 'languagecount', 'hasvariants', 'displaytitle');
        $this->setMwGlobals('wgAPIModules', array('mobileview' => 'MockApiMobileView'));
        $request = new FauxRequest(array('action' => 'mobileview', 'page' => 'Foo', 'sections' => '1-', 'noheadings' => '', 'text' => 'Lead
== Section 1 ==
Text 1
== Section 2 ==
Text 2
', 'prop' => implode('|', $props), 'page' => 'Redirected', 'redirect' => 'yes'));
        $context = new RequestContext();
        $context->setRequest($request);
        $api = new MockApiMobileView(new ApiMain($context), 'mobileview');
        $api->execute();
        if (defined('ApiResult::META_CONTENT')) {
            $result = $api->getResult()->getResultData();
        } else {
            $result = $api->getResultData();
        }
        foreach ($props as $prop) {
            $this->assertFalse(isset($result[$prop]), "{$prop} isn't included in the response when it can't be fetched.");
        }
    }
예제 #17
0
 /**
  * @covers OutputPage::haveCacheVaryCookies
  */
 function testHaveCacheVaryCookies()
 {
     $request = new FauxRequest();
     $context = new RequestContext();
     $context->setRequest($request);
     $outputPage = new OutputPage($context);
     // No cookies are set.
     $this->assertFalse($outputPage->haveCacheVaryCookies());
     // 'Token' is present but empty, so it shouldn't count.
     $request->setCookie('Token', '');
     $this->assertFalse($outputPage->haveCacheVaryCookies());
     // 'Token' present and nonempty.
     $request->setCookie('Token', '123');
     $this->assertTrue($outputPage->haveCacheVaryCookies());
 }
 public function outputDataProvider()
 {
     $language = Language::factory('en');
     $title = MockTitle::buildMockForMainNamespace(__METHOD__ . 'mock-subject');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $subject = DIWikiPage::newFromTitle($title);
     $semanticData = $this->getMockBuilder('\\SMW\\SemanticData')->disableOriginalConstructor()->getMock();
     $semanticData->expects($this->atLeastOnce())->method('getSubject')->will($this->returnValue($subject));
     $semanticData->expects($this->atLeastOnce())->method('hasVisibleProperties')->will($this->returnValue(true));
     $semanticData->expects($this->atLeastOnce())->method('getPropertyValues')->will($this->returnValue(array(DIWikiPage::newFromTitle($title))));
     $semanticData->expects($this->atLeastOnce())->method('getProperties')->will($this->returnValue(array(new DIProperty(__METHOD__ . 'property'))));
     #0 Simple factbox build, returning content
     $title = MockTitle::buildMock(__METHOD__ . 'title-with-content');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(9098));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'outputPage' => $outputPage, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => $subject->getDBKey()));
     #1 Disabled namespace, no return value expected
     $title = MockTitle::buildMock(__METHOD__ . 'title-ns-disabled');
     $title->expects($this->atLeastOnce())->method('getNamespace')->will($this->returnValue(NS_MAIN));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('getArticleID')->will($this->returnValue(90000));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => false), 'outputPage' => $outputPage, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => ''));
     // #2 Specialpage, no return value expected
     $title = MockTitle::buildMock(__METHOD__ . 'mock-specialpage');
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('isSpecialPage')->will($this->returnValue(true));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'outputPage' => $outputPage, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => ''));
     // #3 Redirect, no return value expected
     $title = MockTitle::buildMock(__METHOD__ . 'mock-redirect');
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $title->expects($this->atLeastOnce())->method('isRedirect')->will($this->returnValue(true));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue(new \RequestContext()));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'outputPage' => $outputPage, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => ''));
     // #4 Oldid
     $title = MockTitle::buildMockForMainNamespace(__METHOD__ . 'mock-oldid');
     $title->expects($this->atLeastOnce())->method('exists')->will($this->returnValue(true));
     $title->expects($this->atLeastOnce())->method('getPageLanguage')->will($this->returnValue($language));
     $outputPage = $this->getMockBuilder('\\OutputPage')->disableOriginalConstructor()->getMock();
     $outputPage->expects($this->atLeastOnce())->method('getTitle')->will($this->returnValue($title));
     $context = new \RequestContext();
     $context->setRequest(new \FauxRequest(array('oldid' => 9001), true));
     $outputPage->expects($this->atLeastOnce())->method('getContext')->will($this->returnValue($context));
     $provider[] = array(array('smwgNamespacesWithSemanticLinks' => array(NS_MAIN => true), 'outputPage' => $outputPage, 'parserOutput' => $this->makeParserOutput($semanticData)), array('text' => $subject->getDBKey()));
     return $provider;
 }
예제 #19
0
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) {
         $this->dieUsageMsg('missingtext');
     }
     $pageObj = $this->getTitleOrPageId($params);
     $titleObj = $pageObj->getTitle();
     $apiResult = $this->getResult();
     if ($params['redirect']) {
         if ($titleObj->isRedirect()) {
             $oldTitle = $titleObj;
             $titles = Revision::newFromTitle($oldTitle, false, Revision::READ_LATEST)->getContent(Revision::FOR_THIS_USER, $user)->getRedirectChain();
             // array_shift( $titles );
             $redirValues = array();
             /** @var $newTitle Title */
             foreach ($titles as $id => $newTitle) {
                 if (!isset($titles[$id - 1])) {
                     $titles[$id - 1] = $oldTitle;
                 }
                 $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText());
                 $titleObj = $newTitle;
             }
             $apiResult->setIndexedTagName($redirValues, 'r');
             $apiResult->addValue(null, 'redirects', $redirValues);
             // Since the page changed, update $pageObj
             $pageObj = WikiPage::factory($titleObj);
         }
     }
     if (!isset($params['contentmodel']) || $params['contentmodel'] == '') {
         $contentHandler = $pageObj->getContentHandler();
     } else {
         $contentHandler = ContentHandler::getForModelID($params['contentmodel']);
     }
     // @todo ask handler whether direct editing is supported at all! make allowFlatEdit() method or some such
     if (!isset($params['contentformat']) || $params['contentformat'] == '') {
         $params['contentformat'] = $contentHandler->getDefaultFormat();
     }
     $contentFormat = $params['contentformat'];
     if (!$contentHandler->isSupportedFormat($contentFormat)) {
         $name = $titleObj->getPrefixedDBkey();
         $model = $contentHandler->getModelID();
         $this->dieUsage("The requested format {$contentFormat} is not supported for content model " . " {$model} used by {$name}", 'badformat');
     }
     if ($params['createonly'] && $titleObj->exists()) {
         $this->dieUsageMsg('createonly-exists');
     }
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg('nocreate-missing');
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $user);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $user));
     }
     if (count($errors)) {
         $this->dieUsageMsg($errors[0]);
     }
     $toMD5 = $params['text'];
     if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) {
         $content = $pageObj->getContent();
         if (!$content) {
             if ($titleObj->getNamespace() == NS_MEDIAWIKI) {
                 # If this is a MediaWiki:x message, then load the messages
                 # and return the message value for x.
                 $text = $titleObj->getDefaultMessageText();
                 if ($text === false) {
                     $text = '';
                 }
                 try {
                     $content = ContentHandler::makeContent($text, $this->getTitle());
                 } catch (MWContentSerializationException $ex) {
                     $this->dieUsage($ex->getMessage(), 'parseerror');
                     return;
                 }
             } else {
                 # Otherwise, make a new empty content.
                 $content = $contentHandler->makeEmptyContent();
             }
         }
         // @todo Add support for appending/prepending to the Content interface
         if (!$content instanceof TextContent) {
             $mode = $contentHandler->getModelID();
             $this->dieUsage("Can't append to pages using content model {$mode}", 'appendnotsupported');
         }
         if (!is_null($params['section'])) {
             if (!$contentHandler->supportsSections()) {
                 $modelName = $contentHandler->getModelID();
                 $this->dieUsage("Sections are not supported for this content model: {$modelName}.", 'sectionsnotsupported');
             }
             // Process the content for section edits
             $section = intval($params['section']);
             $content = $content->getSection($section);
             if (!$content) {
                 $this->dieUsage("There is no section {$section}.", 'nosuchsection');
             }
         }
         if (!$content) {
             $text = '';
         } else {
             $text = $content->serialize($contentFormat);
         }
         $params['text'] = $params['prependtext'] . $text . $params['appendtext'];
         $toMD5 = $params['prependtext'] . $params['appendtext'];
     }
     if ($params['undo'] > 0) {
         if ($params['undoafter'] > 0) {
             if ($params['undo'] < $params['undoafter']) {
                 list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']);
             }
             $undoafterRev = Revision::newFromID($params['undoafter']);
         }
         $undoRev = Revision::newFromID($params['undo']);
         if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undo']));
         }
         if ($params['undoafter'] == 0) {
             $undoafterRev = $undoRev->getPrevious();
         }
         if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undoafter']));
         }
         if ($undoRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText()));
         }
         if ($undoafterRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText()));
         }
         $newContent = $contentHandler->getUndoContent($pageObj->getRevision(), $undoRev, $undoafterRev);
         if (!$newContent) {
             $this->dieUsageMsg('undo-failure');
         }
         $params['text'] = $newContent->serialize($params['contentformat']);
         // If no summary was given and we only undid one rev,
         // use an autosummary
         if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) {
             $params['summary'] = wfMessage('undo-summary', $params['undo'], $undoRev->getUserText())->inContentLanguage()->text();
         }
     }
     // See if the MD5 hash checks out
     if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) {
         $this->dieUsageMsg('hashcheckfailed');
     }
     // EditPage wants to parse its stuff from a WebRequest
     // That interface kind of sucks, but it's workable
     $requestArray = array('wpTextbox1' => $params['text'], 'format' => $contentFormat, 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '');
     if (!is_null($params['summary'])) {
         $requestArray['wpSummary'] = $params['summary'];
     }
     if (!is_null($params['sectiontitle'])) {
         $requestArray['wpSectionTitle'] = $params['sectiontitle'];
     }
     // TODO: Pass along information from 'undoafter' as well
     if ($params['undo'] > 0) {
         $requestArray['wpUndidRevision'] = $params['undo'];
     }
     // Watch out for basetimestamp == ''
     // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
     if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') {
         $requestArray['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']);
     } else {
         $requestArray['wpEdittime'] = $pageObj->getTimestamp();
     }
     if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') {
         $requestArray['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']);
     } else {
         $requestArray['wpStarttime'] = wfTimestampNow();
         // Fake wpStartime
     }
     if ($params['minor'] || !$params['notminor'] && $user->getOption('minordefault')) {
         $requestArray['wpMinoredit'] = '';
     }
     if ($params['recreate']) {
         $requestArray['wpRecreate'] = '';
     }
     if (!is_null($params['section'])) {
         $section = intval($params['section']);
         if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') {
             $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection");
         }
         $requestArray['wpSection'] = $params['section'];
     } else {
         $requestArray['wpSection'] = '';
     }
     $watch = $this->getWatchlistValue($params['watchlist'], $titleObj);
     // Deprecated parameters
     if ($params['watch']) {
         $watch = true;
     } elseif ($params['unwatch']) {
         $watch = false;
     }
     if ($watch) {
         $requestArray['wpWatchthis'] = '';
     }
     global $wgTitle, $wgRequest;
     $req = new DerivativeRequest($this->getRequest(), $requestArray, true);
     // Some functions depend on $wgTitle == $ep->mTitle
     // TODO: Make them not or check if they still do
     $wgTitle = $titleObj;
     $articleContext = new RequestContext();
     $articleContext->setRequest($req);
     $articleContext->setWikiPage($pageObj);
     $articleContext->setUser($this->getUser());
     /** @var $articleObject Article */
     $articleObject = Article::newFromWikiPage($pageObj, $articleContext);
     $ep = new EditPage($articleObject);
     // allow editing of non-textual content.
     $ep->allowNonTextContent = true;
     $ep->setContextTitle($titleObj);
     $ep->importFormData($req);
     // Run hooks
     // Handle APIEditBeforeSave parameters
     $r = array();
     if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) {
         if (count($r)) {
             $r['result'] = 'Failure';
             $apiResult->addValue(null, $this->getModuleName(), $r);
             return;
         } else {
             $this->dieUsageMsg('hookaborted');
         }
     }
     // Do the actual save
     $oldRevId = $articleObject->getRevIdFetched();
     $result = null;
     // Fake $wgRequest for some hooks inside EditPage
     // @todo FIXME: This interface SUCKS
     $oldRequest = $wgRequest;
     $wgRequest = $req;
     $status = $ep->internalAttemptSave($result, $user->isAllowed('bot') && $params['bot']);
     $wgRequest = $oldRequest;
     global $wgMaxArticleSize;
     switch ($status->value) {
         case EditPage::AS_HOOK_ERROR:
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             $this->dieUsageMsg('hookaborted');
         case EditPage::AS_PARSE_ERROR:
             $this->dieUsage($status->getMessage(), 'parseerror');
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             $this->dieUsageMsg('noimageredirect-anon');
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             $this->dieUsageMsg('noimageredirect-logged');
         case EditPage::AS_SPAM_ERROR:
             $this->dieUsageMsg(array('spamdetected', $result['spam']));
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $this->dieUsageMsg('blockedtext');
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
         case EditPage::AS_CONTENT_TOO_BIG:
             $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize));
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             $this->dieUsageMsg('noedit-anon');
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $this->dieUsageMsg('noedit');
         case EditPage::AS_READ_ONLY_PAGE:
             $this->dieReadOnly();
         case EditPage::AS_RATE_LIMITED:
             $this->dieUsageMsg('actionthrottledtext');
         case EditPage::AS_ARTICLE_WAS_DELETED:
             $this->dieUsageMsg('wasdeleted');
         case EditPage::AS_NO_CREATE_PERMISSION:
             $this->dieUsageMsg('nocreate-loggedin');
         case EditPage::AS_BLANK_ARTICLE:
             $this->dieUsageMsg('blankpage');
         case EditPage::AS_CONFLICT_DETECTED:
             $this->dieUsageMsg('editconflict');
             // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         case EditPage::AS_TEXTBOX_EMPTY:
             $this->dieUsageMsg('emptynewsection');
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             $r['new'] = '';
             // fall-through
         // fall-through
         case EditPage::AS_SUCCESS_UPDATE:
             $r['result'] = 'Success';
             $r['pageid'] = intval($titleObj->getArticleID());
             $r['title'] = $titleObj->getPrefixedText();
             $r['contentmodel'] = $titleObj->getContentModel();
             $newRevId = $articleObject->getLatest();
             if ($newRevId == $oldRevId) {
                 $r['nochange'] = '';
             } else {
                 $r['oldrevid'] = intval($oldRevId);
                 $r['newrevid'] = intval($newRevId);
                 $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $pageObj->getTimestamp());
             }
             break;
         case EditPage::AS_SUMMARY_NEEDED:
             $this->dieUsageMsg('summaryrequired');
         case EditPage::AS_END:
         default:
             // $status came from WikiPage::doEdit()
             $errors = $status->getErrorsArray();
             $this->dieUsageMsg($errors[0]);
             // TODO: Add new errors to message map
             break;
     }
     $apiResult->addValue(null, $this->getModuleName(), $r);
 }
예제 #20
0
 /**
  * Create a new RequestContext object to use e.g. for calls to other parts
  * the software.
  * The object will have the WebRequest and the User object set to the ones
  * used in this instance.
  *
  * @return RequestContext
  */
 public function createContext()
 {
     global $wgUser;
     $context = new RequestContext();
     $context->setRequest($this->getMain()->getRequest());
     $context->setUser($wgUser);
     /// @todo FIXME: we should store the User object
     return $context;
 }