mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/AbuseFilter.git
synced 2024-11-27 15:30:42 +00:00
Add ConsequencesLookup
The class is used to retrieve consequences from the Database. Change-Id: I46b3925aac47554723649c076eff64707a2ea2e6
This commit is contained in:
parent
d76affb1db
commit
c957188866
|
@ -184,6 +184,7 @@
|
|||
"MediaWiki\\Extension\\AbuseFilter\\InvalidImportDataException": "includes/InvalidImportDataException.php",
|
||||
"MediaWiki\\Extension\\AbuseFilter\\FilterStore": "includes/FilterStore.php",
|
||||
"MediaWiki\\Extension\\AbuseFilter\\ConsequencesFactory": "includes/ConsequencesFactory.php",
|
||||
"MediaWiki\\Extension\\AbuseFilter\\ConsequencesLookup": "includes/ConsequencesLookup.php",
|
||||
"AFComputedVariable": "includes/AFComputedVariable.php",
|
||||
"AFPData": "includes/parser/AFPData.php",
|
||||
"AFPException": "includes/parser/AFPException.php",
|
||||
|
|
|
@ -5,7 +5,6 @@ use MediaWiki\Extension\AbuseFilter\Hooks\AbuseFilterHookRunner;
|
|||
use MediaWiki\Extension\AbuseFilter\VariableGenerator\VariableGenerator;
|
||||
use MediaWiki\Logger\LoggerFactory;
|
||||
use MediaWiki\Revision\RevisionRecord;
|
||||
use Wikimedia\Rdbms\IDatabase;
|
||||
|
||||
/**
|
||||
* This class contains most of the business logic of AbuseFilter. It consists of
|
||||
|
@ -170,86 +169,10 @@ class AbuseFilter {
|
|||
/**
|
||||
* @param string[] $filters
|
||||
* @return array[][]
|
||||
* @deprecated since 1.36 Use ConsequencesLookup
|
||||
*/
|
||||
public static function getConsequencesForFilters( $filters ) {
|
||||
$globalFilters = [];
|
||||
$localFilters = [];
|
||||
|
||||
foreach ( $filters as $filter ) {
|
||||
list( $filterID, $global ) = self::splitGlobalName( $filter );
|
||||
|
||||
if ( $global ) {
|
||||
$globalFilters[] = $filterID;
|
||||
} else {
|
||||
$localFilters[] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
// Load local filter info
|
||||
$dbr = wfGetDB( DB_REPLICA );
|
||||
// Retrieve the consequences.
|
||||
$consequences = [];
|
||||
|
||||
if ( count( $localFilters ) ) {
|
||||
$consequences = self::loadConsequencesFromDB( $dbr, $localFilters, '' );
|
||||
}
|
||||
|
||||
if ( count( $globalFilters ) ) {
|
||||
$consequences += self::loadConsequencesFromDB(
|
||||
AbuseFilterServices::getCentralDBManager()->getConnection( DB_REPLICA ),
|
||||
$globalFilters,
|
||||
self::GLOBAL_FILTER_PREFIX
|
||||
);
|
||||
}
|
||||
|
||||
return $consequences;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IDatabase $dbr
|
||||
* @param string[] $filters
|
||||
* @param string $prefix
|
||||
* @return array[][]
|
||||
*/
|
||||
private static function loadConsequencesFromDB( IDatabase $dbr, $filters, $prefix = '' ) {
|
||||
$actionsByFilter = [];
|
||||
foreach ( $filters as $filter ) {
|
||||
$actionsByFilter[$prefix . $filter] = [];
|
||||
}
|
||||
|
||||
$res = $dbr->select(
|
||||
[ 'abuse_filter_action', 'abuse_filter' ],
|
||||
'*',
|
||||
[ 'af_id' => $filters ],
|
||||
__METHOD__,
|
||||
[],
|
||||
[ 'abuse_filter_action' => [ 'LEFT JOIN', 'afa_filter=af_id' ] ]
|
||||
);
|
||||
|
||||
// Categorise consequences by filter.
|
||||
foreach ( $res as $row ) {
|
||||
if ( $row->af_throttled
|
||||
&& in_array( $row->afa_consequence, self::getDangerousActions() )
|
||||
) {
|
||||
// Don't do the action, just log
|
||||
$logger = LoggerFactory::getInstance( 'AbuseFilter' );
|
||||
$logger->info(
|
||||
'Filter {filter_id} is throttled, skipping action: {action}',
|
||||
[
|
||||
'filter_id' => $row->af_id,
|
||||
'action' => $row->afa_consequence
|
||||
]
|
||||
);
|
||||
} elseif ( $row->afa_filter !== $row->af_id ) {
|
||||
// We probably got a NULL, as it's a LEFT JOIN. Don't add it.
|
||||
continue;
|
||||
} else {
|
||||
$actionsByFilter[$prefix . $row->afa_filter][$row->afa_consequence] =
|
||||
array_filter( explode( "\n", $row->afa_parameters ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $actionsByFilter;
|
||||
return AbuseFilterServices::getConsequencesLookup()->getConsequencesForFilters( $filters );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -448,7 +448,8 @@ class AbuseFilterRunner {
|
|||
* the errors and warnings to be shown to the user to explain the actions.
|
||||
*/
|
||||
protected function executeFilterActions( array $filters ) : Status {
|
||||
$actionsByFilter = AbuseFilter::getConsequencesForFilters( $filters );
|
||||
$consLookup = AbuseFilterServices::getConsequencesLookup();
|
||||
$actionsByFilter = $consLookup->getConsequencesForFilters( $filters );
|
||||
$consequences = $this->replaceArraysWithConsequences( $actionsByFilter );
|
||||
$actionsToTake = $this->getFilteredConsequences( $consequences );
|
||||
$actionsTaken = array_fill_keys( $filters, [] );
|
||||
|
|
|
@ -136,4 +136,11 @@ class AbuseFilterServices {
|
|||
public static function getEditBoxBuilderFactory() : EditBoxBuilderFactory {
|
||||
return MediaWikiServices::getInstance()->getService( EditBoxBuilderFactory::SERVICE_NAME );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ConsequencesLookup
|
||||
*/
|
||||
public static function getConsequencesLookup() : ConsequencesLookup {
|
||||
return MediaWikiServices::getInstance()->getService( ConsequencesLookup::SERVICE_NAME );
|
||||
}
|
||||
}
|
||||
|
|
123
includes/ConsequencesLookup.php
Normal file
123
includes/ConsequencesLookup.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Extension\AbuseFilter;
|
||||
|
||||
use AbuseFilter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Wikimedia\Rdbms\IDatabase;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
|
||||
/**
|
||||
* Class for retrieving actions and parameters from the database
|
||||
*/
|
||||
class ConsequencesLookup {
|
||||
public const SERVICE_NAME = 'AbuseFilterConsequencesLookup';
|
||||
|
||||
/** @var ILoadBalancer */
|
||||
private $loadBalancer;
|
||||
/** @var CentralDBManager */
|
||||
private $centralDBManager;
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @param ILoadBalancer $loadBalancer
|
||||
* @param CentralDBManager $centralDBManager
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(
|
||||
ILoadBalancer $loadBalancer,
|
||||
CentralDBManager $centralDBManager,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->loadBalancer = $loadBalancer;
|
||||
$this->centralDBManager = $centralDBManager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $filters
|
||||
* @return array[][]
|
||||
*/
|
||||
public function getConsequencesForFilters( array $filters ) : array {
|
||||
$globalFilters = [];
|
||||
$localFilters = [];
|
||||
|
||||
foreach ( $filters as $filter ) {
|
||||
list( $filterID, $global ) = AbuseFilter::splitGlobalName( $filter );
|
||||
|
||||
if ( $global ) {
|
||||
$globalFilters[] = $filterID;
|
||||
} else {
|
||||
$localFilters[] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
// Load local filter info
|
||||
$dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
|
||||
// Retrieve the consequences.
|
||||
$consequences = [];
|
||||
|
||||
if ( count( $localFilters ) ) {
|
||||
$consequences = $this->loadConsequencesFromDB( $dbr, $localFilters );
|
||||
}
|
||||
|
||||
if ( count( $globalFilters ) ) {
|
||||
$consequences += $this->loadConsequencesFromDB(
|
||||
$this->centralDBManager->getConnection( DB_REPLICA ),
|
||||
$globalFilters,
|
||||
AbuseFilter::GLOBAL_FILTER_PREFIX
|
||||
);
|
||||
}
|
||||
|
||||
return $consequences;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IDatabase $dbr
|
||||
* @param string[] $filters
|
||||
* @param string $prefix
|
||||
* @return array[][]
|
||||
*/
|
||||
private function loadConsequencesFromDB( IDatabase $dbr, array $filters, string $prefix = '' ) : array {
|
||||
$actionsByFilter = [];
|
||||
foreach ( $filters as $filter ) {
|
||||
$actionsByFilter[$prefix . $filter] = [];
|
||||
}
|
||||
|
||||
$res = $dbr->select(
|
||||
[ 'abuse_filter_action', 'abuse_filter' ],
|
||||
'*',
|
||||
[ 'af_id' => $filters ],
|
||||
__METHOD__,
|
||||
[],
|
||||
[ 'abuse_filter_action' => [ 'LEFT JOIN', 'afa_filter=af_id' ] ]
|
||||
);
|
||||
|
||||
$dangerousActions = AbuseFilter::getDangerousActions();
|
||||
// Categorise consequences by filter.
|
||||
foreach ( $res as $row ) {
|
||||
if ( $row->af_throttled
|
||||
&& in_array( $row->afa_consequence, $dangerousActions )
|
||||
) {
|
||||
// Don't do the action, just log
|
||||
$this->logger->info(
|
||||
'Filter {filter_id} is throttled, skipping action: {action}',
|
||||
[
|
||||
'filter_id' => $row->af_id,
|
||||
'action' => $row->afa_consequence
|
||||
]
|
||||
);
|
||||
} elseif ( $row->afa_filter !== $row->af_id ) {
|
||||
// We probably got a NULL, as it's a LEFT JOIN. Don't add it.
|
||||
continue;
|
||||
} else {
|
||||
$actionsByFilter[$prefix . $row->afa_filter][$row->afa_consequence] =
|
||||
array_filter( explode( "\n", $row->afa_parameters ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $actionsByFilter;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ use MediaWiki\Extension\AbuseFilter\ChangeTags\ChangeTagger;
|
|||
use MediaWiki\Extension\AbuseFilter\ChangeTags\ChangeTagsManager;
|
||||
use MediaWiki\Extension\AbuseFilter\ChangeTags\ChangeTagValidator;
|
||||
use MediaWiki\Extension\AbuseFilter\ConsequencesFactory;
|
||||
use MediaWiki\Extension\AbuseFilter\ConsequencesLookup;
|
||||
use MediaWiki\Extension\AbuseFilter\EditBoxBuilderFactory;
|
||||
use MediaWiki\Extension\AbuseFilter\FilterCompare;
|
||||
use MediaWiki\Extension\AbuseFilter\FilterImporter;
|
||||
|
@ -173,6 +174,13 @@ return [
|
|||
ExtensionRegistry::getInstance()->isLoaded( 'CodeEditor' )
|
||||
);
|
||||
},
|
||||
ConsequencesLookup::SERVICE_NAME => function ( MediaWikiServices $services ) : ConsequencesLookup {
|
||||
return new ConsequencesLookup(
|
||||
$services->getDBLoadBalancer(),
|
||||
$services->get( CentralDBManager::SERVICE_NAME ),
|
||||
LoggerFactory::getInstance( 'AbuseFilter' )
|
||||
);
|
||||
},
|
||||
];
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
|
28
tests/phpunit/unit/AbuseFilterConsequencesLookupTest.php
Normal file
28
tests/phpunit/unit/AbuseFilterConsequencesLookupTest.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\Extension\AbuseFilter\CentralDBManager;
|
||||
use MediaWiki\Extension\AbuseFilter\ConsequencesLookup;
|
||||
use Psr\Log\NullLogger;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
|
||||
/**
|
||||
* @group Test
|
||||
* @group AbuseFilter
|
||||
* @coversDefaultClass \MediaWiki\Extension\AbuseFilter\ConsequencesLookup
|
||||
* @todo Write unit tests (non-trivial because the class is tied to a DB)
|
||||
*/
|
||||
class AbuseFilterConsequencesLookupTest extends MediaWikiUnitTestCase {
|
||||
/**
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testConstructor() {
|
||||
$this->assertInstanceOf(
|
||||
ConsequencesLookup::class,
|
||||
new ConsequencesLookup(
|
||||
$this->createMock( ILoadBalancer::class ),
|
||||
$this->createMock( CentralDBManager::class ),
|
||||
new NullLogger()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue