Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 180 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
SpecialListGroupRights | |
0.00% |
0 / 179 |
|
0.00% |
0 / 5 |
870 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 70 |
|
0.00% |
0 / 1 |
90 | |||
outputNamespaceProtectionInfo | |
0.00% |
0 / 62 |
|
0.00% |
0 / 1 |
56 | |||
formatPermissions | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
132 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Implements Special:Listgrouprights |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup SpecialPage |
22 | */ |
23 | |
24 | namespace MediaWiki\Specials; |
25 | |
26 | use ILanguageConverter; |
27 | use MediaWiki\Html\Html; |
28 | use MediaWiki\Languages\LanguageConverterFactory; |
29 | use MediaWiki\MainConfigNames; |
30 | use MediaWiki\Parser\Sanitizer; |
31 | use MediaWiki\Permissions\GroupPermissionsLookup; |
32 | use MediaWiki\SpecialPage\SpecialPage; |
33 | use MediaWiki\Title\NamespaceInfo; |
34 | use MediaWiki\Title\Title; |
35 | use MediaWiki\User\User; |
36 | use MediaWiki\User\UserGroupManager; |
37 | use MediaWiki\User\UserGroupMembership; |
38 | |
39 | /** |
40 | * This special page lists all defined user groups and the associated rights. |
41 | * See also @ref $wgGroupPermissions. |
42 | * |
43 | * @ingroup SpecialPage |
44 | * @author Petr Kadlec <mormegil@centrum.cz> |
45 | */ |
46 | class SpecialListGroupRights extends SpecialPage { |
47 | |
48 | private NamespaceInfo $nsInfo; |
49 | private UserGroupManager $userGroupManager; |
50 | private ILanguageConverter $languageConverter; |
51 | private GroupPermissionsLookup $groupPermissionsLookup; |
52 | |
53 | /** |
54 | * @param NamespaceInfo $nsInfo |
55 | * @param UserGroupManager $userGroupManager |
56 | * @param LanguageConverterFactory $languageConverterFactory |
57 | * @param GroupPermissionsLookup $groupPermissionsLookup |
58 | */ |
59 | public function __construct( |
60 | NamespaceInfo $nsInfo, |
61 | UserGroupManager $userGroupManager, |
62 | LanguageConverterFactory $languageConverterFactory, |
63 | GroupPermissionsLookup $groupPermissionsLookup |
64 | ) { |
65 | parent::__construct( 'Listgrouprights' ); |
66 | $this->nsInfo = $nsInfo; |
67 | $this->userGroupManager = $userGroupManager; |
68 | $this->languageConverter = $languageConverterFactory->getLanguageConverter( $this->getContentLanguage() ); |
69 | $this->groupPermissionsLookup = $groupPermissionsLookup; |
70 | } |
71 | |
72 | /** |
73 | * Show the special page |
74 | * @param string|null $par |
75 | */ |
76 | public function execute( $par ) { |
77 | $this->setHeaders(); |
78 | $this->outputHeader(); |
79 | |
80 | $out = $this->getOutput(); |
81 | $out->addModuleStyles( 'mediawiki.special' ); |
82 | $this->addHelpLink( 'Help:User_rights_and_groups' ); |
83 | |
84 | $out->wrapWikiMsg( "<div class=\"mw-listgrouprights-key\">\n$1\n</div>", 'listgrouprights-key' ); |
85 | |
86 | $out->addHTML( |
87 | Html::openElement( 'table', [ 'class' => 'wikitable mw-listgrouprights-table' ] ) . |
88 | '<tr>' . |
89 | Html::element( 'th', [], $this->msg( 'listgrouprights-group' )->text() ) . |
90 | Html::element( 'th', [], $this->msg( 'listgrouprights-rights' )->text() ) . |
91 | '</tr>' |
92 | ); |
93 | |
94 | $config = $this->getConfig(); |
95 | $addGroups = $config->get( MainConfigNames::AddGroups ); |
96 | $removeGroups = $config->get( MainConfigNames::RemoveGroups ); |
97 | $groupsAddToSelf = $config->get( MainConfigNames::GroupsAddToSelf ); |
98 | $groupsRemoveFromSelf = $config->get( MainConfigNames::GroupsRemoveFromSelf ); |
99 | $allGroups = array_merge( |
100 | $this->userGroupManager->listAllGroups(), |
101 | $this->userGroupManager->listAllImplicitGroups() |
102 | ); |
103 | asort( $allGroups ); |
104 | |
105 | $linkRenderer = $this->getLinkRenderer(); |
106 | $lang = $this->getLanguage(); |
107 | |
108 | foreach ( $allGroups as $group ) { |
109 | $permissions = $this->groupPermissionsLookup->getGrantedPermissions( $group ); |
110 | $groupname = ( $group == '*' ) // Replace * with a more descriptive groupname |
111 | ? 'all' |
112 | : $group; |
113 | |
114 | $groupnameLocalized = $lang->getGroupName( $groupname ); |
115 | |
116 | $grouppageLocalizedTitle = UserGroupMembership::getGroupPage( $groupname ) |
117 | ?: Title::makeTitleSafe( NS_PROJECT, $groupname ); |
118 | |
119 | if ( $group == '*' || !$grouppageLocalizedTitle ) { |
120 | // Do not make a link for the generic * group or group with invalid group page |
121 | $grouppage = htmlspecialchars( $groupnameLocalized ); |
122 | } else { |
123 | $grouppage = $linkRenderer->makeLink( |
124 | $grouppageLocalizedTitle, |
125 | $groupnameLocalized |
126 | ); |
127 | } |
128 | |
129 | $groupWithParentheses = $this->msg( 'parentheses' )->rawParams( $group )->escaped(); |
130 | $groupname = "<br /><code>$groupWithParentheses</code>"; |
131 | |
132 | if ( $group === 'user' ) { |
133 | // Link to Special:listusers for implicit group 'user' |
134 | $grouplink = '<br />' . $linkRenderer->makeKnownLink( |
135 | SpecialPage::getTitleFor( 'Listusers' ), |
136 | $this->msg( 'listgrouprights-members' )->text() |
137 | ); |
138 | } elseif ( !in_array( $group, $config->get( MainConfigNames::ImplicitGroups ) ) ) { |
139 | $grouplink = '<br />' . $linkRenderer->makeKnownLink( |
140 | SpecialPage::getTitleFor( 'Listusers' ), |
141 | $this->msg( 'listgrouprights-members' )->text(), |
142 | [], |
143 | [ 'group' => $group ] |
144 | ); |
145 | } else { |
146 | // No link to Special:listusers for other implicit groups as they are unlistable |
147 | $grouplink = ''; |
148 | } |
149 | |
150 | $revoke = $this->groupPermissionsLookup->getRevokedPermissions( $group ); |
151 | $addgroups = $addGroups[$group] ?? []; |
152 | $removegroups = $removeGroups[$group] ?? []; |
153 | $addgroupsSelf = $groupsAddToSelf[$group] ?? []; |
154 | $removegroupsSelf = $groupsRemoveFromSelf[$group] ?? []; |
155 | |
156 | $id = $group == '*' ? false : Sanitizer::escapeIdForAttribute( $group ); |
157 | $out->addHTML( Html::rawElement( 'tr', [ 'id' => $id ], " |
158 | <td>$grouppage$groupname$grouplink</td> |
159 | <td>" . |
160 | $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups, |
161 | $addgroupsSelf, $removegroupsSelf ) . |
162 | '</td> |
163 | ' |
164 | ) ); |
165 | } |
166 | $out->addHTML( Html::closeElement( 'table' ) ); |
167 | $this->outputNamespaceProtectionInfo(); |
168 | } |
169 | |
170 | private function outputNamespaceProtectionInfo() { |
171 | $out = $this->getOutput(); |
172 | $namespaceProtection = $this->getConfig()->get( MainConfigNames::NamespaceProtection ); |
173 | |
174 | if ( count( $namespaceProtection ) == 0 ) { |
175 | return; |
176 | } |
177 | |
178 | $header = $this->msg( 'listgrouprights-namespaceprotection-header' )->text(); |
179 | $out->addHTML( |
180 | Html::element( 'h2', [ |
181 | 'id' => Sanitizer::escapeIdForAttribute( $header ) |
182 | ], $header ) . |
183 | Html::openElement( 'table', [ 'class' => 'wikitable' ] ) . |
184 | Html::element( |
185 | 'th', |
186 | [], |
187 | $this->msg( 'listgrouprights-namespaceprotection-namespace' )->text() |
188 | ) . |
189 | Html::element( |
190 | 'th', |
191 | [], |
192 | $this->msg( 'listgrouprights-namespaceprotection-restrictedto' )->text() |
193 | ) |
194 | ); |
195 | $linkRenderer = $this->getLinkRenderer(); |
196 | ksort( $namespaceProtection ); |
197 | $validNamespaces = $this->nsInfo->getValidNamespaces(); |
198 | foreach ( $namespaceProtection as $namespace => $rights ) { |
199 | if ( !in_array( $namespace, $validNamespaces ) ) { |
200 | continue; |
201 | } |
202 | |
203 | if ( $namespace == NS_MAIN ) { |
204 | $namespaceText = $this->msg( 'blanknamespace' )->text(); |
205 | } else { |
206 | $namespaceText = $this->languageConverter->convertNamespace( $namespace ); |
207 | } |
208 | |
209 | $out->addHTML( |
210 | Html::openElement( 'tr' ) . |
211 | Html::rawElement( |
212 | 'td', |
213 | [], |
214 | $linkRenderer->makeLink( |
215 | SpecialPage::getTitleFor( 'Allpages' ), |
216 | $namespaceText, |
217 | [], |
218 | [ 'namespace' => $namespace ] |
219 | ) |
220 | ) . |
221 | Html::openElement( 'td' ) . Html::openElement( 'ul' ) |
222 | ); |
223 | |
224 | if ( !is_array( $rights ) ) { |
225 | $rights = [ $rights ]; |
226 | } |
227 | |
228 | foreach ( $rights as $right ) { |
229 | $out->addHTML( Html::rawElement( 'li', [], |
230 | $this->msg( 'listgrouprights-right-display' ) |
231 | ->params( User::getRightDescription( $right ) ) |
232 | ->rawParams( Html::element( |
233 | 'span', |
234 | [ 'class' => 'mw-listgrouprights-right-name' ], |
235 | $right |
236 | ) )->parse() |
237 | ) ); |
238 | } |
239 | |
240 | $out->addHTML( |
241 | Html::closeElement( 'ul' ) . |
242 | Html::closeElement( 'td' ) . |
243 | Html::closeElement( 'tr' ) |
244 | ); |
245 | } |
246 | $out->addHTML( Html::closeElement( 'table' ) ); |
247 | } |
248 | |
249 | /** |
250 | * Create a user-readable list of permissions from the given array. |
251 | * |
252 | * @param string[] $permissions Array of granted permissions |
253 | * @param string[] $revoke Array of revoked permissions |
254 | * @param array $add Array of groups this group is allowed to add or true |
255 | * @param array $remove Array of groups this group is allowed to remove or true |
256 | * @param array $addSelf Array of groups this group is allowed to add to self or true |
257 | * @param array $removeSelf Array of group this group is allowed to remove from self or true |
258 | * @return string HTML list of all granted permissions |
259 | */ |
260 | private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) { |
261 | $r = []; |
262 | foreach ( $permissions as $permission ) { |
263 | // show as granted only if it isn't revoked to prevent duplicate display of permissions |
264 | if ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) { |
265 | $r[] = $this->msg( 'listgrouprights-right-display' ) |
266 | ->params( User::getRightDescription( $permission ) ) |
267 | ->rawParams( Html::element( |
268 | 'span', |
269 | [ 'class' => 'mw-listgrouprights-right-name' ], |
270 | $permission |
271 | ) )->parse(); |
272 | } |
273 | } |
274 | foreach ( $revoke as $permission ) { |
275 | $r[] = $this->msg( 'listgrouprights-right-revoked' ) |
276 | ->params( User::getRightDescription( $permission ) ) |
277 | ->rawParams( Html::element( |
278 | 'span', |
279 | [ 'class' => 'mw-listgrouprights-right-name' ], |
280 | $permission |
281 | ) )->parse(); |
282 | } |
283 | |
284 | sort( $r ); |
285 | |
286 | $lang = $this->getLanguage(); |
287 | $allGroups = $this->userGroupManager->listAllGroups(); |
288 | |
289 | $changeGroups = [ |
290 | 'addgroup' => $add, |
291 | 'removegroup' => $remove, |
292 | 'addgroup-self' => $addSelf, |
293 | 'removegroup-self' => $removeSelf |
294 | ]; |
295 | |
296 | foreach ( $changeGroups as $messageKey => $changeGroup ) { |
297 | // @phan-suppress-next-line PhanTypeComparisonFromArray |
298 | if ( $changeGroup === true ) { |
299 | // For grep: listgrouprights-addgroup-all, listgrouprights-removegroup-all, |
300 | // listgrouprights-addgroup-self-all, listgrouprights-removegroup-self-all |
301 | $r[] = $this->msg( 'listgrouprights-' . $messageKey . '-all' )->escaped(); |
302 | } elseif ( is_array( $changeGroup ) ) { |
303 | $changeGroup = array_intersect( array_values( array_unique( $changeGroup ) ), $allGroups ); |
304 | if ( count( $changeGroup ) ) { |
305 | $groupLinks = []; |
306 | foreach ( $changeGroup as $group ) { |
307 | $groupLinks[] = UserGroupMembership::getLinkWiki( $group, $this->getContext() ); |
308 | } |
309 | // For grep: listgrouprights-addgroup, listgrouprights-removegroup, |
310 | // listgrouprights-addgroup-self, listgrouprights-removegroup-self |
311 | $r[] = $this->msg( 'listgrouprights-' . $messageKey, |
312 | $lang->listToText( $groupLinks ), count( $changeGroup ) )->parse(); |
313 | } |
314 | } |
315 | } |
316 | |
317 | if ( !$r ) { |
318 | return ''; |
319 | } else { |
320 | return '<ul><li>' . implode( "</li>\n<li>", $r ) . '</li></ul>'; |
321 | } |
322 | } |
323 | |
324 | protected function getGroupName() { |
325 | return 'users'; |
326 | } |
327 | } |
328 | |
329 | /** @deprecated class alias since 1.41 */ |
330 | class_alias( SpecialListGroupRights::class, 'SpecialListGroupRights' ); |