userOptions.inc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. /**
  3. * Helper class for userOptions.php script.
  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 Maintenance
  22. */
  23. // Options we will use
  24. $options = [ 'list', 'nowarn', 'quiet', 'usage', 'dry' ];
  25. $optionsWithArgs = [ 'old', 'new' ];
  26. require_once __DIR__ . '/commandLine.inc';
  27. /**
  28. * @ingroup Maintenance
  29. */
  30. class UserOptions {
  31. public $mQuick;
  32. public $mQuiet;
  33. public $mDry;
  34. public $mAnOption;
  35. public $mOldValue;
  36. public $mNewValue;
  37. private $mMode, $mReady;
  38. /**
  39. * Constructor. Will show usage and exit if script options are not correct
  40. * @param array $opts
  41. * @param array $args
  42. */
  43. function __construct( $opts, $args ) {
  44. if ( !$this->checkOpts( $opts, $args ) ) {
  45. UserOptions::showUsageAndExit();
  46. } else {
  47. $this->mReady = $this->initializeOpts( $opts, $args );
  48. }
  49. }
  50. /**
  51. * This is used to check options. Only needed on construction
  52. *
  53. * @param array $opts
  54. * @param array $args
  55. *
  56. * @return bool
  57. */
  58. private function checkOpts( $opts, $args ) {
  59. // The three possible ways to run the script:
  60. $list = isset( $opts['list'] );
  61. $usage = isset( $opts['usage'] ) && ( count( $args ) <= 1 );
  62. $change = isset( $opts['old'] ) && isset( $opts['new'] ) && ( count( $args ) <= 1 );
  63. // We want only one of them
  64. $isValid = ( ( $list + $usage + $change ) == 1 );
  65. return $isValid;
  66. }
  67. /**
  68. * load script options in the object
  69. *
  70. * @param array $opts
  71. * @param array $args
  72. *
  73. * @return bool
  74. */
  75. private function initializeOpts( $opts, $args ) {
  76. $this->mQuick = isset( $opts['nowarn'] );
  77. $this->mQuiet = isset( $opts['quiet'] );
  78. $this->mDry = isset( $opts['dry'] );
  79. // Set object properties, specially 'mMode' used by run()
  80. if ( isset( $opts['list'] ) ) {
  81. $this->mMode = 'LISTER';
  82. } elseif ( isset( $opts['usage'] ) ) {
  83. $this->mMode = 'USAGER';
  84. $this->mAnOption = isset( $args[0] ) ? $args[0] : false;
  85. } elseif ( isset( $opts['old'] ) && isset( $opts['new'] ) ) {
  86. $this->mMode = 'CHANGER';
  87. $this->mOldValue = $opts['old'];
  88. $this->mNewValue = $opts['new'];
  89. $this->mAnOption = $args[0];
  90. } else {
  91. die( "There is a bug in the software, this should never happen\n" );
  92. }
  93. return true;
  94. }
  95. /**
  96. * Dumb stuff to run a mode.
  97. */
  98. public function run() {
  99. if ( !$this->mReady ) {
  100. return false;
  101. }
  102. $this->{$this->mMode}();
  103. return true;
  104. }
  105. /**
  106. * List default options and their value
  107. */
  108. private function LISTER() {
  109. $def = User::getDefaultOptions();
  110. ksort( $def );
  111. $maxOpt = 0;
  112. foreach ( $def as $opt => $value ) {
  113. $maxOpt = max( $maxOpt, strlen( $opt ) );
  114. }
  115. foreach ( $def as $opt => $value ) {
  116. printf( "%-{$maxOpt}s: %s\n", $opt, $value );
  117. }
  118. }
  119. /**
  120. * List options usage
  121. */
  122. private function USAGER() {
  123. $ret = [];
  124. $defaultOptions = User::getDefaultOptions();
  125. // We list user by user_id from one of the slave database
  126. $dbr = wfGetDB( DB_SLAVE );
  127. $result = $dbr->select( 'user',
  128. [ 'user_id' ],
  129. [],
  130. __METHOD__
  131. );
  132. foreach ( $result as $id ) {
  133. $user = User::newFromId( $id->user_id );
  134. // Get the options and update stats
  135. if ( $this->mAnOption ) {
  136. if ( !array_key_exists( $this->mAnOption, $defaultOptions ) ) {
  137. print "Invalid user option. Use --list to see valid choices\n";
  138. exit;
  139. }
  140. $userValue = $user->getOption( $this->mAnOption );
  141. if ( $userValue <> $defaultOptions[$this->mAnOption] ) {
  142. // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
  143. @$ret[$this->mAnOption][$userValue]++;
  144. // @codingStandardsIgnoreEnd
  145. }
  146. } else {
  147. foreach ( $defaultOptions as $name => $defaultValue ) {
  148. $userValue = $user->getOption( $name );
  149. if ( $userValue <> $defaultValue ) {
  150. // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
  151. @$ret[$name][$userValue]++;
  152. // @codingStandardsIgnoreEnd
  153. }
  154. }
  155. }
  156. }
  157. foreach ( $ret as $optionName => $usageStats ) {
  158. print "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n";
  159. foreach ( $usageStats as $value => $count ) {
  160. print " $count user(s): '$value'\n";
  161. }
  162. print "\n";
  163. }
  164. }
  165. /**
  166. * Change our users options
  167. */
  168. private function CHANGER() {
  169. $this->warn();
  170. // We list user by user_id from one of the slave database
  171. $dbr = wfGetDB( DB_SLAVE );
  172. $result = $dbr->select( 'user',
  173. [ 'user_id' ],
  174. [],
  175. __METHOD__
  176. );
  177. foreach ( $result as $id ) {
  178. $user = User::newFromId( $id->user_id );
  179. $curValue = $user->getOption( $this->mAnOption );
  180. $username = $user->getName();
  181. if ( $curValue == $this->mOldValue ) {
  182. if ( !$this->mQuiet ) {
  183. print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' " .
  184. "to '{$this->mNewValue}'): ";
  185. }
  186. // Change value
  187. $user->setOption( $this->mAnOption, $this->mNewValue );
  188. // Will not save the settings if run with --dry
  189. if ( !$this->mDry ) {
  190. $user->saveSettings();
  191. }
  192. if ( !$this->mQuiet ) {
  193. print " OK\n";
  194. }
  195. } elseif ( !$this->mQuiet ) {
  196. print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n";
  197. }
  198. }
  199. }
  200. /**
  201. * Return an array of option names
  202. * @return array
  203. */
  204. public static function getDefaultOptionsNames() {
  205. $def = User::getDefaultOptions();
  206. $ret = [];
  207. foreach ( $def as $optname => $defaultValue ) {
  208. array_push( $ret, $optname );
  209. }
  210. return $ret;
  211. }
  212. public static function showUsageAndExit() {
  213. print <<<USAGE
  214. This script pass through all users and change one of their options.
  215. The new option is NOT validated.
  216. Usage:
  217. php userOptions.php --list
  218. php userOptions.php [user option] --usage
  219. php userOptions.php [options] <user option> --old <old value> --new <new value>
  220. Switchs:
  221. --list : list available user options and their default value
  222. --usage : report all options statistics or just one if you specify it.
  223. --old <old value> : the value to look for
  224. --new <new value> : new value to update users with
  225. Options:
  226. --nowarn: hides the 5 seconds warning
  227. --quiet : do not print what is happening
  228. --dry : do not save user settings back to database
  229. USAGE;
  230. exit( 0 );
  231. }
  232. /**
  233. * The warning message and countdown
  234. * @return bool
  235. */
  236. public function warn() {
  237. if ( $this->mQuick ) {
  238. return true;
  239. }
  240. print <<<WARN
  241. The script is about to change the skin for ALL USERS in the database.
  242. Users with option <$this->mAnOption> = '$this->mOldValue' will be made to use '$this->mNewValue'.
  243. Abort with control-c in the next five seconds....
  244. WARN;
  245. wfCountDown( 5 );
  246. return true;
  247. }
  248. }