Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.49% |
678 / 710 |
|
70.27% |
26 / 37 |
CRAP | |
0.00% |
0 / 1 |
ApiQuerySiteinfo | |
95.49% |
678 / 710 |
|
70.27% |
26 / 37 |
173 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
97.83% |
90 / 92 |
|
0.00% |
0 / 1 |
32 | |||
appendGeneralInfo | |
100.00% |
108 / 108 |
|
100.00% |
1 / 1 |
13 | |||
appendNamespaces | |
96.00% |
24 / 25 |
|
0.00% |
0 / 1 |
7 | |||
appendNamespaceAliases | |
91.67% |
11 / 12 |
|
0.00% |
0 / 1 |
3.01 | |||
appendSpecialPageAliases | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
3 | |||
appendMagicWords | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
2 | |||
appendInterwikiMap | |
97.78% |
44 / 45 |
|
0.00% |
0 / 1 |
16 | |||
appendDbReplLagInfo | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
5 | |||
appendStatistics | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
1 | |||
appendUserGroups | |
100.00% |
34 / 34 |
|
100.00% |
1 / 1 |
10 | |||
appendAutoCreateTempUser | |
91.67% |
11 / 12 |
|
0.00% |
0 / 1 |
3.01 | |||
appendFileExtensions | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
appendInstalledClientLibraries | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
appendInstalledLibraries | |
85.71% |
12 / 14 |
|
0.00% |
0 / 1 |
4.05 | |||
appendExtensions | |
88.46% |
46 / 52 |
|
0.00% |
0 / 1 |
17.44 | |||
appendRightsInfo | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
4 | |||
appendRestrictions | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
1 | |||
appendLanguages | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
2 | |||
appendLanguageVariants | |
95.83% |
23 / 24 |
|
0.00% |
0 / 1 |
5 | |||
appendSkins | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
7 | |||
appendExtensionTags | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
appendFunctionHooks | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
appendVariables | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
appendProtocols | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
appendDefaultOptions | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
appendUploadDialog | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getAutoPromoteConds | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
processAutoPromote | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
appendAutoPromote | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
appendAutoPromoteOnce | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
recAutopromote | |
100.00% |
27 / 27 |
|
100.00% |
1 / 1 |
9 | |||
appendSubscribedHooks | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
2 | |||
getCacheMode | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
getAllowedParams | |
100.00% |
46 / 46 |
|
100.00% |
1 / 1 |
1 | |||
getExamplesMessages | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
getHelpUrls | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com" |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | */ |
22 | |
23 | use MediaWiki\Interwiki\InterwikiLookup; |
24 | use MediaWiki\Languages\LanguageConverterFactory; |
25 | use MediaWiki\Languages\LanguageFactory; |
26 | use MediaWiki\Languages\LanguageNameUtils; |
27 | use MediaWiki\MainConfigNames; |
28 | use MediaWiki\MediaWikiServices; |
29 | use MediaWiki\Parser\MagicWordFactory; |
30 | use MediaWiki\ResourceLoader\SkinModule; |
31 | use MediaWiki\SiteStats\SiteStats; |
32 | use MediaWiki\SpecialPage\SpecialPage; |
33 | use MediaWiki\SpecialPage\SpecialPageFactory; |
34 | use MediaWiki\Specials\SpecialVersion; |
35 | use MediaWiki\Title\NamespaceInfo; |
36 | use MediaWiki\Title\Title; |
37 | use MediaWiki\User\Options\UserOptionsLookup; |
38 | use MediaWiki\User\UserGroupManager; |
39 | use MediaWiki\Utils\ExtensionInfo; |
40 | use MediaWiki\Utils\GitInfo; |
41 | use MediaWiki\Utils\UrlUtils; |
42 | use MediaWiki\WikiMap\WikiMap; |
43 | use Wikimedia\Composer\ComposerInstalled; |
44 | use Wikimedia\ParamValidator\ParamValidator; |
45 | use Wikimedia\Rdbms\ILoadBalancer; |
46 | use Wikimedia\Rdbms\ReadOnlyMode; |
47 | |
48 | /** |
49 | * A query action to return meta information about the wiki site. |
50 | * |
51 | * @ingroup API |
52 | */ |
53 | class ApiQuerySiteinfo extends ApiQueryBase { |
54 | |
55 | private UserOptionsLookup $userOptionsLookup; |
56 | private UserGroupManager $userGroupManager; |
57 | private LanguageConverterFactory $languageConverterFactory; |
58 | private LanguageFactory $languageFactory; |
59 | private LanguageNameUtils $languageNameUtils; |
60 | private Language $contentLanguage; |
61 | private NamespaceInfo $namespaceInfo; |
62 | private InterwikiLookup $interwikiLookup; |
63 | private ParserFactory $parserFactory; |
64 | private MagicWordFactory $magicWordFactory; |
65 | private SpecialPageFactory $specialPageFactory; |
66 | private SkinFactory $skinFactory; |
67 | private ILoadBalancer $loadBalancer; |
68 | private ReadOnlyMode $readOnlyMode; |
69 | private UrlUtils $urlUtils; |
70 | |
71 | /** |
72 | * @param ApiQuery $query |
73 | * @param string $moduleName |
74 | * @param UserOptionsLookup $userOptionsLookup |
75 | * @param UserGroupManager $userGroupManager |
76 | * @param LanguageConverterFactory $languageConverterFactory |
77 | * @param LanguageFactory $languageFactory |
78 | * @param LanguageNameUtils $languageNameUtils |
79 | * @param Language $contentLanguage |
80 | * @param NamespaceInfo $namespaceInfo |
81 | * @param InterwikiLookup $interwikiLookup |
82 | * @param ParserFactory $parserFactory |
83 | * @param MagicWordFactory $magicWordFactory |
84 | * @param SpecialPageFactory $specialPageFactory |
85 | * @param SkinFactory $skinFactory |
86 | * @param ILoadBalancer $loadBalancer |
87 | * @param ReadOnlyMode $readOnlyMode |
88 | * @param UrlUtils $urlUtils |
89 | */ |
90 | public function __construct( |
91 | ApiQuery $query, |
92 | $moduleName, |
93 | UserOptionsLookup $userOptionsLookup, |
94 | UserGroupManager $userGroupManager, |
95 | LanguageConverterFactory $languageConverterFactory, |
96 | LanguageFactory $languageFactory, |
97 | LanguageNameUtils $languageNameUtils, |
98 | Language $contentLanguage, |
99 | NamespaceInfo $namespaceInfo, |
100 | InterwikiLookup $interwikiLookup, |
101 | ParserFactory $parserFactory, |
102 | MagicWordFactory $magicWordFactory, |
103 | SpecialPageFactory $specialPageFactory, |
104 | SkinFactory $skinFactory, |
105 | ILoadBalancer $loadBalancer, |
106 | ReadOnlyMode $readOnlyMode, |
107 | UrlUtils $urlUtils |
108 | ) { |
109 | parent::__construct( $query, $moduleName, 'si' ); |
110 | $this->userOptionsLookup = $userOptionsLookup; |
111 | $this->userGroupManager = $userGroupManager; |
112 | $this->languageConverterFactory = $languageConverterFactory; |
113 | $this->languageFactory = $languageFactory; |
114 | $this->languageNameUtils = $languageNameUtils; |
115 | $this->contentLanguage = $contentLanguage; |
116 | $this->namespaceInfo = $namespaceInfo; |
117 | $this->interwikiLookup = $interwikiLookup; |
118 | $this->parserFactory = $parserFactory; |
119 | $this->magicWordFactory = $magicWordFactory; |
120 | $this->specialPageFactory = $specialPageFactory; |
121 | $this->skinFactory = $skinFactory; |
122 | $this->loadBalancer = $loadBalancer; |
123 | $this->readOnlyMode = $readOnlyMode; |
124 | $this->urlUtils = $urlUtils; |
125 | } |
126 | |
127 | public function execute() { |
128 | $params = $this->extractRequestParams(); |
129 | $done = []; |
130 | foreach ( $params['prop'] as $p ) { |
131 | switch ( $p ) { |
132 | case 'general': |
133 | $fit = $this->appendGeneralInfo( $p ); |
134 | break; |
135 | case 'namespaces': |
136 | $fit = $this->appendNamespaces( $p ); |
137 | break; |
138 | case 'namespacealiases': |
139 | $fit = $this->appendNamespaceAliases( $p ); |
140 | break; |
141 | case 'specialpagealiases': |
142 | $fit = $this->appendSpecialPageAliases( $p ); |
143 | break; |
144 | case 'magicwords': |
145 | $fit = $this->appendMagicWords( $p ); |
146 | break; |
147 | case 'interwikimap': |
148 | $fit = $this->appendInterwikiMap( $p, $params['filteriw'] ); |
149 | break; |
150 | case 'dbrepllag': |
151 | $fit = $this->appendDbReplLagInfo( $p, $params['showalldb'] ); |
152 | break; |
153 | case 'statistics': |
154 | $fit = $this->appendStatistics( $p ); |
155 | break; |
156 | case 'usergroups': |
157 | $fit = $this->appendUserGroups( $p, $params['numberingroup'] ); |
158 | break; |
159 | case 'autocreatetempuser': |
160 | $fit = $this->appendAutoCreateTempUser( $p ); |
161 | break; |
162 | case 'clientlibraries': |
163 | $fit = $this->appendInstalledClientLibraries( $p ); |
164 | break; |
165 | case 'libraries': |
166 | $fit = $this->appendInstalledLibraries( $p ); |
167 | break; |
168 | case 'extensions': |
169 | $fit = $this->appendExtensions( $p ); |
170 | break; |
171 | case 'fileextensions': |
172 | $fit = $this->appendFileExtensions( $p ); |
173 | break; |
174 | case 'rightsinfo': |
175 | $fit = $this->appendRightsInfo( $p ); |
176 | break; |
177 | case 'restrictions': |
178 | $fit = $this->appendRestrictions( $p ); |
179 | break; |
180 | case 'languages': |
181 | $fit = $this->appendLanguages( $p ); |
182 | break; |
183 | case 'languagevariants': |
184 | $fit = $this->appendLanguageVariants( $p ); |
185 | break; |
186 | case 'skins': |
187 | $fit = $this->appendSkins( $p ); |
188 | break; |
189 | case 'extensiontags': |
190 | $fit = $this->appendExtensionTags( $p ); |
191 | break; |
192 | case 'functionhooks': |
193 | $fit = $this->appendFunctionHooks( $p ); |
194 | break; |
195 | case 'showhooks': |
196 | $fit = $this->appendSubscribedHooks( $p ); |
197 | break; |
198 | case 'variables': |
199 | $fit = $this->appendVariables( $p ); |
200 | break; |
201 | case 'protocols': |
202 | $fit = $this->appendProtocols( $p ); |
203 | break; |
204 | case 'defaultoptions': |
205 | $fit = $this->appendDefaultOptions( $p ); |
206 | break; |
207 | case 'uploaddialog': |
208 | $fit = $this->appendUploadDialog( $p ); |
209 | break; |
210 | case 'autopromote': |
211 | $fit = $this->appendAutoPromote( $p ); |
212 | break; |
213 | case 'autopromoteonce': |
214 | $fit = $this->appendAutoPromoteOnce( $p ); |
215 | break; |
216 | default: |
217 | ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" ); // @codeCoverageIgnore |
218 | } |
219 | if ( !$fit ) { |
220 | // Abuse siprop as a query-continue parameter |
221 | // and set it to all unprocessed props |
222 | $this->setContinueEnumParameter( 'prop', implode( '|', |
223 | array_diff( $params['prop'], $done ) ) ); |
224 | break; |
225 | } |
226 | $done[] = $p; |
227 | } |
228 | } |
229 | |
230 | protected function appendGeneralInfo( $property ) { |
231 | $config = $this->getConfig(); |
232 | $mainPage = Title::newMainPage(); |
233 | $logo = SkinModule::getAvailableLogos( $config ); |
234 | |
235 | $data = [ |
236 | 'mainpage' => $mainPage->getPrefixedText(), |
237 | 'base' => (string)$this->urlUtils->expand( $mainPage->getFullURL(), PROTO_CURRENT ), |
238 | 'sitename' => $config->get( MainConfigNames::Sitename ), |
239 | 'mainpageisdomainroot' => (bool)$config->get( MainConfigNames::MainPageIsDomainRoot ), |
240 | |
241 | // A logo can either be a relative or an absolute path |
242 | // make sure we always return an absolute path |
243 | 'logo' => (string)$this->urlUtils->expand( $logo['1x'], PROTO_RELATIVE ), |
244 | |
245 | 'generator' => 'MediaWiki ' . MW_VERSION, |
246 | |
247 | 'phpversion' => PHP_VERSION, |
248 | 'phpsapi' => PHP_SAPI, |
249 | 'dbtype' => $config->get( MainConfigNames::DBtype ), |
250 | 'dbversion' => $this->getDB()->getServerVersion(), |
251 | ]; |
252 | |
253 | $allowFrom = [ '' ]; |
254 | $allowException = true; |
255 | if ( !$config->get( MainConfigNames::AllowExternalImages ) ) { |
256 | $data['imagewhitelistenabled'] = |
257 | (bool)$config->get( MainConfigNames::EnableImageWhitelist ); |
258 | $allowFrom = $config->get( MainConfigNames::AllowExternalImagesFrom ); |
259 | $allowException = (bool)$allowFrom; |
260 | } |
261 | if ( $allowException ) { |
262 | $data['externalimages'] = (array)$allowFrom; |
263 | ApiResult::setIndexedTagName( $data['externalimages'], 'prefix' ); |
264 | } |
265 | |
266 | $data['langconversion'] = !$this->languageConverterFactory->isConversionDisabled(); |
267 | $data['linkconversion'] = !$this->languageConverterFactory->isLinkConversionDisabled(); |
268 | // For backwards compatibility (soft deprecated since MW 1.36) |
269 | $data['titleconversion'] = $data['linkconversion']; |
270 | |
271 | $contLangConverter = $this->languageConverterFactory->getLanguageConverter( $this->contentLanguage ); |
272 | if ( $this->contentLanguage->linkPrefixExtension() ) { |
273 | $linkPrefixCharset = $this->contentLanguage->linkPrefixCharset(); |
274 | $data['linkprefixcharset'] = $linkPrefixCharset; |
275 | // For backwards compatibility |
276 | $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu"; |
277 | } else { |
278 | $data['linkprefixcharset'] = ''; |
279 | $data['linkprefix'] = ''; |
280 | } |
281 | |
282 | $data['linktrail'] = $this->contentLanguage->linkTrail() ?: ''; |
283 | |
284 | $data['legaltitlechars'] = Title::legalChars(); |
285 | $data['invalidusernamechars'] = $config->get( MainConfigNames::InvalidUsernameCharacters ); |
286 | |
287 | $data['allunicodefixes'] = (bool)$config->get( MainConfigNames::AllUnicodeFixes ); |
288 | $data['fixarabicunicode'] = true; // Config removed in 1.35, always true |
289 | $data['fixmalayalamunicode'] = true; // Config removed in 1.35, always true |
290 | |
291 | $git = GitInfo::repo()->getHeadSHA1(); |
292 | if ( $git ) { |
293 | $data['git-hash'] = $git; |
294 | $data['git-branch'] = GitInfo::repo()->getCurrentBranch(); |
295 | } |
296 | |
297 | // 'case-insensitive' option is reserved for future |
298 | $data['case'] = |
299 | $config->get( MainConfigNames::CapitalLinks ) ? 'first-letter' : 'case-sensitive'; |
300 | $data['lang'] = $config->get( MainConfigNames::LanguageCode ); |
301 | |
302 | $fallbacks = []; |
303 | foreach ( $this->contentLanguage->getFallbackLanguages() as $code ) { |
304 | $fallbacks[] = [ 'code' => $code ]; |
305 | } |
306 | $data['fallback'] = $fallbacks; |
307 | ApiResult::setIndexedTagName( $data['fallback'], 'lang' ); |
308 | |
309 | if ( $contLangConverter->hasVariants() ) { |
310 | $variants = []; |
311 | foreach ( $contLangConverter->getVariants() as $code ) { |
312 | $variants[] = [ |
313 | 'code' => $code, |
314 | 'name' => $this->contentLanguage->getVariantname( $code ), |
315 | ]; |
316 | } |
317 | $data['variants'] = $variants; |
318 | ApiResult::setIndexedTagName( $data['variants'], 'lang' ); |
319 | } |
320 | |
321 | $data['rtl'] = $this->contentLanguage->isRTL(); |
322 | $data['fallback8bitEncoding'] = $this->contentLanguage->fallback8bitEncoding(); |
323 | |
324 | $data['readonly'] = $this->readOnlyMode->isReadOnly(); |
325 | if ( $data['readonly'] ) { |
326 | $data['readonlyreason'] = $this->readOnlyMode->getReason(); |
327 | } |
328 | $data['writeapi'] = true; // Deprecated since MW 1.32 |
329 | |
330 | $data['maxarticlesize'] = $config->get( MainConfigNames::MaxArticleSize ) * 1024; |
331 | |
332 | $data['timezone'] = $config->get( MainConfigNames::Localtimezone ); |
333 | $data['timeoffset'] = (int)( $config->get( MainConfigNames::LocalTZoffset ) ); |
334 | $data['articlepath'] = $config->get( MainConfigNames::ArticlePath ); |
335 | $data['scriptpath'] = $config->get( MainConfigNames::ScriptPath ); |
336 | $data['script'] = $config->get( MainConfigNames::Script ); |
337 | $data['variantarticlepath'] = $config->get( MainConfigNames::VariantArticlePath ); |
338 | $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath'; |
339 | $data['server'] = $config->get( MainConfigNames::Server ); |
340 | $data['servername'] = $config->get( MainConfigNames::ServerName ); |
341 | $data['wikiid'] = WikiMap::getCurrentWikiId(); |
342 | $data['time'] = wfTimestamp( TS_ISO_8601, time() ); |
343 | |
344 | $data['misermode'] = (bool)$config->get( MainConfigNames::MiserMode ); |
345 | |
346 | $data['uploadsenabled'] = UploadBase::isEnabled(); |
347 | $data['maxuploadsize'] = UploadBase::getMaxUploadSize(); |
348 | $data['minuploadchunksize'] = ApiUpload::getMinUploadChunkSize( $config ); |
349 | |
350 | $data['galleryoptions'] = $config->get( MainConfigNames::GalleryOptions ); |
351 | |
352 | $data['thumblimits'] = $config->get( MainConfigNames::ThumbLimits ); |
353 | ApiResult::setArrayType( $data['thumblimits'], 'BCassoc' ); |
354 | ApiResult::setIndexedTagName( $data['thumblimits'], 'limit' ); |
355 | $data['imagelimits'] = []; |
356 | ApiResult::setArrayType( $data['imagelimits'], 'BCassoc' ); |
357 | ApiResult::setIndexedTagName( $data['imagelimits'], 'limit' ); |
358 | foreach ( $config->get( MainConfigNames::ImageLimits ) as $k => $limit ) { |
359 | $data['imagelimits'][$k] = [ 'width' => $limit[0], 'height' => $limit[1] ]; |
360 | } |
361 | |
362 | $favicon = $config->get( MainConfigNames::Favicon ); |
363 | if ( $favicon ) { |
364 | // Expand any local path to full URL to improve API usability (T77093). |
365 | $data['favicon'] = (string)$this->urlUtils->expand( $favicon ); |
366 | } |
367 | |
368 | $data['centralidlookupprovider'] = $config->get( MainConfigNames::CentralIdLookupProvider ); |
369 | $providerIds = array_keys( $config->get( MainConfigNames::CentralIdLookupProviders ) ); |
370 | $data['allcentralidlookupproviders'] = $providerIds; |
371 | |
372 | $data['interwikimagic'] = (bool)$config->get( MainConfigNames::InterwikiMagic ); |
373 | $data['magiclinks'] = $config->get( MainConfigNames::EnableMagicLinks ); |
374 | |
375 | $data['categorycollation'] = $config->get( MainConfigNames::CategoryCollation ); |
376 | |
377 | $data['nofollowlinks'] = $config->get( MainConfigNames::NoFollowLinks ); |
378 | $data['nofollownsexceptions'] = $config->get( MainConfigNames::NoFollowNsExceptions ); |
379 | $data['nofollowdomainexceptions'] = $config->get( MainConfigNames::NoFollowDomainExceptions ); |
380 | $data['externallinktarget'] = $config->get( MainConfigNames::ExternalLinkTarget ); |
381 | |
382 | $this->getHookRunner()->onAPIQuerySiteInfoGeneralInfo( $this, $data ); |
383 | |
384 | return $this->getResult()->addValue( 'query', $property, $data ); |
385 | } |
386 | |
387 | protected function appendNamespaces( $property ) { |
388 | $nsProtection = $this->getConfig()->get( MainConfigNames::NamespaceProtection ); |
389 | |
390 | $data = [ ApiResult::META_TYPE => 'assoc' ]; |
391 | foreach ( $this->contentLanguage->getFormattedNamespaces() as $ns => $title ) { |
392 | $data[$ns] = [ |
393 | 'id' => (int)$ns, |
394 | 'case' => $this->namespaceInfo->isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive', |
395 | ]; |
396 | ApiResult::setContentValue( $data[$ns], 'name', $title ); |
397 | $canonical = $this->namespaceInfo->getCanonicalName( $ns ); |
398 | |
399 | $data[$ns]['subpages'] = $this->namespaceInfo->hasSubpages( $ns ); |
400 | |
401 | if ( $canonical ) { |
402 | $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' ); |
403 | } |
404 | |
405 | $data[$ns]['content'] = $this->namespaceInfo->isContent( $ns ); |
406 | $data[$ns]['nonincludable'] = $this->namespaceInfo->isNonincludable( $ns ); |
407 | |
408 | $specificNs = $nsProtection[$ns] ?? ''; |
409 | if ( is_array( $specificNs ) ) { |
410 | $specificNs = implode( "|", array_filter( $specificNs ) ); |
411 | } |
412 | if ( $specificNs !== '' ) { |
413 | $data[$ns]['namespaceprotection'] = $specificNs; |
414 | } |
415 | |
416 | $contentmodel = $this->namespaceInfo->getNamespaceContentModel( $ns ); |
417 | if ( $contentmodel ) { |
418 | $data[$ns]['defaultcontentmodel'] = $contentmodel; |
419 | } |
420 | } |
421 | |
422 | ApiResult::setArrayType( $data, 'assoc' ); |
423 | ApiResult::setIndexedTagName( $data, 'ns' ); |
424 | |
425 | return $this->getResult()->addValue( 'query', $property, $data ); |
426 | } |
427 | |
428 | protected function appendNamespaceAliases( $property ) { |
429 | $aliases = $this->contentLanguage->getNamespaceAliases(); |
430 | $namespaces = $this->contentLanguage->getNamespaces(); |
431 | $data = []; |
432 | foreach ( $aliases as $title => $ns ) { |
433 | if ( $namespaces[$ns] == $title ) { |
434 | // Don't list duplicates |
435 | continue; |
436 | } |
437 | $item = [ 'id' => (int)$ns ]; |
438 | ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) ); |
439 | $data[] = $item; |
440 | } |
441 | |
442 | sort( $data ); |
443 | |
444 | ApiResult::setIndexedTagName( $data, 'ns' ); |
445 | |
446 | return $this->getResult()->addValue( 'query', $property, $data ); |
447 | } |
448 | |
449 | protected function appendSpecialPageAliases( $property ) { |
450 | $data = []; |
451 | $aliases = $this->contentLanguage->getSpecialPageAliases(); |
452 | foreach ( $this->specialPageFactory->getNames() as $specialpage ) { |
453 | if ( isset( $aliases[$specialpage] ) ) { |
454 | $arr = [ 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] ]; |
455 | ApiResult::setIndexedTagName( $arr['aliases'], 'alias' ); |
456 | $data[] = $arr; |
457 | } |
458 | } |
459 | ApiResult::setIndexedTagName( $data, 'specialpage' ); |
460 | |
461 | return $this->getResult()->addValue( 'query', $property, $data ); |
462 | } |
463 | |
464 | protected function appendMagicWords( $property ) { |
465 | $data = []; |
466 | foreach ( $this->contentLanguage->getMagicWords() as $name => $aliases ) { |
467 | $caseSensitive = (bool)array_shift( $aliases ); |
468 | $arr = [ |
469 | 'name' => $name, |
470 | 'aliases' => $aliases, |
471 | 'case-sensitive' => $caseSensitive, |
472 | ]; |
473 | ApiResult::setIndexedTagName( $arr['aliases'], 'alias' ); |
474 | $data[] = $arr; |
475 | } |
476 | ApiResult::setIndexedTagName( $data, 'magicword' ); |
477 | |
478 | return $this->getResult()->addValue( 'query', $property, $data ); |
479 | } |
480 | |
481 | protected function appendInterwikiMap( $property, $filter ) { |
482 | $local = $filter ? $filter === 'local' : null; |
483 | |
484 | $params = $this->extractRequestParams(); |
485 | $langCode = $params['inlanguagecode'] ?? ''; |
486 | $interwikiMagic = $this->getConfig()->get( MainConfigNames::InterwikiMagic ); |
487 | |
488 | if ( $interwikiMagic ) { |
489 | $langNames = $this->languageNameUtils->getLanguageNames( $langCode ); |
490 | } |
491 | |
492 | $extraLangPrefixes = $this->getConfig()->get( MainConfigNames::ExtraInterlanguageLinkPrefixes ); |
493 | $extraLangCodeMap = $this->getConfig()->get( MainConfigNames::InterlanguageLinkCodeMap ); |
494 | $localInterwikis = $this->getConfig()->get( MainConfigNames::LocalInterwikis ); |
495 | $data = []; |
496 | |
497 | foreach ( $this->interwikiLookup->getAllPrefixes( $local ) as $row ) { |
498 | $prefix = $row['iw_prefix']; |
499 | $val = []; |
500 | $val['prefix'] = $prefix; |
501 | if ( $row['iw_local'] ?? false ) { |
502 | $val['local'] = true; |
503 | } |
504 | if ( $row['iw_trans'] ?? false ) { |
505 | $val['trans'] = true; |
506 | } |
507 | |
508 | if ( $interwikiMagic && isset( $langNames[$prefix] ) ) { |
509 | $val['language'] = $langNames[$prefix]; |
510 | $standard = LanguageCode::replaceDeprecatedCodes( $prefix ); |
511 | if ( $standard !== $prefix ) { |
512 | # Note that even if this code is deprecated, it should |
513 | # only be remapped if extralanglink (set below) is false. |
514 | $val['deprecated'] = $standard; |
515 | } |
516 | $val['bcp47'] = LanguageCode::bcp47( $standard ); |
517 | } |
518 | if ( in_array( $prefix, $localInterwikis ) ) { |
519 | $val['localinterwiki'] = true; |
520 | } |
521 | if ( $interwikiMagic && in_array( $prefix, $extraLangPrefixes ) ) { |
522 | $val['extralanglink'] = true; |
523 | $val['code'] = $extraLangCodeMap[$prefix] ?? $prefix; |
524 | $val['bcp47'] = LanguageCode::bcp47( $val['code'] ); |
525 | |
526 | $linktext = $this->msg( "interlanguage-link-$prefix" ); |
527 | if ( !$linktext->isDisabled() ) { |
528 | $val['linktext'] = $linktext->text(); |
529 | } |
530 | |
531 | $sitename = $this->msg( "interlanguage-link-sitename-$prefix" ); |
532 | if ( !$sitename->isDisabled() ) { |
533 | $val['sitename'] = $sitename->text(); |
534 | } |
535 | } |
536 | |
537 | $val['url'] = (string)$this->urlUtils->expand( $row['iw_url'], PROTO_CURRENT ); |
538 | $val['protorel'] = str_starts_with( $row['iw_url'], '//' ); |
539 | if ( ( $row['iw_wikiid'] ?? '' ) !== '' ) { |
540 | $val['wikiid'] = $row['iw_wikiid']; |
541 | } |
542 | if ( ( $row['iw_api'] ?? '' ) !== '' ) { |
543 | $val['api'] = $row['iw_api']; |
544 | } |
545 | |
546 | $data[] = $val; |
547 | } |
548 | |
549 | ApiResult::setIndexedTagName( $data, 'iw' ); |
550 | |
551 | return $this->getResult()->addValue( 'query', $property, $data ); |
552 | } |
553 | |
554 | protected function appendDbReplLagInfo( $property, $includeAll ) { |
555 | $data = []; |
556 | $showHostnames = $this->getConfig()->get( MainConfigNames::ShowHostnames ); |
557 | if ( $includeAll ) { |
558 | if ( !$showHostnames ) { |
559 | $this->dieWithError( 'apierror-siteinfo-includealldenied', 'includeAllDenied' ); |
560 | } |
561 | |
562 | foreach ( $this->loadBalancer->getLagTimes() as $i => $lag ) { |
563 | $data[] = [ |
564 | 'host' => $this->loadBalancer->getServerName( $i ), |
565 | 'lag' => $lag |
566 | ]; |
567 | } |
568 | } else { |
569 | [ , $lag, $index ] = $this->loadBalancer->getMaxLag(); |
570 | $data[] = [ |
571 | 'host' => $showHostnames ? $this->loadBalancer->getServerName( $index ) : '', |
572 | 'lag' => $lag |
573 | ]; |
574 | } |
575 | |
576 | ApiResult::setIndexedTagName( $data, 'db' ); |
577 | |
578 | return $this->getResult()->addValue( 'query', $property, $data ); |
579 | } |
580 | |
581 | protected function appendStatistics( $property ) { |
582 | $data = [ |
583 | 'pages' => SiteStats::pages(), |
584 | 'articles' => SiteStats::articles(), |
585 | 'edits' => SiteStats::edits(), |
586 | 'images' => SiteStats::images(), |
587 | 'users' => SiteStats::users(), |
588 | 'activeusers' => SiteStats::activeUsers(), |
589 | 'admins' => SiteStats::numberingroup( 'sysop' ), |
590 | 'jobs' => SiteStats::jobs(), |
591 | ]; |
592 | |
593 | $this->getHookRunner()->onAPIQuerySiteInfoStatisticsInfo( $data ); |
594 | |
595 | return $this->getResult()->addValue( 'query', $property, $data ); |
596 | } |
597 | |
598 | protected function appendUserGroups( $property, $numberInGroup ) { |
599 | $config = $this->getConfig(); |
600 | |
601 | $data = []; |
602 | $result = $this->getResult(); |
603 | $allGroups = array_values( $this->userGroupManager->listAllGroups() ); |
604 | foreach ( $config->get( MainConfigNames::GroupPermissions ) as $group => $permissions ) { |
605 | $arr = [ |
606 | 'name' => $group, |
607 | 'rights' => array_keys( $permissions, true ), |
608 | ]; |
609 | |
610 | if ( $numberInGroup ) { |
611 | $autopromote = $config->get( MainConfigNames::Autopromote ); |
612 | |
613 | if ( $group == 'user' ) { |
614 | $arr['number'] = SiteStats::users(); |
615 | // '*' and autopromote groups have no size |
616 | } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) { |
617 | $arr['number'] = SiteStats::numberingroup( $group ); |
618 | } |
619 | } |
620 | |
621 | $groupArr = [ |
622 | 'add' => $config->get( MainConfigNames::AddGroups ), |
623 | 'remove' => $config->get( MainConfigNames::RemoveGroups ), |
624 | 'add-self' => $config->get( MainConfigNames::GroupsAddToSelf ), |
625 | 'remove-self' => $config->get( MainConfigNames::GroupsRemoveFromSelf ) |
626 | ]; |
627 | |
628 | foreach ( $groupArr as $type => $rights ) { |
629 | if ( isset( $rights[$group] ) ) { |
630 | if ( $rights[$group] === true ) { |
631 | $groups = $allGroups; |
632 | } else { |
633 | $groups = array_intersect( $rights[$group], $allGroups ); |
634 | } |
635 | if ( $groups ) { |
636 | $arr[$type] = $groups; |
637 | ApiResult::setArrayType( $arr[$type], 'BCarray' ); |
638 | ApiResult::setIndexedTagName( $arr[$type], 'group' ); |
639 | } |
640 | } |
641 | } |
642 | |
643 | ApiResult::setIndexedTagName( $arr['rights'], 'permission' ); |
644 | $data[] = $arr; |
645 | } |
646 | |
647 | ApiResult::setIndexedTagName( $data, 'group' ); |
648 | |
649 | return $result->addValue( 'query', $property, $data ); |
650 | } |
651 | |
652 | protected function appendAutoCreateTempUser( $property ) { |
653 | $config = $this->getConfig()->get( MainConfigNames::AutoCreateTempUser ); |
654 | |
655 | $data = [ 'enabled' => false ]; |
656 | if ( $config['enabled'] ?? false ) { |
657 | $data['enabled'] = true; |
658 | $data['actions'] = $config['actions']; |
659 | $data['genPattern'] = $config['genPattern']; |
660 | $data['matchPattern'] = $config['matchPattern'] ?? $data['genPattern']; |
661 | $data['serialProvider'] = $config['serialProvider']; |
662 | $data['serialMapping'] = $config['serialMapping']; |
663 | } |
664 | if ( isset( $config['reservedPattern'] ) ) { |
665 | $data['reservedPattern'] = $config['reservedPattern']; |
666 | } |
667 | |
668 | return $this->getResult()->addValue( 'query', $property, $data ); |
669 | } |
670 | |
671 | protected function appendFileExtensions( $property ) { |
672 | $data = []; |
673 | foreach ( |
674 | array_unique( $this->getConfig()->get( MainConfigNames::FileExtensions ) ) as $ext |
675 | ) { |
676 | $data[] = [ 'ext' => $ext ]; |
677 | } |
678 | ApiResult::setIndexedTagName( $data, 'fe' ); |
679 | |
680 | return $this->getResult()->addValue( 'query', $property, $data ); |
681 | } |
682 | |
683 | protected function appendInstalledClientLibraries( $property ) { |
684 | $data = []; |
685 | foreach ( SpecialVersion::parseForeignResources() as $name => $info ) { |
686 | $data[] = [ |
687 | // Can't use $name as it is version suffixed (as multiple versions |
688 | // of a library may exist, provided by different skins/extensions) |
689 | 'name' => $info['name'], |
690 | 'version' => $info['version'], |
691 | ]; |
692 | } |
693 | ApiResult::setIndexedTagName( $data, 'library' ); |
694 | return $this->getResult()->addValue( 'query', $property, $data ); |
695 | } |
696 | |
697 | protected function appendInstalledLibraries( $property ) { |
698 | $path = MW_INSTALL_PATH . '/vendor/composer/installed.json'; |
699 | if ( !file_exists( $path ) ) { |
700 | return true; |
701 | } |
702 | |
703 | $data = []; |
704 | $installed = new ComposerInstalled( $path ); |
705 | foreach ( $installed->getInstalledDependencies() as $name => $info ) { |
706 | if ( str_starts_with( $info['type'], 'mediawiki-' ) ) { |
707 | // Skip any extensions or skins since they'll be listed |
708 | // in their proper section |
709 | continue; |
710 | } |
711 | $data[] = [ |
712 | 'name' => $name, |
713 | 'version' => $info['version'], |
714 | ]; |
715 | } |
716 | ApiResult::setIndexedTagName( $data, 'library' ); |
717 | |
718 | return $this->getResult()->addValue( 'query', $property, $data ); |
719 | } |
720 | |
721 | protected function appendExtensions( $property ) { |
722 | $data = []; |
723 | $credits = SpecialVersion::getCredits( |
724 | ExtensionRegistry::getInstance(), |
725 | $this->getConfig() |
726 | ); |
727 | foreach ( $credits as $type => $extensions ) { |
728 | foreach ( $extensions as $ext ) { |
729 | $ret = [ 'type' => $type ]; |
730 | if ( isset( $ext['name'] ) ) { |
731 | $ret['name'] = $ext['name']; |
732 | } |
733 | if ( isset( $ext['namemsg'] ) ) { |
734 | $ret['namemsg'] = $ext['namemsg']; |
735 | } |
736 | if ( isset( $ext['description'] ) ) { |
737 | $ret['description'] = $ext['description']; |
738 | } |
739 | if ( isset( $ext['descriptionmsg'] ) ) { |
740 | // Can be a string or [ key, param1, param2, ... ] |
741 | if ( is_array( $ext['descriptionmsg'] ) ) { |
742 | $ret['descriptionmsg'] = $ext['descriptionmsg'][0]; |
743 | $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 ); |
744 | ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' ); |
745 | } else { |
746 | $ret['descriptionmsg'] = $ext['descriptionmsg']; |
747 | } |
748 | } |
749 | if ( isset( $ext['author'] ) ) { |
750 | $ret['author'] = is_array( $ext['author'] ) ? |
751 | implode( ', ', $ext['author'] ) : $ext['author']; |
752 | } |
753 | if ( isset( $ext['url'] ) ) { |
754 | $ret['url'] = $ext['url']; |
755 | } |
756 | if ( isset( $ext['version'] ) ) { |
757 | $ret['version'] = $ext['version']; |
758 | } |
759 | if ( isset( $ext['path'] ) ) { |
760 | $extensionPath = dirname( $ext['path'] ); |
761 | $gitInfo = new GitInfo( $extensionPath ); |
762 | $vcsVersion = $gitInfo->getHeadSHA1(); |
763 | if ( $vcsVersion !== false ) { |
764 | $ret['vcs-system'] = 'git'; |
765 | $ret['vcs-version'] = $vcsVersion; |
766 | $ret['vcs-url'] = $gitInfo->getHeadViewUrl(); |
767 | $vcsDate = $gitInfo->getHeadCommitDate(); |
768 | if ( $vcsDate !== false ) { |
769 | $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate ); |
770 | } |
771 | } |
772 | |
773 | if ( ExtensionInfo::getLicenseFileNames( $extensionPath ) ) { |
774 | $ret['license-name'] = $ext['license-name'] ?? ''; |
775 | $ret['license'] = SpecialPage::getTitleFor( |
776 | 'Version', |
777 | "License/{$ext['name']}" |
778 | )->getLinkURL(); |
779 | } |
780 | |
781 | if ( ExtensionInfo::getAuthorsFileName( $extensionPath ) ) { |
782 | $ret['credits'] = SpecialPage::getTitleFor( |
783 | 'Version', |
784 | "Credits/{$ext['name']}" |
785 | )->getLinkURL(); |
786 | } |
787 | } |
788 | $data[] = $ret; |
789 | } |
790 | } |
791 | |
792 | ApiResult::setIndexedTagName( $data, 'ext' ); |
793 | |
794 | return $this->getResult()->addValue( 'query', $property, $data ); |
795 | } |
796 | |
797 | protected function appendRightsInfo( $property ) { |
798 | $config = $this->getConfig(); |
799 | $title = Title::newFromText( $config->get( MainConfigNames::RightsPage ) ); |
800 | if ( $title ) { |
801 | $url = $this->urlUtils->expand( $title->getLinkURL(), PROTO_CURRENT ); |
802 | } else { |
803 | $url = $config->get( MainConfigNames::RightsUrl ); |
804 | } |
805 | $text = $config->get( MainConfigNames::RightsText ) ?? ''; |
806 | if ( $text === '' && $title ) { |
807 | $text = $title->getPrefixedText(); |
808 | } |
809 | |
810 | $data = [ |
811 | 'url' => (string)$url, |
812 | 'text' => (string)$text, |
813 | ]; |
814 | |
815 | return $this->getResult()->addValue( 'query', $property, $data ); |
816 | } |
817 | |
818 | protected function appendRestrictions( $property ) { |
819 | $config = $this->getConfig(); |
820 | $data = [ |
821 | 'types' => $config->get( MainConfigNames::RestrictionTypes ), |
822 | 'levels' => $config->get( MainConfigNames::RestrictionLevels ), |
823 | 'cascadinglevels' => $config->get( MainConfigNames::CascadingRestrictionLevels ), |
824 | 'semiprotectedlevels' => $config->get( MainConfigNames::SemiprotectedRestrictionLevels ), |
825 | ]; |
826 | |
827 | ApiResult::setArrayType( $data['types'], 'BCarray' ); |
828 | ApiResult::setArrayType( $data['levels'], 'BCarray' ); |
829 | ApiResult::setArrayType( $data['cascadinglevels'], 'BCarray' ); |
830 | ApiResult::setArrayType( $data['semiprotectedlevels'], 'BCarray' ); |
831 | |
832 | ApiResult::setIndexedTagName( $data['types'], 'type' ); |
833 | ApiResult::setIndexedTagName( $data['levels'], 'level' ); |
834 | ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' ); |
835 | ApiResult::setIndexedTagName( $data['semiprotectedlevels'], 'level' ); |
836 | |
837 | return $this->getResult()->addValue( 'query', $property, $data ); |
838 | } |
839 | |
840 | public function appendLanguages( $property ) { |
841 | $params = $this->extractRequestParams(); |
842 | $langCode = $params['inlanguagecode'] ?? ''; |
843 | $langNames = $this->languageNameUtils->getLanguageNames( $langCode ); |
844 | |
845 | $data = []; |
846 | |
847 | foreach ( $langNames as $code => $name ) { |
848 | $lang = [ |
849 | 'code' => $code, |
850 | 'bcp47' => LanguageCode::bcp47( $code ), |
851 | ]; |
852 | ApiResult::setContentValue( $lang, 'name', $name ); |
853 | $data[] = $lang; |
854 | } |
855 | ApiResult::setIndexedTagName( $data, 'lang' ); |
856 | |
857 | return $this->getResult()->addValue( 'query', $property, $data ); |
858 | } |
859 | |
860 | // Export information about which page languages will trigger |
861 | // language conversion. (T153341) |
862 | public function appendLanguageVariants( $property ) { |
863 | $langNames = $this->languageConverterFactory->isConversionDisabled() ? [] : |
864 | LanguageConverter::$languagesWithVariants; |
865 | sort( $langNames ); |
866 | |
867 | $data = []; |
868 | foreach ( $langNames as $langCode ) { |
869 | $lang = $this->languageFactory->getLanguage( $langCode ); |
870 | $langConverter = $this->languageConverterFactory->getLanguageConverter( $lang ); |
871 | if ( !$langConverter->hasVariants() ) { |
872 | // Only languages which have variants should be listed |
873 | continue; |
874 | } |
875 | $data[$langCode] = []; |
876 | ApiResult::setIndexedTagName( $data[$langCode], 'variant' ); |
877 | ApiResult::setArrayType( $data[$langCode], 'kvp', 'code' ); |
878 | |
879 | $variants = $langConverter->getVariants(); |
880 | sort( $variants ); |
881 | foreach ( $variants as $v ) { |
882 | $data[$langCode][$v] = [ |
883 | 'fallbacks' => (array)$langConverter->getVariantFallbacks( $v ), |
884 | ]; |
885 | ApiResult::setIndexedTagName( |
886 | $data[$langCode][$v]['fallbacks'], 'variant' |
887 | ); |
888 | } |
889 | } |
890 | ApiResult::setIndexedTagName( $data, 'lang' ); |
891 | ApiResult::setArrayType( $data, 'kvp', 'code' ); |
892 | |
893 | return $this->getResult()->addValue( 'query', $property, $data ); |
894 | } |
895 | |
896 | public function appendSkins( $property ) { |
897 | $data = []; |
898 | $allowed = $this->skinFactory->getAllowedSkins(); |
899 | $default = Skin::normalizeKey( 'default' ); |
900 | |
901 | foreach ( $this->skinFactory->getInstalledSkins() as $name => $displayName ) { |
902 | $msg = $this->msg( "skinname-{$name}" ); |
903 | $code = $this->getParameter( 'inlanguagecode' ); |
904 | if ( $code && $this->languageNameUtils->isValidCode( $code ) ) { |
905 | $msg->inLanguage( $code ); |
906 | } else { |
907 | $msg->inContentLanguage(); |
908 | } |
909 | if ( $msg->exists() ) { |
910 | $displayName = $msg->text(); |
911 | } |
912 | $skin = [ 'code' => $name ]; |
913 | ApiResult::setContentValue( $skin, 'name', $displayName ); |
914 | if ( !isset( $allowed[$name] ) ) { |
915 | $skin['unusable'] = true; |
916 | } |
917 | if ( $name === $default ) { |
918 | $skin['default'] = true; |
919 | } |
920 | $data[] = $skin; |
921 | } |
922 | ApiResult::setIndexedTagName( $data, 'skin' ); |
923 | |
924 | return $this->getResult()->addValue( 'query', $property, $data ); |
925 | } |
926 | |
927 | public function appendExtensionTags( $property ) { |
928 | $tags = array_map( |
929 | static function ( $item ) { |
930 | return "<$item>"; |
931 | }, |
932 | $this->parserFactory->getMainInstance()->getTags() |
933 | ); |
934 | ApiResult::setArrayType( $tags, 'BCarray' ); |
935 | ApiResult::setIndexedTagName( $tags, 't' ); |
936 | |
937 | return $this->getResult()->addValue( 'query', $property, $tags ); |
938 | } |
939 | |
940 | public function appendFunctionHooks( $property ) { |
941 | $hooks = $this->parserFactory->getMainInstance()->getFunctionHooks(); |
942 | ApiResult::setArrayType( $hooks, 'BCarray' ); |
943 | ApiResult::setIndexedTagName( $hooks, 'h' ); |
944 | |
945 | return $this->getResult()->addValue( 'query', $property, $hooks ); |
946 | } |
947 | |
948 | public function appendVariables( $property ) { |
949 | $variables = $this->magicWordFactory->getVariableIDs(); |
950 | ApiResult::setArrayType( $variables, 'BCarray' ); |
951 | ApiResult::setIndexedTagName( $variables, 'v' ); |
952 | |
953 | return $this->getResult()->addValue( 'query', $property, $variables ); |
954 | } |
955 | |
956 | public function appendProtocols( $property ) { |
957 | // Make a copy of the global so we don't try to set the _element key of it - T47130 |
958 | $protocols = array_values( $this->getConfig()->get( MainConfigNames::UrlProtocols ) ); |
959 | ApiResult::setArrayType( $protocols, 'BCarray' ); |
960 | ApiResult::setIndexedTagName( $protocols, 'p' ); |
961 | |
962 | return $this->getResult()->addValue( 'query', $property, $protocols ); |
963 | } |
964 | |
965 | public function appendDefaultOptions( $property ) { |
966 | $options = $this->userOptionsLookup->getDefaultOptions( null ); |
967 | $options[ApiResult::META_BC_BOOLS] = array_keys( $options ); |
968 | return $this->getResult()->addValue( 'query', $property, $options ); |
969 | } |
970 | |
971 | public function appendUploadDialog( $property ) { |
972 | $config = $this->getConfig()->get( MainConfigNames::UploadDialog ); |
973 | return $this->getResult()->addValue( 'query', $property, $config ); |
974 | } |
975 | |
976 | private function getAutoPromoteConds() { |
977 | $allowedConditions = []; |
978 | foreach ( get_defined_constants() as $constantName => $constantValue ) { |
979 | if ( strpos( $constantName, 'APCOND_' ) !== false ) { |
980 | $allowedConditions[$constantName] = $constantValue; |
981 | } |
982 | } |
983 | return $allowedConditions; |
984 | } |
985 | |
986 | private function processAutoPromote( $input, $allowedConditions ) { |
987 | $data = []; |
988 | foreach ( $input as $groupName => $conditions ) { |
989 | $row = $this->recAutopromote( $conditions, $allowedConditions ); |
990 | if ( !isset( $row[0] ) || is_string( $row ) ) { |
991 | $row = [ $row ]; |
992 | } |
993 | $data[$groupName] = $row; |
994 | } |
995 | return $data; |
996 | } |
997 | |
998 | private function appendAutoPromote( $property ) { |
999 | return $this->getResult()->addValue( |
1000 | 'query', |
1001 | $property, |
1002 | $this->processAutoPromote( |
1003 | $this->getConfig()->get( 'Autopromote' ), |
1004 | $this->getAutoPromoteConds() |
1005 | ) |
1006 | ); |
1007 | } |
1008 | |
1009 | private function appendAutoPromoteOnce( $property ) { |
1010 | $allowedConditions = $this->getAutoPromoteConds(); |
1011 | $data = []; |
1012 | foreach ( $this->getConfig()->get( 'AutopromoteOnce' ) as $key => $value ) { |
1013 | $data[$key] = $this->processAutoPromote( $value, $allowedConditions ); |
1014 | } |
1015 | return $this->getResult()->addValue( 'query', $property, $data ); |
1016 | } |
1017 | |
1018 | /** |
1019 | * @param array|int|string $cond |
1020 | * @param array $allowedConditions |
1021 | * @return array|string |
1022 | */ |
1023 | private function recAutopromote( $cond, $allowedConditions ) { |
1024 | $config = []; |
1025 | // First, checks if $cond is an array |
1026 | if ( is_array( $cond ) ) { |
1027 | // Checks if $cond[0] is a valid operand |
1028 | if ( in_array( $cond[0], UserGroupManager::VALID_OPS, true ) ) { |
1029 | $config['operand'] = $cond[0]; |
1030 | // Traversal checks conditions |
1031 | foreach ( array_slice( $cond, 1 ) as $value ) { |
1032 | $config[] = $this->recAutopromote( $value, $allowedConditions ); |
1033 | } |
1034 | } elseif ( is_string( $cond[0] ) ) { |
1035 | // Returns $cond directly, if $cond[0] is a string |
1036 | $config = $cond; |
1037 | } else { |
1038 | // When $cond is equal to an APCOND_ constant value |
1039 | $params = array_slice( $cond, 1 ); |
1040 | if ( $params === [ null ] ) { |
1041 | // Special casing for these conditions and their default of null, |
1042 | // to replace their values with $wgAutoConfirmCount/$wgAutoConfirmAge as appropriate |
1043 | if ( $cond[0] === APCOND_EDITCOUNT ) { |
1044 | $params = [ $this->getConfig()->get( MainConfigNames::AutoConfirmCount ) ]; |
1045 | } elseif ( $cond[0] === APCOND_AGE ) { |
1046 | $params = [ $this->getConfig()->get( MainConfigNames::AutoConfirmAge ) ]; |
1047 | } |
1048 | } |
1049 | $config = [ |
1050 | 'condname' => array_search( $cond[0], $allowedConditions ), |
1051 | 'params' => $params |
1052 | ]; |
1053 | ApiResult::setIndexedTagName( $config, 'params' ); |
1054 | } |
1055 | } elseif ( is_string( $cond ) ) { |
1056 | $config = $cond; |
1057 | } else { |
1058 | // When $cond is equal to an APCOND_ constant value |
1059 | $config = [ |
1060 | 'condname' => array_search( $cond, $allowedConditions ), |
1061 | 'params' => [] |
1062 | ]; |
1063 | ApiResult::setIndexedTagName( $config, 'params' ); |
1064 | } |
1065 | |
1066 | return $config; |
1067 | } |
1068 | |
1069 | public function appendSubscribedHooks( $property ) { |
1070 | $hookContainer = MediaWikiServices::getInstance()->getHookContainer(); |
1071 | $hookNames = $hookContainer->getHookNames(); |
1072 | sort( $hookNames ); |
1073 | |
1074 | $data = []; |
1075 | foreach ( $hookNames as $name ) { |
1076 | $arr = [ |
1077 | 'name' => $name, |
1078 | 'subscribers' => $hookContainer->getHandlerDescriptions( $name ), |
1079 | ]; |
1080 | |
1081 | ApiResult::setArrayType( $arr['subscribers'], 'array' ); |
1082 | ApiResult::setIndexedTagName( $arr['subscribers'], 's' ); |
1083 | $data[] = $arr; |
1084 | } |
1085 | |
1086 | ApiResult::setIndexedTagName( $data, 'hook' ); |
1087 | |
1088 | return $this->getResult()->addValue( 'query', $property, $data ); |
1089 | } |
1090 | |
1091 | public function getCacheMode( $params ) { |
1092 | // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language |
1093 | if ( $this->getConfig()->get( MainConfigNames::ExtraInterlanguageLinkPrefixes ) && |
1094 | in_array( 'interwikimap', $params['prop'] ?? [] ) |
1095 | ) { |
1096 | return 'anon-public-user-private'; |
1097 | } |
1098 | |
1099 | return 'public'; |
1100 | } |
1101 | |
1102 | public function getAllowedParams() { |
1103 | return [ |
1104 | 'prop' => [ |
1105 | ParamValidator::PARAM_DEFAULT => 'general', |
1106 | ParamValidator::PARAM_ISMULTI => true, |
1107 | ParamValidator::PARAM_TYPE => [ |
1108 | 'general', |
1109 | 'namespaces', |
1110 | 'namespacealiases', |
1111 | 'specialpagealiases', |
1112 | 'magicwords', |
1113 | 'interwikimap', |
1114 | 'dbrepllag', |
1115 | 'statistics', |
1116 | 'usergroups', |
1117 | 'autocreatetempuser', |
1118 | 'clientlibraries', |
1119 | 'libraries', |
1120 | 'extensions', |
1121 | 'fileextensions', |
1122 | 'rightsinfo', |
1123 | 'restrictions', |
1124 | 'languages', |
1125 | 'languagevariants', |
1126 | 'skins', |
1127 | 'extensiontags', |
1128 | 'functionhooks', |
1129 | 'showhooks', |
1130 | 'variables', |
1131 | 'protocols', |
1132 | 'defaultoptions', |
1133 | 'uploaddialog', |
1134 | 'autopromote', |
1135 | 'autopromoteonce', |
1136 | ], |
1137 | ApiBase::PARAM_HELP_MSG_PER_VALUE => [], |
1138 | ], |
1139 | 'filteriw' => [ |
1140 | ParamValidator::PARAM_TYPE => [ |
1141 | 'local', |
1142 | '!local', |
1143 | ] |
1144 | ], |
1145 | 'showalldb' => false, |
1146 | 'numberingroup' => false, |
1147 | 'inlanguagecode' => null, |
1148 | ]; |
1149 | } |
1150 | |
1151 | protected function getExamplesMessages() { |
1152 | return [ |
1153 | 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics' |
1154 | => 'apihelp-query+siteinfo-example-simple', |
1155 | 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local' |
1156 | => 'apihelp-query+siteinfo-example-interwiki', |
1157 | 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=' |
1158 | => 'apihelp-query+siteinfo-example-replag', |
1159 | ]; |
1160 | } |
1161 | |
1162 | public function getHelpUrls() { |
1163 | return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Siteinfo'; |
1164 | } |
1165 | } |