Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 146 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
ApiQueryGlobalBlocks | |
0.00% |
0 / 146 |
|
0.00% |
0 / 6 |
1122 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 90 |
|
0.00% |
0 / 1 |
756 | |||
getCacheMode | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAllowedParams | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
2 | |||
getDB | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getExamplesMessages | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * Created on Nov 1, 2008 |
5 | * |
6 | * GlobalBlocking extension |
7 | * |
8 | * Copyright (C) 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. |
14 | * |
15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU General Public License along |
21 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
23 | * http://www.gnu.org/copyleft/gpl.html |
24 | */ |
25 | |
26 | namespace MediaWiki\Extension\GlobalBlocking\Api; |
27 | |
28 | use ApiBase; |
29 | use ApiQuery; |
30 | use ApiQueryBase; |
31 | use ApiResult; |
32 | use CentralIdLookup; |
33 | use MediaWiki\Extension\GlobalBlocking\GlobalBlocking; |
34 | use Wikimedia\IPUtils; |
35 | use Wikimedia\ParamValidator\ParamValidator; |
36 | use Wikimedia\ParamValidator\TypeDef\IntegerDef; |
37 | use Wikimedia\Rdbms\IDatabase; |
38 | use Wikimedia\Rdbms\IExpression; |
39 | use Wikimedia\Rdbms\LikeValue; |
40 | |
41 | /** |
42 | * Query module to enumerate all global blocks. |
43 | * |
44 | * @ingroup API |
45 | * @ingroup Extensions |
46 | */ |
47 | class ApiQueryGlobalBlocks extends ApiQueryBase { |
48 | |
49 | /** |
50 | * @var IDatabase |
51 | */ |
52 | private $globalBlockingDb; |
53 | |
54 | /** |
55 | * @var CentralIdLookup |
56 | */ |
57 | private $lookup; |
58 | |
59 | /** |
60 | * @param ApiQuery $query |
61 | * @param string $moduleName |
62 | * @param CentralIdLookup $lookup |
63 | */ |
64 | public function __construct( |
65 | ApiQuery $query, |
66 | $moduleName, |
67 | CentralIdLookup $lookup |
68 | ) { |
69 | parent::__construct( $query, $moduleName, 'bg' ); |
70 | $this->lookup = $lookup; |
71 | } |
72 | |
73 | public function execute() { |
74 | $params = $this->extractRequestParams(); |
75 | $this->requireMaxOneParameter( $params, 'addresses', 'ip' ); |
76 | |
77 | $prop = array_flip( $params['prop'] ); |
78 | $fld_id = isset( $prop['id'] ); |
79 | $fld_address = isset( $prop['address'] ); |
80 | $fld_by = isset( $prop['by'] ); |
81 | $fld_timestamp = isset( $prop['timestamp'] ); |
82 | $fld_expiry = isset( $prop['expiry'] ); |
83 | $fld_reason = isset( $prop['reason'] ); |
84 | $fld_range = isset( $prop['range'] ); |
85 | |
86 | $result = $this->getResult(); |
87 | $data = []; |
88 | |
89 | $this->addTables( 'globalblocks' ); |
90 | if ( $fld_id ) { |
91 | $this->addFields( 'gb_id' ); |
92 | } |
93 | if ( $fld_address ) { |
94 | $this->addFields( [ 'gb_address', 'gb_anon_only' ] ); |
95 | } |
96 | if ( $fld_by ) { |
97 | $this->addFields( [ 'gb_by_central_id', 'gb_by_wiki' ] ); |
98 | } |
99 | |
100 | $this->addFields( 'gb_timestamp' ); |
101 | |
102 | if ( $fld_expiry ) { |
103 | $this->addFields( 'gb_expiry' ); |
104 | } |
105 | if ( $fld_reason ) { |
106 | $this->addFields( 'gb_reason' ); |
107 | } |
108 | if ( $fld_range ) { |
109 | $this->addFields( [ 'gb_range_start', 'gb_range_end' ] ); |
110 | } |
111 | |
112 | $dbr = $this->getDB(); |
113 | $this->addOption( 'LIMIT', $params['limit'] + 1 ); |
114 | $this->addWhereRange( 'gb_timestamp', $params['dir'], $params['start'], $params['end'] ); |
115 | $this->addWhere( $dbr->expr( 'gb_expiry', '>', $dbr->timestamp() ) ); |
116 | if ( isset( $params['ids'] ) ) { |
117 | $this->addWhereFld( 'gb_id', $params['ids'] ); |
118 | } |
119 | if ( isset( $params['addresses'] ) ) { |
120 | $addresses = []; |
121 | foreach ( (array)$params['addresses'] as $address ) { |
122 | if ( !IPUtils::isIPAddress( $address ) ) { |
123 | $this->dieWithError( |
124 | [ 'globalblocking-apierror-badip', wfEscapeWikiText( $address ) ], |
125 | 'param_addresses' |
126 | ); |
127 | } |
128 | $addresses[] = $address; |
129 | } |
130 | $this->addWhereFld( 'gb_address', $addresses ); |
131 | } |
132 | if ( isset( $params['ip'] ) ) { |
133 | if ( IPUtils::isIPv4( $params['ip'] ) ) { |
134 | $type = 'IPv4'; |
135 | $cidrLimit = 16; // @todo Make this configurable |
136 | $prefixLen = 0; |
137 | } elseif ( IPUtils::isIPv6( $params['ip'] ) ) { |
138 | $type = 'IPv6'; |
139 | $cidrLimit = 16; // @todo Make this configurable |
140 | $prefixLen = 3; // IPUtils::toHex output is prefixed with "v6-" |
141 | } else { |
142 | $this->dieWithError( 'apierror-badip', 'param_ip' ); |
143 | } |
144 | |
145 | # Check range validity, if it's a CIDR |
146 | [ $ip, $range ] = IPUtils::parseCIDR( $params['ip'] ); |
147 | if ( $ip !== false && $range !== false && $range < $cidrLimit ) { |
148 | $this->dieWithError( [ 'apierror-cidrtoobroad', $type, $cidrLimit ] ); |
149 | } |
150 | |
151 | # Let IPUtils::parseRange handle calculating $upper, instead of duplicating the logic here. |
152 | [ $lower, $upper ] = IPUtils::parseRange( $params['ip'] ); |
153 | |
154 | # Extract the common prefix to any rangeblock affecting this IP/CIDR |
155 | $prefix = substr( $lower, 0, $prefixLen + $cidrLimit / 4 ); |
156 | |
157 | $this->addWhere( [ |
158 | $dbr->expr( 'gb_range_start', IExpression::LIKE, new LikeValue( $prefix, $dbr->anyString() ) ), |
159 | $dbr->expr( 'gb_range_start', '<=', $lower ), |
160 | $dbr->expr( 'gb_range_end', '>=', $upper ), |
161 | ] ); |
162 | } |
163 | |
164 | $res = $this->select( __METHOD__ ); |
165 | |
166 | $count = 0; |
167 | foreach ( $res as $row ) { |
168 | if ( ++$count > $params['limit'] ) { |
169 | // We've had enough |
170 | $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->gb_timestamp ) ); |
171 | break; |
172 | } |
173 | $block = []; |
174 | if ( $fld_id ) { |
175 | $block['id'] = $row->gb_id; |
176 | } |
177 | if ( $fld_address ) { |
178 | $block['address'] = $row->gb_address; |
179 | if ( $row->gb_anon_only ) { |
180 | $block['anononly'] = ''; |
181 | } |
182 | } |
183 | if ( $fld_by ) { |
184 | $block['by'] = $this->lookup->nameFromCentralId( $row->gb_by_central_id ); |
185 | $block['bywiki'] = $row->gb_by_wiki; |
186 | } |
187 | if ( $fld_timestamp ) { |
188 | $block['timestamp'] = wfTimestamp( TS_ISO_8601, $row->gb_timestamp ); |
189 | } |
190 | if ( $fld_expiry ) { |
191 | $block['expiry'] = ApiResult::formatExpiry( $row->gb_expiry ); |
192 | } |
193 | if ( $fld_reason ) { |
194 | $block['reason'] = $row->gb_reason; |
195 | } |
196 | if ( $fld_range ) { |
197 | $block['rangestart'] = IPUtils::hexToQuad( $row->gb_range_start ); |
198 | $block['rangeend'] = IPUtils::hexToQuad( $row->gb_range_end ); |
199 | } |
200 | $data[] = $block; |
201 | } |
202 | $result->setIndexedTagName( $data, 'block' ); |
203 | $result->addValue( 'query', $this->getModuleName(), $data ); |
204 | } |
205 | |
206 | public function getCacheMode( $params ) { |
207 | return 'public'; |
208 | } |
209 | |
210 | public function getAllowedParams() { |
211 | return [ |
212 | 'start' => [ |
213 | ParamValidator::PARAM_TYPE => 'timestamp' |
214 | ], |
215 | 'end' => [ |
216 | ParamValidator::PARAM_TYPE => 'timestamp', |
217 | ], |
218 | 'dir' => [ |
219 | ParamValidator::PARAM_TYPE => [ |
220 | 'newer', |
221 | 'older' |
222 | ], |
223 | ParamValidator::PARAM_DEFAULT => 'older', |
224 | ApiBase::PARAM_HELP_MSG => 'api-help-param-direction', |
225 | ], |
226 | 'ids' => [ |
227 | ParamValidator::PARAM_TYPE => 'integer', |
228 | ParamValidator::PARAM_ISMULTI => true |
229 | ], |
230 | 'addresses' => [ |
231 | ParamValidator::PARAM_ISMULTI => true |
232 | ], |
233 | 'ip' => null, |
234 | 'limit' => [ |
235 | ParamValidator::PARAM_DEFAULT => 10, |
236 | ParamValidator::PARAM_TYPE => 'limit', |
237 | IntegerDef::PARAM_MIN => 1, |
238 | IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1, |
239 | IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2 |
240 | ], |
241 | 'prop' => [ |
242 | ParamValidator::PARAM_DEFAULT => 'id|address|by|timestamp|expiry|reason', |
243 | ParamValidator::PARAM_TYPE => [ |
244 | 'id', |
245 | 'address', |
246 | 'by', |
247 | 'timestamp', |
248 | 'expiry', |
249 | 'reason', |
250 | 'range', |
251 | ], |
252 | ParamValidator::PARAM_ISMULTI => true |
253 | ] |
254 | ]; |
255 | } |
256 | |
257 | protected function getDB() { |
258 | if ( $this->globalBlockingDb === null ) { |
259 | $this->globalBlockingDb = GlobalBlocking::getReplicaGlobalBlockingDatabase(); |
260 | } |
261 | return $this->globalBlockingDb; |
262 | } |
263 | |
264 | /** |
265 | * @see ApiBase::getExamplesMessages() |
266 | * @return array |
267 | */ |
268 | protected function getExamplesMessages() { |
269 | return [ |
270 | 'action=query&list=globalblocks' |
271 | => 'apihelp-query+globalblocks-example-1', |
272 | 'action=query&list=globalblocks&bgip=192.0.2.18' |
273 | => 'apihelp-query+globalblocks-example-2', |
274 | ]; |
275 | } |
276 | } |