From 6df5d031c4504e72b62527105e4945c932357a47 Mon Sep 17 00:00:00 2001 From: Max Semenik Date: Thu, 5 Oct 2017 18:53:57 -0700 Subject: [PATCH] Rewrite userOptions.php * Convert to use Maintenance * Clean up * I want to use the class name UserOptions for something else so rename it. Change-Id: Ic441087702376b1ca0e70554c71cdf7ecad908af --- autoload.php | 2 +- maintenance/userOptions.inc | 292 ------------------------------------ maintenance/userOptions.php | 182 +++++++++++++++++++++- 3 files changed, 177 insertions(+), 299 deletions(-) delete mode 100644 maintenance/userOptions.inc diff --git a/autoload.php b/autoload.php index 39ec4b03b9..bfc892878c 100644 --- a/autoload.php +++ b/autoload.php @@ -1568,7 +1568,7 @@ $wgAutoloadLocalClasses = [ 'UserMailer' => __DIR__ . '/includes/mail/UserMailer.php', 'UserNamePrefixSearch' => __DIR__ . '/includes/user/UserNamePrefixSearch.php', 'UserNotLoggedIn' => __DIR__ . '/includes/exception/UserNotLoggedIn.php', - 'UserOptions' => __DIR__ . '/maintenance/userOptions.inc', + 'UserOptionsMaintenance' => __DIR__ . '/maintenance/userOptions.php', 'UserPasswordPolicy' => __DIR__ . '/includes/password/UserPasswordPolicy.php', 'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php', 'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php', diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc deleted file mode 100644 index 8ac7f919ee..0000000000 --- a/maintenance/userOptions.inc +++ /dev/null @@ -1,292 +0,0 @@ -checkOpts( $opts, $args ) ) { - self::showUsageAndExit(); - } else { - $this->mReady = $this->initializeOpts( $opts, $args ); - } - } - - /** - * This is used to check options. Only needed on construction - * - * @param array $opts - * @param array $args - * - * @return bool - */ - private function checkOpts( $opts, $args ) { - // The three possible ways to run the script: - $list = isset( $opts['list'] ); - $usage = isset( $opts['usage'] ) && ( count( $args ) <= 1 ); - $change = isset( $opts['old'] ) && isset( $opts['new'] ) && ( count( $args ) <= 1 ); - - // We want only one of them - $isValid = ( ( $list + $usage + $change ) == 1 ); - - return $isValid; - } - - /** - * load script options in the object - * - * @param array $opts - * @param array $args - * - * @return bool - */ - private function initializeOpts( $opts, $args ) { - $this->mQuick = isset( $opts['nowarn'] ); - $this->mQuiet = isset( $opts['quiet'] ); - $this->mDry = isset( $opts['dry'] ); - - // Set object properties, specially 'mMode' used by run() - if ( isset( $opts['list'] ) ) { - $this->mMode = 'LISTER'; - } elseif ( isset( $opts['usage'] ) ) { - $this->mMode = 'USAGER'; - $this->mAnOption = isset( $args[0] ) ? $args[0] : false; - } elseif ( isset( $opts['old'] ) && isset( $opts['new'] ) ) { - $this->mMode = 'CHANGER'; - $this->mOldValue = $opts['old']; - $this->mNewValue = $opts['new']; - $this->mAnOption = $args[0]; - } else { - die( "There is a bug in the software, this should never happen\n" ); - } - - return true; - } - - /** - * Dumb stuff to run a mode. - * @return bool - */ - public function run() { - if ( !$this->mReady ) { - return false; - } - - $this->{$this->mMode}(); - - return true; - } - - /** - * List default options and their value - */ - private function LISTER() { - $def = User::getDefaultOptions(); - ksort( $def ); - $maxOpt = 0; - foreach ( $def as $opt => $value ) { - $maxOpt = max( $maxOpt, strlen( $opt ) ); - } - foreach ( $def as $opt => $value ) { - printf( "%-{$maxOpt}s: %s\n", $opt, $value ); - } - } - - /** - * List options usage - */ - private function USAGER() { - $ret = []; - $defaultOptions = User::getDefaultOptions(); - - // We list user by user_id from one of the replica DBs - $dbr = wfGetDB( DB_REPLICA ); - $result = $dbr->select( 'user', - [ 'user_id' ], - [], - __METHOD__ - ); - - foreach ( $result as $id ) { - $user = User::newFromId( $id->user_id ); - - // Get the options and update stats - if ( $this->mAnOption ) { - if ( !array_key_exists( $this->mAnOption, $defaultOptions ) ) { - print "Invalid user option. Use --list to see valid choices\n"; - exit; - } - - $userValue = $user->getOption( $this->mAnOption ); - if ( $userValue <> $defaultOptions[$this->mAnOption] ) { - // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning - @$ret[$this->mAnOption][$userValue]++; - // @codingStandardsIgnoreEnd - } - } else { - - foreach ( $defaultOptions as $name => $defaultValue ) { - $userValue = $user->getOption( $name ); - if ( $userValue <> $defaultValue ) { - // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning - @$ret[$name][$userValue]++; - // @codingStandardsIgnoreEnd - } - } - } - } - - foreach ( $ret as $optionName => $usageStats ) { - print "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n"; - foreach ( $usageStats as $value => $count ) { - print " $count user(s): '$value'\n"; - } - print "\n"; - } - } - - /** - * Change our users options - */ - private function CHANGER() { - $this->warn(); - - // We list user by user_id from one of the replica DBs - $dbr = wfGetDB( DB_REPLICA ); - $result = $dbr->select( 'user', - [ 'user_id' ], - [], - __METHOD__ - ); - - foreach ( $result as $id ) { - $user = User::newFromId( $id->user_id ); - - $curValue = $user->getOption( $this->mAnOption ); - $username = $user->getName(); - - if ( $curValue == $this->mOldValue ) { - if ( !$this->mQuiet ) { - print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' " . - "to '{$this->mNewValue}'): "; - } - - // Change value - $user->setOption( $this->mAnOption, $this->mNewValue ); - - // Will not save the settings if run with --dry - if ( !$this->mDry ) { - $user->saveSettings(); - } - if ( !$this->mQuiet ) { - print " OK\n"; - } - } elseif ( !$this->mQuiet ) { - print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n"; - } - } - } - - /** - * Return an array of option names - * @return array - */ - public static function getDefaultOptionsNames() { - $def = User::getDefaultOptions(); - $ret = []; - foreach ( $def as $optname => $defaultValue ) { - array_push( $ret, $optname ); - } - - return $ret; - } - - public static function showUsageAndExit() { - print << --old --new - -Switchs: - --list : list available user options and their default value - - --usage : report all options statistics or just one if you specify it. - - --old : the value to look for - --new : new value to update users with - -Options: - --nowarn: hides the 5 seconds warning - --quiet : do not print what is happening - --dry : do not save user settings back to database - -USAGE; - exit( 0 ); - } - - /** - * The warning message and countdown - * @return bool - */ - public function warn() { - if ( $this->mQuick ) { - return true; - } - - print <<mAnOption> = '$this->mOldValue' will be made to use '$this->mNewValue'. - -Abort with control-c in the next five seconds.... -WARN; - wfCountDown( 5 ); - - return true; - } -} diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php index 53db48cd5b..7cf16b611e 100644 --- a/maintenance/userOptions.php +++ b/maintenance/userOptions.php @@ -24,12 +24,182 @@ * @author Antoine Musso */ -// This is a command line script, load tools and parse args -require_once 'userOptions.inc'; +require_once __DIR__ . '/Maintenance.php'; -// Load up our tool system, exit with usage() if options are not fine -$uo = new UserOptions( $options, $args ); +/** + * @ingroup Maintenance + */ +class UserOptionsMaintenance extends Maintenance { + + function __construct() { + parent::__construct(); + + $this->addDescription( 'Pass through all users and change one of their options. +The new option is NOT validated.' ); + + $this->addOption( 'list', 'List available user options and their default value' ); + $this->addOption( 'usage', 'Report all options statistics or just one if you specify it' ); + $this->addOption( 'old', 'The value to look for', false, true ); + $this->addOption( 'new', 'Rew value to update users with', false, true ); + $this->addOption( 'nowarn', 'Hides the 5 seconds warning' ); + $this->addOption( 'dry', 'Do not save user settings back to database' ); + $this->addArg( 'option name', 'Name of the option to change or provide statistics about', false ); + } + + /** + * Do the actual work + */ + public function execute() { + if ( $this->hasOption( 'list' ) ) { + $this->listAvailableOptions(); + } elseif ( $this->hasOption( 'usage' ) ) { + $this->showUsageStats(); + } elseif ( $this->hasOption( 'old' ) + && $this->hasOption( 'new' ) + && $this->hasArg( 0 ) + ) { + $this->updateOptions(); + } else { + $this->maybeHelp( /* force = */ true ); + } + } + + /** + * List default options and their value + */ + private function listAvailableOptions() { + $def = User::getDefaultOptions(); + ksort( $def ); + $maxOpt = 0; + foreach ( $def as $opt => $value ) { + $maxOpt = max( $maxOpt, strlen( $opt ) ); + } + foreach ( $def as $opt => $value ) { + $this->output( sprintf( "%-{$maxOpt}s: %s\n", $opt, $value ) ); + } + } + + /** + * List options usage + */ + private function showUsageStats() { + $option = $this->getArg( 0 ); + + $ret = []; + $defaultOptions = User::getDefaultOptions(); + + // We list user by user_id from one of the replica DBs + $dbr = wfGetDB( DB_REPLICA ); + $result = $dbr->select( 'user', + [ 'user_id' ], + [], + __METHOD__ + ); + + foreach ( $result as $id ) { + $user = User::newFromId( $id->user_id ); + + // Get the options and update stats + if ( $option ) { + if ( !array_key_exists( $option, $defaultOptions ) ) { + $this->error( "Invalid user option. Use --list to see valid choices\n", 1 ); + } + + $userValue = $user->getOption( $option ); + if ( $userValue <> $defaultOptions[$option] ) { + // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning + @$ret[$option][$userValue]++; + // @codingStandardsIgnoreEnd + } + } else { + + foreach ( $defaultOptions as $name => $defaultValue ) { + $userValue = $user->getOption( $name ); + if ( $userValue != $defaultValue ) { + // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning + @$ret[$name][$userValue]++; + // @codingStandardsIgnoreEnd + } + } + } + } + + foreach ( $ret as $optionName => $usageStats ) { + $this->output( "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n" ); + foreach ( $usageStats as $value => $count ) { + $this->output( " $count user(s): '$value'\n" ); + } + print "\n"; + } + } + + /** + * Change our users options + */ + private function updateOptions() { + $dryRun = $this->hasOption( 'dry' ); + $option = $this->getArg( 0 ); + $from = $this->getOption( 'old' ); + $to = $this->getOption( 'new' ); + + if ( !$dryRun ) { + $this->warn( $option, $from, $to ); + } + + // We list user by user_id from one of the replica DBs + // @todo: getting all users in one query does not scale + $dbr = wfGetDB( DB_REPLICA ); + $result = $dbr->select( 'user', + [ 'user_id' ], + [], + __METHOD__ + ); + + foreach ( $result as $id ) { + $user = User::newFromId( $id->user_id ); + + $curValue = $user->getOption( $option ); + $username = $user->getName(); + + if ( $curValue == $from ) { + $this->output( "Setting {$option} for $username from '{$from}' to '{$to}'): " ); + + // Change value + $user->setOption( $option, $to ); + + // Will not save the settings if run with --dry + if ( !$dryRun ) { + $user->saveSettings(); + } + $this->output( " OK\n" ); + } else { + $this->output( "Not changing '$username' using <{$option}> = '$curValue'\n" ); + } + } + } + + /** + * The warning message and countdown + * + * @param string $option + * @param string $from + * @param string $to + */ + private function warn( $option, $from, $to ) { + if ( $this->hasOption( 'nowarn' ) ) { + return; + } + + $this->output( << = '$from' will be made to use '$to'. -$uo->run(); +Abort with control-c in the next five seconds.... +WARN + ); + $this->countDown( 5 ); + } +} -print "Done.\n"; +$maintClass = 'UserOptionsMaintenance'; +require RUN_MAINTENANCE_IF_MAIN; -- 2.20.1