Add language Doteli (dty)
[lhc/web/wiklou.git] / includes / api / ApiQuerySiteinfo.php
1 <?php
2 /**
3 *
4 *
5 * Created on Sep 25, 2006
6 *
7 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
23 *
24 * @file
25 */
26
27 /**
28 * A query action to return meta information about the wiki site.
29 *
30 * @ingroup API
31 */
32 class ApiQuerySiteinfo extends ApiQueryBase {
33
34 public function __construct( ApiQuery $query, $moduleName ) {
35 parent::__construct( $query, $moduleName, 'si' );
36 }
37
38 public function execute() {
39 $params = $this->extractRequestParams();
40 $done = array();
41 $fit = false;
42 foreach ( $params['prop'] as $p ) {
43 switch ( $p ) {
44 case 'general':
45 $fit = $this->appendGeneralInfo( $p );
46 break;
47 case 'namespaces':
48 $fit = $this->appendNamespaces( $p );
49 break;
50 case 'namespacealiases':
51 $fit = $this->appendNamespaceAliases( $p );
52 break;
53 case 'specialpagealiases':
54 $fit = $this->appendSpecialPageAliases( $p );
55 break;
56 case 'magicwords':
57 $fit = $this->appendMagicWords( $p );
58 break;
59 case 'interwikimap':
60 $filteriw = isset( $params['filteriw'] ) ? $params['filteriw'] : false;
61 $fit = $this->appendInterwikiMap( $p, $filteriw );
62 break;
63 case 'dbrepllag':
64 $fit = $this->appendDbReplLagInfo( $p, $params['showalldb'] );
65 break;
66 case 'statistics':
67 $fit = $this->appendStatistics( $p );
68 break;
69 case 'usergroups':
70 $fit = $this->appendUserGroups( $p, $params['numberingroup'] );
71 break;
72 case 'libraries':
73 $fit = $this->appendInstalledLibraries( $p );
74 break;
75 case 'extensions':
76 $fit = $this->appendExtensions( $p );
77 break;
78 case 'fileextensions':
79 $fit = $this->appendFileExtensions( $p );
80 break;
81 case 'rightsinfo':
82 $fit = $this->appendRightsInfo( $p );
83 break;
84 case 'restrictions':
85 $fit = $this->appendRestrictions( $p );
86 break;
87 case 'languages':
88 $fit = $this->appendLanguages( $p );
89 break;
90 case 'skins':
91 $fit = $this->appendSkins( $p );
92 break;
93 case 'extensiontags':
94 $fit = $this->appendExtensionTags( $p );
95 break;
96 case 'functionhooks':
97 $fit = $this->appendFunctionHooks( $p );
98 break;
99 case 'showhooks':
100 $fit = $this->appendSubscribedHooks( $p );
101 break;
102 case 'variables':
103 $fit = $this->appendVariables( $p );
104 break;
105 case 'protocols':
106 $fit = $this->appendProtocols( $p );
107 break;
108 case 'defaultoptions':
109 $fit = $this->appendDefaultOptions( $p );
110 break;
111 default:
112 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
113 }
114 if ( !$fit ) {
115 // Abuse siprop as a query-continue parameter
116 // and set it to all unprocessed props
117 $this->setContinueEnumParameter( 'prop', implode( '|',
118 array_diff( $params['prop'], $done ) ) );
119 break;
120 }
121 $done[] = $p;
122 }
123 }
124
125 protected function appendGeneralInfo( $property ) {
126 global $wgContLang;
127
128 $config = $this->getConfig();
129
130 $data = array();
131 $mainPage = Title::newMainPage();
132 $data['mainpage'] = $mainPage->getPrefixedText();
133 $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
134 $data['sitename'] = $config->get( 'Sitename' );
135
136 // wgLogo can either be a relative or an absolute path
137 // make sure we always return an absolute path
138 $data['logo'] = wfExpandUrl( $config->get( 'Logo' ), PROTO_RELATIVE );
139
140 $data['generator'] = "MediaWiki {$config->get( 'Version' )}";
141
142 $data['phpversion'] = PHP_VERSION;
143 $data['phpsapi'] = PHP_SAPI;
144 if ( defined( 'HHVM_VERSION' ) ) {
145 $data['hhvmversion'] = HHVM_VERSION;
146 }
147 $data['dbtype'] = $config->get( 'DBtype' );
148 $data['dbversion'] = $this->getDB()->getServerVersion();
149
150 $allowFrom = array( '' );
151 $allowException = true;
152 if ( !$config->get( 'AllowExternalImages' ) ) {
153 $data['imagewhitelistenabled'] = (bool)$config->get( 'EnableImageWhitelist' );
154 $allowFrom = $config->get( 'AllowExternalImagesFrom' );
155 $allowException = !empty( $allowFrom );
156 }
157 if ( $allowException ) {
158 $data['externalimages'] = (array)$allowFrom;
159 ApiResult::setIndexedTagName( $data['externalimages'], 'prefix' );
160 }
161
162 $data['langconversion'] = !$config->get( 'DisableLangConversion' );
163 $data['titleconversion'] = !$config->get( 'DisableTitleConversion' );
164
165 if ( $wgContLang->linkPrefixExtension() ) {
166 $linkPrefixCharset = $wgContLang->linkPrefixCharset();
167 $data['linkprefixcharset'] = $linkPrefixCharset;
168 // For backwards compatibility
169 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
170 } else {
171 $data['linkprefixcharset'] = '';
172 $data['linkprefix'] = '';
173 }
174
175 $linktrail = $wgContLang->linkTrail();
176 $data['linktrail'] = $linktrail ?: '';
177
178 $data['legaltitlechars'] = Title::legalChars();
179 $data['invalidusernamechars'] = $config->get( 'InvalidUsernameCharacters' );
180
181 global $IP;
182 $git = SpecialVersion::getGitHeadSha1( $IP );
183 if ( $git ) {
184 $data['git-hash'] = $git;
185 $data['git-branch'] =
186 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
187 } else {
188 $svn = SpecialVersion::getSvnRevision( $IP );
189 if ( $svn ) {
190 $data['rev'] = $svn;
191 }
192 }
193
194 // 'case-insensitive' option is reserved for future
195 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
196 $data['lang'] = $config->get( 'LanguageCode' );
197
198 $fallbacks = array();
199 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
200 $fallbacks[] = array( 'code' => $code );
201 }
202 $data['fallback'] = $fallbacks;
203 ApiResult::setIndexedTagName( $data['fallback'], 'lang' );
204
205 if ( $wgContLang->hasVariants() ) {
206 $variants = array();
207 foreach ( $wgContLang->getVariants() as $code ) {
208 $variants[] = array(
209 'code' => $code,
210 'name' => $wgContLang->getVariantname( $code ),
211 );
212 }
213 $data['variants'] = $variants;
214 ApiResult::setIndexedTagName( $data['variants'], 'lang' );
215 }
216
217 $data['rtl'] = $wgContLang->isRTL();
218 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
219
220 $data['readonly'] = wfReadOnly();
221 if ( $data['readonly'] ) {
222 $data['readonlyreason'] = wfReadOnlyReason();
223 }
224 $data['writeapi'] = (bool)$config->get( 'EnableWriteAPI' );
225
226 $tz = $config->get( 'Localtimezone' );
227 $offset = $config->get( 'LocalTZoffset' );
228 if ( is_null( $tz ) ) {
229 $tz = 'UTC';
230 $offset = 0;
231 } elseif ( is_null( $offset ) ) {
232 $offset = 0;
233 }
234 $data['timezone'] = $tz;
235 $data['timeoffset'] = intval( $offset );
236 $data['articlepath'] = $config->get( 'ArticlePath' );
237 $data['scriptpath'] = $config->get( 'ScriptPath' );
238 $data['script'] = $config->get( 'Script' );
239 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
240 $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
241 $data['server'] = $config->get( 'Server' );
242 $data['servername'] = $config->get( 'ServerName' );
243 $data['wikiid'] = wfWikiID();
244 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
245
246 $data['misermode'] = (bool)$config->get( 'MiserMode' );
247
248 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
249
250 $data['thumblimits'] = $config->get( 'ThumbLimits' );
251 ApiResult::setArrayType( $data['thumblimits'], 'BCassoc' );
252 ApiResult::setIndexedTagName( $data['thumblimits'], 'limit' );
253 $data['imagelimits'] = array();
254 ApiResult::setArrayType( $data['imagelimits'], 'BCassoc' );
255 ApiResult::setIndexedTagName( $data['imagelimits'], 'limit' );
256 foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
257 $data['imagelimits'][$k] = array( 'width' => $limit[0], 'height' => $limit[1] );
258 }
259
260 $favicon = $config->get( 'Favicon' );
261 if ( !empty( $favicon ) ) {
262 // wgFavicon can either be a relative or an absolute path
263 // make sure we always return an absolute path
264 $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
265 }
266
267 Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
268
269 return $this->getResult()->addValue( 'query', $property, $data );
270 }
271
272 protected function appendNamespaces( $property ) {
273 global $wgContLang;
274 $data = array(
275 ApiResult::META_TYPE => 'assoc',
276 );
277 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
278 $data[$ns] = array(
279 'id' => intval( $ns ),
280 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
281 );
282 ApiResult::setContentValue( $data[$ns], 'name', $title );
283 $canonical = MWNamespace::getCanonicalName( $ns );
284
285 $data[$ns]['subpages'] = MWNamespace::hasSubpages( $ns );
286
287 if ( $canonical ) {
288 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
289 }
290
291 $data[$ns]['content'] = MWNamespace::isContent( $ns );
292 $data[$ns]['nonincludable'] = MWNamespace::isNonincludable( $ns );
293
294 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
295 if ( $contentmodel ) {
296 $data[$ns]['defaultcontentmodel'] = $contentmodel;
297 }
298 }
299
300 ApiResult::setIndexedTagName( $data, 'ns' );
301
302 return $this->getResult()->addValue( 'query', $property, $data );
303 }
304
305 protected function appendNamespaceAliases( $property ) {
306 global $wgContLang;
307 $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
308 $wgContLang->getNamespaceAliases() );
309 $namespaces = $wgContLang->getNamespaces();
310 $data = array();
311 foreach ( $aliases as $title => $ns ) {
312 if ( $namespaces[$ns] == $title ) {
313 // Don't list duplicates
314 continue;
315 }
316 $item = array(
317 'id' => intval( $ns )
318 );
319 ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) );
320 $data[] = $item;
321 }
322
323 sort( $data );
324
325 ApiResult::setIndexedTagName( $data, 'ns' );
326
327 return $this->getResult()->addValue( 'query', $property, $data );
328 }
329
330 protected function appendSpecialPageAliases( $property ) {
331 global $wgContLang;
332 $data = array();
333 $aliases = $wgContLang->getSpecialPageAliases();
334 foreach ( SpecialPageFactory::getNames() as $specialpage ) {
335 if ( isset( $aliases[$specialpage] ) ) {
336 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
337 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
338 $data[] = $arr;
339 }
340 }
341 ApiResult::setIndexedTagName( $data, 'specialpage' );
342
343 return $this->getResult()->addValue( 'query', $property, $data );
344 }
345
346 protected function appendMagicWords( $property ) {
347 global $wgContLang;
348 $data = array();
349 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
350 $caseSensitive = array_shift( $aliases );
351 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
352 $arr['case-sensitive'] = (bool)$caseSensitive;
353 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
354 $data[] = $arr;
355 }
356 ApiResult::setIndexedTagName( $data, 'magicword' );
357
358 return $this->getResult()->addValue( 'query', $property, $data );
359 }
360
361 protected function appendInterwikiMap( $property, $filter ) {
362 $local = null;
363 if ( $filter === 'local' ) {
364 $local = 1;
365 } elseif ( $filter === '!local' ) {
366 $local = 0;
367 } elseif ( $filter ) {
368 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
369 }
370
371 $params = $this->extractRequestParams();
372 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
373 $langNames = Language::fetchLanguageNames( $langCode );
374
375 $getPrefixes = Interwiki::getAllPrefixes( $local );
376 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
377 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
378 $data = array();
379
380 foreach ( $getPrefixes as $row ) {
381 $prefix = $row['iw_prefix'];
382 $val = array();
383 $val['prefix'] = $prefix;
384 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
385 $val['local'] = true;
386 }
387 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
388 $val['trans'] = true;
389 }
390
391 if ( isset( $langNames[$prefix] ) ) {
392 $val['language'] = $langNames[$prefix];
393 }
394 if ( in_array( $prefix, $localInterwikis ) ) {
395 $val['localinterwiki'] = true;
396 }
397 if ( in_array( $prefix, $extraLangPrefixes ) ) {
398 $val['extralanglink'] = true;
399
400 $linktext = wfMessage( "interlanguage-link-$prefix" );
401 if ( !$linktext->isDisabled() ) {
402 $val['linktext'] = $linktext->text();
403 }
404
405 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
406 if ( !$sitename->isDisabled() ) {
407 $val['sitename'] = $sitename->text();
408 }
409 }
410
411 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
412 $val['protorel'] = substr( $row['iw_url'], 0, 2 ) == '//';
413 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
414 $val['wikiid'] = $row['iw_wikiid'];
415 }
416 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
417 $val['api'] = $row['iw_api'];
418 }
419
420 $data[] = $val;
421 }
422
423 ApiResult::setIndexedTagName( $data, 'iw' );
424
425 return $this->getResult()->addValue( 'query', $property, $data );
426 }
427
428 protected function appendDbReplLagInfo( $property, $includeAll ) {
429 $data = array();
430 $lb = wfGetLB();
431 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
432 if ( $includeAll ) {
433 if ( !$showHostnames ) {
434 $this->dieUsage(
435 'Cannot view all servers info unless $wgShowHostnames is true',
436 'includeAllDenied'
437 );
438 }
439
440 $lags = $lb->getLagTimes();
441 foreach ( $lags as $i => $lag ) {
442 $data[] = array(
443 'host' => $lb->getServerName( $i ),
444 'lag' => $lag
445 );
446 }
447 } else {
448 list( , $lag, $index ) = $lb->getMaxLag();
449 $data[] = array(
450 'host' => $showHostnames
451 ? $lb->getServerName( $index )
452 : '',
453 'lag' => intval( $lag )
454 );
455 }
456
457 $result = $this->getResult();
458 ApiResult::setIndexedTagName( $data, 'db' );
459
460 return $this->getResult()->addValue( 'query', $property, $data );
461 }
462
463 protected function appendStatistics( $property ) {
464 $data = array();
465 $data['pages'] = intval( SiteStats::pages() );
466 $data['articles'] = intval( SiteStats::articles() );
467 $data['edits'] = intval( SiteStats::edits() );
468 $data['images'] = intval( SiteStats::images() );
469 $data['users'] = intval( SiteStats::users() );
470 $data['activeusers'] = intval( SiteStats::activeUsers() );
471 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
472 $data['jobs'] = intval( SiteStats::jobs() );
473
474 Hooks::run( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
475
476 return $this->getResult()->addValue( 'query', $property, $data );
477 }
478
479 protected function appendUserGroups( $property, $numberInGroup ) {
480 $config = $this->getConfig();
481
482 $data = array();
483 $result = $this->getResult();
484 $allGroups = User::getAllGroups();
485 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
486 $arr = array(
487 'name' => $group,
488 'rights' => array_keys( $permissions, true ),
489 );
490
491 if ( $numberInGroup ) {
492 $autopromote = $config->get( 'Autopromote' );
493
494 if ( $group == 'user' ) {
495 $arr['number'] = SiteStats::users();
496 // '*' and autopromote groups have no size
497 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
498 $arr['number'] = SiteStats::numberInGroup( $group );
499 }
500 }
501
502 $groupArr = array(
503 'add' => $config->get( 'AddGroups' ),
504 'remove' => $config->get( 'RemoveGroups' ),
505 'add-self' => $config->get( 'GroupsAddToSelf' ),
506 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
507 );
508
509 foreach ( $groupArr as $type => $rights ) {
510 if ( isset( $rights[$group] ) ) {
511 $groups = array_intersect( $rights[$group], $allGroups );
512 if ( $groups ) {
513 $arr[$type] = $groups;
514 ApiResult::setIndexedTagName( $arr[$type], 'group' );
515 }
516 }
517 }
518
519 ApiResult::setIndexedTagName( $arr['rights'], 'permission' );
520 $data[] = $arr;
521 }
522
523 ApiResult::setIndexedTagName( $data, 'group' );
524
525 return $result->addValue( 'query', $property, $data );
526 }
527
528 protected function appendFileExtensions( $property ) {
529 $data = array();
530 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
531 $data[] = array( 'ext' => $ext );
532 }
533 ApiResult::setIndexedTagName( $data, 'fe' );
534
535 return $this->getResult()->addValue( 'query', $property, $data );
536 }
537
538 protected function appendInstalledLibraries( $property ) {
539 global $IP;
540 $path = "$IP/composer.lock";
541 if ( !file_exists( $path ) ) {
542 // Maybe they're using mediawiki/vendor?
543 $path = "$IP/vendor/composer.lock";
544 if ( !file_exists( $path ) ) {
545 return true;
546 }
547 }
548
549 $data = array();
550 $lock = new ComposerLock( $path );
551 foreach ( $lock->getInstalledDependencies() as $name => $info ) {
552 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
553 // Skip any extensions or skins since they'll be listed
554 // in their proper section
555 continue;
556 }
557 $data[] = array(
558 'name' => $name,
559 'version' => $info['version'],
560 );
561 }
562 ApiResult::setIndexedTagName( $data, 'library' );
563
564 return $this->getResult()->addValue( 'query', $property, $data );
565
566 }
567
568 protected function appendExtensions( $property ) {
569 $data = array();
570 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
571 foreach ( $extensions as $ext ) {
572 $ret = array();
573 $ret['type'] = $type;
574 if ( isset( $ext['name'] ) ) {
575 $ret['name'] = $ext['name'];
576 }
577 if ( isset( $ext['namemsg'] ) ) {
578 $ret['namemsg'] = $ext['namemsg'];
579 }
580 if ( isset( $ext['description'] ) ) {
581 $ret['description'] = $ext['description'];
582 }
583 if ( isset( $ext['descriptionmsg'] ) ) {
584 // Can be a string or array( key, param1, param2, ... )
585 if ( is_array( $ext['descriptionmsg'] ) ) {
586 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
587 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
588 ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
589 } else {
590 $ret['descriptionmsg'] = $ext['descriptionmsg'];
591 }
592 }
593 if ( isset( $ext['author'] ) ) {
594 $ret['author'] = is_array( $ext['author'] ) ?
595 implode( ', ', $ext['author'] ) : $ext['author'];
596 }
597 if ( isset( $ext['url'] ) ) {
598 $ret['url'] = $ext['url'];
599 }
600 if ( isset( $ext['version'] ) ) {
601 $ret['version'] = $ext['version'];
602 } elseif ( isset( $ext['svn-revision'] ) &&
603 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
604 $ext['svn-revision'], $m )
605 ) {
606 $ret['version'] = 'r' . $m[1];
607 }
608 if ( isset( $ext['path'] ) ) {
609 $extensionPath = dirname( $ext['path'] );
610 $gitInfo = new GitInfo( $extensionPath );
611 $vcsVersion = $gitInfo->getHeadSHA1();
612 if ( $vcsVersion !== false ) {
613 $ret['vcs-system'] = 'git';
614 $ret['vcs-version'] = $vcsVersion;
615 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
616 $vcsDate = $gitInfo->getHeadCommitDate();
617 if ( $vcsDate !== false ) {
618 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
619 }
620 } else {
621 $svnInfo = SpecialVersion::getSvnInfo( $extensionPath );
622 if ( $svnInfo !== false ) {
623 $ret['vcs-system'] = 'svn';
624 $ret['vcs-version'] = $svnInfo['checkout-rev'];
625 $ret['vcs-url'] = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
626 }
627 }
628
629 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
630 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
631 $ret['license'] = SpecialPage::getTitleFor(
632 'Version',
633 "License/{$ext['name']}"
634 )->getLinkURL();
635 }
636
637 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
638 $ret['credits'] = SpecialPage::getTitleFor(
639 'Version',
640 "Credits/{$ext['name']}"
641 )->getLinkURL();
642 }
643 }
644 $data[] = $ret;
645 }
646 }
647
648 ApiResult::setIndexedTagName( $data, 'ext' );
649
650 return $this->getResult()->addValue( 'query', $property, $data );
651 }
652
653 protected function appendRightsInfo( $property ) {
654 $config = $this->getConfig();
655 $rightsPage = $config->get( 'RightsPage' );
656 if ( is_string( $rightsPage ) ) {
657 $title = Title::newFromText( $rightsPage );
658 $url = wfExpandUrl( $title, PROTO_CURRENT );
659 } else {
660 $title = false;
661 $url = $config->get( 'RightsUrl' );
662 }
663 $text = $config->get( 'RightsText' );
664 if ( !$text && $title ) {
665 $text = $title->getPrefixedText();
666 }
667
668 $data = array(
669 'url' => $url ? $url : '',
670 'text' => $text ? $text : ''
671 );
672
673 return $this->getResult()->addValue( 'query', $property, $data );
674 }
675
676 protected function appendRestrictions( $property ) {
677 $config = $this->getConfig();
678 $data = array(
679 'types' => $config->get( 'RestrictionTypes' ),
680 'levels' => $config->get( 'RestrictionLevels' ),
681 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
682 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
683 );
684
685 ApiResult::setIndexedTagName( $data['types'], 'type' );
686 ApiResult::setIndexedTagName( $data['levels'], 'level' );
687 ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' );
688 ApiResult::setIndexedTagName( $data['semiprotectedlevels'], 'level' );
689
690 return $this->getResult()->addValue( 'query', $property, $data );
691 }
692
693 public function appendLanguages( $property ) {
694 $params = $this->extractRequestParams();
695 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
696 $langNames = Language::fetchLanguageNames( $langCode );
697
698 $data = array();
699
700 foreach ( $langNames as $code => $name ) {
701 $lang = array( 'code' => $code );
702 ApiResult::setContentValue( $lang, 'name', $name );
703 $data[] = $lang;
704 }
705 ApiResult::setIndexedTagName( $data, 'lang' );
706
707 return $this->getResult()->addValue( 'query', $property, $data );
708 }
709
710 public function appendSkins( $property ) {
711 $data = array();
712 $allowed = Skin::getAllowedSkins();
713 $default = Skin::normalizeKey( 'default' );
714 foreach ( Skin::getSkinNames() as $name => $displayName ) {
715 $msg = $this->msg( "skinname-{$name}" );
716 $code = $this->getParameter( 'inlanguagecode' );
717 if ( $code && Language::isValidCode( $code ) ) {
718 $msg->inLanguage( $code );
719 } else {
720 $msg->inContentLanguage();
721 }
722 if ( $msg->exists() ) {
723 $displayName = $msg->text();
724 }
725 $skin = array( 'code' => $name );
726 ApiResult::setContentValue( $skin, 'name', $displayName );
727 if ( !isset( $allowed[$name] ) ) {
728 $skin['unusable'] = true;
729 }
730 if ( $name === $default ) {
731 $skin['default'] = true;
732 }
733 $data[] = $skin;
734 }
735 ApiResult::setIndexedTagName( $data, 'skin' );
736
737 return $this->getResult()->addValue( 'query', $property, $data );
738 }
739
740 public function appendExtensionTags( $property ) {
741 global $wgParser;
742 $wgParser->firstCallInit();
743 $tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
744 ApiResult::setIndexedTagName( $tags, 't' );
745
746 return $this->getResult()->addValue( 'query', $property, $tags );
747 }
748
749 public function appendFunctionHooks( $property ) {
750 global $wgParser;
751 $wgParser->firstCallInit();
752 $hooks = $wgParser->getFunctionHooks();
753 ApiResult::setIndexedTagName( $hooks, 'h' );
754
755 return $this->getResult()->addValue( 'query', $property, $hooks );
756 }
757
758 public function appendVariables( $property ) {
759 $variables = MagicWord::getVariableIDs();
760 ApiResult::setIndexedTagName( $variables, 'v' );
761
762 return $this->getResult()->addValue( 'query', $property, $variables );
763 }
764
765 public function appendProtocols( $property ) {
766 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
767 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
768 ApiResult::setIndexedTagName( $protocols, 'p' );
769
770 return $this->getResult()->addValue( 'query', $property, $protocols );
771 }
772
773 public function appendDefaultOptions( $property ) {
774 $options = User::getDefaultOptions();
775 $options[ApiResult::META_BC_BOOLS] = array_keys( $options );
776 return $this->getResult()->addValue( 'query', $property, $options );
777 }
778
779 private function formatParserTags( $item ) {
780 return "<{$item}>";
781 }
782
783 public function appendSubscribedHooks( $property ) {
784 $hooks = $this->getConfig()->get( 'Hooks' );
785 $myWgHooks = $hooks;
786 ksort( $myWgHooks );
787
788 $data = array();
789 foreach ( $myWgHooks as $name => $subscribers ) {
790 $arr = array(
791 'name' => $name,
792 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $subscribers ),
793 );
794
795 ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
796 $data[] = $arr;
797 }
798
799 ApiResult::setIndexedTagName( $data, 'hook' );
800
801 return $this->getResult()->addValue( 'query', $property, $data );
802 }
803
804 public function getCacheMode( $params ) {
805 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
806 if (
807 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
808 !is_null( $params['prop'] ) &&
809 in_array( 'interwikimap', $params['prop'] )
810 ) {
811 return 'anon-public-user-private';
812 }
813
814 return 'public';
815 }
816
817 public function getAllowedParams() {
818 return array(
819 'prop' => array(
820 ApiBase::PARAM_DFLT => 'general',
821 ApiBase::PARAM_ISMULTI => true,
822 ApiBase::PARAM_TYPE => array(
823 'general',
824 'namespaces',
825 'namespacealiases',
826 'specialpagealiases',
827 'magicwords',
828 'interwikimap',
829 'dbrepllag',
830 'statistics',
831 'usergroups',
832 'libraries',
833 'extensions',
834 'fileextensions',
835 'rightsinfo',
836 'restrictions',
837 'languages',
838 'skins',
839 'extensiontags',
840 'functionhooks',
841 'showhooks',
842 'variables',
843 'protocols',
844 'defaultoptions',
845 )
846 ),
847 'filteriw' => array(
848 ApiBase::PARAM_TYPE => array(
849 'local',
850 '!local',
851 )
852 ),
853 'showalldb' => false,
854 'numberingroup' => false,
855 'inlanguagecode' => null,
856 );
857 }
858
859 protected function getExamplesMessages() {
860 return array(
861 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
862 => 'apihelp-query+siteinfo-example-simple',
863 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
864 => 'apihelp-query+siteinfo-example-interwiki',
865 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
866 => 'apihelp-query+siteinfo-example-replag',
867 );
868 }
869
870 public function getHelpUrls() {
871 return 'https://www.mediawiki.org/wiki/API:Siteinfo';
872 }
873 }