Index: includes/Article.php =================================================================== --- includes/Article.php (revision 46705) +++ includes/Article.php (working copy) @@ -1520,6 +1520,7 @@ */ public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) { global $wgUser, $wgDBtransactions, $wgUseAutomaticEditSummaries; + global $wgUseRCPatrol, $wgUseNPPatrol; # Low-level sanity check if( $this->mTitle->getText() == '' ) { @@ -1597,11 +1598,17 @@ wfProfileOut( __METHOD__ ); return $status; } + + # Mark as patrolled if the user can do so + $patrolled = $wgUseRCPatrol && $this->mTitle->userCan('autopatrol'); + $revision = new Revision( array( 'page' => $this->getId(), 'comment' => $summary, 'minor_edit' => $isminor, + 'bot' => $bot, + 'patrolled' => $patrolled, 'text' => $text, 'parent_id' => $this->mLatest, 'user' => $user->getId(), @@ -1630,12 +1637,9 @@ $revisionId = 0; $dbw->rollback(); } else { - global $wgUseRCPatrol; wfRunHooks( 'NewRevisionFromEditComplete', array($this, $revision, $baseRevId, $user) ); # Update recentchanges if( !( $flags & EDIT_SUPPRESS_RC ) ) { - # Mark as patrolled if the user can do so - $patrolled = $wgUseRCPatrol && $this->mTitle->userCan('autopatrol'); # Add RC row to the DB $rc = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $user, $summary, $this->mLatest, $this->getTimestamp(), $bot, '', $oldsize, $newsize, @@ -1695,12 +1699,17 @@ wfProfileOut( __METHOD__ ); return $status; } + + # Mark as patrolled if the user can do so + $patrolled = ($wgUseRCPatrol || $wgUseNPPatrol) && $this->mTitle->userCan('autopatrol'); # Save the revision text... $revision = new Revision( array( 'page' => $newid, 'comment' => $summary, 'minor_edit' => $isminor, + 'bot' => $bot, + 'patrolled' => $patrolled, 'text' => $text, 'user' => $user->getId(), 'user_text' => $user->getName(), @@ -1715,9 +1724,6 @@ wfRunHooks( 'NewRevisionFromEditComplete', array($this, $revision, false, $user) ); # Update recentchanges if( !( $flags & EDIT_SUPPRESS_RC ) ) { - global $wgUseRCPatrol, $wgUseNPPatrol; - # Mark as patrolled if the user can do so - $patrolled = ($wgUseRCPatrol || $wgUseNPPatrol) && $this->mTitle->userCan('autopatrol'); # Add RC row to the DB $rc = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $user, $summary, $bot, '', strlen($text), $revisionId, $patrolled ); Index: includes/RecentChange.php =================================================================== --- includes/RecentChange.php (revision 46705) +++ includes/RecentChange.php (working copy) @@ -313,11 +313,26 @@ 'rc_patrolled' => 1 ), array( - 'rc_id' => $this->getAttribute('rc_id') + 'rc_id' => $this->getAttribute( 'rc_id' ) ), __METHOD__ ); - return $dbw->affectedRows(); + $rows = $dbw->affectedRows(); + $oldid = $this->getAttribute( 'rc_this_oldid' ); + if( $oldid != 0 ) { + $dbw->update( + 'revision', + array( + 'rev_patrolled' => 1 + ), + array( + 'rev_id' => $oldid + ), + __METHOD__ + ); + $rows += $dbw->affectedRows(); + } + return $rows; } # Makes an entry in the database corresponding to an edit @@ -555,12 +570,12 @@ 'rc_cur_id' => $row->page_id, 'rc_this_oldid' => $row->rev_id, 'rc_last_oldid' => isset($row->rc_last_oldid) ? $row->rc_last_oldid : 0, - 'rc_bot' => 0, + 'rc_bot' => $row->rev_bot ? 1 : 0, 'rc_moved_to_ns' => 0, 'rc_moved_to_title' => '', 'rc_ip' => '', 'rc_id' => $row->rc_id, - 'rc_patrolled' => $row->rc_patrolled, + 'rc_patrolled' => $row->rev_patrolled ? 1 : 0, 'rc_new' => $row->page_is_new, # obsolete 'rc_old_len' => $row->rc_old_len, 'rc_new_len' => $row->rc_new_len, Index: includes/Revision.php =================================================================== --- includes/Revision.php (revision 46705) +++ includes/Revision.php (working copy) @@ -267,7 +267,9 @@ 'rev_minor_edit', 'rev_deleted', 'rev_len', - 'rev_parent_id' + 'rev_parent_id', + 'rev_bot', + 'rev_patrolled' ); } @@ -317,6 +319,16 @@ $this->mSize = null; else $this->mSize = intval( $row->rev_len ); + + if( !isset( $row->rev_bot ) ) + $this->mBot = 0; + else + $this->mBot = intval( $row->rev_bot ); + + if( !isset( $row->rev_patrolled ) ) + $this->mPatrolled = 0; + else + $this->mPatrolled = intval( $row->rev_patrolled ); if( isset( $row->page_latest ) ) { $this->mCurrent = ( $row->rev_id == $row->page_latest ); @@ -328,7 +340,7 @@ } // Lazy extraction... - $this->mText = null; + $this->mText = null; if( isset( $row->old_text ) ) { $this->mTextRow = $row; } else { @@ -349,6 +361,8 @@ $this->mDeleted = isset( $row['deleted'] ) ? intval( $row['deleted'] ) : 0; $this->mSize = isset( $row['len'] ) ? intval( $row['len'] ) : null; $this->mParentId = isset( $row['parent_id'] ) ? intval( $row['parent_id'] ) : null; + $this->mBot = isset( $row['bot'] ) ? intval( $row['bot'] ) : 0; + $this->mPatrolled = isset( $row['patrolled'] ) ? intval( $row['patrolled'] ) : 0; // Enforce spacing trimming on supplied text $this->mComment = isset( $row['comment'] ) ? trim( strval( $row['comment'] ) ) : null; @@ -539,9 +553,25 @@ } /** + * @return bool + */ + public function isBot() { + return (bool)$this->mBot; + } + + /** + * @return bool + */ + public function isPatrolled() { + return (bool)$this->mPatrolled; + } + + /** + * @deprecated * @return int rcid of the unpatrolled row, zero if there isn't one */ public function isUnpatrolled() { + wfDeprecated(__METHOD__); if( $this->mUnpatrolled !== NULL ) { return $this->mUnpatrolled; } @@ -560,7 +590,7 @@ } /** - * int $field one of DELETED_* bitfield constants + * @param int $field one of DELETED_* bitfield constants * @return bool */ public function isDeleted( $field ) { @@ -842,7 +872,9 @@ 'rev_deleted' => $this->mDeleted, 'rev_len' => $this->mSize, 'rev_parent_id' => is_null($this->mParentId) ? - $this->getPreviousRevisionId( $dbw ) : $this->mParentId + $this->getPreviousRevisionId( $dbw ) : $this->mParentId, + 'rev_bot' => $this->mBot ? 1 : 0, + 'rev_patrolled' => $this->mPatrolled ? 1 : 0 ), __METHOD__ ); @@ -924,9 +956,10 @@ * @param int $pageId ID number of the page to read from * @param string $summary * @param bool $minor + * @param bool $bot * @return Revision */ - public static function newNullRevision( $dbw, $pageId, $summary, $minor ) { + public static function newNullRevision( $dbw, $pageId, $summary, $minor, $bot = false ) { wfProfileIn( __METHOD__ ); $current = $dbw->selectRow( @@ -943,6 +976,8 @@ 'page' => $pageId, 'comment' => $summary, 'minor_edit' => $minor, + 'bot' => $bot, + 'patrolled' => 1, # null revisions are always patrolled 'text_id' => $current->rev_text_id, 'parent_id' => $current->page_latest, 'len' => $current->rev_len Index: maintenance/populateRevBotPatrolled.inc =================================================================== --- maintenance/populateRevBotPatrolled.inc (revision 0) +++ maintenance/populateRevBotPatrolled.inc (revision 0) @@ -0,0 +1,53 @@ +selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ ); + $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ ); + if( is_null( $start ) || is_null( $end ) ){ + echo "...revision table seems to be empty.\n"; + $db->insert( 'updatelog', + array( 'ul_key' => 'populate rev_bot and rev_patrolled' ), + __FUNCTION__, + 'IGNORE' ); + return; + } + # Do remaining chunk + $end += BATCH_SIZE - 1; + $blockStart = $start; + $blockEnd = $start + BATCH_SIZE - 1; + $count = 0; + $changed = 0; + while( $blockEnd <= $end ) { + echo "...doing rc_this_oldid from $blockStart to $blockEnd\n"; + $cond = "rc_this_oldid BETWEEN $blockStart AND $blockEnd"; + $res = $db->select( 'recentchanges', + array( 'rc_this_oldid', 'rc_bot', 'rc_patrolled' ), + $cond, __FUNCTION__ ); + foreach( $res as $row ) { + $db->update( 'revision', + array( 'rev_bot' => $row->rc_bot, + 'rev_patrolled' => $row->rc_patrolled ), + array( 'rev_id' => $row->rc_this_oldid ), + __FUNCTION__ ); + $count++; + } + $blockStart += BATCH_SIZE - 1; + $blockEnd += BATCH_SIZE - 1; + wfWaitForSlaves( 5 ); + } + $logged = $db->insert( 'updatelog', + array( 'ul_key' => 'populate rev_bot and rev_patrolled' ), + __FUNCTION__, + 'IGNORE' ); + if( $logged ) { + echo "rev_bot and rev_patrolled population complete ... {$count} rows\n"; + return true; + } else { + echo "Could not insert rev_bot and rev_patrolled population row.\n"; + return false; + } +} + Index: maintenance/populateRevBotPatrolled.php =================================================================== --- maintenance/populateRevBotPatrolled.php (revision 0) +++ maintenance/populateRevBotPatrolled.php (revision 0) @@ -0,0 +1,16 @@ +tableExists( 'revision' ) ) { + echo "revision table does not exist\n"; + exit( 1 ); +} + +populate_rev_bot_patrolled( $db ); Index: maintenance/tables.sql =================================================================== --- maintenance/tables.sql (revision 46705) +++ maintenance/tables.sql (working copy) @@ -278,7 +278,15 @@ -- Key to revision.rev_id -- This field is used to add support for a tree structure (The Adjacency List Model) - rev_parent_id int unsigned default NULL + rev_parent_id int unsigned default NULL, + + -- Records whether the edit was marked with the bot flag. + -- These edits are hidden from Special:Recentchanges by default + rev_bot tinyint unsigned NOT NULL default 0, + + -- Records whether the edit was marked as patrolled. If patrolling is enabled, + -- non-patrolled edits will have a warning flag on Special:Recentchanges + rev_patrolled tinyint unsigned NOT NULL default 0 ) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; -- In case tables are created as MyISAM, use row hints for MySQL <5.0 to avoid 4GB limit Index: maintenance/updaters.inc =================================================================== --- maintenance/updaters.inc (revision 46705) +++ maintenance/updaters.inc (working copy) @@ -153,6 +153,9 @@ array( 'add_table', 'change_tag', 'patch-change_tag.sql' ), array( 'add_table', 'tag_summary', 'patch-change_tag.sql' ), array( 'add_table', 'valid_tag', 'patch-change_tag.sql' ), + array( 'add_field', 'revision', 'rev_bot', 'patch-rev_bot.sql' ), + array( 'add_field', 'revision', 'rev_patrolled', 'patch-rev_patrolled.sql' ), + array( 'do_populate_rev_bot_patrolled' ), ), 'sqlite' => array( @@ -1235,6 +1238,17 @@ populate_rev_parent_id( $wgDatabase ); } +function do_populate_rev_bot_patrolled() { + if( update_row_exists( 'populate rev_bot and rev_patrolled' ) ) { + echo "...rev_bot and rev_patrolled columns already populated.\n"; + return; + } + require_once( 'populateRevBotPatrolled.inc' ); + + global $wgDatabase; + populate_rev_bot_patrolled( $wgDatabase ); +} + function update_password_format() { if ( update_row_exists( 'password format' ) ) { echo "...password hash format already changed\n";