MessagePoster followup: Dependency and docs
[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 if ( $config->get( 'EnableImageWhitelist' ) ) {
154 $data['imagewhitelistenabled'] = '';
155 }
156 $allowFrom = $config->get( 'AllowExternalImagesFrom' );
157 $allowException = !empty( $allowFrom );
158 }
159 if ( $allowException ) {
160 $data['externalimages'] = (array)$allowFrom;
161 $this->getResult()->setIndexedTagName( $data['externalimages'], 'prefix' );
162 }
163
164 if ( !$config->get( 'DisableLangConversion' ) ) {
165 $data['langconversion'] = '';
166 }
167
168 if ( !$config->get( 'DisableTitleConversion' ) ) {
169 $data['titleconversion'] = '';
170 }
171
172 if ( $wgContLang->linkPrefixExtension() ) {
173 $linkPrefixCharset = $wgContLang->linkPrefixCharset();
174 $data['linkprefixcharset'] = $linkPrefixCharset;
175 // For backwards compatibility
176 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
177 } else {
178 $data['linkprefixcharset'] = '';
179 $data['linkprefix'] = '';
180 }
181
182 $linktrail = $wgContLang->linkTrail();
183 if ( $linktrail ) {
184 $data['linktrail'] = $linktrail;
185 } else {
186 $data['linktrail'] = '';
187 }
188
189 $data['legaltitlechars'] = Title::legalChars();
190
191 global $IP;
192 $git = SpecialVersion::getGitHeadSha1( $IP );
193 if ( $git ) {
194 $data['git-hash'] = $git;
195 $data['git-branch'] =
196 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
197 } else {
198 $svn = SpecialVersion::getSvnRevision( $IP );
199 if ( $svn ) {
200 $data['rev'] = $svn;
201 }
202 }
203
204 // 'case-insensitive' option is reserved for future
205 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
206 $data['lang'] = $config->get( 'LanguageCode' );
207
208 $fallbacks = array();
209 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
210 $fallbacks[] = array( 'code' => $code );
211 }
212 $data['fallback'] = $fallbacks;
213 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
214
215 if ( $wgContLang->hasVariants() ) {
216 $variants = array();
217 foreach ( $wgContLang->getVariants() as $code ) {
218 $variants[] = array(
219 'code' => $code,
220 'name' => $wgContLang->getVariantname( $code ),
221 );
222 }
223 $data['variants'] = $variants;
224 $this->getResult()->setIndexedTagName( $data['variants'], 'lang' );
225 }
226
227 if ( $wgContLang->isRTL() ) {
228 $data['rtl'] = '';
229 }
230 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
231
232 if ( wfReadOnly() ) {
233 $data['readonly'] = '';
234 $data['readonlyreason'] = wfReadOnlyReason();
235 }
236 if ( $config->get( 'EnableWriteAPI' ) ) {
237 $data['writeapi'] = '';
238 }
239
240 $tz = $config->get( 'Localtimezone' );
241 $offset = $config->get( 'LocalTZoffset' );
242 if ( is_null( $tz ) ) {
243 $tz = 'UTC';
244 $offset = 0;
245 } elseif ( is_null( $offset ) ) {
246 $offset = 0;
247 }
248 $data['timezone'] = $tz;
249 $data['timeoffset'] = intval( $offset );
250 $data['articlepath'] = $config->get( 'ArticlePath' );
251 $data['scriptpath'] = $config->get( 'ScriptPath' );
252 $data['script'] = $config->get( 'Script' );
253 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
254 $data['server'] = $config->get( 'Server' );
255 $data['servername'] = $config->get( 'ServerName' );
256 $data['wikiid'] = wfWikiID();
257 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
258
259 if ( $config->get( 'MiserMode' ) ) {
260 $data['misermode'] = '';
261 }
262
263 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
264
265 $data['thumblimits'] = $config->get( 'ThumbLimits' );
266 $this->getResult()->setIndexedTagName( $data['thumblimits'], 'limit' );
267 $data['imagelimits'] = array();
268 $this->getResult()->setIndexedTagName( $data['imagelimits'], 'limit' );
269 foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
270 $data['imagelimits'][$k] = array( 'width' => $limit[0], 'height' => $limit[1] );
271 }
272
273 $favicon = $config->get( 'Favicon' );
274 if ( !empty( $favicon ) ) {
275 // wgFavicon can either be a relative or an absolute path
276 // make sure we always return an absolute path
277 $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
278 }
279
280 Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
281
282 return $this->getResult()->addValue( 'query', $property, $data );
283 }
284
285 protected function appendNamespaces( $property ) {
286 global $wgContLang;
287 $data = array();
288 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
289 $data[$ns] = array(
290 'id' => intval( $ns ),
291 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
292 );
293 ApiResult::setContent( $data[$ns], $title );
294 $canonical = MWNamespace::getCanonicalName( $ns );
295
296 if ( MWNamespace::hasSubpages( $ns ) ) {
297 $data[$ns]['subpages'] = '';
298 }
299
300 if ( $canonical ) {
301 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
302 }
303
304 if ( MWNamespace::isContent( $ns ) ) {
305 $data[$ns]['content'] = '';
306 }
307
308 if ( MWNamespace::isNonincludable( $ns ) ) {
309 $data[$ns]['nonincludable'] = '';
310 }
311
312 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
313 if ( $contentmodel ) {
314 $data[$ns]['defaultcontentmodel'] = $contentmodel;
315 }
316 }
317
318 $this->getResult()->setIndexedTagName( $data, 'ns' );
319
320 return $this->getResult()->addValue( 'query', $property, $data );
321 }
322
323 protected function appendNamespaceAliases( $property ) {
324 global $wgContLang;
325 $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
326 $wgContLang->getNamespaceAliases() );
327 $namespaces = $wgContLang->getNamespaces();
328 $data = array();
329 foreach ( $aliases as $title => $ns ) {
330 if ( $namespaces[$ns] == $title ) {
331 // Don't list duplicates
332 continue;
333 }
334 $item = array(
335 'id' => intval( $ns )
336 );
337 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
338 $data[] = $item;
339 }
340
341 sort( $data );
342
343 $this->getResult()->setIndexedTagName( $data, 'ns' );
344
345 return $this->getResult()->addValue( 'query', $property, $data );
346 }
347
348 protected function appendSpecialPageAliases( $property ) {
349 global $wgContLang;
350 $data = array();
351 $aliases = $wgContLang->getSpecialPageAliases();
352 foreach ( SpecialPageFactory::getNames() as $specialpage ) {
353 if ( isset( $aliases[$specialpage] ) ) {
354 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
355 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
356 $data[] = $arr;
357 }
358 }
359 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
360
361 return $this->getResult()->addValue( 'query', $property, $data );
362 }
363
364 protected function appendMagicWords( $property ) {
365 global $wgContLang;
366 $data = array();
367 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
368 $caseSensitive = array_shift( $aliases );
369 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
370 if ( $caseSensitive ) {
371 $arr['case-sensitive'] = '';
372 }
373 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
374 $data[] = $arr;
375 }
376 $this->getResult()->setIndexedTagName( $data, 'magicword' );
377
378 return $this->getResult()->addValue( 'query', $property, $data );
379 }
380
381 protected function appendInterwikiMap( $property, $filter ) {
382 $local = null;
383 if ( $filter === 'local' ) {
384 $local = 1;
385 } elseif ( $filter === '!local' ) {
386 $local = 0;
387 } elseif ( $filter ) {
388 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
389 }
390
391 $params = $this->extractRequestParams();
392 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
393 $langNames = Language::fetchLanguageNames( $langCode );
394
395 $getPrefixes = Interwiki::getAllPrefixes( $local );
396 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
397 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
398 $data = array();
399
400 foreach ( $getPrefixes as $row ) {
401 $prefix = $row['iw_prefix'];
402 $val = array();
403 $val['prefix'] = $prefix;
404 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
405 $val['local'] = '';
406 }
407 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
408 $val['trans'] = '';
409 }
410
411 if ( isset( $langNames[$prefix] ) ) {
412 $val['language'] = $langNames[$prefix];
413 }
414 if ( in_array( $prefix, $localInterwikis ) ) {
415 $val['localinterwiki'] = '';
416 }
417 if ( in_array( $prefix, $extraLangPrefixes ) ) {
418 $val['extralanglink'] = '';
419
420 $linktext = wfMessage( "interlanguage-link-$prefix" );
421 if ( !$linktext->isDisabled() ) {
422 $val['linktext'] = $linktext->text();
423 }
424
425 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
426 if ( !$sitename->isDisabled() ) {
427 $val['sitename'] = $sitename->text();
428 }
429 }
430
431 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
432 if ( substr( $row['iw_url'], 0, 2 ) == '//' ) {
433 $val['protorel'] = '';
434 }
435 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
436 $val['wikiid'] = $row['iw_wikiid'];
437 }
438 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
439 $val['api'] = $row['iw_api'];
440 }
441
442 $data[] = $val;
443 }
444
445 $this->getResult()->setIndexedTagName( $data, 'iw' );
446
447 return $this->getResult()->addValue( 'query', $property, $data );
448 }
449
450 protected function appendDbReplLagInfo( $property, $includeAll ) {
451 $data = array();
452 $lb = wfGetLB();
453 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
454 if ( $includeAll ) {
455 if ( !$showHostnames ) {
456 $this->dieUsage(
457 'Cannot view all servers info unless $wgShowHostnames is true',
458 'includeAllDenied'
459 );
460 }
461
462 $lags = $lb->getLagTimes();
463 foreach ( $lags as $i => $lag ) {
464 $data[] = array(
465 'host' => $lb->getServerName( $i ),
466 'lag' => $lag
467 );
468 }
469 } else {
470 list( , $lag, $index ) = $lb->getMaxLag();
471 $data[] = array(
472 'host' => $showHostnames
473 ? $lb->getServerName( $index )
474 : '',
475 'lag' => intval( $lag )
476 );
477 }
478
479 $result = $this->getResult();
480 $result->setIndexedTagName( $data, 'db' );
481
482 return $this->getResult()->addValue( 'query', $property, $data );
483 }
484
485 protected function appendStatistics( $property ) {
486 $data = array();
487 $data['pages'] = intval( SiteStats::pages() );
488 $data['articles'] = intval( SiteStats::articles() );
489 $data['edits'] = intval( SiteStats::edits() );
490 $data['images'] = intval( SiteStats::images() );
491 $data['users'] = intval( SiteStats::users() );
492 $data['activeusers'] = intval( SiteStats::activeUsers() );
493 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
494 $data['jobs'] = intval( SiteStats::jobs() );
495
496 Hooks::run( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
497
498 return $this->getResult()->addValue( 'query', $property, $data );
499 }
500
501 protected function appendUserGroups( $property, $numberInGroup ) {
502 $config = $this->getConfig();
503
504 $data = array();
505 $result = $this->getResult();
506 $allGroups = User::getAllGroups();
507 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
508 $arr = array(
509 'name' => $group,
510 'rights' => array_keys( $permissions, true ),
511 );
512
513 if ( $numberInGroup ) {
514 $autopromote = $config->get( 'Autopromote' );
515
516 if ( $group == 'user' ) {
517 $arr['number'] = SiteStats::users();
518 // '*' and autopromote groups have no size
519 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
520 $arr['number'] = SiteStats::numberInGroup( $group );
521 }
522 }
523
524 $groupArr = array(
525 'add' => $config->get( 'AddGroups' ),
526 'remove' => $config->get( 'RemoveGroups' ),
527 'add-self' => $config->get( 'GroupsAddToSelf' ),
528 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
529 );
530
531 foreach ( $groupArr as $type => $rights ) {
532 if ( isset( $rights[$group] ) ) {
533 $groups = array_intersect( $rights[$group], $allGroups );
534 if ( $groups ) {
535 $arr[$type] = $groups;
536 $result->setIndexedTagName( $arr[$type], 'group' );
537 }
538 }
539 }
540
541 $result->setIndexedTagName( $arr['rights'], 'permission' );
542 $data[] = $arr;
543 }
544
545 $result->setIndexedTagName( $data, 'group' );
546
547 return $result->addValue( 'query', $property, $data );
548 }
549
550 protected function appendFileExtensions( $property ) {
551 $data = array();
552 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
553 $data[] = array( 'ext' => $ext );
554 }
555 $this->getResult()->setIndexedTagName( $data, 'fe' );
556
557 return $this->getResult()->addValue( 'query', $property, $data );
558 }
559
560 protected function appendInstalledLibraries( $property ) {
561 global $IP;
562 $path = "$IP/composer.lock";
563 if ( !file_exists( $path ) ) {
564 // Maybe they're using mediawiki/vendor?
565 $path = "$IP/vendor/composer.lock";
566 if ( !file_exists( $path ) ) {
567 return true;
568 }
569 }
570
571 $data = array();
572 $lock = new ComposerLock( $path );
573 foreach ( $lock->getInstalledDependencies() as $name => $info ) {
574 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
575 // Skip any extensions or skins since they'll be listed
576 // in their proper section
577 continue;
578 }
579 $data[] = array(
580 'name' => $name,
581 'version' => $info['version'],
582 );
583 }
584 $this->getResult()->setIndexedTagName( $data, 'library' );
585
586 return $this->getResult()->addValue( 'query', $property, $data );
587
588 }
589
590 protected function appendExtensions( $property ) {
591 $data = array();
592 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
593 foreach ( $extensions as $ext ) {
594 $ret = array();
595 $ret['type'] = $type;
596 if ( isset( $ext['name'] ) ) {
597 $ret['name'] = $ext['name'];
598 }
599 if ( isset( $ext['namemsg'] ) ) {
600 $ret['namemsg'] = $ext['namemsg'];
601 }
602 if ( isset( $ext['description'] ) ) {
603 $ret['description'] = $ext['description'];
604 }
605 if ( isset( $ext['descriptionmsg'] ) ) {
606 // Can be a string or array( key, param1, param2, ... )
607 if ( is_array( $ext['descriptionmsg'] ) ) {
608 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
609 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
610 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
611 } else {
612 $ret['descriptionmsg'] = $ext['descriptionmsg'];
613 }
614 }
615 if ( isset( $ext['author'] ) ) {
616 $ret['author'] = is_array( $ext['author'] ) ?
617 implode( ', ', $ext['author'] ) : $ext['author'];
618 }
619 if ( isset( $ext['url'] ) ) {
620 $ret['url'] = $ext['url'];
621 }
622 if ( isset( $ext['version'] ) ) {
623 $ret['version'] = $ext['version'];
624 } elseif ( isset( $ext['svn-revision'] ) &&
625 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
626 $ext['svn-revision'], $m )
627 ) {
628 $ret['version'] = 'r' . $m[1];
629 }
630 if ( isset( $ext['path'] ) ) {
631 $extensionPath = dirname( $ext['path'] );
632 $gitInfo = new GitInfo( $extensionPath );
633 $vcsVersion = $gitInfo->getHeadSHA1();
634 if ( $vcsVersion !== false ) {
635 $ret['vcs-system'] = 'git';
636 $ret['vcs-version'] = $vcsVersion;
637 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
638 $vcsDate = $gitInfo->getHeadCommitDate();
639 if ( $vcsDate !== false ) {
640 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
641 }
642 } else {
643 $svnInfo = SpecialVersion::getSvnInfo( $extensionPath );
644 if ( $svnInfo !== false ) {
645 $ret['vcs-system'] = 'svn';
646 $ret['vcs-version'] = $svnInfo['checkout-rev'];
647 $ret['vcs-url'] = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
648 }
649 }
650
651 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
652 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
653 $ret['license'] = SpecialPage::getTitleFor(
654 'Version',
655 "License/{$ext['name']}"
656 )->getLinkURL();
657 }
658
659 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
660 $ret['credits'] = SpecialPage::getTitleFor(
661 'Version',
662 "Credits/{$ext['name']}"
663 )->getLinkURL();
664 }
665 }
666 $data[] = $ret;
667 }
668 }
669
670 $this->getResult()->setIndexedTagName( $data, 'ext' );
671
672 return $this->getResult()->addValue( 'query', $property, $data );
673 }
674
675 protected function appendRightsInfo( $property ) {
676 $config = $this->getConfig();
677 $title = Title::newFromText( $config->get( 'RightsPage' ) );
678 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $config->get( 'RightsUrl' );
679 $text = $config->get( 'RightsText' );
680 if ( !$text && $title ) {
681 $text = $title->getPrefixedText();
682 }
683
684 $data = array(
685 'url' => $url ? $url : '',
686 'text' => $text ? $text : ''
687 );
688
689 return $this->getResult()->addValue( 'query', $property, $data );
690 }
691
692 protected function appendRestrictions( $property ) {
693 $config = $this->getConfig();
694 $data = array(
695 'types' => $config->get( 'RestrictionTypes' ),
696 'levels' => $config->get( 'RestrictionLevels' ),
697 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
698 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
699 );
700
701 $this->getResult()->setIndexedTagName( $data['types'], 'type' );
702 $this->getResult()->setIndexedTagName( $data['levels'], 'level' );
703 $this->getResult()->setIndexedTagName( $data['cascadinglevels'], 'level' );
704 $this->getResult()->setIndexedTagName( $data['semiprotectedlevels'], 'level' );
705
706 return $this->getResult()->addValue( 'query', $property, $data );
707 }
708
709 public function appendLanguages( $property ) {
710 $params = $this->extractRequestParams();
711 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
712 $langNames = Language::fetchLanguageNames( $langCode );
713
714 $data = array();
715
716 foreach ( $langNames as $code => $name ) {
717 $lang = array( 'code' => $code );
718 ApiResult::setContent( $lang, $name );
719 $data[] = $lang;
720 }
721 $this->getResult()->setIndexedTagName( $data, 'lang' );
722
723 return $this->getResult()->addValue( 'query', $property, $data );
724 }
725
726 public function appendSkins( $property ) {
727 $data = array();
728 $allowed = Skin::getAllowedSkins();
729 $default = Skin::normalizeKey( 'default' );
730 foreach ( Skin::getSkinNames() as $name => $displayName ) {
731 $msg = $this->msg( "skinname-{$name}" );
732 $code = $this->getParameter( 'inlanguagecode' );
733 if ( $code && Language::isValidCode( $code ) ) {
734 $msg->inLanguage( $code );
735 } else {
736 $msg->inContentLanguage();
737 }
738 if ( $msg->exists() ) {
739 $displayName = $msg->text();
740 }
741 $skin = array( 'code' => $name );
742 ApiResult::setContent( $skin, $displayName );
743 if ( !isset( $allowed[$name] ) ) {
744 $skin['unusable'] = '';
745 }
746 if ( $name === $default ) {
747 $skin['default'] = '';
748 }
749 $data[] = $skin;
750 }
751 $this->getResult()->setIndexedTagName( $data, 'skin' );
752
753 return $this->getResult()->addValue( 'query', $property, $data );
754 }
755
756 public function appendExtensionTags( $property ) {
757 global $wgParser;
758 $wgParser->firstCallInit();
759 $tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
760 $this->getResult()->setIndexedTagName( $tags, 't' );
761
762 return $this->getResult()->addValue( 'query', $property, $tags );
763 }
764
765 public function appendFunctionHooks( $property ) {
766 global $wgParser;
767 $wgParser->firstCallInit();
768 $hooks = $wgParser->getFunctionHooks();
769 $this->getResult()->setIndexedTagName( $hooks, 'h' );
770
771 return $this->getResult()->addValue( 'query', $property, $hooks );
772 }
773
774 public function appendVariables( $property ) {
775 $variables = MagicWord::getVariableIDs();
776 $this->getResult()->setIndexedTagName( $variables, 'v' );
777
778 return $this->getResult()->addValue( 'query', $property, $variables );
779 }
780
781 public function appendProtocols( $property ) {
782 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
783 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
784 $this->getResult()->setIndexedTagName( $protocols, 'p' );
785
786 return $this->getResult()->addValue( 'query', $property, $protocols );
787 }
788
789 public function appendDefaultOptions( $property ) {
790 return $this->getResult()->addValue( 'query', $property, User::getDefaultOptions() );
791 }
792
793 private function formatParserTags( $item ) {
794 return "<{$item}>";
795 }
796
797 public function appendSubscribedHooks( $property ) {
798 $hooks = $this->getConfig()->get( 'Hooks' );
799 $myWgHooks = $hooks;
800 ksort( $myWgHooks );
801
802 $data = array();
803 foreach ( $myWgHooks as $name => $subscribers ) {
804 $arr = array(
805 'name' => $name,
806 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $subscribers ),
807 );
808
809 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
810 $data[] = $arr;
811 }
812
813 $this->getResult()->setIndexedTagName( $data, 'hook' );
814
815 return $this->getResult()->addValue( 'query', $property, $data );
816 }
817
818 public function getCacheMode( $params ) {
819 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
820 if (
821 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
822 !is_null( $params['prop'] ) &&
823 in_array( 'interwikimap', $params['prop'] )
824 ) {
825 return 'anon-public-user-private';
826 }
827
828 return 'public';
829 }
830
831 public function getAllowedParams() {
832 return array(
833 'prop' => array(
834 ApiBase::PARAM_DFLT => 'general',
835 ApiBase::PARAM_ISMULTI => true,
836 ApiBase::PARAM_TYPE => array(
837 'general',
838 'namespaces',
839 'namespacealiases',
840 'specialpagealiases',
841 'magicwords',
842 'interwikimap',
843 'dbrepllag',
844 'statistics',
845 'usergroups',
846 'libraries',
847 'extensions',
848 'fileextensions',
849 'rightsinfo',
850 'restrictions',
851 'languages',
852 'skins',
853 'extensiontags',
854 'functionhooks',
855 'showhooks',
856 'variables',
857 'protocols',
858 'defaultoptions',
859 )
860 ),
861 'filteriw' => array(
862 ApiBase::PARAM_TYPE => array(
863 'local',
864 '!local',
865 )
866 ),
867 'showalldb' => false,
868 'numberingroup' => false,
869 'inlanguagecode' => null,
870 );
871 }
872
873 protected function getExamplesMessages() {
874 return array(
875 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
876 => 'apihelp-query+siteinfo-example-simple',
877 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
878 => 'apihelp-query+siteinfo-example-interwiki',
879 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
880 => 'apihelp-query+siteinfo-example-replag',
881 );
882 }
883
884 public function getHelpUrls() {
885 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
886 }
887 }