'ExternalStoreHttp' => __DIR__ . '/includes/externalstore/ExternalStoreHttp.php',
'ExternalStoreMedium' => __DIR__ . '/includes/externalstore/ExternalStoreMedium.php',
'ExternalStoreMwstore' => __DIR__ . '/includes/externalstore/ExternalStoreMwstore.php',
+ 'ExternalUserNames' => __DIR__ . '/includes/user/ExternalUserNames.php',
'FSFile' => __DIR__ . '/includes/libs/filebackend/fsfile/FSFile.php',
'FSFileBackend' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
'FSFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
$classes = 'mw-userlink';
$page = null;
if ( $userId == 0 ) {
- $pos = strpos( $userName, '>' );
- if ( $pos !== false ) {
- $iw = explode( ':', substr( $userName, 0, $pos ) );
- $firstIw = array_shift( $iw );
- $interwikiLookup = MediaWikiServices::getInstance()->getInterwikiLookup();
- if ( $interwikiLookup->isValidInterwiki( $firstIw ) ) {
- $title = MWNamespace::getCanonicalName( NS_USER ) . ':' . substr( $userName, $pos + 1 );
- if ( $iw ) {
- $title = join( ':', $iw ) . ':' . $title;
- }
- $page = Title::makeTitle( NS_MAIN, $title, '', $firstIw );
- }
+ $page = ExternalUserNames::getUserLinkTitle( $userName );
+
+ if ( ExternalUserNames::isExternal( $userName ) ) {
$classes .= ' mw-extuserlink';
- } else {
- $page = SpecialPage::getTitleFor( 'Contributions', $userName );
- if ( $altUserName === false ) {
- $altUserName = IP::prettifyIP( $userName );
- }
+ } elseif ( $altUserName === false ) {
+ $altUserName = IP::prettifyIP( $userName );
}
$classes .= ' mw-anonuserlink'; // Separate link class for anons (T45179)
} else {
$blockable = !( $flags & self::TOOL_LINKS_NOBLOCK );
$addEmailLink = $flags & self::TOOL_LINKS_EMAIL && $userId;
- if ( $userId == 0 && strpos( $userText, '>' ) !== false ) {
+ if ( $userId == 0 && ExternalUserNames::isExternal( $userText ) ) {
// No tools for an external user
return '';
}
private $countableCache = [];
/** @var bool */
private $disableStatisticsUpdate = false;
- private $usernamePrefix = 'imported';
- private $assignKnownUsers = false;
- private $triedCreations = [];
+ /** @var ExternalUserNames */
+ private $externalUserNames;
/**
* Creates an ImportXMLReader drawing from the source provided
$this->setPageOutCallback( [ $this, 'finishImportPage' ] );
$this->importTitleFactory = new NaiveImportTitleFactory();
+ $this->externalUserNames = new ExternalUserNames( 'imported', false );
}
/**
* @param bool $assignKnownUsers Whether to apply the prefix to usernames that exist locally
*/
public function setUsernamePrefix( $usernamePrefix, $assignKnownUsers ) {
- $this->usernamePrefix = rtrim( (string)$usernamePrefix, ':>' );
- $this->assignKnownUsers = (bool)$assignKnownUsers;
+ $this->externalUserNames = new ExternalUserNames( $usernamePrefix, $assignKnownUsers );
}
/**
}
if ( !isset( $logInfo['contributor']['username'] ) ) {
- $revision->setUsername( $this->usernamePrefix . '>Unknown user' );
+ $revision->setUsername( $this->externalUserNames->addPrefix( 'Unknown user' ) );
} else {
- $revision->setUsername( $this->prefixUsername( $logInfo['contributor']['username'] ) );
+ $revision->setUsername(
+ $this->externalUserNames->applyPrefix( $logInfo['contributor']['username'] )
+ );
}
return $this->logItemCallback( $revision );
if ( isset( $revisionInfo['contributor']['ip'] ) ) {
$revision->setUserIP( $revisionInfo['contributor']['ip'] );
} elseif ( isset( $revisionInfo['contributor']['username'] ) ) {
- $revision->setUsername( $this->prefixUsername( $revisionInfo['contributor']['username'] ) );
+ $revision->setUsername(
+ $this->externalUserNames->applyPrefix( $revisionInfo['contributor']['username'] )
+ );
} else {
- $revision->setUsername( $this->usernamePrefix . '>Unknown user' );
+ $revision->setUsername( $this->externalUserNames->addPrefix( 'Unknown user' ) );
}
if ( isset( $revisionInfo['sha1'] ) ) {
$revision->setSha1Base36( $revisionInfo['sha1'] );
$revision->setUserIP( $uploadInfo['contributor']['ip'] );
}
if ( isset( $uploadInfo['contributor']['username'] ) ) {
- $revision->setUsername( $this->prefixUsername( $uploadInfo['contributor']['username'] ) );
+ $revision->setUsername(
+ $this->externalUserNames->applyPrefix( $uploadInfo['contributor']['username'] )
+ );
}
$revision->setNoUpdates( $this->mNoUpdates );
return call_user_func( $this->mUploadCallback, $revision );
}
- /**
- * Add an interwiki prefix to the username, if appropriate
- * @since 1.31
- * @param string $name Name being imported
- * @return string Name, possibly with the prefix prepended.
- */
- protected function prefixUsername( $name ) {
- if ( !User::isUsableName( $name ) ) {
- return $name;
- }
-
- if ( $this->assignKnownUsers ) {
- if ( User::idFromName( $name ) ) {
- return $name;
- }
-
- // See if any extension wants to create it.
- if ( !isset( $this->triedCreations[$name] ) ) {
- $this->triedCreations[$name] = true;
- if ( !Hooks::run( 'ImportHandleUnknownUser', [ $name ] ) &&
- User::idFromName( $name, User::READ_LATEST )
- ) {
- return $name;
- }
- }
- }
-
- return substr( $this->usernamePrefix . '>' . $name, 0, 255 );
- }
-
/**
* @return array
*/
--- /dev/null
+<?php
+/**
+ * Class to parse and build external user names
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Class to parse and build external user names
+ * @since 1.31
+ */
+class ExternalUserNames {
+ private $usernamePrefix = 'imported';
+ private $assignKnownUsers = false;
+ private $triedCreations = [];
+
+ /**
+ * @param string $usernamePrefix Prefix to apply to unknown (and possibly also known) usernames
+ * @param bool $assignKnownUsers Whether to apply the prefix to usernames that exist locally
+ */
+ public function __construct( $usernamePrefix, $assignKnownUsers ) {
+ $this->usernamePrefix = rtrim( (string)$usernamePrefix, ':>' );
+ $this->assignKnownUsers = (bool)$assignKnownUsers;
+ }
+
+ /**
+ * Get a target Title to link a username.
+ *
+ * @param string $userName Username to link
+ *
+ * @return null|Title
+ */
+ public static function getUserLinkTitle( $userName ) {
+ $pos = strpos( $userName, '>' );
+ if ( $pos !== false ) {
+ $iw = explode( ':', substr( $userName, 0, $pos ) );
+ $firstIw = array_shift( $iw );
+ $interwikiLookup = MediaWikiServices::getInstance()->getInterwikiLookup();
+ if ( $interwikiLookup->isValidInterwiki( $firstIw ) ) {
+ $title = MWNamespace::getCanonicalName( NS_USER ) . ':' . substr( $userName, $pos + 1 );
+ if ( $iw ) {
+ $title = join( ':', $iw ) . ':' . $title;
+ }
+ return Title::makeTitle( NS_MAIN, $title, '', $firstIw );
+ }
+ return null;
+ } else {
+ return SpecialPage::getTitleFor( 'Contributions', $userName );
+ }
+ }
+
+ /**
+ * Add an interwiki prefix to the username, if appropriate
+ *
+ * @param string $name Name being imported
+ * @return string Name, possibly with the prefix prepended.
+ */
+ public function applyPrefix( $name ) {
+ if ( !User::isUsableName( $name ) ) {
+ return $name;
+ }
+
+ if ( $this->assignKnownUsers ) {
+ if ( User::idFromName( $name ) ) {
+ return $name;
+ }
+
+ // See if any extension wants to create it.
+ if ( !isset( $this->triedCreations[$name] ) ) {
+ $this->triedCreations[$name] = true;
+ if ( !Hooks::run( 'ImportHandleUnknownUser', [ $name ] ) &&
+ User::idFromName( $name, User::READ_LATEST )
+ ) {
+ return $name;
+ }
+ }
+ }
+
+ return $this->addPrefix( $name );
+ }
+
+ /**
+ * Add an interwiki prefix to the username regardless of circumstances
+ *
+ * @param string $name Name being imported
+ * @return string Name
+ */
+ public function addPrefix( $name ) {
+ return substr( $this->usernamePrefix . '>' . $name, 0, 255 );
+ }
+
+ /**
+ * Tells whether the username is external or not
+ *
+ * @param string $username Username to check
+ * @return bool true if it's external, false otherwise.
+ */
+ public static function isExternal( $username ) {
+ return strpos( $username, '>' ) !== false;
+ }
+
+}
--- /dev/null
+<?php
+
+use MediaWiki\Interwiki\InterwikiLookup;
+
+/**
+ * @covers ExternalUserNames
+ */
+class ExternalUserNamesTest extends MediaWikiTestCase {
+
+ public function provideGetUserLinkTitle() {
+ return [
+ [ 'valid:>User1', Title::makeTitle( NS_MAIN, ':User:User1', '', 'valid' ) ],
+ [
+ 'valid:valid:>User1',
+ Title::makeTitle( NS_MAIN, 'valid::User:User1', '', 'valid' )
+ ],
+ [
+ '127.0.0.1',
+ Title::makeTitle( NS_SPECIAL, 'Contributions/127.0.0.1', '', '' )
+ ],
+ [ 'invalid:>User1', null ]
+ ];
+ }
+
+ /**
+ * @covers ExternalUserNames::getUserLinkTitle
+ * @dataProvider provideGetUserLinkTitle
+ */
+ public function testGetUserLinkTitle( $username, $expected ) {
+ $interwikiLookupMock = $this->getMockBuilder( InterwikiLookup::class )
+ ->getMock();
+
+ $interwikiValueMap = [
+ [ 'valid', true ],
+ [ 'invalid', false ]
+ ];
+ $interwikiLookupMock->expects( $this->any() )
+ ->method( 'isValidInterwiki' )
+ ->will( $this->returnValueMap( $interwikiValueMap ) );
+
+ $this->setService( 'InterwikiLookup', $interwikiLookupMock );
+
+ $this->assertEquals(
+ $expected,
+ ExternalUserNames::getUserLinkTitle( $username )
+ );
+ }
+
+ public function provideApplyPrefix() {
+ return [
+ [ 'User1', 'prefix', 'prefix>User1' ],
+ [ 'User1', 'prefix:>', 'prefix>User1' ],
+ [ 'User1', 'prefix:', 'prefix>User1' ],
+ ];
+ }
+
+ /**
+ * @covers ExternalUserNames::applyPrefix
+ * @dataProvider provideApplyPrefix
+ */
+ public function testApplyPrefix( $username, $prefix, $expected ) {
+ $externalUserNames = new ExternalUserNames( $prefix, true );
+
+ $this->assertSame(
+ $expected,
+ $externalUserNames->applyPrefix( $username )
+ );
+ }
+
+ public function provideAddPrefix() {
+ return [
+ [ 'User1', 'prefix', 'prefix>User1' ],
+ [ 'User2', 'prefix2', 'prefix2>User2' ],
+ [ 'User3', 'prefix3', 'prefix3>User3' ],
+ ];
+ }
+
+ /**
+ * @covers ExternalUserNames::addPrefix
+ * @dataProvider provideAddPrefix
+ */
+ public function testAddPrefix( $username, $prefix, $expected ) {
+ $externalUserNames = new ExternalUserNames( $prefix, true );
+
+ $this->assertSame(
+ $expected,
+ $externalUserNames->addPrefix( $username )
+ );
+ }
+
+ public function provideIsExternal() {
+ return [
+ [ 'User1', false ],
+ [ '>User1', true ],
+ [ 'prefix>User1', true ],
+ [ 'prefix:>User1', true ],
+ ];
+ }
+
+ /**
+ * @covers ExternalUserNames::isExternal
+ * @dataProvider provideIsExternal
+ */
+ public function testIsExternal( $username, $expected ) {
+ $this->assertSame(
+ $expected,
+ ExternalUserNames::isExternal( $username )
+ );
+ }
+
+}