public function execute() { if (!$this->hasAnyRoutes()) { $this->dieUsage('No password reset routes are available.', 'moduledisabled'); } $params = $this->extractRequestParams() + ['user' => null, 'email' => null]; $this->requireOnlyOneParameter($params, 'user', 'email'); $passwordReset = new PasswordReset($this->getConfig(), AuthManager::singleton()); $status = $passwordReset->isAllowed($this->getUser(), $params['capture']); if (!$status->isOK()) { $this->dieStatus(Status::wrap($status)); } $status = $passwordReset->execute($this->getUser(), $params['user'], $params['email'], $params['capture']); if (!$status->isOK()) { $status->value = null; $this->dieStatus(Status::wrap($status)); } $result = $this->getResult(); $result->addValue(['resetpassword'], 'status', 'success'); if ($params['capture']) { $passwords = $status->getValue() ?: []; ApiResult::setArrayType($passwords, 'kvp', 'user'); ApiResult::setIndexedTagName($passwords, 'p'); $result->addValue(['resetpassword'], 'passwords', $passwords); } }
/** * Add page properties to an ApiResult, adding a continue * parameter if it doesn't fit. * * @param ApiResult $result * @param int $page * @param array $props * @return bool True if it fits in the result */ private function addPageProps($result, $page, $props) { ApiResult::setArrayType($props, 'assoc'); $fit = $result->addValue(['query', 'pages', $page], 'pageprops', $props); if (!$fit) { $this->setContinueEnumParameter('continue', $page); } return $fit; }
public function execute() { $params = $this->extractRequestParams(); $props = array_flip($params['prop']); $repos = array(); $repoGroup = $this->getInitialisedRepoGroup(); $repoGroup->forEachForeignRepo(function ($repo) use(&$repos, $props) { $repos[] = array_intersect_key($repo->getInfo(), $props); }); $repos[] = array_intersect_key($repoGroup->getLocalRepo()->getInfo(), $props); $result = $this->getResult(); ApiResult::setIndexedTagName($repos, 'repo'); ApiResult::setArrayTypeRecursive($repos, 'assoc'); ApiResult::setArrayType($repos, 'array'); $result->addValue(array('query'), 'repos', $repos); }
public function execute() { $conf = $this->getConfig(); $params = $this->extractRequestParams(); $props = array_flip($params['prop']); $repos = []; $repoGroup = $this->getInitialisedRepoGroup(); $foreignTargets = $conf->get('ForeignUploadTargets'); $repoGroup->forEachForeignRepo(function ($repo) use(&$repos, $props, $foreignTargets) { $repoProps = $repo->getInfo(); $repoProps['canUpload'] = in_array($repoProps['name'], $foreignTargets); $repos[] = array_intersect_key($repoProps, $props); }); $localInfo = $repoGroup->getLocalRepo()->getInfo(); $localInfo['canUpload'] = $conf->get('EnableUploads'); $repos[] = array_intersect_key($localInfo, $props); $result = $this->getResult(); ApiResult::setIndexedTagName($repos, 'repo'); ApiResult::setArrayTypeRecursive($repos, 'assoc'); ApiResult::setArrayType($repos, 'array'); $result->addValue(['query'], 'repos', $repos); }
public function execute() { $params = $this->extractRequestParams(); if (!is_null($params['prop'])) { $this->prop = array_flip($params['prop']); } else { $this->prop = []; } $users = (array) $params['users']; $goodNames = $done = []; $result = $this->getResult(); // Canonicalize user names foreach ($users as $u) { $n = User::getCanonicalName($u); if ($n === false || $n === '') { $vals = ['name' => $u, 'invalid' => true]; $fit = $result->addValue(['query', $this->getModuleName()], null, $vals); if (!$fit) { $this->setContinueEnumParameter('users', implode('|', array_diff($users, $done))); $goodNames = []; break; } $done[] = $u; } else { $goodNames[] = $n; } } $result = $this->getResult(); if (count($goodNames)) { $this->addTables('user'); $this->addFields(User::selectFields()); $this->addWhereFld('user_name', $goodNames); $this->showHiddenUsersAddBlockInfo(isset($this->prop['blockinfo'])); $data = []; $res = $this->select(__METHOD__); $this->resetQueryParams(); // get user groups if needed if (isset($this->prop['groups']) || isset($this->prop['rights'])) { $userGroups = []; $this->addTables('user'); $this->addWhereFld('user_name', $goodNames); $this->addTables('user_groups'); $this->addJoinConds(['user_groups' => ['INNER JOIN', 'ug_user=user_id']]); $this->addFields(['user_name', 'ug_group']); $userGroupsRes = $this->select(__METHOD__); foreach ($userGroupsRes as $row) { $userGroups[$row->user_name][] = $row->ug_group; } } foreach ($res as $row) { // create user object and pass along $userGroups if set // that reduces the number of database queries needed in User dramatically if (!isset($userGroups)) { $user = User::newFromRow($row); } else { if (!isset($userGroups[$row->user_name]) || !is_array($userGroups[$row->user_name])) { $userGroups[$row->user_name] = []; } $user = User::newFromRow($row, ['user_groups' => $userGroups[$row->user_name]]); } $name = $user->getName(); $data[$name]['userid'] = $user->getId(); $data[$name]['name'] = $name; if (isset($this->prop['editcount'])) { $data[$name]['editcount'] = $user->getEditCount(); } if (isset($this->prop['registration'])) { $data[$name]['registration'] = wfTimestampOrNull(TS_ISO_8601, $user->getRegistration()); } if (isset($this->prop['groups'])) { $data[$name]['groups'] = $user->getEffectiveGroups(); } if (isset($this->prop['implicitgroups'])) { $data[$name]['implicitgroups'] = $user->getAutomaticGroups(); } if (isset($this->prop['rights'])) { $data[$name]['rights'] = $user->getRights(); } if ($row->ipb_deleted) { $data[$name]['hidden'] = true; } if (isset($this->prop['blockinfo']) && !is_null($row->ipb_by_text)) { $data[$name]['blockid'] = (int) $row->ipb_id; $data[$name]['blockedby'] = $row->ipb_by_text; $data[$name]['blockedbyid'] = (int) $row->ipb_by; $data[$name]['blockedtimestamp'] = wfTimestamp(TS_ISO_8601, $row->ipb_timestamp); $data[$name]['blockreason'] = $row->ipb_reason; $data[$name]['blockexpiry'] = $row->ipb_expiry; } if (isset($this->prop['emailable'])) { $data[$name]['emailable'] = $user->canReceiveEmail(); } if (isset($this->prop['gender'])) { $gender = $user->getOption('gender'); if (strval($gender) === '') { $gender = 'unknown'; } $data[$name]['gender'] = $gender; } if (isset($this->prop['centralids'])) { $data[$name] += ApiQueryUserInfo::getCentralUserInfo($this->getConfig(), $user, $params['attachedwiki']); } if (!is_null($params['token'])) { $tokenFunctions = $this->getTokenFunctions(); foreach ($params['token'] as $t) { $val = call_user_func($tokenFunctions[$t], $user); if ($val === false) { $this->setWarning("Action '{$t}' is not allowed for the current user"); } else { $data[$name][$t . 'token'] = $val; } } } } } $context = $this->getContext(); // Second pass: add result data to $retval foreach ($goodNames as $u) { if (!isset($data[$u])) { $data[$u] = ['name' => $u]; $urPage = new UserrightsPage(); $urPage->setContext($context); $iwUser = $urPage->fetchUser($u); if ($iwUser instanceof UserRightsProxy) { $data[$u]['interwiki'] = true; if (!is_null($params['token'])) { $tokenFunctions = $this->getTokenFunctions(); foreach ($params['token'] as $t) { $val = call_user_func($tokenFunctions[$t], $iwUser); if ($val === false) { $this->setWarning("Action '{$t}' is not allowed for the current user"); } else { $data[$u][$t . 'token'] = $val; } } } } else { $data[$u]['missing'] = true; if (isset($this->prop['cancreate'])) { $status = MediaWiki\Auth\AuthManager::singleton()->canCreateAccount($u); $data[$u]['cancreate'] = $status->isGood(); if (!$status->isGood()) { $data[$u]['cancreateerror'] = $this->getErrorFormatter()->arrayFromStatus($status); } } } } else { if (isset($this->prop['groups']) && isset($data[$u]['groups'])) { ApiResult::setArrayType($data[$u]['groups'], 'array'); ApiResult::setIndexedTagName($data[$u]['groups'], 'g'); } if (isset($this->prop['implicitgroups']) && isset($data[$u]['implicitgroups'])) { ApiResult::setArrayType($data[$u]['implicitgroups'], 'array'); ApiResult::setIndexedTagName($data[$u]['implicitgroups'], 'g'); } if (isset($this->prop['rights']) && isset($data[$u]['rights'])) { ApiResult::setArrayType($data[$u]['rights'], 'array'); ApiResult::setIndexedTagName($data[$u]['rights'], 'r'); } } $fit = $result->addValue(['query', $this->getModuleName()], null, $data[$u]); if (!$fit) { $this->setContinueEnumParameter('users', implode('|', array_diff($users, $done))); break; } $done[] = $u; } $result->addIndexedTagName(['query', $this->getModuleName()], 'user'); }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; if ($title === null) { $titleProvided = false; // A title is needed for parsing, so arbitrarily choose one $title = 'API'; } else { $titleProvided = true; } $page = $params['page']; $pageid = $params['pageid']; $oldid = $params['oldid']; $model = $params['contentmodel']; $format = $params['contentformat']; if (!is_null($page) && (!is_null($text) || $titleProvided)) { $this->dieUsage('The page parameter cannot be used together with the text and title parameters', 'params'); } $prop = array_flip($params['prop']); if (isset($params['section'])) { $this->section = $params['section']; if (!preg_match('/^((T-)?\\d+|new)$/', $this->section)) { $this->dieUsage("The section parameter must be a valid section id or 'new'", "invalidsection"); } } else { $this->section = false; } // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* // TODO: Does this still need $wgTitle? global $wgParser, $wgTitle; $redirValues = null; // Return result $result = $this->getResult(); if (!is_null($oldid) || !is_null($pageid) || !is_null($page)) { if ($this->section === 'new') { $this->dieUsage('section=new cannot be combined with oldid, pageid or page parameters. ' . 'Please use text', 'params'); } if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromId($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT, $this->getUser())) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $titleObj = $rev->getTitle(); $wgTitle = $titleObj; $pageObj = WikiPage::factory($titleObj); $popts = $this->makeParserOptions($pageObj, $params); // If for some reason the "oldid" is actually the current revision, it may be cached // Deliberately comparing $pageObj->getLatest() with $rev->getId(), rather than // checking $rev->isCurrent(), because $pageObj is what actually ends up being used, // and if its ->getLatest() is outdated, $rev->isCurrent() won't tell us that. if ($rev->getId() == $pageObj->getLatest()) { // May get from/save to parser cache $p_result = $this->getParsedContent($pageObj, $popts, $pageid, isset($prop['wikitext'])); } else { // This is an old revision, so get the text differently $this->content = $rev->getContent(Revision::FOR_THIS_USER, $this->getUser()); if ($this->section !== false) { $this->content = $this->getSectionContent($this->content, 'r' . $rev->getId()); } // Should we save old revision parses to the parser cache? $p_result = $this->content->getParserOutput($titleObj, $rev->getId(), $popts); } } else { // Not $oldid, but $pageid or $page if ($params['redirects']) { $reqParams = array('redirects' => ''); if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; } else { // $page $reqParams['titles'] = $page; } $req = new FauxRequest($reqParams); $main = new ApiMain($req); $pageSet = new ApiPageSet($main); $pageSet->execute(); $redirValues = $pageSet->getRedirectTitlesAsResult($this->getResult()); $to = $page; foreach ($pageSet->getRedirectTitles() as $title) { $to = $title->getFullText(); } $pageParams = array('title' => $to); } elseif (!is_null($pageid)) { $pageParams = array('pageid' => $pageid); } else { // $page $pageParams = array('title' => $page); } $pageObj = $this->getTitleOrPageId($pageParams, 'fromdb'); $titleObj = $pageObj->getTitle(); if (!$titleObj || !$titleObj->exists()) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $wgTitle = $titleObj; if (isset($prop['revid'])) { $oldid = $pageObj->getLatest(); } $popts = $this->makeParserOptions($pageObj, $params); // Don't pollute the parser cache when setting options that aren't // in ParserOptions::optionsHash() /// @todo: This should be handled closer to the actual cache instead of here, see T110269 $suppressCache = $params['disablepp'] || $params['disablelimitreport'] || $params['preview'] || $params['sectionpreview'] || $params['disabletidy']; if ($suppressCache) { $this->content = $this->getContent($pageObj, $pageid); $p_result = $this->content->getParserOutput($titleObj, null, $popts); } else { // Potentially cached $p_result = $this->getParsedContent($pageObj, $popts, $pageid, isset($prop['wikitext'])); } } } else { // Not $oldid, $pageid, $page. Hence based on $text $titleObj = Title::newFromText($title); if (!$titleObj || $titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $title)); } $wgTitle = $titleObj; if ($titleObj->canExist()) { $pageObj = WikiPage::factory($titleObj); } else { // Do like MediaWiki::initializeArticle() $article = Article::newFromTitle($titleObj, $this->getContext()); $pageObj = $article->getPage(); } $popts = $this->makeParserOptions($pageObj, $params); $textProvided = !is_null($text); if (!$textProvided) { if ($titleProvided && ($prop || $params['generatexml'])) { $this->setWarning("'title' used without 'text', and parsed page properties were requested " . "(did you mean to use 'page' instead of 'title'?)"); } // Prevent warning from ContentHandler::makeContent() $text = ''; } // If we are parsing text, do not use the content model of the default // API title, but default to wikitext to keep BC. if ($textProvided && !$titleProvided && is_null($model)) { $model = CONTENT_MODEL_WIKITEXT; $this->setWarning("No 'title' or 'contentmodel' was given, assuming {$model}."); } try { $this->content = ContentHandler::makeContent($text, $titleObj, $model, $format); } catch (MWContentSerializationException $ex) { $this->dieUsage($ex->getMessage(), 'parseerror'); } if ($this->section !== false) { if ($this->section === 'new') { // Insert the section title above the content. if (!is_null($params['sectiontitle']) && $params['sectiontitle'] !== '') { $this->content = $this->content->addSectionHeader($params['sectiontitle']); } } else { $this->content = $this->getSectionContent($this->content, $titleObj->getPrefixedText()); } } if ($params['pst'] || $params['onlypst']) { $this->pstContent = $this->content->preSaveTransform($titleObj, $this->getUser(), $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array = array(); $result_array['text'] = $this->pstContent->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text'; if (isset($prop['wikitext'])) { $result_array['wikitext'] = $this->content->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext'; } if (!is_null($params['summary']) || !is_null($params['sectiontitle']) && $this->section === 'new') { $result_array['parsedsummary'] = $this->formatSummary($titleObj, $params); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary'; } $result->addValue(null, $this->getModuleName(), $result_array); return; } // Not cached (save or load) if ($params['pst']) { $p_result = $this->pstContent->getParserOutput($titleObj, null, $popts); } else { $p_result = $this->content->getParserOutput($titleObj, null, $popts); } } $result_array = array(); $result_array['title'] = $titleObj->getPrefixedText(); $result_array['pageid'] = $pageid ? $pageid : $pageObj->getId(); if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if ($params['disabletoc']) { $p_result->setTOCEnabled(false); } if (isset($prop['text'])) { $result_array['text'] = $p_result->getText(); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text'; } if (!is_null($params['summary']) || !is_null($params['sectiontitle']) && $this->section === 'new') { $result_array['parsedsummary'] = $this->formatSummary($titleObj, $params); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary'; } if (isset($prop['langlinks'])) { $langlinks = $p_result->getLanguageLinks(); if ($params['effectivelanglinks']) { // Link flags are ignored for now, but may in the future be // included in the result. $linkFlags = array(); Hooks::run('LanguageLinks', array($titleObj, &$langlinks, &$linkFlags)); } } else { $langlinks = false; } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($langlinks); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['categorieshtml'])) { $result_array['categorieshtml'] = $this->categoriesHtml($p_result->getCategories()); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'categorieshtml'; } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems']) || isset($prop['headhtml'])) { $context = $this->getContext(); $context->setTitle($titleObj); $context->getOutput()->addParserOutputMetadata($p_result); if (isset($prop['headitems'])) { $headItems = $this->formatHeadItems($p_result->getHeadItems()); $css = $this->formatCss($context->getOutput()->buildCssLinksArray()); $scripts = array($context->getOutput()->getHeadScripts()); $result_array['headitems'] = array_merge($headItems, $css, $scripts); } if (isset($prop['headhtml'])) { $result_array['headhtml'] = $context->getOutput()->headElement($context->getSkin()); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml'; } } if (isset($prop['modules'])) { $result_array['modules'] = array_values(array_unique($p_result->getModules())); $result_array['modulescripts'] = array_values(array_unique($p_result->getModuleScripts())); $result_array['modulestyles'] = array_values(array_unique($p_result->getModuleStyles())); // To be removed in 1.27 $result_array['modulemessages'] = array(); $this->setWarning('modulemessages is deprecated since MediaWiki 1.26'); } if (isset($prop['jsconfigvars'])) { $result_array['jsconfigvars'] = ApiResult::addMetadataToResultVars($p_result->getJsConfigVars()); } if (isset($prop['encodedjsconfigvars'])) { $result_array['encodedjsconfigvars'] = FormatJson::encode($p_result->getJsConfigVars(), false, FormatJson::ALL_OK); $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars'; } if (isset($prop['modules']) && !isset($prop['jsconfigvars']) && !isset($prop['encodedjsconfigvars'])) { $this->setWarning("Property 'modules' was set but not 'jsconfigvars' " . "or 'encodedjsconfigvars'. Configuration variables are necessary " . "for proper module usage."); } if (isset($prop['indicators'])) { $result_array['indicators'] = (array) $p_result->getIndicators(); ApiResult::setArrayType($result_array['indicators'], 'BCkvp', 'name'); } if (isset($prop['iwlinks'])) { $result_array['iwlinks'] = $this->formatIWLinks($p_result->getInterwikiLinks()); } if (isset($prop['wikitext'])) { $result_array['wikitext'] = $this->content->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext'; if (!is_null($this->pstContent)) { $result_array['psttext'] = $this->pstContent->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'psttext'; } } if (isset($prop['properties'])) { $result_array['properties'] = (array) $p_result->getProperties(); ApiResult::setArrayType($result_array['properties'], 'BCkvp', 'name'); } if (isset($prop['limitreportdata'])) { $result_array['limitreportdata'] = $this->formatLimitReportData($p_result->getLimitReportData()); } if (isset($prop['limitreporthtml'])) { $result_array['limitreporthtml'] = EditPage::getPreviewLimitReport($p_result); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml'; } if (isset($prop['parsetree']) || $params['generatexml']) { if ($this->content->getModel() != CONTENT_MODEL_WIKITEXT) { $this->dieUsage("parsetree is only supported for wikitext content", "notwikitext"); } $wgParser->startExternalParse($titleObj, $popts, Parser::OT_PREPROCESS); $dom = $wgParser->preprocessToDom($this->content->getNativeData()); if (is_callable(array($dom, 'saveXML'))) { $xml = $dom->saveXML(); } else { $xml = $dom->__toString(); } $result_array['parsetree'] = $xml; $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree'; } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'iwlinks' => 'iw', 'sections' => 's', 'headitems' => 'hi', 'modules' => 'm', 'indicators' => 'ind', 'modulescripts' => 'm', 'modulestyles' => 'm', 'modulemessages' => 'm', 'properties' => 'pp', 'limitreportdata' => 'lr'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); }
/** * @dataProvider provideApiParamFormatting * @covers LogFormatter::formatParametersForApi * @covers LogFormatter::formatParameterValueForApi */ public function testApiParamFormatting($key, $value, $expected) { $entry = $this->newLogEntry('param', array($key => $value)); $formatter = LogFormatter::newFromEntry($entry); $formatter->setContext($this->context); ApiResult::setIndexedTagName($expected, 'param'); ApiResult::setArrayType($expected, 'assoc'); $this->assertEquals($expected, $formatter->formatParametersForApi()); }
protected function getCurrentUserInfo() { $user = $this->getUser(); $result = $this->getResult(); $vals = array(); $vals['id'] = intval($user->getId()); $vals['name'] = $user->getName(); if ($user->isAnon()) { $vals['anon'] = true; } if (isset($this->prop['blockinfo'])) { if ($user->isBlocked()) { $block = $user->getBlock(); $vals['blockid'] = $block->getId(); $vals['blockedby'] = $block->getByName(); $vals['blockedbyid'] = $block->getBy(); $vals['blockreason'] = $user->blockedFor(); $vals['blockedtimestamp'] = wfTimestamp(TS_ISO_8601, $block->mTimestamp); $vals['blockexpiry'] = $block->getExpiry() === 'infinity' ? 'infinite' : wfTimestamp(TS_ISO_8601, $block->getExpiry()); } } if (isset($this->prop['hasmsg'])) { $vals['messages'] = $user->getNewtalk(); } if (isset($this->prop['groups'])) { $vals['groups'] = $user->getEffectiveGroups(); ApiResult::setArrayType($vals['groups'], 'array'); // even if empty ApiResult::setIndexedTagName($vals['groups'], 'g'); // even if empty } if (isset($this->prop['implicitgroups'])) { $vals['implicitgroups'] = $user->getAutomaticGroups(); ApiResult::setArrayType($vals['implicitgroups'], 'array'); // even if empty ApiResult::setIndexedTagName($vals['implicitgroups'], 'g'); // even if empty } if (isset($this->prop['rights'])) { // User::getRights() may return duplicate values, strip them $vals['rights'] = array_values(array_unique($user->getRights())); ApiResult::setArrayType($vals['rights'], 'array'); // even if empty ApiResult::setIndexedTagName($vals['rights'], 'r'); // even if empty } if (isset($this->prop['changeablegroups'])) { $vals['changeablegroups'] = $user->changeableGroups(); ApiResult::setIndexedTagName($vals['changeablegroups']['add'], 'g'); ApiResult::setIndexedTagName($vals['changeablegroups']['remove'], 'g'); ApiResult::setIndexedTagName($vals['changeablegroups']['add-self'], 'g'); ApiResult::setIndexedTagName($vals['changeablegroups']['remove-self'], 'g'); } if (isset($this->prop['options'])) { $vals['options'] = $user->getOptions(); $vals['options'][ApiResult::META_BC_BOOLS] = array_keys($vals['options']); } if (isset($this->prop['preferencestoken'])) { $p = $this->getModulePrefix(); $this->setWarning("{$p}prop=preferencestoken has been deprecated. Please use action=query&meta=tokens instead."); } if (isset($this->prop['preferencestoken']) && !$this->lacksSameOriginSecurity() && $user->isAllowed('editmyoptions')) { $vals['preferencestoken'] = $user->getEditToken('', $this->getMain()->getRequest()); } if (isset($this->prop['editcount'])) { // use intval to prevent null if a non-logged-in user calls // api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount $vals['editcount'] = intval($user->getEditCount()); } if (isset($this->prop['ratelimits'])) { $vals['ratelimits'] = $this->getRateLimits(); } if (isset($this->prop['realname']) && !in_array('realname', $this->getConfig()->get('HiddenPrefs'))) { $vals['realname'] = $user->getRealName(); } if ($user->isAllowed('viewmyprivateinfo')) { if (isset($this->prop['email'])) { $vals['email'] = $user->getEmail(); $auth = $user->getEmailAuthenticationTimestamp(); if (!is_null($auth)) { $vals['emailauthenticated'] = wfTimestamp(TS_ISO_8601, $auth); } } } if (isset($this->prop['registrationdate'])) { $regDate = $user->getRegistration(); if ($regDate !== false) { $vals['registrationdate'] = wfTimestamp(TS_ISO_8601, $regDate); } } if (isset($this->prop['acceptlang'])) { $langs = $this->getRequest()->getAcceptLang(); $acceptLang = array(); foreach ($langs as $lang => $val) { $r = array('q' => $val); ApiResult::setContentValue($r, 'code', $lang); $acceptLang[] = $r; } ApiResult::setIndexedTagName($acceptLang, 'lang'); $vals['acceptlang'] = $acceptLang; } if (isset($this->prop['unreadcount'])) { $dbr = $this->getQuery()->getNamedDB('watchlist', DB_SLAVE, 'watchlist'); $count = $dbr->selectRowCount('watchlist', '1', array('wl_user' => $user->getId(), 'wl_notificationtimestamp IS NOT NULL'), __METHOD__, array('LIMIT' => self::WL_UNREAD_LIMIT)); if ($count >= self::WL_UNREAD_LIMIT) { $vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+'; } else { $vals['unreadcount'] = $count; } } return $vals; }
public function execute() { // Cache may vary on $wgUser because ParserOptions gets data from it $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $this->requireMaxOneParameter($params, 'prop', 'generatexml'); if ($params['prop'] === null) { $this->logFeatureUsage('action=expandtemplates&!prop'); $this->setWarning('Because no values have been specified for the prop parameter, a ' . 'legacy format has been used for the output. This format is deprecated, and in ' . 'the future, a default value will be set for the prop parameter, causing the new' . 'format to always be used.'); $prop = array(); } else { $prop = array_flip($params['prop']); } // Get title and revision ID for parser $revid = $params['revid']; if ($revid !== null) { $rev = Revision::newFromId($revid); if (!$rev) { $this->dieUsage("There is no revision ID {$revid}", 'missingrev'); } $title_obj = $rev->getTitle(); } else { $title_obj = Title::newFromText($params['title']); if (!$title_obj || $title_obj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $params['title'])); } } $result = $this->getResult(); // Parse text global $wgParser; $options = ParserOptions::newFromContext($this->getContext()); if ($params['includecomments']) { $options->setRemoveComments(false); } $retval = array(); if (isset($prop['parsetree']) || $params['generatexml']) { if (!isset($prop['parsetree'])) { $this->logFeatureUsage('action=expandtemplates&generatexml'); } $wgParser->startExternalParse($title_obj, $options, Parser::OT_PREPROCESS); $dom = $wgParser->preprocessToDom($params['text']); if (is_callable(array($dom, 'saveXML'))) { $xml = $dom->saveXML(); } else { $xml = $dom->__toString(); } if (isset($prop['parsetree'])) { unset($prop['parsetree']); $retval['parsetree'] = $xml; } else { // the old way $result->addValue(null, 'parsetree', $xml); $result->addValue(null, ApiResult::META_BC_SUBELEMENTS, array('parsetree')); } } // if they didn't want any output except (probably) the parse tree, // then don't bother actually fully expanding it if ($prop || $params['prop'] === null) { $wgParser->startExternalParse($title_obj, $options, Parser::OT_PREPROCESS); $frame = $wgParser->getPreprocessor()->newFrame(); $wikitext = $wgParser->preprocess($params['text'], $title_obj, $options, $revid, $frame); if ($params['prop'] === null) { // the old way ApiResult::setContentValue($retval, 'wikitext', $wikitext); } else { if (isset($prop['categories'])) { $categories = $wgParser->getOutput()->getCategories(); if ($categories) { $categories_result = array(); foreach ($categories as $category => $sortkey) { $entry = array(); $entry['sortkey'] = $sortkey; ApiResult::setContentValue($entry, 'category', $category); $categories_result[] = $entry; } ApiResult::setIndexedTagName($categories_result, 'category'); $retval['categories'] = $categories_result; } } if (isset($prop['properties'])) { $properties = $wgParser->getOutput()->getProperties(); if ($properties) { ApiResult::setArrayType($properties, 'BCkvp', 'name'); ApiResult::setIndexedTagName($properties, 'property'); $retval['properties'] = $properties; } } if (isset($prop['volatile'])) { $retval['volatile'] = $frame->isVolatile(); } if (isset($prop['ttl']) && $frame->getTTL() !== null) { $retval['ttl'] = $frame->getTTL(); } if (isset($prop['wikitext'])) { $retval['wikitext'] = $wikitext; } } } ApiResult::setSubelementsList($retval, array('wikitext', 'parsetree')); $result->addValue(null, $this->getModuleName(), $retval); }
protected function appendGeneralInfo($property) { global $wgContLang; $config = $this->getConfig(); $data = array(); $mainPage = Title::newMainPage(); $data['mainpage'] = $mainPage->getPrefixedText(); $data['base'] = wfExpandUrl($mainPage->getFullURL(), PROTO_CURRENT); $data['sitename'] = $config->get('Sitename'); // wgLogo can either be a relative or an absolute path // make sure we always return an absolute path $data['logo'] = wfExpandUrl($config->get('Logo'), PROTO_RELATIVE); $data['generator'] = "MediaWiki {$config->get('Version')}"; $data['phpversion'] = PHP_VERSION; $data['phpsapi'] = PHP_SAPI; if (defined('HHVM_VERSION')) { $data['hhvmversion'] = HHVM_VERSION; } $data['dbtype'] = $config->get('DBtype'); $data['dbversion'] = $this->getDB()->getServerVersion(); $allowFrom = array(''); $allowException = true; if (!$config->get('AllowExternalImages')) { $data['imagewhitelistenabled'] = (bool) $config->get('EnableImageWhitelist'); $allowFrom = $config->get('AllowExternalImagesFrom'); $allowException = !empty($allowFrom); } if ($allowException) { $data['externalimages'] = (array) $allowFrom; ApiResult::setIndexedTagName($data['externalimages'], 'prefix'); } $data['langconversion'] = !$config->get('DisableLangConversion'); $data['titleconversion'] = !$config->get('DisableTitleConversion'); if ($wgContLang->linkPrefixExtension()) { $linkPrefixCharset = $wgContLang->linkPrefixCharset(); $data['linkprefixcharset'] = $linkPrefixCharset; // For backwards compatibility $data['linkprefix'] = "/^((?>.*[^{$linkPrefixCharset}]|))(.+)\$/sDu"; } else { $data['linkprefixcharset'] = ''; $data['linkprefix'] = ''; } $linktrail = $wgContLang->linkTrail(); $data['linktrail'] = $linktrail ?: ''; $data['legaltitlechars'] = Title::legalChars(); global $IP; $git = SpecialVersion::getGitHeadSha1($IP); if ($git) { $data['git-hash'] = $git; $data['git-branch'] = SpecialVersion::getGitCurrentBranch($GLOBALS['IP']); } else { $svn = SpecialVersion::getSvnRevision($IP); if ($svn) { $data['rev'] = $svn; } } // 'case-insensitive' option is reserved for future $data['case'] = $config->get('CapitalLinks') ? 'first-letter' : 'case-sensitive'; $data['lang'] = $config->get('LanguageCode'); $fallbacks = array(); foreach ($wgContLang->getFallbackLanguages() as $code) { $fallbacks[] = array('code' => $code); } $data['fallback'] = $fallbacks; ApiResult::setIndexedTagName($data['fallback'], 'lang'); if ($wgContLang->hasVariants()) { $variants = array(); foreach ($wgContLang->getVariants() as $code) { $variants[] = array('code' => $code, 'name' => $wgContLang->getVariantname($code)); } $data['variants'] = $variants; ApiResult::setIndexedTagName($data['variants'], 'lang'); } $data['rtl'] = $wgContLang->isRTL(); $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding(); $data['readonly'] = wfReadOnly(); if ($data['readonly']) { $data['readonlyreason'] = wfReadOnlyReason(); } $data['writeapi'] = (bool) $config->get('EnableWriteAPI'); $tz = $config->get('Localtimezone'); $offset = $config->get('LocalTZoffset'); if (is_null($tz)) { $tz = 'UTC'; $offset = 0; } elseif (is_null($offset)) { $offset = 0; } $data['timezone'] = $tz; $data['timeoffset'] = intval($offset); $data['articlepath'] = $config->get('ArticlePath'); $data['scriptpath'] = $config->get('ScriptPath'); $data['script'] = $config->get('Script'); $data['variantarticlepath'] = $config->get('VariantArticlePath'); $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath'; $data['server'] = $config->get('Server'); $data['servername'] = $config->get('ServerName'); $data['wikiid'] = wfWikiID(); $data['time'] = wfTimestamp(TS_ISO_8601, time()); $data['misermode'] = (bool) $config->get('MiserMode'); $data['maxuploadsize'] = UploadBase::getMaxUploadSize(); $data['minuploadchunksize'] = (int) $this->getConfig()->get('MinUploadChunkSize'); $data['thumblimits'] = $config->get('ThumbLimits'); ApiResult::setArrayType($data['thumblimits'], 'BCassoc'); ApiResult::setIndexedTagName($data['thumblimits'], 'limit'); $data['imagelimits'] = array(); ApiResult::setArrayType($data['imagelimits'], 'BCassoc'); ApiResult::setIndexedTagName($data['imagelimits'], 'limit'); foreach ($config->get('ImageLimits') as $k => $limit) { $data['imagelimits'][$k] = array('width' => $limit[0], 'height' => $limit[1]); } $favicon = $config->get('Favicon'); if (!empty($favicon)) { // wgFavicon can either be a relative or an absolute path // make sure we always return an absolute path $data['favicon'] = wfExpandUrl($favicon, PROTO_RELATIVE); } Hooks::run('APIQuerySiteInfoGeneralInfo', array($this, &$data)); return $this->getResult()->addValue('query', $property, $data); }
public function appendSubscribedHooks($property) { $hooks = $this->getConfig()->get('Hooks'); $myWgHooks = $hooks; ksort($myWgHooks); $data = array(); foreach ($myWgHooks as $name => $subscribers) { $arr = array('name' => $name, 'subscribers' => array_map(array('SpecialVersion', 'arrayToString'), $subscribers)); ApiResult::setArrayType($arr['subscribers'], 'array'); ApiResult::setIndexedTagName($arr['subscribers'], 's'); $data[] = $arr; } ApiResult::setIndexedTagName($data, 'hook'); return $this->getResult()->addValue('query', $property, $data); }
public function execute() { $params = $this->extractRequestParams(); $activeUserDays = $this->getConfig()->get('ActiveUserDays'); $db = $this->getDB(); $prop = $params['prop']; if (!is_null($prop)) { $prop = array_flip($prop); $fld_blockinfo = isset($prop['blockinfo']); $fld_editcount = isset($prop['editcount']); $fld_groups = isset($prop['groups']); $fld_rights = isset($prop['rights']); $fld_registration = isset($prop['registration']); $fld_implicitgroups = isset($prop['implicitgroups']); $fld_centralids = isset($prop['centralids']); } else { $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = $fld_implicitgroups = $fld_centralids = false; } $limit = $params['limit']; $this->addTables('user'); $dir = $params['dir'] == 'descending' ? 'older' : 'newer'; $from = is_null($params['from']) ? null : $this->getCanonicalUserName($params['from']); $to = is_null($params['to']) ? null : $this->getCanonicalUserName($params['to']); # MySQL can't figure out that 'user_name' and 'qcc_title' are the same # despite the JOIN condition, so manually sort on the correct one. $userFieldToSort = $params['activeusers'] ? 'qcc_title' : 'user_name'; # Some of these subtable joins are going to give us duplicate rows, so # calculate the maximum number of duplicates we might see. $maxDuplicateRows = 1; $this->addWhereRange($userFieldToSort, $dir, $from, $to); if (!is_null($params['prefix'])) { $this->addWhere($userFieldToSort . $db->buildLike($this->getCanonicalUserName($params['prefix']), $db->anyString())); } if (!is_null($params['rights']) && count($params['rights'])) { $groups = array(); foreach ($params['rights'] as $r) { $groups = array_merge($groups, User::getGroupsWithPermission($r)); } // no group with the given right(s) exists, no need for a query if (!count($groups)) { $this->getResult()->addIndexedTagName(array('query', $this->getModuleName()), ''); return; } $groups = array_unique($groups); if (is_null($params['group'])) { $params['group'] = $groups; } else { $params['group'] = array_unique(array_merge($params['group'], $groups)); } } if (!is_null($params['group']) && !is_null($params['excludegroup'])) { $this->dieUsage('group and excludegroup cannot be used together', 'group-excludegroup'); } if (!is_null($params['group']) && count($params['group'])) { // Filter only users that belong to a given group. This might // produce as many rows-per-user as there are groups being checked. $this->addTables('user_groups', 'ug1'); $this->addJoinConds(array('ug1' => array('INNER JOIN', array('ug1.ug_user=user_id', 'ug1.ug_group' => $params['group'])))); $maxDuplicateRows *= count($params['group']); } if (!is_null($params['excludegroup']) && count($params['excludegroup'])) { // Filter only users don't belong to a given group. This can only // produce one row-per-user, because we only keep on "no match". $this->addTables('user_groups', 'ug1'); if (count($params['excludegroup']) == 1) { $exclude = array('ug1.ug_group' => $params['excludegroup'][0]); } else { $exclude = array($db->makeList(array('ug1.ug_group' => $params['excludegroup']), LIST_OR)); } $this->addJoinConds(array('ug1' => array('LEFT OUTER JOIN', array_merge(array('ug1.ug_user=user_id'), $exclude)))); $this->addWhere('ug1.ug_user IS NULL'); } if ($params['witheditsonly']) { $this->addWhere('user_editcount > 0'); } $this->showHiddenUsersAddBlockInfo($fld_blockinfo); if ($fld_groups || $fld_rights) { $this->addFields(array('groups' => $db->buildGroupConcatField('|', 'user_groups', 'ug_group', 'ug_user=user_id'))); } if ($params['activeusers']) { $activeUserSeconds = $activeUserDays * 86400; // Filter query to only include users in the active users cache. // There shouldn't be any duplicate rows in querycachetwo here. $this->addTables('querycachetwo'); $this->addJoinConds(array('querycachetwo' => array('INNER JOIN', array('qcc_type' => 'activeusers', 'qcc_namespace' => NS_USER, 'qcc_title=user_name')))); // Actually count the actions using a subquery (bug 64505 and bug 64507) $timestamp = $db->timestamp(wfTimestamp(TS_UNIX) - $activeUserSeconds); $this->addFields(array('recentactions' => '(' . $db->selectSQLText('recentchanges', 'COUNT(*)', array('rc_user_text = user_name', 'rc_type != ' . $db->addQuotes(RC_EXTERNAL), 'rc_log_type IS NULL OR rc_log_type != ' . $db->addQuotes('newusers'), 'rc_timestamp >= ' . $db->addQuotes($timestamp))) . ')')); } $sqlLimit = $limit + $maxDuplicateRows; $this->addOption('LIMIT', $sqlLimit); $this->addFields(array('user_name', 'user_id')); $this->addFieldsIf('user_editcount', $fld_editcount); $this->addFieldsIf('user_registration', $fld_registration); $res = $this->select(__METHOD__); $count = 0; $countDuplicates = 0; $lastUser = false; $result = $this->getResult(); foreach ($res as $row) { $count++; if ($lastUser === $row->user_name) { // Duplicate row due to one of the needed subtable joins. // Ignore it, but count the number of them to sanely handle // miscalculation of $maxDuplicateRows. $countDuplicates++; if ($countDuplicates == $maxDuplicateRows) { ApiBase::dieDebug(__METHOD__, 'Saw more duplicate rows than expected'); } continue; } $countDuplicates = 0; $lastUser = $row->user_name; if ($count > $limit) { // We've reached the one extra which shows that there are // additional pages to be had. Stop here... $this->setContinueEnumParameter('from', $row->user_name); break; } if ($count == $sqlLimit) { // Should never hit this (either the $countDuplicates check or // the $count > $limit check should hit first), but check it // anyway just in case. ApiBase::dieDebug(__METHOD__, 'Saw more duplicate rows than expected'); } if ($params['activeusers'] && $row->recentactions === 0) { // activeusers cache was out of date continue; } $data = array('userid' => (int) $row->user_id, 'name' => $row->user_name); if ($fld_centralids) { $data += ApiQueryUserInfo::getCentralUserInfo($this->getConfig(), User::newFromId($row->user_id), $params['attachedwiki']); } if ($fld_blockinfo && !is_null($row->ipb_by_text)) { $data['blockid'] = (int) $row->ipb_id; $data['blockedby'] = $row->ipb_by_text; $data['blockedbyid'] = (int) $row->ipb_by; $data['blockedtimestamp'] = wfTimestamp(TS_ISO_8601, $row->ipb_timestamp); $data['blockreason'] = $row->ipb_reason; $data['blockexpiry'] = $row->ipb_expiry; } if ($row->ipb_deleted) { $data['hidden'] = true; } if ($fld_editcount) { $data['editcount'] = intval($row->user_editcount); } if ($params['activeusers']) { $data['recentactions'] = intval($row->recentactions); // @todo 'recenteditcount' is set for BC, remove in 1.25 $data['recenteditcount'] = $data['recentactions']; } if ($fld_registration) { $data['registration'] = $row->user_registration ? wfTimestamp(TS_ISO_8601, $row->user_registration) : ''; } if ($fld_implicitgroups || $fld_groups || $fld_rights) { $implicitGroups = User::newFromId($row->user_id)->getAutomaticGroups(); if (isset($row->groups) && $row->groups !== '') { $groups = array_merge($implicitGroups, explode('|', $row->groups)); } else { $groups = $implicitGroups; } if ($fld_groups) { $data['groups'] = $groups; ApiResult::setIndexedTagName($data['groups'], 'g'); ApiResult::setArrayType($data['groups'], 'array'); } if ($fld_implicitgroups) { $data['implicitgroups'] = $implicitGroups; ApiResult::setIndexedTagName($data['implicitgroups'], 'g'); ApiResult::setArrayType($data['implicitgroups'], 'array'); } if ($fld_rights) { $data['rights'] = User::getGroupPermissions($groups); ApiResult::setIndexedTagName($data['rights'], 'r'); ApiResult::setArrayType($data['rights'], 'array'); } } $fit = $result->addValue(array('query', $this->getModuleName()), null, $data); if (!$fit) { $this->setContinueEnumParameter('from', $data['name']); break; } } $result->addIndexedTagName(array('query', $this->getModuleName()), 'u'); }
/** * Appends an element for each page in the current pageSet with the * most general information (id, title), plus any title normalizations * and missing or invalid title/pageids/revids. */ private function outputGeneralPageInfo() { $pageSet = $this->getPageSet(); $result = $this->getResult(); // We can't really handle max-result-size failure here, but we need to // check anyway in case someone set the limit stupidly low. $fit = true; $values = $pageSet->getNormalizedTitlesAsResult($result); if ($values) { $fit = $fit && $result->addValue('query', 'normalized', $values); } $values = $pageSet->getConvertedTitlesAsResult($result); if ($values) { $fit = $fit && $result->addValue('query', 'converted', $values); } $values = $pageSet->getInterwikiTitlesAsResult($result, $this->mParams['iwurl']); if ($values) { $fit = $fit && $result->addValue('query', 'interwiki', $values); } $values = $pageSet->getRedirectTitlesAsResult($result); if ($values) { $fit = $fit && $result->addValue('query', 'redirects', $values); } $values = $pageSet->getMissingRevisionIDsAsResult($result); if ($values) { $fit = $fit && $result->addValue('query', 'badrevids', $values); } // Page elements $pages = array(); // Report any missing titles foreach ($pageSet->getMissingTitles() as $fakeId => $title) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); $vals['missing'] = true; $pages[$fakeId] = $vals; } // Report any invalid titles foreach ($pageSet->getInvalidTitlesAndReasons() as $fakeId => $data) { $pages[$fakeId] = $data + array('invalid' => true); } // Report any missing page ids foreach ($pageSet->getMissingPageIDs() as $pageid) { $pages[$pageid] = array('pageid' => $pageid, 'missing' => true); } // Report special pages /** @var $title Title */ foreach ($pageSet->getSpecialTitles() as $fakeId => $title) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); $vals['special'] = true; if ($title->isSpecialPage() && !SpecialPageFactory::exists($title->getDBkey())) { $vals['missing'] = true; } elseif ($title->getNamespace() == NS_MEDIA && !wfFindFile($title)) { $vals['missing'] = true; } $pages[$fakeId] = $vals; } // Output general page information for found titles foreach ($pageSet->getGoodTitles() as $pageid => $title) { $vals = array(); $vals['pageid'] = $pageid; ApiQueryBase::addTitleInfo($vals, $title); $pages[$pageid] = $vals; } if (count($pages)) { $pageSet->populateGeneratorData($pages); ApiResult::setArrayType($pages, 'BCarray'); if ($this->mParams['indexpageids']) { $pageIDs = array_keys(ApiResult::stripMetadataNonRecursive($pages)); // json treats all map keys as strings - converting to match $pageIDs = array_map('strval', $pageIDs); ApiResult::setIndexedTagName($pageIDs, 'id'); $fit = $fit && $result->addValue('query', 'pageids', $pageIDs); } ApiResult::setIndexedTagName($pages, 'page'); $fit = $fit && $result->addValue('query', 'pages', $pages); } if (!$fit) { $this->dieUsage('The value of $wgAPIMaxResultSize on this wiki is ' . 'too small to hold basic result information', 'badconfig'); } if ($this->mParams['export']) { $this->doExport($pageSet, $result); } }
protected function getCurrentUserInfo() { $user = $this->getUser(); $vals = []; $vals['id'] = intval($user->getId()); $vals['name'] = $user->getName(); if ($user->isAnon()) { $vals['anon'] = true; } if (isset($this->prop['blockinfo']) && $user->isBlocked()) { $vals = array_merge($vals, self::getBlockInfo($user->getBlock())); } if (isset($this->prop['hasmsg'])) { $vals['messages'] = $user->getNewtalk(); } if (isset($this->prop['groups'])) { $vals['groups'] = $user->getEffectiveGroups(); ApiResult::setArrayType($vals['groups'], 'array'); // even if empty ApiResult::setIndexedTagName($vals['groups'], 'g'); // even if empty } if (isset($this->prop['implicitgroups'])) { $vals['implicitgroups'] = $user->getAutomaticGroups(); ApiResult::setArrayType($vals['implicitgroups'], 'array'); // even if empty ApiResult::setIndexedTagName($vals['implicitgroups'], 'g'); // even if empty } if (isset($this->prop['rights'])) { // User::getRights() may return duplicate values, strip them $vals['rights'] = array_values(array_unique($user->getRights())); ApiResult::setArrayType($vals['rights'], 'array'); // even if empty ApiResult::setIndexedTagName($vals['rights'], 'r'); // even if empty } if (isset($this->prop['changeablegroups'])) { $vals['changeablegroups'] = $user->changeableGroups(); ApiResult::setIndexedTagName($vals['changeablegroups']['add'], 'g'); ApiResult::setIndexedTagName($vals['changeablegroups']['remove'], 'g'); ApiResult::setIndexedTagName($vals['changeablegroups']['add-self'], 'g'); ApiResult::setIndexedTagName($vals['changeablegroups']['remove-self'], 'g'); } if (isset($this->prop['options'])) { $vals['options'] = $user->getOptions(); $vals['options'][ApiResult::META_BC_BOOLS] = array_keys($vals['options']); } if (isset($this->prop['preferencestoken'])) { $p = $this->getModulePrefix(); $this->setWarning("{$p}prop=preferencestoken has been deprecated. Please use action=query&meta=tokens instead."); } if (isset($this->prop['preferencestoken']) && !$this->lacksSameOriginSecurity() && $user->isAllowed('editmyoptions')) { $vals['preferencestoken'] = $user->getEditToken('', $this->getMain()->getRequest()); } if (isset($this->prop['editcount'])) { // use intval to prevent null if a non-logged-in user calls // api.php?format=jsonfm&action=query&meta=userinfo&uiprop=editcount $vals['editcount'] = intval($user->getEditCount()); } if (isset($this->prop['ratelimits'])) { $vals['ratelimits'] = $this->getRateLimits(); } if (isset($this->prop['realname']) && !in_array('realname', $this->getConfig()->get('HiddenPrefs'))) { $vals['realname'] = $user->getRealName(); } if ($user->isAllowed('viewmyprivateinfo')) { if (isset($this->prop['email'])) { $vals['email'] = $user->getEmail(); $auth = $user->getEmailAuthenticationTimestamp(); if (!is_null($auth)) { $vals['emailauthenticated'] = wfTimestamp(TS_ISO_8601, $auth); } } } if (isset($this->prop['registrationdate'])) { $regDate = $user->getRegistration(); if ($regDate !== false) { $vals['registrationdate'] = wfTimestamp(TS_ISO_8601, $regDate); } } if (isset($this->prop['acceptlang'])) { $langs = $this->getRequest()->getAcceptLang(); $acceptLang = []; foreach ($langs as $lang => $val) { $r = ['q' => $val]; ApiResult::setContentValue($r, 'code', $lang); $acceptLang[] = $r; } ApiResult::setIndexedTagName($acceptLang, 'lang'); $vals['acceptlang'] = $acceptLang; } if (isset($this->prop['unreadcount'])) { $store = MediaWikiServices::getInstance()->getWatchedItemStore(); $unreadNotifications = $store->countUnreadNotifications($user, self::WL_UNREAD_LIMIT); if ($unreadNotifications === true) { $vals['unreadcount'] = self::WL_UNREAD_LIMIT . '+'; } else { $vals['unreadcount'] = $unreadNotifications; } } if (isset($this->prop['centralids'])) { $vals += self::getCentralUserInfo($this->getConfig(), $this->getUser(), $this->params['attachedwiki']); } return $vals; }
/** * Format a single parameter value for API output * * @since 1.25 * @param string $name * @param string $type * @param string $value * @return array */ protected function formatParameterValueForApi($name, $type, $value) { $type = strtolower(trim($type)); switch ($type) { case 'bool': $value = (bool) $value; break; case 'number': if (ctype_digit($value) || is_int($value)) { $value = (int) $value; } else { $value = (double) $value; } break; case 'array': case 'assoc': case 'kvp': if (is_array($value)) { ApiResult::setArrayType($value, $type); } break; case 'timestamp': $value = wfTimestamp(TS_ISO_8601, $value); break; case 'msg': case 'msg-content': $msg = $this->msg($value); if ($type === 'msg-content') { $msg->inContentLanguage(); } $value = array(); $value["{$name}_key"] = $msg->getKey(); if ($msg->getParams()) { $value["{$name}_params"] = $msg->getParams(); } $value["{$name}_text"] = $msg->text(); return $value; case 'title': case 'title-link': $title = Title::newFromText($value); if ($title) { $value = array(); ApiQueryBase::addTitleInfo($value, $title, "{$name}_"); } return $value; case 'user': case 'user-link': $user = User::newFromName($value); if ($user) { $value = $user->getName(); } break; default: // do nothing break; } return array($name => $value); }
/** * @covers ApiResult */ public function testMetadata() { $arr = array('foo' => array('bar' => array())); $result = new ApiResult(8388608); $result->addValue(null, 'foo', array('bar' => array())); $expect = array('foo' => array('bar' => array(ApiResult::META_INDEXED_TAG_NAME => 'ritn', ApiResult::META_TYPE => 'default'), ApiResult::META_INDEXED_TAG_NAME => 'ritn', ApiResult::META_TYPE => 'default'), ApiResult::META_SUBELEMENTS => array('foo', 'bar'), ApiResult::META_INDEXED_TAG_NAME => 'itn', ApiResult::META_PRESERVE_KEYS => array('foo', 'bar'), ApiResult::META_TYPE => 'array'); ApiResult::setSubelementsList($arr, 'foo'); ApiResult::setSubelementsList($arr, array('bar', 'baz')); ApiResult::unsetSubelementsList($arr, 'baz'); ApiResult::setIndexedTagNameRecursive($arr, 'ritn'); ApiResult::setIndexedTagName($arr, 'itn'); ApiResult::setPreserveKeysList($arr, 'foo'); ApiResult::setPreserveKeysList($arr, array('bar', 'baz')); ApiResult::unsetPreserveKeysList($arr, 'baz'); ApiResult::setArrayTypeRecursive($arr, 'default'); ApiResult::setArrayType($arr, 'array'); $this->assertSame($expect, $arr); $result->addSubelementsList(null, 'foo'); $result->addSubelementsList(null, array('bar', 'baz')); $result->removeSubelementsList(null, 'baz'); $result->addIndexedTagNameRecursive(null, 'ritn'); $result->addIndexedTagName(null, 'itn'); $result->addPreserveKeysList(null, 'foo'); $result->addPreserveKeysList(null, array('bar', 'baz')); $result->removePreserveKeysList(null, 'baz'); $result->addArrayTypeRecursive(null, 'default'); $result->addArrayType(null, 'array'); $this->assertEquals($expect, $result->getResultData()); $arr = array('foo' => array('bar' => array())); $expect = array('foo' => array('bar' => array(ApiResult::META_TYPE => 'kvp', ApiResult::META_KVP_KEY_NAME => 'key'), ApiResult::META_TYPE => 'kvp', ApiResult::META_KVP_KEY_NAME => 'key'), ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'bc'); ApiResult::setArrayTypeRecursive($arr, 'kvp', 'key'); ApiResult::setArrayType($arr, 'BCkvp', 'bc'); $this->assertSame($expect, $arr); }
/** * Clean up a field array for output * @param ApiBase $module For context and parameters 'mergerequestfields' * and 'messageformat' * @param array $fields * @return array */ private function formatFields(array $fields) { static $copy = ['type' => true, 'image' => true, 'value' => true]; $module = $this->module; $retFields = []; foreach ($fields as $name => $field) { $ret = array_intersect_key($field, $copy); if (isset($field['options'])) { $ret['options'] = array_map(function ($msg) use($module) { return $msg->setContext($module)->plain(); }, $field['options']); ApiResult::setArrayType($ret['options'], 'assoc'); } $this->formatMessage($ret, 'label', $field['label']); $this->formatMessage($ret, 'help', $field['help']); $ret['optional'] = !empty($field['optional']); $retFields[$name] = $ret; } ApiResult::setArrayType($retFields, 'assoc'); return $retFields; }