/** * The general method for handling the communication with the service. */ public function request($resourceName, $getParams = [], $postData = [], $extraRequestOptions = []) { // Crash if we cannot make HTTP requests. \Wikia\Util\Assert::true(\MWHttpRequest::canMakeRequests()); // Add client_id and client_secret to the GET data. $getParams['client_id'] = $this->clientId; $getParams['client_secret'] = $this->clientSecret; // Request URI pre-processing. $uri = "{$this->baseUri}{$resourceName}?" . http_build_query($getParams); // Request options pre-processing. $options = ['method' => 'GET', 'timeout' => 5, 'postData' => $postData, 'noProxy' => true, 'followRedirects' => false, 'returnInstance' => true, 'internalRequest' => true]; $options = array_merge($options, $extraRequestOptions); /* * MediaWiki's MWHttpRequest class heavily relies on Messaging API * (wfMessage()) which happens to rely on the value of $wgLang. * $wgLang is set after $wgUser. On per-request authentication with * an access token we use MWHttpRequest before wgUser is created so * we need $wgLang to be present. With GlobalStateWrapper we can set * the global variable in the local, function's scope, so it is the * same as the already existing $wgContLang. */ global $wgContLang; $wrapper = new GlobalStateWrapper(['wgLang' => $wgContLang]); // Request execution. /** @var \MWHttpRequest $request */ $request = $wrapper->wrap(function () use($options, $uri) { return \Http::request($options['method'], $uri, $options); }); $this->status = $request->status; $output = json_decode($request->getContent()); if (!$output) { throw new ClientException('Invalid response.'); } return $output; }
/** * Get connection to flags database * * Flags database is encoded in utf-8, while in most cases MW communicate with * databases using latin1, so sometimes we get strings in wrong encoding. * The only way to force utf-8 communication (adding SET NAMES utf8) is setting * global variable wgDBmysql5. * * @see https://github.com/Wikia/app/blob/dev/includes/db/DatabaseMysqlBase.php#L113 * * @param int $dbType master or slave * @return \DatabaseBase */ protected function getDatabase($dbType) { $wrapper = new GlobalStateWrapper(['wgDBmysql5' => true]); $db = $wrapper->wrap(function () use($dbType) { return wfGetDB($dbType, [], $this->wg->FlagsDB); }); return $db; }
public function getContext(Title $title, $skinName) { $wrapper = new GlobalStateWrapper(['wgTitle' => $title]); $wg = F::app()->wg; return $wrapper->wrap(function () use($title, $wg, $skinName) { $wikiFactoryHub = WikiFactoryHub::getInstance(); $hubService = new HubService(); $adPageTypeService = new AdEngine2PageTypeService(); $wikiaPageType = new WikiaPageType(); $sevenOneMediaCombinedUrl = null; if (!empty($wg->AdDriverUseSevenOneMedia)) { // TODO: implicitly gets the skin from the context! $sevenOneMediaCombinedUrl = ResourceLoader::makeCustomURL($wg->Out, ['wikia.ext.adengine.sevenonemedia'], 'scripts'); } $monetizationServiceAds = null; if (!empty($wg->AdDriverUseMonetizationService) && !empty($wg->EnableMonetizationModuleExt)) { $monetizationServiceAds = F::app()->sendRequest('MonetizationModule', 'index')->getData()['data']; } $langCode = $title->getPageLanguage()->getCode(); return ['opts' => $this->filterOutEmptyItems(['adsInContent' => $wg->EnableAdsInContent, 'delayBtf' => $wg->AdDriverDelayBelowTheFold, 'enableAdsInMaps' => $wg->AdDriverEnableAdsInMaps, 'pageType' => $adPageTypeService->getPageType(), 'paidAssetDropConfig' => $wg->PaidAssetDropConfig, 'showAds' => $adPageTypeService->areAdsShowableOnPage(), 'trackSlotState' => $wg->AdDriverTrackState, 'usePostScribe' => $wg->Request->getBool('usepostscribe', false)]), 'targeting' => $this->filterOutEmptyItems(['enablePageCategories' => array_search($langCode, $wg->AdPageLevelCategoryLangs) !== false, 'pageArticleId' => $title->getArticleId(), 'pageIsArticle' => !!$title->getArticleId(), 'pageIsHub' => $wikiaPageType->isWikiaHub(), 'pageName' => $title->getPrefixedDBKey(), 'pageType' => $wikiaPageType->getPageType(), 'sevenOneMediaSub2Site' => $wg->AdDriverSevenOneMediaOverrideSub2Site, 'skin' => $skinName, 'wikiCategory' => $wikiFactoryHub->getCategoryShort($wg->CityId), 'wikiCustomKeyValues' => $wg->DartCustomKeyValues, 'wikiDbName' => $wg->DBname, 'wikiDirectedAtChildren' => $wg->WikiDirectedAtChildrenByFounder || $wg->WikiDirectedAtChildrenByStaff, 'wikiIsCorporate' => $wikiaPageType->isCorporatePage(), 'wikiIsTop1000' => $wg->AdDriverWikiIsTop1000, 'wikiLanguage' => $langCode, 'wikiVertical' => $hubService->getCategoryInfoForCity($wg->CityId)->cat_name]), 'providers' => $this->filterOutEmptyItems(['monetizationService' => $wg->AdDriverUseMonetizationService, 'monetizationServiceAds' => $monetizationServiceAds, 'sevenOneMedia' => $wg->AdDriverUseSevenOneMedia, 'sevenOneMediaCombinedUrl' => $sevenOneMediaCombinedUrl, 'taboola' => $wg->AdDriverUseTaboola]), 'slots' => $this->filterOutEmptyItems(['exitstitial' => $wg->EnableOutboundScreenExt, 'exitstitialRedirectDelay' => $wg->OutboundScreenRedirectDelay, 'invisibleHighImpact' => $wg->AdDriverEnableInvisibleHighImpactSlot]), 'forcedProvider' => $wg->AdDriverForcedProvider]; }); }
/** * Get Articles under a category * * @requestParam string $category [OPTIONAL] The name of a category (e.g. Characters) to use as a filter * @requestParam array $namespaces [OPTIONAL] The name of the namespaces (e.g. 0, 14, 5, etc.) to use as a filter, comma separated * @requestParam integer $limit [OPTIONAL] The maximum number of results to fetch, defaults to 25 * @requestParam integer $offset [OPTIONAL] Offset to start fetching data from * @requestParam string $expand [OPTIONAL] if set will expand result with getDetails data * * @responseParam array $items The list of top articles by pageviews matching the optional filtering * @responseParam array $basepath domain of a wiki to create a url for an article * @responseParam string $offset offset to start next batch of data * * @example * @example &namespaces=14 * @example &limit=10&namespaces=14 * @example &limit=10&namespaces=14&offset=R * @example &category=Weapons * @example &category=Weapons&limit=5 */ public function getList() { wfProfileIn(__METHOD__); $category = $this->request->getVal(self::PARAMETER_CATEGORY, null); $namespaces = $this->request->getArray(self::PARAMETER_NAMESPACES, null); $limit = $this->request->getVal('limit', self::ITEMS_PER_BATCH); $offset = $this->request->getVal('offset', ''); $expand = $this->request->getBool(static::PARAMETER_EXPAND, false); if (!empty($category)) { $category = self::resolveCategoryName($category); if (!is_null($category)) { if (!empty($namespaces)) { foreach ($namespaces as &$n) { if (!is_numeric($n)) { throw new InvalidParameterApiException(self::PARAMETER_NAMESPACES); } } $namespaces = implode('|', $namespaces); } /** * Wrapping global wgMiserMode. * * wgMiserMode = true (default) changes the behavior of categorymembers mediawiki API, causing it to * filter by namespace after making database query constrained by $limit and thus resulting * in Api returning fewer than $limit results * * wgMiserMode = false filters on DB level */ $wrapper = new GlobalStateWrapper(['wgMiserMode' => $this->excludeNamespacesFromCategoryMembersDBQuery]); $articles = $wrapper->wrap(function () use($category, $limit, $offset, $namespaces) { return self::getCategoryMembers($category->getFullText(), $limit, $offset, $namespaces); }); } else { wfProfileOut(__METHOD__); throw new InvalidParameterApiException(self::PARAMETER_CATEGORY); } } else { $namespace = $namespaces[0]; if (!empty($namespace) && !is_numeric($namespace) || $namespace === '' || is_array($namespaces) && count($namespaces) > 1) { //throw an error as for now this method accepts only one namespace throw new InvalidParameterApiException(self::PARAMETER_NAMESPACES); } $articles = WikiaDataAccess::cache(self::getCacheKey($offset, self::PAGE_CACHE_ID, [$limit . $namespace]), self::CLIENT_CACHE_VALIDITY, function () use($limit, $offset, $namespace) { $params = ['action' => 'query', 'list' => 'allpages', 'aplimit' => $limit, 'apfrom' => $offset]; //even if this is $namespace empty string allpages fail to fallback to Main namespace if (!empty($namespace)) { $params['apnamespace'] = $namespace; } $pages = ApiService::call($params); if (!empty($pages)) { return [$pages['query']['allpages'], !empty($pages['query-continue']) ? $pages['query-continue']['allpages']['apfrom'] : null]; } else { return null; } }); } if (is_array($articles) && !empty($articles[0])) { $ret = []; if ($expand) { $articleIds = array_map(function ($item) { if (isset($item['pageid'])) { return $item['pageid']; } }, $articles[0]); $params = $this->getDetailsParams(); $ret = $this->getArticlesDetails($articleIds, $params['titleKeys'], $params['width'], $params['height'], $params['length'], true); } else { foreach ($articles[0] as $article) { $title = Title::newFromText($article['title']); if ($title instanceof Title) { $ret[] = ['id' => $article['pageid'], 'title' => $title->getText(), 'url' => $title->getLocalURL(), 'ns' => $article['ns']]; } } } $responseValues = ['items' => $ret, 'basepath' => $this->wg->Server]; if (!empty($articles[1])) { $responseValues['offset'] = $articles[1]; } $this->setResponseData($responseValues, ['imgFields' => 'thumbnail', 'urlFields' => ['thumbnail', 'url']], self::getMetadataCacheTime()); } else { wfProfileOut(__METHOD__); throw new NotFoundApiException('No members'); } wfProfileOut(__METHOD__); }
/** * move main page to SEO-friendly name */ private function moveMainPage() { global $wgSitename, $parserMemc, $wgContLanguageCode; $source = wfMsgForContent('Mainpage'); $target = $wgSitename; $sourceTitle = \Title::newFromText($source); if (!$sourceTitle) { $sourceTitle = \Title::newFromText('Main_Page'); if (!$sourceTitle) { $this->error('invalid page title', ['title' => $source]); return; } } $mainArticle = new \Article($sourceTitle, 0); if ($mainArticle->exists()) { /** * check target title */ $targetTitle = \Title::newFromText($target); if ($targetTitle) { $moveContext = ['source' => $sourceTitle->getPrefixedText(), 'target' => $targetTitle->getPrefixedText()]; if ($sourceTitle->getPrefixedText() !== $targetTitle->getPrefixedText()) { $wikiaUser = \User::newFromName(self::WIKIA_USER); $wrapper = new GlobalStateWrapper(['wgUser' => $wikiaUser]); $err = $wrapper->wrap(function () use($sourceTitle, $targetTitle) { return $sourceTitle->moveTo($targetTitle, false, 'SEO'); }); if ($err !== true) { $this->error('main page move failed', $moveContext); } else { $this->info('main page moved', $moveContext); /** * fill Mediawiki:Mainpage with new title */ $mwMainPageTitle = \Title::newFromText('Mainpage', NS_MEDIAWIKI); $mwMainPageArticle = new \Article($mwMainPageTitle, 0); $mwMainPageArticle->doEdit($targetTitle->getText(), 'SEO', EDIT_SUPPRESS_RC | EDIT_MINOR | EDIT_FORCE_BOT, false, $wikiaUser); $mwMainPageArticle->doPurge(); /** * also move associated talk page if it exists */ $sourceTalkTitle = $sourceTitle->getTalkPage(); $targetTalkTitle = $targetTitle->getTalkPage(); if ($sourceTalkTitle instanceof \Title && $sourceTalkTitle->exists() && $targetTalkTitle instanceof \Title) { $moveContext = ['source' => $sourceTalkTitle->getPrefixedText(), 'target' => $targetTalkTitle->getPrefixedText()]; $err = $wrapper->wrap(function () use($sourceTalkTitle, $targetTitle) { return $sourceTalkTitle->moveTo($targetTitle->getTalkPage(), false, "SEO"); }); if ($err === true) { $this->info('talk page moved', $moveContext); } else { $this->warning('talk page move failed', $moveContext); } } } } else { $this->info('talk page not moved. source, destination are the same', $moveContext); } } } /** * clear skin cache for rt#63874 * * @todo establish what $code is exactly in this case */ $parserMemc->delete(wfMemcKey('sidebar', $wgContLanguageCode)); $parserMemc->delete(wfMemcKey('quartzsidebar')); $parserMemc->delete(wfMemcKey('navlinks')); $parserMemc->delete(wfMemcKey('MonacoData')); $parserMemc->delete(wfMemcKey('MonacoDataOld')); }
public function postWallMessageToRecipient() { $defaultWelcomeUser = $this->getDefaultWelcomerUser(); // some of the lower level methods used in buildNewMessageAndPost do not pass the // $user object down the call stack and instead rely on the $wgUser which is // not set in a Task environment $wrapper = new GlobalStateWrapper(array('wgUser' => $defaultWelcomeUser)); $this->info("creating a welcome wall message"); $welcomeMessage = $this->welcomeMessage; $recipientName = $this->recipientName; $textMessage = $this->getTextVersionOfMessage('welcome-message-log'); $message = $wrapper->wrap(function () use($defaultWelcomeUser, $welcomeMessage, $recipientName, $textMessage) { return $this->executeBuildAndPostWallMessage($defaultWelcomeUser, $welcomeMessage, $recipientName, $textMessage); }); $message = $this->setWallMessagePostedAsBot($message); return $message; }
/** * @expectedException InvalidArgumentException */ public function testWrapWithNotCallable() { $wrapper = new GlobalStateWrapper(array()); $wrapper->wrap('foo'); }
/** * @param $content * @param bool $useYUI * @return string * @throws Exception */ public static function minifyJS($content, $useYUI = false) { global $IP; wfProfileIn(__METHOD__); $tempInFile = tempnam(sys_get_temp_dir(), 'AMIn'); file_put_contents($tempInFile, $content); $retval = 1; if ($useYUI) { wfProfileIn(__METHOD__ . '::yui'); $wrapper = new GlobalStateWrapper(['wgMaxShellMemory' => 0]); $out = $wrapper->wrap(function () use($IP, &$retval, $tempInFile) { $tempOutFile = tempnam(sys_get_temp_dir(), 'AMOut'); wfShellExec("nice -n 15 java -jar {$IP}/lib/vendor/yuicompressor-2.4.2.jar --type js -o {$tempOutFile} {$tempInFile}", $retval); $out = file_get_contents($tempOutFile); unlink($tempOutFile); return $out; }); wfProfileOut(__METHOD__ . '::yui'); } else { wfProfileIn(__METHOD__ . '::jsmin'); $jsmin = "{$IP}/lib/vendor/jsmin"; $out = wfShellExec("cat {$tempInFile} | {$jsmin}", $retval); wfProfileOut(__METHOD__ . '::jsmin'); } unlink($tempInFile); if ($retval !== 0) { \Wikia\Logger\WikiaLogger::instance()->error('AssetsManagerBaseBuilder::minifyJS failed', ['exception' => new Exception()]); throw new Exception('JS minification failed'); } wfProfileOut(__METHOD__); return $out; }
/** * Check if the current page should be rendered using Venus * * @param Title $title * @return bool */ public static function showVenusSkin(Title $title) { global $wgEnableVenusSkin, $wgEnableVenusSpecialSearch, $wgEnableVenusArticle, $wgRequest; $wrapper = new GlobalStateWrapper(['wgTitle' => $title]); $isSearch = false; $isArticlePage = false; $wrapper->wrap(function () use(&$isSearch, &$isArticlePage) { $isSearch = WikiaPageType::isSearch(); $isArticlePage = WikiaPageType::isArticlePage(); }); $action = $wgRequest->getVal('action'); $diff = $wgRequest->getVal('diff'); $isSpecialSearch = $isSearch && $wgEnableVenusSpecialSearch; $isSpecialVenusTest = $title->isSpecialPage() && $title->getText() == 'VenusTest'; $isVenusArticle = $isArticlePage && $wgEnableVenusArticle && (empty($action) || $action == 'view') && empty($diff); return $wgEnableVenusSkin && ($isSpecialSearch || $isSpecialVenusTest || $isVenusArticle); }