Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
67.35% |
66 / 98 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
QueryAbuseFilters | |
67.35% |
66 / 98 |
|
50.00% |
1 / 2 |
77.65 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
66.32% |
63 / 95 |
|
0.00% |
0 / 1 |
71.14 | |||
getAllowedParams | n/a |
0 / 0 |
n/a |
0 / 0 |
1 | |||||
getExamplesMessages | n/a |
0 / 0 |
n/a |
0 / 0 |
1 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | */ |
18 | |
19 | namespace MediaWiki\Extension\AbuseFilter\Api; |
20 | |
21 | use MediaWiki\Api\ApiBase; |
22 | use MediaWiki\Api\ApiQuery; |
23 | use MediaWiki\Api\ApiQueryBase; |
24 | use MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager; |
25 | use MediaWiki\Extension\AbuseFilter\Filter\Flags; |
26 | use MediaWiki\Extension\AbuseFilter\FilterLookup; |
27 | use Wikimedia\ParamValidator\ParamValidator; |
28 | use Wikimedia\ParamValidator\TypeDef\IntegerDef; |
29 | use Wikimedia\Timestamp\ConvertibleTimestamp; |
30 | |
31 | /** |
32 | * Query module to list abuse filter details. |
33 | * |
34 | * @copyright 2009 Alex Z. <mrzmanwiki AT gmail DOT com> |
35 | * Based mostly on code by Bryan Tong Minh and Roan Kattouw |
36 | * |
37 | * @ingroup API |
38 | * @ingroup Extensions |
39 | */ |
40 | class QueryAbuseFilters extends ApiQueryBase { |
41 | |
42 | private AbuseFilterPermissionManager $afPermManager; |
43 | private FilterLookup $filterLookup; |
44 | |
45 | public function __construct( |
46 | ApiQuery $query, |
47 | string $moduleName, |
48 | AbuseFilterPermissionManager $afPermManager, |
49 | FilterLookup $filterLookup |
50 | ) { |
51 | parent::__construct( $query, $moduleName, 'abf' ); |
52 | $this->afPermManager = $afPermManager; |
53 | $this->filterLookup = $filterLookup; |
54 | } |
55 | |
56 | /** |
57 | * @inheritDoc |
58 | */ |
59 | public function execute() { |
60 | $this->checkUserRightsAny( 'abusefilter-view' ); |
61 | |
62 | $params = $this->extractRequestParams(); |
63 | |
64 | $prop = array_fill_keys( $params['prop'], true ); |
65 | $fld_id = isset( $prop['id'] ); |
66 | $fld_desc = isset( $prop['description'] ); |
67 | $fld_pattern = isset( $prop['pattern'] ); |
68 | $fld_actions = isset( $prop['actions'] ); |
69 | $fld_hits = isset( $prop['hits'] ); |
70 | $fld_comments = isset( $prop['comments'] ); |
71 | $fld_user = isset( $prop['lasteditor'] ); |
72 | $fld_time = isset( $prop['lastedittime'] ); |
73 | $fld_status = isset( $prop['status'] ); |
74 | $fld_private = isset( $prop['private'] ); |
75 | $fld_protected = isset( $prop['protected'] ); |
76 | |
77 | $result = $this->getResult(); |
78 | |
79 | // Use the SelectQueryBuilder from the FilterLookup service as a base so that we can construct |
80 | // Filter objects from the rows got in the query. |
81 | $this->getQueryBuilder()->queryInfo( |
82 | $this->filterLookup->getAbuseFilterQueryBuilder( $this->getDB() )->getQueryInfo() |
83 | ); |
84 | |
85 | $this->addOption( 'LIMIT', $params['limit'] + 1 ); |
86 | |
87 | $this->addWhereRange( 'af_id', $params['dir'], $params['startid'], $params['endid'] ); |
88 | |
89 | if ( $params['show'] !== null ) { |
90 | $show = array_fill_keys( $params['show'], true ); |
91 | |
92 | /* Check for conflicting parameters. */ |
93 | if ( ( isset( $show['enabled'] ) && isset( $show['!enabled'] ) ) |
94 | || ( isset( $show['deleted'] ) && isset( $show['!deleted'] ) ) |
95 | || ( isset( $show['private'] ) && isset( $show['!private'] ) ) |
96 | ) { |
97 | $this->dieWithError( 'apierror-show' ); |
98 | } |
99 | |
100 | $dbr = $this->getDb(); |
101 | $this->addWhereIf( $dbr->expr( 'af_enabled', '=', 0 ), isset( $show['!enabled'] ) ); |
102 | $this->addWhereIf( $dbr->expr( 'af_enabled', '!=', 0 ), isset( $show['enabled'] ) ); |
103 | $this->addWhereIf( $dbr->expr( 'af_deleted', '=', 0 ), isset( $show['!deleted'] ) ); |
104 | $this->addWhereIf( $dbr->expr( 'af_deleted', '!=', 0 ), isset( $show['deleted'] ) ); |
105 | $this->addWhereIf( |
106 | $dbr->bitAnd( 'af_hidden', Flags::FILTER_HIDDEN ) . ' = 0', |
107 | isset( $show['!private'] ) |
108 | ); |
109 | $this->addWhereIf( |
110 | $dbr->bitAnd( 'af_hidden', Flags::FILTER_HIDDEN ) . ' != 0', |
111 | isset( $show['private'] ) |
112 | ); |
113 | $this->addWhereIf( |
114 | $dbr->bitAnd( 'af_hidden', Flags::FILTER_USES_PROTECTED_VARS ) . ' != 0', |
115 | isset( $show['!protected'] ) |
116 | ); |
117 | $this->addWhereIf( |
118 | $dbr->bitAnd( 'af_hidden', Flags::FILTER_USES_PROTECTED_VARS ) . ' = 0', |
119 | isset( $show['!protected'] ) |
120 | ); |
121 | } |
122 | |
123 | $res = $this->select( __METHOD__ ); |
124 | |
125 | $showhidden = $this->afPermManager->canViewPrivateFilters( $this->getAuthority() ); |
126 | |
127 | $count = 0; |
128 | foreach ( $res as $row ) { |
129 | // FilterLookup::filterFromRow will override af_actions, so we need to define the callback to generate |
130 | // the data. We do not need to define anything other than the names because we only call |
131 | // AbstractFilter::getActionNames. |
132 | $actions = array_flip( explode( ',', $row->af_actions ) ); |
133 | $filter = $this->filterLookup->filterFromRow( $row, $actions ); |
134 | if ( ++$count > $params['limit'] ) { |
135 | // We've had enough |
136 | $this->setContinueEnumParameter( 'startid', $filter->getID() ); |
137 | break; |
138 | } |
139 | |
140 | // Hide the pattern and non-public comments from the API response if the user would not |
141 | // be able to open the editor for the filter. |
142 | $canViewExtendedDetailsAboutFilter = ( !$filter->isHidden() || $showhidden ); |
143 | |
144 | if ( $filter->isProtected() && $canViewExtendedDetailsAboutFilter ) { |
145 | $canViewExtendedDetailsAboutFilter = $this->afPermManager |
146 | ->canViewProtectedVariablesInFilter( $this->getAuthority(), $filter ) |
147 | ->isGood(); |
148 | } |
149 | |
150 | $entry = []; |
151 | if ( $fld_id ) { |
152 | $entry['id'] = $filter->getID(); |
153 | } |
154 | if ( $fld_desc ) { |
155 | $entry['description'] = $filter->getName(); |
156 | } |
157 | if ( $fld_pattern && $canViewExtendedDetailsAboutFilter ) { |
158 | $entry['pattern'] = $filter->getRules(); |
159 | } |
160 | if ( $fld_actions ) { |
161 | $entry['actions'] = implode( ',', $filter->getActionsNames() ); |
162 | } |
163 | if ( $fld_hits ) { |
164 | $entry['hits'] = $filter->getHitCount(); |
165 | } |
166 | if ( $fld_comments && $canViewExtendedDetailsAboutFilter ) { |
167 | $entry['comments'] = $filter->getComments(); |
168 | } |
169 | if ( $fld_user ) { |
170 | $entry['lasteditor'] = $filter->getLastEditInfo()->getUserName(); |
171 | } |
172 | if ( $fld_time ) { |
173 | $entry['lastedittime'] = ConvertibleTimestamp::convert( |
174 | TS_ISO_8601, $filter->getLastEditInfo()->getTimestamp() |
175 | ); |
176 | } |
177 | if ( $fld_private && $filter->isHidden() ) { |
178 | $entry['private'] = ''; |
179 | } |
180 | if ( $fld_protected && $filter->isProtected() ) { |
181 | $entry['protected'] = ''; |
182 | } |
183 | if ( $fld_status ) { |
184 | if ( $filter->isEnabled() ) { |
185 | $entry['enabled'] = ''; |
186 | } |
187 | if ( $filter->isDeleted() ) { |
188 | $entry['deleted'] = ''; |
189 | } |
190 | } |
191 | if ( $entry ) { |
192 | $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $entry ); |
193 | if ( !$fit ) { |
194 | $this->setContinueEnumParameter( 'startid', $filter->getID() ); |
195 | break; |
196 | } |
197 | } |
198 | } |
199 | $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'filter' ); |
200 | } |
201 | |
202 | /** |
203 | * @codeCoverageIgnore Merely declarative |
204 | * @inheritDoc |
205 | */ |
206 | public function getAllowedParams() { |
207 | return [ |
208 | 'startid' => [ |
209 | ParamValidator::PARAM_TYPE => 'integer' |
210 | ], |
211 | 'endid' => [ |
212 | ParamValidator::PARAM_TYPE => 'integer', |
213 | ], |
214 | 'dir' => [ |
215 | ParamValidator::PARAM_TYPE => [ |
216 | 'older', |
217 | 'newer' |
218 | ], |
219 | ParamValidator::PARAM_DEFAULT => 'newer', |
220 | ApiBase::PARAM_HELP_MSG => 'api-help-param-direction', |
221 | ], |
222 | 'show' => [ |
223 | ParamValidator::PARAM_ISMULTI => true, |
224 | ParamValidator::PARAM_TYPE => [ |
225 | 'enabled', |
226 | '!enabled', |
227 | 'deleted', |
228 | '!deleted', |
229 | 'private', |
230 | '!private', |
231 | 'protected', |
232 | '!protected', |
233 | ], |
234 | ], |
235 | 'limit' => [ |
236 | ParamValidator::PARAM_DEFAULT => 10, |
237 | ParamValidator::PARAM_TYPE => 'limit', |
238 | IntegerDef::PARAM_MIN => 1, |
239 | IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1, |
240 | IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2 |
241 | ], |
242 | 'prop' => [ |
243 | ParamValidator::PARAM_DEFAULT => 'id|description|actions|status', |
244 | ParamValidator::PARAM_TYPE => [ |
245 | 'id', |
246 | 'description', |
247 | 'pattern', |
248 | 'actions', |
249 | 'hits', |
250 | 'comments', |
251 | 'lasteditor', |
252 | 'lastedittime', |
253 | 'status', |
254 | 'private', |
255 | 'protected', |
256 | ], |
257 | ParamValidator::PARAM_ISMULTI => true |
258 | ] |
259 | ]; |
260 | } |
261 | |
262 | /** |
263 | * @codeCoverageIgnore Merely declarative |
264 | * @inheritDoc |
265 | */ |
266 | protected function getExamplesMessages() { |
267 | return [ |
268 | 'action=query&list=abusefilters&abfshow=enabled|!private' |
269 | => 'apihelp-query+abusefilters-example-1', |
270 | 'action=query&list=abusefilters&abfprop=id|description|pattern' |
271 | => 'apihelp-query+abusefilters-example-2', |
272 | ]; |
273 | } |
274 | } |