00001 <?php
00025 require_once( dirname(__FILE__) . '/Maintenance.php' );
00026
00027 class RebuildRecentchanges extends Maintenance {
00028 public function __construct() {
00029 parent::__construct();
00030 $this->mDescription = "Rebuild recent changes";
00031 }
00032
00033 public function execute() {
00034 global $wgTitle;
00035 $wgTitle = Title::newFromText( "Rebuild recent changes script" );
00036 $this->rebuildRecentChangesTablePass1();
00037 $this->rebuildRecentChangesTablePass2();
00038 $this->rebuildRecentChangesTablePass3();
00039 $this->rebuildRecentChangesTablePass4();
00040 $this->purgeFeeds();
00041 $this->output( "Done.\n" );
00042 }
00043
00048 function rebuildRecentChangesTablePass1()
00049 {
00050 $dbw = wfGetDB( DB_MASTER );
00051
00052 $dbw->delete( 'recentchanges', '*' );
00053
00054 $this->output( "Loading from page and revision tables...\n" );
00055
00056 global $wgRCMaxAge;
00057
00058 $this->output( '$wgRCMaxAge=' . $wgRCMaxAge );
00059 $days = $wgRCMaxAge / 24 / 3600;
00060 if ( intval($days) == $days ) {
00061 $this->output( " (" . $days . " days)\n" );
00062 } else {
00063 $this->output( " (approx. " . intval($days) . " days)\n" );
00064 }
00065
00066 $cutoff = time() - $wgRCMaxAge;
00067 $dbw->insertSelect( 'recentchanges', array( 'page', 'revision' ),
00068 array(
00069 'rc_timestamp' => 'rev_timestamp',
00070 'rc_cur_time' => 'rev_timestamp',
00071 'rc_user' => 'rev_user',
00072 'rc_user_text' => 'rev_user_text',
00073 'rc_namespace' => 'page_namespace',
00074 'rc_title' => 'page_title',
00075 'rc_comment' => 'rev_comment',
00076 'rc_minor' => 'rev_minor_edit',
00077 'rc_bot' => 0,
00078 'rc_new' => 'page_is_new',
00079 'rc_cur_id' => 'page_id',
00080 'rc_this_oldid' => 'rev_id',
00081 'rc_last_oldid' => 0,
00082 'rc_type' => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ),
00083 'rc_deleted' => 'rev_deleted'
00084 ), array(
00085 'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
00086 'rev_page=page_id'
00087 ), __METHOD__,
00088 array(),
00089 array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 5000 )
00090 );
00091 }
00092
00097 private function rebuildRecentChangesTablePass2() {
00098 $dbw = wfGetDB( DB_MASTER );
00099 list ($recentchanges, $revision) = $dbw->tableNamesN( 'recentchanges', 'revision' );
00100
00101 $this->output( "Updating links and size differences...\n" );
00102
00103 # Fill in the rc_last_oldid field, which points to the previous edit
00104 $sql = "SELECT rc_cur_id,rc_this_oldid,rc_timestamp FROM $recentchanges " .
00105 "ORDER BY rc_cur_id,rc_timestamp";
00106 $res = $dbw->query( $sql, DB_MASTER );
00107
00108 $lastCurId = 0;
00109 $lastOldId = 0;
00110 foreach ( $res as $obj ) {
00111 $new = 0;
00112 if( $obj->rc_cur_id != $lastCurId ) {
00113 # Switch! Look up the previous last edit, if any
00114 $lastCurId = intval( $obj->rc_cur_id );
00115 $emit = $obj->rc_timestamp;
00116 $sql2 = "SELECT rev_id,rev_len FROM $revision " .
00117 "WHERE rev_page={$lastCurId} ".
00118 "AND rev_timestamp<'{$emit}' ORDER BY rev_timestamp DESC";
00119 $sql2 = $dbw->limitResult($sql2, 1, false);
00120 $res2 = $dbw->query( $sql2 );
00121 if( $row = $dbw->fetchObject( $res2 ) ) {
00122 $lastOldId = intval($row->rev_id);
00123 # Grab the last text size if available
00124 $lastSize = !is_null($row->rev_len) ? intval($row->rev_len) : 'NULL';
00125 } else {
00126 # No previous edit
00127 $lastOldId = 0;
00128 $lastSize = 'NULL';
00129 $new = 1;
00130 }
00131 $dbw->freeResult( $res2 );
00132 }
00133 if( $lastCurId == 0 ) {
00134 $this->output( "Uhhh, something wrong? No curid\n" );
00135 } else {
00136 # Grab the entry's text size
00137 $size = $dbw->selectField( 'revision', 'rev_len', array('rev_id' => $obj->rc_this_oldid ) );
00138 $size = !is_null($size) ? intval($size) : 'NULL';
00139
00140 $sql3 = "UPDATE $recentchanges SET rc_last_oldid=$lastOldId,rc_new=$new,rc_type=$new," .
00141 "rc_old_len=$lastSize,rc_new_len=$size " .
00142 "WHERE rc_cur_id={$lastCurId} AND rc_this_oldid={$obj->rc_this_oldid}";
00143 $dbw->query( $sql3 );
00144
00145 $lastOldId = intval( $obj->rc_this_oldid );
00146 $lastSize = $size;
00147 }
00148 }
00149 $dbw->freeResult( $res );
00150 }
00151
00156 private function rebuildRecentChangesTablePass3() {
00157 $dbw = wfGetDB( DB_MASTER );
00158
00159 $this->output( "Loading from user, page, and logging tables...\n" );
00160
00161 global $wgRCMaxAge, $wgLogTypes, $wgLogRestrictions;
00162
00163 $basicRCLogs = array_diff( $wgLogTypes, array_keys( $wgLogRestrictions ) );
00164
00165
00166 $selectLogs = array();
00167 foreach( $basicRCLogs as $logtype ) {
00168 $safetype = $dbw->strencode( $logtype );
00169 $selectLogs[] = "'$safetype'";
00170 }
00171
00172 $cutoff = time() - $wgRCMaxAge;
00173 list($logging, $page) = $dbw->tableNamesN( 'logging', 'page' );
00174 $dbw->insertSelect( 'recentchanges', array( 'user', "$logging LEFT JOIN $page ON (log_namespace=page_namespace AND log_title=page_title)" ),
00175 array(
00176 'rc_timestamp' => 'log_timestamp',
00177 'rc_cur_time' => 'log_timestamp',
00178 'rc_user' => 'log_user',
00179 'rc_user_text' => 'user_name',
00180 'rc_namespace' => 'log_namespace',
00181 'rc_title' => 'log_title',
00182 'rc_comment' => 'log_comment',
00183 'rc_minor' => 0,
00184 'rc_bot' => 0,
00185 'rc_patrolled' => 1,
00186 'rc_new' => 0,
00187 'rc_this_oldid' => 0,
00188 'rc_last_oldid' => 0,
00189 'rc_type' => RC_LOG,
00190 'rc_cur_id' => $dbw->cascadingDeletes() ? 'page_id' : 'COALESCE(page_id, 0)',
00191 'rc_log_type' => 'log_type',
00192 'rc_log_action' => 'log_action',
00193 'rc_logid' => 'log_id',
00194 'rc_params' => 'log_params',
00195 'rc_deleted' => 'log_deleted'
00196 ), array(
00197 'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
00198 'log_user=user_id',
00199 'log_type IN(' . implode(',',$selectLogs) . ')'
00200 ), __METHOD__,
00201 array(),
00202 array( 'ORDER BY' => 'log_timestamp DESC', 'LIMIT' => 5000 )
00203 );
00204 }
00205
00210 private function rebuildRecentChangesTablePass4() {
00211 global $wgGroupPermissions, $wgUseRCPatrol;
00212
00213 $dbw = wfGetDB( DB_MASTER );
00214
00215 list($recentchanges,$usergroups,$user) = $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
00216
00217 $botgroups = $autopatrolgroups = array();
00218 foreach( $wgGroupPermissions as $group => $rights ) {
00219 if( isset( $rights['bot'] ) && $rights['bot'] == true ) {
00220 $botgroups[] = $dbw->addQuotes( $group );
00221 }
00222 if( $wgUseRCPatrol && isset( $rights['autopatrol'] ) && $rights['autopatrol'] == true ) {
00223 $autopatrolgroups[] = $dbw->addQuotes( $group );
00224 }
00225 }
00226 # Flag our recent bot edits
00227 if( !empty($botgroups) ) {
00228 $botwhere = implode(',',$botgroups);
00229 $botusers = array();
00230
00231 $this->output( "Flagging bot account edits...\n" );
00232
00233 # Find all users that are bots
00234 $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
00235 "WHERE ug_group IN($botwhere) AND user_id = ug_user";
00236 $res = $dbw->query( $sql, DB_MASTER );
00237
00238 foreach( $res as $obj ) {
00239 $botusers[] = $dbw->addQuotes( $obj->user_name );
00240 }
00241 # Fill in the rc_bot field
00242 if( !empty($botusers) ) {
00243 $botwhere = implode(',',$botusers);
00244 $sql2 = "UPDATE $recentchanges SET rc_bot=1 " .
00245 "WHERE rc_user_text IN($botwhere)";
00246 $dbw->query( $sql2 );
00247 }
00248 }
00249 global $wgMiserMode;
00250 # Flag our recent autopatrolled edits
00251 if( !$wgMiserMode && !empty($autopatrolgroups) ) {
00252 $patrolwhere = implode(',',$autopatrolgroups);
00253 $patrolusers = array();
00254
00255 $this->output( "Flagging auto-patrolled edits...\n" );
00256
00257 # Find all users in RC with autopatrol rights
00258 $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
00259 "WHERE ug_group IN($patrolwhere) AND user_id = ug_user";
00260 $res = $dbw->query( $sql, DB_MASTER );
00261
00262 foreach( $res as $obj ) {
00263 $patrolusers[] = $dbw->addQuotes( $obj->user_name );
00264 }
00265
00266 # Fill in the rc_patrolled field
00267 if( !empty($patrolusers) ) {
00268 $patrolwhere = implode(',',$patrolusers);
00269 $sql2 = "UPDATE $recentchanges SET rc_patrolled=1 " .
00270 "WHERE rc_user_text IN($patrolwhere)";
00271 $dbw->query( $sql2 );
00272 }
00273 }
00274
00275 $dbw->freeResult( $res );
00276 }
00277
00281 private function purgeFeeds() {
00282 global $wgFeedClasses, $messageMemc;
00283
00284 $this->output( "Deleting feed timestamps.\n" );
00285
00286 foreach( $wgFeedClasses as $feed => $className ) {
00287 $messageMemc->delete( wfMemcKey( 'rcfeed', $feed, 'timestamp' ) ); # Good enough for now.
00288 }
00289 }
00290
00291 }
00292
00293 $maintClass = "RebuildRecentchanges";
00294 require_once( DO_MAINTENANCE );