migrateUserGroup.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. /**
  3. * Re-assign users from an old group to a new one
  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. require_once __DIR__ . '/Maintenance.php';
  24. /**
  25. * Maintenance script that re-assigns users from an old group to a new one.
  26. *
  27. * @ingroup Maintenance
  28. */
  29. class MigrateUserGroup extends Maintenance {
  30. public function __construct() {
  31. parent::__construct();
  32. $this->addDescription( 'Re-assign users from an old group to a new one' );
  33. $this->addArg( 'oldgroup', 'Old user group key', true );
  34. $this->addArg( 'newgroup', 'New user group key', true );
  35. $this->setBatchSize( 200 );
  36. }
  37. public function execute() {
  38. $count = 0;
  39. $oldGroup = $this->getArg( 0 );
  40. $newGroup = $this->getArg( 1 );
  41. $dbw = $this->getDB( DB_MASTER );
  42. $start = $dbw->selectField( 'user_groups', 'MIN(ug_user)',
  43. [ 'ug_group' => $oldGroup ], __FUNCTION__ );
  44. $end = $dbw->selectField( 'user_groups', 'MAX(ug_user)',
  45. [ 'ug_group' => $oldGroup ], __FUNCTION__ );
  46. if ( $start === null ) {
  47. $this->error( "Nothing to do - no users in the '$oldGroup' group", true );
  48. }
  49. # Do remaining chunk
  50. $end += $this->mBatchSize - 1;
  51. $blockStart = $start;
  52. $blockEnd = $start + $this->mBatchSize - 1;
  53. // Migrate users over in batches...
  54. while ( $blockEnd <= $end ) {
  55. $affected = 0;
  56. $this->output( "Doing users $blockStart to $blockEnd\n" );
  57. $this->beginTransaction( $dbw, __METHOD__ );
  58. $dbw->update( 'user_groups',
  59. [ 'ug_group' => $newGroup ],
  60. [ 'ug_group' => $oldGroup,
  61. "ug_user BETWEEN $blockStart AND $blockEnd" ],
  62. __METHOD__,
  63. [ 'IGNORE' ]
  64. );
  65. $affected += $dbw->affectedRows();
  66. // Delete rows that the UPDATE operation above had to ignore.
  67. // This happens when a user is in both the old and new group.
  68. // Updating the row for the old group membership failed since
  69. // user/group is UNIQUE.
  70. $dbw->delete( 'user_groups',
  71. [ 'ug_group' => $oldGroup,
  72. "ug_user BETWEEN $blockStart AND $blockEnd" ],
  73. __METHOD__
  74. );
  75. $affected += $dbw->affectedRows();
  76. $this->commitTransaction( $dbw, __METHOD__ );
  77. // Clear cache for the affected users (bug 40340)
  78. if ( $affected > 0 ) {
  79. // XXX: This also invalidates cache of unaffected users that
  80. // were in the new group and not in the group.
  81. $res = $dbw->select( 'user_groups', 'ug_user',
  82. [ 'ug_group' => $newGroup,
  83. "ug_user BETWEEN $blockStart AND $blockEnd" ],
  84. __METHOD__
  85. );
  86. if ( $res !== false ) {
  87. foreach ( $res as $row ) {
  88. $user = User::newFromId( $row->ug_user );
  89. $user->invalidateCache();
  90. }
  91. }
  92. }
  93. $count += $affected;
  94. $blockStart += $this->mBatchSize;
  95. $blockEnd += $this->mBatchSize;
  96. wfWaitForSlaves();
  97. }
  98. $this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" );
  99. }
  100. }
  101. $maintClass = "MigrateUserGroup";
  102. require_once RUN_MAINTENANCE_IF_MAIN;