}
public function getQueryInfo() {
+ $tables = array( 'logging', 'user' );
$this->mConds[] = 'user_id = log_user';
+ $index = array();
+ # Add log_search table if there are conditions on it
+ if( array_key_exists('ls_field',$this->mConds) ) {
+ $tables[] = 'log_search';
+ $index = array( 'log_search' => 'PRIMARY', 'logging' => 'PRIMARY' );
# Don't use the wrong logging index
- if( $this->title || $this->pattern || $this->user ) {
- $index = array( 'USE INDEX' => array( 'logging' => array('page_time','user_time') ) );
+ } else if( $this->title || $this->pattern || $this->user ) {
+ $index = array( 'logging' => array('page_time','user_time') );
} else if( $this->types ) {
- $index = array( 'USE INDEX' => array( 'logging' => 'type_time' ) );
+ $index = array( 'logging' => 'type_time' );
} else {
- $index = array( 'USE INDEX' => array( 'logging' => 'times' ) );
+ $index = array( 'logging' => 'times' );
}
$info = array(
- 'tables' => array( 'logging', 'user' ),
+ 'tables' => $tables,
'fields' => array( 'log_type', 'log_action', 'log_user', 'log_namespace', 'log_title', 'log_params',
'log_comment', 'log_id', 'log_deleted', 'log_timestamp', 'user_name', 'user_editcount' ),
'conds' => $this->mConds,
- 'options' => $index,
- 'join_conds' => array( 'user' => array( 'INNER JOIN', 'user_id=log_user' ) ),
+ 'options' => array( 'USE INDEX' => $index ),
+ 'join_conds' => array( 'user' => array( 'INNER JOIN', 'user_id=log_user' ),
+ 'log_search' => array( 'INNER JOIN', 'ls_log_id=log_id' ) ),
);
ChangeTags::modifyDisplayQuery( $info['tables'], $info['fields'], $info['conds'],
$this->type, $this->action, $this->target, $this->comment, $this->params, $newId );
$rc->notifyRC2UDP();
}
- return true;
+ return $newId;
}
/**
return $this->saveContent();
}
+
+ /**
+ * Add relations to log_search table
+ * @static
+ */
+ public function addRelations( $field, $values, $logid ) {
+ if( empty($values) )
+ return false; // nothing
+ $data = array();
+ foreach( $values as $value ) {
+ $data[] = array('ls_field' => $field,'ls_value' => $value,'ls_log_id' => $logid);
+ }
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' );
+ return true;
+ }
/**
* Create a blob from a parameter array
$this->showImages();
} else if( $this->deleteKey == 'logid' ) {
$this->showLogItems();
- return; // no logs for now
}
- list($qc,$lim) = $this->getLogQueryCond();
+ $qc = $this->getLogQueryCond();
# Show relevant lines from the deletion log
$wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'delete' ) ) . "</h2>\n" );
- LogEventsList::showLogExtract( $wgOut, 'delete', $this->page->getPrefixedText(), '', $lim, $qc );
+ LogEventsList::showLogExtract( $wgOut, 'delete', $this->page->getPrefixedText(), '', 25, $qc );
# Show relevant lines from the suppression log
if( $wgUser->isAllowed( 'suppressionlog' ) ) {
$wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'suppress' ) ) . "</h2>\n" );
- LogEventsList::showLogExtract( $wgOut, 'suppress', $this->page->getPrefixedText(), '', $lim, $qc );
+ LogEventsList::showLogExtract( $wgOut, 'suppress', $this->page->getPrefixedText(), '', 25, $qc );
}
}
}
private function getLogQueryCond() {
- $ids = $safeIds = array();
- $limit = 25; // default
- $conds = array( 'log_action' => 'revision' ); // revision delete logs
+ $logAction = 'revision';
switch( $this->deleteKey ) {
case 'oldid':
$ids = $this->oldids;
case 'fileid':
$ids = $this->fileids;
break;
+ case 'logid':
+ $ids = $this->logids;
+ $logAction = 'event';
+ break;
default: // bad type?
- return array($conds,$limit);
- }
- // Just get the whole log if there are a lot if items
- if( count($ids) > $limit )
- return array($conds,$limit);
- // Digit chars only
- foreach( $ids as $id ) {
- if( preg_match( '/^\d+$/', $id, $m ) ) {
- $safeIds[] = $m[0];
- }
- }
- // Format is <id1,id2,i3...>
- if( count($safeIds) ) {
- $conds[] = "log_params RLIKE '^{$this->deleteKey}.*(^|\n|,)(".implode('|',$safeIds).")(,|\n|$)'";
- } else {
- $conds = array('1=0');
- }
- return array($conds,$limit);
+ return array();
+ }
+ // Revision delete logs for these item
+ $conds = array( 'log_action' => $logAction );
+ $conds['ls_field'] = RevisionDeleter::getRelationType( $this->deleteKey );
+ $conds['ls_value'] = $ids;
+ $conds[] = 'log_id = ls_log_id';
+ return $conds;
}
private function secureOperation() {
private function failure() {
global $wgOut;
- $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
+ $wgOut->setPagetitle( wfMsg( 'actionfailed' ) );
$wrap = '<span class="error">$1</span>';
if( $this->deleteKey == 'logid' ) {
$this->showLogItems();
$param, $items = array() )
{
// Put things hidden from sysops in the oversight log
- $logtype = ( ($nbitfield | $obitfield) & Revision::DELETED_RESTRICTED ) ?
+ $logType = ( ($nbitfield | $obitfield) & Revision::DELETED_RESTRICTED ) ?
'suppress' : 'delete';
- $log = new LogPage( $logtype );
+ // Log deletions show with a difference action message
+ $logAction = ( $param == 'logid' ) ? 'event' : 'revision';
+ // Track what items changed here
$itemCSV = implode(',',$items);
-
+ // Add params for effected page and ids
if( $param == 'logid' ) {
$params = array( $itemCSV, "ofield={$obitfield}", "nfield={$nbitfield}" );
- $log->addEntry( 'event', $title, $comment, $params );
} else {
- // Add params for effected page and ids
$params = array( $param, $itemCSV, "ofield={$obitfield}", "nfield={$nbitfield}" );
- $log->addEntry( 'revision', $title, $comment, $params );
}
+ // Actually add the deletion log entry
+ $log = new LogPage( $logType );
+ $logid = $log->addEntry( $logAction, $title, $comment, $params );
+ // Allow for easy searching of deletion log items for revision/log items
+ $log->addRelations( self::getRelationType($param), $items, $logid );
}
-}
+
+ // Get DB field name for URL param...
+ // Future code for other things may also track
+ // other types of revision-specific changes.
+ public static function getRelationType( $param ) {
+ switch( $param ) {
+ case 'oldid':
+ return 'rev_id';
+ case 'artimestamp':
+ return 'rev_timestamp';
+ case 'oldimage':
+ return 'oi_timestamp';
+ case 'fileid':
+ return 'file_id';
+ case 'logid':
+ return 'log_id';
+ }
+ throw new MWException( "Bad log URL param type!" );
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Makes the required database updates for Special:ProtectedPages
+ * to show all protected pages, even ones before the page restrictions
+ * schema change. All remaining page_restriction column values are moved
+ * to the new table.
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+define( 'BATCH_SIZE', 100 );
+
+require_once 'commandLine.inc';
+
+$db =& wfGetDB( DB_MASTER );
+if ( !$db->tableExists( 'log_search' ) ) {
+ echo "log_search does not exist\n";
+ exit( 1 );
+}
+
+migrate_log_params( $db );
+
+function migrate_log_params( $db ) {
+ $start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
+ if( !$start ) {
+ die("Nothing to do.\n");
+ }
+ $end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
+
+ # Do remaining chunk
+ $end += BATCH_SIZE - 1;
+ $blockStart = $start;
+ $blockEnd = $start + BATCH_SIZE - 1;
+ while( $blockEnd <= $end ) {
+ echo "...doing log_id from $blockStart to $blockEnd\n";
+ $cond = "log_id BETWEEN $blockStart AND $blockEnd";
+ $res = $db->select( 'logging', '*', $cond, __FUNCTION__ );
+ $batch = array();
+ while( $row = $db->fetchObject( $res ) ) {
+ // RevisionDelete logs - revisions
+ if( LogEventsList::typeAction( $row, array('delete','suppress'), 'revision' ) ) {
+ $params = LogPage::extractParams( $row->log_params );
+ // Param format: <urlparam> <item CSV> [<ofield> <nfield>]
+ if( count($params) >= 2 ) {
+ $field = RevisionDeleter::getRelationType($params[0]);
+ $items = explode(',',$params[1]);
+ $log = new LogPage( $row->log_type );
+ $log->addRelations( $field, $items, $row->log_id );
+ }
+ // RevisionDelete logs - log events
+ } else if( LogEventsList::typeAction( $row, array('delete','suppress'), 'event' ) ) {
+ $params = LogPage::extractParams( $row->log_params );
+ // Param format: <item CSV> [<ofield> <nfield>]
+ if( count($params) >= 1 ) {
+ $items = explode(',',$params[0]);
+ $log = new LogPage( $row->log_type );
+ $log->addRelations( 'log_id', $items, $row->log_id );
+ }
+ }
+ }
+ $blockStart += BATCH_SIZE - 1;
+ $blockEnd += BATCH_SIZE - 1;
+ wfWaitForSlaves( 5 );
+ }
+ echo "...Done!\n";
+}
CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
+CREATE TABLE /*_*/log_search (
+ -- The type of ID (rev ID, log ID, rev timestamp, username)
+ ls_field varbinary(32) NOT NULL,
+ -- The value of the ID
+ ls_value varchar(255) NOT NULL,
+ -- Key to log_id
+ ls_log_id int unsigned NOT NULL default 0,
+ PRIMARY KEY (ls_field,ls_value,ls_log_id)
+);
+CREATE INDEX /*i*/ls_log_id ON /*_*/log_search (ls_log_id);
+
+
CREATE TABLE /*_*/trackbacks (
tb_id int PRIMARY KEY AUTO_INCREMENT,
tb_page int REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
array( 'add_table', 'tag_summary', 'patch-change_tag.sql' ),
array( 'add_table', 'valid_tag', 'patch-change_tag.sql' ),
array( 'add_table', 'user_properties', 'patch-user_properties.sql' ),
+ array( 'add_table', 'log_search', 'patch-log_search.sql' ),
),
'sqlite' => array(