Merge "Authority: expose user block info"
This commit is contained in:
commit
8e20e195eb
24 changed files with 435 additions and 125 deletions
|
|
@ -371,6 +371,12 @@ because of Phabricator reports.
|
|||
the method it wraps, User->isRegistered(), instead.
|
||||
* FileBackendGroup::singleton() and ::destroySingletons(), deprecated since
|
||||
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
|
||||
MediaWikiServices::getJobQueueGroup instead.
|
||||
* JobQueueGroup::destroySingletons was deprecated. JobQueueGroups are now
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
namespace MediaWiki\Permissions;
|
||||
|
||||
use IDBAccessObject;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
||||
|
|
@ -34,6 +36,18 @@ use MediaWiki\User\UserIdentity;
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
@ -44,6 +58,17 @@ interface Authority {
|
|||
*/
|
||||
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.
|
||||
* 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\HookRunner;
|
||||
use MediaWiki\Linker\LinkTarget;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\Revision\RevisionLookup;
|
||||
use MediaWiki\Revision\RevisionRecord;
|
||||
use MediaWiki\Session\SessionManager;
|
||||
|
|
@ -329,19 +330,22 @@ class PermissionManager {
|
|||
* have a block, this will return false.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isBlockedFrom( User $user, LinkTarget $page, $fromReplica = false ) {
|
||||
public function isBlockedFrom( User $user, $page, $fromReplica = false ) {
|
||||
$block = $user->getBlock( $fromReplica );
|
||||
if ( !$block ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: remove upon further migration to LinkTarget
|
||||
$title = Title::newFromLinkTarget( $page );
|
||||
if ( $page instanceof PageIdentity ) {
|
||||
$title = Title::castFromPageIdentity( $page );
|
||||
} else {
|
||||
$title = Title::castFromLinkTarget( $page );
|
||||
}
|
||||
|
||||
$blocked = $user->isHidden();
|
||||
if ( !$blocked ) {
|
||||
|
|
@ -723,8 +727,21 @@ class PermissionManager {
|
|||
$errors[] = [ 'confirmedittext' ];
|
||||
}
|
||||
|
||||
$useReplica = ( $rigor !== self::RIGOR_SECURE );
|
||||
$block = $user->getBlock( $useReplica );
|
||||
switch ( $rigor ) {
|
||||
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' ) {
|
||||
$applicableBlock = null;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
namespace MediaWiki\Permissions;
|
||||
|
||||
use MediaWiki\Block\Block;
|
||||
use StatusValue;
|
||||
|
||||
/**
|
||||
|
|
@ -33,6 +34,33 @@ use 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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
namespace MediaWiki\Permissions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
||||
|
|
@ -60,6 +61,16 @@ class SimpleAuthority implements Authority {
|
|||
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
|
||||
*
|
||||
|
|
@ -191,4 +202,5 @@ class SimpleAuthority implements Authority {
|
|||
): bool {
|
||||
return $this->checkPermission( $action, $status );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
namespace MediaWiki\Permissions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
||||
|
|
@ -53,6 +54,16 @@ class UltimateAuthority implements Authority {
|
|||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
namespace MediaWiki\Permissions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Linker\LinkTarget;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
|
@ -49,10 +50,17 @@ class UserAuthority implements Authority {
|
|||
private $permissionManager;
|
||||
|
||||
/**
|
||||
* @var UserIdentity
|
||||
* @var User
|
||||
*/
|
||||
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 PermissionManager $permissionManager
|
||||
|
|
@ -254,8 +262,22 @@ class UserAuthority implements Authority {
|
|||
$rigor
|
||||
);
|
||||
|
||||
$blockError = false;
|
||||
foreach ( $errors as $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();
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,8 +246,7 @@ return [
|
|||
BlockPermissionCheckerFactory::CONSTRUCTOR_OPTIONS,
|
||||
$services->getMainConfig()
|
||||
),
|
||||
$services->getBlockUtils(),
|
||||
$services->getUserFactory()
|
||||
$services->getBlockUtils()
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@
|
|||
|
||||
use MediaWiki\Api\ApiHookRunner;
|
||||
use MediaWiki\Api\Validator\SubmoduleDef;
|
||||
use MediaWiki\Block\AbstractBlock;
|
||||
use MediaWiki\Block\DatabaseBlock;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\HookContainer\HookContainer;
|
||||
use MediaWiki\Linker\LinkTarget;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\ParamValidator\TypeDef\NamespaceDef;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Permissions\GroupPermissionsLookup;
|
||||
use MediaWiki\Permissions\PermissionManager;
|
||||
use MediaWiki\Permissions\PermissionStatus;
|
||||
|
|
@ -1218,19 +1218,25 @@ abstract class ApiBase extends ContextSource {
|
|||
/**
|
||||
* Add block info to block messages in a Status
|
||||
* @since 1.33
|
||||
* @internal since 1.37, should become protected in the future.
|
||||
* @param StatusValue $status
|
||||
* @param User|null $user
|
||||
* @param Authority|null $user
|
||||
*/
|
||||
public function addBlockInfoToStatus( StatusValue $status, User $user = null ) {
|
||||
if ( $user === null ) {
|
||||
$user = $this->getUser();
|
||||
public function addBlockInfoToStatus( StatusValue $status, Authority $user = null ) {
|
||||
if ( $status instanceof PermissionStatus ) {
|
||||
$block = $status->getBlock();
|
||||
} else {
|
||||
$user = $user ?: $this->getAuthority();
|
||||
$block = $user->getBlock();
|
||||
}
|
||||
|
||||
foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
|
||||
if ( $status->hasMessage( $msg ) && $user->getBlock() ) {
|
||||
$status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
|
||||
[ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
|
||||
) );
|
||||
if ( $block ) {
|
||||
foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
|
||||
if ( $status->hasMessage( $msg ) ) {
|
||||
$status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
|
||||
[ 'blockinfo' => $this->getBlockDetails( $block ) ]
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1405,12 +1411,12 @@ abstract class ApiBase extends ContextSource {
|
|||
* error handler and die with an error message including block info.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function dieBlocked( AbstractBlock $block ) {
|
||||
public function dieBlocked( Block $block ) {
|
||||
// Die using the appropriate message depending on block type
|
||||
if ( $block->getType() == DatabaseBlock::TYPE_AUTO ) {
|
||||
if ( $block->getType() == Block::TYPE_AUTO ) {
|
||||
$this->dieWithError(
|
||||
'apierror-autoblocked',
|
||||
'autoblocked',
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
* @file
|
||||
*/
|
||||
|
||||
use MediaWiki\Permissions\Authority;
|
||||
|
||||
/**
|
||||
* @ingroup API
|
||||
*/
|
||||
|
|
@ -40,9 +42,9 @@ class ApiUndelete extends ApiBase {
|
|||
$params = $this->extractRequestParams();
|
||||
|
||||
$user = $this->getUser();
|
||||
$block = $user->getBlock();
|
||||
$block = $user->getBlock( Authority::READ_LATEST );
|
||||
if ( $block && $block->isSitewide() ) {
|
||||
$this->dieBlocked( $user->getBlock() );
|
||||
$this->dieBlocked( $block );
|
||||
}
|
||||
|
||||
$titleObj = Title::newFromText( $params['title'] );
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
use MediaWiki\ParamValidator\TypeDef\UserDef;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
|
||||
/**
|
||||
* @ingroup API
|
||||
|
|
@ -54,7 +55,7 @@ class ApiUserrights extends ApiBase {
|
|||
// Deny if the user is blocked and doesn't have the full 'userrights' permission.
|
||||
// This matches what Special:UserRights does for the web UI.
|
||||
if ( !$this->getAuthority()->isAllowed( 'userrights' ) ) {
|
||||
$block = $pUser->getBlock();
|
||||
$block = $pUser->getBlock( Authority::READ_LATEST );
|
||||
if ( $block && $block->isSitewide() ) {
|
||||
$this->dieBlocked( $block );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ namespace MediaWiki\Block;
|
|||
|
||||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\User\UserFactory;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
||||
/**
|
||||
|
|
@ -62,26 +61,20 @@ class BlockPermissionChecker {
|
|||
/** @var ServiceOptions */
|
||||
private $options;
|
||||
|
||||
/** @var UserFactory */
|
||||
private $userFactory;
|
||||
|
||||
/**
|
||||
* @param ServiceOptions $options
|
||||
* @param BlockUtils $blockUtils
|
||||
* @param UserFactory $userFactory
|
||||
* @param UserIdentity|string|null $target
|
||||
* @param Authority $performer
|
||||
*/
|
||||
public function __construct(
|
||||
ServiceOptions $options,
|
||||
BlockUtils $blockUtils,
|
||||
UserFactory $userFactory,
|
||||
$target,
|
||||
Authority $performer
|
||||
) {
|
||||
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||
$this->options = $options;
|
||||
$this->userFactory = $userFactory;
|
||||
list( $this->target, $this->targetType ) = $blockUtils->parseBlockTarget( $target );
|
||||
$this->performer = $performer;
|
||||
}
|
||||
|
|
@ -120,10 +113,7 @@ class BlockPermissionChecker {
|
|||
* @return bool|string True when checks passed, message code for failures
|
||||
*/
|
||||
public function checkBlockPermissions() {
|
||||
$performerIdentity = $this->performer->getUser();
|
||||
$legacyUser = $this->userFactory->newFromUserIdentity( $performerIdentity );
|
||||
|
||||
$block = $legacyUser->getBlock();
|
||||
$block = $this->performer->getBlock(); // TODO: pass disposition parameter
|
||||
if ( !$block ) {
|
||||
// User is not blocked, process as normal
|
||||
return true;
|
||||
|
|
@ -134,6 +124,8 @@ class BlockPermissionChecker {
|
|||
return true;
|
||||
}
|
||||
|
||||
$performerIdentity = $this->performer->getUser();
|
||||
|
||||
if (
|
||||
$this->target instanceof UserIdentity &&
|
||||
$this->target->getId() === $performerIdentity->getId()
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ namespace MediaWiki\Block;
|
|||
|
||||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\User\UserFactory;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
|
||||
/**
|
||||
|
|
@ -44,23 +43,17 @@ class BlockPermissionCheckerFactory {
|
|||
/** @var BlockUtils */
|
||||
private $blockUtils;
|
||||
|
||||
/** @var UserFactory */
|
||||
private $userFactory;
|
||||
|
||||
/**
|
||||
* @param ServiceOptions $options
|
||||
* @param BlockUtils $blockUtils
|
||||
* @param UserFactory $userFactory
|
||||
*/
|
||||
public function __construct(
|
||||
ServiceOptions $options,
|
||||
BlockUtils $blockUtils,
|
||||
UserFactory $userFactory
|
||||
BlockUtils $blockUtils
|
||||
) {
|
||||
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||
$this->options = $options;
|
||||
$this->blockUtils = $blockUtils;
|
||||
$this->userFactory = $userFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -76,7 +69,6 @@ class BlockPermissionCheckerFactory {
|
|||
return new BlockPermissionChecker(
|
||||
$this->options,
|
||||
$this->blockUtils,
|
||||
$this->userFactory,
|
||||
$target,
|
||||
$performer
|
||||
);
|
||||
|
|
|
|||
|
|
@ -517,10 +517,12 @@ class DatabaseBlockStore {
|
|||
'LIMIT' => 1,
|
||||
];
|
||||
|
||||
$actor = $this->actorStoreFactory->getActorNormalization()->findActorId(
|
||||
$block->getTargetUserIdentity(),
|
||||
$targetUser = $block->getTargetUserIdentity();
|
||||
$actor = $targetUser ? $this->actorStoreFactory->getActorNormalization()->findActorId(
|
||||
$targetUser,
|
||||
$dbr
|
||||
);
|
||||
) : null;
|
||||
|
||||
if ( !$actor ) {
|
||||
$this->logger->debug( 'No actor found to retroactively autoblock' );
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
|||
$chosenSkinName = $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) );
|
||||
|
||||
if ( $skins ) {
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped skin names are valid
|
||||
$radioButtons = $this->parent->getRadioElements( [
|
||||
'var' => 'wgDefaultSkin',
|
||||
'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
|
||||
|
|
@ -124,10 +123,8 @@ class WebInstallerOptions extends WebInstallerPage {
|
|||
|
||||
foreach ( $skins as $skin => $info ) {
|
||||
if ( isset( $info['screenshots'] ) ) {
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped skin names are valid
|
||||
$screenshotText = $this->makeScreenshotsLink( $skin, $info['screenshots'] );
|
||||
} else {
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
||||
$screenshotText = htmlspecialchars( $skin );
|
||||
}
|
||||
$skinHtml .=
|
||||
|
|
@ -179,7 +176,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
|||
foreach ( $extByType[$type] as $ext => $info ) {
|
||||
$urlText = '';
|
||||
if ( isset( $info['url'] ) ) {
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
||||
$urlText = ' ' . Html::element( 'a', [ 'href' => $info['url'] ], '(more information)' );
|
||||
}
|
||||
$attribs = [
|
||||
|
|
@ -202,7 +198,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
|||
// extension/skin that is required
|
||||
if ( isset( $dependencyMap[$ext]['extensions'] ) ) {
|
||||
foreach ( $dependencyMap[$ext]['extensions'] as $name ) {
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
||||
$links[] = Html::element(
|
||||
'a',
|
||||
[ 'href' => "#config_ext-$name" ],
|
||||
|
|
@ -212,7 +207,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
|||
}
|
||||
if ( isset( $dependencyMap[$ext]['skins'] ) ) {
|
||||
foreach ( $dependencyMap[$ext]['skins'] as $name ) {
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
||||
$links[] = Html::element(
|
||||
'a',
|
||||
[ 'href' => "#config_skin-$name" ],
|
||||
|
|
@ -243,7 +237,6 @@ class WebInstallerOptions extends WebInstallerPage {
|
|||
$this->addHTML( $extHtml );
|
||||
// Push the dependency map to the client side
|
||||
$this->addHTML( Html::inlineScript(
|
||||
// @phan-suppress-next-line SecurityCheck-DoubleEscaped False positive
|
||||
'var extDependencyMap = ' . Xml::encodeJsVar( $dependencyMap )
|
||||
) );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
use MediaWiki\Auth\AuthenticationRequest;
|
||||
use MediaWiki\Auth\AuthManager;
|
||||
use MediaWiki\Block\AbstractBlock;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Block\DatabaseBlock;
|
||||
use MediaWiki\Block\SystemBlock;
|
||||
use MediaWiki\DAO\WikiAwareEntityTrait;
|
||||
|
|
@ -64,10 +65,22 @@ use Wikimedia\ScopedCallback;
|
|||
*
|
||||
* @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 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.
|
||||
*/
|
||||
|
|
@ -1891,26 +1904,40 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
|
|||
* Check if user is blocked
|
||||
*
|
||||
* @deprecated since 1.34, use User::getBlock() or
|
||||
* PermissionManager::isBlockedFrom() or
|
||||
* PermissionManager::userCan() instead.
|
||||
* Authority:getBlock() or Authority:definitlyCan() or
|
||||
* Authority:authorizeRead() or Authority:authorizeWrite() or
|
||||
* PermissionManager::isBlockedFrom(), as appropriate.
|
||||
*
|
||||
* @param bool $fromReplica Whether to check the replica DB instead of
|
||||
* the master. Hacked from false due to horrible probs on site.
|
||||
* @return bool True if blocked, false otherwise
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @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
|
||||
* 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 );
|
||||
return $this->mBlock instanceof AbstractBlock ? $this->mBlock : null;
|
||||
}
|
||||
|
|
@ -3481,7 +3508,7 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
|
|||
[ 'LOCK IN SHARE MODE' ]
|
||||
);
|
||||
$loaded = false;
|
||||
if ( $this->mId && $this->loadFromDatabase( self::READ_LOCKING ) ) {
|
||||
if ( $this->mId && $this->loadFromDatabase( IDBAccessObject::READ_LOCKING ) ) {
|
||||
$loaded = true;
|
||||
}
|
||||
if ( !$loaded ) {
|
||||
|
|
@ -4192,7 +4219,7 @@ class User implements Authority, IDBAccessObject, UserIdentity, UserEmailContact
|
|||
}
|
||||
|
||||
$user = self::newFromId( $this->getId() );
|
||||
if ( !$user->loadFromId( self::READ_EXCLUSIVE ) ) {
|
||||
if ( !$user->loadFromId( IDBAccessObject::READ_EXCLUSIVE ) ) {
|
||||
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
|
||||
// param to true.
|
||||
// See T270145.
|
||||
$block = $user->getBlock( false, true );
|
||||
$block = $user->getBlock( Authority::READ_LATEST, true );
|
||||
return $block && $block->isSitewide();
|
||||
case APCOND_ISBOT:
|
||||
return in_array( 'bot', $this->groupPermissionsLookup
|
||||
|
|
|
|||
|
|
@ -1362,19 +1362,21 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
|||
* @covers User::getBlockedStatus
|
||||
*/
|
||||
public function testCompositeBlocks() {
|
||||
$this->tablesUsed[] = 'ipblocks';
|
||||
|
||||
$user = $this->getMutableTestUser()->getUser();
|
||||
$request = $user->getRequest();
|
||||
$this->setSessionUser( $user, $request );
|
||||
|
||||
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
||||
$ipBlock = new Block( [
|
||||
$ipBlock = new DatabaseBlock( [
|
||||
'address' => $user->getRequest()->getIP(),
|
||||
'by' => $this->getTestSysop()->getUser(),
|
||||
'createAccount' => true,
|
||||
] );
|
||||
$blockStore->insertBlock( $ipBlock );
|
||||
|
||||
$userBlock = new Block( [
|
||||
$userBlock = new DatabaseBlock( [
|
||||
'address' => $user,
|
||||
'by' => $this->getTestSysop()->getUser(),
|
||||
'createAccount' => false,
|
||||
|
|
@ -1388,6 +1390,30 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
|||
$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
|
||||
* @dataProvider provideIsBlockedFrom
|
||||
|
|
@ -1403,7 +1429,7 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
|||
'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
|
||||
] );
|
||||
|
||||
$user = $this->user;
|
||||
$user = $this->getMutableTestUser()->getUser();
|
||||
|
||||
if ( $title === self::USER_TALK_PAGE ) {
|
||||
$title = $user->getTalkPage();
|
||||
|
|
@ -1527,7 +1553,7 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
|||
* @param bool $blockFromAccountCreation Whether to block account creation.
|
||||
*/
|
||||
public function testIsBlockedFromAction( $blockFromEmail, $blockFromAccountCreation ) {
|
||||
$user = $this->getTestUser( 'accountcreator' )->getUser();
|
||||
$user = $this->getMutableTestUser( 'accountcreator' )->getUser();
|
||||
|
||||
$block = new DatabaseBlock( [
|
||||
'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
|
||||
|
|
@ -1564,17 +1590,19 @@ class UserTest extends MediaWikiIntegrationTestCase {
|
|||
* @param bool $expected Whether the user is expected to be blocked from uploads.
|
||||
*/
|
||||
public function testIsBlockedFromUpload( $sitewide, $expected ) {
|
||||
$user = $this->getMutableTestUser()->getUser();
|
||||
|
||||
$block = new DatabaseBlock( [
|
||||
'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
|
||||
'sitewide' => $sitewide,
|
||||
] );
|
||||
$block->setTarget( $this->user );
|
||||
$block->setTarget( $user );
|
||||
$block->setBlocker( $this->getTestSysop()->getUser() );
|
||||
$blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
|
||||
$blockStore->insertBlock( $block );
|
||||
|
||||
try {
|
||||
$this->assertSame( $expected, $this->user->isBlockedFromUpload() );
|
||||
$this->assertSame( $expected, $user->isBlockedFromUpload() );
|
||||
} finally {
|
||||
$blockStore->deleteBlock( $block );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace MediaWiki\Tests\Unit\Permissions;
|
||||
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Permissions\SimpleAuthority;
|
||||
use MediaWiki\Permissions\UltimateAuthority;
|
||||
|
|
@ -84,6 +85,29 @@ trait MockAuthorityTrait {
|
|||
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
|
||||
* @param array $permissions
|
||||
|
|
@ -157,9 +181,15 @@ trait MockAuthorityTrait {
|
|||
*
|
||||
* @param UserIdentity $user
|
||||
* @param callable $permissionCallback ( string $permission, ?PageIdentity $page )
|
||||
* @param Block|null $block
|
||||
*
|
||||
* @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->method( 'getUser' )->willReturn( $user );
|
||||
$methods = [ 'isAllowed', 'probablyCan', 'definitelyCan', 'authorizeRead', 'authorizeWrite' ];
|
||||
|
|
@ -184,6 +214,7 @@ trait MockAuthorityTrait {
|
|||
}
|
||||
return true;
|
||||
} );
|
||||
$mock->method( 'getBlock' )->willReturn( $block );
|
||||
return $mock;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
namespace MediaWiki\Tests\Unit\Permissions;
|
||||
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Permissions\PermissionStatus;
|
||||
use MediaWikiUnitTestCase;
|
||||
|
||||
|
|
@ -36,4 +37,15 @@ class PermissionStatusTest extends MediaWikiUnitTestCase {
|
|||
$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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\Block\Block;
|
||||
use MediaWiki\Page\PageIdentity;
|
||||
use MediaWiki\Page\PageIdentityValue;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Permissions\PermissionManager;
|
||||
use MediaWiki\Permissions\PermissionStatus;
|
||||
use MediaWiki\Permissions\UserAuthority;
|
||||
use MediaWikiUnitTestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use User;
|
||||
|
||||
/**
|
||||
|
|
@ -36,13 +39,13 @@ class UserAuthorityTest extends MediaWikiUnitTestCase {
|
|||
|
||||
/**
|
||||
* @param string[] $permissions
|
||||
* @param User|null $actor The user to use, null to create a new mock
|
||||
* @return UserAuthority
|
||||
* @return PermissionManager
|
||||
*/
|
||||
private function newAuthority( array $permissions, User $actor = null ) : UserAuthority {
|
||||
private function newPermissionsManager( array $permissions ) : PermissionManager {
|
||||
/** @var PermissionManager|MockObject $permissionManager */
|
||||
$permissionManager = $this->createNoOpMock(
|
||||
PermissionManager::class,
|
||||
[ 'userHasRight', 'userCan', 'getPermissionErrors' ]
|
||||
[ 'userHasRight', 'userCan', 'getPermissionErrors', 'isBlockedFrom' ]
|
||||
);
|
||||
|
||||
$permissionManager->method( 'userHasRight' )->willReturnCallback(
|
||||
|
|
@ -64,21 +67,97 @@ class UserAuthorityTest extends MediaWikiUnitTestCase {
|
|||
$errors[] = [ 'permissionserrors' ];
|
||||
}
|
||||
|
||||
if ( $user->getBlock() && $permission !== 'read' ) {
|
||||
$errors[] = [ 'blockedtext-partial' ];
|
||||
}
|
||||
|
||||
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(
|
||||
$actor ?? $this->createNoOpMock( User::class ),
|
||||
$actor ?? $this->newUser(),
|
||||
$permissionManager
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetAuthor() {
|
||||
$actor = $this->createNoOpMock( User::class );
|
||||
$authority = $this->newAuthority( [], $actor );
|
||||
public function testGetUser() {
|
||||
$user = $this->newUser();
|
||||
$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() {
|
||||
|
|
@ -173,4 +252,20 @@ class UserAuthorityTest extends MediaWikiUnitTestCase {
|
|||
$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\DatabaseBlock;
|
||||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
|
||||
use MediaWiki\User\UserFactory;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
use MediaWiki\User\UserIdentityValue;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
|
@ -22,30 +22,19 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
/**
|
||||
* @param bool $enableUserEmail
|
||||
* @param array $targetAndType
|
||||
* @param UserIdentity|MockObject $user
|
||||
* @param string[] $rights
|
||||
* @param Authority $performer
|
||||
* @return BlockPermissionChecker
|
||||
*/
|
||||
private function getBlockPermissionChecker(
|
||||
bool $enableUserEmail,
|
||||
array $targetAndType,
|
||||
$user,
|
||||
array $rights
|
||||
Authority $performer
|
||||
) {
|
||||
$options = new ServiceOptions(
|
||||
BlockPermissionChecker::CONSTRUCTOR_OPTIONS,
|
||||
[ '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
|
||||
// override with whatever. Only used for a single call in the constructor
|
||||
// for getting target and type
|
||||
|
|
@ -54,12 +43,9 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
->method( 'parseBlockTarget' )
|
||||
->willReturn( $targetAndType );
|
||||
|
||||
$performer = $this->mockUserAuthorityWithPermissions( $user, $rights );
|
||||
|
||||
return new BlockPermissionChecker(
|
||||
$options,
|
||||
$blockUtils,
|
||||
$userFactory,
|
||||
'foo', // input to BlockUtils::parseBlockTarget, not used
|
||||
$performer
|
||||
);
|
||||
|
|
@ -94,12 +80,11 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
* @dataProvider provideCheckBasePermissions
|
||||
*/
|
||||
public function testCheckBasePermissions( $rights, $checkHideuser, $expect ) {
|
||||
$user = new UserIdentityValue( 4, 'admin' );
|
||||
$performer = $this->mockRegisteredAuthorityWithPermissions( $rights );
|
||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||
true, // $enableUserEmail, irrelevant
|
||||
[ null, null ], // $targetAndType, irrelevant
|
||||
$user,
|
||||
$rights
|
||||
$performer
|
||||
);
|
||||
$this->assertSame(
|
||||
$expect,
|
||||
|
|
@ -112,14 +97,10 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
*/
|
||||
public function testNotBlockedPerformer() {
|
||||
// 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(
|
||||
true, // $enableUserEmail, irrelevant
|
||||
[ null, null ], // $targetAndType, irrelevant
|
||||
$user,
|
||||
[] // $rights, irrelevant
|
||||
$this->mockRegisteredAuthorityWithoutPermissions( [] )
|
||||
);
|
||||
$this->assertTrue(
|
||||
$blockPermissionChecker->checkBlockPermissions()
|
||||
|
|
@ -131,16 +112,13 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
*/
|
||||
public function testPartialBlockedPerformer() {
|
||||
// checkBlockPermissions has an early return true if the performer is not sitewide blocked
|
||||
$user = $this->createMock( User::class );
|
||||
$user->method( 'getBlock' )->willReturn(
|
||||
$this->getBlock( false, '' )
|
||||
);
|
||||
$blocker = new UserIdentityValue( 1, 'blocker', UserIdentity::LOCAL );
|
||||
$performer = $this->mockUserAuthorityWithBlock( $blocker, $this->getBlock( false, '' ) );
|
||||
|
||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||
true, // $enableUserEmail, irrelevant
|
||||
[ null, null ], // $targetAndType, irrelevant
|
||||
$user,
|
||||
[] // $rights, irrelevant
|
||||
$performer
|
||||
);
|
||||
$this->assertTrue(
|
||||
$blockPermissionChecker->checkBlockPermissions()
|
||||
|
|
@ -177,21 +155,17 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
true, // sitewide
|
||||
$blockedBy
|
||||
);
|
||||
$user = $this->createMock( User::class );
|
||||
$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';
|
||||
} );
|
||||
$rights = $unblockSelf ? [ 'unblockself' ] : [];
|
||||
|
||||
$blocker = new UserIdentityValue( 1, 'blocker', UserIdentity::LOCAL );
|
||||
$performer = $this->mockUserAuthorityWithBlock( $blocker, $block, $rights );
|
||||
|
||||
$target = new UserIdentityValue( $targetUserId, $targetUserName );
|
||||
|
||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||
true, // $enableUserEmail, irrelevant
|
||||
[ $target, AbstractBlock::TYPE_USER ], // $targetAndType, irrelevant
|
||||
$user,
|
||||
$unblockSelf ? [ 'unblockself' ] : []
|
||||
$performer
|
||||
);
|
||||
$this->assertSame(
|
||||
$expect,
|
||||
|
|
@ -212,12 +186,11 @@ class BlockPermissionCheckerTest extends MediaWikiUnitTestCase {
|
|||
* @dataProvider provideCheckEmailPermissions
|
||||
*/
|
||||
public function testCheckEmailPermissionOkay( $enableEmail, $rights, $expect ) {
|
||||
$user = new UserIdentityValue( 4, 'admin' );
|
||||
$performer = $this->mockRegisteredAuthorityWithPermissions( $rights );
|
||||
$blockPermissionChecker = $this->getBlockPermissionChecker(
|
||||
$enableEmail,
|
||||
[ null, null ], // $targetAndType, irrelevant
|
||||
$user,
|
||||
$rights
|
||||
$performer
|
||||
);
|
||||
$this->assertSame( $expect, $blockPermissionChecker->checkEmailPermissions() );
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue