that tests continue to run properly.
&$tables: array of table names
+'ParserOutputStashForEdit': Called when an edit stash parse finishes, before the output is cached.
+$page: the WikiPage of the candidate edit
+$content: the Content object of the candidate edit
+$output: the ParserOutput result of the candidate edit
+
'PasswordPoliciesForUser': Alter the effective password policy for a user.
$user: User object whose policy you are modifying
&$effectivePolicy: Array of policy statements that apply to this user
$config = $context->getConfig();
$factory = wfGetLBFactory();
- // Check if any transaction was too big
- $limit = $config->get( 'MaxUserDBWriteDuration' );
- $factory->forEachLB( function ( LoadBalancer $lb ) use ( $limit ) {
- $lb->forEachOpenConnection( function ( IDatabase $db ) use ( $limit ) {
- $time = $db->pendingWriteQueryDuration();
- if ( $limit > 0 && $time > $limit ) {
- throw new DBTransactionError(
- $db,
- wfMessage( 'transaction-duration-limit-exceeded', $time, $limit )->text()
- );
- }
- } );
- } );
// Commit all changes
- $factory->commitMasterChanges( __METHOD__ );
+ $factory->commitMasterChanges(
+ __METHOD__,
+ // Abort if any transaction was too big
+ array( 'maxWriteDuration' => $config->get( 'MaxUserDBWriteDuration' ) )
+ );
// Record ChronologyProtector positions
$factory->shutdown();
wfDebug( __METHOD__ . ': all transactions committed' );
/**
* Return an associative array of attribute names and values from
- * a partial tag string. Attribute names are forces to lowercase,
+ * a partial tag string. Attribute names are forced to lowercase,
* character references are decoded to UTF-8 text.
*
* @param string $text
* Create a new Title from text, such as what one would find in a link. De-
* codes any HTML entities in the text.
*
- * @param string|null $text The link text; spaces, prefixes, and an
+ * @param string|int|null $text The link text; spaces, prefixes, and an
* initial ':' indicating the main namespace are accepted.
* @param int $defaultNamespace The namespace to use if none is specified
* by a prefix. If you want to force a specific namespace even if
if ( is_object( $text ) ) {
throw new InvalidArgumentException( '$text must be a string.' );
}
- if ( $text !== null && !is_string( $text ) ) {
+ // DWIM: Integers can be passed in here when page titles are used as array keys.
+ if ( $text !== null && !is_string( $text ) && !is_int( $text ) ) {
wfDebugLog( 'T76305', wfGetAllCallers( 5 ) );
return null;
}
}
try {
- return Title::newFromTextThrow( $text, $defaultNamespace );
+ return Title::newFromTextThrow( strval( $text ), $defaultNamespace );
} catch ( MalformedTitleException $ex ) {
return null;
}
* @param array $params An array with the request parameters
*/
protected function setupExternalResponse( $module, $params ) {
- if ( !$this->getRequest()->wasPosted() && $module->mustBePosted() ) {
+ $request = $this->getRequest();
+ if ( !$request->wasPosted() && $module->mustBePosted() ) {
// Module requires POST. GET request might still be allowed
// if $wgDebugApi is true, otherwise fail.
$this->dieUsageMsgOrDebug( array( 'mustbeposted', $this->mAction ) );
// Create an appropriate printer
$this->mPrinter = $this->createPrinterByName( $params['format'] );
}
+
+ if ( $request->getProtocol() === 'http' && (
+ $request->getSession()->shouldForceHTTPS() ||
+ ( $this->getUser()->isLoggedIn() &&
+ $this->getUser()->requiresHTTPS() )
+ ) ) {
+ $this->logFeatureUsage( 'https-expected' );
+ $this->setWarning( 'HTTP used when HTTPS was expected' );
+ }
}
/**
if ( $editInfo && $editInfo->output ) {
$key = self::getStashKey( $page->getTitle(), $content, $user );
+ // Let extensions add ParserOutput metadata or warm other caches
+ Hooks::run( 'ParserOutputStashForEdit', array( $page, $content, $editInfo->output ) );
+
list( $stashInfo, $ttl ) = self::buildStashValue(
$editInfo->pstContent, $editInfo->output, $editInfo->timestamp
);
if ( $stashInfo ) {
$ok = $cache->set( $key, $stashInfo, $ttl );
if ( $ok ) {
+
$logger->debug( "Cached parser output for key '$key'." );
return self::ERROR_NONE;
} else {
/**
* Commit changes on all master connections
* @param string $fname Caller name
+ * @param array $options Options map:
+ * - maxWriteDuration: abort if more than this much time was spent in write queries
*/
- public function commitMasterChanges( $fname = __METHOD__ ) {
+ public function commitMasterChanges( $fname = __METHOD__, array $options = array() ) {
+ $limit = isset( $options['maxWriteDuration'] ) ? $options['maxWriteDuration'] : 0;
+
$this->logMultiDbTransaction();
+ $this->forEachLB( function ( LoadBalancer $lb ) use ( $limit ) {
+ $lb->forEachOpenConnection( function ( IDatabase $db ) use ( $limit ) {
+ $time = $db->pendingWriteQueryDuration();
+ if ( $limit > 0 && $time > $limit ) {
+ throw new DBTransactionError(
+ $db,
+ wfMessage( 'transaction-duration-limit-exceeded', $time, $limit )->text()
+ );
+ }
+ } );
+ } );
$start = microtime( true );
$this->forEachLBCallMethod( 'commitMasterChanges', array( $fname ) );
// Ensure the user has a token
// @codeCoverageIgnoreStart
$anon = $this->user->isAnon();
- if ( !$anon && !$this->user->getToken() ) {
+ if ( !$anon && !$this->user->getToken( false ) ) {
$this->logger->debug(
"SessionBackend $this->id creating token for user {$this->user} on save"
);
'provider' => (string)$this->provider,
'providerMetadata' => $this->providerMetadata,
'userId' => $anon ? 0 : $this->user->getId(),
- 'userName' => $anon ? null : $this->user->getName(),
+ 'userName' => User::isValidUserName( $this->user->getName() ) ? $this->user->getName() : null,
'userToken' => $anon ? null : $this->user->getToken(),
'remember' => !$anon && $this->remember,
'forceHTTPS' => $this->forceHTTPS,
// Reset the user's token to kill existing sessions
$user = User::newFromName( $username );
- if ( $user && $user->getToken() ) {
+ if ( $user && $user->getToken( false ) ) {
$user->setToken( true );
$user->saveSettings();
}
/**
* Return the user token
- * @return string|null
+ * @return string
*/
public function getToken() {
- return $this->user === null || $this->user->getId() === 0 ? null : $this->user->getToken( true );
+ return $this->user === null || $this->user->getId() === 0 ? '' : $this->user->getToken( false );
}
/**
$all = false;
}
- if ( isset( $row->user_email ) ) {
- $this->mEmail = $row->user_email;
- $this->mToken = $row->user_token;
- if ( $this->mToken == '' ) {
+ if ( isset( $row->user_token ) ) {
+ // The definition for the column is binary(32), so trim the NULs
+ // that appends. The previous definition was char(32), so trim
+ // spaces too.
+ $this->mToken = rtrim( $row->user_token, " \0" );
+ if ( $this->mToken === '' ) {
$this->mToken = null;
}
+ } else {
+ $all = false;
+ }
+
+ if ( isset( $row->user_email ) ) {
+ $this->mEmail = $row->user_email;
$this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
$this->mEmailToken = $row->user_email_token;
$this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-require_once __DIR__ . '/LanguageZh.php';
-
/**
* @ingroup Language
*/
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-
/**
* Conversion script between Latin and Syllabics for Inuktitut.
* - Syllabics -> lowercase Latin
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-require_once __DIR__ . '/LanguageKk_cyrl.php';
-
define( 'KK_C_UC', 'АӘБВГҒДЕЁЖЗИЙКҚЛМНҢОӨПРСТУҰҮФХҺЦЧШЩЪЫІЬЭЮЯ' ); # Kazakh Cyrillic uppercase
define( 'KK_C_LC', 'аәбвгғдеёжзийкқлмнңоөпрстуұүфхһцчшщъыіьэюя' ); # Kazakh Cyrillic lowercase
define( 'KK_L_UC', 'AÄBCÇDEÉFGĞHIİÏJKLMNÑOÖPQRSŞTUÜVWXYÝZ' ); # Kazakh Latin uppercase
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-require_once __DIR__ . '/LanguageKu_ku.php';
-
/**
* Kurdish converter routines
*
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-
/**
* Conversion script between Latin and Tifinagh for Tachelhit.
* - Tifinagh -> lowercase Latin
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-
/**
* There are two levels of conversion for Serbian: the script level
* (Cyrillics <-> Latin), and the variant level (ekavian
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-
/**
* Converts Tajiki to latin orthography
*
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-
/**
* @ingroup Language
*/
* @ingroup Language
*/
-require_once __DIR__ . '/../LanguageConverter.php';
-require_once __DIR__ . '/LanguageZh_hans.php';
-
/**
* @ingroup Language
*/
/**
* Get a message object.
*
- * Shorcut for `new mw.Message( mw.messages, key, parameters )`.
+ * Shortcut for `new mw.Message( mw.messages, key, parameters )`.
*
* @see mw.Message
* @param {string} key Key of message to get
*/
/**
- * Write a message the console's warning channel.
+ * Write a message to the console's warning channel.
* Actions not supported by the browser console are silently ignored.
*
* @param {...string} msg Messages to output to console
$.noop;
/**
- * Write a message the console's error channel.
+ * Write a message to the console's error channel.
*
* Most browsers provide a stacktrace by default if the argument
* is a caught Error object.
/**
* A module has entered state 'ready', 'error', or 'missing'. Automatically update
* pending jobs and modules that depend upon this module. If the given module failed,
- * propagate the 'error' state up the dependency tree. Otherwise, go ahead an execute
+ * propagate the 'error' state up the dependency tree. Otherwise, go ahead and execute
* all jobs/modules now having their dependencies satisfied.
*
* Jobs that depend on a failed module, will have their error callback ran (if any).
script( $, $ );
markModuleReady();
} else if ( typeof script === 'string' ) {
- // Site and user modules are a legacy scripts that run in the global scope.
+ // Site and user modules are legacy scripts that run in the global scope.
// This is transported as a string instead of a function to avoid needing
// to use string manipulation to undo the function wrapper.
if ( module === 'user' ) {
}
/**
- * Adds a dependencies to the queue with optional callbacks to be run
+ * Adds all dependencies to the queue with optional callbacks to be run
* when the dependencies are ready or fail
*
* @private
* When #load or #using requests one or more modules, the server
* response contain calls to this function.
*
- * All arguments are required.
- *
* @param {string} module Name of module
- * @param {Function|Array} script Function with module code or Array of URLs to
+ * @param {Function|Array} [script] Function with module code or Array of URLs to
* be used as the src attribute of a new `<script>` tag.
* @param {Object} [style] Should follow one of the following patterns:
*
/**
* Log a message to window.console, if possible.
*
- * Useful to force logging of some errors that are otherwise hard to detect (i.e., this logs
+ * Useful to force logging of some errors that are otherwise hard to detect (i.e., this logs
* also in production mode). Gets console references in each invocation instead of caching the
* reference, so that debugging tools loaded later are supported (e.g. Firebug Lite in IE).
*
msg += ( e ? ':' : '.' );
console.log( msg );
- // If we have an exception object, log it to the error channel to trigger a
- // proper stacktraces in browsers that support it. No fallback as we have no browsers
- // that don't support error(), but do support log().
+ // If we have an exception object, log it to the error channel to trigger
+ // proper stacktraces in browsers that support it. No fallback as we have
+ // no browsers that don't support error(), but do support log().
if ( e && console.error ) {
console.error( String( e ), e );
}
$this->assertTrue( $userinfo->isVerified() );
$this->assertSame( 0, $userinfo->getId() );
$this->assertSame( null, $userinfo->getName() );
- $this->assertSame( null, $userinfo->getToken() );
+ $this->assertSame( '', $userinfo->getToken() );
$this->assertNotNull( $userinfo->getUser() );
$this->assertSame( $userinfo, $userinfo->verified() );
$this->assertSame( '<anon>', (string)$userinfo );
$this->assertFalse( $userinfo->isVerified() );
$this->assertSame( $user->getId(), $userinfo->getId() );
$this->assertSame( $user->getName(), $userinfo->getName() );
- $this->assertSame( null, $userinfo->getToken() );
+ $this->assertSame( '', $userinfo->getToken() );
$this->assertInstanceOf( 'User', $userinfo->getUser() );
$userinfo2 = $userinfo->verified();
$this->assertNotSame( $userinfo2, $userinfo );
$this->assertTrue( $userinfo2->isVerified() );
$this->assertSame( $user->getId(), $userinfo2->getId() );
$this->assertSame( $user->getName(), $userinfo2->getName() );
- $this->assertSame( null, $userinfo2->getToken() );
+ $this->assertSame( '', $userinfo2->getToken() );
$this->assertInstanceOf( 'User', $userinfo2->getUser() );
$this->assertSame( $userinfo2, $userinfo2->verified() );
$this->assertSame( "<+:{$user->getId()}:{$user->getName()}>", (string)$userinfo2 );
$this->assertFalse( $userinfo->isVerified() );
$this->assertSame( $user->getId(), $userinfo->getId() );
$this->assertSame( $user->getName(), $userinfo->getName() );
- $this->assertSame( null, $userinfo->getToken() );
+ $this->assertSame( '', $userinfo->getToken() );
$this->assertSame( $user, $userinfo->getUser() );
$userinfo2 = $userinfo->verified();
$this->assertNotSame( $userinfo2, $userinfo );
$this->assertTrue( $userinfo2->isVerified() );
$this->assertSame( $user->getId(), $userinfo2->getId() );
$this->assertSame( $user->getName(), $userinfo2->getName() );
- $this->assertSame( null, $userinfo2->getToken() );
+ $this->assertSame( '', $userinfo2->getToken() );
$this->assertSame( $user, $userinfo2->getUser() );
$this->assertSame( $userinfo2, $userinfo2->verified() );
$this->assertSame( "<+:{$user->getId()}:{$user->getName()}>", (string)$userinfo2 );
} );
} );
+ QUnit.test( 'mw.loader.implement( empty )', 1, function ( assert ) {
+ mw.loader.implement( 'test.empty' );
+ assert.strictEqual( mw.loader.getState( 'test.empty' ), 'ready' );
+ } );
+
QUnit.test( 'mw.loader with broken indirect dependency', 4, function ( assert ) {
// don't emit an error event
this.sandbox.stub( mw, 'track' );