mediawiki-extensions-AbuseF.../includes/Consequences/ConsequencesLookup.php
Umherirrender 6dccb17255 Migrate to IReadableDatabase::newSelectQueryBuilder
Also use expression builder to avoid raw sql

Bug: T312420
Change-Id: I83eb39f1c65a698108ae5bb72f633afda37a9f23
2024-04-30 20:45:51 +02:00

130 lines
3.4 KiB
PHP

<?php
namespace MediaWiki\Extension\AbuseFilter\Consequences;
use MediaWiki\Extension\AbuseFilter\CentralDBManager;
use MediaWiki\Extension\AbuseFilter\GlobalNameUtils;
use Psr\Log\LoggerInterface;
use Wikimedia\Rdbms\IReadableDatabase;
use Wikimedia\Rdbms\LBFactory;
/**
* Class for retrieving actions and parameters from the database
* @todo Can we better integrate this with FilterLookup?
*/
class ConsequencesLookup {
public const SERVICE_NAME = 'AbuseFilterConsequencesLookup';
/** @var LBFactory */
private $lbFactory;
/** @var CentralDBManager */
private $centralDBManager;
/** @var ConsequencesRegistry */
private $consequencesRegistry;
/** @var LoggerInterface */
private $logger;
/**
* @param LBFactory $lbFactory
* @param CentralDBManager $centralDBManager
* @param ConsequencesRegistry $consequencesRegistry
* @param LoggerInterface $logger
*/
public function __construct(
LBFactory $lbFactory,
CentralDBManager $centralDBManager,
ConsequencesRegistry $consequencesRegistry,
LoggerInterface $logger
) {
$this->lbFactory = $lbFactory;
$this->centralDBManager = $centralDBManager;
$this->consequencesRegistry = $consequencesRegistry;
$this->logger = $logger;
}
/**
* @param array<int|string> $filters
* @return array[][]
*/
public function getConsequencesForFilters( array $filters ): array {
$globalFilters = [];
$localFilters = [];
foreach ( $filters as $filter ) {
[ $filterID, $global ] = GlobalNameUtils::splitGlobalName( $filter );
if ( $global ) {
$globalFilters[] = $filterID;
} else {
$localFilters[] = (int)$filter;
}
}
// Load local filter info
$dbr = $this->lbFactory->getReplicaDatabase();
// Retrieve the consequences.
$consequences = [];
if ( count( $localFilters ) ) {
$consequences = $this->loadConsequencesFromDB( $dbr, $localFilters );
}
if ( count( $globalFilters ) ) {
$consequences += $this->loadConsequencesFromDB(
$this->centralDBManager->getConnection( DB_REPLICA ),
$globalFilters,
GlobalNameUtils::GLOBAL_FILTER_PREFIX
);
}
return $consequences;
}
/**
* @param IReadableDatabase $dbr
* @param int[] $filters
* @param string $prefix
* @return array[][]
*/
private function loadConsequencesFromDB( IReadableDatabase $dbr, array $filters, string $prefix = '' ): array {
$actionsByFilter = [];
foreach ( $filters as $filter ) {
$actionsByFilter[$prefix . $filter] = [];
}
$res = $dbr->newSelectQueryBuilder()
->select( '*' )
->from( 'abuse_filter_action' )
->leftJoin( 'abuse_filter', null, 'afa_filter=af_id' )
->where( [ 'af_id' => $filters ] )
->caller( __METHOD__ )
->fetchResultSet();
$dangerousActions = $this->consequencesRegistry->getDangerousActionNames();
// 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] =
$row->afa_parameters !== '' ? explode( "\n", $row->afa_parameters ) : [];
}
}
return $actionsByFilter;
}
}