2008-06-27 06:18:51 +00:00
< ? php
if ( ! defined ( 'MEDIAWIKI' ) )
die ();
class SpecialAbuseFilter extends SpecialPage {
var $mSkin ;
2008-10-21 15:14:30 +00:00
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' );
2008-06-27 06:18:51 +00:00
function __construct () {
wfLoadExtensionMessages ( 'AbuseFilter' );
parent :: __construct ( 'AbuseFilter' , 'abusefilter-view' );
}
function execute ( $subpage ) {
global $wgUser , $wgOut , $wgRequest ;
$this -> setHeaders ();
$this -> loadParameters ( $subpage );
$wgOut -> setPageTitle ( wfMsg ( 'abusefilter-management' ) );
2008-07-23 19:33:28 +00:00
$wgOut -> setRobotPolicy ( " noindex,nofollow " );
2008-06-27 06:18:51 +00:00
$wgOut -> setArticleRelated ( false );
$wgOut -> enableClientCache ( false );
// Are we allowed?
2008-09-05 14:27:18 +00:00
if ( ! $wgUser -> isAllowed ( 'abusefilter-view' ) ) {
2008-06-27 06:18:51 +00:00
// Go away.
2008-09-05 14:27:18 +00:00
$this -> displayRestrictionError ();
2008-06-27 06:18:51 +00:00
return ;
}
$this -> mSkin = $wgUser -> getSkin ();
2008-10-21 15:14:30 +00:00
$params = array_filter ( explode ( '/' , $subpage ) );
2008-07-17 13:40:45 +00:00
if ( $subpage == 'tools' ) {
// Some useful tools
$this -> doTools ();
return ;
}
2008-10-21 15:14:30 +00:00
if ( ! empty ( $params [ 0 ]) && $params [ 0 ] == 'history' ) {
if ( count ( $params ) == 1 ) {
// ... useless?
} elseif ( count ( $params ) == 2 ) {
## Second param is a filter ID
$this -> showHistory ( $params [ 1 ]);
return ;
} elseif ( count ( $params ) == 4 && $params [ 2 ] == 'item' ) {
$wgOut -> addWikiMsg ( 'abusefilter-edit-oldwarning' , $params [ 3 ], $params [ 1 ] );
$out = $this -> buildFilterEditor ( null , $params [ 1 ], $params [ 3 ] );
$wgOut -> addHTML ( $out );
$wgOut -> addWikiMsg ( 'abusefilter-edit-oldwarning' , $params [ 3 ], $params [ 1 ] );
return ;
}
2008-08-03 14:04:26 +00:00
}
2008-06-27 09:26:54 +00:00
if ( $output = $this -> doEdit ()) {
2008-06-27 06:18:51 +00:00
$wgOut -> addHtml ( $output );
2008-08-03 14:04:26 +00:00
return ;
}
// Show list of filters.
$this -> showStatus ();
2008-09-05 14:27:18 +00:00
// Quick links
$wgOut -> addWikiMsg ( 'abusefilter-links' );
2008-10-21 13:43:05 +00:00
$lists = array ( 'tools' );
2008-09-05 14:27:18 +00:00
$links = '' ;
$sk = $wgUser -> getSkin ();
foreach ( $lists as $list ) {
$title = $this -> getTitle ( $list );
$link = $sk -> link ( $title , wfMsg ( " abusefilter-show- $list " ) );
$links .= Xml :: tags ( 'li' , null , $link ) . " \n " ;
}
$links .= Xml :: tags ( 'li' , null , $sk -> link ( SpecialPage :: getTitleFor ( 'AbuseLog' ), wfMsg ( 'abusefilter-loglink' ) ) );
$links = Xml :: tags ( 'ul' , null , $links );
$wgOut -> addHTML ( $links );
2008-10-21 13:43:05 +00:00
// Options.
$conds = array ();
$deleted = $wgRequest -> getVal ( 'deletedfilters' );
$hidedisabled = $wgRequest -> getBool ( 'hidedisabled' );
if ( $deleted == 'show' ) {
## Nothing
} elseif ( $deleted == 'only' ) {
$conds [ 'af_deleted' ] = 1 ;
} else { ## hide, or anything else.
$conds [ 'af_deleted' ] = 0 ;
$deleted = 'hide' ;
2008-09-05 14:27:18 +00:00
}
2008-10-21 13:43:05 +00:00
if ( $hidedisabled ) {
$conds [ 'af_deleted' ] = 0 ;
$conds [ 'af_enabled' ] = 1 ;
2008-09-05 14:27:18 +00:00
}
2008-10-21 13:43:05 +00:00
$options = '' ;
$fields = array ();
$fields [ 'abusefilter-list-options-deleted' ] = Xml :: radioLabel ( wfMsg ( 'abusefilter-list-options-deleted-show' ), 'deletedfilters' , 'show' , 'mw-abusefilter-deletedfilters-show' , $deleted == 'show' );
$fields [ 'abusefilter-list-options-deleted' ] .= Xml :: radioLabel ( wfMsg ( 'abusefilter-list-options-deleted-hide' ), 'deletedfilters' , 'hide' , 'mw-abusefilter-deletedfilters-hide' , $deleted == 'hide' );
$fields [ 'abusefilter-list-options-deleted' ] .= Xml :: radioLabel ( wfMsg ( 'abusefilter-list-options-deleted-only' ), 'deletedfilters' , 'only' , 'mw-abusefilter-deletedfilters-only' , $deleted == 'only' );
$fields [ 'abusefilter-list-options-disabled' ] = Xml :: checkLabel ( wfMsg ( 'abusefilter-list-options-hidedisabled' ), 'hidedisabled' , 'mw-abusefilter-disabledfilters-hide' , $hidedisabled );
$options = Xml :: buildForm ( $fields , 'abusefilter-list-options-submit' );
$options .= Xml :: hidden ( 'title' , $this -> getTitle () -> getPrefixedText () );
$options = Xml :: tags ( 'form' , array ( 'method' => 'get' , 'action' => $this -> getTitle () -> getFullURL () ), $options );
$options = Xml :: fieldset ( wfMsg ( 'abusefilter-list-options' ), $options );
$wgOut -> addHTML ( $options );
$this -> showList ( $conds );
2008-08-03 14:04:26 +00:00
}
2008-09-05 14:27:18 +00:00
function showDeleted () {
$this -> showList ( array ( 'af_deleted' => 1 ) );
}
function showActive () {
$this -> showList ( array ( 'af_deleted' => 0 , 'af_enabled' => 1 ) );
}
2008-10-21 15:14:30 +00:00
function showHistory ( $filter ) {
2008-08-03 14:04:26 +00:00
global $wgRequest , $wgOut ;
global $wgUser ;
$sk = $wgUser -> getSkin ();
$wgOut -> setPageTitle ( wfMsg ( 'abusefilter-history' , $filter ) );
$backToFilter_label = wfMsgExt ( 'abusefilter-history-backedit' , array ( 'parseinline' ) );
$backToList_label = wfMsgExt ( 'abusefilter-history-backlist' , array ( 'parseinline' ) );
$backlinks = $sk -> makeKnownLinkObj ( $this -> getTitle ( $filter ), $backToFilter_label ) . ' • ' .
$sk -> makeKnownLinkObj ( $this -> getTitle ( ), $backToList_label );
$wgOut -> addHTML ( Xml :: tags ( 'p' , null , $backlinks ) );
// Produce table
$table = '' ;
$headers = array ( 'abusefilter-history-timestamp' , 'abusefilter-history-user' , 'abusefilter-history-public' , 'abusefilter-history-flags' , 'abusefilter-history-filter' , 'abusefilter-history-comments' , 'abusefilter-history-actions' );
$header_row = '' ;
foreach ( $headers as $header ) {
$label = wfMsgExt ( $header , array ( 'parseinline' ) );
$header_row .= Xml :: tags ( 'th' , null , $label );
2008-06-27 06:18:51 +00:00
}
2008-08-03 14:04:26 +00:00
$table .= Xml :: tags ( 'tr' , null , $header_row );
$pager = new AbuseFilterHistoryPager ( $filter );
$table .= $pager -> getBody ();
$table = " <table class= \" wikitable \" ><tbody> $table </table></tbody> " ;
$wgOut -> addHTML ( $pager -> getNavigationBar () . $table . $pager -> getNavigationBar () );
return true ;
2008-06-27 06:18:51 +00:00
}
2008-07-17 13:40:45 +00:00
function doTools () {
global $wgRequest , $wgOut ;
2008-08-03 14:04:26 +00:00
2008-08-04 14:27:48 +00:00
// Header
$wgOut -> setSubTitle ( wfMsg ( 'abusefilter-tools-subtitle' ) );
$wgOut -> addWikiMsg ( 'abusefilter-tools-text' );
// Expression evaluator
$eval = '' ;
$eval .= Xml :: textarea ( 'wpTestExpr' , " " );
$eval .= Xml :: tags ( 'p' , null , Xml :: element ( 'input' , array ( 'type' => 'button' , 'id' => 'mw-abusefilter-submitexpr' , 'onclick' => 'doExprSubmit();' , 'value' => wfMsg ( 'abusefilter-tools-submitexpr' ) ) ) );
$eval .= Xml :: element ( 'p' , array ( 'id' => 'mw-abusefilter-expr-result' ), ' ' );
$eval = Xml :: fieldset ( wfMsg ( 'abusefilter-tools-expr' ), $eval );
$wgOut -> addHtml ( $eval );
// Associated script
$exprScript = " function doExprSubmit()
{
var expr = document . getElementById ( 'wpTestExpr' ) . value ;
injectSpinner ( document . getElementById ( 'mw-abusefilter-submitexpr' ), 'abusefilter-expr' );
sajax_do_call ( 'AbuseFilter::ajaxEvaluateExpression' , [ expr ], processExprResult );
2008-07-17 13:40:45 +00:00
}
2008-08-04 14:27:48 +00:00
function processExprResult ( request ) {
var response = request . responseText ;
2008-07-17 13:40:45 +00:00
2008-08-04 14:27:48 +00:00
removeSpinner ( 'abusefilter-expr' );
var el = document . getElementById ( 'mw-abusefilter-expr-result' );
changeText ( el , response );
2008-09-29 13:30:11 +00:00
}
function doReautoSubmit ()
{
var name = document . getElementById ( 'reautoconfirm-user' ) . value ;
injectSpinner ( document . getElementById ( 'mw-abusefilter-reautoconfirmsubmit' ), 'abusefilter-reautoconfirm' );
sajax_do_call ( 'AbuseFilter::ajaxReAutoconfirm' , [ name ], processReautoconfirm );
}
function processReautoconfirm ( request ) {
var response = request . responseText ;
if ( strlen ( response )) {
jsMsg ( response );
}
removeSpinner ( 'abusefilter-reautoconfirm' );
}
" ;
2008-07-17 13:40:45 +00:00
2008-08-04 14:27:48 +00:00
$wgOut -> addInlineScript ( $exprScript );
2008-09-29 13:30:11 +00:00
2008-10-21 13:43:05 +00:00
global $wgUser ;
if ( $wgUser -> isAllowed ( 'abusefilter-modify' )) {
// Hacky little box to re-enable autoconfirmed if it got disabled
$rac = '' ;
$rac .= Xml :: inputLabel ( wfMsg ( 'abusefilter-tools-reautoconfirm-user' ), 'wpReAutoconfirmUser' , 'reautoconfirm-user' , 45 );
$rac .= Xml :: element ( 'input' , array ( 'type' => 'button' , 'id' => 'mw-abusefilter-reautoconfirmsubmit' , 'onclick' => 'doReautoSubmit();' , 'value' => wfMsg ( 'abusefilter-tools-reautoconfirm-submit' ) ) );
$rac = Xml :: fieldset ( wfMsg ( 'abusefilter-tools-reautoconfirm' ), $rac );
$wgOut -> addHtml ( $rac );
}
2008-07-17 13:40:45 +00:00
}
2008-07-17 02:43:45 +00:00
function showStatus () {
2008-07-29 11:16:35 +00:00
global $wgMemc , $wgAbuseFilterConditionLimit , $wgOut , $wgLang ;
2008-07-17 02:43:45 +00:00
$overflow_count = ( int ) $wgMemc -> get ( AbuseFilter :: filterLimitReachedKey () );
$match_count = ( int ) $wgMemc -> get ( AbuseFilter :: filterMatchesKey () );
$total_count = ( int ) $wgMemc -> get ( AbuseFilter :: filterUsedKey () );
if ( $total_count > 0 ) {
$overflow_percent = sprintf ( " %.2f " , 100 * $overflow_count / $total_count );
$match_percent = sprintf ( " %.2f " , 100 * $match_count / $total_count );
2008-07-29 11:16:35 +00:00
$status = wfMsgExt ( 'abusefilter-status' , array ( 'parsemag' , 'escape' ),
$wgLang -> formatNum ( $total_count ),
$wgLang -> formatNum ( $overflow_count ),
$wgLang -> formatNum ( $overflow_percent ),
$wgLang -> formatNum ( $wgAbuseFilterConditionLimit ),
$wgLang -> formatNum ( $match_count ),
$wgLang -> formatNum ( $match_percent )
);
2008-08-04 14:27:48 +00:00
$status = Xml :: tags ( 'div' , array ( 'class' => 'mw-abusefilter-status' ), $status );
$wgOut -> addHTML ( $status );
2008-07-17 02:43:45 +00:00
}
}
2008-10-21 15:14:30 +00:00
function doEdit ( $history_id = null ) {
2008-06-27 06:18:51 +00:00
global $wgRequest , $wgUser ;
$filter = $this -> mFilter ;
$editToken = $wgRequest -> getVal ( 'wpEditToken' );
2008-06-27 07:21:26 +00:00
$didEdit = $this -> canEdit () && $wgUser -> matchEditToken ( $editToken , array ( 'abusefilter' , $filter ) );
2008-06-27 06:18:51 +00:00
if ( $didEdit ) {
2008-08-03 14:04:26 +00:00
// Check syntax
$syntaxerr = AbuseFilter :: checkSyntax ( $wgRequest -> getVal ( 'wpFilterRules' ) );
if ( $syntaxerr !== true ) {
return $this -> buildFilterEditor ( wfMsgExt ( 'abusefilter-edit-badsyntax' , array ( 'parseinline' ), array ( $syntaxerr ) ) );
}
2008-06-27 06:18:51 +00:00
$dbw = wfGetDB ( DB_MASTER );
2008-10-21 15:14:30 +00:00
list ( $newRow , $actions ) = $this -> loadRequest ( $filter );
2008-06-27 06:18:51 +00:00
2008-08-03 14:04:26 +00:00
$newRow = get_object_vars ( $newRow ); // Convert from object to array
2008-06-27 06:18:51 +00:00
2008-08-03 14:04:26 +00:00
// Set last modifier.
2008-06-27 06:18:51 +00:00
$newRow [ 'af_timestamp' ] = $dbw -> timestamp ( wfTimestampNow () );
$newRow [ 'af_user' ] = $wgUser -> getId ();
$newRow [ 'af_user_text' ] = $wgUser -> getName ();
2008-08-03 14:04:26 +00:00
$dbw -> begin ();
2008-07-17 02:43:45 +00:00
2008-08-03 14:04:26 +00:00
if ( $filter == 'new' ) {
2008-10-21 12:58:01 +00:00
$new_id = $dbw -> nextSequenceValue ( 'abuse_filter_af_id_seq' );
$is_new = true ;
2008-08-03 14:04:26 +00:00
} else {
$new_id = $this -> mFilter ;
2008-10-21 12:58:01 +00:00
$is_new = false ;
}
$newRow [ 'af_id' ] = $new_id ;
$dbw -> replace ( 'abuse_filter' , array ( 'af_id' ), $newRow , __METHOD__ );
if ( $is_new ) {
$new_id = $dbw -> insertId ();
2008-06-27 07:55:13 +00:00
}
2008-06-27 06:18:51 +00:00
// Actions
global $wgAbuseFilterAvailableActions ;
$deadActions = array ();
$actionsRows = array ();
foreach ( $wgAbuseFilterAvailableActions as $action ) {
// Check if it's set
2008-09-05 14:27:18 +00:00
$enabled = isset ( $actions [ $action ]) && ( bool ) $actions [ $action ];
2008-06-27 06:18:51 +00:00
if ( $enabled ) {
2008-08-03 14:04:26 +00:00
$parameters = $actions [ $action ][ 'parameters' ];
2008-06-27 06:18:51 +00:00
2008-08-03 14:04:26 +00:00
$thisRow = array ( 'afa_filter' => $new_id , 'afa_consequence' => $action , 'afa_parameters' => implode ( " \n " , $parameters ) );
2008-06-27 06:18:51 +00:00
$actionsRows [] = $thisRow ;
2008-08-03 14:04:26 +00:00
} else {
$deadActions [] = $action ;
2008-06-27 06:18:51 +00:00
}
}
2008-10-21 15:14:30 +00:00
// Create a history row
2008-08-03 14:04:26 +00:00
$afh_row = array ();
2008-10-21 15:14:30 +00:00
foreach ( self :: $history_mappings as $af_col => $afh_col ) {
2008-08-03 14:04:26 +00:00
$afh_row [ $afh_col ] = $newRow [ $af_col ];
}
// Actions
$displayActions = array ();
foreach ( $actions as $action ) {
$displayActions [ $action [ 'action' ]] = $action [ 'parameters' ];
}
$afh_row [ 'afh_actions' ] = serialize ( $displayActions );
// Flags
$flags = array ();
if ( $newRow [ 'af_hidden' ])
2008-10-21 15:14:30 +00:00
$flags [] = 'hidden' ;
2008-08-03 14:04:26 +00:00
if ( $newRow [ 'af_enabled' ])
2008-10-21 15:14:30 +00:00
$flags [] = 'enabled' ;
2008-09-05 14:27:18 +00:00
if ( $newRow [ 'af_deleted' ])
2008-10-21 15:14:30 +00:00
$flags [] = 'deleted' ;
2008-08-03 14:04:26 +00:00
$afh_row [ 'afh_flags' ] = implode ( " , " , $flags );
$afh_row [ 'afh_filter' ] = $new_id ;
// Do the update
$dbw -> insert ( 'abuse_filter_history' , $afh_row , __METHOD__ );
2008-06-27 06:18:51 +00:00
$dbw -> delete ( 'abuse_filter_action' , array ( 'afa_filter' => $filter , 'afa_consequence' => $deadActions ), __METHOD__ );
$dbw -> replace ( 'abuse_filter_action' , array ( array ( 'afa_filter' , 'afa_consequence' ) ), $actionsRows , __METHOD__ );
2008-10-21 12:58:01 +00:00
2008-06-27 06:18:51 +00:00
$dbw -> commit ();
global $wgOut ;
$wgOut -> setSubtitle ( wfMsg ( 'abusefilter-edit-done-subtitle' ) );
return wfMsgExt ( 'abusefilter-edit-done' , array ( 'parse' ) );
} else {
2008-10-21 15:14:30 +00:00
return $this -> buildFilterEditor ( null , $filter , $history_id );
2008-06-27 06:18:51 +00:00
}
}
2008-10-21 15:14:30 +00:00
function buildFilterEditor ( $error = '' , $filter , $history_id = null ) {
if ( $filter === null ) {
2008-06-27 06:18:51 +00:00
return false ;
}
// Build the edit form
global $wgOut , $wgLang , $wgUser ;
$sk = $this -> mSkin ;
2008-10-21 15:14:30 +00:00
$wgOut -> setSubtitle ( wfMsg ( 'abusefilter-edit-subtitle' , $filter , $history_id ) );
2008-06-27 06:18:51 +00:00
2008-10-21 15:14:30 +00:00
list ( $row , $actions ) = $this -> loadRequest ( $filter , $history_id );
2008-06-27 09:26:54 +00:00
2008-08-04 14:27:48 +00:00
if ( ! $row ) {
return false ;
}
2008-06-27 09:26:54 +00:00
2008-08-31 07:08:11 +00:00
if ( isset ( $row -> af_hidden ) && $row -> af_hidden && ! $this -> canEdit ()) {
2008-08-04 14:27:48 +00:00
return wfMsg ( 'abusefilter-edit-denied' );
2008-06-27 06:18:51 +00:00
}
$output = '' ;
2008-08-03 14:04:26 +00:00
if ( $error ) {
$wgOut -> addHTML ( " <span class= \" error \" > $error </span> " );
}
2008-06-27 06:18:51 +00:00
$fields = array ();
2008-10-21 15:14:30 +00:00
$fields [ 'abusefilter-edit-id' ] = $this -> mFilter == 'new' ? wfMsg ( 'abusefilter-edit-new' ) : $filter ;
2008-10-21 12:58:01 +00:00
$fields [ 'abusefilter-edit-description' ] = Xml :: input ( 'wpFilterDescription' , 45 , isset ( $row -> af_public_comments ) ? $row -> af_public_comments : '' );
2008-06-27 06:18:51 +00:00
// Hit count display
2008-10-21 15:14:30 +00:00
if ( ! empty ( $row -> af_hit_count ) ){
2008-06-27 09:26:54 +00:00
$count = ( int ) $row -> af_hit_count ;
2008-07-29 11:16:35 +00:00
$count_display = wfMsgExt ( 'abusefilter-hitcount' , array ( 'parseinline' ),
$wgLang -> formatNum ( $count )
);
2008-06-27 09:26:54 +00:00
$hitCount = $sk -> makeKnownLinkObj ( SpecialPage :: getTitleFor ( 'AbuseLog' ), $count_display , 'wpSearchFilter=' . $row -> af_id );
2008-06-27 06:18:51 +00:00
2008-06-27 09:26:54 +00:00
$fields [ 'abusefilter-edit-hitcount' ] = $hitCount ;
}
2008-07-17 02:43:45 +00:00
2008-10-21 15:14:30 +00:00
if ( $filter !== 'new' ) {
2008-07-17 02:43:45 +00:00
// Statistics
2008-07-29 11:16:35 +00:00
global $wgMemc , $wgLang ;
2008-10-21 15:14:30 +00:00
$matches_count = $wgMemc -> get ( AbuseFilter :: filterMatchesKey ( $filter ) );
2008-07-17 02:43:45 +00:00
$total = $wgMemc -> get ( AbuseFilter :: filterUsedKey () );
if ( $total > 0 ) {
$matches_percent = sprintf ( '%.2f' , 100 * $matches_count / $total );
2008-07-29 11:16:35 +00:00
$fields [ 'abusefilter-edit-status-label' ] =
wfMsgExt ( 'abusefilter-edit-status' , array ( 'parsemag' , 'escape' ),
$wgLang -> formatNum ( $total ),
$wgLang -> formatNum ( $matches_count ),
$wgLang -> formatNum ( $matches_percent )
);
2008-07-17 02:43:45 +00:00
}
}
2008-06-27 06:18:51 +00:00
2008-08-08 09:37:05 +00:00
$fields [ 'abusefilter-edit-rules' ] = $this -> buildEditBox ( $row );
2008-06-27 10:44:39 +00:00
$fields [ 'abusefilter-edit-notes' ] = Xml :: textarea ( 'wpFilterNotes' , ( isset ( $row -> af_comments ) ? $row -> af_comments . " \n " : " \n " ) );
2008-06-27 06:18:51 +00:00
// Build checkboxen
2008-09-05 14:27:18 +00:00
$checkboxes = array ( 'hidden' , 'enabled' , 'deleted' );
2008-06-27 06:18:51 +00:00
$flags = '' ;
2008-07-17 02:43:45 +00:00
if ( isset ( $row -> af_throttled ) && $row -> af_throttled ) {
global $wgAbuseFilterEmergencyDisableThreshold ;
$threshold_percent = sprintf ( '%.2f' , $wgAbuseFilterEmergencyDisableThreshold * 100 );
2008-07-29 11:16:35 +00:00
$flags .= $wgOut -> parse ( wfMsg ( 'abusefilter-edit-throttled' , $wgLang -> formatNum ( $threshold_percent ) ) );
2008-07-17 02:43:45 +00:00
}
2008-06-27 06:18:51 +00:00
foreach ( $checkboxes as $checkboxId ) {
$message = " abusefilter-edit- $checkboxId " ;
$dbField = " af_ $checkboxId " ;
$postVar = " wpFilter " . ucfirst ( $checkboxId );
2008-06-27 09:26:54 +00:00
$checkbox = Xml :: checkLabel ( wfMsg ( $message ), $postVar , $postVar , isset ( $row -> $dbField ) ? $row -> $dbField : false );
2008-06-27 06:18:51 +00:00
$checkbox = Xml :: tags ( 'p' , null , $checkbox );
$flags .= $checkbox ;
}
$fields [ 'abusefilter-edit-flags' ] = $flags ;
2008-10-21 15:14:30 +00:00
if ( $filter != 'new' ) {
2008-06-27 07:21:26 +00:00
// Last modification details
2008-10-21 14:11:03 +00:00
$user = $sk -> userLink ( $row -> af_user , $row -> af_user_text ) . $sk -> userToolLinks ( $row -> af_user , $row -> af_user_text );
$fields [ 'abusefilter-edit-lastmod' ] = wfMsgExt ( 'abusefilter-edit-lastmod-text' , array ( 'parseinline' , 'replaceafter' ), array ( $wgLang -> timeanddate ( $row -> af_timestamp ), $user ) );
2008-08-03 14:04:26 +00:00
$history_display = wfMsgExt ( 'abusefilter-edit-viewhistory' , array ( 'parseinline' ) );
2008-10-21 15:14:30 +00:00
$fields [ 'abusefilter-edit-history' ] = $sk -> makeKnownLinkObj ( $this -> getTitle ( 'history/' . $filter ), $history_display );
2008-06-27 07:21:26 +00:00
}
2008-06-27 06:18:51 +00:00
$form = Xml :: buildForm ( $fields );
$form = Xml :: fieldset ( wfMsg ( 'abusefilter-edit-main' ), $form );
$form .= Xml :: fieldset ( wfMsg ( 'abusefilter-edit-consequences' ), $this -> buildConsequenceEditor ( $row , $actions ) );
if ( $this -> canEdit ()) {
$form .= Xml :: submitButton ( wfMsg ( 'abusefilter-edit-save' ) );
2008-10-21 15:14:30 +00:00
$form .= Xml :: hidden ( 'wpEditToken' , $wgUser -> editToken ( array ( 'abusefilter' , $filter )) );
2008-06-27 06:18:51 +00:00
}
2008-10-21 15:14:30 +00:00
$form = Xml :: tags ( 'form' , array ( 'action' => $this -> getTitle ( $filter ) -> getFullURL (), 'method' => 'POST' ), $form );
2008-06-27 06:18:51 +00:00
$output .= $form ;
return $output ;
}
2008-08-08 09:37:05 +00:00
function buildEditBox ( $row ) {
global $wgOut ;
$rules = Xml :: textarea ( 'wpFilterRules' , ( isset ( $row -> af_pattern ) ? $row -> af_pattern . " \n " : " \n " ) );
$dropDown = array (
'op-arithmetic' => array ( '+' => 'addition' , '-' => 'subtraction' , '*' => 'multiplication' , '/' => 'divide' , '%' => 'modulo' , '**' => 'pow' ),
'op-comparison' => array ( '==' => 'equal' , '!=' => 'notequal' , '<' => 'lt' , '>' => 'gt' , '<=' => 'lte' , '>=' => 'gte' ),
'op-bool' => array ( '!' => 'not' , '&' => 'and' , '|' => 'or' , '^' => 'xor' ),
2008-09-18 13:01:50 +00:00
'misc' => array ( 'val1 ? iftrue : iffalse' => 'ternary' , 'in' => 'in' , 'like' => 'like' , '""' => 'stringlit' , ),
2008-08-08 09:37:05 +00:00
'funcs' => array ( 'length(string)' => 'length' , 'lcase(string)' => 'lcase' , 'ccnorm(string)' => 'ccnorm' , 'rmdoubles(string)' => 'rmdoubles' , 'specialratio(string)' => 'specialratio' , 'norm(string)' => 'norm' , 'count(needle,haystack)' => 'count' ),
'vars' => array ( 'ACCOUNTNAME' => 'accountname' , 'ACTION' => 'action' , 'ADDED_LINES' => 'addedlines' , 'EDIT_DELTA' => 'delta' , 'EDIT_DIFF' => 'diff' , 'NEW_SIZE' => 'newsize' , 'OLD_SIZE' => 'oldsize' , 'REMOVED_LINES' => 'removedlines' , 'SUMMARY' => 'summary' , 'ARTICLE_ARTICLEID' => 'article-id' , 'ARTICLE_NAMESPACE' => 'article-ns' , 'ARTICLE_TEXT' => 'article-text' , 'ARTICLE_PREFIXEDTEXT' => 'article-prefixedtext' , 'MOVED_FROM_ARTICLEID' => 'movedfrom-id' , 'MOVED_FROM_NAMESPACE' => 'movedfrom-ns' , 'MOVED_FROM_TEXT' => 'movedfrom-text' , 'MOVED_FROM_PREFIXEDTEXT' => 'movedfrom-prefixedtext' , 'MOVED_TO_ARTICLEID' => 'movedto-id' , 'MOVED_TO_NAMESPACE' => 'movedto-ns' , 'MOVED_TO_TEXT' => 'movedto-text' , 'MOVED_TO_PREFIXEDTEXT' => 'movedto-prefixedtext' , 'USER_EDITCOUNT' => 'user-editcount' , 'USER_AGE' => 'user-age' , 'USER_NAME' => 'user-name' , 'USER_GROUPS' => 'user-groups' , 'USER_EMAILCONFIRM' => 'user-emailconfirm' ),
);
// Generate builder drop-down
$builder = '' ;
$builder .= Xml :: option ( wfMsg ( " abusefilter-edit-builder-select " ) );
foreach ( $dropDown as $group => $values ) {
$builder .= Xml :: openElement ( 'optgroup' , array ( 'label' => wfMsg ( " abusefilter-edit-builder-group- $group " ) ) ) . " \n " ;
foreach ( $values as $content => $name ) {
$builder .= Xml :: option ( wfMsg ( " abusefilter-edit-builder- $group - $name " ), $content ) . " \n " ;
}
$builder .= Xml :: closeElement ( 'optgroup' ) . " \n " ;
}
$rules .= Xml :: tags ( 'select' , array ( 'id' => 'wpFilterBuilder' , 'onchange' => 'addText();' ), $builder );
// Add syntax checking
$rules .= Xml :: element ( 'input' , array ( 'type' => 'button' , 'onclick' => 'doSyntaxCheck()' , 'value' => wfMsg ( 'abusefilter-edit-check' ), 'id' => 'mw-abusefilter-syntaxcheck' ) );
// Add script
$scScript = file_get_contents ( dirname ( __FILE__ ) . " /edit.js " );
$wgOut -> addInlineScript ( $scScript );
return $rules ;
}
2008-06-27 06:18:51 +00:00
function buildConsequenceEditor ( $row , $actions ) {
global $wgAbuseFilterAvailableActions ;
$setActions = array ();
foreach ( $wgAbuseFilterAvailableActions as $action ) {
2008-06-27 09:26:54 +00:00
$setActions [ $action ] = array_key_exists ( $action , $actions );
2008-06-27 06:18:51 +00:00
}
$output = '' ;
// Special case: flagging - always on.
$checkbox = Xml :: checkLabel ( wfMsg ( 'abusefilter-edit-action-flag' ), 'wpFilterActionFlag' , 'wpFilterActionFlag' , true , array ( 'disabled' => '1' ) );
$output .= Xml :: tags ( 'p' , null , $checkbox );
// Special case: throttling
$throttleSettings = Xml :: checkLabel ( wfMsg ( 'abusefilter-edit-action-throttle' ), 'wpFilterActionThrottle' , 'wpFilterActionThrottle' , $setActions [ 'throttle' ] );
$throttleFields = array ();
if ( $setActions [ 'throttle' ]) {
2008-09-18 13:42:36 +00:00
array_shift ( $actions [ 'throttle' ][ 'parameters' ] );
2008-06-27 06:18:51 +00:00
$throttleRate = explode ( ',' , $actions [ 'throttle' ][ 'parameters' ][ 0 ]);
$throttleCount = $throttleRate [ 0 ];
$throttlePeriod = $throttleRate [ 1 ];
$throttleGroups = implode ( " \n " , array_slice ( $actions [ 'throttle' ][ 'parameters' ], 1 ) );
} else {
$throttleCount = 3 ;
$throttlePeriod = 60 ;
$throttleGroups = " user \n " ;
}
$throttleFields [ 'abusefilter-edit-throttle-count' ] = Xml :: input ( 'wpFilterThrottleCount' , 20 , $throttleCount );
$throttleFields [ 'abusefilter-edit-throttle-period' ] = wfMsgExt ( 'abusefilter-edit-throttle-seconds' , array ( 'parseinline' , 'replaceafter' ), array ( Xml :: input ( 'wpFilterThrottlePeriod' , 20 , $throttlePeriod ) ) );
$throttleFields [ 'abusefilter-edit-throttle-groups' ] = Xml :: textarea ( 'wpFilterThrottleGroups' , $throttleGroups . " \n " );
$throttleSettings .= Xml :: buildForm ( $throttleFields );
$output .= Xml :: tags ( 'p' , null , $throttleSettings );
2008-10-21 14:11:03 +00:00
// Special case: Warning
$checkbox = Xml :: checkLabel ( wfMsg ( 'abusefilter-edit-action-warn' ), 'wpFilterActionWarn' , 'wpFilterActionWarn' , $setActions [ 'warn' ] );
$output .= Xml :: tags ( 'p' , null , $checkbox );
$warnMsg = empty ( $setActions [ 'warn' ]) ? 'abusefilter-warning' : $actions [ 'warn' ][ 'parameters' ][ 0 ];
$warnFields [ 'abusefilter-edit-warn-message' ] = Xml :: input ( 'wpFilterWarnMessage' , 45 , $warnMsg );
$output .= Xml :: tags ( 'p' , null , Xml :: buildForm ( $warnFields ) );
2008-06-27 06:18:51 +00:00
// The remainder are just toggles
2008-10-21 14:11:03 +00:00
$remainingActions = array_diff ( $wgAbuseFilterAvailableActions , array ( 'flag' , 'throttle' , 'warn' ) );
2008-06-27 06:18:51 +00:00
foreach ( $remainingActions as $action ) {
$message = 'abusefilter-edit-action-' . $action ;
$form_field = 'wpFilterAction' . ucfirst ( $action );
$status = $setActions [ $action ];
$thisAction = Xml :: checkLabel ( wfMsg ( $message ), $form_field , $form_field , $status );
$thisAction = Xml :: tags ( 'p' , null , $thisAction );
$output .= $thisAction ;
}
return $output ;
}
2008-10-21 15:14:30 +00:00
function loadFilterData ( $id ) {
2008-06-27 06:18:51 +00:00
$dbr = wfGetDB ( DB_SLAVE );
// Load the main row
$row = $dbr -> selectRow ( 'abuse_filter' , '*' , array ( 'af_id' => $id ), __METHOD__ );
2008-08-31 07:08:11 +00:00
if ( ! isset ( $row ) || ! isset ( $row -> af_id ) || ! $row -> af_id )
2008-08-04 14:27:48 +00:00
return array ( new stdClass , array () );
2008-06-27 06:18:51 +00:00
// Load the actions
$actions = array ();
$res = $dbr -> select ( 'abuse_filter_action' , '*' , array ( 'afa_filter' => $id ), __METHOD__ );
while ( $actionRow = $dbr -> fetchObject ( $res ) ) {
$thisAction = array ();
$thisAction [ 'action' ] = $actionRow -> afa_consequence ;
$thisAction [ 'parameters' ] = explode ( " \n " , $actionRow -> afa_parameters );
$actions [ $actionRow -> afa_consequence ] = $thisAction ;
}
return array ( $row , $actions );
}
2008-10-21 15:14:30 +00:00
function loadHistoryItem ( $id ) {
$dbr = wfGetDB ( DB_SLAVE );
// 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 );
}
2008-06-27 06:18:51 +00:00
function loadParameters ( $subpage ) {
2008-06-27 09:26:54 +00:00
global $wgRequest ;
2008-06-27 06:18:51 +00:00
$filter = $subpage ;
2008-06-27 09:26:54 +00:00
if ( ! is_numeric ( $filter ) && $filter != 'new' ) {
2008-06-27 06:18:51 +00:00
$filter = $wgRequest -> getIntOrNull ( 'wpFilter' );
}
$this -> mFilter = $filter ;
}
2008-10-21 15:14:30 +00:00
function loadRequest ( $filter , $history_id = null ) {
2008-08-03 14:04:26 +00:00
static $row = null ;
static $actions = null ;
global $wgRequest ;
if ( ! is_null ( $actions ) && ! is_null ( $row )) {
return array ( $row , $actions );
2008-10-21 15:14:30 +00:00
} elseif ( $wgRequest -> wasPosted ()) {
## Nothing, we do it all later
} elseif ( $history_id ) {
return $this -> loadHistoryItem ( $history_id );
} else {
return $this -> loadFilterData ( $filter );
2008-08-03 14:04:26 +00:00
}
// We need some details like last editor
list ( $row ) = $this -> loadFilterData ();
$textLoads = array ( 'af_public_comments' => 'wpFilterDescription' , 'af_pattern' => 'wpFilterRules' , 'af_comments' => 'wpFilterNotes' );
foreach ( $textLoads as $col => $field ) {
$row -> $col = $wgRequest -> getVal ( $field );
}
2008-09-05 14:27:18 +00:00
$row -> af_deleted = $wgRequest -> getBool ( 'wpFilterDeleted' );
$row -> af_enabled = $wgRequest -> getBool ( 'wpFilterEnabled' ) && ! $row -> af_deleted ;
2008-08-03 14:04:26 +00:00
$row -> af_hidden = $wgRequest -> getBool ( 'wpFilterHidden' );
// Actions
global $wgAbuseFilterAvailableActions ;
$actions = array ();
foreach ( $wgAbuseFilterAvailableActions as $action ) {
// Check if it's set
$enabled = $wgRequest -> getBool ( 'wpFilterAction' . ucfirst ( $action ) );
if ( $enabled ) {
$parameters = array ();
if ( $action == 'throttle' ) {
// Grumble grumble.
// We need to load the parameters
$throttleCount = $wgRequest -> getIntOrNull ( 'wpFilterThrottleCount' );
$throttlePeriod = $wgRequest -> getIntOrNull ( 'wpFilterThrottlePeriod' );
$throttleGroups = explode ( " \n " , trim ( $wgRequest -> getText ( 'wpFilterThrottleGroups' ) ) );
$parameters [ 0 ] = $this -> mFilter ; // For now, anyway
$parameters [ 1 ] = " $throttleCount , $throttlePeriod " ;
$parameters = array_merge ( $parameters , $throttleGroups );
2008-10-21 14:11:03 +00:00
} elseif ( $action == 'warn' ) {
$parameters [ 0 ] = $wgRequest -> getVal ( 'wpFilterWarnMessage' );
2008-08-03 14:04:26 +00:00
}
$thisAction = array ( 'action' => $action , 'parameters' => $parameters );
$actions [ $action ] = $thisAction ;
}
}
return array ( $row , $actions );
}
2008-06-27 06:18:51 +00:00
function canEdit () {
global $wgUser ;
static $canEdit = 'unset' ;
if ( $canEdit == 'unset' ) {
$canEdit = ! count ( $errors = $this -> getTitle () -> getUserPermissionsErrors ( 'abusefilter-modify' , $wgUser , true , array ( 'ns-specialprotected' ) ) );
}
return $canEdit ;
}
2008-09-05 14:27:18 +00:00
function showList ( $conds = array ( 'af_deleted' => 0 )) {
2008-06-27 07:21:26 +00:00
global $wgOut , $wgUser ;
2008-06-27 06:18:51 +00:00
2008-06-27 07:21:26 +00:00
$sk = $this -> mSkin = $wgUser -> getSkin ();
2008-06-27 06:18:51 +00:00
$output = '' ;
$output .= Xml :: element ( 'h2' , null , wfMsgExt ( 'abusefilter-list' , array ( 'parseinline' ) ) );
// We shouldn't have more than 100 filters, so don't bother paging.
$dbr = wfGetDB ( DB_SLAVE );
2008-06-27 13:04:39 +00:00
$abuse_filter = $dbr -> tableName ( 'abuse_filter' );
2008-09-05 14:27:18 +00:00
$res = $dbr -> select ( array ( 'abuse_filter' , 'abuse_filter_action' ), $abuse_filter . '.*,group_concat(afa_consequence) AS consequences' , $conds , __METHOD__ , array ( 'LIMIT' => 100 , 'GROUP BY' => 'af_id' ),
2008-06-27 07:55:13 +00:00
array ( 'abuse_filter_action' => array ( 'LEFT OUTER JOIN' , 'afa_filter=af_id' ) ) );
2008-06-27 06:18:51 +00:00
$list = '' ;
$editLabel = $this -> canEdit () ? 'abusefilter-list-edit' : 'abusefilter-list-details' ;
// Build in a table
$headers = array ( 'abusefilter-list-id' , 'abusefilter-list-public' , 'abusefilter-list-consequences' , 'abusefilter-list-status' , 'abusefilter-list-visibility' , 'abusefilter-list-hitcount' , $editLabel );
$header_row = '' ;
foreach ( $headers as $header ) {
$header_row .= Xml :: element ( 'th' , null , wfMsgExt ( $header , array ( 'parseinline' ) ) );
}
$list .= Xml :: tags ( 'tr' , null , $header_row );
while ( $row = $dbr -> fetchObject ( $res ) ) {
$list .= $this -> shortFormatFilter ( $row );
}
$output .= Xml :: tags ( 'table' , array ( 'class' => 'wikitable' ), Xml :: tags ( 'tbody' , null , $list ) );
2008-06-27 07:21:26 +00:00
if ( $this -> canEdit ()) {
2008-07-29 11:16:35 +00:00
$output .= $sk -> makeKnownLinkObj ( $this -> getTitle ( 'new' ), wfMsgHtml ( 'abusefilter-list-new' ) );
2008-06-27 07:21:26 +00:00
}
2008-06-27 06:18:51 +00:00
$wgOut -> addHTML ( $output );
}
2008-06-27 09:26:54 +00:00
function shortFormatFilter ( $row ) {
2008-07-29 11:16:35 +00:00
global $wgOut , $wgLang ;
2008-06-27 06:18:51 +00:00
$sk = $this -> mSkin ;
$editLabel = $this -> canEdit () ? 'abusefilter-list-edit' : 'abusefilter-list-details' ;
// Build a table row
$trow = '' ;
2008-09-05 14:27:18 +00:00
if ( $row -> af_deleted ) {
$status = wfMsgExt ( 'abusefilter-deleted' , array ( 'parseinline' ) );
} else {
$status = $row -> af_enabled ? 'abusefilter-enabled' : 'abusefilter-disabled' ;
$status = wfMsgExt ( $status , array ( 'parseinline' ) );
}
2008-06-27 06:18:51 +00:00
$visibility = $row -> af_hidden ? 'abusefilter-hidden' : 'abusefilter-unhidden' ;
$visibility = wfMsgExt ( $visibility , array ( 'parseinline' ) );
// Hit count
$count = $row -> af_hit_count ;
2008-07-29 11:16:35 +00:00
$count_display = wfMsgExt ( 'abusefilter-hitcount' , array ( 'parseinline' ), $wgLang -> formatNum ( $count ) );
2008-06-27 06:18:51 +00:00
$hitCount = $sk -> makeKnownLinkObj ( SpecialPage :: getTitleFor ( 'AbuseLog' ), $count_display , 'wpSearchFilter=' . $row -> af_id );
2008-07-29 11:16:35 +00:00
$editLink = $sk -> makeKnownLinkObj ( $this -> getTitle ( $row -> af_id ), wfMsgHtml ( $editLabel ) );
2008-06-27 06:18:51 +00:00
2008-06-27 07:55:13 +00:00
$consequences = wfEscapeWikitext ( $row -> consequences );
$values = array ( $row -> af_id , $wgOut -> parse ( $row -> af_public_comments ), $consequences , $status , $visibility , $hitCount , $editLink );
2008-06-27 06:18:51 +00:00
foreach ( $values as $value ) {
$trow .= Xml :: tags ( 'td' , null , $value );
}
$trow = Xml :: tags ( 'tr' , null , $trow );
return $trow ;
}
2008-08-03 14:04:26 +00:00
}
class AbuseFilterHistoryPager extends ReverseChronologicalPager {
function __construct ( $filter ) {
$this -> mFilter = $filter ;
parent :: __construct ();
}
function formatRow ( $row ) {
static $sk = null ;
if ( is_null ( $sk )) {
global $wgUser ;
$sk = $wgUser -> getSkin ();
}
global $wgLang ;
$tr = '' ;
2008-10-21 15:14:30 +00:00
$title = SpecialPage :: getTitleFor ( 'AbuseFilter' , 'history/' . $this -> mFilter . '/item/' . $row -> afh_id );
$link = $sk -> link ( $title , $wgLang -> timeanddate ( $row -> afh_timestamp ) );
$flags = array_filter ( explode ( ',' , $row -> afh_flags ));
$display_flags = array ();
foreach ( $flags as $flag ) {
$display_flags [] = wfMsgForContent ( " abusefilter-history- $flag " );
}
$comments = $wgLang -> truncate ( $row -> afh_public_comments , 50 , '...' );
$pattern = $wgLang -> truncate ( $row -> afh_pattern , 200 , '...' );
$notes = $wgLang -> truncate ( $row -> afh_comments , 200 , '...' );
$tr .= Xml :: tags ( 'td' , null , $link );
2008-08-03 14:04:26 +00:00
$tr .= Xml :: tags ( 'td' , null , $sk -> userLink ( $row -> afh_user , $row -> afh_user_text ) . $sk -> userToolLinks ( $row -> afh_user , $row -> afh_user_text ) );
2008-10-21 15:14:30 +00:00
$tr .= Xml :: element ( 'td' , null , $comments );
$tr .= Xml :: element ( 'td' , null , implode ( ', ' , $display_flags ) );
$tr .= Xml :: element ( 'td' , null , $pattern );
$tr .= Xml :: element ( 'td' , null , $notes );
2008-08-03 14:04:26 +00:00
// Build actions
$actions = unserialize ( $row -> afh_actions );
$display_actions = '' ;
foreach ( $actions as $action => $parameters ) {
$display_actions .= Xml :: tags ( 'li' , null , wfMsgExt ( 'abusefilter-history-action' , array ( 'parseinline' ), array ( $action , implode ( ';' , $parameters )) ) );
}
$display_actions = Xml :: tags ( 'ul' , null , $display_actions );
$tr .= Xml :: tags ( 'td' , null , $display_actions );
return Xml :: tags ( 'tr' , null , $tr );
}
function getQueryInfo () {
return array (
'tables' => 'abuse_filter_history' ,
'fields' => '*' ,
'conds' => array ( 'afh_filter' => $this -> mFilter ),
);
}
function getIndexField () {
return 'afh_timestamp' ;
}
2008-06-27 06:18:51 +00:00
}