protected function addPageProtectionWarningHeaders() {
$out = $this->context->getOutput();
if ( $this->mTitle->isProtected( 'edit' ) &&
- MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
- $this->mTitle->getNamespace()
+ MediaWikiServices::getInstance()->getPermissionManager()->getNamespaceRestrictionLevels(
+ $this->getTitle()->getNamespace()
) !== [ '' ]
) {
# Is the title semi-protected?
* @return array
*/
public static function getRestrictionLevels( $index, User $user = null ) {
- return MediaWikiServices::getInstance()->getNamespaceInfo()->
- getRestrictionLevels( $index, $user );
+ return MediaWikiServices::getInstance()
+ ->getPermissionManager()
+ ->getNamespaceRestrictionLevels( $index, $user );
}
/**
'BlockDisablesLogin',
'GroupPermissions',
'RevokePermissions',
- 'AvailableRights'
+ 'AvailableRights',
+ 'NamespaceProtection',
+ 'RestrictionLevels'
];
/** @var ServiceOptions */
return $this->allRights;
}
+ /**
+ * Determine which restriction levels it makes sense to use in a namespace,
+ * optionally filtered by a user's rights.
+ *
+ * @param int $index Index to check
+ * @param UserIdentity|null $user User to check
+ * @return array
+ */
+ public function getNamespaceRestrictionLevels( $index, UserIdentity $user = null ) {
+ if ( !isset( $this->options->get( 'NamespaceProtection' )[$index] ) ) {
+ // All levels are valid if there's no namespace restriction.
+ // But still filter by user, if necessary
+ $levels = $this->options->get( 'RestrictionLevels' );
+ if ( $user ) {
+ $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) {
+ $right = $level;
+ if ( $right == 'sysop' ) {
+ $right = 'editprotected'; // BC
+ }
+ if ( $right == 'autoconfirmed' ) {
+ $right = 'editsemiprotected'; // BC
+ }
+ return $this->userHasRight( $user, $right );
+ } ) );
+ }
+ return $levels;
+ }
+
+ // $wgNamespaceProtection can require one or more rights to edit the namespace, which
+ // may be satisfied by membership in multiple groups each giving a subset of those rights.
+ // A restriction level is redundant if, for any one of the namespace rights, all groups
+ // giving that right also give the restriction level's right. Or, conversely, a
+ // restriction level is not redundant if, for every namespace right, there's at least one
+ // group giving that right without the restriction level's right.
+ //
+ // First, for each right, get a list of groups with that right.
+ $namespaceRightGroups = [];
+ foreach ( (array)$this->options->get( 'NamespaceProtection' )[$index] as $right ) {
+ if ( $right == 'sysop' ) {
+ $right = 'editprotected'; // BC
+ }
+ if ( $right == 'autoconfirmed' ) {
+ $right = 'editsemiprotected'; // BC
+ }
+ if ( $right != '' ) {
+ $namespaceRightGroups[$right] = $this->getGroupsWithPermission( $right );
+ }
+ }
+
+ // Now, go through the protection levels one by one.
+ $usableLevels = [ '' ];
+ foreach ( $this->options->get( 'RestrictionLevels' ) as $level ) {
+ $right = $level;
+ if ( $right == 'sysop' ) {
+ $right = 'editprotected'; // BC
+ }
+ if ( $right == 'autoconfirmed' ) {
+ $right = 'editsemiprotected'; // BC
+ }
+
+ if ( $right != '' &&
+ !isset( $namespaceRightGroups[$right] ) &&
+ ( !$user || $this->userHasRight( $user, $right ) )
+ ) {
+ // Do any of the namespace rights imply the restriction right? (see explanation above)
+ foreach ( $namespaceRightGroups as $groups ) {
+ if ( !array_diff( $groups, $this->getGroupsWithPermission( $right ) ) ) {
+ // Yes, this one does.
+ continue 2;
+ }
+ }
+ // No, keep the restriction level
+ $usableLevels[] = $level;
+ }
+ }
+
+ return $usableLevels;
+ }
+
/**
* Add temporary user rights, only valid for the current scope.
* This is meant for making it possible to programatically trigger certain actions that
* Loads the current state of protection into the object.
*/
function loadData() {
- $levels = MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
+ $levels = MediaWikiServices::getInstance()->getPermissionManager()->getNamespaceRestrictionLevels(
$this->mTitle->getNamespace(), $this->mContext->getUser()
);
$this->mCascade = $this->mTitle->areRestrictionsCascading();
*/
function execute() {
if (
- MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
+ MediaWikiServices::getInstance()->getPermissionManager()->getNamespaceRestrictionLevels(
$this->mTitle->getNamespace()
) === [ '' ]
) {
function buildSelector( $action, $selected ) {
// If the form is disabled, display all relevant levels. Otherwise,
// just show the ones this user can use.
- $levels = MediaWikiServices::getInstance()->getNamespaceInfo()->getRestrictionLevels(
- $this->mTitle->getNamespace(),
- $this->disabled ? null : $this->mContext->getUser()
- );
+ $levels = MediaWikiServices::getInstance()
+ ->getPermissionManager()
+ ->getNamespaceRestrictionLevels(
+ $this->mTitle->getNamespace(),
+ $this->disabled ? null : $this->mContext->getUser()
+ );
$id = 'mwProtect-level-' . $action;
public function getTextboxProtectionCSSClasses( Title $title ) {
$classes = []; // Textarea CSS
if ( $title->isProtected( 'edit' ) &&
- MediaWikiServices::getInstance()->getNamespaceInfo()->
- getRestrictionLevels( $title->getNamespace() ) !== [ '' ]
+ MediaWikiServices::getInstance()->getPermissionManager()
+ ->getNamespaceRestrictionLevels( $title->getNamespace() ) !== [ '' ]
) {
# Is the title semi-protected?
if ( $title->isSemiProtected() ) {
}
if ( $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() &&
- MediaWikiServices::getInstance()->getNamespaceInfo()->
- getRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
+ MediaWikiServices::getInstance()->getPermissionManager()
+ ->getNamespaceRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
) {
$mode = $title->isProtected() ? 'unprotect' : 'protect';
$content_navigation['actions'][$mode] = [
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
/**
* This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of
'ExtraNamespaces',
'ExtraSignatureNamespaces',
'NamespaceContentModels',
- 'NamespaceProtection',
'NamespacesWithSubpages',
'NonincludableNamespaces',
- 'RestrictionLevels',
];
/**
* Determine which restriction levels it makes sense to use in a namespace,
* optionally filtered by a user's rights.
*
- * @todo Move this to PermissionManager and remove the dependency here on permissions-related
- * config settings.
- *
+ * @deprecated since 1.34 User PermissionManager::getNamespaceRestrictionLevels instead.
* @param int $index Index to check
* @param User|null $user User to check
* @return array
*/
public function getRestrictionLevels( $index, User $user = null ) {
- if ( !isset( $this->options->get( 'NamespaceProtection' )[$index] ) ) {
- // All levels are valid if there's no namespace restriction.
- // But still filter by user, if necessary
- $levels = $this->options->get( 'RestrictionLevels' );
- if ( $user ) {
- $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) {
- $right = $level;
- if ( $right == 'sysop' ) {
- $right = 'editprotected'; // BC
- }
- if ( $right == 'autoconfirmed' ) {
- $right = 'editsemiprotected'; // BC
- }
- return ( $right == '' || $user->isAllowed( $right ) );
- } ) );
- }
- return $levels;
- }
-
- // $wgNamespaceProtection can require one or more rights to edit the namespace, which
- // may be satisfied by membership in multiple groups each giving a subset of those rights.
- // A restriction level is redundant if, for any one of the namespace rights, all groups
- // giving that right also give the restriction level's right. Or, conversely, a
- // restriction level is not redundant if, for every namespace right, there's at least one
- // group giving that right without the restriction level's right.
- //
- // First, for each right, get a list of groups with that right.
- $namespaceRightGroups = [];
- foreach ( (array)$this->options->get( 'NamespaceProtection' )[$index] as $right ) {
- if ( $right == 'sysop' ) {
- $right = 'editprotected'; // BC
- }
- if ( $right == 'autoconfirmed' ) {
- $right = 'editsemiprotected'; // BC
- }
- if ( $right != '' ) {
- $namespaceRightGroups[$right] = User::getGroupsWithPermission( $right );
- }
- }
-
- // Now, go through the protection levels one by one.
- $usableLevels = [ '' ];
- foreach ( $this->options->get( 'RestrictionLevels' ) as $level ) {
- $right = $level;
- if ( $right == 'sysop' ) {
- $right = 'editprotected'; // BC
- }
- if ( $right == 'autoconfirmed' ) {
- $right = 'editsemiprotected'; // BC
- }
-
- if ( $right != '' &&
- !isset( $namespaceRightGroups[$right] ) &&
- ( !$user || $user->isAllowed( $right ) )
- ) {
- // Do any of the namespace rights imply the restriction right? (see explanation above)
- foreach ( $namespaceRightGroups as $groups ) {
- if ( !array_diff( $groups, User::getGroupsWithPermission( $right ) ) ) {
- // Yes, this one does.
- continue 2;
- }
- }
- // No, keep the restriction level
- $usableLevels[] = $level;
- }
- }
-
- return $usableLevels;
+ // PermissionManager is not injected because adding an explicit dependency
+ // breaks MW installer by adding a dependency chain on the database before
+ // it was set up. Also, the method is deprecated and will be soon removed.
+ return MediaWikiServices::getInstance()
+ ->getPermissionManager()
+ ->getNamespaceRestrictionLevels( $index, $user );
}
/**
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RevisionLookup;
+use MWException;
use TestAllServiceOptionsUsed;
use Wikimedia\ScopedCallback;
use MediaWiki\Session\SessionId;
'BlockDisablesLogin' => false,
'GroupPermissions' => [],
'RevokePermissions' => [],
- 'AvailableRights' => []
+ 'AvailableRights' => [],
+ 'NamespaceProtection' => [],
+ 'RestrictionLevels' => []
]
),
$services->getSpecialPageFactory(),
return $revision;
}
+ public function provideGetRestrictionLevels() {
+ return [
+ 'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK ],
+ 'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN ],
+ 'Restricted to sysop' => [ [ '' ], NS_USER ],
+ 'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
+ 'No special permissions' => [
+ [ '' ],
+ NS_TALK,
+ []
+ ],
+ 'autoconfirmed' => [
+ [ '', 'autoconfirmed' ],
+ NS_TALK,
+ [ 'autoconfirmed' ]
+ ],
+ 'autoconfirmed revoked' => [
+ [ '' ],
+ NS_TALK,
+ [ 'autoconfirmed', 'noeditsemiprotected' ]
+ ],
+ 'sysop' => [
+ [ '', 'autoconfirmed', 'sysop' ],
+ NS_TALK,
+ [ 'sysop' ]
+ ],
+ 'sysop with autoconfirmed revoked (a bit silly)' => [
+ [ '', 'sysop' ],
+ NS_TALK,
+ [ 'sysop', 'noeditsemiprotected' ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetRestrictionLevels
+ * @covers \MediaWiki\Permissions\PermissionManager::getNamespaceRestrictionLevels
+ *
+ * @param array $expected
+ * @param int $ns
+ * @param array|null $userGroups
+ * @throws MWException
+ */
+ public function testGetRestrictionLevels( array $expected, $ns, array $userGroups = null ) {
+ $this->setMwGlobals( [
+ 'wgGroupPermissions' => [
+ '*' => [ 'edit' => true ],
+ 'autoconfirmed' => [ 'editsemiprotected' => true ],
+ 'sysop' => [
+ 'editsemiprotected' => true,
+ 'editprotected' => true,
+ ],
+ 'privileged' => [ 'privileged' => true ],
+ ],
+ 'wgRevokePermissions' => [
+ 'noeditsemiprotected' => [ 'editsemiprotected' => true ],
+ ],
+ 'wgNamespaceProtection' => [
+ NS_MAIN => 'autoconfirmed',
+ NS_USER => 'sysop',
+ 101 => [ 'editsemiprotected', 'privileged' ],
+ ],
+ 'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
+ 'wgAutopromote' => []
+ ] );
+ $this->resetServices();
+ $user = is_null( $userGroups ) ? null : $this->getTestUser( $userGroups )->getUser();
+ $this->assertSame( $expected, MediaWikiServices::getInstance()
+ ->getPermissionManager()
+ ->getNamespaceRestrictionLevels( $ns, $user ) );
+ }
}
'ExtraNamespaces' => [],
'ExtraSignatureNamespaces' => [],
'NamespaceContentModels' => [],
- 'NamespaceProtection' => [],
'NamespacesWithSubpages' => [
NS_TALK => true,
NS_USER => true,
NS_USER_TALK => true,
],
'NonincludableNamespaces' => [],
- 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
];
private function newObj( array $options = [] ) : NamespaceInfo {
*/
/**
- * This mock user can only have isAllowed() called on it.
- *
- * @param array $groups Groups for the mock user to have
- * @return User
- */
- private function getMockUser( array $groups = [] ) : User {
- $groups[] = '*';
-
- $mock = $this->createMock( User::class );
- $mock->method( 'isAllowed' )->will( $this->returnCallback(
- function ( $action ) use ( $groups ) {
- global $wgGroupPermissions, $wgRevokePermissions;
- if ( $action == '' ) {
- return true;
- }
- foreach ( $wgRevokePermissions as $group => $rights ) {
- if ( !in_array( $group, $groups ) ) {
- continue;
- }
- if ( isset( $rights[$action] ) && $rights[$action] ) {
- return false;
- }
- }
- foreach ( $wgGroupPermissions as $group => $rights ) {
- if ( !in_array( $group, $groups ) ) {
- continue;
- }
- if ( isset( $rights[$action] ) && $rights[$action] ) {
- return true;
- }
- }
- return false;
- }
- ) );
- $mock->expects( $this->never() )->method( $this->anythingBut( 'isAllowed' ) );
- return $mock;
- }
-
- /**
+ * TODO: This is superceeded by PermissionManagerTest::testGetNamespaceRestrictionLevels
+ * Remove when deprecated method is removed.
* @dataProvider provideGetRestrictionLevels
- * @covers NamespaceInfo::getRestrictionLevels
+ * @covers NamespaceInfo::getRestrictionLevels
*
* @param array $expected
* @param int $ns
- * @param User|null $user
+ * @param array|null $groups
+ * @throws MWException
*/
- public function testGetRestrictionLevels( array $expected, $ns, User $user = null ) {
+ public function testGetRestrictionLevels( array $expected, $ns, array $groups = null ) {
$this->setMwGlobals( [
'wgGroupPermissions' => [
'*' => [ 'edit' => true ],
'wgRevokePermissions' => [
'noeditsemiprotected' => [ 'editsemiprotected' => true ],
],
- ] );
- $obj = $this->newObj( [
- 'NamespaceProtection' => [
+ 'wgNamespaceProtection' => [
NS_MAIN => 'autoconfirmed',
NS_USER => 'sysop',
101 => [ 'editsemiprotected', 'privileged' ],
],
+ 'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
+ 'wgAutopromote' => []
] );
+ $this->resetServices();
+ $obj = $this->newObj();
+ $user = is_null( $groups ) ? null : $this->getTestUser( $groups )->getUser();
$this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
}
'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN ],
'Restricted to sysop' => [ [ '' ], NS_USER ],
'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
- 'No special permissions' => [ [ '' ], NS_TALK, $this->getMockUser() ],
+ 'No special permissions' => [ [ '' ], NS_TALK, [] ],
'autoconfirmed' => [
[ '', 'autoconfirmed' ],
NS_TALK,
- $this->getMockUser( [ 'autoconfirmed' ] )
+ [ 'autoconfirmed' ]
],
'autoconfirmed revoked' => [
[ '' ],
NS_TALK,
- $this->getMockUser( [ 'autoconfirmed', 'noeditsemiprotected' ] )
+ [ 'autoconfirmed', 'noeditsemiprotected' ]
],
'sysop' => [
[ '', 'autoconfirmed', 'sysop' ],
NS_TALK,
- $this->getMockUser( [ 'sysop' ] )
+ [ 'sysop' ]
],
'sysop with autoconfirmed revoked (a bit silly)' => [
[ '', 'sysop' ],
NS_TALK,
- $this->getMockUser( [ 'sysop', 'noeditsemiprotected' ] )
+ [ 'sysop', 'noeditsemiprotected' ]
],
];
}