69 parent::__construct(
'Userrights' );
70 $services = MediaWikiServices::getInstance();
72 $this->userNameUtils =
$userNameUtils ?? $services->getUserNameUtils();
76 $this->userGroupManager = ( $userGroupManagerFactory ?? $services->getUserGroupManagerFactory() )
77 ->getUserGroupManager(
false );
97 if ( $targetUser->
getId() === 0 ) {
101 if ( $available[
'add'] || $available[
'remove'] ) {
106 if ( ( $available[
'add-self'] || $available[
'remove-self'] )
107 && (
$isself || !$checkIfSelf )
126 $session = $request->getSession();
129 $out->addModules( [
'mediawiki.special.userrights' ] );
131 $this->mTarget = $par ?? $request->getVal(
'user' );
133 if ( is_string( $this->mTarget ) ) {
134 $this->mTarget = trim( $this->mTarget );
137 if ( $this->mTarget !==
null && $this->userNameUtils->getCanonical( $this->mTarget ) === $user->getName() ) {
138 $this->isself =
true;
141 $fetchedStatus = $this->mTarget ===
null ? Status::newFatal(
'nouserspecified' ) :
142 $this->
fetchUser( $this->mTarget,
true );
143 if ( $fetchedStatus->isOK() ) {
144 $this->mFetchedUser = $fetchedStatus->value;
145 if ( $this->mFetchedUser instanceof
User ) {
148 $this->
getSkin()->setRelevantUser( $this->mFetchedUser );
154 $session->get(
'specialUserrightsSaveSuccess' ) &&
155 $this->mFetchedUser !==
null
158 $session->remove(
'specialUserrightsSaveSuccess' );
160 $out->addModuleStyles(
'mediawiki.notification.convertmessagebox.styles' );
165 'class' =>
'mw-notify-success successbox',
166 'id' =>
'mw-preferences-success',
167 'data-mw-autohide' =>
'false',
172 $this->
msg(
'savedrights', $this->mFetchedUser->getName() )->text()
181 $out->addModuleStyles(
'mediawiki.special' );
182 $this->
addHelpLink(
'Help:Assigning permissions' );
187 $request->wasPosted() &&
188 $request->getCheck(
'saveusergroups' ) &&
189 $this->mTarget !==
null &&
190 $user->matchEditToken( $request->getVal(
'wpEditToken' ), $this->mTarget )
197 if ( !$this->
getAuthority()->isAllowed(
'userrights' ) ) {
198 $block = $user->getBlock();
199 if ( $block && $block->isSitewide() ) {
212 if ( !$fetchedStatus->isOK() ) {
213 $this->
getOutput()->addWikiTextAsInterface(
214 $fetchedStatus->getWikiText(
false,
false, $this->getLanguage() )
221 if ( $targetUser instanceof
User ) {
225 $conflictCheck = $request->getVal(
'conflictcheck-originalgroups' );
226 $conflictCheck = ( $conflictCheck ===
'' ) ? [] : explode(
',', $conflictCheck );
227 $userGroups = $targetUser->getGroups();
229 if ( $userGroups !== $conflictCheck ) {
230 $out->addHTML( Html::errorBox(
231 $this->
msg(
'userrights-conflict' )->parse()
236 $request->getVal(
'user-reason' ),
240 if ( $status->isOK() ) {
242 $session->set(
'specialUserrightsSaveSuccess', 1 );
248 $out->wrapWikiTextAsInterface(
249 'error', $status->getWikiText(
false,
false, $this->getLanguage() )
256 if ( $this->mTarget !==
null ) {
262 return $this->
getPageTitle( $this->mTarget )->getFullURL();
289 $unix = strtotime( $expiry );
291 if ( !$unix || $unix === -1 ) {
314 $existingUGMs = $user->getGroupMemberships();
318 foreach ( $allgroups as $group ) {
321 if ( $this->
getRequest()->getCheck(
"wpGroup-$group" ) ) {
322 $addgroup[] = $group;
326 $expiryDropdown = $this->
getRequest()->getVal(
"wpExpiry-$group" );
327 if ( $expiryDropdown ===
'existing' ) {
331 if ( $expiryDropdown ===
'other' ) {
332 $expiryValue = $this->
getRequest()->getVal(
"wpExpiry-$group-other" );
334 $expiryValue = $expiryDropdown;
340 if ( $groupExpiries[$group] ===
false ) {
341 return Status::newFatal(
'userrights-invalid-expiry', $group );
345 if ( $groupExpiries[$group] && $groupExpiries[$group] <
wfTimestampNow() ) {
346 return Status::newFatal(
'userrights-expiry-in-past', $group );
352 isset( $existingUGMs[$group] ) &&
353 ( $existingUGMs[$group]->getExpiry() ?:
'infinity' ) >
354 ( $groupExpiries[$group] ?:
'infinity' )
356 return Status::newFatal(
'userrights-cannot-shorten-expiry', $group );
360 $removegroup[] = $group;
364 $this->
doSaveUserGroups( $user, $addgroup, $removegroup, $reason, [], $groupExpiries );
366 return Status::newGood();
383 array $tags = [], array $groupExpiries = []
387 $groups = $user->getGroups();
388 $ugms = $user->getGroupMemberships();
390 $addable = array_merge( $changeable[
'add'],
$isself ? $changeable[
'add-self'] : [] );
391 $removable = array_merge( $changeable[
'remove'],
$isself ? $changeable[
'remove-self'] : [] );
393 $remove = array_unique( array_intersect( $remove, $removable, $groups ) );
394 $add = array_intersect( $add, $addable );
399 $add = array_filter( $add,
400 static function ( $group ) use ( $groups, $groupExpiries, $removable, $ugms ) {
401 if ( isset( $groupExpiries[$group] ) &&
402 !in_array( $group, $removable ) &&
403 isset( $ugms[$group] ) &&
404 ( $ugms[$group]->getExpiry() ?:
'infinity' ) >
405 ( $groupExpiries[$group] ?:
'infinity' )
409 return !in_array( $group, $groups ) || array_key_exists( $group, $groupExpiries );
414 $oldGroups = $groups;
415 $oldUGMs = $user->getGroupMemberships();
416 $newGroups = $oldGroups;
420 foreach ( $remove as $index => $group ) {
421 if ( !$user->removeGroup( $group ) ) {
422 unset( $remove[$index] );
425 $newGroups = array_diff( $newGroups, $remove );
428 foreach ( $add as $index => $group ) {
429 $expiry = $groupExpiries[$group] ??
null;
430 if ( !$user->addGroup( $group, $expiry ) ) {
431 unset( $add[$index] );
434 $newGroups = array_merge( $newGroups, $add );
436 $newGroups = array_unique( $newGroups );
437 $newUGMs = $user->getGroupMemberships();
440 $user->invalidateCache();
443 $this->
getHookRunner()->onUserGroupsChanged( $user, $add, $remove,
444 $this->
getUser(), $reason, $oldUGMs, $newUGMs );
446 wfDebug(
'oldGroups: ' . print_r( $oldGroups,
true ) );
447 wfDebug(
'newGroups: ' . print_r( $newGroups,
true ) );
448 wfDebug(
'oldUGMs: ' . print_r( $oldUGMs,
true ) );
449 wfDebug(
'newUGMs: ' . print_r( $newUGMs,
true ) );
452 if ( $newGroups != $oldGroups || $newUGMs != $oldUGMs ) {
453 $this->
addLogEntry( $user, $oldGroups, $newGroups, $reason, $tags, $oldUGMs, $newUGMs );
456 return [ $add, $remove ];
470 return [
'expiry' => $ugm->getExpiry() ];
483 protected function addLogEntry( $user, array $oldGroups, array $newGroups, $reason,
484 array $tags, array $oldUGMs, array $newUGMs
488 $oldUGMs = array_map(
function ( $group ) use ( $oldUGMs ) {
489 return isset( $oldUGMs[$group] ) ?
493 $newUGMs = array_map(
function ( $group ) use ( $newUGMs ) {
494 return isset( $newUGMs[$group] ) ?
500 $logEntry->setPerformer( $this->
getUser() );
501 $logEntry->setTarget( $user->getUserPage() );
502 $logEntry->setComment( $reason );
503 $logEntry->setParameters( [
504 '4::oldgroups' => $oldGroups,
505 '5::newgroups' => $newGroups,
506 'oldmetadata' => $oldUGMs,
507 'newmetadata' => $newUGMs,
509 $logid = $logEntry->insert();
510 if ( count( $tags ) ) {
511 $logEntry->addTags( $tags );
513 $logEntry->publish( $logid );
521 $status = $this->
fetchUser( $username,
true );
522 if ( !$status->isOK() ) {
523 $this->
getOutput()->addWikiTextAsInterface(
524 $status->getWikiText(
false,
false, $this->getLanguage() )
531 $user = $status->value;
532 '@phan-var User $user';
534 $groups = $user->getGroups();
535 $groupMemberships = $user->getGroupMemberships();
552 public function fetchUser( $username, $writing =
true ) {
553 $parts = explode( $this->
getConfig()->
get(
'UserrightsInterwikiDelimiter' ), $username );
554 if ( count( $parts ) < 2 ) {
555 $name = trim( $username );
558 list( $name, $dbDomain ) = array_map(
'trim', $parts );
560 if ( WikiMap::isCurrentWikiId( $dbDomain ) ) {
564 !$this->
getAuthority()->isAllowed(
'userrights-interwiki' )
566 return Status::newFatal(
'userrights-no-interwiki' );
569 return Status::newFatal(
'userrights-nodatabase', $dbDomain );
574 if ( $name ===
'' ) {
575 return Status::newFatal(
'nouserspecified' );
578 if ( $name[0] ==
'#' ) {
581 $id = intval( substr( $name, 1 ) );
583 if ( $dbDomain ==
'' ) {
590 return Status::newFatal(
'noname' );
593 $name = $this->userNameUtils->getCanonical( $name );
594 if ( $name ===
false ) {
596 return Status::newFatal(
'nosuchusershort', $username );
600 if ( $dbDomain ==
'' ) {
606 if ( !$user || $user->isAnon() ) {
607 return Status::newFatal(
'nosuchusershort', $username );
610 if ( $user instanceof
User &&
612 !$this->getAuthority()->isAllowed(
'hideuser' )
615 return Status::newFatal(
'nosuchusershort', $username );
618 return Status::newGood( $user );
629 if ( empty( $ids ) ) {
630 return $this->
msg(
'rightsnone' )->inContentLanguage()->text();
632 return implode(
', ', $ids );
640 $this->
getOutput()->addModules(
'mediawiki.userSuggest' );
649 'id' =>
'mw-userrights-form1'
652 Html::hidden(
'title', $this->
getPageTitle()->getPrefixedText() ) .
653 Xml::fieldset( $this->
msg(
'userrights-lookup-user' )->text() ) .
655 $this->
msg(
'userrights-user-editname' )->text(),
659 $this->mTarget ? str_replace(
'_',
' ', $this->mTarget ) :
'',
661 'class' =>
'mw-autocomplete-user',
664 $this->mFetchedUser ===
null ? [
'autofocus' =>
'' ] : []
668 $this->
msg(
'editusergroup' )->text()
670 Html::closeElement(
'fieldset' ) .
671 Html::closeElement(
'form' ) .
"\n"
685 $list = $membersList = $tempList = $tempMembersList = [];
686 foreach ( $groupMemberships as $ugm ) {
687 $linkG = UserGroupMembership::getLink( $ugm, $this->
getContext(),
'html' );
688 $linkM = UserGroupMembership::getLink( $ugm, $this->
getContext(),
'html',
690 if ( $ugm->getExpiry() ) {
691 $tempList[] = $linkG;
692 $tempMembersList[] = $linkM;
695 $membersList[] = $linkM;
701 $autoMembersList = [];
703 $isUserInstance = $user instanceof
User;
705 if ( $isUserInstance ) {
706 foreach ( $this->userGroupManager->getUserAutopromoteGroups( $user ) as $group ) {
707 $autoList[] = UserGroupMembership::getLink( $group, $this->
getContext(),
'html' );
708 $autoMembersList[] = UserGroupMembership::getLink( $group, $this->
getContext(),
709 'html', $user->getName() );
714 $displayedList = $this->
msg(
'userrights-groupsmember-type' )
716 $language->commaList( array_merge( $tempList, $list ) ),
717 $language->commaList( array_merge( $tempMembersList, $membersList ) )
719 $displayedAutolist = $this->
msg(
'userrights-groupsmember-type' )
721 $language->commaList( $autoList ),
722 $language->commaList( $autoMembersList )
726 $count = count( $list ) + count( $tempList );
728 $grouplist = $this->
msg(
'userrights-groupsmember' )
729 ->numParams( $count )
730 ->params( $user->getName() )
732 $grouplist =
'<p>' . $grouplist .
' ' . $displayedList .
"</p>\n";
735 $count = count( $autoList );
737 $autogrouplistintro = $this->
msg(
'userrights-groupsmember-auto' )
738 ->numParams( $count )
739 ->params( $user->getName() )
741 $grouplist .=
'<p>' . $autogrouplistintro .
' ' . $displayedAutolist .
"</p>\n";
744 $systemUser = $isUserInstance && $user->isSystemUser();
746 $systemusernote = $this->
msg(
'userrights-systemuser' )
747 ->params( $user->getName() )
749 $grouplist .=
'<p>' . $systemusernote .
"</p>\n";
761 list( $groupCheckboxes, $canChangeAny ) =
769 'name' =>
'editGroup',
770 'id' =>
'mw-userrights-form2'
773 Html::hidden(
'user', $this->mTarget ) .
774 Html::hidden(
'wpEditToken', $this->
getUser()->getEditToken( $this->mTarget ) ) .
776 'conflictcheck-originalgroups',
777 implode(
',', $user->getGroups() )
779 Xml::openElement(
'fieldset' ) .
784 $canChangeAny ?
'userrights-editusergroup' :
'userrights-viewusergroup',
789 $canChangeAny ?
'editinguser' :
'viewinguserrights'
791 ->rawParams( $userToolLinks )->parse()
793 if ( $canChangeAny ) {
795 $this->
msg(
'userrights-groups-help', $user->getName() )->parse() .
798 Xml::openElement(
'table', [
'id' =>
'mw-userrights-table-outer' ] ) .
800 <td class='mw-label'>" .
801 Xml::label( $this->msg(
'userrights-reason' )->text(),
'wpReason' ) .
803 <td class='mw-input'>" .
804 Xml::input(
'user-reason', 60, $this->getRequest()->getVal(
'user-reason',
false ), [
809 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
815 <td class='mw-submit'>" .
816 Xml::submitButton( $this->msg(
'saveusergroups', $user->getName() )->text(),
817 [
'name' =>
'saveusergroups' ] +
822 Xml::closeElement(
'table' ) .
"\n"
825 $this->
getOutput()->addHTML( $grouplist );
828 Xml::closeElement(
'fieldset' ) .
829 Xml::closeElement(
'form' ) .
"\n"
838 return MediaWikiServices::getInstance()
839 ->getUserGroupManagerFactory()
840 ->getUserGroupManager(
false )
858 $expiryOptionsMsg = $this->
msg(
'userrights-expiry-options' )->inContentLanguage();
859 $expiryOptions = $expiryOptionsMsg->isDisabled()
865 $columns = [
'unchangeable' => [],
'changeable' => [] ];
867 foreach ( $allgroups as $group ) {
868 $set = isset( $usergroups[$group] );
872 $canOnlyLengthenExpiry = ( $set && $this->
canAdd( $group ) &&
873 !$this->
canRemove( $group ) && $usergroups[$group]->getExpiry() );
875 $disabledCheckbox = !(
876 ( $set && $this->
canRemove( $group ) ) ||
877 ( !$set && $this->
canAdd( $group ) ) );
879 $disabledExpiry = $disabledCheckbox && !$canOnlyLengthenExpiry;
881 $irreversible = !$disabledCheckbox && (
882 ( $set && !$this->
canAdd( $group ) ) ||
883 ( !$set && !$this->
canRemove( $group ) ) );
887 'disabled' => $disabledCheckbox,
888 'disabled-expiry' => $disabledExpiry,
889 'irreversible' => $irreversible
892 if ( $disabledCheckbox && $disabledExpiry ) {
893 $columns[
'unchangeable'][$group] = $checkbox;
895 $columns[
'changeable'][$group] = $checkbox;
900 $ret .= Xml::openElement(
'table', [
'class' =>
'mw-userrights-groups' ] ) .
902 foreach ( $columns as $name => $column ) {
903 if ( $column === [] ) {
907 $ret .= Xml::element(
910 $this->
msg(
'userrights-' . $name .
'-col', count( $column ) )->text()
914 $ret .=
"</tr>\n<tr>\n";
915 foreach ( $columns as $column ) {
916 if ( $column === [] ) {
919 $ret .=
"\t<td style='vertical-align:top;'>\n";
920 foreach ( $column as $group => $checkbox ) {
921 $attr = [
'class' =>
'mw-userrights-groupcheckbox' ];
922 if ( $checkbox[
'disabled'] ) {
923 $attr[
'disabled'] =
'disabled';
926 $member = UserGroupMembership::getGroupMemberName( $group, $user->getName() );
927 if ( $checkbox[
'irreversible'] ) {
928 $text = $this->
msg(
'userrights-irreversible-marker', $member )->text();
929 } elseif ( $checkbox[
'disabled'] && !$checkbox[
'disabled-expiry'] ) {
930 $text = $this->
msg(
'userrights-no-shorten-expiry-marker', $member )->text();
934 $checkboxHtml = Xml::checkLabel( $text,
"wpGroup-" . $group,
935 "wpGroup-" . $group, $checkbox[
'set'], $attr );
941 $currentExpiry = isset( $usergroups[$group] ) ?
942 $usergroups[$group]->getExpiry() :
947 if ( $checkbox[
'set'] &&
948 ( $checkbox[
'irreversible'] || $checkbox[
'disabled-expiry'] )
950 if ( $currentExpiry ) {
951 $expiryFormatted = $uiLanguage->userTimeAndDate( $currentExpiry, $uiUser );
952 $expiryFormattedD = $uiLanguage->userDate( $currentExpiry, $uiUser );
953 $expiryFormattedT = $uiLanguage->userTime( $currentExpiry, $uiUser );
954 $expiryHtml = Xml::element(
'span',
null,
955 $this->
msg(
'userrights-expiry-current' )->params(
956 $expiryFormatted, $expiryFormattedD, $expiryFormattedT )->text() );
958 $expiryHtml = Xml::element(
'span',
null,
959 $this->
msg(
'userrights-expiry-none' )->text() );
963 $expiryHtml .= Html::hidden(
"wpExpiry-$group",
964 $currentExpiry ?
'existing' :
'infinite' );
965 $expiryHtml .=
"<br />\n";
967 $expiryHtml = Xml::element(
'span',
null,
968 $this->
msg(
'userrights-expiry' )->text() );
969 $expiryHtml .= Xml::openElement(
'span' );
974 "mw-input-wpExpiry-$group",
975 $currentExpiry ?
'existing' :
'infinite'
977 if ( $checkbox[
'disabled-expiry'] ) {
978 $expiryFormOptions->
setAttribute(
'disabled',
'disabled' );
981 if ( $currentExpiry ) {
982 $timestamp = $uiLanguage->userTimeAndDate( $currentExpiry, $uiUser );
983 $d = $uiLanguage->userDate( $currentExpiry, $uiUser );
984 $t = $uiLanguage->userTime( $currentExpiry, $uiUser );
985 $existingExpiryMessage = $this->
msg(
'userrights-expiry-existing',
986 $timestamp, $d,
$t );
987 $expiryFormOptions->addOption( $existingExpiryMessage->text(),
'existing' );
990 $expiryFormOptions->addOption(
991 $this->
msg(
'userrights-expiry-none' )->text(),
994 $expiryFormOptions->addOption(
995 $this->
msg(
'userrights-expiry-othertime' )->text(),
999 $expiryFormOptions->addOptions( $expiryOptions );
1002 $expiryHtml .= $expiryFormOptions->getHTML() .
'<br />';
1006 'id' =>
"mw-input-wpExpiry-$group-other",
1007 'class' =>
'mw-userrights-expiryfield',
1009 if ( $checkbox[
'disabled-expiry'] ) {
1010 $attribs[
'disabled'] =
'disabled';
1012 $expiryHtml .= Xml::input(
"wpExpiry-$group-other", 30,
'', $attribs );
1016 if ( $checkbox[
'set'] && $checkbox[
'disabled'] ) {
1017 $expiryHtml .= Html::hidden(
"wpGroup-$group", 1 );
1020 $expiryHtml .= Xml::closeElement(
'span' );
1024 'id' =>
"mw-userrights-nested-wpGroup-$group",
1025 'class' =>
'mw-userrights-nested',
1027 $checkboxHtml .=
"\t\t\t" . Xml::tags(
'div', $divAttribs, $expiryHtml ) .
"\n";
1029 $ret .=
"\t\t" . ( ( $checkbox[
'disabled'] && $checkbox[
'disabled-expiry'] )
1030 ? Xml::tags(
'div', [
'class' =>
'mw-userrights-disabled' ], $checkboxHtml )
1031 : Xml::tags(
'div', [], $checkboxHtml )
1034 $ret .=
"\t</td>\n";
1036 $ret .= Xml::closeElement(
'tr' ) . Xml::closeElement(
'table' );
1038 return [ $ret, (bool)$columns[
'changeable'] ];
1050 $groups[
'remove'] ) || ( $this->isself && in_array( $group, $groups[
'remove-self'] )
1063 $groups[
'add'] ) || ( $this->isself && in_array( $group, $groups[
'add-self'] )
1088 $rightsLogPage =
new LogPage(
'rights' );
1089 $output->addHTML( Xml::element(
'h2',
null, $rightsLogPage->getName()->text() ) );
1090 LogEventsList::showLogExtract( $output,
'rights', $user->getUserPage() );
1102 $search = $this->userNameUtils->getCanonical( $search );
1108 return $this->userNamePrefixSearch
1109 ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
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.
getAuthority()
Shortcut to get the Authority executing this instance.
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 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')
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
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.
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.
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.
UserGroupManager $userGroupManager
fetchUser( $username, $writing=true)
Normalize the input username, which may be local or remote, and return a user (or proxy) object for m...
null User $mFetchedUser
The user object of the target username or null.
showLogFragment( $user, $output)
Show a rights log fragment for the specified user.
userCanChangeRights(UserIdentity $targetUser, $checkIfSelf=true)
Check whether the current user (from context) can change the target user's rights.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
__construct(UserGroupManagerFactory $userGroupManagerFactory=null, UserNameUtils $userNameUtils=null, UserNamePrefixSearch $userNamePrefixSearch=null)
execute( $par)
Manage forms to be shown according to posted data.
saveUserGroups( $username, $reason, $user)
Save user groups changes in the database.
UserNameUtils $userNameUtils
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()
UserNamePrefixSearch $userNamePrefixSearch
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)