From: jenkins-bot Date: Mon, 26 Mar 2018 18:21:13 +0000 (+0000) Subject: Merge "Added heartbeat for pingback." X-Git-Tag: 1.31.0-rc.0~280 X-Git-Url: http://git.cyclocoop.org/url?a=commitdiff_plain;h=1ef3e79ea405a8be28ed269e0ee64ae9d5ea6027;hp=fbba5dae54e0396d859a7e32872d60e9909213a9;p=lhc%2Fweb%2Fwiklou.git Merge "Added heartbeat for pingback." --- diff --git a/RELEASE-NOTES-1.31 b/RELEASE-NOTES-1.31 index 4181a2c82b..bc142ae52a 100644 --- a/RELEASE-NOTES-1.31 +++ b/RELEASE-NOTES-1.31 @@ -295,6 +295,8 @@ changes to languages because of Phabricator reports. * StripState::merge() * The "free" CSS class is now only applied to unbracketed URLs in wikitext. Links written using square brackets will get the class "text" not "free". +* SpecialPageFactory::getList(), deprecated in 1.24, has been removed. You can + use ::getNames() instead. * OpenSearch::getOpenSearchTemplate(), deprecated in 1.25, has been removed. You can use ApiOpenSearch::getOpenSearchTemplate() instead. * The global function wfBaseConvert, deprecated in 1.27, has been removed. Use @@ -311,6 +313,13 @@ changes to languages because of Phabricator reports. * The global function wfOutputHandler() was removed, use the its replacement MediaWiki\OutputHandler::handle() instead. The global function was only sometimes defined. Its replacement is always available via the autoloader. +* ChangeTags::listExtensionActivatedTags and ::listExtensionDefinedTags, deprecated + in 1.28, have been removed. Use ::listSoftwareActivatedTags() and + ::listSoftwareDefinedTags() instead. +* Title::getTitleInvalidRegex(), deprecated in 1.25, has been removed. You + can use MediaWikiTitleCodec::getTitleInvalidRegex() instead. +* HTMLForm & VFormHTMLForm::isVForm(), deprecated in 1.25, have been removed. +* The ProfileSection class, deprecated in 1.25 and unused, has been removed. == Compatibility == MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported, diff --git a/autoload.php b/autoload.php index 0b0c288ffb..126362c2e6 100644 --- a/autoload.php +++ b/autoload.php @@ -1185,7 +1185,6 @@ $wgAutoloadLocalClasses = [ 'Preprocessor_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php', 'ProcessCacheLRU' => __DIR__ . '/includes/libs/ProcessCacheLRU.php', 'Processor' => __DIR__ . '/includes/registration/Processor.php', - 'ProfileSection' => __DIR__ . '/includes/profiler/ProfileSection.php', 'Profiler' => __DIR__ . '/includes/profiler/Profiler.php', 'ProfilerOutput' => __DIR__ . '/includes/profiler/output/ProfilerOutput.php', 'ProfilerOutputDb' => __DIR__ . '/includes/profiler/output/ProfilerOutputDb.php', diff --git a/includes/Title.php b/includes/Title.php index 66aadebc19..8dda01f464 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -625,20 +625,6 @@ class Title implements LinkTarget { return $wgLegalTitleChars; } - /** - * Returns a simple regex that will match on characters and sequences invalid in titles. - * Note that this doesn't pick up many things that could be wrong with titles, but that - * replacing this regex with something valid will make many titles valid. - * - * @deprecated since 1.25, use MediaWikiTitleCodec::getTitleInvalidRegex() instead - * - * @return string Regex string - */ - static function getTitleInvalidRegex() { - wfDeprecated( __METHOD__, '1.25' ); - return MediaWikiTitleCodec::getTitleInvalidRegex(); - } - /** * Utility method for converting a character sequence from bytes to Unicode. * diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php index f4aea986f0..8f4028310a 100644 --- a/includes/api/ApiBlock.php +++ b/includes/api/ApiBlock.php @@ -124,8 +124,8 @@ class ApiBlock extends ApiBase { $res['id'] = $block->getId(); } else { # should be unreachable - $res['expiry'] = ''; - $res['id'] = ''; + $res['expiry'] = ''; // @codeCoverageIgnore + $res['id'] = ''; // @codeCoverageIgnore } $res['reason'] = $params['reason']; diff --git a/includes/changetags/ChangeTags.php b/includes/changetags/ChangeTags.php index b30b82df1d..5b6088d59f 100644 --- a/includes/changetags/ChangeTags.php +++ b/includes/changetags/ChangeTags.php @@ -1295,20 +1295,9 @@ class ChangeTags { ); } - /** - * @see listSoftwareActivatedTags - * @deprecated since 1.28 call listSoftwareActivatedTags directly - * @return array - */ - public static function listExtensionActivatedTags() { - wfDeprecated( __METHOD__, '1.28' ); - return self::listSoftwareActivatedTags(); - } - /** * Basically lists defined tags which count even if they aren't applied to anything. - * It returns a union of the results of listExplicitlyDefinedTags() and - * listExtensionDefinedTags(). + * It returns a union of the results of listExplicitlyDefinedTags() * * @return string[] Array of strings: tags */ @@ -1385,18 +1374,6 @@ class ChangeTags { ); } - /** - * Call listSoftwareDefinedTags directly - * - * @see listSoftwareDefinedTags - * @deprecated since 1.28 - * @return array - */ - public static function listExtensionDefinedTags() { - wfDeprecated( __METHOD__, '1.28' ); - return self::listSoftwareDefinedTags(); - } - /** * Invalidates the short-term cache of defined tags used by the * list*DefinedTags functions, as well as the tag statistics cache. diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php index 9b58f924f4..af1743e078 100644 --- a/includes/htmlform/HTMLForm.php +++ b/includes/htmlform/HTMLForm.php @@ -430,17 +430,6 @@ class HTMLForm extends ContextSource { return $this->displayFormat; } - /** - * Test if displayFormat is 'vform' - * @since 1.22 - * @deprecated since 1.25 - * @return bool - */ - public function isVForm() { - wfDeprecated( __METHOD__, '1.25' ); - return false; - } - /** * Get the HTMLFormField subclass for this descriptor. * diff --git a/includes/htmlform/VFormHTMLForm.php b/includes/htmlform/VFormHTMLForm.php index 325526bac2..7bf5f9e2ae 100644 --- a/includes/htmlform/VFormHTMLForm.php +++ b/includes/htmlform/VFormHTMLForm.php @@ -37,11 +37,6 @@ class VFormHTMLForm extends HTMLForm { */ protected $displayFormat = 'vform'; - public function isVForm() { - wfDeprecated( __METHOD__, '1.25' ); - return true; - } - public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) { diff --git a/includes/installer/PostgresUpdater.php b/includes/installer/PostgresUpdater.php index 48f47f5f61..ba6e9683e3 100644 --- a/includes/installer/PostgresUpdater.php +++ b/includes/installer/PostgresUpdater.php @@ -294,7 +294,7 @@ class PostgresUpdater extends DatabaseUpdater { [ 'log_timestamp', 'timestamptz_ops', 'btree', 0 ], ], 'CREATE INDEX "logging_times" ON "logging" USING "btree" ("log_timestamp")' ], - [ 'dropIndex', 'oldimage', 'oi_name' ], + [ 'dropPgIndex', 'oldimage', 'oi_name' ], [ 'checkIndex', 'oi_name_archive_name', [ [ 'oi_name', 'text_ops', 'btree', 0 ], [ 'oi_archive_name', 'text_ops', 'btree', 0 ], @@ -353,7 +353,7 @@ class PostgresUpdater extends DatabaseUpdater { [ 'checkOiNameConstraint' ], [ 'checkPageDeletedTrigger' ], [ 'checkRevUserFkey' ], - [ 'dropIndex', 'ipblocks', 'ipb_address' ], + [ 'dropPgIndex', 'ipblocks', 'ipb_address' ], [ 'checkIndex', 'ipb_address_unique', [ [ 'ipb_address', 'text_ops', 'btree', 0 ], [ 'ipb_user', 'int4_ops', 'btree', 0 ], @@ -1060,7 +1060,7 @@ END; } } - protected function dropIndex( $table, $index, $patch = '', $fullpath = false ) { + protected function dropPgIndex( $table, $index ) { if ( $this->db->indexExists( $table, $index ) ) { $this->output( "Dropping obsolete index '$index'\n" ); $this->db->query( "DROP INDEX \"" . $index . "\"" ); diff --git a/includes/profiler/ProfileSection.php b/includes/profiler/ProfileSection.php deleted file mode 100644 index 124e2d3b11..0000000000 --- a/includes/profiler/ProfileSection.php +++ /dev/null @@ -1,45 +0,0 @@ -request = $request; $this->logger = $resourceLoader->getLogger(); - // Future developers: Avoid use of getVal() in this class, which performs - // expensive UTF normalisation by default. Use getRawVal() instead. - // Values here are either one of a finite number of internal IDs, - // or previously-stored user input (e.g. titles, user names) that were passed - // to this endpoint by ResourceLoader itself from the canonical value. - // Values do not come directly from user input and need not match. + // Future developers: Use WebRequest::getRawVal() instead getVal(). + // The getVal() method performs slow Language+UTF logic. (f303bb9360) // List of modules $modules = $request->getRawVal( 'modules' ); diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php index ae9520d1a6..681e8dc005 100644 --- a/includes/resourceloader/ResourceLoaderStartUpModule.php +++ b/includes/resourceloader/ResourceLoaderStartUpModule.php @@ -206,7 +206,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { */ public function getModuleRegistrations( ResourceLoaderContext $context ) { $resourceLoader = $context->getResourceLoader(); - $target = $context->getRequest()->getVal( 'target', 'desktop' ); + // Future developers: Use WebRequest::getRawVal() instead getVal(). + // The getVal() method performs slow Language+UTF logic. (f303bb9360) + $target = $context->getRequest()->getRawVal( 'target', 'desktop' ); // Bypass target filter if this request is Special:JavaScriptTest. // To prevent misuse in production, this is only allowed if testing is enabled server-side. $byPassTargetFilter = $this->getConfig()->get( 'EnableJavaScriptTest' ) && $target === 'test'; diff --git a/includes/specialpage/SpecialPageFactory.php b/includes/specialpage/SpecialPageFactory.php index 9469e69ce9..fdf4d52d78 100644 --- a/includes/specialpage/SpecialPageFactory.php +++ b/includes/specialpage/SpecialPageFactory.php @@ -212,17 +212,6 @@ class SpecialPageFactory { return array_keys( self::getPageList() ); } - /** - * Get the special page list as an array - * - * @deprecated since 1.24, use getNames() instead. - * @return array - */ - public static function getList() { - wfDeprecated( __FUNCTION__, '1.24' ); - return self::getPageList(); - } - /** * Get the special page list as an array * diff --git a/tests/parser/ParserTestRunner.php b/tests/parser/ParserTestRunner.php index f0c815f8ca..28335ecdde 100644 --- a/tests/parser/ParserTestRunner.php +++ b/tests/parser/ParserTestRunner.php @@ -1108,6 +1108,7 @@ class ParserTestRunner { // Set content language. This invalidates the magic word cache and title services $lang = Language::factory( $langCode ); + $lang->resetNamespaces(); $setup['wgContLang'] = $lang; $reset = function () { MagicWord::clearCache(); diff --git a/tests/phpunit/includes/api/ApiBlockTest.php b/tests/phpunit/includes/api/ApiBlockTest.php index 832a113f0e..c456e9abbb 100644 --- a/tests/phpunit/includes/api/ApiBlockTest.php +++ b/tests/phpunit/includes/api/ApiBlockTest.php @@ -8,13 +8,17 @@ * @covers ApiBlock */ class ApiBlockTest extends ApiTestCase { + protected $mUser = null; + protected function setUp() { parent::setUp(); $this->doLogin(); + + $this->mUser = $this->getMutableTestUser()->getUser(); } protected function tearDown() { - $block = Block::newFromTarget( 'UTApiBlockee' ); + $block = Block::newFromTarget( $this->mUser->getName() ); if ( !is_null( $block ) ) { $block->delete(); } @@ -25,80 +29,192 @@ class ApiBlockTest extends ApiTestCase { return $this->getTokenList( self::$users['sysop'] ); } - function addDBDataOnce() { - $user = User::newFromName( 'UTApiBlockee' ); - - if ( $user->getId() == 0 ) { - $user->addToDatabase(); - TestUser::setPasswordForUser( $user, 'UTApiBlockeePassword' ); - - $user->saveSettings(); - } - } - /** - * This test has probably always been broken and use an invalid token - * Bug tracking brokenness is https://phabricator.wikimedia.org/T37646 - * - * Root cause is https://gerrit.wikimedia.org/r/3434 - * Which made the Block/Unblock API to actually verify the token - * previously always considered valid (T36212). + * @param array $extraParams Extra API parameters to pass to doApiRequest + * @param User $blocker User to do the blocking, null to pick + * arbitrarily */ - public function testMakeNormalBlock() { - $tokens = $this->getTokens(); + private function doBlock( array $extraParams = [], User $blocker = null ) { + if ( $blocker === null ) { + $blocker = self::$users['sysop']->getUser(); + } - $user = User::newFromName( 'UTApiBlockee' ); + $tokens = $this->getTokens(); - if ( !$user->getId() ) { - $this->markTestIncomplete( "The user UTApiBlockee does not exist" ); - } + $this->assertNotNull( $this->mUser, 'Sanity check' ); + $this->assertNotSame( 0, $this->mUser->getId(), 'Sanity check' ); - if ( !array_key_exists( 'blocktoken', $tokens ) ) { - $this->markTestIncomplete( "No block token found" ); - } + $this->assertArrayHasKey( 'blocktoken', $tokens, 'Sanity check' ); - $this->doApiRequest( [ + $params = [ 'action' => 'block', - 'user' => 'UTApiBlockee', + 'user' => $this->mUser->getName(), 'reason' => 'Some reason', - 'token' => $tokens['blocktoken'] ], null, false, self::$users['sysop']->getUser() ); + 'token' => $tokens['blocktoken'], + ]; + if ( array_key_exists( 'userid', $extraParams ) ) { + // Make sure we don't have both user and userid + unset( $params['user'] ); + } + $ret = $this->doApiRequest( array_merge( $params, $extraParams ), null, + false, $blocker ); - $block = Block::newFromTarget( 'UTApiBlockee' ); + $block = Block::newFromTarget( $this->mUser->getName() ); $this->assertTrue( !is_null( $block ), 'Block is valid' ); - $this->assertEquals( 'UTApiBlockee', (string)$block->getTarget() ); - $this->assertEquals( 'Some reason', $block->mReason ); - $this->assertEquals( 'infinity', $block->mExpiry ); + $this->assertSame( $this->mUser->getName(), (string)$block->getTarget() ); + $this->assertSame( 'Some reason', $block->mReason ); + + return $ret; + } + + /** + * Block by username + */ + public function testNormalBlock() { + $this->doBlock(); } /** * Block by user ID */ - public function testMakeNormalBlockId() { - $tokens = $this->getTokens(); - $user = User::newFromName( 'UTApiBlockee' ); + public function testBlockById() { + $this->doBlock( [ 'userid' => $this->mUser->getId() ] ); + } - if ( !$user->getId() ) { - $this->markTestIncomplete( "The user UTApiBlockee does not exist." ); - } + /** + * A blocked user can't block + */ + public function testBlockByBlockedUser() { + $this->setExpectedException( ApiUsageException::class, + 'You cannot block or unblock other users because you are yourself blocked.' ); + + $blocked = $this->getMutableTestUser( [ 'sysop' ] )->getUser(); + $block = new Block( [ + 'address' => $blocked->getName(), + 'by' => self::$users['sysop']->getUser()->getId(), + 'reason' => 'Capriciousness', + 'timestamp' => '19370101000000', + 'expiry' => 'infinity', + ] ); + $block->insert(); + + $this->doBlock( [], $blocked ); + } - if ( !array_key_exists( 'blocktoken', $tokens ) ) { - $this->markTestIncomplete( "No block token found" ); - } + public function testBlockOfNonexistentUser() { + $this->setExpectedException( ApiUsageException::class, + 'There is no user by the name "Nonexistent". Check your spelling.' ); - $data = $this->doApiRequest( [ - 'action' => 'block', - 'userid' => $user->getId(), - 'reason' => 'Some reason', - 'token' => $tokens['blocktoken'] ], null, false, self::$users['sysop']->getUser() ); + $this->doBlock( [ 'user' => 'Nonexistent' ] ); + } + + public function testBlockOfNonexistentUserId() { + $id = 948206325; + $this->setExpectedException( ApiUsageException::class, + "There is no user with ID $id." ); + + $this->assertFalse( User::whoIs( $id ), 'Sanity check' ); + + $this->doBlock( [ 'userid' => $id ] ); + } + + public function testBlockWithTag() { + ChangeTags::defineTag( 'custom tag' ); + + $this->doBlock( [ 'tags' => 'custom tag' ] ); + + $dbw = wfGetDB( DB_MASTER ); + $this->assertSame( 'custom tag', $dbw->selectField( + [ 'change_tag', 'logging' ], + 'ct_tag', + [ 'log_type' => 'block' ], + __METHOD__, + [], + [ 'change_tag' => [ 'INNER JOIN', 'ct_log_id = log_id' ] ] + ) ); + } + + public function testBlockWithProhibitedTag() { + $this->setExpectedException( ApiUsageException::class, + 'You do not have permission to apply change tags along with your changes.' ); + + ChangeTags::defineTag( 'custom tag' ); + + $this->setMwGlobals( 'wgRevokePermissions', + [ 'user' => [ 'applychangetags' => true ] ] ); + + $this->doBlock( [ 'tags' => 'custom tag' ] ); + } + + public function testBlockWithHide() { + global $wgGroupPermissions; + $newPermissions = $wgGroupPermissions['sysop']; + $newPermissions['hideuser'] = true; + $this->mergeMwGlobalArrayValue( 'wgGroupPermissions', + [ 'sysop' => $newPermissions ] ); + + $res = $this->doBlock( [ 'hidename' => '' ] ); + + $dbw = wfGetDB( DB_MASTER ); + $this->assertSame( '1', $dbw->selectField( + 'ipblocks', + 'ipb_deleted', + [ 'ipb_id' => $res[0]['block']['id'] ], + __METHOD__ + ) ); + } + + public function testBlockWithProhibitedHide() { + $this->setExpectedException( ApiUsageException::class, + "You don't have permission to hide user names from the block log." ); + + $this->doBlock( [ 'hidename' => '' ] ); + } + + public function testBlockWithEmailBlock() { + $res = $this->doBlock( [ 'noemail' => '' ] ); + + $dbw = wfGetDB( DB_MASTER ); + $this->assertSame( '1', $dbw->selectField( + 'ipblocks', + 'ipb_block_email', + [ 'ipb_id' => $res[0]['block']['id'] ], + __METHOD__ + ) ); + } + + public function testBlockWithProhibitedEmailBlock() { + $this->setExpectedException( ApiUsageException::class, + "You don't have permission to block users from sending email through the wiki." ); + + $this->setMwGlobals( 'wgRevokePermissions', + [ 'sysop' => [ 'blockemail' => true ] ] ); + + $this->doBlock( [ 'noemail' => '' ] ); + } + + public function testBlockWithExpiry() { + $res = $this->doBlock( [ 'expiry' => '1 day' ] ); + + $dbw = wfGetDB( DB_MASTER ); + $expiry = $dbw->selectField( + 'ipblocks', + 'ipb_expiry', + [ 'ipb_id' => $res[0]['block']['id'] ], + __METHOD__ + ); + + // Allow flakiness up to one second + $this->assertLessThanOrEqual( 1, + abs( wfTimestamp( TS_UNIX, $expiry ) - ( time() + 86400 ) ) ); + } - $block = Block::newFromTarget( 'UTApiBlockee' ); + public function testBlockWithInvalidExpiry() { + $this->setExpectedException( ApiUsageException::class, "Expiry time invalid." ); - $this->assertTrue( !is_null( $block ), 'Block is valid.' ); - $this->assertEquals( 'UTApiBlockee', (string)$block->getTarget() ); - $this->assertEquals( 'Some reason', $block->mReason ); - $this->assertEquals( 'infinity', $block->mExpiry ); + $this->doBlock( [ 'expiry' => '' ] ); } /** @@ -109,7 +225,7 @@ class ApiBlockTest extends ApiTestCase { $this->doApiRequest( [ 'action' => 'block', - 'user' => 'UTApiBlockee', + 'user' => $this->mUser->getName(), 'reason' => 'Some reason', ], null,