MediaWiki 1.24.
* action=parse now has disabletoc flag to disable table of contents in output.
* SpecialRecentChanges::feedSetup() was removed.
+* (bug 25702) list=allcategories, list=allimages, list=alllinks, list=allpages,
+ list=deletedrevs and list=filearchive did not handle case-sensitivity
+ properly for all parameters.
+* ApiQueryBase::titlePartToKey allows an extra parameter that indicates the
+ namespace in order to properly capitalize the title part.
=== Languages updated in 1.23 ===
}
$dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
- $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
- $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_CATEGORY ) );
+ $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_CATEGORY ) );
$this->addWhereRange( 'cat_title', $dir, $from, $to );
$min = $params['min'];
}
if ( isset( $params['prefix'] ) ) {
- $this->addWhere( 'cat_title' .
- $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
+ $this->addWhere( 'cat_title' . $db->buildLike(
+ $this->titlePartToKey( $params['prefix'], NS_CATEGORY ),
+ $db->anyString() ) );
}
$this->addOption( 'LIMIT', $params['limit'] + 1 );
}
// Image filters
- $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
- $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE ) );
+ $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE ) );
$this->addWhereRange( 'img_name', ( $ascendingOrder ? 'newer' : 'older' ), $from, $to );
if ( isset( $params['prefix'] ) ) {
- $this->addWhere( 'img_name' .
- $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
+ $this->addWhere( 'img_name' . $db->buildLike(
+ $this->titlePartToKey( $params['prefix'], NS_FILE ),
+ $db->anyString() ) );
}
} else {
// Check mutually exclusive params
}
// 'continue' always overrides 'from'
- $from = $continue || is_null( $params['from'] )
- ? null
- : $this->titlePartToKey( $params['from'] );
- $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $from = ( $continue || $params['from'] === null ? null :
+ $this->titlePartToKey( $params['from'], $params['namespace'] ) );
+ $to = ( $params['to'] === null ? null :
+ $this->titlePartToKey( $params['to'], $params['namespace'] ) );
$this->addWhereRange( $pfx . $fieldTitle, 'newer', $from, $to );
+
if ( isset( $params['prefix'] ) ) {
- $this->addWhere( $pfx . $fieldTitle .
- $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
+ $this->addWhere( $pfx . $fieldTitle . $db->buildLike( $this->titlePartToKey(
+ $params['prefix'], $params['namespace'] ), $db->anyString() ) );
}
$this->addFields( array( 'pl_title' => $pfx . $fieldTitle ) );
$this->addWhereFld( 'page_namespace', $params['namespace'] );
$dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
- $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
- $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], $params['namespace'] ) );
+ $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], $params['namespace'] ) );
$this->addWhereRange( 'page_title', $dir, $from, $to );
if ( isset( $params['prefix'] ) ) {
- $this->addWhere( 'page_title' .
- $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
+ $this->addWhere( 'page_title' . $db->buildLike(
+ $this->titlePartToKey( $params['prefix'], $params['namespace'] ),
+ $db->anyString() ) );
}
if ( is_null( $resultPageSet ) ) {
}
/**
- * An alternative to titleToKey() that doesn't trim trailing spaces
+ * An alternative to titleToKey() that doesn't trim trailing spaces, and
+ * does not mangle the input if starts with something that looks like a
+ * namespace. It is advisable to pass the namespace parameter in order to
+ * handle per-namespace capitalization settings.
* @param string $titlePart Title part with spaces
+ * @param $defaultNamespace int Namespace to assume
* @return string Title part with underscores
*/
- public function titlePartToKey( $titlePart ) {
- return substr( $this->titleToKey( $titlePart . 'x' ), 0, -1 );
+ public function titlePartToKey( $titlePart, $defaultNamespace = NS_MAIN ) {
+ $t = Title::makeTitleSafe( $defaultNamespace, $titlePart . 'x' );
+ if ( !$t ) {
+ $this->dieUsageMsg( array( 'invalidtitle', $titlePart ) );
+ }
+ if ( $defaultNamespace != $t->getNamespace() || $t->getInterwiki() !== '' ) {
+ // This can happen in two cases. First, if you call titlePartToKey with a title part
+ // that looks like a namespace, but with $defaultNamespace = NS_MAIN. It would be very
+ // difficult to handle such a case. Such cases cannot exist and are therefore treated
+ // as invalid user input. The second case is when somebody specifies a title interwiki
+ // prefix.
+ $this->dieUsageMsg( array( 'invalidtitle', $titlePart ) );
+ }
+ return substr( $t->getDbKey(), 0, -1 );
}
/**
} elseif ( $mode == 'all' ) {
$this->addWhereFld( 'ar_namespace', $params['namespace'] );
- $from = is_null( $params['from'] ) ? null : $this->titleToKey( $params['from'] );
- $to = is_null( $params['to'] ) ? null : $this->titleToKey( $params['to'] );
+ $from = $params['from'] === null ? null : $this->titlePartToKey( $params['from'], $params['namespace'] );
+ $to = $params['to'] === null ? null : $this->titlePartToKey( $params['to'], $params['namespace'] );
$this->addWhereRange( 'ar_title', $dir, $from, $to );
if ( isset( $params['prefix'] ) ) {
- $this->addWhere( 'ar_title' .
- $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
+ $this->addWhere( 'ar_title' . $db->buildLike(
+ $this->titlePartToKey( $params['prefix'], $params['namespace'] ),
+ $db->anyString() ) );
}
}
// Image filters
$dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
- $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
+ $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE ) );
if ( !is_null( $params['continue'] ) ) {
$from = $params['continue'];
}
- $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE ) );
$this->addWhereRange( 'fa_name', $dir, $from, $to );
if ( isset( $params['prefix'] ) ) {
- $this->addWhere( 'fa_name' .
- $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
+ $this->addWhere( 'fa_name' . $db->buildLike(
+ $this->titlePartToKey( $params['prefix'], NS_FILE ),
+ $db->anyString() ) );
}
$sha1Set = isset( $params['sha1'] );
'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php",
'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestContext.php",
'MockApi' => "$testDir/phpunit/includes/api/MockApi.php",
+ 'MockApiQueryBase' => "$testDir/phpunit/includes/api/MockApiQueryBase.php",
'UserWrapper' => "$testDir/phpunit/includes/api/UserWrapper.php",
'RandomImageGenerator' => "$testDir/phpunit/includes/api/RandomImageGenerator.php",
--- /dev/null
+<?php
+
+/**
+ * @group API
+ * @group Database
+ * @group medium
+ */
+class ApiQueryAllPagesTest extends ApiTestCase {
+ protected function setUp() {
+ parent::setUp();
+ $this->doLogin();
+ }
+
+ function testBug25702() {
+ $title = Title::newFromText( 'Category:Template:xyz' );
+ $page = WikiPage::factory( $title );
+ $page->doEdit( 'Some text', 'inserting content' );
+
+ $result = $this->doApiRequest( array(
+ 'action' => 'query',
+ 'list' => 'allpages',
+ 'apnamespace' => NS_CATEGORY,
+ 'apprefix' => 'Template:x' ) );
+
+ $this->assertArrayHasKey( 'query', $result[0] );
+ $this->assertArrayHasKey( 'allpages', $result[0]['query'] );
+ $this->assertNotEquals( 0, count( $result[0]['query']['allpages'] ),
+ 'allpages list does not contain page Category:Template:xyz' );
+ }
+}
--- /dev/null
+<?php
+class MockApiQueryBase extends ApiQueryBase {
+ public function execute() {
+ }
+
+ public function getVersion() {
+ }
+
+ public function __construct() {
+ }
+}
* @covers ApiQuery
*/
class ApiQueryTest extends ApiTestCase {
+ /**
+ * @var array Storage for $wgHooks
+ */
+ protected $hooks;
protected function setUp() {
+ global $wgHooks;
+
parent::setUp();
$this->doLogin();
+
+ // Setup en: as interwiki prefix
+ $this->hooks = $wgHooks;
+ $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) {
+ if ( $prefix == 'en' ) {
+ $data = array( 'iw_url' => 'wikipedia' );
+ }
+ return false;
+ };
+ }
+
+ protected function tearDown() {
+ global $wgHooks;
+ $wgHooks = $this->hooks;
+
+ parent::tearDown();
}
public function testTitlesGetNormalized() {
$this->assertArrayHasKey( 'missing', $data[0]['query']['pages'][-2] );
$this->assertArrayHasKey( 'invalid', $data[0]['query']['pages'][-1] );
}
+
+ /**
+ * Test the ApiBase::titlePartToKey function
+ *
+ * @param string $titlePart
+ * @param int $namespace
+ * @param string $expected
+ * @param string $description
+ * @dataProvider provideTestTitlePartToKey
+ */
+ function testTitlePartToKey( $titlePart, $namespace, $expected, $expectException ) {
+ $api = new MockApiQueryBase();
+ $exceptionCaught = false;
+ try {
+ $this->assertEquals( $expected, $api->titlePartToKey( $titlePart, $namespace ) );
+ } catch ( UsageException $e ) {
+ $exceptionCaught = true;
+ }
+ $this->assertEquals( $expectException, $exceptionCaught,
+ 'UsageException thrown by titlePartToKey' );
+ }
+
+ function provideTestTitlePartToKey() {
+ return array(
+ array( 'a b c', NS_MAIN, 'A_b_c', false ),
+ array( 'x', NS_MAIN, 'X', false ),
+ array( 'y ', NS_MAIN, 'Y_', false ),
+ array( 'template:foo', NS_CATEGORY, 'Template:foo', false ),
+ array( 'en:foo', NS_CATEGORY, 'En:foo', false ),
+ array( "\xF7", NS_MAIN, null, true ),
+ array( 'template:foo', NS_MAIN, null, true ),
+ array( 'en:foo', NS_MAIN, null, true ),
+ );
+ }
}