/** * Does the API request and returns the result. * * The returned value is an array containing * - the result data (array) * - the request (WebRequest) * - the session data of the request (array) * - if $appendModule is true, the Api module $module * * @param array $params * @param array|null $session * @param bool $appendModule * @param User|null $user * * @return array */ protected function doApiRequest(array $params, array $session = null, $appendModule = false, User $user = null) { global $wgRequest, $wgUser; if (is_null($session)) { // re-use existing global session by default $session = $wgRequest->getSessionArray(); } // set up global environment if ($user) { $wgUser = $user; } $wgRequest = new FauxRequest($params, true, $session); RequestContext::getMain()->setRequest($wgRequest); RequestContext::getMain()->setUser($wgUser); MediaWiki\Auth\AuthManager::resetCache(); // set up local environment $context = $this->apiContext->newTestContext($wgRequest, $wgUser); $module = new ApiMain($context, true); // run it! $module->execute(); // construct result $results = [$module->getResult()->getResultData(null, ['Strip' => 'all']), $context->getRequest(), $context->getRequest()->getSessionArray()]; if ($appendModule) { $results[] = $module; } return $results; }
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'); }
$profName = $fname . '-extensions-' . get_class($func[0]) . '::' . $func[1]; } else { $profName = $fname . '-extensions-' . implode('::', $func); } } else { $profName = $fname . '-extensions-' . strval($func); } $ps_ext_func = Profiler::instance()->scopedProfileIn($profName); call_user_func($func); Profiler::instance()->scopedProfileOut($ps_ext_func); } // If the session user has a 0 id but a valid name, that means we need to // autocreate it. if (!defined('MW_NO_SESSION') && !$wgCommandLineMode) { $sessionUser = MediaWiki\Session\SessionManager::getGlobalSession()->getUser(); if ($sessionUser->getId() === 0 && User::isValidUserName($sessionUser->getName())) { $ps_autocreate = Profiler::instance()->scopedProfileIn($fname . '-autocreate'); $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser($sessionUser, MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION, true); Profiler::instance()->scopedProfileOut($ps_autocreate); \MediaWiki\Logger\LoggerFactory::getInstance('authevents')->info('Autocreation attempt', ['event' => 'autocreate', 'status' => $res]); unset($res); } unset($sessionUser); } if (!$wgCommandLineMode) { Pingback::schedulePingback(); } wfDebug("Fully initialised\n"); $wgFullyInitialised = true; Profiler::instance()->scopedProfileOut($ps_extensions); Profiler::instance()->scopedProfileOut($ps_setup);
protected function tearDown() { global $wgRequest, $wgSQLMode; $status = ob_get_status(); if (isset($status['name']) && $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier') { ob_end_flush(); } $this->called['tearDown'] = true; // Cleaning up temporary files foreach ($this->tmpFiles as $fileName) { if (is_file($fileName) || is_link($fileName)) { unlink($fileName); } elseif (is_dir($fileName)) { wfRecursiveRemoveDir($fileName); } } if ($this->needsDB() && $this->db) { // Clean up open transactions while ($this->db->trxLevel() > 0) { $this->db->rollback(__METHOD__, 'flush'); } if ($this->db->getType() === 'mysql') { $this->db->query("SET sql_mode = " . $this->db->addQuotes($wgSQLMode)); } } // Restore mw globals foreach ($this->mwGlobals as $key => $value) { $GLOBALS[$key] = $value; } $this->mwGlobals = []; $this->restoreLoggers(); if (self::$serviceLocator && MediaWikiServices::getInstance() !== self::$serviceLocator) { MediaWikiServices::forceGlobalInstance(self::$serviceLocator); } // TODO: move global state into MediaWikiServices RequestContext::resetMain(); if (session_id() !== '') { session_write_close(); session_id(''); } $wgRequest = new FauxRequest(); MediaWiki\Session\SessionManager::resetCache(); MediaWiki\Auth\AuthManager::resetCache(); $phpErrorLevel = intval(ini_get('error_reporting')); if ($phpErrorLevel !== $this->phpErrorLevel) { ini_set('error_reporting', $this->phpErrorLevel); $oldHex = strtoupper(dechex($this->phpErrorLevel)); $newHex = strtoupper(dechex($phpErrorLevel)); $message = "PHP error_reporting setting was left dirty: " . "was 0x{$oldHex} before test, 0x{$newHex} after test!"; $this->fail($message); } parent::tearDown(); }
/** * Save user groups changes in the database. * * @param User|UserRightsProxy $user * @param array $add Array of groups to add * @param array $remove Array of groups to remove * @param string $reason Reason for group change * @return array Tuple of added, then removed groups */ function doSaveUserGroups($user, $add, $remove, $reason = '') { // Validate input set... $isself = $user->getName() == $this->getUser()->getName(); $groups = $user->getGroups(); $changeable = $this->changeableGroups(); $addable = array_merge($changeable['add'], $isself ? $changeable['add-self'] : []); $removable = array_merge($changeable['remove'], $isself ? $changeable['remove-self'] : []); $remove = array_unique(array_intersect((array) $remove, $removable, $groups)); $add = array_unique(array_diff(array_intersect((array) $add, $addable), $groups)); $oldGroups = $user->getGroups(); $newGroups = $oldGroups; // Remove then add groups if ($remove) { foreach ($remove as $index => $group) { if (!$user->removeGroup($group)) { unset($remove[$index]); } } $newGroups = array_diff($newGroups, $remove); } if ($add) { foreach ($add as $index => $group) { if (!$user->addGroup($group)) { unset($add[$index]); } } $newGroups = array_merge($newGroups, $add); } $newGroups = array_unique($newGroups); // Ensure that caches are cleared $user->invalidateCache(); // update groups in external authentication database Hooks::run('UserGroupsChanged', [$user, $add, $remove, $this->getUser(), $reason]); MediaWiki\Auth\AuthManager::callLegacyAuthPlugin('updateExternalDBGroups', [$user, $add, $remove]); wfDebug('oldGroups: ' . print_r($oldGroups, true) . "\n"); wfDebug('newGroups: ' . print_r($newGroups, true) . "\n"); // Deprecated in favor of UserGroupsChanged hook Hooks::run('UserRights', [&$user, $add, $remove], '1.26'); if ($newGroups != $oldGroups) { $this->addLogEntry($user, $oldGroups, $newGroups, $reason); } return [$add, $remove]; }