jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/341374 )
Change subject: ApiPageSet: Follow RedirectSpecialArticle redirects
......................................................................
ApiPageSet: Follow RedirectSpecialArticle redirects
For example Special:MyPage, Special:MyTalk, and Special:MyLanguage.
Don't follow other redirect special pages like Special:MyContributions,
though, because the following only really makes sense when the redirect
is to an article.
Bug: T145541
Change-Id: I8c8065552ed128017887e48285e359def8bd3cd3
---
M includes/api/ApiPageSet.php
M tests/phpunit/includes/api/ApiPageSetTest.php
2 files changed, 168 insertions(+), 48 deletions(-)
Approvals:
Legoktm: Looks good to me, approved
jenkins-bot: Verified
diff --git a/includes/api/ApiPageSet.php b/includes/api/ApiPageSet.php
index 7d16af8..71f6e0b 100644
--- a/includes/api/ApiPageSet.php
+++ b/includes/api/ApiPageSet.php
@@ -70,6 +70,7 @@
private $mInterwikiTitles = [];
/** @var Title[] */
private $mPendingRedirectIDs = [];
+ private $mPendingRedirectSpecialPages = []; // [dbkey] => [ Title
$from, Title $to ]
private $mResolvedRedirectTitles = [];
private $mConvertedTitles = [];
private $mGoodRevIDs = [];
@@ -812,6 +813,8 @@
// Get validated and normalized title objects
$linkBatch = $this->processTitlesArray( $titles );
if ( $linkBatch->isEmpty() ) {
+ // There might be special-page redirects
+ $this->resolvePendingRedirects();
return;
}
@@ -1032,7 +1035,7 @@
// Repeat until all redirects have been resolved
// The infinite loop is prevented by keeping all known
pages in $this->mAllPages
- while ( $this->mPendingRedirectIDs ) {
+ while ( $this->mPendingRedirectIDs ||
$this->mPendingRedirectSpecialPages ) {
// Resolve redirects by querying the pagelinks
table, and repeat the process
// Create a new linkBatch object for the next
pass
$linkBatch = $this->getRedirectTargets();
@@ -1066,56 +1069,76 @@
$titlesToResolve = [];
$db = $this->getDB();
- $res = $db->select(
- 'redirect',
- [
- 'rd_from',
- 'rd_namespace',
- 'rd_fragment',
- 'rd_interwiki',
- 'rd_title'
- ], [ 'rd_from' => array_keys(
$this->mPendingRedirectIDs ) ],
- __METHOD__
- );
- foreach ( $res as $row ) {
- $rdfrom = intval( $row->rd_from );
- $from =
$this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
- $to = Title::makeTitle(
- $row->rd_namespace,
- $row->rd_title,
- $row->rd_fragment,
- $row->rd_interwiki
- );
- $this->mResolvedRedirectTitles[$from] =
$this->mPendingRedirectIDs[$rdfrom];
- unset( $this->mPendingRedirectIDs[$rdfrom] );
- if ( $to->isExternal() ) {
- $this->mInterwikiTitles[$to->getPrefixedText()]
= $to->getInterwiki();
- } elseif ( !isset(
$this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
- $titlesToResolve[] = $to;
+ if ( $this->mPendingRedirectIDs ) {
+ $res = $db->select(
+ 'redirect',
+ [
+ 'rd_from',
+ 'rd_namespace',
+ 'rd_fragment',
+ 'rd_interwiki',
+ 'rd_title'
+ ], [ 'rd_from' => array_keys(
$this->mPendingRedirectIDs ) ],
+ __METHOD__
+ );
+ foreach ( $res as $row ) {
+ $rdfrom = intval( $row->rd_from );
+ $from =
$this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
+ $to = Title::makeTitle(
+ $row->rd_namespace,
+ $row->rd_title,
+ $row->rd_fragment,
+ $row->rd_interwiki
+ );
+ $this->mResolvedRedirectTitles[$from] =
$this->mPendingRedirectIDs[$rdfrom];
+ unset( $this->mPendingRedirectIDs[$rdfrom] );
+ if ( $to->isExternal() ) {
+
$this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
+ } elseif ( !isset(
$this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
+ $titlesToResolve[] = $to;
+ }
+ $this->mRedirectTitles[$from] = $to;
}
- $this->mRedirectTitles[$from] = $to;
+
+ if ( $this->mPendingRedirectIDs ) {
+ // We found pages that aren't in the redirect
table
+ // Add them
+ foreach ( $this->mPendingRedirectIDs as $id =>
$title ) {
+ $page = WikiPage::factory( $title );
+ $rt = $page->insertRedirect();
+ if ( !$rt ) {
+ // What the hell. Let's just
ignore this
+ continue;
+ }
+ if ( $rt->isExternal() ) {
+
$this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
+ } elseif ( !isset(
$this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
+ $titlesToResolve[] = $rt;
+ }
+ $from = $title->getPrefixedText();
+ $this->mResolvedRedirectTitles[$from] =
$title;
+ $this->mRedirectTitles[$from] = $rt;
+ unset( $this->mPendingRedirectIDs[$id]
);
+ }
+ }
}
- if ( $this->mPendingRedirectIDs ) {
- // We found pages that aren't in the redirect table
- // Add them
- foreach ( $this->mPendingRedirectIDs as $id => $title )
{
- $page = WikiPage::factory( $title );
- $rt = $page->insertRedirect();
- if ( !$rt ) {
- // What the hell. Let's just ignore this
- continue;
+ if ( $this->mPendingRedirectSpecialPages ) {
+ foreach ( $this->mPendingRedirectSpecialPages as $key
=> list( $from, $to ) ) {
+ $fromKey = $from->getPrefixedText();
+ $this->mResolvedRedirectTitles[$fromKey] =
$from;
+ $this->mRedirectTitles[$fromKey] = $to;
+ if ( $to->isExternal() ) {
+
$this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
+ } elseif ( !isset(
$this->mAllPages[$to->getNamespace()][$to->getDBkey()] ) ) {
+ $titlesToResolve[] = $to;
}
- if ( $rt->isExternal() ) {
-
$this->mInterwikiTitles[$rt->getPrefixedText()] = $rt->getInterwiki();
- } elseif ( !isset(
$this->mAllPages[$rt->getNamespace()][$rt->getDBkey()] ) ) {
- $titlesToResolve[] = $rt;
- }
- $from = $title->getPrefixedText();
- $this->mResolvedRedirectTitles[$from] = $title;
- $this->mRedirectTitles[$from] = $rt;
- unset( $this->mPendingRedirectIDs[$id] );
}
+ $this->mPendingRedirectSpecialPages = [];
+
+ // Set private caching since we don't know what
criteria the
+ // special pages used to decide on these redirects.
+ $this->mCacheMode = 'private';
}
return $this->processTitlesArray( $titlesToResolve );
@@ -1196,8 +1219,26 @@
$dbkey = $titleObj->getDBkey();
if ( !isset(
$this->mAllSpecials[$ns][$dbkey] ) ) {
$this->mAllSpecials[$ns][$dbkey] = $this->mFakePageId;
-
$this->mSpecialTitles[$this->mFakePageId] = $titleObj;
- $this->mFakePageId--;
+ $target = null;
+ if ( $ns === NS_SPECIAL &&
$this->mResolveRedirects ) {
+ $special =
SpecialPageFactory::getPage( $dbkey );
+ if ( $special
instanceof RedirectSpecialArticle ) {
+ // Only
RedirectSpecialArticle is intended to redirect to an article, other kinds of
+ //
RedirectSpecialPage are probably applying weird URL parameters we don't want to
handle.
+ $context = new
DerivativeContext( $this );
+
$context->setTitle( $titleObj );
+
$context->setRequest( new FauxRequest );
+
$special->setContext( $context );
+ list( /* $alias
*/, $subpage ) = SpecialPageFactory::resolveAlias( $dbkey );
+ $target =
$special->getRedirect( $subpage );
+ }
+ }
+ if ( $target ) {
+
$this->mPendingRedirectSpecialPages[$dbkey] = [ $titleObj, $target ];
+ } else {
+
$this->mSpecialTitles[$this->mFakePageId] = $titleObj;
+ $this->mFakePageId--;
+ }
}
} else {
// Regular page
diff --git a/tests/phpunit/includes/api/ApiPageSetTest.php
b/tests/phpunit/includes/api/ApiPageSetTest.php
index ad1deee..8a2146a 100644
--- a/tests/phpunit/includes/api/ApiPageSetTest.php
+++ b/tests/phpunit/includes/api/ApiPageSetTest.php
@@ -96,4 +96,83 @@
$pageSet->getNormalizedTitlesAsResult()
);
}
+
+ public function testSpecialRedirects() {
+ $id1 = self::editPage( 'UTApiPageSet', 'UTApiPageSet in the
default language' )
+ ->value['revision']->getTitle()->getArticleID();
+ $id2 = self::editPage( 'UTApiPageSet/de', 'UTApiPageSet in
German' )
+ ->value['revision']->getTitle()->getArticleID();
+
+ $user = $this->getTestUser()->getUser();
+ $userName = $user->getName();
+ $userDbkey = str_replace( ' ', '_', $userName );
+ $request = new FauxRequest( [
+ 'titles' => join( '|', [
+ 'Special:MyContributions',
+ 'Special:MyPage',
+ 'Special:MyTalk/subpage',
+ 'Special:MyLanguage/UTApiPageSet',
+ ] ),
+ ] );
+ $context = new RequestContext();
+ $context->setRequest( $request );
+ $context->setUser( $user );
+
+ $main = new ApiMain( $context );
+ $pageSet = new ApiPageSet( $main );
+ $pageSet->execute();
+
+ $this->assertEquals( [
+ ], $pageSet->getRedirectTitlesAsResult() );
+ $this->assertEquals( [
+ [ 'ns' => -1, 'title' => 'Special:MyContributions',
'special' => true ],
+ [ 'ns' => -1, 'title' => 'Special:MyPage', 'special' =>
true ],
+ [ 'ns' => -1, 'title' => 'Special:MyTalk/subpage',
'special' => true ],
+ [ 'ns' => -1, 'title' =>
'Special:MyLanguage/UTApiPageSet', 'special' => true ],
+ ], $pageSet->getInvalidTitlesAndRevisions() );
+ $this->assertEquals( [
+ ], $pageSet->getAllTitlesByNamespace() );
+
+ $request->setVal( 'redirects', 1 );
+ $main = new ApiMain( $context );
+ $pageSet = new ApiPageSet( $main );
+ $pageSet->execute();
+
+ $this->assertEquals( [
+ [ 'from' => 'Special:MyPage', 'to' => "User:$userName"
],
+ [ 'from' => 'Special:MyTalk/subpage', 'to' => "User
talk:$userName/subpage" ],
+ [ 'from' => 'Special:MyLanguage/UTApiPageSet', 'to' =>
'UTApiPageSet' ],
+ ], $pageSet->getRedirectTitlesAsResult() );
+ $this->assertEquals( [
+ [ 'ns' => -1, 'title' => 'Special:MyContributions',
'special' => true ],
+ [ 'ns' => 2, 'title' => "User:$userName", 'missing' =>
true ],
+ [ 'ns' => 3, 'title' => "User talk:$userName/subpage",
'missing' => true ],
+ ], $pageSet->getInvalidTitlesAndRevisions() );
+ $this->assertEquals( [
+ 0 => [ 'UTApiPageSet' => $id1 ],
+ 2 => [ $userDbkey => -2 ],
+ 3 => [ "$userDbkey/subpage" => -3 ],
+ ], $pageSet->getAllTitlesByNamespace() );
+
+ $context->setLanguage( 'de' );
+ $main = new ApiMain( $context );
+ $pageSet = new ApiPageSet( $main );
+ $pageSet->execute();
+
+ $this->assertEquals( [
+ [ 'from' => 'Special:MyPage', 'to' => "User:$userName"
],
+ [ 'from' => 'Special:MyTalk/subpage', 'to' => "User
talk:$userName/subpage" ],
+ [ 'from' => 'Special:MyLanguage/UTApiPageSet', 'to' =>
'UTApiPageSet/de' ],
+ ], $pageSet->getRedirectTitlesAsResult() );
+ $this->assertEquals( [
+ [ 'ns' => -1, 'title' => 'Special:MyContributions',
'special' => true ],
+ [ 'ns' => 2, 'title' => "User:$userName", 'missing' =>
true ],
+ [ 'ns' => 3, 'title' => "User talk:$userName/subpage",
'missing' => true ],
+ ], $pageSet->getInvalidTitlesAndRevisions() );
+ $this->assertEquals( [
+ 0 => [ 'UTApiPageSet/de' => $id2 ],
+ 2 => [ $userDbkey => -2 ],
+ 3 => [ "$userDbkey/subpage" => -3 ],
+ ], $pageSet->getAllTitlesByNamespace() );
+ }
}
--
To view, visit https://gerrit.wikimedia.org/r/341374
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I8c8065552ed128017887e48285e359def8bd3cd3
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Anomie <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: Brion VIBBER <[email protected]>
Gerrit-Reviewer: Gergő Tisza <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: MaxSem <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits