diff options
author | daniel <dkinzler@wikimedia.org> | 2021-04-16 14:55:24 +0200 |
---|---|---|
committer | daniel <dkinzler@wikimedia.org> | 2021-05-11 11:36:11 +0200 |
commit | 753b1bcaffa3b575d91b31ec20ba4fa420009813 (patch) | |
tree | 0ee7fd54706a4edc2979cac5e5a4f3c99f7c195d | |
parent | b6fea9934146a76fea1f887ab6022d53f7d30995 (diff) | |
download | mediawikicore-753b1bcaffa3b575d91b31ec20ba4fa420009813.tar.gz mediawikicore-753b1bcaffa3b575d91b31ec20ba4fa420009813.zip |
Introduce Block interface and replace AbstractBlock.
In order to allow Authority to know about user blocks,
we need a narrow interface to represent such blocks.
This deprecates some methods on AbstractBlocks in favor
of new methods on the Block interface that avoid binding to
the User class.
Bug: T271494
Change-Id: I7bb950533970984a014de0434518fbbefb695131
-rw-r--r-- | RELEASE-NOTES-1.37 | 3 | ||||
-rw-r--r-- | includes/EditPage.php | 2 | ||||
-rw-r--r-- | includes/api/ApiBlockInfoTrait.php | 12 | ||||
-rw-r--r-- | includes/block/AbstractBlock.php | 58 | ||||
-rw-r--r-- | includes/block/Block.php | 150 | ||||
-rw-r--r-- | includes/block/BlockErrorFormatter.php | 29 | ||||
-rw-r--r-- | includes/block/BlockPermissionChecker.php | 5 | ||||
-rw-r--r-- | includes/block/BlockUser.php | 6 | ||||
-rw-r--r-- | includes/block/CompositeBlock.php | 8 | ||||
-rw-r--r-- | includes/block/DatabaseBlock.php | 8 | ||||
-rw-r--r-- | includes/block/DatabaseBlockStore.php | 20 | ||||
-rw-r--r-- | includes/block/SystemBlock.php | 9 | ||||
-rw-r--r-- | includes/block/UnblockUser.php | 17 | ||||
-rw-r--r-- | includes/exception/UserBlockedError.php | 6 | ||||
-rw-r--r-- | includes/page/Article.php | 2 | ||||
-rw-r--r-- | includes/specials/SpecialBlock.php | 7 | ||||
-rw-r--r-- | includes/specials/SpecialContributions.php | 3 | ||||
-rw-r--r-- | includes/specials/SpecialDeletedContributions.php | 3 | ||||
-rw-r--r-- | includes/specials/SpecialUnblock.php | 15 | ||||
-rw-r--r-- | tests/phpunit/includes/block/DatabaseBlockTest.php | 11 | ||||
-rw-r--r-- | tests/phpunit/unit/includes/block/BlockPermissionCheckerTest.php | 7 |
21 files changed, 296 insertions, 85 deletions
diff --git a/RELEASE-NOTES-1.37 b/RELEASE-NOTES-1.37 index e6630b2e4be3..862971539644 100644 --- a/RELEASE-NOTES-1.37 +++ b/RELEASE-NOTES-1.37 @@ -199,6 +199,9 @@ because of Phabricator reports. === Deprecations in 1.37 === * JobQueue::getWiki, deprecated in 1.33, now emits deprecation warnings. +* In AbstractBlock, the getTargetAndType() and getTarget() methods are + deprecated. Instead use getTargetName() and getTargetUserIdentity() together + with getType(). * Deprecated passing UserIdentity to WatchlistManager::clearAllUserNotifications() and WatchlistManager::clearTitleUserNotifications(). Pass Authority instead. diff --git a/includes/EditPage.php b/includes/EditPage.php index e9adf4dc831e..e4a7ddb967b5 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -2746,7 +2746,7 @@ class EditPage implements IEditObject { $out, 'block', MediaWikiServices::getInstance()->getNamespaceInfo()-> - getCanonicalName( NS_USER ) . ':' . $block->getTarget(), + getCanonicalName( NS_USER ) . ':' . $block->getTargetName(), '', [ 'lim' => 1, diff --git a/includes/api/ApiBlockInfoTrait.php b/includes/api/ApiBlockInfoTrait.php index 7f9ac9f8766f..e0f8bddb9cef 100644 --- a/includes/api/ApiBlockInfoTrait.php +++ b/includes/api/ApiBlockInfoTrait.php @@ -18,7 +18,7 @@ * @file */ -use MediaWiki\Block\AbstractBlock; +use MediaWiki\Block\Block; use MediaWiki\Block\SystemBlock; /** @@ -28,7 +28,7 @@ trait ApiBlockInfoTrait { /** * Get basic info about a given block - * @param AbstractBlock $block + * @param Block $block * @param Language|null $language * @return array Array containing several keys: * - blockid - ID of the block @@ -41,17 +41,19 @@ trait ApiBlockInfoTrait { * - systemblocktype - system block type, if any */ private function getBlockDetails( - AbstractBlock $block, + Block $block, $language = null ) { if ( $language === null ) { $language = $this->getLanguage(); } + $blocker = $block->getBlocker(); + $vals = []; $vals['blockid'] = $block->getId(); - $vals['blockedby'] = $block->getByName(); - $vals['blockedbyid'] = $block->getBy(); + $vals['blockedby'] = $blocker ? $blocker->getName() : ''; + $vals['blockedbyid'] = $blocker ? $blocker->getId() : 0; $vals['blockreason'] = $block->getReasonComment() ->message->inLanguage( $language )->plain(); $vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->getTimestamp() ); diff --git a/includes/block/AbstractBlock.php b/includes/block/AbstractBlock.php index c56859b5f02c..49280ef4f168 100644 --- a/includes/block/AbstractBlock.php +++ b/includes/block/AbstractBlock.php @@ -34,7 +34,7 @@ use User; * @note Extensions should not subclass this, as MediaWiki currently does not support custom block types. * @since 1.34 Factored out from DatabaseBlock (previously Block). */ -abstract class AbstractBlock { +abstract class AbstractBlock implements Block { /** @var CommentStoreComment */ protected $reason; @@ -80,14 +80,6 @@ abstract class AbstractBlock { /** @var bool */ protected $isSitewide = true; - # TYPE constants - # Do not introduce negative constants without changing BlockUser command object. - public const TYPE_USER = 1; - public const TYPE_IP = 2; - public const TYPE_RANGE = 3; - public const TYPE_AUTO = 4; - public const TYPE_ID = 5; - /** * Create a new block with specified parameters on a user, IP or IP range. * @@ -139,15 +131,6 @@ abstract class AbstractBlock { } /** - * Get the information that identifies this block, such that a user could - * look up everything that can be found about this block. May be an ID, - * array of IDs, type, etc. - * - * @return mixed Identifying information - */ - abstract public function getIdentifier(); - - /** * Get the reason given for creating the block, as a string. * * Deprecated, since this gives the caller no control over the language @@ -350,6 +333,9 @@ abstract class AbstractBlock { * * If the type is not null, it will be an AbstractBlock::TYPE_ constant. * + * @deprecated since 1.37, use getTargetName() and getTargetUserIdentity() + * together with getType() + * * @return array [ User|String|null, int|null ] * @todo FIXME: This should be an integral part of the block member variables */ @@ -358,9 +344,11 @@ abstract class AbstractBlock { } /** - * Get the target for this particular block. Note that for autoblocks, + * Get the target for this particular block. Note that for autoblocks, * this returns the unredacted name; frontend functions need to call $block->getRedactedName() * in this situation. + * @deprecated since 1.37, use getTargetName() and getTargetUserIdentity() + * together with getType() * @return User|string|null */ public function getTarget() { @@ -368,6 +356,38 @@ abstract class AbstractBlock { } /** + * @since 1.37 + * @return ?UserIdentity + */ + public function getTargetUserIdentity(): ?UserIdentity { + return $this->target instanceof UserIdentity ? $this->target : null; + } + + /** + * @since 1.37 + * @return string + */ + public function getTargetName(): string { + return $this->target instanceof UserIdentity + ? $this->target->getName() + : (string)$this->target; + } + + /** + * @param UserIdentity|string $target + * + * @return bool + * @since 1.37 + */ + public function isBlocking( $target ): bool { + $targetName = $target instanceof UserIdentity + ? $target->getName() + : (string)$target; + + return $targetName === $this->getTargetName(); + } + + /** * Get the block expiry time * * @since 1.19 diff --git a/includes/block/Block.php b/includes/block/Block.php new file mode 100644 index 000000000000..523a23d3166a --- /dev/null +++ b/includes/block/Block.php @@ -0,0 +1,150 @@ +<?php + +/** + * 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 + */ + +namespace MediaWiki\Block; + +use CommentStoreComment; +use MediaWiki\User\UserIdentity; + +/** + * Represents a block that may prevent users from performing specific operations. + * The block may apply to a specific user, to a network address, network range, + * or some other aspect of a web request. + * The block may apply to the entire site, or may be limited to specific pages + * or namespaces. + * + * @since 1.37 Extracted from the AbstractBlock base class, + * which was in turn factored out of DatabaseBlock in 1.34. + */ +interface Block { + + # TYPE constants + # Do not introduce negative constants without changing BlockUser command object. + public const TYPE_USER = 1; + public const TYPE_IP = 2; + public const TYPE_RANGE = 3; + public const TYPE_AUTO = 4; + public const TYPE_ID = 5; + + /** + * Get the block ID + * @return ?int + */ + public function getId(); + + /** + * Get the information that identifies this block, such that a user could + * look up everything that can be found about this block. Typically a scalar ID (integer + * or string), but can also return a list of IDs, or an associative array encoding a composite + * ID. Must be safe to serialize as JSON. + * + * @return mixed Identifying information + */ + public function getIdentifier(); + + /** + * Get the user who applied this block + * + * @return UserIdentity|null user identity or null. May be an external user. + */ + public function getBlocker(): ?UserIdentity; + + /** + * Get the reason for creating the block. + * + * @return CommentStoreComment + */ + public function getReasonComment(); + + /** + * Get the UserIdentity identifying the blocked user, + * if the target is indeed a user (that is, if getType() returns TYPE_USER). + * + * @return ?UserIdentity + */ + public function getTargetUserIdentity(): ?UserIdentity; + + /** + * Return the name of the block target as a string. + * Depending on the type returned by get Type(), this could be a user name, + * an IP address or range, an internal ID, etc. + * + * @return string + */ + public function getTargetName(): string; + + /** + * Determines whether this block is blocking the given target (and only that target). + * + * @param UserIdentity|string $target + * + * @return bool + */ + public function isBlocking( $target ): bool; + + /** + * Get the block expiry time + * + * @return string + */ + public function getExpiry(); + + /** + * Get the type of target for this particular block. + * @return int|null Block::TYPE_ constant, will never be TYPE_ID + */ + public function getType(); + + /** + * Get the timestamp indicating when the block was created + * + * @return string + */ + public function getTimestamp(); + + /** + * Indicates that the block is a sitewide block. This means the user is + * prohibited from editing any page on the site (other than their own talk + * page). + * + * @return bool + */ + public function isSitewide(); + + /** + * Get the flag indicating whether this block blocks the target from + * creating an account. (Note that the flag may be overridden depending on + * global configs.) + * + * @return bool + */ + public function isCreateAccountBlocked(); + + /** + * Returns whether the block is a hardblock (affects logged-in users on a given IP/range) + * + * Note that users are always hardblocked, since they're logged in by definition. + * + * @return bool + */ + public function isHardblock(); + +} diff --git a/includes/block/BlockErrorFormatter.php b/includes/block/BlockErrorFormatter.php index 9382f1edd54b..ca224f47a9a9 100644 --- a/includes/block/BlockErrorFormatter.php +++ b/includes/block/BlockErrorFormatter.php @@ -49,14 +49,14 @@ class BlockErrorFormatter { * block features. Message parameters are formatted for the specified user and * language. * - * @param AbstractBlock $block + * @param Block $block * @param UserIdentity $user * @param Language $language * @param string $ip * @return Message */ public function getMessage( - AbstractBlock $block, + Block $block, UserIdentity $user, Language $language, $ip @@ -69,7 +69,7 @@ class BlockErrorFormatter { /** * Get a standard set of block details for building a block error message. * - * @param AbstractBlock $block + * @param Block $block * @return mixed[] * - identifier: Information for looking up the block * - targetName: The target, as a string @@ -79,12 +79,13 @@ class BlockErrorFormatter { * - expiry: Expiry time * - timestamp: Time the block was created */ - private function getBlockErrorInfo( AbstractBlock $block ) { + private function getBlockErrorInfo( Block $block ) { + $blocker = $block->getBlocker(); return [ 'identifier' => $block->getIdentifier(), - 'targetName' => (string)$block->getTarget(), - 'blockerName' => $block->getByName(), - 'blockerId' => $block->getBy(), + 'targetName' => $block->getTargetName(), + 'blockerName' => $blocker ? $blocker->getName() : '', + 'blockerId' => $blocker ? $blocker->getId() : 0, 'reason' => $block->getReasonComment(), 'expiry' => $block->getExpiry(), 'timestamp' => $block->getTimestamp(), @@ -96,13 +97,13 @@ class BlockErrorFormatter { * formatted for a specified user and language. * * @since 1.35 - * @param AbstractBlock $block + * @param Block $block * @param UserIdentity $user * @param Language $language * @return mixed[] See getBlockErrorInfo */ private function getFormattedBlockErrorInfo( - AbstractBlock $block, + Block $block, UserIdentity $user, Language $language ) { @@ -158,13 +159,13 @@ class BlockErrorFormatter { /** * Determine the block error message key by examining the block. * - * @param AbstractBlock $block + * @param Block $block * @return string Message key */ - private function getBlockErrorMessageKey( AbstractBlock $block ) { + private function getBlockErrorMessageKey( Block $block ) { $key = 'blockedtext'; if ( $block instanceof DatabaseBlock ) { - if ( $block->getType() === AbstractBlock::TYPE_AUTO ) { + if ( $block->getType() === Block::TYPE_AUTO ) { $key = 'autoblockedtext'; } elseif ( !$block->isSitewide() ) { $key = 'blockedtext-partial'; @@ -181,7 +182,7 @@ class BlockErrorFormatter { * Get the formatted parameters needed to build the block error messages handled by * getBlockErrorMessageKey. * - * @param AbstractBlock $block + * @param Block $block * @param UserIdentity $user * @param Language $language * @param string $ip @@ -196,7 +197,7 @@ class BlockErrorFormatter { * - timestamp: Time the block was created, in the specified language */ private function getBlockErrorMessageParams( - AbstractBlock $block, + Block $block, UserIdentity $user, Language $language, $ip diff --git a/includes/block/BlockPermissionChecker.php b/includes/block/BlockPermissionChecker.php index f2cb746e8d4e..9bd91540a619 100644 --- a/includes/block/BlockPermissionChecker.php +++ b/includes/block/BlockPermissionChecker.php @@ -141,7 +141,7 @@ class BlockPermissionChecker { // Blocked admin is trying to alter their own block // Self-blocked admins can always remove or alter their block - if ( $block->getByName() === $performerIdentity->getName() ) { + if ( $block->getBlocker() && $performerIdentity->equals( $block->getBlocker() ) ) { return true; } @@ -155,7 +155,8 @@ class BlockPermissionChecker { if ( $this->target instanceof UserIdentity && - $block->getByName() === $this->target->getName() + $block->getBlocker() && + $this->target->equals( $block->getBlocker() ) ) { // T150826: Blocked admins can always block the admin who blocked them return true; diff --git a/includes/block/BlockUser.php b/includes/block/BlockUser.php index 8555f8a2dfb4..04f5f90c5057 100644 --- a/includes/block/BlockUser.php +++ b/includes/block/BlockUser.php @@ -559,12 +559,12 @@ class BlockUser { if ( $priorBlock === null ) { $this->logger->warning( 'Block could not be inserted. No existing block was found.' ); - return Status::newFatal( 'ipb-block-not-found', $block->getTarget() ); + return Status::newFatal( 'ipb-block-not-found', $block->getTargetName() ); } if ( $block->equals( $priorBlock ) ) { // Block settings are equal => user is already blocked - return Status::newFatal( 'ipb_already_blocked', $block->getTarget() ); + return Status::newFatal( 'ipb_already_blocked', $block->getTargetName() ); } $currentBlock = $this->configureBlock( $priorBlock ); @@ -572,7 +572,7 @@ class BlockUser { $isReblock = true; $block = $currentBlock; } else { - return Status::newFatal( 'ipb_already_blocked', $block->getTarget() ); + return Status::newFatal( 'ipb_already_blocked', $block->getTargetName() ); } } diff --git a/includes/block/CompositeBlock.php b/includes/block/CompositeBlock.php index b333b26ac189..0f898b829640 100644 --- a/includes/block/CompositeBlock.php +++ b/includes/block/CompositeBlock.php @@ -22,6 +22,7 @@ namespace MediaWiki\Block; +use MediaWiki\User\UserIdentity; use Title; /** @@ -206,4 +207,11 @@ class CompositeBlock extends AbstractBlock { public function getByName() { return ''; } + + /** + * @inheritDoc + */ + public function getBlocker(): ?UserIdentity { + return null; + } } diff --git a/includes/block/DatabaseBlock.php b/includes/block/DatabaseBlock.php index 949c8d1528db..761aa836ecea 100644 --- a/includes/block/DatabaseBlock.php +++ b/includes/block/DatabaseBlock.php @@ -391,7 +391,7 @@ class DatabaseBlock extends AbstractBlock { if ( $block->getType() == self::TYPE_RANGE ) { # This is the number of bits that are allowed to vary in the block, give # or take some floating point errors - $target = $block->getTarget(); + $target = $block->getTargetName(); $max = IPUtils::isIPv6( $target ) ? 128 : 32; list( $network, $bits ) = IPUtils::parseCIDR( $target ); $size = $max - $bits; @@ -655,13 +655,13 @@ class DatabaseBlock extends AbstractBlock { # Make a new block object with the desired properties. $autoblock = new DatabaseBlock; - wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP ); + wfDebug( "Autoblocking {$this->getTargetName()}@" . $autoblockIP ); $autoblock->setTarget( $autoblockIP ); $autoblock->setBlocker( $this->getBlocker() ); $autoblock->setReason( wfMessage( 'autoblocker', - (string)$this->getTarget(), + $this->getTargetName(), $this->getReasonComment()->text )->inContentLanguage()->plain() ); @@ -854,7 +854,7 @@ class DatabaseBlock extends AbstractBlock { wfMessage( 'autoblockid', $this->mId )->text() ); } else { - return htmlspecialchars( $this->getTarget() ); + return htmlspecialchars( $this->getTargetName() ); } } diff --git a/includes/block/DatabaseBlockStore.php b/includes/block/DatabaseBlockStore.php index 191579ca17c9..ea5404399715 100644 --- a/includes/block/DatabaseBlockStore.php +++ b/includes/block/DatabaseBlockStore.php @@ -29,7 +29,6 @@ use MediaWiki\Config\ServiceOptions; use MediaWiki\HookContainer\HookContainer; use MediaWiki\HookContainer\HookRunner; use MediaWiki\User\ActorStoreFactory; -use MediaWiki\User\UserIdentity; use MWException; use Psr\Log\LoggerInterface; use ReadOnlyMode; @@ -342,12 +341,11 @@ class DatabaseBlockStore { ) : array { $expiry = $dbw->encodeExpiry( $block->getExpiry() ); - $target = $block->getTarget(); - $forcedTargetId = $block->getForcedTargetId(); + $forcedTargetId = $block->getForcedTargetID(); if ( $forcedTargetId ) { $userId = $forcedTargetId; - } elseif ( $target instanceof User ) { - $userId = $target->getId(); + } elseif ( $block->getTargetUserIdentity() ) { + $userId = $block->getTargetUserIdentity()->getId(); } else { $userId = 0; } @@ -360,7 +358,7 @@ class DatabaseBlockStore { ->acquireActorId( $block->getBlocker(), $dbw ); $blockArray = [ - 'ipb_address' => (string)$target, + 'ipb_address' => $block->getTargetName(), 'ipb_user' => $userId, 'ipb_by_actor' => $blockerActor, 'ipb_timestamp' => $dbw->timestamp( $block->getTimestamp() ), @@ -431,7 +429,7 @@ class DatabaseBlockStore { // If autoblock is enabled, autoblock the LAST IP(s) used if ( $block->isAutoblocking() && $block->getType() == AbstractBlock::TYPE_USER ) { $this->logger->debug( - 'Doing retroactive autoblocks for ' . $block->getTarget() + 'Doing retroactive autoblocks for ' . $block->getTargetName() ); $hookAutoBlocked = []; @@ -463,12 +461,11 @@ class DatabaseBlockStore { return []; } - list( $target, $type ) = $block->getTargetAndType(); + $type = $block->getType(); if ( $type !== AbstractBlock::TYPE_USER ) { // Autoblocks only apply to users return []; } - /** @var UserIdentity $target */ $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA ); @@ -477,7 +474,10 @@ class DatabaseBlockStore { 'LIMIT' => 1, ]; - $actor = $this->actorStoreFactory->getActorNormalization()->findActorId( $target, $dbr ); + $actor = $this->actorStoreFactory->getActorNormalization()->findActorId( + $block->getTargetUserIdentity(), + $dbr + ); if ( !$actor ) { $this->logger->debug( 'No actor found to retroactively autoblock' ); return []; diff --git a/includes/block/SystemBlock.php b/includes/block/SystemBlock.php index e99d076f09fb..318cc1ab05d9 100644 --- a/includes/block/SystemBlock.php +++ b/includes/block/SystemBlock.php @@ -22,6 +22,8 @@ namespace MediaWiki\Block; +use MediaWiki\User\UserIdentity; + /** * System blocks are temporary blocks that are created on enforcement (e.g. * from IP lists) and are not saved to the database. The target of a @@ -107,4 +109,11 @@ class SystemBlock extends AbstractBlock { public function getByName() { return ''; } + + /** + * @inheritDoc + */ + public function getBlocker(): ?UserIdentity { + return null; + } } diff --git a/includes/block/UnblockUser.php b/includes/block/UnblockUser.php index 85a69864c450..92b0e9263b7b 100644 --- a/includes/block/UnblockUser.php +++ b/includes/block/UnblockUser.php @@ -31,7 +31,6 @@ use MediaWiki\User\UserIdentity; use RevisionDeleteUser; use Status; use TitleValue; -use User; /** * Backend class for unblocking users @@ -175,7 +174,7 @@ class UnblockUser { $this->block->getType() === AbstractBlock::TYPE_RANGE && $this->targetType === AbstractBlock::TYPE_IP ) { - $status->fatal( 'ipb_blocked_as_range', $this->target, $this->block->getTarget() ); + $status->fatal( 'ipb_blocked_as_range', $this->target, $this->block->getTargetName() ); return $status; } @@ -190,17 +189,17 @@ class UnblockUser { $deleteBlockStatus = $this->blockStore->deleteBlock( $this->block ); if ( !$deleteBlockStatus ) { - $status->fatal( 'ipb_cant_unblock', $this->block->getTarget() ); + $status->fatal( 'ipb_cant_unblock', $this->block->getTargetName() ); return $status; } $this->hookRunner->onUnblockUserComplete( $this->block, $legacyUser ); // Unset _deleted fields as needed - if ( $this->block->getHideName() && $this->block->getTarget() instanceof User ) { - // Something is deeply FUBAR if this is not a User object, but who knows? - $id = $this->block->getTarget()->getId(); - RevisionDeleteUser::unsuppressUserName( $this->block->getTarget(), $id ); + $user = $this->block->getTargetUserIdentity(); + if ( $this->block->getHideName() && $user ) { + $id = $user->getId(); + RevisionDeleteUser::unsuppressUserName( $user->getName(), $id ); } $this->log(); @@ -217,9 +216,7 @@ class UnblockUser { if ( $this->block->getType() === DatabaseBlock::TYPE_AUTO ) { $page = TitleValue::tryNew( NS_USER, '#' . $this->block->getId() ); } else { - $page = $this->block->getTarget() instanceof UserIdentity - ? $this->block->getTarget()->getUserPage() - : TitleValue::tryNew( NS_USER, $this->block->getTarget() ); + $page = TitleValue::tryNew( NS_USER, $this->block->getTargetName() ); } $logEntry = new ManualLogEntry( 'block', 'unblock' ); diff --git a/includes/exception/UserBlockedError.php b/includes/exception/UserBlockedError.php index 48c34791f1d8..a2d429a9fb59 100644 --- a/includes/exception/UserBlockedError.php +++ b/includes/exception/UserBlockedError.php @@ -18,7 +18,7 @@ * @file */ -use MediaWiki\Block\AbstractBlock; +use MediaWiki\Block\Block; use MediaWiki\MediaWikiServices; use MediaWiki\User\UserIdentity; @@ -32,13 +32,13 @@ use MediaWiki\User\UserIdentity; class UserBlockedError extends ErrorPageError { /** * @stable to call - * @param AbstractBlock $block + * @param Block $block * @param UserIdentity|null $user * @param Language|null $language * @param string|null $ip */ public function __construct( - AbstractBlock $block, + Block $block, UserIdentity $user = null, Language $language = null, $ip = null diff --git a/includes/page/Article.php b/includes/page/Article.php index 81052b26b2da..2fa523ead84e 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -1382,7 +1382,7 @@ class Article implements Page { $outputPage, 'block', $services->getNamespaceInfo()->getCanonicalName( NS_USER ) . ':' . - $block->getTarget(), + $block->getTargetName(), '', [ 'lim' => 1, diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php index bda4016d18df..e3d21f503233 100644 --- a/includes/specials/SpecialBlock.php +++ b/includes/specials/SpecialBlock.php @@ -432,11 +432,14 @@ class SpecialBlock extends FormSpecialPage { $block = DatabaseBlock::newFromTarget( $this->target ); + // UserIdentity object if possible, string otherwise. Like $this->target + $blockTarget = $block ? ( $block->getTargetUserIdentity() ?: $block->getTargetName() ) : null; + // Populate fields if there is a block that is not an autoblock; if it is a range // block, only populate the fields if the range is the same as $this->target if ( $block instanceof DatabaseBlock && $block->getType() !== DatabaseBlock::TYPE_AUTO && ( $this->type != DatabaseBlock::TYPE_RANGE - || $block->getTarget() == $this->target ) + || ( $this->target && $block->isBlocking( $this->target ) ) ) ) { $fields['HardBlock']['default'] = $block->isHardblock(); $fields['CreateAccount']['default'] = $block->isCreateAccountBlocked(); @@ -519,7 +522,7 @@ class SpecialBlock extends FormSpecialPage { } $this->alreadyBlocked = true; - $this->preErrors[] = [ 'ipb-needreblock', wfEscapeWikiText( (string)$block->getTarget() ) ]; + $this->preErrors[] = [ 'ipb-needreblock', wfEscapeWikiText( $block->getTargetName() ) ]; } if ( $this->alreadyBlocked || $this->getRequest()->wasPosted() diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php index fe86983af611..f4ad5738de91 100644 --- a/includes/specials/SpecialContributions.php +++ b/includes/specials/SpecialContributions.php @@ -449,7 +449,8 @@ class SpecialContributions extends IncludableSpecialPage { if ( $block !== null && $block->getType() != DatabaseBlock::TYPE_AUTO ) { if ( $block->getType() == DatabaseBlock::TYPE_RANGE ) { - $nt = $this->namespaceInfo->getCanonicalName( NS_USER ) . ':' . $block->getTarget(); + $nt = $this->namespaceInfo->getCanonicalName( NS_USER ) + . ':' . $block->getTargetName(); } $out = $this->getOutput(); // showLogExtract() wants first parameter by reference diff --git a/includes/specials/SpecialDeletedContributions.php b/includes/specials/SpecialDeletedContributions.php index 1daae03d5a79..c33d455a4e1d 100644 --- a/includes/specials/SpecialDeletedContributions.php +++ b/includes/specials/SpecialDeletedContributions.php @@ -229,7 +229,8 @@ class SpecialDeletedContributions extends SpecialPage { $block = DatabaseBlock::newFromTarget( $userObj, $userObj ); if ( $block !== null && $block->getType() != DatabaseBlock::TYPE_AUTO ) { if ( $block->getType() == DatabaseBlock::TYPE_RANGE ) { - $nt = $this->namespaceInfo->getCanonicalName( NS_USER ) . ':' . $block->getTarget(); + $nt = $this->namespaceInfo->getCanonicalName( NS_USER ) + . ':' . $block->getTargetName(); } // LogEventsList::showLogExtract() wants the first parameter by ref diff --git a/includes/specials/SpecialUnblock.php b/includes/specials/SpecialUnblock.php index 2e8f6eaff8a5..e0fc7832a52c 100644 --- a/includes/specials/SpecialUnblock.php +++ b/includes/specials/SpecialUnblock.php @@ -175,7 +175,8 @@ class SpecialUnblock extends SpecialPage { ]; if ( $this->block instanceof DatabaseBlock ) { - list( $target, $type ) = $this->block->getTargetAndType(); + $type = $this->block->getType(); + $targetName = $this->block->getTargetName(); # Autoblocks are logged as "autoblock #123 because the IP was recently used by # User:Foo, and we've just got any block, auto or not, that applies to a target @@ -185,26 +186,26 @@ class SpecialUnblock extends SpecialPage { $fields['Target']['default'] = $this->target; unset( $fields['Name'] ); } else { - $fields['Target']['default'] = $target; + $fields['Target']['default'] = $targetName; $fields['Target']['type'] = 'hidden'; switch ( $type ) { case DatabaseBlock::TYPE_IP: $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink( - $this->getSpecialPageFactory()->getTitleForAlias( 'Contributions/' . $target->getName() ), - $target->getName() + $this->getSpecialPageFactory()->getTitleForAlias( 'Contributions/' . $targetName ), + $targetName ); $fields['Name']['raw'] = true; break; case DatabaseBlock::TYPE_USER: $fields['Name']['default'] = $this->getLinkRenderer()->makeLink( - $target->getUserPage(), - $target->getName() + new TitleValue( NS_USER, $targetName ), + $targetName ); $fields['Name']['raw'] = true; break; case DatabaseBlock::TYPE_RANGE: - $fields['Name']['default'] = $target; + $fields['Name']['default'] = $targetName; break; case DatabaseBlock::TYPE_AUTO: diff --git a/tests/phpunit/includes/block/DatabaseBlockTest.php b/tests/phpunit/includes/block/DatabaseBlockTest.php index 5dbb156e9421..335780efd34b 100644 --- a/tests/phpunit/includes/block/DatabaseBlockTest.php +++ b/tests/phpunit/includes/block/DatabaseBlockTest.php @@ -318,7 +318,15 @@ class DatabaseBlockTest extends MediaWikiLangTestCase { $block->getTarget()->getName(), 'Correct blockee name' ); + $this->assertEquals( + 'UserOnForeignWiki', + $block->getTargetUserIdentity()->getName(), + 'Correct blockee name' + ); $this->assertEquals( $userId, $block->getTarget()->getId(), 'Correct blockee id' ); + $this->assertEquals( $userId, $block->getTargetUserIdentity()->getId(), 'Correct blockee id' ); + $this->assertEquals( 'UserOnForeignWiki', $block->getTargetName(), 'Correct blockee name' ); + $this->assertTrue( $block->isBlocking( 'UserOnForeignWiki' ), 'Is blocking blockee' ); $this->assertEquals( 'Meta>MetaWikiUser', $block->getBlocker()->getName(), 'Correct blocker name' ); $this->assertEquals( 'Meta>MetaWikiUser', $block->getByName(), 'Correct blocker name' ); @@ -485,6 +493,9 @@ class DatabaseBlockTest extends MediaWikiLangTestCase { $this->assertInstanceOf( DatabaseBlock::class, $block ); $this->assertEquals( $block->getBy(), $sysop->getId() ); $this->assertEquals( $block->getTarget()->getName(), $badActor->getName() ); + $this->assertEquals( $block->getTargetName(), $badActor->getName() ); + $this->assertTrue( $block->isBlocking( $badActor ), 'Is blocking expected user' ); + $this->assertEquals( $block->getTargetUserIdentity()->getId(), $badActor->getId() ); $blockStore->deleteBlock( $block ); } diff --git a/tests/phpunit/unit/includes/block/BlockPermissionCheckerTest.php b/tests/phpunit/unit/includes/block/BlockPermissionCheckerTest.php index 8a0f15459a4e..a5ec1b4901e7 100644 --- a/tests/phpunit/unit/includes/block/BlockPermissionCheckerTest.php +++ b/tests/phpunit/unit/includes/block/BlockPermissionCheckerTest.php @@ -74,10 +74,10 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase { // Mock DatabaseBlock instead of AbstractBlock because its easier $block = $this->createNoOpMock( DatabaseBlock::class, - [ 'isSitewide', 'getByName' ] + [ 'isSitewide', 'getBlocker' ] ); $block->method( 'isSitewide' )->willReturn( $isSitewide ); - $block->method( 'getByName' )->willReturn( $byName ); + $block->method( 'getBlocker' )->willReturn( new UserIdentityValue( 7, $byName ) ); return $block; } @@ -181,6 +181,9 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase { $user->method( 'getBlock' )->willReturn( $block ); $user->method( 'getId' )->willReturn( 1 ); $user->method( 'getName' )->willReturn( 'blocker' ); + $user->method( 'equals' )->willReturnCallback( static function ( $user ) { + return $user->getName() === 'blocker'; + } ); $target = new UserIdentityValue( $targetUserId, $targetUserName ); |