diff --git a/RELEASE-NOTES-1.37 b/RELEASE-NOTES-1.37 index 988781a83a7..3cda0433e01 100644 --- a/RELEASE-NOTES-1.37 +++ b/RELEASE-NOTES-1.37 @@ -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 === diff --git a/includes/EditPage.php b/includes/EditPage.php index 42ecacf3ebb..b79ecb38990 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -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() ); diff --git a/includes/ParamValidator/TypeDef/UserDef.php b/includes/ParamValidator/TypeDef/UserDef.php index 2d2b0930a06..493c4fbad13 100644 --- a/includes/ParamValidator/TypeDef/UserDef.php +++ b/includes/ParamValidator/TypeDef/UserDef.php @@ -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. diff --git a/includes/Storage/DerivedPageDataUpdater.php b/includes/Storage/DerivedPageDataUpdater.php index c1c9a4f0d6c..60e78836b1c 100644 --- a/includes/Storage/DerivedPageDataUpdater.php +++ b/includes/Storage/DerivedPageDataUpdater.php @@ -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() ) { diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index d77259e270c..4b7cf27dd96 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -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, diff --git a/includes/api/ApiOptions.php b/includes/api/ApiOptions.php index 900945159a5..ae55bad578c 100644 --- a/includes/api/ApiOptions.php +++ b/includes/api/ApiOptions.php @@ -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': diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php index dad4cc6b66d..cd4e3fe4029 100644 --- a/includes/api/ApiQuery.php +++ b/includes/api/ApiQuery.php @@ -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, diff --git a/includes/api/ApiQueryBlocks.php b/includes/api/ApiQueryBlocks.php index e5607916041..e4dc8140757 100644 --- a/includes/api/ApiQueryBlocks.php +++ b/includes/api/ApiQueryBlocks.php @@ -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 ) { diff --git a/includes/api/ApiQueryUserContribs.php b/includes/api/ApiQueryUserContribs.php index 07a3ae624d0..faff0f8ae8d 100644 --- a/includes/api/ApiQueryUserContribs.php +++ b/includes/api/ApiQueryUserContribs.php @@ -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' ); diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php index 476d7f04634..5da4e49e840 100644 --- a/includes/api/ApiQueryUserInfo.php +++ b/includes/api/ApiQueryUserInfo.php @@ -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'] ); } diff --git a/includes/page/Article.php b/includes/page/Article.php index ebb68c7e622..09c460a766a 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -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() && diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index ed0f8b8d4b5..29e3c46ebe7 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -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' ) ); diff --git a/includes/preferences/DefaultPreferencesFactory.php b/includes/preferences/DefaultPreferencesFactory.php index 33791d34fbe..2f26192b55a 100644 --- a/includes/preferences/DefaultPreferencesFactory.php +++ b/includes/preferences/DefaultPreferencesFactory.php @@ -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] ); diff --git a/includes/resourceloader/ResourceLoaderUserOptionsModule.php b/includes/resourceloader/ResourceLoaderUserOptionsModule.php index 55a837caa1f..06496702324 100644 --- a/includes/resourceloader/ResourceLoaderUserOptionsModule.php +++ b/includes/resourceloader/ResourceLoaderUserOptionsModule.php @@ -1,4 +1,8 @@ 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 ) . ');'; diff --git a/includes/search/SearchNearMatcher.php b/includes/search/SearchNearMatcher.php index 4e60d052f48..146841ec4fe 100644 --- a/includes/search/SearchNearMatcher.php +++ b/includes/search/SearchNearMatcher.php @@ -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() ); } } diff --git a/includes/skins/Skin.php b/includes/skins/Skin.php index 54bcf0a6f61..b4b6071499b 100644 --- a/includes/skins/Skin.php +++ b/includes/skins/Skin.php @@ -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 ); diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php index d06c62f6ba9..fe86983af61 100644 --- a/includes/specials/SpecialContributions.php +++ b/includes/specials/SpecialContributions.php @@ -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( "