bug 18472 Suppression log filtered by "offender", as Oversight log can be
authorAaron Schulz <aaron@users.mediawiki.org>
Mon, 14 Sep 2009 17:09:13 +0000 (17:09 +0000)
committerAaron Schulz <aaron@users.mediawiki.org>
Mon, 14 Sep 2009 17:09:13 +0000 (17:09 +0000)
includes/LogEventsList.php
includes/specials/SpecialLog.php
includes/specials/SpecialRevisiondelete.php
languages/messages/MessagesEn.php
maintenance/language/messages.inc
maintenance/populateLogSearch.php

index e7e4dbe..7c209f9 100644 (file)
@@ -94,6 +94,7 @@ class LogEventsList {
                $html .= $this->getTypeMenu( $types ) . "\n";
                $html .= $this->getUserInput( $user ) . "\n";
                $html .= $this->getTitleInput( $page ) . "\n";
+               $html .= $this->getExtraInputs( $types ) . "\n";
 
                // Title pattern, if allowed
                if (!$wgMiserMode) {
@@ -238,6 +239,15 @@ class LogEventsList {
                        Xml::checkLabel( wfMsg( 'log-title-wildcard' ), 'pattern', 'pattern', $pattern ) .
                        '</span>';
        }
+       
+       private function getExtraInputs( $types ) {
+               global $wgRequest;
+               if( count($types) == 1 && $types[0] == 'suppress' ) {
+                       return Xml::inputLabel( wfMsg('revdelete-offender'), 'offender',
+                               'mw-log-offender', 20, $wgRequest->getVal('offender') );
+               }
+               return '';
+       }
 
        public function beginLogEventsList() {
                return "<ul>\n";
index 2382344..d1ccc8c 100644 (file)
@@ -52,9 +52,19 @@ function wfSpecialLog( $par = '' ) {
                $y = '';
                $m = '';
        }
+       # Handle type-specific inputs
+       $qc = array();
+       if( $type == 'suppress' ) {
+               $offender = User::newFromName( $wgRequest->getVal('offender'), false );
+               if( $offender && $offender->getId() > 0 ) {
+                       $qc = array( 'ls_field' => 'target_author_id', 'ls_value' => $offender->getId() );
+               } else if( $offender && IP::isIPAddress( $offender->getName() ) ) {
+                       $qc = array( 'ls_field' => 'target_author_ip', 'ls_value' => $offender->getName() );
+               }
+       }
        # Create a LogPager item to get the results and a LogEventsList item to format them...
        $loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
-       $pager = new LogPager( $loglist, $type, $user, $title, $pattern, array(), $y, $m, $tagFilter );
+       $pager = new LogPager( $loglist, $type, $user, $title, $pattern, $qc, $y, $m, $tagFilter );
        # Set title and add header
        $loglist->showHeader( $pager->getType() );
        # Show form options
index 26e4de5..c4656b3 100644 (file)
@@ -201,9 +201,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                # Give a link to the logs/hist for this page
                if( $this->targetObj ) {
                        $links = array();
-                       $logtitle = SpecialPage::getTitleFor( 'Log' );
                        $links[] = $this->skin->linkKnown(
-                               $logtitle,
+                               SpecialPage::getTitleFor( 'Log' ),
                                wfMsgHtml( 'viewpagelogs' ),
                                array(),
                                array( 'page' => $this->targetObj->getPrefixedText() )
@@ -616,6 +615,7 @@ class RevisionDeleter {
        // Get DB field name for URL param...
        // Future code for other things may also track
        // other types of revision-specific changes.
+       // @returns string One of log_id/rev_id/fa_id/ar_timestamp/oi_archive_name
        public static function getRelationType( $typeName ) {
                if ( isset( SpecialRevisionDelete::$deprecatedTypeMap[$typeName] ) ) {
                        $typeName = SpecialRevisionDelete::$deprecatedTypeMap[$typeName];
@@ -638,6 +638,8 @@ abstract class RevDel_List {
        var $type = null; // override this
        var $idField = null; // override this
        var $dateField = false; // override this
+       var $authorIdField = false; // override this
+       var $authorNameField = false; // override this
 
        /**
         * @param $special The parent SpecialPage
@@ -658,7 +660,7 @@ abstract class RevDel_List {
        }
 
        /**
-        * Get the DB field name associated with the ID list/
+        * Get the DB field name associated with the ID list
         */
        public function getIdField() {
                return $this->idField;
@@ -671,6 +673,19 @@ abstract class RevDel_List {
                return $this->dateField;
        }
 
+       /**
+        * Get the DB field name storing user ids
+        */
+       public function getAuthorIdField() {
+               return $this->authorIdField;
+       }
+
+       /**
+        * Get the DB field name storing user names
+        */
+       public function getAuthorNameField() {
+               return $this->authorNameField;
+       }
        /**
         * Set the visibility for the revisions in this list. Logging and 
         * transactions are done here.
@@ -692,6 +707,7 @@ abstract class RevDel_List {
                $missing = array_flip( $this->ids );
                $this->clearFileOps();
                $idsForLog = array();
+               $authorIds = $authorIPs = array();
 
                for ( $this->reset(); $this->current(); $this->next() ) {
                        $item = $this->current();
@@ -731,6 +747,11 @@ abstract class RevDel_List {
                        if ( $ok ) {
                                $idsForLog[] = $item->getId();
                                $status->successCount++;
+                               if( $item->getAuthorId() > 0 ) {
+                                       $authorIds[] = $item->getAuthorId();
+                               } else if( IP::isIPAddress( $item->getAuthorName() ) ) {
+                                       $authorIPs[] = $item->getAuthorName();
+                               }
                        } else {
                                $status->error( 'revdelete-concurrent-change', $item->formatDate(), $item->formatTime() );
                                $status->failCount++;
@@ -768,6 +789,8 @@ abstract class RevDel_List {
                        'oldBits' => $oldBits,
                        'comment' => $comment,
                        'ids' => $idsForLog,
+                       'authorIds' => $authorIds,
+                       'authorIPs' => $authorIPs
                ) );
                $dbw->commit();
 
@@ -793,6 +816,8 @@ abstract class RevDel_List {
         *     title:           The target title
         *     ids:             The ID list
         *     comment:         The log comment
+        *     authorsIds:      The array of the user IDs of the offenders
+        *     authorsIPs:      The array of the IP/anon user offenders
         */
        protected function updateLog( $params ) {
                // Get the URL param's corresponding DB field
@@ -814,6 +839,8 @@ abstract class RevDel_List {
                        $params['comment'], $logParams );
                // Allow for easy searching of deletion log items for revision/log items
                $log->addRelations( $field, $params['ids'], $logid );
+               $log->addRelations( 'target_author_id', $params['authorIds'], $logid );
+               $log->addRelations( 'target_author_ip', $params['authorIPs'], $logid );
        }
 
        /**
@@ -976,6 +1003,22 @@ abstract class RevDel_Item {
                $field = $this->list->getTimestampField();
                return wfTimestamp( TS_MW, $this->row->$field );
        }
+       
+       /**
+        * Get the author user ID
+        */     
+       public function getAuthorId() {
+               $field = $this->list->getAuthorIdField();
+               return intval( $this->row->$field );
+       }
+
+       /**
+        * Get the author user name
+        */     
+       public function getAuthorName() {
+               $field = $this->list->getAuthorNameField();
+               return strval( $this->row->$field );
+       }
 
        /** 
         * Returns true if the item is "current", and the operation to set the given
@@ -1023,6 +1066,8 @@ class RevDel_RevisionList extends RevDel_List {
        var $type = 'revision';
        var $idField = 'rev_id';
        var $dateField = 'rev_timestamp';
+       var $authorIdField = 'rev_user';
+       var $authorNameField = 'rev_user_text';
 
        public function doQuery( $db ) {
                $ids = array_map( 'intval', $this->ids );
@@ -1192,6 +1237,8 @@ class RevDel_ArchiveList extends RevDel_RevisionList {
        var $type = 'archive';
        var $idField = 'ar_timestamp';
        var $dateField = 'ar_timestamp';
+       var $authorIdField = 'ar_user';
+       var $authorNameField = 'ar_user_text';
 
        public function doQuery( $db ) {
                $timestamps = array();
@@ -1286,6 +1333,8 @@ class RevDel_FileList extends RevDel_List {
        var $type = 'oldimage';
        var $idField = 'oi_archive_name';
        var $dateField = 'oi_timestamp';
+       var $authorIdField = 'oi_user';
+       var $authorNameField = 'oi_user_text';
        var $storeBatch, $deleteBatch, $cleanupBatch;
 
        public function doQuery( $db ) {
@@ -1501,6 +1550,8 @@ class RevDel_ArchivedFileList extends RevDel_FileList {
        var $type = 'filearchive';
        var $idField = 'fa_id';
        var $dateField = 'fa_timestamp';
+       var $authorIdField = 'fa_user';
+       var $authorNameField = 'fa_user_text';
        
        public function doQuery( $db ) {
                $ids = array_map( 'intval', $this->ids );
@@ -1566,6 +1617,8 @@ class RevDel_LogList extends RevDel_List {
        var $type = 'logging';
        var $idField = 'log_id';
        var $dateField = 'log_timestamp';
+       var $authorIdField = 'log_user';
+       var $authorNameField = 'log_user_text';
 
        public function doQuery( $db ) {
                global $wgMessageCache;
@@ -1619,7 +1672,7 @@ class RevDel_LogItem extends RevDel_Item {
                        ),
                        array(
                                'rc_logid' => $this->row->log_id,
-                               'rc_timestamp' => $this->row->log_timestamp
+                               'rc_timestamp' => $this->row->log_timestamp // index
                        ),
                        __METHOD__
                );
@@ -1641,9 +1694,9 @@ class RevDel_LogItem extends RevDel_Item {
                $paramArray = LogPage::extractParams( $this->row->log_params );
                $title = Title::makeTitle( $this->row->log_namespace, $this->row->log_title );
 
-               $logtitle = SpecialPage::getTitleFor( 'Log' );
+               // Log link for this page
                $loglink = $this->special->skin->link(
-                       $logtitle,
+                       SpecialPage::getTitleFor( 'Log' ),
                        wfMsgHtml( 'log' ),
                        array(),
                        array( 'page' => $title->getPrefixedText() )
index 88454c6..a7eef37 100644 (file)
@@ -1509,6 +1509,7 @@ Please check the logs.',
 'revdelete-otherreason'       => 'Other/additional reason:',
 'revdelete-reasonotherlist'   => 'Other reason',
 'revdelete-edit-reasonlist'   => 'Edit delete reasons',
+'revdelete-offender'          => 'Offender:',
 
 # Suppression log
 'suppressionlog'     => 'Suppression log',
index 5ed0e1b..43bd0c0 100644 (file)
@@ -717,6 +717,7 @@ $wgMessageStructure = array(
                'revdelete-otherreason',
                'revdelete-reasonotherlist',
                'revdelete-edit-reasonlist',
+               'revdelete-offender',
        ),
        'suppression' => array(
                'suppressionlog',
index 390a57a..b045104 100644 (file)
@@ -27,6 +27,8 @@ class PopulateLogSearch extends Maintenance {
 
        const LOG_SEARCH_BATCH_SIZE = 100;
 
+       static $tableMap = array('rev' => 'revision', 'fa' => 'filearchive', 'oi' => 'oldimage', 'ar' => 'archive');
+       
        public function __construct() {
                parent::__construct();
                $this->mDescription = "Migrate log params to new table and index for searching";
@@ -48,6 +50,8 @@ class PopulateLogSearch extends Maintenance {
                $end += self::LOG_SEARCH_BATCH_SIZE - 1;
                $blockStart = $start;
                $blockEnd = $start + self::LOG_SEARCH_BATCH_SIZE - 1;
+               
+               $delTypes = array('delete','suppress'); // revisiondelete types
                while( $blockEnd <= $end ) {
                        $this->output( "...doing log_id from $blockStart to $blockEnd\n" );
                        $cond = "log_id BETWEEN $blockStart AND $blockEnd";
@@ -55,33 +59,74 @@ class PopulateLogSearch extends Maintenance {
                        $batch = array();
                        foreach( $res as $row ) {
                                // RevisionDelete logs - revisions
-                               if( LogEventsList::typeAction( $row, array('delete','suppress'), 'revision' ) ) {
+                               if( LogEventsList::typeAction( $row, $delTypes, 'revision' ) ) {
                                        $params = LogPage::extractParams( $row->log_params );
                                        // Param format: <urlparam> <item CSV> [<ofield> <nfield>]
-                                       if( count($params) >= 2 ) {
+                                       if( count($params) < 2 ) continue; // bad row?
+                                       $field = RevisionDeleter::getRelationType($params[0]);
+                                       // B/C, the params may start with a title key (<title> <urlparam> <CSV>)
+                                       if( $field == null ) {
+                                               array_shift($params); // remove title param
                                                $field = RevisionDeleter::getRelationType($params[0]);
-                                               // B/C, the params may start with a title key
-                                               if( $field == null ) {
-                                                       array_shift($params);
-                                                       $field = RevisionDeleter::getRelationType($params[0]);
-                                               }
                                                if( $field == null ) {
-                                                       $this->output( "Invalid param type for $row->log_id\n" );
+                                                       $this->output( "Invalid param type for {$row->log_id}\n" );
                                                        continue; // skip this row
+                                               } else {
+                                                       // Clean up the row...
+                                                       $db->update( 'logging', 
+                                                               array('log_params' => implode(',',$params) ),
+                                                               array('log_id' => $row->log_id ) );
                                                }
-                                               $items = explode(',',$params[1]);
-                                               $log = new LogPage( $row->log_type );
-                                               $log->addRelations( $field, $items, $row->log_id );
                                        }
+                                       $items = explode(',',$params[1]);
+                                       $log = new LogPage( $row->log_type );
+                                       // Add item relations...
+                                       $log->addRelations( $field, $items, $row->log_id );
+                                       // Determine what table to query...
+                                       $prefix = substr( $field, 0, strpos($field,'_') ); // db prefix
+                                       if( !isset(self::$tableMap[$prefix]) )
+                                               continue; // bad row?
+                                       $table = self::$tableMap[$prefix];
+                                       $userField = $prefix.'_user';
+                                       $userTextField = $prefix.'_user_text';
+                                       // Add item author relations...
+                                       $userIds = $userIPs = array();
+                                       $sres = $db->select( $table,
+                                               array($userField,$userTextField),
+                                               array($field => $items)
+                                       );
+                                       foreach( $sres as $srow ) {
+                                               if( $srow->$userField > 0 )
+                                                       $userIds[] = intval($srow->$userField);
+                                               else if( $srow->$userTextField != '' )
+                                                       $userIPs[] = $srow->$userTextField;
+                                       }
+                                       // Add item author relations...
+                                       $log->addRelations( 'target_author_id', $userIds, $row->log_id );
+                                       $log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
                                // RevisionDelete logs - log events
-                               } else if( LogEventsList::typeAction( $row, array('delete','suppress'), 'event' ) ) {
+                               } else if( LogEventsList::typeAction( $row, $delTypes, '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 );
+                                       if( count($params) < 1 ) continue; // bad row
+                                       $items = explode( ',', $params[0] );
+                                       $log = new LogPage( $row->log_type );
+                                       // Add item relations...
+                                       $log->addRelations( 'log_id', $items, $row->log_id );
+                                       // Add item author relations...
+                                       $userIds = $userIPs = array();
+                                       $sres = $db->select( 'logging',
+                                               array('log_user','log_user_text'),
+                                               array('log_id' => $items)
+                                       );
+                                       foreach( $sres as $srow ) {
+                                               if( $srow->log_user > 0 )
+                                                       $userIds[] = intval($srow->log_user);
+                                               else if( IP::isIPAddress($srow->log_user_text) )
+                                                       $userIPs[] = $srow->log_user_text;
                                        }
+                                       $log->addRelations( 'target_author_id', $userIds, $row->log_id );
+                                       $log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
                                }
                        }
                        $blockStart += self::LOG_SEARCH_BATCH_SIZE;