Bold and apply a subtle background colour to the changed fields in Abuse Filter history -- will make things much easier to track.

This commit is contained in:
Andrew Garrett 2009-01-26 22:31:02 +00:00
parent 83cb0e5322
commit 83d4b5a91f
7 changed files with 126 additions and 81 deletions

View file

@ -11,6 +11,7 @@ class AbuseFilter {
public static $condCount = 0;
public static $filters = array();
public static $tagsToSet = array();
public static $history_mappings = array( 'af_pattern' => 'afh_pattern', 'af_user' => 'afh_user', 'af_user_text' => 'afh_user_text', 'af_timestamp' => 'afh_timestamp', 'af_comments' => 'afh_comments', 'af_public_comments' => 'afh_public_comments', 'af_deleted' => 'afh_deleted', 'af_id' => 'afh_filter' );
public static function generateUserVars( $user ) {
$vars = array();
@ -675,4 +676,69 @@ class AbuseFilter {
return $rules;
}
/** Each version is expected to be an array( $row, $actions )
Returns an array of fields that are different.*/
static function compareVersions( $version_1, $version_2 ) {
$compareFields = array( 'af_public_comments', 'af_pattern', 'af_comments', 'af_deleted', 'af_enabled', 'af_hidden' );
$differences = array();
list($row1, $actions1) = $version_1;
list($row2, $actions2) = $version_2;
foreach( $compareFields as $field ) {
if ($row1->$field != $row2->$field) {
$differences[] = $field;
}
}
global $wgAbuseFilterAvailableActions;
foreach( $wgAbuseFilterAvailableActions as $action ) {
if ( !isset($actions1[$action]) && !isset( $actions2[$action] ) ) {
// They're both unset
} elseif ( isset($actions1[$action]) && isset( $actions2[$action] ) ) {
// They're both set.
if ( array_diff( $actions1[$action]['parameters'], $actions2[$action]['parameters'] ) ) {
// Different parameters
$differences[] = 'actions';
}
} else {
// One's unset, one's set.
$differences[] = 'actions';
}
}
return array_unique( $differences );
}
static function translateFromHistory( $row ) {
## Translate into an abuse_filter row with some black magic. This is ever so slightly evil!
$af_row = new StdClass;
foreach (self::$history_mappings as $af_col => $afh_col ) {
$af_row->$af_col = $row->$afh_col;
}
## Process flags
$af_row->af_deleted = 0;
$af_row->af_hidden = 0;
$af_row->af_enabled = 0;
$flags = explode(',', $row->afh_flags );
foreach( $flags as $flag ) {
$col_name = "af_$flag";
$af_row->$col_name = 1;
}
## Process actions
$actions_raw = unserialize($row->afh_actions);
$actions_output = array();
foreach( $actions_raw as $action => $parameters ) {
$actions_output[$action] = array( 'action' => $action, 'parameters' => $parameters );
}
return array( $af_row, $actions_output );
}
}

View file

@ -237,8 +237,8 @@ A brief description of the abuse rule which your action matched is: $1",
'abusefilter-filter-log' => 'Recent filter changes',
'abusefilter-history' => 'History for filter $1',
'abusefilter-history-foruser' => 'Changes by $1',
'abusefilter-history-hidden' => 'hidden',
'abusefilter-history-enabled' => 'enabled',
'abusefilter-history-hidden' => 'Hidden',
'abusefilter-history-enabled' => 'Enabled',
'abusefilter-history-timestamp' => 'Time',
'abusefilter-history-user' => 'User',
'abusefilter-history-public' => 'Public filter description',

View file

@ -24,6 +24,9 @@ class SpecialAbuseFilter extends SpecialPage {
$wgOut->setRobotPolicy( "noindex,nofollow" );
$wgOut->setArticleRelated( false );
$wgOut->enableClientCache( false );
global $wgScriptPath;
$wgOut->addExtensionStyle( $wgScriptPath."/extensions/AbuseFilter/abusefilter.css" );
// Are we allowed?
if ( !$wgUser->isAllowed( 'abusefilter-view' ) ) {

View file

@ -5,8 +5,6 @@ if (!defined( 'MEDIAWIKI' ))
class AbuseFilterViewEdit extends AbuseFilterView {
static $history_mappings = array( 'af_pattern' => 'afh_pattern', 'af_user' => 'afh_user', 'af_user_text' => 'afh_user_text', 'af_timestamp' => 'afh_timestamp', 'af_comments' => 'afh_comments', 'af_public_comments' => 'afh_public_comments', 'af_deleted' => 'afh_deleted', 'af_id' => 'afh_filter' );
function __construct( $page, $params ) {
parent::__construct( $page, $params );
$this->mFilter = $page->mFilter;
@ -34,7 +32,10 @@ class AbuseFilterViewEdit extends AbuseFilterView {
list ($newRow, $actions) = $this->loadRequest($filter);
$differences = $this->compareVersions( array($newRow, $actions), array( $newRow->mOriginalRow, $newRow->mOriginalActions ) );
$differences = AbuseFilter::compareVersions( array($newRow, $actions), array( $newRow->mOriginalRow, $newRow->mOriginalActions ) );
unset( $newRow->mOriginalRow );
unset( $newRow->mOriginalActions );
if (!count($differences)) {
$wgOut->redirect( $this->getTitle()->getLocalURL() );
@ -90,7 +91,7 @@ class AbuseFilterViewEdit extends AbuseFilterView {
// Create a history row
$afh_row = array();
foreach( self::$history_mappings as $af_col => $afh_col ) {
foreach( AbuseFilter::$history_mappings as $af_col => $afh_col ) {
$afh_row[$afh_col] = $newRow[$af_col];
}
@ -101,6 +102,8 @@ class AbuseFilterViewEdit extends AbuseFilterView {
}
$afh_row['afh_actions'] = serialize($displayActions);
$afh_row['afh_changed_fields'] = implode( ',', $differences );
// Flags
$flags = array();
if ($newRow['af_hidden'])
@ -367,40 +370,6 @@ class AbuseFilterViewEdit extends AbuseFilterView {
return array( $row, $actions );
}
/** Each version is expected to be an array( $row, $actions )
Returns an array of fields that are different.*/
function compareVersions( $version_1, $version_2 ) {
$compareFields = array( 'af_public_comments', 'af_pattern', 'af_comments', 'af_deleted', 'af_enabled', 'af_hidden' );
$differences = array();
list($row1, $actions1) = $version_1;
list($row2, $actions2) = $version_2;
foreach( $compareFields as $field ) {
if ($row1->$field != $row2->$field) {
$differences[] = $field;
}
}
global $wgAbuseFilterAvailableActions;
foreach( $wgAbuseFilterAvailableActions as $action ) {
if ( !isset($actions1[$action]) && !isset( $actions2[$action] ) ) {
// They're both unset
} elseif ( isset($actions1[$action]) && isset( $actions2[$action] ) ) {
// They're both set.
if ( array_diff( $actions1[$action]['parameters'], $actions2[$action]['parameters'] ) ) {
// Different parameters
$differences[] = 'actions';
}
} else {
// One's unset, one's set.
$differences[] = 'actions';
}
}
return array_unique( $differences );
}
function loadRequest( $filter, $history_id = null ) {
static $row = null;
static $actions = null;
@ -471,34 +440,6 @@ class AbuseFilterViewEdit extends AbuseFilterView {
// Load the row.
$row = $dbr->selectRow( 'abuse_filter_history', '*', array( 'afh_id' => $id ), __METHOD__ );
## Translate into an abuse_filter row with some black magic. This is ever so slightly evil!
$af_row = new StdClass;
foreach (self::$history_mappings as $af_col => $afh_col ) {
$af_row->$af_col = $row->$afh_col;
}
## Process flags
$af_row->af_deleted = 0;
$af_row->af_hidden = 0;
$af_row->af_enabled = 0;
$flags = explode(',', $row->afh_flags );
foreach( $flags as $flag ) {
$col_name = "af_$flag";
$af_row->$col_name = 1;
}
## Process actions
$actions_raw = unserialize($row->afh_actions);
$actions_output = array();
foreach( $actions_raw as $action => $parameters ) {
$actions_output[$action] = array( 'action' => $action, 'parameters' => $parameters );
}
return array( $af_row, $actions_output );
return AbuseFilter::translateFromHistory( $row );
}
}

View file

@ -80,6 +80,7 @@ class AbuseFilterHistoryPager extends TablePager {
if (!$this->mFilter) {
// awful hack
$headers = array( 'afh_filter' => 'abusefilter-history-filterid' ) + $headers;
unset( $headers['afh_pattern'] );
}
$headers = array_map( 'wfMsg', $headers );
@ -99,25 +100,33 @@ class AbuseFilterHistoryPager extends TablePager {
$row = $this->mCurrentRow;
$formatted = '';
switch($name) {
case 'afh_timestamp':
$title = SpecialPage::getTitleFor( 'AbuseFilter', 'history/'.$this->mFilter.'/item/'.$row->afh_id );
return $sk->link( $title, $wgLang->timeanddate( $row->afh_timestamp ) );
$formatted = $sk->link( $title, $wgLang->timeanddate( $row->afh_timestamp ) );
break;
case 'afh_user_text':
return $sk->userLink( $row->afh_user, $row->afh_user_text ) . ' ' . $sk->userToolLinks( $row->afh_user, $row->afh_user_text );
$formatted = $sk->userLink( $row->afh_user, $row->afh_user_text ) . ' ' . $sk->userToolLinks( $row->afh_user, $row->afh_user_text );
break;
case 'afh_public_comments':
return $wgOut->parse( $value );
$formatted = $wgOut->parse( $value );
break;
case 'afh_flags':
$flags = array_filter( explode( ',', $value ) );
$flags_display = array();
foreach( $flags as $flag ) {
$flags_display[] = wfMsg( "abusefilter-history-$flag" );
}
return implode( ', ', $flags_display );
$formatted = implode( ', ', $flags_display );
break;
case 'afh_pattern':
return htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
$formatted = htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
break;
case 'afh_comments':
return htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
$formatted = htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
break;
case 'afh_actions':
$actions = unserialize( $value );
@ -128,21 +137,42 @@ class AbuseFilterHistoryPager extends TablePager {
}
$display_actions = Xml::tags( 'ul', null, $display_actions );
return $display_actions;
$formatted = $display_actions;
break;
case 'afh_filter':
$title = $this->getTitle( $value );
return $sk->link( $title, $value );
$title = $this->mPage->getTitle( strval($value) );
$formatted = $sk->link( $title, $value );
break;
default:
$formatted = "Unable to format $name";
break;
}
return "Unable to format name $name\n";
$mappings = array_flip(AbuseFilter::$history_mappings) + array( 'afh_actions' => 'actions' );
$changed = explode( ',', $row->afh_changed_fields );
$fieldChanged = false;
if ($name == 'afh_flags') {
// This is a bit freaky, but it works. Basically, returns true if any of those filters are in the $changed array.
if ( count( array_diff( array( 'af_enabled', 'af_hidden', 'af_deleted' ), $changed ) ) < 3 ) {
$fieldChanged = true;
}
} elseif ( in_array( $mappings[$name], $changed ) ) {
$fieldChanged = true;
}
if ($fieldChanged)
$formatted = Xml::tags( 'strong', array( 'class' => 'mw-abusefilter-history-changed' ), $formatted );
return $formatted;
}
function getQueryInfo() {
$info = array(
'tables' => 'abuse_filter_history',
'fields' => $this->mFilter ?
array( 'afh_timestamp', 'afh_user_text', 'afh_public_comments', 'afh_flags', 'afh_pattern', 'afh_comments', 'afh_actions', 'afh_id', 'afh_user' ) :
array( 'afh_filter', 'afh_timestamp', 'afh_user_text', 'afh_public_comments', 'afh_flags', 'afh_comments', 'afh_actions', 'afh_id', 'afh_user' ),
array( 'afh_timestamp', 'afh_user_text', 'afh_public_comments', 'afh_flags', 'afh_pattern', 'afh_comments', 'afh_actions', 'afh_id', 'afh_user', 'afh_changed_fields' ) :
array( 'afh_filter', 'afh_timestamp', 'afh_user_text', 'afh_public_comments', 'afh_flags', 'afh_comments', 'afh_actions', 'afh_id', 'afh_user', 'afh_changed_fields'),
'conds' => $this->mFilter ? array( 'afh_filter' => $this->mFilter ) : array(),
);

View file

@ -18,4 +18,8 @@ table.mw-abuselog-details th {
table.mw-abuselog-details caption {
font-weight: bold;
}
.mw-abusefilter-history-changed {
background: #ffe0e0;
}

View file

@ -60,6 +60,7 @@ CREATE TABLE /*$wgDBprefix*/abuse_filter_history (
afh_public_comments TINYBLOB,
afh_actions BLOB,
afh_deleted tinyint(1) NOT NULL DEFAULT 0,
afh_changed_fields varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (afh_id),
KEY (afh_filter),