MediaWiki  master
SpecialListGroupRights.php
Go to the documentation of this file.
1 <?php
24 namespace MediaWiki\Specials;
25 
38 use Xml;
39 
48 
49  private NamespaceInfo $nsInfo;
50  private UserGroupManager $userGroupManager;
51  private ILanguageConverter $languageConverter;
52  private GroupPermissionsLookup $groupPermissionsLookup;
53 
60  public function __construct(
61  NamespaceInfo $nsInfo,
62  UserGroupManager $userGroupManager,
63  LanguageConverterFactory $languageConverterFactory,
64  GroupPermissionsLookup $groupPermissionsLookup
65  ) {
66  parent::__construct( 'Listgrouprights' );
67  $this->nsInfo = $nsInfo;
68  $this->userGroupManager = $userGroupManager;
69  $this->languageConverter = $languageConverterFactory->getLanguageConverter( $this->getContentLanguage() );
70  $this->groupPermissionsLookup = $groupPermissionsLookup;
71  }
72 
77  public function execute( $par ) {
78  $this->setHeaders();
79  $this->outputHeader();
80 
81  $out = $this->getOutput();
82  $out->addModuleStyles( 'mediawiki.special' );
83  $this->addHelpLink( 'Help:User_rights_and_groups' );
84 
85  $out->wrapWikiMsg( "<div class=\"mw-listgrouprights-key\">\n$1\n</div>", 'listgrouprights-key' );
86 
87  $out->addHTML(
88  Xml::openElement( 'table', [ 'class' => 'wikitable mw-listgrouprights-table' ] ) .
89  '<tr>' .
90  Xml::element( 'th', null, $this->msg( 'listgrouprights-group' )->text() ) .
91  Xml::element( 'th', null, $this->msg( 'listgrouprights-rights' )->text() ) .
92  '</tr>'
93  );
94 
95  $config = $this->getConfig();
96  $addGroups = $config->get( MainConfigNames::AddGroups );
97  $removeGroups = $config->get( MainConfigNames::RemoveGroups );
98  $groupsAddToSelf = $config->get( MainConfigNames::GroupsAddToSelf );
99  $groupsRemoveFromSelf = $config->get( MainConfigNames::GroupsRemoveFromSelf );
100  $allGroups = array_merge(
101  $this->userGroupManager->listAllGroups(),
102  $this->userGroupManager->listAllImplicitGroups()
103  );
104  asort( $allGroups );
105 
106  $linkRenderer = $this->getLinkRenderer();
107  $lang = $this->getLanguage();
108 
109  foreach ( $allGroups as $group ) {
110  $permissions = $this->groupPermissionsLookup->getGrantedPermissions( $group );
111  $groupname = ( $group == '*' ) // Replace * with a more descriptive groupname
112  ? 'all'
113  : $group;
114 
115  $groupnameLocalized = $lang->getGroupName( $groupname );
116 
117  $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $groupname )
118  ?: Title::makeTitleSafe( NS_PROJECT, $groupname );
119 
120  if ( $group == '*' || !$grouppageLocalizedTitle ) {
121  // Do not make a link for the generic * group or group with invalid group page
122  $grouppage = htmlspecialchars( $groupnameLocalized );
123  } else {
124  $grouppage = $linkRenderer->makeLink(
125  $grouppageLocalizedTitle,
126  $groupnameLocalized
127  );
128  }
129 
130  $groupWithParentheses = $this->msg( 'parentheses' )->rawParams( $group )->escaped();
131  $groupname = "<br /><code>$groupWithParentheses</code>";
132 
133  if ( $group === 'user' ) {
134  // Link to Special:listusers for implicit group 'user'
135  $grouplink = '<br />' . $linkRenderer->makeKnownLink(
136  SpecialPage::getTitleFor( 'Listusers' ),
137  $this->msg( 'listgrouprights-members' )->text()
138  );
139  } elseif ( !in_array( $group, $config->get( MainConfigNames::ImplicitGroups ) ) ) {
140  $grouplink = '<br />' . $linkRenderer->makeKnownLink(
141  SpecialPage::getTitleFor( 'Listusers' ),
142  $this->msg( 'listgrouprights-members' )->text(),
143  [],
144  [ 'group' => $group ]
145  );
146  } else {
147  // No link to Special:listusers for other implicit groups as they are unlistable
148  $grouplink = '';
149  }
150 
151  $revoke = $this->groupPermissionsLookup->getRevokedPermissions( $group );
152  $addgroups = $addGroups[$group] ?? [];
153  $removegroups = $removeGroups[$group] ?? [];
154  $addgroupsSelf = $groupsAddToSelf[$group] ?? [];
155  $removegroupsSelf = $groupsRemoveFromSelf[$group] ?? [];
156 
157  $id = $group == '*' ? false : Sanitizer::escapeIdForAttribute( $group );
158  $out->addHTML( Html::rawElement( 'tr', [ 'id' => $id ], "
159  <td>$grouppage$groupname$grouplink</td>
160  <td>" .
161  $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups,
162  $addgroupsSelf, $removegroupsSelf ) .
163  '</td>
164  '
165  ) );
166  }
167  $out->addHTML( Xml::closeElement( 'table' ) );
168  $this->outputNamespaceProtectionInfo();
169  }
170 
171  private function outputNamespaceProtectionInfo() {
172  $out = $this->getOutput();
173  $namespaceProtection = $this->getConfig()->get( MainConfigNames::NamespaceProtection );
174 
175  if ( count( $namespaceProtection ) == 0 ) {
176  return;
177  }
178 
179  $header = $this->msg( 'listgrouprights-namespaceprotection-header' )->text();
180  $out->addHTML(
181  Html::element( 'h2', [
183  ], $header ) .
184  Xml::openElement( 'table', [ 'class' => 'wikitable' ] ) .
186  'th',
187  [],
188  $this->msg( 'listgrouprights-namespaceprotection-namespace' )->text()
189  ) .
191  'th',
192  [],
193  $this->msg( 'listgrouprights-namespaceprotection-restrictedto' )->text()
194  )
195  );
196  $linkRenderer = $this->getLinkRenderer();
197  ksort( $namespaceProtection );
198  $validNamespaces = $this->nsInfo->getValidNamespaces();
199  foreach ( $namespaceProtection as $namespace => $rights ) {
200  if ( !in_array( $namespace, $validNamespaces ) ) {
201  continue;
202  }
203 
204  if ( $namespace == NS_MAIN ) {
205  $namespaceText = $this->msg( 'blanknamespace' )->text();
206  } else {
207  $namespaceText = $this->languageConverter->convertNamespace( $namespace );
208  }
209 
210  $out->addHTML(
211  Xml::openElement( 'tr' ) .
213  'td',
214  [],
215  $linkRenderer->makeLink(
216  SpecialPage::getTitleFor( 'Allpages' ),
217  $namespaceText,
218  [],
219  [ 'namespace' => $namespace ]
220  )
221  ) .
222  Xml::openElement( 'td' ) . Xml::openElement( 'ul' )
223  );
224 
225  if ( !is_array( $rights ) ) {
226  $rights = [ $rights ];
227  }
228 
229  foreach ( $rights as $right ) {
230  $out->addHTML( Html::rawElement( 'li', [],
231  $this->msg( 'listgrouprights-right-display' )
232  ->params( User::getRightDescription( $right ) )
233  ->rawParams( Html::element(
234  'span',
235  [ 'class' => 'mw-listgrouprights-right-name' ],
236  $right
237  ) )->parse()
238  ) );
239  }
240 
241  $out->addHTML(
242  Xml::closeElement( 'ul' ) .
243  Xml::closeElement( 'td' ) .
244  Xml::closeElement( 'tr' )
245  );
246  }
247  $out->addHTML( Xml::closeElement( 'table' ) );
248  }
249 
261  private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
262  $r = [];
263  foreach ( $permissions as $permission ) {
264  // show as granted only if it isn't revoked to prevent duplicate display of permissions
265  if ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) {
266  $r[] = $this->msg( 'listgrouprights-right-display' )
267  ->params( User::getRightDescription( $permission ) )
268  ->rawParams( Html::element(
269  'span',
270  [ 'class' => 'mw-listgrouprights-right-name' ],
271  $permission
272  ) )->parse();
273  }
274  }
275  foreach ( $revoke as $permission ) {
276  $r[] = $this->msg( 'listgrouprights-right-revoked' )
277  ->params( User::getRightDescription( $permission ) )
278  ->rawParams( Html::element(
279  'span',
280  [ 'class' => 'mw-listgrouprights-right-name' ],
281  $permission
282  ) )->parse();
283  }
284 
285  sort( $r );
286 
287  $lang = $this->getLanguage();
288  $allGroups = $this->userGroupManager->listAllGroups();
289 
290  $changeGroups = [
291  'addgroup' => $add,
292  'removegroup' => $remove,
293  'addgroup-self' => $addSelf,
294  'removegroup-self' => $removeSelf
295  ];
296 
297  foreach ( $changeGroups as $messageKey => $changeGroup ) {
298  // @phan-suppress-next-line PhanTypeComparisonFromArray
299  if ( $changeGroup === true ) {
300  // For grep: listgrouprights-addgroup-all, listgrouprights-removegroup-all,
301  // listgrouprights-addgroup-self-all, listgrouprights-removegroup-self-all
302  $r[] = $this->msg( 'listgrouprights-' . $messageKey . '-all' )->escaped();
303  } elseif ( is_array( $changeGroup ) ) {
304  $changeGroup = array_intersect( array_values( array_unique( $changeGroup ) ), $allGroups );
305  if ( count( $changeGroup ) ) {
306  $groupLinks = [];
307  foreach ( $changeGroup as $group ) {
308  $groupLinks[] = UserGroupMembership::getLinkWiki( $group, $this->getContext() );
309  }
310  // For grep: listgrouprights-addgroup, listgrouprights-removegroup,
311  // listgrouprights-addgroup-self, listgrouprights-removegroup-self
312  $r[] = $this->msg( 'listgrouprights-' . $messageKey,
313  $lang->listToText( $groupLinks ), count( $changeGroup ) )->parse();
314  }
315  }
316  }
317 
318  if ( !$r ) {
319  return '';
320  } else {
321  return '<ul><li>' . implode( "</li>\n<li>", $r ) . '</li></ul>';
322  }
323  }
324 
325  protected function getGroupName() {
326  return 'users';
327  }
328 }
329 
333 class_alias( SpecialListGroupRights::class, 'SpecialListGroupRights' );
const NS_MAIN
Definition: Defines.php:64
const NS_PROJECT
Definition: Defines.php:68
This class is a collection of static functions that serve two purposes:
Definition: Html.php:57
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:235
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:256
An interface for creating language converters.
getLanguageConverter( $language=null)
Provide a LanguageConverter for given language.
A class containing constants representing the names of configuration variables.
const ImplicitGroups
Name constant for the ImplicitGroups setting, for use with Config::get()
const NamespaceProtection
Name constant for the NamespaceProtection setting, for use with Config::get()
const GroupsRemoveFromSelf
Name constant for the GroupsRemoveFromSelf setting, for use with Config::get()
const AddGroups
Name constant for the AddGroups setting, for use with Config::get()
const GroupsAddToSelf
Name constant for the GroupsAddToSelf setting, for use with Config::get()
const RemoveGroups
Name constant for the RemoveGroups setting, for use with Config::get()
HTML sanitizer for MediaWiki.
Definition: Sanitizer.php:46
static escapeIdForAttribute( $id, $mode=self::ID_PRIMARY)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid HTM...
Definition: Sanitizer.php:951
Parent class for all special pages.
Definition: SpecialPage.php:66
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getContentLanguage()
Shortcut to get content language.
getLanguage()
Shortcut to get user's language.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
This special page lists all defined user groups and the associated rights.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
__construct(NamespaceInfo $nsInfo, UserGroupManager $userGroupManager, LanguageConverterFactory $languageConverterFactory, GroupPermissionsLookup $groupPermissionsLookup)
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Represents a title within MediaWiki.
Definition: Title.php:76
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:650
Represents a "user group membership" – a specific instance of a user belonging to a group.
static getGroupPage( $group)
Gets the title of a page describing a particular user group.
static getLinkWiki( $ugm, IContextSource $context, $userName=null)
Gets a link for a user group, possibly including the expiry date if relevant.
internal since 1.36
Definition: User.php:98
static getRightDescription( $right)
Get the description of a given right.
Definition: User.php:3315
Module of static functions for generating XML.
Definition: Xml.php:33
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:120
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:111
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:46
The shared interface for all language converters.
$header