RevisionDeleteUser.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <?php
  2. /**
  3. * Backend functions for suppressing and unsuppressing all references to a given user.
  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 RevisionDelete
  22. */
  23. use Wikimedia\Rdbms\IDatabase;
  24. /**
  25. * Backend functions for suppressing and unsuppressing all references to a given user,
  26. * used when blocking with HideUser enabled. This was spun out of SpecialBlockip.php
  27. * in 1.18; at some point it needs to be rewritten to either use RevisionDelete abstraction,
  28. * or at least schema abstraction.
  29. *
  30. * @ingroup RevisionDelete
  31. */
  32. class RevisionDeleteUser {
  33. /**
  34. * Update *_deleted bitfields in various tables to hide or unhide usernames
  35. * @param string $name Username
  36. * @param int $userId User id
  37. * @param string $op Operator '|' or '&'
  38. * @param null|IDatabase $dbw If you happen to have one lying around
  39. * @return bool
  40. */
  41. private static function setUsernameBitfields( $name, $userId, $op, $dbw ) {
  42. global $wgActorTableSchemaMigrationStage;
  43. if ( !$userId || ( $op !== '|' && $op !== '&' ) ) {
  44. return false; // sanity check
  45. }
  46. if ( !$dbw instanceof IDatabase ) {
  47. $dbw = wfGetDB( DB_MASTER );
  48. }
  49. # To suppress, we OR the current bitfields with Revision::DELETED_USER
  50. # to put a 1 in the username *_deleted bit. To unsuppress we AND the
  51. # current bitfields with the inverse of Revision::DELETED_USER. The
  52. # username bit is made to 0 (x & 0 = 0), while others are unchanged (x & 1 = x).
  53. # The same goes for the sysop-restricted *_deleted bit.
  54. $delUser = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
  55. $delAction = LogPage::DELETED_ACTION | Revision::DELETED_RESTRICTED;
  56. if ( $op == '&' ) {
  57. $delUser = $dbw->bitNot( $delUser );
  58. $delAction = $dbw->bitNot( $delAction );
  59. }
  60. # Normalize user name
  61. $userTitle = Title::makeTitleSafe( NS_USER, $name );
  62. $userDbKey = $userTitle->getDBkey();
  63. if ( $wgActorTableSchemaMigrationStage < MIGRATION_NEW ) {
  64. # Hide name from live edits
  65. $dbw->update(
  66. 'revision',
  67. [ self::buildSetBitDeletedField( 'rev_deleted', $op, $delUser, $dbw ) ],
  68. [ 'rev_user' => $userId ],
  69. __METHOD__ );
  70. # Hide name from deleted edits
  71. $dbw->update(
  72. 'archive',
  73. [ self::buildSetBitDeletedField( 'ar_deleted', $op, $delUser, $dbw ) ],
  74. [ 'ar_user_text' => $name ],
  75. __METHOD__
  76. );
  77. # Hide name from logs
  78. $dbw->update(
  79. 'logging',
  80. [ self::buildSetBitDeletedField( 'log_deleted', $op, $delUser, $dbw ) ],
  81. [ 'log_user' => $userId, 'log_type != ' . $dbw->addQuotes( 'suppress' ) ],
  82. __METHOD__
  83. );
  84. # Hide name from RC
  85. $dbw->update(
  86. 'recentchanges',
  87. [ self::buildSetBitDeletedField( 'rc_deleted', $op, $delUser, $dbw ) ],
  88. [ 'rc_user_text' => $name ],
  89. __METHOD__
  90. );
  91. # Hide name from live images
  92. $dbw->update(
  93. 'oldimage',
  94. [ self::buildSetBitDeletedField( 'oi_deleted', $op, $delUser, $dbw ) ],
  95. [ 'oi_user_text' => $name ],
  96. __METHOD__
  97. );
  98. # Hide name from deleted images
  99. $dbw->update(
  100. 'filearchive',
  101. [ self::buildSetBitDeletedField( 'fa_deleted', $op, $delUser, $dbw ) ],
  102. [ 'fa_user_text' => $name ],
  103. __METHOD__
  104. );
  105. }
  106. if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
  107. $actorId = $dbw->selectField( 'actor', 'actor_id', [ 'actor_name' => $name ], __METHOD__ );
  108. if ( $actorId ) {
  109. # Hide name from live edits
  110. $subquery = $dbw->selectSQLText(
  111. 'revision_actor_temp', 'revactor_rev', [ 'revactor_actor' => $actorId ], __METHOD__
  112. );
  113. $dbw->update(
  114. 'revision',
  115. [ self::buildSetBitDeletedField( 'rev_deleted', $op, $delUser, $dbw ) ],
  116. [ "rev_id IN ($subquery)" ],
  117. __METHOD__ );
  118. # Hide name from deleted edits
  119. $dbw->update(
  120. 'archive',
  121. [ self::buildSetBitDeletedField( 'ar_deleted', $op, $delUser, $dbw ) ],
  122. [ 'ar_actor' => $actorId ],
  123. __METHOD__
  124. );
  125. # Hide name from logs
  126. $dbw->update(
  127. 'logging',
  128. [ self::buildSetBitDeletedField( 'log_deleted', $op, $delUser, $dbw ) ],
  129. [ 'log_actor' => $actorId, 'log_type != ' . $dbw->addQuotes( 'suppress' ) ],
  130. __METHOD__
  131. );
  132. # Hide name from RC
  133. $dbw->update(
  134. 'recentchanges',
  135. [ self::buildSetBitDeletedField( 'rc_deleted', $op, $delUser, $dbw ) ],
  136. [ 'rc_actor' => $actorId ],
  137. __METHOD__
  138. );
  139. # Hide name from live images
  140. $dbw->update(
  141. 'oldimage',
  142. [ self::buildSetBitDeletedField( 'oi_deleted', $op, $delUser, $dbw ) ],
  143. [ 'oi_actor' => $actorId ],
  144. __METHOD__
  145. );
  146. # Hide name from deleted images
  147. $dbw->update(
  148. 'filearchive',
  149. [ self::buildSetBitDeletedField( 'fa_deleted', $op, $delUser, $dbw ) ],
  150. [ 'fa_actor' => $actorId ],
  151. __METHOD__
  152. );
  153. }
  154. }
  155. # Hide log entries pointing to the user page
  156. $dbw->update(
  157. 'logging',
  158. [ self::buildSetBitDeletedField( 'log_deleted', $op, $delAction, $dbw ) ],
  159. [ 'log_namespace' => NS_USER, 'log_title' => $userDbKey,
  160. 'log_type != ' . $dbw->addQuotes( 'suppress' ) ],
  161. __METHOD__
  162. );
  163. # Hide RC entries pointing to the user page
  164. $dbw->update(
  165. 'recentchanges',
  166. [ self::buildSetBitDeletedField( 'rc_deleted', $op, $delAction, $dbw ) ],
  167. [ 'rc_namespace' => NS_USER, 'rc_title' => $userDbKey, 'rc_logid > 0' ],
  168. __METHOD__
  169. );
  170. # Done!
  171. return true;
  172. }
  173. private static function buildSetBitDeletedField( $field, $op, $value, $dbw ) {
  174. return $field . ' = ' . ( $op === '&'
  175. ? $dbw->bitAnd( $field, $value )
  176. : $dbw->bitOr( $field, $value ) );
  177. }
  178. public static function suppressUserName( $name, $userId, $dbw = null ) {
  179. return self::setUsernameBitfields( $name, $userId, '|', $dbw );
  180. }
  181. public static function unsuppressUserName( $name, $userId, $dbw = null ) {
  182. return self::setUsernameBitfields( $name, $userId, '&', $dbw );
  183. }
  184. }