Hard deprecate User ::isIP, ::getOptions

Bug: T275602
Change-Id: Id4be13751ca0a900e51214c1855a4624077a5a62
This commit is contained in:
vladshapik 2021-04-12 17:45:26 +03:00 committed by Vlad.shapik
parent b1f51795bb
commit 9cc797695b
28 changed files with 207 additions and 68 deletions

View file

@ -122,6 +122,10 @@ because of Phabricator reports.
::setHookContainer() were soft deprecated. Use ::init() to inject
dependencies or override ::postInitSetup() to do any custom
post-initialization configuration.
* The following functions from the User class, deprecated in 1.35, now emit
deprecation warnings:
- getOptions
- isIP
* …
=== Other changes in 1.37 ===

View file

@ -56,6 +56,7 @@ use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\RevisionStoreRecord;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserNameUtils;
use MediaWiki\Watchlist\WatchlistManager;
use OOUI\CheckboxInputWidget;
use OOUI\DropdownInputWidget;
@ -428,6 +429,11 @@ class EditPage implements IEditObject {
*/
private $watchlistManager;
/**
* @var UserNameUtils
*/
private $userNameUtils;
/**
* @stable to call
* @param Article $article
@ -461,6 +467,7 @@ class EditPage implements IEditObject {
$this->watchedItemStore = $services->getWatchedItemStore();
$this->wikiPageFactory = $services->getWikiPageFactory();
$this->watchlistManager = $services->getWatchlistManager();
$this->userNameUtils = $services->getUserNameUtils();
$this->deprecatePublicProperty( 'mBaseRevision', '1.35', __CLASS__ );
$this->deprecatePublicProperty( 'deletedSinceEdit', '1.35', __CLASS__ );
@ -2747,7 +2754,7 @@ class EditPage implements IEditObject {
if ( $namespace === NS_USER || $namespace === NS_USER_TALK ) {
$username = explode( '/', $this->mTitle->getText(), 2 )[0];
$user = User::newFromName( $username, false /* allow IP users */ );
$ip = User::isIP( $username );
$ip = $this->userNameUtils->isIP( $username );
$block = DatabaseBlock::newFromTarget( $user, $user );
$userExists = ( $user && $user->isRegistered() );

View file

@ -200,7 +200,7 @@ class UserDef extends TypeDef {
// An IP?
$b = IPUtils::RE_IP_BYTE;
if ( IPUtils::isValid( $value ) ||
// See comment for User::isIP. We don't just call that function
// See comment for UserNameUtils::isIP. We don't just call that function
// here because it also returns true for things like
// 300.300.300.300 that are neither valid usernames nor valid IP
// addresses.

View file

@ -48,6 +48,7 @@ use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\Revision\SlotRoleRegistry;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserNameUtils;
use MessageCache;
use MWTimestamp;
use MWUnknownContentModelException;
@ -286,6 +287,9 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
/** @var EditResultCache */
private $editResultCache;
/** @var UserNameUtils */
private $userNameUtils;
/**
* @param WikiPage $wikiPage ,
* @param RevisionStore $revisionStore
@ -299,6 +303,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
* @param IContentHandlerFactory $contentHandlerFactory
* @param HookContainer $hookContainer
* @param EditResultCache $editResultCache
* @param UserNameUtils $userNameUtils
*/
public function __construct(
WikiPage $wikiPage,
@ -312,7 +317,8 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
ILBFactory $loadbalancerFactory,
IContentHandlerFactory $contentHandlerFactory,
HookContainer $hookContainer,
EditResultCache $editResultCache
EditResultCache $editResultCache,
UserNameUtils $userNameUtils
) {
$this->wikiPage = $wikiPage;
@ -329,6 +335,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
$this->contentHandlerFactory = $contentHandlerFactory;
$this->hookRunner = new HookRunner( $hookContainer );
$this->editResultCache = $editResultCache;
$this->userNameUtils = $userNameUtils;
$this->logger = new NullLogger();
}
@ -1591,7 +1598,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
$revRecord = $this->revision;
$talkPageNotificationManager = MediaWikiServices::getInstance()
->getTalkPageNotificationManager();
if ( User::isIP( $shortTitle ) ) {
if ( $this->userNameUtils->isIP( $shortTitle ) ) {
// An anonymous user
$talkPageNotificationManager->setUserHasNewMessages( $recipient, $revRecord );
} elseif ( $recipient->isRegistered() ) {

View file

@ -173,7 +173,12 @@ class ApiMain extends ApiBase {
]
],
'userrights' => ApiUserrights::class,
'options' => ApiOptions::class,
'options' => [
'class' => ApiOptions::class,
'services' => [
'UserOptionsManager',
],
],
'imagerotate' => ApiImageRotate::class,
'revisiondelete' => ApiRevisionDelete::class,
'managetags' => ApiManageTags::class,

View file

@ -22,6 +22,7 @@
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use MediaWiki\User\UserOptionsManager;
/**
* API module that facilitates the changing of user's preferences.
@ -33,6 +34,27 @@ class ApiOptions extends ApiBase {
/** @var User User account to modify */
private $userForUpdates;
/** @var UserOptionsManager */
private $userOptionsManager;
/**
* @param ApiMain $main
* @param string $action
* @param UserOptionsManager|null $userOptionsManager
*/
public function __construct(
ApiMain $main,
$action,
UserOptionsManager $userOptionsManager = null
) {
parent::__construct( $main, $action );
/**
* This class is extended by GlobalPreferences extension.
* So it falls back to the global state.
*/
$this->userOptionsManager = $userOptionsManager ?? MediaWikiServices::getInstance()->getUserOptionsManager();
}
/**
* Changes preferences of the current user.
*/
@ -99,7 +121,7 @@ class ApiOptions extends ApiBase {
$htmlForm = new HTMLForm( [], $this );
}
$field = HTMLForm::loadInputFromParameters( $key, $prefs[$key], $htmlForm );
$validation = $field->validate( $value, $user->getOptions() );
$validation = $field->validate( $value, $this->userOptionsManager->getOptions( $user ) );
}
break;
case 'registered-multiselect':

View file

@ -92,6 +92,7 @@ class ApiQuery extends ApiBase {
'services' => [
'BlockRestrictionStore',
'CommentStore',
'UserNameUtils',
],
],
'categorymembers' => ApiQueryCategoryMembers::class,
@ -142,6 +143,7 @@ class ApiQuery extends ApiBase {
'services' => [
'CommentStore',
'UserIdentityLookup',
'UserNameUtils',
],
],
'users' => ApiQueryUsers::class,
@ -171,7 +173,8 @@ class ApiQuery extends ApiBase {
'services' => [
'TalkPageNotificationManager',
'WatchedItemStore',
'UserEditTracker'
'UserEditTracker',
'UserOptionsLookup',
]
],
'filerepoinfo' => ApiQueryFileRepoInfo::class,

View file

@ -22,6 +22,7 @@
use MediaWiki\Block\BlockRestrictionStore;
use MediaWiki\ParamValidator\TypeDef\UserDef;
use MediaWiki\User\UserNameUtils;
use Wikimedia\IPUtils;
use Wikimedia\Rdbms\IResultWrapper;
@ -38,21 +39,27 @@ class ApiQueryBlocks extends ApiQueryBase {
/** @var CommentStore */
private $commentStore;
/** @var UserNameUtils */
private $userNameUtils;
/**
* @param ApiQuery $query
* @param string $moduleName
* @param BlockRestrictionStore $blockRestrictionStore
* @param CommentStore $commentStore
* @param UserNameUtils $userNameUtils
*/
public function __construct(
ApiQuery $query,
$moduleName,
BlockRestrictionStore $blockRestrictionStore,
CommentStore $commentStore
CommentStore $commentStore,
UserNameUtils $userNameUtils
) {
parent::__construct( $query, $moduleName, 'bk' );
$this->blockRestrictionStore = $blockRestrictionStore;
$this->commentStore = $commentStore;
$this->userNameUtils = $userNameUtils;
}
public function execute() {
@ -283,7 +290,7 @@ class ApiQueryBlocks extends ApiQueryBase {
"baduser_{$encParamName}"
);
}
$name = User::isIP( $user )
$name = $this->userNameUtils->isIP( $user ) || IPUtils::isIPv6( $user )
? $user
: User::getCanonicalName( $user, 'valid' );
if ( $name === false ) {

View file

@ -26,6 +26,7 @@ use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Storage\NameTableAccessException;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserIdentityLookup;
use MediaWiki\User\UserNameUtils;
use Wikimedia\Rdbms\SelectQueryBuilder;
/**
@ -41,21 +42,27 @@ class ApiQueryUserContribs extends ApiQueryBase {
/** @var UserIdentityLookup */
private $userIdentityLookup;
/** @var UserNameUtils */
private $userNameUtils;
/**
* @param ApiQuery $query
* @param string $moduleName
* @param CommentStore $commentStore
* @param UserIdentityLookup $userIdentityLookup
* @param UserNameUtils $userNameUtils
*/
public function __construct(
ApiQuery $query,
$moduleName,
CommentStore $commentStore,
UserIdentityLookup $userIdentityLookup
UserIdentityLookup $userIdentityLookup,
UserNameUtils $userNameUtils
) {
parent::__construct( $query, $moduleName, 'uc' );
$this->commentStore = $commentStore;
$this->userIdentityLookup = $userIdentityLookup;
$this->userNameUtils = $userNameUtils;
}
private $params, $multiUserMode, $orderBy, $parentLens;
@ -187,7 +194,7 @@ class ApiQueryUserContribs extends ApiQueryBase {
);
}
if ( User::isIP( $u ) || ExternalUserNames::isExternal( $u ) ) {
if ( $this->userNameUtils->isIP( $u ) || ExternalUserNames::isExternal( $u ) ) {
$names[$u] = null;
} else {
$name = User::getCanonicalName( $u, 'valid' );

View file

@ -22,6 +22,7 @@
use MediaWiki\User\TalkPageNotificationManager;
use MediaWiki\User\UserEditTracker;
use MediaWiki\User\UserOptionsLookup;
/**
* Query module to get information about the currently logged-in user
@ -55,17 +56,32 @@ class ApiQueryUserInfo extends ApiQueryBase {
*/
private $userEditTracker;
/**
* @var UserOptionsLookup
*/
private $userOptionsLookup;
/**
* @param ApiQuery $query
* @param string $moduleName
* @param TalkPageNotificationManager $talkPageNotificationManager
* @param WatchedItemStore $watchedItemStore
* @param UserEditTracker $userEditTracker
* @param UserOptionsLookup $userOptionsLookup
*/
public function __construct(
ApiQuery $query,
$moduleName,
TalkPageNotificationManager $talkPageNotificationManager,
WatchedItemStore $watchedItemStore,
UserEditTracker $userEditTracker
UserEditTracker $userEditTracker,
UserOptionsLookup $userOptionsLookup
) {
parent::__construct( $query, $moduleName, 'ui' );
$this->talkPageNotificationManager = $talkPageNotificationManager;
$this->watchedItemStore = $watchedItemStore;
$this->userEditTracker = $userEditTracker;
$this->userOptionsLookup = $userOptionsLookup;
}
public function execute() {
@ -180,7 +196,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
}
if ( isset( $this->prop['options'] ) ) {
$vals['options'] = $user->getOptions();
$vals['options'] = $this->userOptionsLookup->getOptions( $user );
$vals['options'][ApiResult::META_BC_BOOLS] = array_keys( $vals['options'] );
}

View file

@ -29,6 +29,7 @@ use MediaWiki\Permissions\PermissionStatus;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\User\UserNameUtils;
use MediaWiki\Watchlist\WatchlistManager;
use Wikimedia\IPUtils;
use Wikimedia\NonSerializable\NonSerializableTrait;
@ -104,6 +105,11 @@ class Article implements Page {
*/
private $watchlistManager;
/**
* @var UserNameUtils
*/
private $userNameUtils;
/**
* @var RevisionRecord|null Revision to be shown
*
@ -127,6 +133,7 @@ class Article implements Page {
$this->linkRenderer = $services->getLinkRenderer();
$this->revisionStore = $services->getRevisionStore();
$this->watchlistManager = $services->getWatchlistManager();
$this->userNameUtils = $services->getUserNameUtils();
}
/**
@ -1367,7 +1374,7 @@ class Article implements Page {
) {
$rootPart = explode( '/', $title->getText() )[0];
$user = User::newFromName( $rootPart, false /* allow IP users */ );
$ip = User::isIP( $rootPart );
$ip = $this->userNameUtils->isIP( $rootPart );
$block = DatabaseBlock::newFromTarget( $user, $user );
if ( $user && $user->isRegistered() && $user->isHidden() &&

View file

@ -1857,7 +1857,8 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
$services->getDBLoadBalancerFactory(),
$this->getContentHandlerFactory(),
$this->getHookContainer(),
$editResultCache
$editResultCache,
$services->getUserNameUtils()
);
$derivedDataUpdater->setLogger( LoggerFactory::getInstance( 'SaveParse' ) );

View file

@ -230,7 +230,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
$disable = !$this->permissionManager->userHasRight( $user, 'editmyoptions' );
$defaultOptions = $this->userOptionsLookup->getDefaultOptions();
$userOptions = $user->getOptions();
$userOptions = $this->userOptionsLookup->getOptions( $user );
$this->applyFilters( $userOptions, $defaultPreferences, 'filterForForm' );
// Add in defaults from the user
foreach ( $defaultPreferences as $name => &$info ) {
@ -246,9 +246,9 @@ class DefaultPreferencesFactory implements PreferencesFactory {
// Already set, no problem
continue;
} elseif ( $prefFromUser !== null && // Make sure we're not just pulling nothing
$field->validate( $prefFromUser, $user->getOptions() ) === true ) {
$field->validate( $prefFromUser, $this->userOptionsLookup->getOptions( $user ) ) === true ) {
$info['default'] = $prefFromUser;
} elseif ( $field->validate( $globalDefault, $user->getOptions() ) === true ) {
} elseif ( $field->validate( $globalDefault, $this->userOptionsLookup->getOptions( $user ) ) === true ) {
$info['default'] = $globalDefault;
} else {
$globalDefault = json_encode( $globalDefault );
@ -1779,7 +1779,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
}
if ( $this->permissionManager->userHasRight( $user, 'editmyoptions' ) ) {
$oldUserOptions = $user->getOptions();
$oldUserOptions = $this->userOptionsLookup->getOptions( $user );
foreach ( $this->getSaveBlacklist() as $b ) {
unset( $formData[$b] );

View file

@ -1,4 +1,8 @@
<?php
use MediaWiki\MediaWikiServices;
use MediaWiki\User\UserOptionsLookup;
/**
* 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
@ -55,7 +59,8 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule {
];
$script = 'mw.user.tokens.set(' . $context->encodeJson( $tokens ) . ');';
$options = $user->getOptions( User::GETOPTIONS_EXCLUDE_DEFAULTS );
$userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
$options = $userOptionsLookup->getOptions( $user, UserOptionsLookup::EXCLUDE_DEFAULTS );
// Optimisation: Only output this function call if the user has non-default settings.
if ( $options ) {
$script .= 'mw.user.options.set(' . $context->encodeJson( $options ) . ');';

View file

@ -4,6 +4,7 @@ use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
use MediaWiki\Page\WikiPageFactory;
use MediaWiki\User\UserNameUtils;
/**
* Implementation of near match title search.
@ -37,6 +38,11 @@ class SearchNearMatcher {
*/
private $wikiPageFactory;
/**
* @var UserNameUtils
*/
private $userNameUtils;
/**
* SearchNearMatcher constructor.
* @param Config $config
@ -51,6 +57,7 @@ class SearchNearMatcher {
->getLanguageConverter( $lang );
$this->wikiPageFactory = $services->getWikiPageFactory();
$this->hookRunner = new HookRunner( $hookContainer );
$this->userNameUtils = $services->getUserNameUtils();
}
/**
@ -168,8 +175,8 @@ class SearchNearMatcher {
# Entering an IP address goes to the contributions page
if ( $this->config->get( 'EnableSearchContributorsByIP' ) ) {
if ( ( $title->getNamespace() === NS_USER && User::isIP( $title->getText() ) )
|| User::isIP( trim( $searchterm ) ) ) {
if ( ( $title->getNamespace() === NS_USER && $this->userNameUtils->isIP( $title->getText() ) )
|| $this->userNameUtils->isIP( trim( $searchterm ) ) ) {
return SpecialPage::getTitleFor( 'Contributions', $title->getDBkey() );
}
}

View file

@ -439,7 +439,9 @@ abstract class Skin extends ContextSource {
$title = $this->getRelevantTitle();
if ( $title->hasSubjectNamespace( NS_USER ) ) {
$rootUser = $title->getRootText();
if ( User::isIP( $rootUser ) ) {
$services = MediaWikiServices::getInstance();
$userNameUtils = $services->getUserNameUtils();
if ( $userNameUtils->isIP( $rootUser ) ) {
$this->mRelevantUser = User::newFromName( $rootUser, false );
} else {
$user = User::newFromName( $rootUser, false );

View file

@ -220,7 +220,7 @@ class SpecialContributions extends IncludableSpecialPage {
# For IP ranges, we want the contributionsSub, but not the skin-dependent
# links under 'Tools', which may include irrelevant links like 'Logs'.
if ( !IPUtils::isValidRange( $target ) &&
( User::isIP( $target ) || $userObj->isRegistered() )
( $this->userNameUtils->isIP( $target ) || $userObj->isRegistered() )
) {
// Don't add non-existent users, because hidden users
// that we add here will be removed later to pretend
@ -389,10 +389,12 @@ class SpecialContributions extends IncludableSpecialPage {
if ( $isAnon ) {
// Show a warning message that the user being searched for doesn't exist.
// User::isIP returns true for IP address and usemod IPs like '123.123.123.xxx',
// UserNameUtils::isIP returns true for IP address and usemod IPs like '123.123.123.xxx',
// but returns false for IP ranges. We don't want to suggest either of these are
// valid usernames which we would with the 'contributions-userdoesnotexist' message.
if ( !User::isIP( $userObj->getName() ) && !IPUtils::isValidRange( $userObj->getName() ) ) {
if ( !$this->userNameUtils->isIP( $userObj->getName() )
&& !IPUtils::isValidRange( $userObj->getName() )
) {
$this->getOutput()->wrapWikiMsg(
"<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
[

View file

@ -106,7 +106,8 @@ class SpecialListFiles extends IncludableSpecialPage {
$this->repoGroup,
$this->loadBalancer,
$this->commentStore,
$this->userCache
$this->userCache,
$this->userNameUtils
);
$out = $this->getOutput();

View file

@ -20,6 +20,7 @@
*/
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\User\UserNameUtils;
use Wikimedia\Rdbms\FakeResultWrapper;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IResultWrapper;
@ -80,6 +81,7 @@ class ImageListPager extends TablePager {
* @param ILoadBalancer $loadBalancer
* @param CommentStore $commentStore
* @param UserCache $userCache
* @param UserNameUtils $userNameUtils
*/
public function __construct(
IContextSource $context,
@ -91,7 +93,8 @@ class ImageListPager extends TablePager {
RepoGroup $repoGroup,
ILoadBalancer $loadBalancer,
CommentStore $commentStore,
UserCache $userCache
UserCache $userCache,
UserNameUtils $userNameUtils
) {
$this->setContext( $context );
@ -109,7 +112,7 @@ class ImageListPager extends TablePager {
if ( $user ) {
$this->mUser = $user;
}
if ( !$user || ( $user->isAnon() && !User::isIP( $user->getName() ) ) ) {
if ( !$user || ( $user->isAnon() && !$userNameUtils->isIP( $user->getName() ) ) ) {
$this->outputUserDoesNotExist( $userName );
}
}

View file

@ -282,7 +282,7 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
return $copy;
} elseif ( $name === 'mOptions' ) {
wfDeprecated( 'User::$mOptions', '1.35' );
$options = $this->getOptions();
$options = MediaWikiServices::getInstance()->getUserOptionsLookup()->getOptions( $this );
return $options;
} elseif ( !property_exists( $this, $name ) ) {
// T227688 - do not break $u->foo['bar'] = 1
@ -974,12 +974,14 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
* addresses like this, if we allowed accounts like this to be created
* new users could get the old edits of these anonymous users.
*
* @deprecated since 1.35, use the UserNameUtils service
* @deprecated since 1.35, use the UserNameUtils service.
* Hard deprecated since 1.37.
* Note that UserNameUtils::isIP does not accept IPv6 ranges, while this method does
* @param string $name Name to match
* @return bool
*/
public static function isIP( $name ) {
wfDeprecated( __METHOD__, '1.35' );
return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name )
|| IPUtils::isIPv6( $name );
}
@ -2058,8 +2060,9 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
*/
public function getId( $wikiId = self::LOCAL ) : int {
$this->deprecateInvalidCrossWiki( $wikiId, '1.36' );
$userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
if ( $this->mId === null && $this->mName !== null &&
( self::isIP( $this->mName ) || ExternalUserNames::isExternal( $this->mName ) )
( $userNameUtils->isIP( $this->mName ) || ExternalUserNames::isExternal( $this->mName ) )
) {
// Special case, we know the user is anonymous
// Note that "external" users are "local" (they have an actor ID that is relative to
@ -2652,9 +2655,11 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
* User::GETOPTIONS_EXCLUDE_DEFAULTS Exclude user options that are set
* to the default value. (Since 1.25)
* @return array
* @deprecated since 1.35 Use UserOptionsLookup::getOptions instead
* @deprecated since 1.35 Use UserOptionsLookup::getOptions instead.
* Hard deprecated since 1.37.
*/
public function getOptions( $flags = 0 ) {
wfDeprecated( __METHOD__, '1.35' );
return MediaWikiServices::getInstance()
->getUserOptionsLookup()
->getOptions( $this, $flags );

View file

@ -258,8 +258,8 @@ class UserOptionsManager extends UserOptionsLookup {
* - 'registered-checkmatrix' - as above, using the 'checkmatrix' type.
* - 'userjs' - preferences with names starting with 'userjs-', intended to
* be used by user scripts.
* - 'special' - "preferences" that are not accessible via User::getOptions
* or UserOptionsManager::setOptions.
* - 'special' - "preferences" that are not accessible via
* UserOptionsLookup::getOptions or UserOptionsManager::setOptions.
* - 'unused' - preferences about which MediaWiki doesn't know anything.
* These are usually legacy options, removed in newer versions.
*

View file

@ -169,7 +169,8 @@ class ReassignEdits extends Maintenance {
* @return User
*/
private function initialiseUser( $username ) {
if ( User::isIP( $username ) ) {
$services = MediaWikiServices::getInstance();
if ( $services->getUserNameUtils()->isIP( $username ) ) {
$user = User::newFromName( $username, false );
$user->getActorId();
} else {

View file

@ -50,7 +50,8 @@ class RollbackEdits extends Maintenance {
public function execute() {
$user = $this->getOption( 'user' );
$username = User::isIP( $user ) ? $user : User::getCanonicalName( $user );
$services = MediaWikiServices::getInstance();
$username = $services->getUserNameUtils()->isIP( $user ) ? $user : User::getCanonicalName( $user );
if ( !$username ) {
$this->fatalError( 'Invalid username' );
}
@ -79,9 +80,8 @@ class RollbackEdits extends Maintenance {
$doer = User::newSystemUser( 'Maintenance script', [ 'steal' => true ] );
$wikiPageFactory = MediaWikiServices::getInstance()->getWikiPageFactory();
$rollbackPageFactory = MediaWikiServices::getInstance()
->getRollbackPageFactory();
$wikiPageFactory = $services->getWikiPageFactory();
$rollbackPageFactory = $services->getRollbackPageFactory();
foreach ( $titles as $t ) {
$page = $wikiPageFactory->newFromTitle( $t );
$this->output( 'Processing ' . $t->getPrefixedText() . '... ' );

View file

@ -1,5 +1,6 @@
<?php
use MediaWiki\User\UserOptionsManager;
use PHPUnit\Framework\MockObject\MockObject;
/**
@ -37,16 +38,12 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
// No actual DB data
$this->mUserMock->method( 'getInstanceForUpdate' )->willReturn( $this->mUserMock );
// Needs to return something
$this->mUserMock->method( 'getOptions' )
->willReturn( [] );
$this->mUserMock->method( 'isAllowedAny' )->willReturn( true );
// DefaultPreferencesFactory calls a ton of user methods, but we still want to list all of
// them in case bugs are caused by unexpected things returning null that shouldn't.
$this->mUserMock->expects( $this->never() )->method( $this->anythingBut(
'getEffectiveGroups', 'getOptionKinds', 'getInstanceForUpdate', 'getOptions', 'getId',
'getEffectiveGroups', 'getOptionKinds', 'getInstanceForUpdate', 'getId',
'isAnon', 'getRequest', 'isLoggedIn', 'getName', 'getGroupMemberships', 'getEditCount',
'getRegistration', 'isAllowed', 'getRealName', 'getOption', 'getStubThreshold',
'getBoolOption', 'getEmail', 'getDatePreference', 'useRCPatrol', 'useNPPatrol',
@ -65,7 +62,11 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
// Empty session
$this->mSession = [];
$this->mTested = new ApiOptions( $main, 'options' );
$userOptionsManagerMock = $this->createNoOpMock( UserOptionsManager::class, [ 'getOptions' ] );
// Needs to return something
$userOptionsManagerMock->method( 'getOptions' )->willReturn( [] );
$this->mTested = new ApiOptions( $main, 'options', $userOptionsManagerMock );
$this->mergeMwGlobalArrayValue( 'wgHooks', [
'GetPreferences' => [

View file

@ -3,6 +3,7 @@
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Preferences\DefaultPreferencesFactory;
use MediaWiki\User\UserOptionsLookup;
use Wikimedia\TestingAccessWrapper;
/**
@ -53,9 +54,14 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
* Get a basic PreferencesFactory for testing with.
* @param PermissionManager $mockPM
* @param Language $language
* @param UserOptionsLookup|null $userOptionsLookup
* @return DefaultPreferencesFactory
*/
protected function getPreferencesFactory( PermissionManager $mockPM, Language $language ) {
protected function getPreferencesFactory(
PermissionManager $mockPM,
Language $language,
UserOptionsLookup $userOptionsLookup = null
) {
$mockNsInfo = $this->createMock( NamespaceInfo::class );
$mockNsInfo->method( 'getValidNamespaces' )->willReturn( [
NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK
@ -76,7 +82,7 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
$services->getLanguageConverterFactory()->getLanguageConverter( $language ),
$services->getLanguageNameUtils(),
$services->getHookContainer(),
$services->getUserOptionsLookup()
$userOptionsLookup ?? $services->getUserOptionsLookup()
);
}
@ -123,14 +129,15 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
->willReturn( [] );
$userMock->method( 'getGroupMemberships' )
->willReturn( [] );
$userMock->method( 'getOptions' )
->willReturn( [ 'test' => 'yes' ] );
$pm = $this->createMock( PermissionManager::class );
$pm->method( 'userHasRight' )
->will( $this->returnValueMap( [
[ $userMock, 'editmyoptions', true ]
] ) );
$prefs = $this->getPreferencesFactory( $pm, new Language() )
$userOptionsLookupMock = $this->createUserOptionsLookupMock( [ 'test' => 'yes' ], true );
$prefs = $this->getPreferencesFactory( $pm, new Language(), $userOptionsLookupMock )
->getFormDescriptor( $userMock, $this->context );
$this->assertArrayNotHasKey( 'showrollbackconfirmation', $prefs );
}
@ -146,15 +153,16 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
->willReturn( [] );
$userMock->method( 'getGroupMemberships' )
->willReturn( [] );
$userMock->method( 'getOptions' )
->willReturn( [ 'test' => 'yes' ] );
$pm = $this->createMock( PermissionManager::class );
$pm->method( 'userHasRight' )
->will( $this->returnValueMap( [
[ $userMock, 'editmyoptions', true ],
[ $userMock, 'rollback', true ]
] ) );
$prefs = $this->getPreferencesFactory( $pm, new Language() )
$userOptionsLookupMock = $this->createUserOptionsLookupMock( [ 'test' => 'yes' ], true );
$prefs = $this->getPreferencesFactory( $pm, new Language(), $userOptionsLookupMock )
->getFormDescriptor( $userMock, $this->context );
$this->assertArrayHasKey( 'showrollbackconfirmation', $prefs );
$this->assertEquals(
@ -205,8 +213,6 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
$userMock = $this->getMockBuilder( User::class )
->disableOriginalConstructor()
->getMock();
$userMock->method( 'getOptions' )
->willReturn( $oldOptions );
$userMock->expects( $this->exactly( 2 ) )
->method( 'setOption' )
@ -234,6 +240,8 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
[ $userMock, 'editmyoptions', true ]
] ) );
$userOptionsLookupMock = $this->createUserOptionsLookupMock( $oldOptions );
$this->setTemporaryHook( 'PreferencesFormPreSave',
function ( $formData, $form, $user, &$result, $oldUserOptions )
use ( $newOptions, $oldOptions, $userMock ) {
@ -250,7 +258,7 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
/** @var DefaultPreferencesFactory $factory */
$factory = TestingAccessWrapper::newFromObject(
$this->getPreferencesFactory( $pm, new Language() )
$this->getPreferencesFactory( $pm, new Language(), $userOptionsLookupMock )
);
$factory->saveFormData( $newOptions, $form, [] );
}
@ -289,8 +297,6 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
->willReturn( [] );
$userMock->method( 'getGroupMemberships' )
->willReturn( [] );
$userMock->method( 'getOptions' )
->willReturn( [ 'LanguageCode' => 'sr', 'variant' => 'sr' ] );
$pm = $this->createMock( PermissionManager::class );
$pm->method( 'userHasRight' )
@ -300,7 +306,11 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
$language->method( 'getCode' )
->willReturn( 'sr' );
$prefs = $this->getPreferencesFactory( $pm, $language )
$userOptionsLookupMock = $this->createUserOptionsLookupMock(
[ 'LanguageCode' => 'sr', 'variant' => 'sr' ], true
);
$prefs = $this->getPreferencesFactory( $pm, $language, $userOptionsLookupMock )
->getFormDescriptor( $userMock, $this->context );
$this->assertArrayHasKey( 'default', $prefs['variant'] );
$this->assertEquals( 'sr', $prefs['variant']['default'] );
@ -317,8 +327,6 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
->willReturn( [ 'users' ] );
$userMock->method( 'getGroupMemberships' )
->willReturn( [ 'users' ] );
$userMock->method( 'getOptions' )
->willReturn( [] );
$pm = $this->createMock( PermissionManager::class );
$pm->method( 'userHasRight' )
@ -328,7 +336,9 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
$language->method( 'getCode' )
->willReturn( 'en' );
$prefs = $this->getPreferencesFactory( $pm, $language )
$userOptionsLookupMock = $this->createUserOptionsLookupMock( [], true );
$prefs = $this->getPreferencesFactory( $pm, $language, $userOptionsLookupMock )
->getFormDescriptor( $userMock, $this->context );
$this->assertArrayHasKey( 'default', $prefs['usergroups'] );
$this->assertEquals( 'users', $prefs['usergroups']['default'] );
@ -347,4 +357,22 @@ class DefaultPreferencesFactoryTest extends \MediaWikiIntegrationTestCase {
'SignatureValidation',
] );
}
/**
* @param array $userOptions
* @param bool $defaultOptions
* @return UserOptionsLookup
*/
private function createUserOptionsLookupMock( array $userOptions, bool $defaultOptions = false ) {
$mock = $this->createMock( UserOptionsLookup::class );
$mock->method( 'getOptions' )->willReturn( $userOptions );
$services = $this->getServiceContainer();
if ( $defaultOptions ) {
$defaults = $services->getMainConfig()->get( 'DefaultUserOptions' );
$defaults['language'] = $services->getContentLanguage()->getCode();
$defaults['skin'] = Skin::normalizeKey( $services->getMainConfig()->get( 'DefaultSkin' ) );
$mock->method( 'getDefaultOptions' )->willReturn( $defaults );
}
return $mock;
}
}

View file

@ -27,7 +27,8 @@ class ImageListPagerTest extends MediaWikiIntegrationTestCase {
$services->getRepoGroup(),
$services->getDBLoadBalancer(),
$services->getCommentStore(),
UserCache::singleton()
UserCache::singleton(),
$services->getUserNameUtils()
);
$this->expectException( MWException::class );
$this->expectExceptionMessage( "invalid_field" );

View file

@ -41,10 +41,6 @@ class SpecialPreferencesTest extends MediaWikiIntegrationTestCase {
]
) );
# Needs to return something
$user->method( 'getOptions' )
->willReturn( [] );
// isAnyAllowed used to return null from the mock,
// thus revoke it's permissions.
$this->overrideUserPermissions( $user, [] );

View file

@ -297,6 +297,7 @@ class UserTest extends MediaWikiIntegrationTestCase {
* @covers User::isIP
*/
public function testIsIP( $value, $result, $message ) {
$this->hideDeprecated( 'User::isIP' );
$this->assertSame( $result, $this->user->isIP( $value ), $message );
}