Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
49 / 49 |
|
100.00% |
3 / 3 |
CRAP | |
100.00% |
1 / 1 |
ConsequencesLookup | |
100.00% |
49 / 49 |
|
100.00% |
3 / 3 |
13 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
getConsequencesForFilters | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
5 | |||
loadConsequencesFromDB | |
100.00% |
27 / 27 |
|
100.00% |
1 / 1 |
7 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\AbuseFilter\Consequences; |
4 | |
5 | use MediaWiki\Extension\AbuseFilter\CentralDBManager; |
6 | use MediaWiki\Extension\AbuseFilter\GlobalNameUtils; |
7 | use Psr\Log\LoggerInterface; |
8 | use Wikimedia\Rdbms\IDatabase; |
9 | use Wikimedia\Rdbms\LBFactory; |
10 | |
11 | /** |
12 | * Class for retrieving actions and parameters from the database |
13 | * @todo Can we better integrate this with FilterLookup? |
14 | */ |
15 | class ConsequencesLookup { |
16 | public const SERVICE_NAME = 'AbuseFilterConsequencesLookup'; |
17 | |
18 | /** @var LBFactory */ |
19 | private $lbFactory; |
20 | /** @var CentralDBManager */ |
21 | private $centralDBManager; |
22 | /** @var ConsequencesRegistry */ |
23 | private $consequencesRegistry; |
24 | /** @var LoggerInterface */ |
25 | private $logger; |
26 | |
27 | /** |
28 | * @param LBFactory $lbFactory |
29 | * @param CentralDBManager $centralDBManager |
30 | * @param ConsequencesRegistry $consequencesRegistry |
31 | * @param LoggerInterface $logger |
32 | */ |
33 | public function __construct( |
34 | LBFactory $lbFactory, |
35 | CentralDBManager $centralDBManager, |
36 | ConsequencesRegistry $consequencesRegistry, |
37 | LoggerInterface $logger |
38 | ) { |
39 | $this->lbFactory = $lbFactory; |
40 | $this->centralDBManager = $centralDBManager; |
41 | $this->consequencesRegistry = $consequencesRegistry; |
42 | $this->logger = $logger; |
43 | } |
44 | |
45 | /** |
46 | * @param array<int|string> $filters |
47 | * @return array[][] |
48 | */ |
49 | public function getConsequencesForFilters( array $filters ): array { |
50 | $globalFilters = []; |
51 | $localFilters = []; |
52 | |
53 | foreach ( $filters as $filter ) { |
54 | list( $filterID, $global ) = GlobalNameUtils::splitGlobalName( $filter ); |
55 | |
56 | if ( $global ) { |
57 | $globalFilters[] = $filterID; |
58 | } else { |
59 | $localFilters[] = (int)$filter; |
60 | } |
61 | } |
62 | |
63 | // Load local filter info |
64 | $dbr = $this->lbFactory->getReplicaDatabase(); |
65 | // Retrieve the consequences. |
66 | $consequences = []; |
67 | |
68 | if ( count( $localFilters ) ) { |
69 | $consequences = $this->loadConsequencesFromDB( $dbr, $localFilters ); |
70 | } |
71 | |
72 | if ( count( $globalFilters ) ) { |
73 | $consequences += $this->loadConsequencesFromDB( |
74 | $this->centralDBManager->getConnection( DB_REPLICA ), |
75 | $globalFilters, |
76 | GlobalNameUtils::GLOBAL_FILTER_PREFIX |
77 | ); |
78 | } |
79 | |
80 | return $consequences; |
81 | } |
82 | |
83 | /** |
84 | * @param IDatabase $dbr |
85 | * @param int[] $filters |
86 | * @param string $prefix |
87 | * @return array[][] |
88 | */ |
89 | private function loadConsequencesFromDB( IDatabase $dbr, array $filters, string $prefix = '' ): array { |
90 | $actionsByFilter = []; |
91 | foreach ( $filters as $filter ) { |
92 | $actionsByFilter[$prefix . $filter] = []; |
93 | } |
94 | |
95 | $res = $dbr->select( |
96 | [ 'abuse_filter_action', 'abuse_filter' ], |
97 | '*', |
98 | [ 'af_id' => $filters ], |
99 | __METHOD__, |
100 | [], |
101 | [ 'abuse_filter_action' => [ 'LEFT JOIN', 'afa_filter=af_id' ] ] |
102 | ); |
103 | |
104 | $dangerousActions = $this->consequencesRegistry->getDangerousActionNames(); |
105 | // Categorise consequences by filter. |
106 | foreach ( $res as $row ) { |
107 | if ( $row->af_throttled |
108 | && in_array( $row->afa_consequence, $dangerousActions ) |
109 | ) { |
110 | // Don't do the action, just log |
111 | $this->logger->info( |
112 | 'Filter {filter_id} is throttled, skipping action: {action}', |
113 | [ |
114 | 'filter_id' => $row->af_id, |
115 | 'action' => $row->afa_consequence |
116 | ] |
117 | ); |
118 | } elseif ( $row->afa_filter !== $row->af_id ) { |
119 | // We probably got a NULL, as it's a LEFT JOIN. Don't add it. |
120 | continue; |
121 | } else { |
122 | $actionsByFilter[$prefix . $row->afa_filter][$row->afa_consequence] = |
123 | $row->afa_parameters !== '' ? explode( "\n", $row->afa_parameters ) : []; |
124 | } |
125 | } |
126 | |
127 | return $actionsByFilter; |
128 | } |
129 | |
130 | } |