Authority: expose user block info
Expose info about user blocks from Authority. This allows calling code to provide more detailed information to the user about why they are denied some action on the wiki. Bug: T271494 Change-Id: Ia84e469888866d72752aad355292666c31e12bad
This commit is contained in:
parent
7afc309346
commit
b3b70624c9
24 changed files with 435 additions and 125 deletions
|
|
@ -345,6 +345,12 @@ because of Phabricator reports.
|
||||||
the method it wraps, User->isRegistered(), instead.
|
the method it wraps, User->isRegistered(), instead.
|
||||||
* FileBackendGroup::singleton() and ::destroySingletons(), deprecated since
|
* FileBackendGroup::singleton() and ::destroySingletons(), deprecated since
|
||||||
1.35, now emit deprecation warnings.
|
1.35, now emit deprecation warnings.
|
||||||
|
* The first parameter of User::getBlock should now be an integer using the
|
||||||
|
Authority::FOR_XXX constants. Providing a boolean is deprecated.
|
||||||
|
* ApiBase::addBlockInfoToStatus() is deprecated for use by extensions. It is now
|
||||||
|
marked as @internal and may be deleted in the future.
|
||||||
|
It should not be necessary to call this method, Authority should be providing
|
||||||
|
all relevant information via a PermissionStatus object.
|
||||||
* JobQueueGroup::singleton was deprecated - use
|
* JobQueueGroup::singleton was deprecated - use
|
||||||
MediaWikiServices::getJobQueueGroup instead.
|
MediaWikiServices::getJobQueueGroup instead.
|
||||||
* JobQueueGroup::destroySingletons was deprecated. JobQueueGroups are now
|
* JobQueueGroup::destroySingletons was deprecated. JobQueueGroups are now
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
namespace MediaWiki\Permissions;
|
namespace MediaWiki\Permissions;
|
||||||
|
|
||||||
|
use IDBAccessObject;
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Page\PageIdentity;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
|
|
||||||
|
|
@ -34,6 +36,18 @@ use MediaWiki\User\UserIdentity;
|
||||||
*/
|
*/
|
||||||
interface Authority {
|
interface Authority {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int Fetch information quickly, slightly stale data is acceptable.
|
||||||
|
* @see IDBAccessObject::READ_NORMAL
|
||||||
|
*/
|
||||||
|
public const READ_NORMAL = IDBAccessObject::READ_NORMAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int Fetch information reliably, stale data is not acceptable.
|
||||||
|
* @see IDBAccessObject::READ_LATEST
|
||||||
|
*/
|
||||||
|
public const READ_LATEST = IDBAccessObject::READ_LATEST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the performer of the actions associated with this authority.
|
* Returns the performer of the actions associated with this authority.
|
||||||
*
|
*
|
||||||
|
|
@ -44,6 +58,17 @@ interface Authority {
|
||||||
*/
|
*/
|
||||||
public function getUser(): UserIdentity;
|
public function getUser(): UserIdentity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any user block affecting the Authority.
|
||||||
|
*
|
||||||
|
* @param int $freshness Indicates whether slightly stale data is acceptable in,
|
||||||
|
* exchange for a fast response.
|
||||||
|
*
|
||||||
|
* @return ?Block
|
||||||
|
* @since 1.37
|
||||||
|
*/
|
||||||
|
public function getBlock( int $freshness = self::READ_NORMAL ): ?Block;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether this authority has the given permission in general.
|
* Checks whether this authority has the given permission in general.
|
||||||
* For some permissions, exceptions may exist, both positive and negative, on a per-target basis.
|
* For some permissions, exceptions may exist, both positive and negative, on a per-target basis.
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use MediaWiki\Config\ServiceOptions;
|
||||||
use MediaWiki\HookContainer\HookContainer;
|
use MediaWiki\HookContainer\HookContainer;
|
||||||
use MediaWiki\HookContainer\HookRunner;
|
use MediaWiki\HookContainer\HookRunner;
|
||||||
use MediaWiki\Linker\LinkTarget;
|
use MediaWiki\Linker\LinkTarget;
|
||||||
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\Revision\RevisionLookup;
|
use MediaWiki\Revision\RevisionLookup;
|
||||||
use MediaWiki\Revision\RevisionRecord;
|
use MediaWiki\Revision\RevisionRecord;
|
||||||
use MediaWiki\Session\SessionManager;
|
use MediaWiki\Session\SessionManager;
|
||||||
|
|
@ -329,19 +330,22 @@ class PermissionManager {
|
||||||
* have a block, this will return false.
|
* have a block, this will return false.
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @param LinkTarget $page Title to check
|
* @param PageIdentity|LinkTarget $page Title to check
|
||||||
* @param bool $fromReplica Whether to check the replica DB instead of the master
|
* @param bool $fromReplica Whether to check the replica DB instead of the master
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isBlockedFrom( User $user, LinkTarget $page, $fromReplica = false ) {
|
public function isBlockedFrom( User $user, $page, $fromReplica = false ) {
|
||||||
$block = $user->getBlock( $fromReplica );
|
$block = $user->getBlock( $fromReplica );
|
||||||
if ( !$block ) {
|
if ( !$block ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove upon further migration to LinkTarget
|
if ( $page instanceof PageIdentity ) {
|
||||||
$title = Title::newFromLinkTarget( $page );
|
$title = Title::castFromPageIdentity( $page );
|
||||||
|
} else {
|
||||||
|
$title = Title::castFromLinkTarget( $page );
|
||||||
|
}
|
||||||
|
|
||||||
$blocked = $user->isHidden();
|
$blocked = $user->isHidden();
|
||||||
if ( !$blocked ) {
|
if ( !$blocked ) {
|
||||||
|
|
@ -721,8 +725,21 @@ class PermissionManager {
|
||||||
$errors[] = [ 'confirmedittext' ];
|
$errors[] = [ 'confirmedittext' ];
|
||||||
}
|
}
|
||||||
|
|
||||||
$useReplica = ( $rigor !== self::RIGOR_SECURE );
|
switch ( $rigor ) {
|
||||||
$block = $user->getBlock( $useReplica );
|
case self::RIGOR_SECURE:
|
||||||
|
$blockInfoFreshness = Authority::READ_LATEST;
|
||||||
|
$useReplica = false;
|
||||||
|
break;
|
||||||
|
case self::RIGOR_FULL:
|
||||||
|
$blockInfoFreshness = Authority::READ_NORMAL;
|
||||||
|
$useReplica = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$useReplica = true;
|
||||||
|
$blockInfoFreshness = Authority::READ_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$block = $user->getBlock( $blockInfoFreshness );
|
||||||
|
|
||||||
if ( $action === 'createaccount' ) {
|
if ( $action === 'createaccount' ) {
|
||||||
$applicableBlock = null;
|
$applicableBlock = null;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
namespace MediaWiki\Permissions;
|
namespace MediaWiki\Permissions;
|
||||||
|
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use StatusValue;
|
use StatusValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -33,6 +34,33 @@ use StatusValue;
|
||||||
*/
|
*/
|
||||||
class PermissionStatus extends StatusValue {
|
class PermissionStatus extends StatusValue {
|
||||||
|
|
||||||
|
/** @var ?Block */
|
||||||
|
private $block = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the user block that contributed to permissions being denied,
|
||||||
|
* if such a block was provided via setBlock().
|
||||||
|
*
|
||||||
|
* This is intended to be used to provide additional information to the user that
|
||||||
|
* allows them to determine the reason for them being denied an action.
|
||||||
|
*
|
||||||
|
* @since 1.37
|
||||||
|
*
|
||||||
|
* @return ?Block
|
||||||
|
*/
|
||||||
|
public function getBlock(): ?Block {
|
||||||
|
return $this->block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 1.37
|
||||||
|
* @internal
|
||||||
|
* @param Block $block
|
||||||
|
*/
|
||||||
|
public function setBlock( Block $block ): void {
|
||||||
|
$this->block = $block;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return static
|
* @return static
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
namespace MediaWiki\Permissions;
|
namespace MediaWiki\Permissions;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Page\PageIdentity;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
|
|
||||||
|
|
@ -60,6 +61,16 @@ class SimpleAuthority implements Authority {
|
||||||
return $this->actor;
|
return $this->actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $freshness
|
||||||
|
*
|
||||||
|
* @return ?Block always null
|
||||||
|
* @since 1.37
|
||||||
|
*/
|
||||||
|
public function getBlock( int $freshness = self::READ_NORMAL ): ?Block {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*
|
*
|
||||||
|
|
@ -191,4 +202,5 @@ class SimpleAuthority implements Authority {
|
||||||
): bool {
|
): bool {
|
||||||
return $this->checkPermission( $action, $status );
|
return $this->checkPermission( $action, $status );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
namespace MediaWiki\Permissions;
|
namespace MediaWiki\Permissions;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Page\PageIdentity;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
|
|
||||||
|
|
@ -53,6 +54,16 @@ class UltimateAuthority implements Authority {
|
||||||
return $this->actor;
|
return $this->actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $freshness
|
||||||
|
*
|
||||||
|
* @return ?Block always null
|
||||||
|
* @since 1.37
|
||||||
|
*/
|
||||||
|
public function getBlock( int $freshness = self::READ_NORMAL ): ?Block {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
namespace MediaWiki\Permissions;
|
namespace MediaWiki\Permissions;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Linker\LinkTarget;
|
use MediaWiki\Linker\LinkTarget;
|
||||||
use MediaWiki\Page\PageIdentity;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
|
|
@ -49,10 +50,17 @@ class UserAuthority implements Authority {
|
||||||
private $permissionManager;
|
private $permissionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var UserIdentity
|
* @var User
|
||||||
*/
|
*/
|
||||||
private $actor;
|
private $actor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local cache for user block information. False is used to indicate that there is no block,
|
||||||
|
* while null indicates that we don't know and have to check.
|
||||||
|
* @var Block|false|null
|
||||||
|
*/
|
||||||
|
private $userBlock = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @param PermissionManager $permissionManager
|
* @param PermissionManager $permissionManager
|
||||||
|
|
@ -254,8 +262,22 @@ class UserAuthority implements Authority {
|
||||||
$rigor
|
$rigor
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$blockError = false;
|
||||||
foreach ( $errors as $err ) {
|
foreach ( $errors as $err ) {
|
||||||
$status->fatal( ...$err );
|
$status->fatal( ...$err );
|
||||||
|
|
||||||
|
// HACK: Detect whether the permission was denied because the user is blocked.
|
||||||
|
// A similar hack exists in ApiBase::$blockMsgMap.
|
||||||
|
// When permission checking logic is moved out of PermissionManager,
|
||||||
|
// we can record the block info directly when first checking the block,
|
||||||
|
// rather than doing that here.
|
||||||
|
if ( strpos( $err[0], 'blockedtext' ) !== false ) {
|
||||||
|
$block = $this->getBlock();
|
||||||
|
|
||||||
|
if ( $block ) {
|
||||||
|
$status->setBlock( $block );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $status->isOK();
|
return $status->isOK();
|
||||||
|
|
@ -270,4 +292,26 @@ class UserAuthority implements Authority {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any user block affecting the Authority.
|
||||||
|
*
|
||||||
|
* @param int $freshness
|
||||||
|
*
|
||||||
|
* @return ?Block
|
||||||
|
* @since 1.37
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getBlock( int $freshness = self::READ_NORMAL ): ?Block {
|
||||||
|
// Cache block info, so we don't have to fetch it again unnecessarily.
|
||||||
|
if ( $this->userBlock === null || $freshness === self::READ_LATEST ) {
|
||||||
|
$this->userBlock = $this->actor->getBlock( $freshness );
|
||||||
|
|
||||||
|
// if we got null back, remember this as "false"
|
||||||
|
$this->userBlock = $this->userBlock ?: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we remembered "false", return null
|
||||||
|
return $this->userBlock ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,8 +245,7 @@ return [
|
||||||
BlockPermissionCheckerFactory::CONSTRUCTOR_OPTIONS,
|
BlockPermissionCheckerFactory::CONSTRUCTOR_OPTIONS,
|
||||||
$services->getMainConfig()
|
$services->getMainConfig()
|
||||||
),
|
),
|
||||||
$services->getBlockUtils(),
|
$services->getBlockUtils()
|
||||||
$services->getUserFactory()
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@
|
||||||
|
|
||||||
use MediaWiki\Api\ApiHookRunner;
|
use MediaWiki\Api\ApiHookRunner;
|
||||||
use MediaWiki\Api\Validator\SubmoduleDef;
|
use MediaWiki\Api\Validator\SubmoduleDef;
|
||||||
use MediaWiki\Block\AbstractBlock;
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Block\DatabaseBlock;
|
|
||||||
use MediaWiki\HookContainer\HookContainer;
|
use MediaWiki\HookContainer\HookContainer;
|
||||||
use MediaWiki\Linker\LinkTarget;
|
use MediaWiki\Linker\LinkTarget;
|
||||||
use MediaWiki\MediaWikiServices;
|
use MediaWiki\MediaWikiServices;
|
||||||
use MediaWiki\Page\PageIdentity;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\ParamValidator\TypeDef\NamespaceDef;
|
use MediaWiki\ParamValidator\TypeDef\NamespaceDef;
|
||||||
|
use MediaWiki\Permissions\Authority;
|
||||||
use MediaWiki\Permissions\GroupPermissionsLookup;
|
use MediaWiki\Permissions\GroupPermissionsLookup;
|
||||||
use MediaWiki\Permissions\PermissionManager;
|
use MediaWiki\Permissions\PermissionManager;
|
||||||
use MediaWiki\Permissions\PermissionStatus;
|
use MediaWiki\Permissions\PermissionStatus;
|
||||||
|
|
@ -1216,19 +1216,25 @@ abstract class ApiBase extends ContextSource {
|
||||||
/**
|
/**
|
||||||
* Add block info to block messages in a Status
|
* Add block info to block messages in a Status
|
||||||
* @since 1.33
|
* @since 1.33
|
||||||
|
* @internal since 1.37, should become protected in the future.
|
||||||
* @param StatusValue $status
|
* @param StatusValue $status
|
||||||
* @param User|null $user
|
* @param Authority|null $user
|
||||||
*/
|
*/
|
||||||
public function addBlockInfoToStatus( StatusValue $status, User $user = null ) {
|
public function addBlockInfoToStatus( StatusValue $status, Authority $user = null ) {
|
||||||
if ( $user === null ) {
|
if ( $status instanceof PermissionStatus ) {
|
||||||
$user = $this->getUser();
|
$block = $status->getBlock();
|
||||||
|
} else {
|
||||||
|
$user = $user ?: $this->getAuthority();
|
||||||
|
$block = $user->getBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
|
if ( $block ) {
|
||||||
if ( $status->hasMessage( $msg ) && $user->getBlock() ) {
|
foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
|
||||||
$status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
|
if ( $status->hasMessage( $msg ) ) {
|
||||||
[ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
|
$status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
|
||||||
) );
|
[ 'blockinfo' => $this->getBlockDetails( $block ) ]
|
||||||
|
) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1403,12 +1409,12 @@ abstract class ApiBase extends ContextSource {
|
||||||
* error handler and die with an error message including block info.
|
* error handler and die with an error message including block info.
|
||||||
*
|
*
|
||||||
* @since 1.27
|
* @since 1.27
|
||||||
* @param AbstractBlock $block The block used to generate the ApiUsageException
|
* @param Block $block The block used to generate the ApiUsageException
|
||||||
* @throws ApiUsageException always
|
* @throws ApiUsageException always
|
||||||
*/
|
*/
|
||||||
public function dieBlocked( AbstractBlock $block ) {
|
public function dieBlocked( Block $block ) {
|
||||||
// Die using the appropriate message depending on block type
|
// Die using the appropriate message depending on block type
|
||||||
if ( $block->getType() == DatabaseBlock::TYPE_AUTO ) {
|
if ( $block->getType() == Block::TYPE_AUTO ) {
|
||||||
$this->dieWithError(
|
$this->dieWithError(
|
||||||
'apierror-autoblocked',
|
'apierror-autoblocked',
|
||||||
'autoblocked',
|
'autoblocked',
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
* @file
|
* @file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use MediaWiki\Permissions\Authority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup API
|
* @ingroup API
|
||||||
*/
|
*/
|
||||||
|
|
@ -40,9 +42,9 @@ class ApiUndelete extends ApiBase {
|
||||||
$params = $this->extractRequestParams();
|
$params = $this->extractRequestParams();
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$block = $user->getBlock();
|
$block = $user->getBlock( Authority::READ_LATEST );
|
||||||
if ( $block && $block->isSitewide() ) {
|
if ( $block && $block->isSitewide() ) {
|
||||||
$this->dieBlocked( $user->getBlock() );
|
$this->dieBlocked( $block );
|
||||||
}
|
}
|
||||||
|
|
||||||
$titleObj = Title::newFromText( $params['title'] );
|
$titleObj = Title::newFromText( $params['title'] );
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use MediaWiki\ParamValidator\TypeDef\UserDef;
|
use MediaWiki\ParamValidator\TypeDef\UserDef;
|
||||||
|
use MediaWiki\Permissions\Authority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup API
|
* @ingroup API
|
||||||
|
|
@ -54,7 +55,7 @@ class ApiUserrights extends ApiBase {
|
||||||
// Deny if the user is blocked and doesn't have the full 'userrights' permission.
|
// Deny if the user is blocked and doesn't have the full 'userrights' permission.
|
||||||
// This matches what Special:UserRights does for the web UI.
|
// This matches what Special:UserRights does for the web UI.
|
||||||
if ( !$this->getAuthority()->isAllowed( 'userrights' ) ) {
|
if ( !$this->getAuthority()->isAllowed( 'userrights' ) ) {
|
||||||
$block = $pUser->getBlock();
|
$block = $pUser->getBlock( Authority::READ_LATEST );
|
||||||
if ( $block && $block->isSitewide() ) {
|
if ( $block && $block->isSitewide() ) {
|
||||||
$this->dieBlocked( $block );
|
$this->dieBlocked( $block );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ namespace MediaWiki\Block;
|
||||||
|
|
||||||
use MediaWiki\Config\ServiceOptions;
|
use MediaWiki\Config\ServiceOptions;
|
||||||
use MediaWiki\Permissions\Authority;
|
use MediaWiki\Permissions\Authority;
|
||||||
use MediaWiki\User\UserFactory;
|
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,26 +61,20 @@ class BlockPermissionChecker {
|
||||||
/** @var ServiceOptions */
|
/** @var ServiceOptions */
|
||||||
private $options;
|
private $options;
|
||||||
|
|
||||||
/** @var UserFactory */
|
|
||||||
private $userFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServiceOptions $options
|
* @param ServiceOptions $options
|
||||||
* @param BlockUtils $blockUtils
|
* @param BlockUtils $blockUtils
|
||||||
* @param UserFactory $userFactory
|
|
||||||
* @param UserIdentity|string|null $target
|
* @param UserIdentity|string|null $target
|
||||||
* @param Authority $performer
|
* @param Authority $performer
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ServiceOptions $options,
|
ServiceOptions $options,
|
||||||
BlockUtils $blockUtils,
|
BlockUtils $blockUtils,
|
||||||
UserFactory $userFactory,
|
|
||||||
$target,
|
$target,
|
||||||
Authority $performer
|
Authority $performer
|
||||||
) {
|
) {
|
||||||
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||||
$this->options = $options;
|
$this->options = $options;
|
||||||
$this->userFactory = $userFactory;
|
|
||||||
list( $this->target, $this->targetType ) = $blockUtils->parseBlockTarget( $target );
|
list( $this->target, $this->targetType ) = $blockUtils->parseBlockTarget( $target );
|
||||||
$this->performer = $performer;
|
$this->performer = $performer;
|
||||||
}
|
}
|
||||||
|
|
@ -120,10 +113,7 @@ class BlockPermissionChecker {
|
||||||
* @return bool|string True when checks passed, message code for failures
|
* @return bool|string True when checks passed, message code for failures
|
||||||
*/
|
*/
|
||||||
public function checkBlockPermissions() {
|
public function checkBlockPermissions() {
|
||||||
$performerIdentity = $this->performer->getUser();
|
$block = $this->performer->getBlock(); // TODO: pass disposition parameter
|
||||||
$legacyUser = $this->userFactory->newFromUserIdentity( $performerIdentity );
|
|
||||||
|
|
||||||
$block = $legacyUser->getBlock();
|
|
||||||
if ( !$block ) {
|
if ( !$block ) {
|
||||||
// User is not blocked, process as normal
|
// User is not blocked, process as normal
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -134,6 +124,8 @@ class BlockPermissionChecker {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$performerIdentity = $this->performer->getUser();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$this->target instanceof UserIdentity &&
|
$this->target instanceof UserIdentity &&
|
||||||
$this->target->getId() === $performerIdentity->getId()
|
$this->target->getId() === $performerIdentity->getId()
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ namespace MediaWiki\Block;
|
||||||
|
|
||||||
use MediaWiki\Config\ServiceOptions;
|
use MediaWiki\Config\ServiceOptions;
|
||||||
use MediaWiki\Permissions\Authority;
|
use MediaWiki\Permissions\Authority;
|
||||||
use MediaWiki\User\UserFactory;
|
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,23 +43,17 @@ class BlockPermissionCheckerFactory {
|
||||||
/** @var BlockUtils */
|
/** @var BlockUtils */
|
||||||
private $blockUtils;
|
private $blockUtils;
|
||||||
|
|
||||||
/** @var UserFactory */
|
|
||||||
private $userFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServiceOptions $options
|
* @param ServiceOptions $options
|
||||||
* @param BlockUtils $blockUtils
|
* @param BlockUtils $blockUtils
|
||||||
* @param UserFactory $userFactory
|
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ServiceOptions $options,
|
ServiceOptions $options,
|
||||||
BlockUtils $blockUtils,
|
BlockUtils $blockUtils
|
||||||
UserFactory $userFactory
|
|
||||||
) {
|
) {
|
||||||
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||||
$this->options = $options;
|
$this->options = $options;
|
||||||
$this->blockUtils = $blockUtils;
|
$this->blockUtils = $blockUtils;
|
||||||
$this->userFactory = $userFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,7 +69,6 @@ class BlockPermissionCheckerFactory {
|
||||||
return new BlockPermissionChecker(
|
return new BlockPermissionChecker(
|
||||||
$this->options,
|
$this->options,
|
||||||
$this->blockUtils,
|
$this->blockUtils,
|
||||||
$this->userFactory,
|
|
||||||
$target,
|
$target,
|
||||||
$performer
|
$performer
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -517,10 +517,12 @@ class DatabaseBlockStore {
|
||||||
'LIMIT' => 1,
|
'LIMIT' => 1,
|
||||||
];
|
];
|
||||||
|
|
||||||
$actor = $this->actorStoreFactory->getActorNormalization()->findActorId(
|
$targetUser = $block->getTargetUserIdentity();
|
||||||
$block->getTargetUserIdentity(),
|
$actor = $targetUser ? $this->actorStoreFactory->getActorNormalization()->findActorId(
|
||||||
|
$targetUser,
|
||||||
$dbr
|
$dbr
|
||||||
);
|
) : null;
|
||||||
|
|
||||||
if ( !$actor ) {
|
if ( !$actor ) {
|
||||||
$this->logger->debug( 'No actor found to retroactively autoblock' );
|
$this->logger->debug( 'No actor found to retroactively autoblock' );
|
||||||
return [];
|
return [];
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
$chosenSkinName = $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) );
|
$chosenSkinName = $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) );
|
||||||
|
|
||||||
if ( $skins ) {
|
if ( $skins ) {
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped skin names are valid
|
|
||||||
$radioButtons = $this->parent->getRadioElements( [
|
$radioButtons = $this->parent->getRadioElements( [
|
||||||
'var' => 'wgDefaultSkin',
|
'var' => 'wgDefaultSkin',
|
||||||
'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
|
'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
|
||||||
|
|
@ -124,10 +123,8 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
|
|
||||||
foreach ( $skins as $skin => $info ) {
|
foreach ( $skins as $skin => $info ) {
|
||||||
if ( isset( $info['screenshots'] ) ) {
|
if ( isset( $info['screenshots'] ) ) {
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped skin names are valid
|
|
||||||
$screenshotText = $this->makeScreenshotsLink( $skin, $info['screenshots'] );
|
$screenshotText = $this->makeScreenshotsLink( $skin, $info['screenshots'] );
|
||||||
} else {
|
} else {
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
|
||||||
$screenshotText = htmlspecialchars( $skin );
|
$screenshotText = htmlspecialchars( $skin );
|
||||||
}
|
}
|
||||||
$skinHtml .=
|
$skinHtml .=
|
||||||
|
|
@ -179,7 +176,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
foreach ( $extByType[$type] as $ext => $info ) {
|
foreach ( $extByType[$type] as $ext => $info ) {
|
||||||
$urlText = '';
|
$urlText = '';
|
||||||
if ( isset( $info['url'] ) ) {
|
if ( isset( $info['url'] ) ) {
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
|
||||||
$urlText = ' ' . Html::element( 'a', [ 'href' => $info['url'] ], '(more information)' );
|
$urlText = ' ' . Html::element( 'a', [ 'href' => $info['url'] ], '(more information)' );
|
||||||
}
|
}
|
||||||
$attribs = [
|
$attribs = [
|
||||||
|
|
@ -202,7 +198,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
// extension/skin that is required
|
// extension/skin that is required
|
||||||
if ( isset( $dependencyMap[$ext]['extensions'] ) ) {
|
if ( isset( $dependencyMap[$ext]['extensions'] ) ) {
|
||||||
foreach ( $dependencyMap[$ext]['extensions'] as $name ) {
|
foreach ( $dependencyMap[$ext]['extensions'] as $name ) {
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
|
||||||
$links[] = Html::element(
|
$links[] = Html::element(
|
||||||
'a',
|
'a',
|
||||||
[ 'href' => "#config_ext-$name" ],
|
[ 'href' => "#config_ext-$name" ],
|
||||||
|
|
@ -212,7 +207,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
}
|
}
|
||||||
if ( isset( $dependencyMap[$ext]['skins'] ) ) {
|
if ( isset( $dependencyMap[$ext]['skins'] ) ) {
|
||||||
foreach ( $dependencyMap[$ext]['skins'] as $name ) {
|
foreach ( $dependencyMap[$ext]['skins'] as $name ) {
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
|
||||||
$links[] = Html::element(
|
$links[] = Html::element(
|
||||||
'a',
|
'a',
|
||||||
[ 'href' => "#config_skin-$name" ],
|
[ 'href' => "#config_skin-$name" ],
|
||||||
|
|
@ -243,7 +237,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
||||||
$this->addHTML( $extHtml );
|
$this->addHTML( $extHtml );
|
||||||
// Push the dependency map to the client side
|
// Push the dependency map to the client side
|
||||||
$this->addHTML( Html::inlineScript(
|
$this->addHTML( Html::inlineScript(
|
||||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
|
||||||
'var extDependencyMap = ' . Xml::encodeJsVar( $dependencyMap )
|
'var extDependencyMap = ' . Xml::encodeJsVar( $dependencyMap )
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
use MediaWiki\Auth\AuthenticationRequest;
|
use MediaWiki\Auth\AuthenticationRequest;
|
||||||
use MediaWiki\Auth\AuthManager;
|
use MediaWiki\Auth\AuthManager;
|
||||||
use MediaWiki\Block\AbstractBlock;
|
use MediaWiki\Block\AbstractBlock;
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Block\DatabaseBlock;
|
use MediaWiki\Block\DatabaseBlock;
|
||||||
use MediaWiki\Block\SystemBlock;
|
use MediaWiki\Block\SystemBlock;
|
||||||
use MediaWiki\DAO\WikiAwareEntityTrait;
|
use MediaWiki\DAO\WikiAwareEntityTrait;
|
||||||
|
|
@ -64,10 +65,22 @@ use Wikimedia\ScopedCallback;
|
||||||
*
|
*
|
||||||
* @newable in 1.35 only, the constructor is @internal since 1.36
|
* @newable in 1.35 only, the constructor is @internal since 1.36
|
||||||
*/
|
*/
|
||||||
class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact {
|
class User implements Authority, UserIdentity, UserEmailContact {
|
||||||
use ProtectedHookAccessorTrait;
|
use ProtectedHookAccessorTrait;
|
||||||
use WikiAwareEntityTrait;
|
use WikiAwareEntityTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
* @see IDBAccessObject::READ_EXCLUSIVE
|
||||||
|
*/
|
||||||
|
public const READ_EXCLUSIVE = IDBAccessObject::READ_EXCLUSIVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
* @see IDBAccessObject::READ_LOCKING
|
||||||
|
*/
|
||||||
|
public const READ_LOCKING = IDBAccessObject::READ_LOCKING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of characters required for the user_token field.
|
* Number of characters required for the user_token field.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1897,26 +1910,40 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
|
||||||
* Check if user is blocked
|
* Check if user is blocked
|
||||||
*
|
*
|
||||||
* @deprecated since 1.34, use User::getBlock() or
|
* @deprecated since 1.34, use User::getBlock() or
|
||||||
* PermissionManager::isBlockedFrom() or
|
* Authority:getBlock() or Authority:definitlyCan() or
|
||||||
* PermissionManager::userCan() instead.
|
* Authority:authorizeRead() or Authority:authorizeWrite() or
|
||||||
|
* PermissionManager::isBlockedFrom(), as appropriate.
|
||||||
*
|
*
|
||||||
* @param bool $fromReplica Whether to check the replica DB instead of
|
* @param bool $fromReplica Whether to check the replica DB instead of
|
||||||
* the master. Hacked from false due to horrible probs on site.
|
* the master. Hacked from false due to horrible probs on site.
|
||||||
* @return bool True if blocked, false otherwise
|
* @return bool True if blocked, false otherwise
|
||||||
*/
|
*/
|
||||||
public function isBlocked( $fromReplica = true ) {
|
public function isBlocked( $fromReplica = true ) {
|
||||||
return $this->getBlock( $fromReplica ) instanceof AbstractBlock;
|
return $this->getBlock( $fromReplica ) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the block affecting the user, or null if the user is not blocked
|
* Get the block affecting the user, or null if the user is not blocked
|
||||||
*
|
*
|
||||||
* @param bool $fromReplica Whether to check the replica DB instead of the master
|
* @param int|bool $freshness One of the Authority::READ_XXX constants.
|
||||||
|
* For backwards compatibility, a boolean is also accepted,
|
||||||
|
* with true meaning READ_NORMAL and false meaning
|
||||||
|
* READ_LATEST.
|
||||||
* @param bool $disableIpBlockExemptChecking This is used internally to prevent
|
* @param bool $disableIpBlockExemptChecking This is used internally to prevent
|
||||||
* a infinite recursion with autopromote. See T270145.
|
* a infinite recursion with autopromote. See T270145.
|
||||||
* @return AbstractBlock|null
|
*
|
||||||
|
* @return ?AbstractBlock
|
||||||
*/
|
*/
|
||||||
public function getBlock( $fromReplica = true, $disableIpBlockExemptChecking = false ) {
|
public function getBlock(
|
||||||
|
$freshness = self::READ_NORMAL,
|
||||||
|
$disableIpBlockExemptChecking = false
|
||||||
|
): ?Block {
|
||||||
|
if ( is_bool( $freshness ) ) {
|
||||||
|
$fromReplica = $freshness;
|
||||||
|
} else {
|
||||||
|
$fromReplica = ( $freshness !== self::READ_LATEST );
|
||||||
|
}
|
||||||
|
|
||||||
$this->getBlockedStatus( $fromReplica, $disableIpBlockExemptChecking );
|
$this->getBlockedStatus( $fromReplica, $disableIpBlockExemptChecking );
|
||||||
return $this->mBlock instanceof AbstractBlock ? $this->mBlock : null;
|
return $this->mBlock instanceof AbstractBlock ? $this->mBlock : null;
|
||||||
}
|
}
|
||||||
|
|
@ -3487,7 +3514,7 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
|
||||||
[ 'LOCK IN SHARE MODE' ]
|
[ 'LOCK IN SHARE MODE' ]
|
||||||
);
|
);
|
||||||
$loaded = false;
|
$loaded = false;
|
||||||
if ( $this->mId && $this->loadFromDatabase( self::READ_LOCKING ) ) {
|
if ( $this->mId && $this->loadFromDatabase( IDBAccessObject::READ_LOCKING ) ) {
|
||||||
$loaded = true;
|
$loaded = true;
|
||||||
}
|
}
|
||||||
if ( !$loaded ) {
|
if ( !$loaded ) {
|
||||||
|
|
@ -4198,7 +4225,7 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = self::newFromId( $this->getId() );
|
$user = self::newFromId( $this->getId() );
|
||||||
if ( !$user->loadFromId( self::READ_EXCLUSIVE ) ) {
|
if ( !$user->loadFromId( IDBAccessObject::READ_EXCLUSIVE ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -554,7 +554,7 @@ class UserGroupManager implements IDBAccessObject {
|
||||||
// we stop checking for ipblock-exempt via here. We do this by setting the second
|
// we stop checking for ipblock-exempt via here. We do this by setting the second
|
||||||
// param to true.
|
// param to true.
|
||||||
// See T270145.
|
// See T270145.
|
||||||
$block = $user->getBlock( false, true );
|
$block = $user->getBlock( Authority::READ_LATEST, true );
|
||||||
return $block && $block->isSitewide();
|
return $block && $block->isSitewide();
|
||||||
case APCOND_ISBOT:
|
case APCOND_ISBOT:
|
||||||
return in_array( 'bot', $this->groupPermissionsLookup
|
return in_array( 'bot', $this->groupPermissionsLookup
|
||||||
|
|
|
||||||
|
|
@ -1363,19 +1363,21 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
||||||
* @covers User::getBlockedStatus
|
* @covers User::getBlockedStatus
|
||||||
*/
|
*/
|
||||||
public function testCompositeBlocks() {
|
public function testCompositeBlocks() {
|
||||||
|
$this->tablesUsed[] = 'ipblocks';
|
||||||
|
|
||||||
$user = $this->getMutableTestUser()->getUser();
|
$user = $this->getMutableTestUser()->getUser();
|
||||||
$request = $user->getRequest();
|
$request = $user->getRequest();
|
||||||
$this->setSessionUser( $user, $request );
|
$this->setSessionUser( $user, $request );
|
||||||
|
|
||||||
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
||||||
$ipBlock = new Block( [
|
$ipBlock = new DatabaseBlock( [
|
||||||
'address' => $user->getRequest()->getIP(),
|
'address' => $user->getRequest()->getIP(),
|
||||||
'by' => $this->getTestSysop()->getUser(),
|
'by' => $this->getTestSysop()->getUser(),
|
||||||
'createAccount' => true,
|
'createAccount' => true,
|
||||||
] );
|
] );
|
||||||
$blockStore->insertBlock( $ipBlock );
|
$blockStore->insertBlock( $ipBlock );
|
||||||
|
|
||||||
$userBlock = new Block( [
|
$userBlock = new DatabaseBlock( [
|
||||||
'address' => $user,
|
'address' => $user,
|
||||||
'by' => $this->getTestSysop()->getUser(),
|
'by' => $this->getTestSysop()->getUser(),
|
||||||
'createAccount' => false,
|
'createAccount' => false,
|
||||||
|
|
@ -1389,6 +1391,30 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
||||||
$this->assertTrue( $block->appliesToNamespace( NS_MAIN ) );
|
$this->assertTrue( $block->appliesToNamespace( NS_MAIN ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers User::getBlock
|
||||||
|
*/
|
||||||
|
public function testUserBlock() {
|
||||||
|
$this->tablesUsed[] = 'ipblocks';
|
||||||
|
|
||||||
|
$user = $this->getMutableTestUser()->getUser();
|
||||||
|
$request = $user->getRequest();
|
||||||
|
$this->setSessionUser( $user, $request );
|
||||||
|
|
||||||
|
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
||||||
|
$ipBlock = new DatabaseBlock( [
|
||||||
|
'address' => $user,
|
||||||
|
'by' => $this->getTestSysop()->getUser(),
|
||||||
|
'createAccount' => true,
|
||||||
|
] );
|
||||||
|
$blockStore->insertBlock( $ipBlock );
|
||||||
|
|
||||||
|
$block = $user->getBlock();
|
||||||
|
$this->assertNotNull( $block, 'getuserBlock' );
|
||||||
|
$this->assertNotNull( $block->getTargetUserIdentity(), 'getTargetUserIdentity()' );
|
||||||
|
$this->assertSame( $user->getName(), $block->getTargetUserIdentity()->getName() );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers User::isBlockedFrom
|
* @covers User::isBlockedFrom
|
||||||
* @dataProvider provideIsBlockedFrom
|
* @dataProvider provideIsBlockedFrom
|
||||||
|
|
@ -1404,7 +1430,7 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
||||||
'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
|
'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
|
||||||
] );
|
] );
|
||||||
|
|
||||||
$user = $this->user;
|
$user = $this->getMutableTestUser()->getUser();
|
||||||
|
|
||||||
if ( $title === self::USER_TALK_PAGE ) {
|
if ( $title === self::USER_TALK_PAGE ) {
|
||||||
$title = $user->getTalkPage();
|
$title = $user->getTalkPage();
|
||||||
|
|
@ -1528,7 +1554,7 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
||||||
* @param bool $blockFromAccountCreation Whether to block account creation.
|
* @param bool $blockFromAccountCreation Whether to block account creation.
|
||||||
*/
|
*/
|
||||||
public function testIsBlockedFromAction( $blockFromEmail, $blockFromAccountCreation ) {
|
public function testIsBlockedFromAction( $blockFromEmail, $blockFromAccountCreation ) {
|
||||||
$user = $this->getTestUser( 'accountcreator' )->getUser();
|
$user = $this->getMutableTestUser( 'accountcreator' )->getUser();
|
||||||
|
|
||||||
$block = new DatabaseBlock( [
|
$block = new DatabaseBlock( [
|
||||||
'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
|
'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
|
||||||
|
|
@ -1565,17 +1591,19 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
||||||
* @param bool $expected Whether the user is expected to be blocked from uploads.
|
* @param bool $expected Whether the user is expected to be blocked from uploads.
|
||||||
*/
|
*/
|
||||||
public function testIsBlockedFromUpload( $sitewide, $expected ) {
|
public function testIsBlockedFromUpload( $sitewide, $expected ) {
|
||||||
|
$user = $this->getMutableTestUser()->getUser();
|
||||||
|
|
||||||
$block = new DatabaseBlock( [
|
$block = new DatabaseBlock( [
|
||||||
'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
|
'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
|
||||||
'sitewide' => $sitewide,
|
'sitewide' => $sitewide,
|
||||||
] );
|
] );
|
||||||
$block->setTarget( $this->user );
|
$block->setTarget( $user );
|
||||||
$block->setBlocker( $this->getTestSysop()->getUser() );
|
$block->setBlocker( $this->getTestSysop()->getUser() );
|
||||||
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
||||||
$blockStore->insertBlock( $block );
|
$blockStore->insertBlock( $block );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->assertSame( $expected, $this->user->isBlockedFromUpload() );
|
$this->assertSame( $expected, $user->isBlockedFromUpload() );
|
||||||
} finally {
|
} finally {
|
||||||
$blockStore->deleteBlock( $block );
|
$blockStore->deleteBlock( $block );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace MediaWiki\Tests\Unit\Permissions;
|
namespace MediaWiki\Tests\Unit\Permissions;
|
||||||
|
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Permissions\Authority;
|
use MediaWiki\Permissions\Authority;
|
||||||
use MediaWiki\Permissions\SimpleAuthority;
|
use MediaWiki\Permissions\SimpleAuthority;
|
||||||
use MediaWiki\Permissions\UltimateAuthority;
|
use MediaWiki\Permissions\UltimateAuthority;
|
||||||
|
|
@ -84,6 +85,29 @@ trait MockAuthorityTrait {
|
||||||
return new SimpleAuthority( $user, $permissions );
|
return new SimpleAuthority( $user, $permissions );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mock Authority for $user with $block and $permissions.
|
||||||
|
*
|
||||||
|
* @param UserIdentity $user
|
||||||
|
* @param Block $block
|
||||||
|
* @param array $permissions
|
||||||
|
*
|
||||||
|
* @return Authority
|
||||||
|
*/
|
||||||
|
private function mockUserAuthorityWithBlock(
|
||||||
|
UserIdentity $user,
|
||||||
|
Block $block,
|
||||||
|
array $permissions = []
|
||||||
|
): Authority {
|
||||||
|
return $this->mockAuthority(
|
||||||
|
$user,
|
||||||
|
static function ( $permission ) use ( $permissions ) {
|
||||||
|
return in_array( $permission, $permissions );
|
||||||
|
},
|
||||||
|
$block
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mock Authority for an anon user with all but $permissions
|
* Create a mock Authority for an anon user with all but $permissions
|
||||||
* @param array $permissions
|
* @param array $permissions
|
||||||
|
|
@ -157,9 +181,15 @@ trait MockAuthorityTrait {
|
||||||
*
|
*
|
||||||
* @param UserIdentity $user
|
* @param UserIdentity $user
|
||||||
* @param callable $permissionCallback ( string $permission, ?PageIdentity $page )
|
* @param callable $permissionCallback ( string $permission, ?PageIdentity $page )
|
||||||
|
* @param Block|null $block
|
||||||
|
*
|
||||||
* @return Authority
|
* @return Authority
|
||||||
*/
|
*/
|
||||||
private function mockAuthority( UserIdentity $user, callable $permissionCallback ): Authority {
|
private function mockAuthority(
|
||||||
|
UserIdentity $user,
|
||||||
|
callable $permissionCallback,
|
||||||
|
Block $block = null
|
||||||
|
): Authority {
|
||||||
$mock = $this->createMock( Authority::class );
|
$mock = $this->createMock( Authority::class );
|
||||||
$mock->method( 'getUser' )->willReturn( $user );
|
$mock->method( 'getUser' )->willReturn( $user );
|
||||||
$methods = [ 'isAllowed', 'probablyCan', 'definitelyCan', 'authorizeRead', 'authorizeWrite' ];
|
$methods = [ 'isAllowed', 'probablyCan', 'definitelyCan', 'authorizeRead', 'authorizeWrite' ];
|
||||||
|
|
@ -184,6 +214,7 @@ trait MockAuthorityTrait {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} );
|
} );
|
||||||
|
$mock->method( 'getBlock' )->willReturn( $block );
|
||||||
return $mock;
|
return $mock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
namespace MediaWiki\Tests\Unit\Permissions;
|
namespace MediaWiki\Tests\Unit\Permissions;
|
||||||
|
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Permissions\PermissionStatus;
|
use MediaWiki\Permissions\PermissionStatus;
|
||||||
use MediaWikiUnitTestCase;
|
use MediaWikiUnitTestCase;
|
||||||
|
|
||||||
|
|
@ -36,4 +37,15 @@ class PermissionStatusTest extends MediaWikiUnitTestCase {
|
||||||
$this->assertEmpty( $status->getErrors() );
|
$this->assertEmpty( $status->getErrors() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testBlock() {
|
||||||
|
$status = PermissionStatus::newEmpty();
|
||||||
|
|
||||||
|
$this->assertNull( $status->getBlock() );
|
||||||
|
|
||||||
|
$block = $this->createMock( Block::class );
|
||||||
|
$status->setBlock( $block );
|
||||||
|
|
||||||
|
$this->assertSame( $block, $status->getBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,4 +139,11 @@ class SimpleAuthorityTest extends MediaWikiUnitTestCase {
|
||||||
$authority->isAllowedAll();
|
$authority->isAllowedAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetBlock() {
|
||||||
|
$actor = new UserIdentityValue( 12, 'Test' );
|
||||||
|
$authority = new SimpleAuthority( $actor, [] );
|
||||||
|
|
||||||
|
$this->assertNull( $authority->getBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,4 +119,11 @@ class UltimateAuthorityTest extends MediaWikiUnitTestCase {
|
||||||
$authority->isAllowedAll();
|
$authority->isAllowedAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetBlock() {
|
||||||
|
$actor = new UserIdentityValue( 12, 'Test' );
|
||||||
|
$authority = new UltimateAuthority( $actor );
|
||||||
|
|
||||||
|
$this->assertNull( $authority->getBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,15 @@
|
||||||
namespace MediaWiki\Tests\Unit\Permissions;
|
namespace MediaWiki\Tests\Unit\Permissions;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use MediaWiki\Block\Block;
|
||||||
use MediaWiki\Page\PageIdentity;
|
use MediaWiki\Page\PageIdentity;
|
||||||
use MediaWiki\Page\PageIdentityValue;
|
use MediaWiki\Page\PageIdentityValue;
|
||||||
|
use MediaWiki\Permissions\Authority;
|
||||||
use MediaWiki\Permissions\PermissionManager;
|
use MediaWiki\Permissions\PermissionManager;
|
||||||
use MediaWiki\Permissions\PermissionStatus;
|
use MediaWiki\Permissions\PermissionStatus;
|
||||||
use MediaWiki\Permissions\UserAuthority;
|
use MediaWiki\Permissions\UserAuthority;
|
||||||
use MediaWikiUnitTestCase;
|
use MediaWikiUnitTestCase;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use User;
|
use User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -36,13 +39,13 @@ class UserAuthorityTest extends MediaWikiUnitTestCase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $permissions
|
* @param string[] $permissions
|
||||||
* @param User|null $actor The user to use, null to create a new mock
|
* @return PermissionManager
|
||||||
* @return UserAuthority
|
|
||||||
*/
|
*/
|
||||||
private function newAuthority( array $permissions, User $actor = null ) : UserAuthority {
|
private function newPermissionsManager( array $permissions ) : PermissionManager {
|
||||||
|
/** @var PermissionManager|MockObject $permissionManager */
|
||||||
$permissionManager = $this->createNoOpMock(
|
$permissionManager = $this->createNoOpMock(
|
||||||
PermissionManager::class,
|
PermissionManager::class,
|
||||||
[ 'userHasRight', 'userCan', 'getPermissionErrors' ]
|
[ 'userHasRight', 'userCan', 'getPermissionErrors', 'isBlockedFrom' ]
|
||||||
);
|
);
|
||||||
|
|
||||||
$permissionManager->method( 'userHasRight' )->willReturnCallback(
|
$permissionManager->method( 'userHasRight' )->willReturnCallback(
|
||||||
|
|
@ -64,21 +67,97 @@ class UserAuthorityTest extends MediaWikiUnitTestCase {
|
||||||
$errors[] = [ 'permissionserrors' ];
|
$errors[] = [ 'permissionserrors' ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( $user->getBlock() && $permission !== 'read' ) {
|
||||||
|
$errors[] = [ 'blockedtext-partial' ];
|
||||||
|
}
|
||||||
|
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$permissionManager->method( 'isBlockedFrom' )->willReturnCallback(
|
||||||
|
static function ( User $user, $page ) {
|
||||||
|
return $page->getDBkey() === 'Forbidden';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $permissionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newUser(): User {
|
||||||
|
/** @var User|MockObject $actor */
|
||||||
|
$actor = $this->createNoOpMock( User::class, [ 'getBlock' ] );
|
||||||
|
$actor->method( 'getBlock' )->willReturn( null );
|
||||||
|
return $actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newAuthority( array $permissions, User $actor = null ): Authority {
|
||||||
|
/** @var UserAuthority|MockObject $permissionManager */
|
||||||
|
$permissionManager = $this->newPermissionsManager( $permissions );
|
||||||
return new UserAuthority(
|
return new UserAuthority(
|
||||||
$actor ?? $this->createNoOpMock( User::class ),
|
$actor ?? $this->newUser(),
|
||||||
$permissionManager
|
$permissionManager
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetAuthor() {
|
public function testGetUser() {
|
||||||
$actor = $this->createNoOpMock( User::class );
|
$user = $this->newUser();
|
||||||
$authority = $this->newAuthority( [], $actor );
|
$authority = $this->newAuthority( [], $user );
|
||||||
|
|
||||||
$this->assertSame( $actor, $authority->getUser() );
|
$this->assertSame( $user, $authority->getUser() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUserBlockNotBlocked() {
|
||||||
|
$authority = $this->newAuthority( [] );
|
||||||
|
$this->assertNull( $authority->getBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Block|null $block
|
||||||
|
*
|
||||||
|
* @return MockObject|User
|
||||||
|
*/
|
||||||
|
private function getBlockedUser( $block = null ) {
|
||||||
|
$block = $block ?: $this->createNoOpMock( Block::class );
|
||||||
|
|
||||||
|
$user = $this->createNoOpMock( User::class, [ 'getBlock' ] );
|
||||||
|
$user->method( 'getBlock' )
|
||||||
|
->willReturn( $block );
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetUserBlockWasBlocked() {
|
||||||
|
$block = $this->createNoOpMock( Block::class );
|
||||||
|
$user = $this->getBlockedUser( $block );
|
||||||
|
|
||||||
|
$authority = $this->newAuthority( [], $user );
|
||||||
|
$this->assertSame( $block, $authority->getBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBlockedUserCanRead() {
|
||||||
|
$block = $this->createNoOpMock( Block::class );
|
||||||
|
$user = $this->getBlockedUser( $block );
|
||||||
|
|
||||||
|
$authority = $this->newAuthority( [ 'read', 'edit' ], $user );
|
||||||
|
|
||||||
|
$status = PermissionStatus::newEmpty();
|
||||||
|
$target = new PageIdentityValue( 321, NS_MAIN, __METHOD__, PageIdentity::LOCAL );
|
||||||
|
$this->assertTrue( $authority->authorizeRead( 'read', $target, $status ) );
|
||||||
|
$this->assertTrue( $status->isOK() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBlockedUserCanNotWrite() {
|
||||||
|
$block = $this->createNoOpMock( Block::class );
|
||||||
|
$user = $this->getBlockedUser( $block );
|
||||||
|
|
||||||
|
$authority = $this->newAuthority( [ 'read', 'edit' ], $user );
|
||||||
|
|
||||||
|
$status = PermissionStatus::newEmpty();
|
||||||
|
$target = new PageIdentityValue( 321, NS_MAIN, __METHOD__, PageIdentity::LOCAL );
|
||||||
|
$this->assertFalse( $authority->authorizeRead( 'edit', $target, $status ) );
|
||||||
|
$this->assertFalse( $status->isOK() );
|
||||||
|
$this->assertSame( $block, $status->getBlock() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPermissions() {
|
public function testPermissions() {
|
||||||
|
|
@ -173,4 +252,20 @@ class UserAuthorityTest extends MediaWikiUnitTestCase {
|
||||||
$authority->isAllowedAll();
|
$authority->isAllowedAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetBlock_none() {
|
||||||
|
$actor = $this->newUser();
|
||||||
|
|
||||||
|
$authority = $this->newAuthority( [ 'foo', 'bar' ], $actor );
|
||||||
|
|
||||||
|
$this->assertNull( $authority->getBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetBlock_blocked() {
|
||||||
|
$block = $this->createNoOpMock( Block::class );
|
||||||
|
$actor = $this->getBlockedUser( $block );
|
||||||
|
|
||||||
|
$authority = $this->newAuthority( [ 'foo', 'bar' ], $actor );
|
||||||
|
|
||||||
|
$this->assertSame( $block, $authority->getBlock() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ use MediaWiki\Block\BlockPermissionChecker;
|
||||||
use MediaWiki\Block\BlockUtils;
|
use MediaWiki\Block\BlockUtils;
|
||||||
use MediaWiki\Block\DatabaseBlock;
|
use MediaWiki\Block\DatabaseBlock;
|
||||||
use MediaWiki\Config\ServiceOptions;
|
use MediaWiki\Config\ServiceOptions;
|
||||||
|
use MediaWiki\Permissions\Authority;
|
||||||
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
|
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
|
||||||
use MediaWiki\User\UserFactory;
|
|
||||||
use MediaWiki\User\UserIdentity;
|
use MediaWiki\User\UserIdentity;
|
||||||
use MediaWiki\User\UserIdentityValue;
|
use MediaWiki\User\UserIdentityValue;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
|
@ -22,30 +22,19 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
/**
|
/**
|
||||||
* @param bool $enableUserEmail
|
* @param bool $enableUserEmail
|
||||||
* @param array $targetAndType
|
* @param array $targetAndType
|
||||||
* @param UserIdentity|MockObject $user
|
* @param Authority $performer
|
||||||
* @param string[] $rights
|
|
||||||
* @return BlockPermissionChecker
|
* @return BlockPermissionChecker
|
||||||
*/
|
*/
|
||||||
private function getBlockPermissionChecker(
|
private function getBlockPermissionChecker(
|
||||||
bool $enableUserEmail,
|
bool $enableUserEmail,
|
||||||
array $targetAndType,
|
array $targetAndType,
|
||||||
$user,
|
Authority $performer
|
||||||
array $rights
|
|
||||||
) {
|
) {
|
||||||
$options = new ServiceOptions(
|
$options = new ServiceOptions(
|
||||||
BlockPermissionChecker::CONSTRUCTOR_OPTIONS,
|
BlockPermissionChecker::CONSTRUCTOR_OPTIONS,
|
||||||
[ 'EnableUserEmail' => $enableUserEmail ]
|
[ 'EnableUserEmail' => $enableUserEmail ]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make things simple: in the test cases when the UserFactory is needed,
|
|
||||||
// we expect to have the mock authority objects be based on mocks of full
|
|
||||||
// User objects instead of just UserIdentity, so performer->getUser() is a
|
|
||||||
// full user object, and have the factory just return that object
|
|
||||||
$userFactory = $this->createMock( UserFactory::class );
|
|
||||||
$userFactory->method( 'newFromUserIdentity' )
|
|
||||||
->with( $this->isInstanceOf( User::class ) )
|
|
||||||
->will( $this->returnArgument( 0 ) );
|
|
||||||
|
|
||||||
// We don't care about how BlockUtils::parseBlockTarget actually works, just
|
// We don't care about how BlockUtils::parseBlockTarget actually works, just
|
||||||
// override with whatever. Only used for a single call in the constructor
|
// override with whatever. Only used for a single call in the constructor
|
||||||
// for getting target and type
|
// for getting target and type
|
||||||
|
|
@ -54,12 +43,9 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
->method( 'parseBlockTarget' )
|
->method( 'parseBlockTarget' )
|
||||||
->willReturn( $targetAndType );
|
->willReturn( $targetAndType );
|
||||||
|
|
||||||
$performer = $this->mockUserAuthorityWithPermissions( $user, $rights );
|
|
||||||
|
|
||||||
return new BlockPermissionChecker(
|
return new BlockPermissionChecker(
|
||||||
$options,
|
$options,
|
||||||
$blockUtils,
|
$blockUtils,
|
||||||
$userFactory,
|
|
||||||
'foo', // input to BlockUtils::parseBlockTarget, not used
|
'foo', // input to BlockUtils::parseBlockTarget, not used
|
||||||
$performer
|
$performer
|
||||||
);
|
);
|
||||||
|
|
@ -94,12 +80,11 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
* @dataProvider provideCheckBasePermissions
|
* @dataProvider provideCheckBasePermissions
|
||||||
*/
|
*/
|
||||||
public function testCheckBasePermissions( $rights, $checkHideuser, $expect ) {
|
public function testCheckBasePermissions( $rights, $checkHideuser, $expect ) {
|
||||||
$user = new UserIdentityValue( 4, 'admin' );
|
$performer = $this->mockRegisteredAuthorityWithPermissions( $rights );
|
||||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||||
true, // $enableUserEmail, irrelevant
|
true, // $enableUserEmail, irrelevant
|
||||||
[ null, null ], // $targetAndType, irrelevant
|
[ null, null ], // $targetAndType, irrelevant
|
||||||
$user,
|
$performer
|
||||||
$rights
|
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
$expect,
|
$expect,
|
||||||
|
|
@ -112,14 +97,10 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
*/
|
*/
|
||||||
public function testNotBlockedPerformer() {
|
public function testNotBlockedPerformer() {
|
||||||
// checkBlockPermissions has an early return true if the performer has no block
|
// checkBlockPermissions has an early return true if the performer has no block
|
||||||
$user = $this->createMock( User::class );
|
|
||||||
$user->method( 'getBlock' )->willReturn( null );
|
|
||||||
|
|
||||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||||
true, // $enableUserEmail, irrelevant
|
true, // $enableUserEmail, irrelevant
|
||||||
[ null, null ], // $targetAndType, irrelevant
|
[ null, null ], // $targetAndType, irrelevant
|
||||||
$user,
|
$this->mockRegisteredAuthorityWithoutPermissions( [] )
|
||||||
[] // $rights, irrelevant
|
|
||||||
);
|
);
|
||||||
$this->assertTrue(
|
$this->assertTrue(
|
||||||
$blockPermissionChecker->checkBlockPermissions()
|
$blockPermissionChecker->checkBlockPermissions()
|
||||||
|
|
@ -131,16 +112,13 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
*/
|
*/
|
||||||
public function testPartialBlockedPerformer() {
|
public function testPartialBlockedPerformer() {
|
||||||
// checkBlockPermissions has an early return true if the performer is not sitewide blocked
|
// checkBlockPermissions has an early return true if the performer is not sitewide blocked
|
||||||
$user = $this->createMock( User::class );
|
$blocker = new UserIdentityValue( 1, 'blocker', UserIdentity::LOCAL );
|
||||||
$user->method( 'getBlock' )->willReturn(
|
$performer = $this->mockUserAuthorityWithBlock( $blocker, $this->getBlock( false, '' ) );
|
||||||
$this->getBlock( false, '' )
|
|
||||||
);
|
|
||||||
|
|
||||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||||
true, // $enableUserEmail, irrelevant
|
true, // $enableUserEmail, irrelevant
|
||||||
[ null, null ], // $targetAndType, irrelevant
|
[ null, null ], // $targetAndType, irrelevant
|
||||||
$user,
|
$performer
|
||||||
[] // $rights, irrelevant
|
|
||||||
);
|
);
|
||||||
$this->assertTrue(
|
$this->assertTrue(
|
||||||
$blockPermissionChecker->checkBlockPermissions()
|
$blockPermissionChecker->checkBlockPermissions()
|
||||||
|
|
@ -177,21 +155,17 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
true, // sitewide
|
true, // sitewide
|
||||||
$blockedBy
|
$blockedBy
|
||||||
);
|
);
|
||||||
$user = $this->createMock( User::class );
|
$rights = $unblockSelf ? [ 'unblockself' ] : [];
|
||||||
$user->method( 'getBlock' )->willReturn( $block );
|
|
||||||
$user->method( 'getId' )->willReturn( 1 );
|
$blocker = new UserIdentityValue( 1, 'blocker', UserIdentity::LOCAL );
|
||||||
$user->method( 'getName' )->willReturn( 'blocker' );
|
$performer = $this->mockUserAuthorityWithBlock( $blocker, $block, $rights );
|
||||||
$user->method( 'equals' )->willReturnCallback( static function ( $user ) {
|
|
||||||
return $user->getName() === 'blocker';
|
|
||||||
} );
|
|
||||||
|
|
||||||
$target = new UserIdentityValue( $targetUserId, $targetUserName );
|
$target = new UserIdentityValue( $targetUserId, $targetUserName );
|
||||||
|
|
||||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||||
true, // $enableUserEmail, irrelevant
|
true, // $enableUserEmail, irrelevant
|
||||||
[ $target, AbstractBlock::TYPE_USER ], // $targetAndType, irrelevant
|
[ $target, AbstractBlock::TYPE_USER ], // $targetAndType, irrelevant
|
||||||
$user,
|
$performer
|
||||||
$unblockSelf ? [ 'unblockself' ] : []
|
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
$expect,
|
$expect,
|
||||||
|
|
@ -212,12 +186,11 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
||||||
* @dataProvider provideCheckEmailPermissions
|
* @dataProvider provideCheckEmailPermissions
|
||||||
*/
|
*/
|
||||||
public function testCheckEmailPermissionOkay( $enableEmail, $rights, $expect ) {
|
public function testCheckEmailPermissionOkay( $enableEmail, $rights, $expect ) {
|
||||||
$user = new UserIdentityValue( 4, 'admin' );
|
$performer = $this->mockRegisteredAuthorityWithPermissions( $rights );
|
||||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||||
$enableEmail,
|
$enableEmail,
|
||||||
[ null, null ], // $targetAndType, irrelevant
|
[ null, null ], // $targetAndType, irrelevant
|
||||||
$user,
|
$performer
|
||||||
$rights
|
|
||||||
);
|
);
|
||||||
$this->assertSame( $expect, $blockPermissionChecker->checkEmailPermissions() );
|
$this->assertSame( $expect, $blockPermissionChecker->checkEmailPermissions() );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue