aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordaniel <dkinzler@wikimedia.org>2021-04-16 14:55:24 +0200
committerdaniel <dkinzler@wikimedia.org>2021-05-11 11:36:11 +0200
commit753b1bcaffa3b575d91b31ec20ba4fa420009813 (patch)
tree0ee7fd54706a4edc2979cac5e5a4f3c99f7c195d
parentb6fea9934146a76fea1f887ab6022d53f7d30995 (diff)
downloadmediawikicore-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.373
-rw-r--r--includes/EditPage.php2
-rw-r--r--includes/api/ApiBlockInfoTrait.php12
-rw-r--r--includes/block/AbstractBlock.php58
-rw-r--r--includes/block/Block.php150
-rw-r--r--includes/block/BlockErrorFormatter.php29
-rw-r--r--includes/block/BlockPermissionChecker.php5
-rw-r--r--includes/block/BlockUser.php6
-rw-r--r--includes/block/CompositeBlock.php8
-rw-r--r--includes/block/DatabaseBlock.php8
-rw-r--r--includes/block/DatabaseBlockStore.php20
-rw-r--r--includes/block/SystemBlock.php9
-rw-r--r--includes/block/UnblockUser.php17
-rw-r--r--includes/exception/UserBlockedError.php6
-rw-r--r--includes/page/Article.php2
-rw-r--r--includes/specials/SpecialBlock.php7
-rw-r--r--includes/specials/SpecialContributions.php3
-rw-r--r--includes/specials/SpecialDeletedContributions.php3
-rw-r--r--includes/specials/SpecialUnblock.php15
-rw-r--r--tests/phpunit/includes/block/DatabaseBlockTest.php11
-rw-r--r--tests/phpunit/unit/includes/block/BlockPermissionCheckerTest.php7
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 );