46 parent::__construct(
'Userrights' );
66 if ( $targetUser->getId() === 0 ) {
70 if ( $available[
'add'] || $available[
'remove'] ) {
75 if ( ( $available[
'add-self'] || $available[
'remove-self'] )
96 $session = $request->getSession();
99 $out->addModules( [
'mediawiki.special.userrights' ] );
101 $this->mTarget = $par ?? $request->getVal(
'user' );
103 if ( is_string( $this->mTarget ) ) {
104 $this->mTarget = trim( $this->mTarget );
108 $this->isself =
true;
111 $fetchedStatus = $this->
fetchUser( $this->mTarget,
true );
112 if ( $fetchedStatus->isOK() ) {
113 $this->mFetchedUser = $fetchedStatus->value;
114 if ( $this->mFetchedUser instanceof
User ) {
117 $this->
getSkin()->setRelevantUser( $this->mFetchedUser );
123 $session->get(
'specialUserrightsSaveSuccess' ) &&
124 $this->mFetchedUser !==
null
127 $session->remove(
'specialUserrightsSaveSuccess' );
129 $out->addModuleStyles(
'mediawiki.notification.convertmessagebox.styles' );
134 'class' =>
'mw-notify-success successbox',
135 'id' =>
'mw-preferences-success',
136 'data-mw-autohide' =>
'false',
141 $this->
msg(
'savedrights', $this->mFetchedUser->getName() )->text()
150 $out->addModuleStyles(
'mediawiki.special' );
151 $this->
addHelpLink(
'Help:Assigning permissions' );
156 $request->wasPosted() &&
157 $request->getCheck(
'saveusergroups' ) &&
158 $this->mTarget !==
null &&
159 $user->matchEditToken( $request->getVal(
'wpEditToken' ), $this->mTarget )
166 if ( !MediaWikiServices::getInstance()
168 ->userHasRight( $user,
'userrights' )
170 $block = $user->getBlock();
171 if ( $block && $block->isSitewide() ) {
184 if ( !$fetchedStatus->isOK() ) {
185 $this->
getOutput()->addWikiTextAsInterface(
186 $fetchedStatus->getWikiText(
false,
false, $this->getLanguage() )
193 if ( $targetUser instanceof
User ) {
194 $targetUser->clearInstanceCache();
197 $conflictCheck = $request->getVal(
'conflictcheck-originalgroups' );
198 $conflictCheck = ( $conflictCheck ===
'' ) ? [] : explode(
',', $conflictCheck );
199 $userGroups = $targetUser->getGroups();
201 if ( $userGroups !== $conflictCheck ) {
202 $out->wrapWikiMsg(
'<span class="error">$1</span>',
'userrights-conflict' );
206 $request->getVal(
'user-reason' ),
210 if ( $status->isOK() ) {
212 $session->set(
'specialUserrightsSaveSuccess', 1 );
218 $out->wrapWikiTextAsInterface(
219 'error', $status->getWikiText(
false,
false, $this->getLanguage() )
226 if ( $this->mTarget !==
null ) {
232 return $this->
getPageTitle( $this->mTarget )->getFullURL();
259 $unix = strtotime( $expiry );
261 if ( !$unix || $unix === -1 ) {
284 $existingUGMs = $user->getGroupMemberships();
288 foreach ( $allgroups as $group ) {
291 if ( $this->
getRequest()->getCheck(
"wpGroup-$group" ) ) {
292 $addgroup[] = $group;
296 $expiryDropdown = $this->
getRequest()->getVal(
"wpExpiry-$group" );
297 if ( $expiryDropdown ===
'existing' ) {
301 if ( $expiryDropdown ===
'other' ) {
302 $expiryValue = $this->
getRequest()->getVal(
"wpExpiry-$group-other" );
304 $expiryValue = $expiryDropdown;
310 if ( $groupExpiries[$group] ===
false ) {
311 return Status::newFatal(
'userrights-invalid-expiry', $group );
315 if ( $groupExpiries[$group] && $groupExpiries[$group] <
wfTimestampNow() ) {
316 return Status::newFatal(
'userrights-expiry-in-past', $group );
322 isset( $existingUGMs[$group] ) &&
323 ( $existingUGMs[$group]->getExpiry() ?:
'infinity' ) >
324 ( $groupExpiries[$group] ?:
'infinity' )
326 return Status::newFatal(
'userrights-cannot-shorten-expiry', $group );
330 $removegroup[] = $group;
334 $this->
doSaveUserGroups( $user, $addgroup, $removegroup, $reason, [], $groupExpiries );
336 return Status::newGood();
353 array $tags = [], array $groupExpiries = []
357 $groups = $user->getGroups();
358 $ugms = $user->getGroupMemberships();
360 $addable = array_merge( $changeable[
'add'],
$isself ? $changeable[
'add-self'] : [] );
361 $removable = array_merge( $changeable[
'remove'],
$isself ? $changeable[
'remove-self'] : [] );
363 $remove = array_unique( array_intersect( $remove, $removable, $groups ) );
364 $add = array_intersect( $add, $addable );
369 $add = array_filter( $add,
370 function ( $group ) use ( $groups, $groupExpiries, $removable, $ugms ) {
371 if ( isset( $groupExpiries[$group] ) &&
372 !in_array( $group, $removable ) &&
373 isset( $ugms[$group] ) &&
374 ( $ugms[$group]->getExpiry() ?:
'infinity' ) >
375 ( $groupExpiries[$group] ?:
'infinity' )
379 return !in_array( $group, $groups ) || array_key_exists( $group, $groupExpiries );
384 $oldGroups = $groups;
385 $oldUGMs = $user->getGroupMemberships();
386 $newGroups = $oldGroups;
390 foreach ( $remove as $index => $group ) {
391 if ( !$user->removeGroup( $group ) ) {
392 unset( $remove[$index] );
395 $newGroups = array_diff( $newGroups, $remove );
398 foreach ( $add as $index => $group ) {
399 $expiry = $groupExpiries[$group] ??
null;
400 if ( !$user->addGroup( $group, $expiry ) ) {
401 unset( $add[$index] );
404 $newGroups = array_merge( $newGroups, $add );
406 $newGroups = array_unique( $newGroups );
407 $newUGMs = $user->getGroupMemberships();
410 $user->invalidateCache();
413 $this->
getHookRunner()->onUserGroupsChanged( $user, $add, $remove,
414 $this->
getUser(), $reason, $oldUGMs, $newUGMs );
416 wfDebug(
'oldGroups: ' . print_r( $oldGroups,
true ) );
417 wfDebug(
'newGroups: ' . print_r( $newGroups,
true ) );
418 wfDebug(
'oldUGMs: ' . print_r( $oldUGMs,
true ) );
419 wfDebug(
'newUGMs: ' . print_r( $newUGMs,
true ) );
422 if ( $newGroups != $oldGroups || $newUGMs != $oldUGMs ) {
423 $this->
addLogEntry( $user, $oldGroups, $newGroups, $reason, $tags, $oldUGMs, $newUGMs );
426 return [ $add, $remove ];
440 return [
'expiry' => $ugm->getExpiry() ];
453 protected function addLogEntry( $user, array $oldGroups, array $newGroups, $reason,
454 array $tags, array $oldUGMs, array $newUGMs
458 $oldUGMs = array_map(
function ( $group ) use ( $oldUGMs ) {
459 return isset( $oldUGMs[$group] ) ?
463 $newUGMs = array_map(
function ( $group ) use ( $newUGMs ) {
464 return isset( $newUGMs[$group] ) ?
470 $logEntry->setPerformer( $this->
getUser() );
471 $logEntry->setTarget( $user->getUserPage() );
472 $logEntry->setComment( $reason );
473 $logEntry->setParameters( [
474 '4::oldgroups' => $oldGroups,
475 '5::newgroups' => $newGroups,
476 'oldmetadata' => $oldUGMs,
477 'newmetadata' => $newUGMs,
479 $logid = $logEntry->insert();
480 if ( count( $tags ) ) {
481 $logEntry->addTags( $tags );
483 $logEntry->publish( $logid );
491 $status = $this->
fetchUser( $username,
true );
492 if ( !$status->isOK() ) {
493 $this->
getOutput()->addWikiTextAsInterface(
494 $status->getWikiText(
false,
false, $this->getLanguage() )
501 $user = $status->value;
502 '@phan-var User $user';
504 $groups = $user->getGroups();
505 $groupMemberships = $user->getGroupMemberships();
522 public function fetchUser( $username, $writing =
true ) {
523 $parts = explode( $this->
getConfig()->
get(
'UserrightsInterwikiDelimiter' ), $username );
524 if ( count( $parts ) < 2 ) {
525 $name = trim( $username );
528 list( $name, $dbDomain ) = array_map(
'trim', $parts );
530 if ( WikiMap::isCurrentWikiId( $dbDomain ) ) {
533 if ( $writing && !MediaWikiServices::getInstance()
535 ->userHasRight( $this->
getUser(),
'userrights-interwiki' )
537 return Status::newFatal(
'userrights-no-interwiki' );
540 return Status::newFatal(
'userrights-nodatabase', $dbDomain );
545 if ( $name ===
'' ) {
546 return Status::newFatal(
'nouserspecified' );
549 if ( $name[0] ==
'#' ) {
552 $id = intval( substr( $name, 1 ) );
554 if ( $dbDomain ==
'' ) {
561 return Status::newFatal(
'noname' );
565 if ( $name ===
false ) {
567 return Status::newFatal(
'nosuchusershort', $username );
571 if ( $dbDomain ==
'' ) {
577 if ( !$user || $user->isAnon() ) {
578 return Status::newFatal(
'nosuchusershort', $username );
581 if ( $user instanceof
User &&
583 !MediaWikiServices::getInstance()
584 ->getPermissionManager()
585 ->userHasRight( $this->getUser(),
'hideuser' )
588 return Status::newFatal(
'nosuchusershort', $username );
591 return Status::newGood( $user );
602 if ( empty( $ids ) ) {
603 return $this->
msg(
'rightsnone' )->inContentLanguage()->text();
605 return implode(
', ', $ids );
613 $this->
getOutput()->addModules(
'mediawiki.userSuggest' );
622 'id' =>
'mw-userrights-form1'
625 Html::hidden(
'title', $this->
getPageTitle()->getPrefixedText() ) .
626 Xml::fieldset( $this->
msg(
'userrights-lookup-user' )->text() ) .
628 $this->
msg(
'userrights-user-editname' )->text(),
632 $this->mTarget ? str_replace(
'_',
' ', $this->mTarget ) :
'',
634 'class' =>
'mw-autocomplete-user',
637 $this->mFetchedUser ===
null ? [
'autofocus' =>
'' ] : []
641 $this->
msg(
'editusergroup' )->text()
643 Html::closeElement(
'fieldset' ) .
644 Html::closeElement(
'form' ) .
"\n"
658 $list = $membersList = $tempList = $tempMembersList = [];
659 foreach ( $groupMemberships as $ugm ) {
660 $linkG = UserGroupMembership::getLink( $ugm, $this->
getContext(),
'html' );
661 $linkM = UserGroupMembership::getLink( $ugm, $this->
getContext(),
'html',
663 if ( $ugm->getExpiry() ) {
664 $tempList[] = $linkG;
665 $tempMembersList[] = $linkM;
668 $membersList[] = $linkM;
674 $autoMembersList = [];
676 $isUserInstance = $user instanceof
User;
678 if ( $isUserInstance ) {
680 $autoList[] = UserGroupMembership::getLink( $group, $this->
getContext(),
'html' );
681 $autoMembersList[] = UserGroupMembership::getLink( $group, $this->
getContext(),
682 'html', $user->getName() );
687 $displayedList = $this->
msg(
'userrights-groupsmember-type' )
689 $language->commaList( array_merge( $tempList, $list ) ),
690 $language->commaList( array_merge( $tempMembersList, $membersList ) )
692 $displayedAutolist = $this->
msg(
'userrights-groupsmember-type' )
694 $language->commaList( $autoList ),
695 $language->commaList( $autoMembersList )
699 $count = count( $list ) + count( $tempList );
701 $grouplist = $this->
msg(
'userrights-groupsmember' )
702 ->numParams( $count )
703 ->params( $user->getName() )
705 $grouplist =
'<p>' . $grouplist .
' ' . $displayedList .
"</p>\n";
708 $count = count( $autoList );
710 $autogrouplistintro = $this->
msg(
'userrights-groupsmember-auto' )
711 ->numParams( $count )
712 ->params( $user->getName() )
714 $grouplist .=
'<p>' . $autogrouplistintro .
' ' . $displayedAutolist .
"</p>\n";
717 $systemUser = $isUserInstance && $user->isSystemUser();
719 $systemusernote = $this->
msg(
'userrights-systemuser' )
720 ->params( $user->getName() )
722 $grouplist .=
'<p>' . $systemusernote .
"</p>\n";
734 list( $groupCheckboxes, $canChangeAny ) =
742 'name' =>
'editGroup',
743 'id' =>
'mw-userrights-form2'
746 Html::hidden(
'user', $this->mTarget ) .
747 Html::hidden(
'wpEditToken', $this->
getUser()->getEditToken( $this->mTarget ) ) .
749 'conflictcheck-originalgroups',
750 implode(
',', $user->getGroups() )
752 Xml::openElement(
'fieldset' ) .
757 $canChangeAny ?
'userrights-editusergroup' :
'userrights-viewusergroup',
762 $canChangeAny ?
'editinguser' :
'viewinguserrights'
764 ->rawParams( $userToolLinks )->parse()
766 if ( $canChangeAny ) {
768 $this->
msg(
'userrights-groups-help', $user->getName() )->parse() .
771 Xml::openElement(
'table', [
'id' =>
'mw-userrights-table-outer' ] ) .
773 <td class='mw-label'>" .
774 Xml::label( $this->msg(
'userrights-reason' )->text(),
'wpReason' ) .
776 <td class='mw-input'>" .
777 Xml::input(
'user-reason', 60, $this->getRequest()->getVal(
'user-reason',
false ), [
782 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
788 <td class='mw-submit'>" .
789 Xml::submitButton( $this->msg(
'saveusergroups', $user->getName() )->text(),
790 [
'name' =>
'saveusergroups' ] +
795 Xml::closeElement(
'table' ) .
"\n"
798 $this->
getOutput()->addHTML( $grouplist );
801 Xml::closeElement(
'fieldset' ) .
802 Xml::closeElement(
'form' ) .
"\n"
828 $expiryOptionsMsg = $this->
msg(
'userrights-expiry-options' )->inContentLanguage();
829 $expiryOptions = $expiryOptionsMsg->isDisabled()
835 $columns = [
'unchangeable' => [],
'changeable' => [] ];
837 foreach ( $allgroups as $group ) {
838 $set = isset( $usergroups[$group] );
842 $canOnlyLengthenExpiry = ( $set && $this->
canAdd( $group ) &&
843 !$this->
canRemove( $group ) && $usergroups[$group]->getExpiry() );
845 $disabledCheckbox = !(
846 ( $set && $this->
canRemove( $group ) ) ||
847 ( !$set && $this->
canAdd( $group ) ) );
849 $disabledExpiry = $disabledCheckbox && !$canOnlyLengthenExpiry;
851 $irreversible = !$disabledCheckbox && (
852 ( $set && !$this->
canAdd( $group ) ) ||
853 ( !$set && !$this->
canRemove( $group ) ) );
857 'disabled' => $disabledCheckbox,
858 'disabled-expiry' => $disabledExpiry,
859 'irreversible' => $irreversible
862 if ( $disabledCheckbox && $disabledExpiry ) {
863 $columns[
'unchangeable'][$group] = $checkbox;
865 $columns[
'changeable'][$group] = $checkbox;
870 $ret .= Xml::openElement(
'table', [
'class' =>
'mw-userrights-groups' ] ) .
872 foreach ( $columns as $name => $column ) {
873 if ( $column === [] ) {
877 $ret .= Xml::element(
880 $this->
msg(
'userrights-' . $name .
'-col', count( $column ) )->text()
884 $ret .=
"</tr>\n<tr>\n";
885 foreach ( $columns as $column ) {
886 if ( $column === [] ) {
889 $ret .=
"\t<td style='vertical-align:top;'>\n";
890 foreach ( $column as $group => $checkbox ) {
891 $attr = [
'class' =>
'mw-userrights-groupcheckbox' ];
892 if ( $checkbox[
'disabled'] ) {
893 $attr[
'disabled'] =
'disabled';
896 $member = UserGroupMembership::getGroupMemberName( $group, $user->getName() );
897 if ( $checkbox[
'irreversible'] ) {
898 $text = $this->
msg(
'userrights-irreversible-marker', $member )->text();
899 } elseif ( $checkbox[
'disabled'] && !$checkbox[
'disabled-expiry'] ) {
900 $text = $this->
msg(
'userrights-no-shorten-expiry-marker', $member )->text();
904 $checkboxHtml = Xml::checkLabel( $text,
"wpGroup-" . $group,
905 "wpGroup-" . $group, $checkbox[
'set'], $attr );
911 $currentExpiry = isset( $usergroups[$group] ) ?
912 $usergroups[$group]->getExpiry() :
917 if ( $checkbox[
'set'] &&
918 ( $checkbox[
'irreversible'] || $checkbox[
'disabled-expiry'] )
920 if ( $currentExpiry ) {
921 $expiryFormatted = $uiLanguage->userTimeAndDate( $currentExpiry, $uiUser );
922 $expiryFormattedD = $uiLanguage->userDate( $currentExpiry, $uiUser );
923 $expiryFormattedT = $uiLanguage->userTime( $currentExpiry, $uiUser );
924 $expiryHtml = Xml::element(
'span',
null,
925 $this->
msg(
'userrights-expiry-current' )->params(
926 $expiryFormatted, $expiryFormattedD, $expiryFormattedT )->text() );
928 $expiryHtml = Xml::element(
'span',
null,
929 $this->
msg(
'userrights-expiry-none' )->text() );
933 $expiryHtml .= Html::hidden(
"wpExpiry-$group",
934 $currentExpiry ?
'existing' :
'infinite' );
935 $expiryHtml .=
"<br />\n";
937 $expiryHtml = Xml::element(
'span',
null,
938 $this->
msg(
'userrights-expiry' )->text() );
939 $expiryHtml .= Xml::openElement(
'span' );
944 "mw-input-wpExpiry-$group",
945 $currentExpiry ?
'existing' :
'infinite'
947 if ( $checkbox[
'disabled-expiry'] ) {
948 $expiryFormOptions->
setAttribute(
'disabled',
'disabled' );
951 if ( $currentExpiry ) {
952 $timestamp = $uiLanguage->userTimeAndDate( $currentExpiry, $uiUser );
953 $d = $uiLanguage->userDate( $currentExpiry, $uiUser );
954 $t = $uiLanguage->userTime( $currentExpiry, $uiUser );
955 $existingExpiryMessage = $this->
msg(
'userrights-expiry-existing',
956 $timestamp, $d,
$t );
957 $expiryFormOptions->addOption( $existingExpiryMessage->text(),
'existing' );
960 $expiryFormOptions->addOption(
961 $this->
msg(
'userrights-expiry-none' )->text(),
964 $expiryFormOptions->addOption(
965 $this->
msg(
'userrights-expiry-othertime' )->text(),
969 $expiryFormOptions->addOptions( $expiryOptions );
972 $expiryHtml .= $expiryFormOptions->getHTML() .
'<br />';
976 'id' =>
"mw-input-wpExpiry-$group-other",
977 'class' =>
'mw-userrights-expiryfield',
979 if ( $checkbox[
'disabled-expiry'] ) {
980 $attribs[
'disabled'] =
'disabled';
982 $expiryHtml .= Xml::input(
"wpExpiry-$group-other", 30,
'', $attribs );
986 if ( $checkbox[
'set'] && $checkbox[
'disabled'] ) {
987 $expiryHtml .= Html::hidden(
"wpGroup-$group", 1 );
990 $expiryHtml .= Xml::closeElement(
'span' );
994 'id' =>
"mw-userrights-nested-wpGroup-$group",
995 'class' =>
'mw-userrights-nested',
997 $checkboxHtml .=
"\t\t\t" . Xml::tags(
'div', $divAttribs, $expiryHtml ) .
"\n";
999 $ret .=
"\t\t" . ( ( $checkbox[
'disabled'] && $checkbox[
'disabled-expiry'] )
1000 ? Xml::tags(
'div', [
'class' =>
'mw-userrights-disabled' ], $checkboxHtml )
1001 : Xml::tags(
'div', [], $checkboxHtml )
1004 $ret .=
"\t</td>\n";
1006 $ret .= Xml::closeElement(
'tr' ) . Xml::closeElement(
'table' );
1008 return [ $ret, (bool)$columns[
'changeable'] ];
1020 $groups[
'remove'] ) || ( $this->isself && in_array( $group, $groups[
'remove-self'] )
1033 $groups[
'add'] ) || ( $this->isself && in_array( $group, $groups[
'add-self'] )
1048 return $this->
getUser()->changeableGroups();
1058 $rightsLogPage =
new LogPage(
'rights' );
1059 $output->addHTML( Xml::element(
'h2',
null, $rightsLogPage->getName()->text() ) );
1060 LogEventsList::showLogExtract( $output,
'rights', $user->getUserPage() );
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
wfIsInfinity( $str)
Determine input string is represents as infinity.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null, $useParentheses=true)
Generate standard user tool links (talk, contributions, block link, etc.)
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Class to simplify the use of log pages.
Class for creating new log entries and inserting them into the database.
Parent class for all special pages.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!...
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
getSkin()
Shortcut to get the skin being used for this instance.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getConfig()
Shortcut to get main config object.
getRequest()
Get the WebRequest being used for this instance.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getPageTitle( $subpage=false)
Get a self-referential title object.
getLanguage()
Shortcut to get user's language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Show an error when the user tries to do something whilst blocked.
Represents a "user group membership" – a specific instance of a user belonging to a group.
static search( $audience, $search, $limit, $offset=0)
Do a prefix search of user names and return a list of matching user names.
static whoIs( $dbDomain, $id, $ignoreInvalidDB=false)
Same as User::whoIs()
static newFromName( $dbDomain, $name, $ignoreInvalidDB=false)
Factory function; get a remote user entry by name.
static validDatabase( $dbDomain)
Confirm the selected database name is a valid local interwiki database name.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
static getAllGroups()
Return the set of defined explicit groups.
static getCanonicalName( $name, $validate='valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid.
isHidden()
Check if user account is hidden.
static whoIs( $id)
Get the username corresponding to a given user ID.
Special page to allow managing user group membership.
doSaveUserGroups( $user, array $add, array $remove, $reason='', array $tags=[], array $groupExpiries=[])
Save user groups changes in the database.
static expiryToTimestamp( $expiry)
Converts a user group membership expiry string into a timestamp.
showEditUserGroupsForm( $user, $groups, $groupMemberships)
Show the form to edit group memberships.
static getAllGroups()
Returns an array of all groups that may be edited.
switchForm()
Output a form to allow searching for a user.
null string $mTarget
The target of the local right-adjuster's interest.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
userCanChangeRights( $targetUser, $checkIfSelf=true)
Check whether the current user (from context) can change the target user's rights.
editUserGroupsForm( $username)
Edit user groups membership.
groupCheckboxes( $usergroups, $user)
Adds a table with checkboxes where you can select what groups to add/remove.
canProcessExpiries()
Returns true if this user rights form can set and change user group expiries.
fetchUser( $username, $writing=true)
Normalize the input username, which may be local or remote, and return a user (or proxy) object for m...
showLogFragment( $user, $output)
Show a rights log fragment for the specified user.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
execute( $par)
Manage forms to be shown according to posted data.
saveUserGroups( $username, $reason, $user)
Save user groups changes in the database.
static serialiseUgmForLog( $ugm)
Serialise a UserGroupMembership object for storage in the log_params section of the logging table.
doesWrites()
Indicates whether this special page may perform database writes.
addLogEntry( $user, array $oldGroups, array $newGroups, $reason, array $tags, array $oldUGMs, array $newUGMs)
Add a rights log entry for an action.
changeableGroups()
Returns $this->getUser()->changeableGroups()
Class for generating HTML <select> or <datalist> elements.
static parseOptionsMessage(string $msg)
Parse labels and values out of a comma- and colon-separated list of options, such as is used for expi...
setAttribute( $name, $value)