*/
$wgUseCombinedLoginLink = false;
-/**
- * Appearance of user page and talk page labels in personal tools.
- * - true = combine links into a single label
- * - false = keep links in separate labels
- */
-$wgVectorCombineUserTalk = false;
-
/**
* Search form look for Vector skin only.
* - true = use an icon search button
public static function userLink( $userId, $userName, $altUserName = false ) {
if ( $userId == 0 ) {
$page = SpecialPage::getTitleFor( 'Contributions', $userName );
+ if ( $altUserName === false ) {
+ $altUserName = IP::prettifyIP( $userName );
+ }
} else {
$page = Title::makeTitle( NS_USER, $userName );
}
'moredotdotdot' => 'More...',
'mypage' => 'Page',
'mytalk' => 'Talk',
-'mytalk-parenthetical' => 'talk',
'anontalk' => 'Talk for this IP address',
'navigation' => 'Navigation',
'and' => ' and',
* $1 is an unknown warning.',
'api-error-uploaddisabled' => 'API error message that can be used for client side localisation of API errors.',
'api-error-verification-error' => 'The word "extension" refers to the part behind the last dot in a file name, that by convention gives a hint about the kind of data format which a files contents are in.',
-
-# Unknown messages
-'mytalk-parenthetical' => 'When user page and talk combined into single label, link title for talk label',
-);
$memcKey = 'jobqueue:dbs:v3';
$pendingDbInfo = $wgMemc->get( $memcKey );
- // If the cache entry wasn't present, or in 1% of cases otherwise,
- // regenerate the cache. Use any available stale cache if another
- // process is currently regenerating the pending DB information.
- if ( !$pendingDbInfo || mt_rand( 0, 100 ) == 0 ) {
- $lock = $wgMemc->add( 'jobqueue:dbs:v3:lock', 1, 1800 ); // lock
- if ( $lock ) {
+ // If the cache entry wasn't present, is stale, or in .1% of cases otherwise,
+ // regenerate the cache. Use any available stale cache if another process is
+ // currently regenerating the pending DB information.
+ if ( !is_array( $pendingDbInfo )
+ || ( time() - $pendingDbInfo['timestamp'] ) > 300 // 5 minutes
+ || mt_rand( 0, 999 ) == 0
+ ) {
+ if ( $wgMemc->add( "$memcKey:rebuild", 1, 1800 ) ) { // lock
$pendingDbInfo = array(
'pendingDBs' => $this->getPendingDbs(),
'timestamp' => time()
);
- $wgMemc->set( $memcKey, $pendingDbInfo );
- $wgMemc->delete( 'jobqueue:dbs:v3:lock' ); // unlock
+ for ( $attempts=1; $attempts <= 25; ++$attempts ) {
+ if ( $wgMemc->add( "$memcKey:lock", 1, 60 ) ) { // lock
+ $wgMemc->set( $memcKey, $pendingDbInfo );
+ $wgMemc->delete( "$memcKey:lock" ); // unlock
+ break;
+ }
+ }
+ $wgMemc->delete( "$memcKey:rebuild" ); // unlock
}
}
- if ( !$pendingDbInfo || !$pendingDbInfo['pendingDBs'] ) {
+ if ( !is_array( $pendingDbInfo ) || !$pendingDbInfo['pendingDBs'] ) {
return; // no DBs with jobs or cache is both empty and locked
}
- $pendingDBs = $pendingDbInfo['pendingDBs'];
+ $pendingDBs = $pendingDbInfo['pendingDBs']; // convenience
do {
$again = false;
// There are no jobs of this type available in the current database
$pendingDBs[$type] = array_diff( $pendingDBs[$type], array( $db ) );
}
- // Update the cache to remove the outdated information
+ // Update the cache to remove the outdated information.
+ // Make sure that this does not race (especially with full rebuilds).
$pendingDbInfo['pendingDBs'] = $pendingDBs;
- // @TODO: fix race condition with these updates
- $wgMemc->set( $memcKey, $pendingDbInfo );
+ if ( $wgMemc->add( "$memcKey:lock", 1, 60 ) ) { // lock
+ $curInfo = $wgMemc->get( $memcKey );
+ if ( $curInfo && $curInfo['timestamp'] === $pendingDbInfo['timestamp'] ) {
+ $wgMemc->set( $memcKey, $pendingDbInfo );
+ }
+ $wgMemc->delete( "$memcKey:lock" ); // unlock
+ }
$again = true;
}
} while ( $again );
* @param $elements array
*/
protected function renderNavigation( $elements ) {
- global $wgVectorUseSimpleSearch, $wgVectorCombineUserTalk;
+ global $wgVectorUseSimpleSearch;
// If only one element was given, wrap it in an array, allowing more
// flexible arguments
<ul<?php $this->html( 'userlangattributes' ) ?>>
<?php
$personalTools = $this->getPersonalTools();
- if ( $wgVectorCombineUserTalk && isset( $personalTools['userpage'] ) ) {
-?>
- <li>
-<?php
- echo $this->makeListItem( 'userpage', $personalTools['userpage'], array( 'tag' => 'span' ) );
-?> <?php
- $personalTools['mytalk']['links'][0]['text'] = $this->getMsg( 'mytalk-parenthetical' )->text();
- $talkItem = $this->makeListItem( 'mytalk', $personalTools['mytalk'], array( 'tag' => 'span' ) );
- echo $this->getMsg( 'parentheses' )->rawParams( $talkItem )->escaped();
- unset( $personalTools['userpage'], $personalTools['mytalk'] );
-?>
- </li>
-<?php
- }
foreach ( $personalTools as $key => $item ) {
echo $this->makeListItem( $key, $item );
}
--- /dev/null
+<?php
+
+class LinkerTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provideCasesForUserLink
+ * @cover Linker::userLink
+ */
+ function testUserLink( $expected, $userId, $userName, $altUserName = false, $msg='' ) {
+ $this->setMwGlobals( array(
+ 'wgArticlePath' => '/wiki/$1',
+ ) );
+
+ $this->assertEquals( $expected,
+ Linker::userLink( $userId, $userName, $altUserName, $msg )
+ );
+ }
+
+ function provideCasesForUserLink() {
+ # Format:
+ # - expected
+ # - userid
+ # - username
+ # - optional altUserName
+ # - optional message
+ return array(
+
+ ### ANONYMOUS USER ########################################
+ array(
+ '<a href="/wiki/Special:Contributions/JohnDoe" title="Special:Contributions/JohnDoe" class="mw-userlink">JohnDoe</a>',
+ 0, 'JohnDoe', false,
+ ),
+ array(
+ '<a href="/wiki/Special:Contributions/::1" title="Special:Contributions/::1" class="mw-userlink">::1</a>',
+ 0, '::1', false,
+ 'Anonymous with pretty IPv6'
+ ),
+ array(
+ '<a href="/wiki/Special:Contributions/0:0:0:0:0:0:0:1" title="Special:Contributions/0:0:0:0:0:0:0:1" class="mw-userlink">::1</a>',
+ 0, '0:0:0:0:0:0:0:1', false,
+ 'Anonymous with almost pretty IPv6'
+ ),
+ array(
+ '<a href="/wiki/Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001" title="Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001" class="mw-userlink">::1</a>',
+ 0, '0000:0000:0000:0000:0000:0000:0000:0001', false,
+ 'Anonymous with full IPv6'
+ ),
+ array(
+ '<a href="/wiki/Special:Contributions/::1" title="Special:Contributions/::1" class="mw-userlink">AlternativeUsername</a>',
+ 0, '::1', 'AlternativeUsername',
+ 'Anonymous with pretty IPv6 and an alternative username'
+ ),
+
+ # IPV4
+ array(
+ '<a href="/wiki/Special:Contributions/127.0.0.1" title="Special:Contributions/127.0.0.1" class="mw-userlink">127.0.0.1</a>',
+ 0, '127.0.0.1', false,
+ 'Anonymous with IPv4'
+ ),
+ array(
+ '<a href="/wiki/Special:Contributions/127.0.0.1" title="Special:Contributions/127.0.0.1" class="mw-userlink">AlternativeUsername</a>',
+ 0, '127.0.0.1', 'AlternativeUsername',
+ 'Anonymous with IPv4 and an alternative username'
+ ),
+
+ ### Regular user ##########################################
+ # TODO!
+ );
+ }
+}