36 use UserRequirementsConditionFormatterTrait;
39 private const RESTRICTED_GROUPS_ID_PREFIX =
'group_restrictions-';
50 parent::__construct(
'Listgrouprights' );
63 $out->addModuleStyles(
'mediawiki.special' );
64 $this->
addHelpLink(
'Help:User_rights_and_groups' );
66 $out->wrapWikiMsg(
"<div class=\"mw-listgrouprights-key\">\n$1\n</div>",
'listgrouprights-key' );
69 Html::openElement(
'table', [
'class' => [
'wikitable',
'mw-listgrouprights-table' ] ] ) .
81 $allGroups = array_merge(
82 $this->userGroupManager->listAllGroups(),
83 $this->userGroupManager->listAllImplicitGroups()
89 $restrictedGroups = $this->restrictedUserGroupConfigReader->getConfig();
91 foreach ( $allGroups as $group ) {
92 $permissions = $this->groupPermissionsLookup->getGrantedPermissions( $group );
93 $groupname = ( $group ==
'*' )
97 $groupnameLocalized = $lang->getGroupName( $groupname );
99 $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $groupname )
100 ?: Title::makeTitleSafe(
NS_PROJECT, $groupname );
102 if ( $group ==
'*' || !$grouppageLocalizedTitle ) {
104 $grouppage = htmlspecialchars( $groupnameLocalized );
106 $grouppage = $linkRenderer->makeLink(
107 $grouppageLocalizedTitle,
112 $groupWithParentheses = $this->
msg(
'parentheses' )->rawParams( $group )->escaped();
113 $groupname =
"<br /><code>$groupWithParentheses</code>";
115 if ( $group ===
'user' ) {
117 $grouplink =
'<br />' . $linkRenderer->makeKnownLink(
119 $this->
msg(
'listgrouprights-members' )->text()
122 $grouplink =
'<br />' . $linkRenderer->makeKnownLink(
124 $this->
msg(
'listgrouprights-members' )->text(),
126 [
'group' => $group ]
133 $restrictionsLink =
'';
134 if ( array_key_exists( $group, $restrictedGroups ) && $restrictedGroups[$group]->hasAnyConditions() ) {
135 $restrictionsSection = Sanitizer::escapeIdForAttribute( self::RESTRICTED_GROUPS_ID_PREFIX . $group );
136 $restrictionsLink = Html::rawElement(
'p', [],
137 $this->
msg(
'listgrouprights-restricted' )
138 ->params(
'#' . $restrictionsSection )
143 $revoke = $this->groupPermissionsLookup->getRevokedPermissions( $group );
144 $addgroups = $addGroups[$group] ?? [];
145 $removegroups = $removeGroups[$group] ?? [];
146 $addgroupsSelf = $groupsAddToSelf[$group] ?? [];
147 $removegroupsSelf = $groupsRemoveFromSelf[$group] ?? [];
149 $id = $group ==
'*' ? false : Sanitizer::escapeIdForAttribute( $group );
150 $out->addHTML( Html::rawElement(
'tr', [
'id' => $id ],
"
151 <td>$grouppage$groupname$grouplink$restrictionsLink</td>
153 $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups,
154 $addgroupsSelf, $removegroupsSelf ) .
159 $out->addHTML( Html::closeElement(
'table' ) );
160 $this->outputRestrictedGroupsConfig();
161 $this->outputNamespaceProtectionInfo();
164 private function outputNamespaceProtectionInfo() {
168 if ( count( $namespaceProtection ) == 0 ) {
172 $header = $this->
msg(
'listgrouprights-namespaceprotection-header' )->text();
175 'id' => Sanitizer::escapeIdForAttribute( $header )
177 Html::openElement(
'table', [
'class' =>
'wikitable' ] ) .
181 $this->
msg(
'listgrouprights-namespaceprotection-namespace' )->text()
186 $this->
msg(
'listgrouprights-namespaceprotection-restrictedto' )->text()
190 ksort( $namespaceProtection );
191 $validNamespaces = $this->nsInfo->getValidNamespaces();
192 foreach ( $namespaceProtection as $namespace => $rights ) {
193 if ( !in_array( $namespace, $validNamespaces ) ) {
198 $namespaceText = $this->
msg(
'blanknamespace' )->text();
200 $namespaceText = $this->languageConverter->convertNamespace( $namespace );
204 Html::openElement(
'tr' ) .
208 $linkRenderer->makeLink(
212 [
'namespace' => $namespace ]
215 Html::openElement(
'td' ) . Html::openElement(
'ul' )
218 if ( !is_array( $rights ) ) {
219 $rights = [ $rights ];
222 foreach ( $rights as $right ) {
223 $out->addHTML( Html::rawElement(
'li', [],
224 $this->
msg(
'listgrouprights-right-display' )
225 ->params( User::getRightDescription( $right ) )
228 [
'class' =>
'mw-listgrouprights-right-name' ],
235 Html::closeElement(
'ul' ) .
236 Html::closeElement(
'td' ) .
237 Html::closeElement(
'tr' )
240 $out->addHTML( Html::closeElement(
'table' ) );
243 private function outputRestrictedGroupsConfig() {
245 $restrictedGroups = $this->restrictedUserGroupConfigReader->getConfig();
247 $allGroups = array_merge(
248 $this->userGroupManager->listAllGroups(),
249 $this->userGroupManager->listAllImplicitGroups()
251 $restrictedGroups = array_filter(
253 static fn ( $restriction, $group ) => in_array( $group, $allGroups ) && $restriction->hasAnyConditions(),
254 ARRAY_FILTER_USE_BOTH
257 if ( !$restrictedGroups ) {
261 $header = $this->
msg(
'listgrouprights-restrictedgroups-header' )->text();
264 'id' => Sanitizer::escapeIdForAttribute( self::RESTRICTED_GROUPS_SECTION_ID )
266 Html::openElement(
'table', [
'class' =>
'wikitable mw-listgrouprights-table' ] ) .
267 Html::rawElement(
'tr', [],
271 $this->
msg(
'listgrouprights-group' )->text()
276 $this->
msg(
'listgrouprights-restrictedgroups-config' )->text()
280 ksort( $restrictedGroups );
284 foreach ( $restrictedGroups as $group => $groupConfig ) {
288 [
'id' => Sanitizer::escapeIdForAttribute( self::RESTRICTED_GROUPS_ID_PREFIX . $group ) ]
293 $linkRenderer->makeKnownLink(
295 $lang->getGroupName( $group )
298 Html::openElement(
'td' )
301 $conditionsParts = [];
302 $memberConditions = $groupConfig->getMemberConditions();
303 if ( $memberConditions ) {
304 $memberHtml = $this->
msg(
'listgrouprights-restrictedgroups-memberconditions' )->parse();
305 $memberHtml .= Html::rawElement(
'ul', [],
306 Html::rawElement(
'li', [], $this->formatCondition( $memberConditions ) )
308 $conditionsParts[] = $memberHtml;
310 $updaterConditions = $groupConfig->getUpdaterConditions();
311 if ( $updaterConditions ) {
312 $updaterHtml = $this->
msg(
'listgrouprights-restrictedgroups-updaterconditions' )->parse();
313 $updaterHtml .= Html::rawElement(
'ul', [],
314 Html::rawElement(
'li', [], $this->formatCondition( $updaterConditions ) )
316 $conditionsParts[] = $updaterHtml;
318 if ( $groupConfig->canBeIgnored() ) {
319 $conditionsParts[] = $this->
msg(
'listgrouprights-restrictedgroups-bypassable' )
320 ->params( User::getRightDescription(
'ignore-restricted-groups' ) )
321 ->rawParams(
Html::element(
'code', [],
'ignore-restricted-groups' ) )
324 if ( $groupConfig->allowsAutomaticDemotion() ) {
325 $conditionsParts[] = $this->
msg(
'listgrouprights-restrictedgroups-autodemotion' )->parse();
327 $out->addHTML( implode(
'', $conditionsParts ) );
330 Html::closeElement(
'td' ) .
331 Html::closeElement(
'tr' )
334 $out->addHTML( Html::closeElement(
'table' ) );
348 private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
350 foreach ( $permissions as $permission ) {
352 if ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) {
353 $r[] = $this->
msg(
'listgrouprights-right-display' )
354 ->params( User::getRightDescription( $permission ) )
357 [
'class' =>
'mw-listgrouprights-right-name' ],
362 foreach ( $revoke as $permission ) {
363 $r[] = $this->
msg(
'listgrouprights-right-revoked' )
364 ->params( User::getRightDescription( $permission ) )
367 [
'class' =>
'mw-listgrouprights-right-name' ],
374 $allGroups = $this->userGroupManager->listAllGroups();
378 'removegroup' => $remove,
379 'addgroup-self' => $addSelf,
380 'removegroup-self' => $removeSelf
383 foreach ( $changeGroups as $messageKey => $changeGroup ) {
385 if ( $changeGroup ===
true ) {
388 $r[] = $this->
msg(
'listgrouprights-' . $messageKey .
'-all' )->escaped();
389 } elseif ( is_array( $changeGroup ) ) {
390 $changeGroup = array_intersect( array_values( array_unique( $changeGroup ) ), $allGroups );
391 if ( count( $changeGroup ) ) {
393 foreach ( $changeGroup as $group ) {
394 $groupLinks[] = UserGroupMembership::getLinkWiki( $group, $this->
getContext() );
398 $r[] = $this->
msg(
'listgrouprights-' . $messageKey,
407 return '<ul><li>' . implode(
"</li>\n<li>", $r ) .
'</li></ul>';