MediaWiki REL1_41
createAndPromote.php
Go to the documentation of this file.
1<?php
26require_once __DIR__ . '/Maintenance.php';
27
30
37 private static $permitRoles = [ 'sysop', 'bureaucrat', 'interface-admin', 'bot' ];
38
39 public function __construct() {
40 parent::__construct();
41 $this->addDescription( 'Create a new user account and/or grant it additional rights' );
42 $this->addOption(
43 'force',
44 'If account exists already, just grant it rights or change password.'
45 );
46 foreach ( self::$permitRoles as $role ) {
47 $this->addOption( $role, "Add the account to the {$role} group" );
48 }
49
50 $this->addOption(
51 'custom-groups',
52 'Comma-separated list of groups to add the user to',
53 false,
54 true
55 );
56
57 $this->addOption(
58 'reason',
59 'Reason for account creation and user rights assignment to log to wiki',
60 false,
61 true
62 );
63
64 $this->addArg( 'username', 'Username of new user' );
65 $this->addArg( 'password', 'Password to set', false );
66 }
67
68 public function execute() {
69 $username = $this->getArg( 0 );
70 $password = $this->getArg( 1 );
71 $force = $this->hasOption( 'force' );
72 $inGroups = [];
73 $services = $this->getServiceContainer();
74
75 $user = $services->getUserFactory()->newFromName( $username );
76 if ( !is_object( $user ) ) {
77 $this->fatalError( 'invalid username.' );
78 }
79
80 $exists = ( $user->idForName() !== 0 );
81
82 if ( $exists && !$force ) {
83 $this->fatalError( 'Account exists. Perhaps you want the --force option?' );
84 } elseif ( !$exists && !$password ) {
85 $this->error( 'Argument <password> required!' );
86 $this->maybeHelp( true );
87 } elseif ( $exists ) {
88 $inGroups = $services->getUserGroupManager()->getUserGroups( $user );
89 }
90
91 $groups = array_filter( self::$permitRoles, [ $this, 'hasOption' ] );
92 if ( $this->hasOption( 'custom-groups' ) ) {
93 $allGroups = array_fill_keys( $services->getUserGroupManager()->listAllGroups(), true );
94 $customGroupsText = $this->getOption( 'custom-groups' );
95 if ( $customGroupsText !== '' ) {
96 $customGroups = explode( ',', $customGroupsText );
97 foreach ( $customGroups as $customGroup ) {
98 if ( isset( $allGroups[$customGroup] ) ) {
99 $groups[] = trim( $customGroup );
100 } else {
101 $this->output( "$customGroup is not a valid group, ignoring!\n" );
102 }
103 }
104 }
105 }
106
107 $promotions = array_diff(
108 $groups,
109 $inGroups
110 );
111
112 if ( $exists && !$password && count( $promotions ) === 0 ) {
113 $this->output( "Account exists and nothing to do.\n" );
114
115 return;
116 } elseif ( count( $promotions ) !== 0 ) {
117 $dbDomain = WikiMap::getCurrentWikiDbDomain()->getId();
118 $promoText = "User:{$username} into " . implode( ', ', $promotions ) . "...\n";
119 if ( $exists ) {
120 $this->output( "$dbDomain: Promoting $promoText" );
121 } else {
122 $this->output( "$dbDomain: Creating and promoting $promoText" );
123 }
124 }
125
126 if ( !$exists ) {
127 // Verify the password meets the password requirements before creating.
128 // This check is repeated below to account for differences between
129 // the password policy for regular users and for users in certain groups.
130 if ( $password ) {
131 $status = $user->checkPasswordValidity( $password );
132
133 if ( !$status->isGood() ) {
134 $this->fatalError( $status->getMessage( false, false, 'en' )->text() );
135 }
136 }
137
138 // Create the user via AuthManager as there may be various side
139 // effects that are performed by the configured AuthManager chain.
140 $status = $this->getServiceContainer()->getAuthManager()->autoCreateUser(
141 $user,
142 MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_MAINT,
143 false
144 );
145 if ( !$status->isGood() ) {
146 $this->fatalError( $status->getMessage( false, false, 'en' )->text() );
147 }
148 }
149
150 if ( $promotions ) {
151 // Add groups before changing password, as the password policy for certain groups has
152 // stricter requirements.
153 $userGroupManager = $services->getUserGroupManager();
154 $userGroupManager->addUserToMultipleGroups( $user, $promotions );
155 $reason = $this->getOption( 'reason' ) ?: '';
156 $this->addLogEntry( $user, $inGroups, array_merge( $inGroups, $promotions ), $reason );
157 }
158
159 if ( $password ) {
160 # Try to set the password
161 try {
162 $status = $user->changeAuthenticationData( [
163 'username' => $user->getName(),
164 'password' => $password,
165 'retype' => $password,
166 ] );
167 if ( !$status->isGood() ) {
168 throw new PasswordError( $status->getMessage( false, false, 'en' )->text() );
169 }
170 if ( $exists ) {
171 $this->output( "Password set.\n" );
172 $user->saveSettings();
173 }
174 } catch ( PasswordError $pwe ) {
175 $this->fatalError( 'Setting the password failed: ' . $pwe->getMessage() );
176 }
177 }
178
179 if ( !$exists ) {
180 # Increment site_stats.ss_users
181 $ssu = SiteStatsUpdate::factory( [ 'users' => 1 ] );
182 $ssu->doUpdate();
183 }
184
185 $this->output( "done.\n" );
186 }
187
198 private function addLogEntry( $user, array $oldGroups, array $newGroups, string $reason ) {
199 $logEntry = new ManualLogEntry( 'rights', 'rights' );
200 $logEntry->setPerformer( User::newSystemUser( User::MAINTENANCE_SCRIPT_USER, [ 'steal' => true ] ) );
201 $logEntry->setTarget( $user->getUserPage() );
202 $logEntry->setComment( $reason );
203 $logEntry->setParameters( [
204 '4::oldgroups' => $oldGroups,
205 '5::newgroups' => $newGroups
206 ] );
207 $logid = $logEntry->insert();
208 $logEntry->publish( $logid );
209 }
210}
211
212$maintClass = CreateAndPromote::class;
213require_once RUN_MAINTENANCE_IF_MAIN;
Maintenance script to create an account and grant it rights.
execute()
Do the actual work.
__construct()
Default constructor.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
error( $err, $die=0)
Throw an error to the user.
addArg( $arg, $description, $required=true, $multi=false)
Add some args that are needed.
output( $out, $channel=null)
Throw some output to the user.
hasOption( $name)
Checks to see if a particular option was set.
getServiceContainer()
Returns the main service container.
getArg( $argId=0, $default=null)
Get an argument.
addDescription( $text)
Set the description text.
maybeHelp( $force=false)
Maybe show the help.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Class for creating new log entries and inserting them into the database.
internal since 1.36
Definition User.php:98
Tools for dealing with other locally-hosted wikis.
Definition WikiMap.php:31
Show an error when any operation involving passwords fails to run.
A helper class for throttling authentication attempts.