/** * Get details about one or more user * * @requestParam string $ids A string with a comma-separated list of user ID's, limit for query equals 100 * @requestParam integer $size [OPTIONAL] The desired width and height for the thumbnail, defaults to 100, 0 for no thumbnail * * @responseParam array $items A list of results with the user ID as the index, each item has a title, name, url, avatar, numberofedits * @responseParam string $basepath domain of a wiki to create a url for an user * * @example &ids=123&size=150 */ public function getDetails() { wfProfileIn(__METHOD__); $ids = $this->request->getVal('ids'); if (empty($ids)) { throw new InvalidParameterApiException('ids'); } $ids = explode(',', trim($ids)); $size = $this->request->getInt('size', static::AVATAR_DEFAULT_SIZE); //limit number of users $ids = array_slice($ids, 0, static::USER_LIMIT); //users are cached inside the service $users = (new UserService())->getUsers($ids); $items = array(); foreach ($users as $user) { $userName = $user->getName(); $item = array('user_id' => $user->getId(), 'title' => $user->getTitleKey(), 'name' => $userName, 'url' => AvatarService::getUrl($userName), 'numberofedits' => (int) $user->getEditCountLocal()); //add avatar url if size !== 0 if ($size > 0) { $item['avatar'] = AvatarService::getAvatarUrl($user, $size); } $items[] = $item; } if (!empty($items)) { $this->setResponseData(['basepath' => $this->wg->Server, 'items' => $items], ['imgFields' => 'avatar', 'urlFields' => ['avatar', 'url']], WikiaResponse::CACHE_STANDARD); } else { throw new NotFoundApiException(); } wfProfileOut(__METHOD__); }
public function votersListItems() { //TODO: imaplmant load more button /** * @var $mw WallMessage */ $mw = $this->request->getVal('mw'); if (empty($mw)) { $mw = F::build('WallMessage', array($this->request->getVal('id')), 'newFromId'); } $from = (int) $this->request->getVal('from', 0); $list = $mw->getVotersList($from, 1000); if (count($list) == 26) { $this->response->setVal('hasmore', true); } else { $this->response->setVal('hasmore', false); } $out = array(); for ($i = 0; $i < min(count($list), 24); $i++) { $user = User::newFromId($list[$i]); if (!empty($user)) { $out[] = array('profilepage' => $user->getUserPage()->getFullUrl(), 'name' => $user->getName(), 'avatar' => AvatarService::getAvatarUrl($user->getName(), 50)); } } $this->response->setVal('hasmore', false); $this->response->setVal('last', $from); $this->response->setVal('list', $out); }
/** * Chat entry point - rendered via Ajax or pre-rendered in JS variable * @todo: backward compatibility method, remove it till Oct 2013 * @todo: Ticket to remove this function: https://wikia-inc.atlassian.net/browse/SOC-638 */ public function executeContents() { global $wgUser, $wgReadOnly, $wgEnableWallExt; wfProfileIn(__METHOD__); if (empty($wgReadOnly)) { // Main variables $this->profileType = !empty($wgEnableWallExt) ? 'message-wall' : 'talk-page'; $this->linkToSpecialChat = SpecialPage::getTitleFor("Chat")->escapeLocalUrl(); $this->isLoggedIn = $wgUser->isLoggedIn(); $this->profileAvatarUrl = $this->isLoggedIn ? AvatarService::getAvatarUrl($wgUser->getName(), ChatRailController::AVATAR_SIZE) : ''; // List of other people in chat $this->totalInRoom = 0; // Gets array of users currently in chat to populate rail module and user stats menus $this->chatters = ChatEntryPoint::getChatUsersInfo(); $this->totalInRoom = count($this->chatters); for ($i = 0; $i < $this->totalInRoom; $i++) { global $wgLang; if ($this->chatters[$i]['showSince']) { $this->chatters[$i]['since'] = $wgLang->getMonthAbbreviation($this->chatters[$i]['since_month']) . ' ' . $this->chatters[$i]['since_year']; } } ChatHelper::info(__METHOD__ . ': Method called', ['chatters' => $this->totalInRoom, 'loggedIn' => $this->isLoggedIn]); } // Cache the entire call in varnish (and browser). $this->response->setCacheValidity(self::CACHE_DURATION); wfProfileOut(__METHOD__); }
/** * Chat entry point - rendered via Ajax or pre-rendered in JS variable */ public function executeContents() { global $wgUser, $wgSitename, $wgOut, $wgExtensionsPath, $wgContLang, $wgReadOnly, $wgEnableWallExt; wfProfileIn(__METHOD__); // Since there is no chat in the backup datacenter yet, if we're in read-only, disable the entry-point. // Depending on the actual failure, chat may or may not work, but the user would have to get there via URL which // is essentially saying that they accept some risk since they're going somewhere our interface doesn't direct them to. // If it's just, eg: a database problem, then they may get lucky and be able to use most of the chat features (kickbanning wouldn't work, etc.). if (empty($wgReadOnly)) { // Main variables $this->profileType = !empty($wgEnableWallExt) ? 'message-wall' : 'talk-page'; $this->linkToSpecialChat = SpecialPage::getTitleFor("Chat")->escapeLocalUrl(); $this->isLoggedIn = $wgUser->isLoggedIn(); $this->profileAvatarUrl = $this->isLoggedIn ? AvatarService::getAvatarUrl($wgUser->getName(), ChatRailController::AVATAR_SIZE) : ''; // List of other people in chat $this->totalInRoom = 0; // Gets array of users currently in chat to populate rail module and user stats menus $chattersIn = NodeApiClient::getChatters($this->totalInRoom); $this->totalInRoom = count($chattersIn); $chatters = array(); foreach ($chattersIn as $i => $val) { $chatters[$i] = array(); $cacheChatter = $this->getCachedUser($val); if (!empty($cacheChatter)) { $chatters[$i] = $cacheChatter; continue; } $chatters[$i]['username'] = $val; $chatters[$i]['avatarUrl'] = AvatarService::getAvatarUrl($chatters[$i]['username'], ChatRailController::AVATAR_SIZE); // get stats for edit count and member since $user = User::newFromName($val); if (is_object($user)) { $userStatsService = new UserStatsService($user->getId()); $stats = $userStatsService->getStats(); // edit count $chatters[$i]['editCount'] = $wgContLang->formatNum((int) $stats['edits']); // member since $chatters[$i]['showSince'] = $chatters[$i]['editCount'] != 0; $date = getdate(strtotime($stats['date'])); global $wgLang; $chatters[$i]['since'] = $wgLang->getMonthAbbreviation($date['mon']) . ' ' . $date['year']; // profile page if ($this->profileType == 'message-wall') { $chatters[$i]['profileUrl'] = Title::makeTitle(NS_USER_WALL, $chatters[$i]['username'])->getFullURL(); } else { $chatters[$i]['profileUrl'] = Title::makeTitle(NS_USER_TALK, $chatters[$i]['username'])->getFullURL(); } // contribs page $chatters[$i]['contribsUrl'] = SpecialPage::getTitleFor('Contributions', $chatters[$i]['username'])->getFullURL(); } $this->cacheUser($val, $chatters[$i]); } $this->chatters = $chatters; } // Cache the entire call in varnish (and browser). $this->response->setCacheValidity(self::CACHE_DURATION, self::CACHE_DURATION, array(WikiaResponse::CACHE_TARGET_BROWSER, WikiaResponse::CACHE_TARGET_VARNISH)); wfProfileOut(__METHOD__); }
/** * @group UsingDB * @dataProvider getAvatarUrlDataProvider */ public function testGetAvatarUrl($url, $userName, $userId, $avatarSize) { $user = new User(); $user->setId($userId); $user->setName($userName); if ($userId > 0) { $user->setGlobalAttribute(AVATAR_USER_OPTION_NAME, $userId); } $this->assertStringEndsWith($url, AvatarService::getAvatarUrl($user, $avatarSize)); }
/** * Get a list of random avatars from the wiki * * @param integer $require (number of avatars) * @param integer $wikiId * @return array $avatars */ protected function getRandomWikiAvatars($require, $wikiId = null) { $avatars = array(); $users = $this->getWikiUsers($wikiId); if (count($users) < $require) { $randomList = array_keys($users); } else { $randomList = array_rand($users, $require); } // get avatar url foreach ($randomList as $userId) { $avatars[$userId] = AvatarService::getAvatarUrl($users[$userId], 30); } return $avatars; }
function testAvatarService() { $anonName = '10.10.10.10'; $userName = '******'; // users $this->assertRegExp('/width="32"/', AvatarService::render($userName, 32)); $this->assertRegExp('/\/20px-/', AvatarService::render($userName, 16)); $this->assertRegExp('/User:WikiaBot/', AvatarService::renderLink($userName)); $this->assertRegExp('/^<img src="http:\/\/images/', AvatarService::renderAvatar($userName)); $this->assertRegExp('/^http:\/\/images/', AvatarService::getAvatarUrl($userName)); // anons $this->assertRegExp('/Special:Contributions\//', AvatarService::getUrl($anonName)); $this->assertRegExp('/^<img src="/', AvatarService::renderAvatar($anonName)); $this->assertRegExp('/\/20px-/', AvatarService::renderAvatar($anonName, 20)); $this->assertRegExp('/Special:Contributions/', AvatarService::renderLink($anonName)); }
/** * Get user info ( user name, avatar url, user page url ) on given wiki * if the user has avatar * @param integer $userId * @param integer $wikiId * @param integer $avatarSize * @param callable $checkUserCallback * @return array userInfo * */ public function getUserInfo($userId, $wikiId, $avatarSize, $checkUserCallback) { $userInfo = array(); $user = User::newFromId($userId); if ($user instanceof User && $checkUserCallback($user)) { $username = $user->getName(); $userInfo['avatarUrl'] = AvatarService::getAvatarUrl($user, $avatarSize); $userInfo['edits'] = 0; $userInfo['name'] = $username; /** @var $userProfileTitle GlobalTitle */ $userProfileTitle = GlobalTitle::newFromTextCached($username, NS_USER, $wikiId); $userInfo['userPageUrl'] = $userProfileTitle instanceof Title ? $userProfileTitle->getFullURL() : '#'; $userContributionsTitle = GlobalTitle::newFromTextCached('Contributions/' . $username, NS_SPECIAL, $wikiId); $userInfo['userContributionsUrl'] = $userContributionsTitle instanceof Title ? $userContributionsTitle->getFullURL() : '#'; $userInfo['userId'] = $userId; $userStatsService = new UserStatsService($userId); $stats = $userStatsService->getGlobalStats($wikiId); if (!empty($stats['date'])) { $date = getdate(strtotime($stats['date'])); } else { $date = getdate(strtotime('2005-06-01')); } $userInfo['lastRevision'] = $stats['lastRevision']; $userInfo['since'] = F::App()->wg->Lang->getMonthAbbreviation($date['mon']) . ' ' . $date['year']; } return $userInfo; }
private function getEventsInfo() { wfProfileIn(__METHOD__); $where = array(); $where['wiki_id'] = intval($this->mCityId); # bot if (empty($this->params['bot'])) { $where['user_is_bot'] = 'N'; } # content if ($this->params['content'] == 1) { $where['is_content'] = 'Y'; } # anons if (empty($this->params['anons'])) { $where[] = 'user_id > 0'; } $db = $this->getDB(); if (is_null($db)) { return false; } $this->profileDBIn(); $oRes = $db->select('events', array('wiki_id', 'page_id', 'rev_id', 'log_id', 'user_id', 'user_is_bot', 'page_ns', 'is_content', 'is_redirect', 'ip', 'rev_timestamp', 'image_links', 'video_links', 'total_words', 'rev_size', 'wiki_lang_id', 'wiki_cat_id', 'event_type', 'event_date', 'media_type'), $where, __METHOD__, array('ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => $this->params['limit'], 'OFFSET' => $this->params['offset'])); $i = 0; $data = array(); while ($row = $db->fetchObject($oRes)) { # wiki $oWiki = WikiFactory::getWikiByID($row->wiki_id); if (empty($oWiki)) { continue; } # server name $server = WikiFactory::getVarValueByName("wgServer", $row->wiki_id); # user $oUser = null; $username = long2ip($row->ip); if ($row->user_id > 0) { $oUser = User::newFromId($row->user_id); $username = $oUser->getName(); } # page $url = ""; if ($row->event_type == 1 || $row->event_type == 2) { // edit or create $oGTitle = GlobalTitle::newFromId($row->page_id, $row->wiki_id); if (is_object($oGTitle)) { $url = $oGTitle->getFullURL(); } } if (empty($url)) { if (is_object($oUser)) { $url = $oUser->getUserPage()->getFullURL(); } else { $url = $server; } } # avatar $avatar = AvatarService::getAvatarUrl($username, 75); $data[$i] = array('wiki_id' => $row->wiki_id, 'wiki_url' => $server, 'page_id' => $row->page_id, 'page_url' => $url, 'namespace' => $row->page_ns, 'action' => $row->log_id > 0 ? 'remove' : 'edit', 'user_id' => $row->user_id, 'user_name' => $username, 'user_avatar' => $avatar, 'bot' => $row->user_is_bot, 'content' => $row->is_content, 'redirect' => $row->is_redirect, 'edited' => $row->rev_timestamp); $i++; } $db->freeResult($oRes); $this->profileDBOut(); wfProfileOut(__METHOD__); return $data; }
/** * This is the ajax-endpoint that the node server will connect to in order to get the currently logged-in user's info. * The node server will pass the same cookies that the client has set, and this will allow this ajax request to be * part of the same sesssion that the user already has going. By doing this, the user's existing wikia login session * can be used, so they don't need to re-login for us to know that they are legitimately authorized to use the chat or not. * * The returned info is just a custom subset of what the node server needs and does not contain an exhaustive list of rights. * * The 'isLoggedIn' field and 'canChat' field of the result should be checked by the calling code before allowing * the user to chat. This is the last line of security against any users attempting to circumvent our protections. Otherwise, * a banned user could copy the entire client code (HTML/JS/etc.) from an unblocked user, then run that code while logged in as * under a banned account, and they would still be given access. * * The returned 'isChatMod' field is boolean based on whether the user is a chat moderator on the current wiki. * * If the user is not allowed to chat, an error message is returned (which can be shown to the user). */ public static function getUserInfo() { ChatHelper::info(__METHOD__ . ': Method called'); global $wgMemc, $wgServer, $wgArticlePath, $wgRequest, $wgCityId, $wgContLang; wfProfileIn(__METHOD__); $data = $wgMemc->get($wgRequest->getVal('key'), false); if (empty($data)) { wfProfileOut(__METHOD__); return array('errorMsg' => "Key not found"); } $user = User::newFromId($data['user_id']); if (empty($user) || !$user->isLoggedIn() || $user->getName() != urldecode($wgRequest->getVal('name', ''))) { wfProfileOut(__METHOD__); return array('errorMsg' => "User not found"); } $isCanGiveChatMod = false; $userChangeableGroups = $user->changeableGroups(); if (in_array('chatmoderator', $userChangeableGroups['add'])) { $isCanGiveChatMod = true; } // First, check if they can chat on this wiki. $retVal = array('canChat' => Chat::canChat($user), 'isLoggedIn' => $user->isLoggedIn(), 'isChatMod' => $user->isAllowed('chatmoderator'), 'isCanGiveChatMod' => $isCanGiveChatMod, 'isStaff' => $user->isAllowed('chatstaff'), 'username' => $user->getName(), 'username_encoded' => rawurlencode($user->getName()), 'avatarSrc' => AvatarService::getAvatarUrl($user->getName(), self::CHAT_AVATAR_DIMENSION), 'editCount' => "", 'since' => '', 'activeBasket' => ChatHelper::getServerBasket(), 'wgCityId' => $wgCityId, 'wgServer' => $wgServer, 'wgArticlePath' => $wgArticlePath); // Figure out the error message to return (i18n is done on this side). if ($retVal['isLoggedIn'] === false) { $retVal['errorMsg'] = wfMsg('chat-no-login'); } else { if ($retVal['canChat'] === false) { $retVal['errorMsg'] = wfMsg('chat-you-are-banned-text'); } } // If the user is approved to chat, make sure the roomId provided is for this wiki. // Users may be banned on the wiki of the room, but not on this wiki for example, so this prevents cross-wiki chat hacks. if ($retVal['canChat']) { $roomId = $wgRequest->getVal('roomId'); $cityIdOfRoom = NodeApiClient::getCityIdForRoom($roomId); if ($wgCityId !== $cityIdOfRoom) { $retVal['canChat'] = false; // don't let the user chat in the room they requested. $retVal['errorMsg'] = wfMsg('chat-room-is-not-on-this-wiki'); } } // If the user can chat, dig up some other stats which are a little more expensive to compute. if ($retVal['canChat']) { // new user joins the chat, purge the cache ChatEntryPoint::purgeChatUsersCache(); $userStatsService = new UserStatsService($user->getId()); $stats = $userStatsService->getStats(); // NOTE: This is attached to the user so it will be in the wiki's content language instead of wgLang (which it normally will). $stats['edits'] = $wgContLang->formatNum($stats['edits']); if (empty($stats['date'])) { // If the user has not edited on this wiki, don't show anything $retVal['since'] = ""; } else { // this results goes to chat server, which obiously has no user lang // so we just return a short month name key - it has to be translated on client side $date = getdate(wfTimestamp(TS_UNIX, $stats['date'])); $retVal['since'] = $date; } $retVal['editCount'] = $stats['edits']; } wfProfileOut(__METHOD__); return $retVal; }
public function executeIndex() { global $wgUser, $wgDevelEnvironment, $wgRequest, $wgCityId, $wgFavicon, $wgOut; wfProfileIn(__METHOD__); // String replacement logic taken from includes/Skin.php $this->wgFavicon = str_replace('images.wikia.com', 'images1.wikia.nocookie.net', $wgFavicon); $this->mainPageURL = Title::newMainPage()->getLocalURL(); // add messages (fetch them using <script> tag) F::build('JSMessages')->enqueuePackage('Chat', JSMessages::EXTERNAL); // package defined in Chat_setup.php $this->jsMessagePackagesUrl = F::build('JSMessages')->getExternalPackagesUrl(); // Variables for this user $this->username = $wgUser->getName(); $this->avatarUrl = AvatarService::getAvatarUrl($this->username, ChatController::CHAT_AVATAR_DIMENSION); // Find the chat for this wiki (or create it, if it isn't there yet). $roomName = $roomTopic = ""; $this->roomId = (int) NodeApiClient::getDefaultRoomId($roomName, $roomTopic); $this->roomName = $roomName; $this->roomTopic = $roomTopic; $this->chatkey = Chat::echoCookies(); // Set the hostname of the node server that the page will connect to. $server = ChatHelper::getServer('Main'); $this->nodePort = $server['port']; $this->nodeHostname = $server['host']; // Some building block for URLs that the UI needs. $this->pathToProfilePage = Title::makeTitle(!empty($this->wg->EnableWallExt) ? NS_USER_WALL : NS_USER_TALK, '$1')->getFullURL(); $this->pathToContribsPage = SpecialPage::getTitleFor('Contributions', '$1')->getFullURL(); $this->bodyClasses = ""; if ($wgUser->isAllowed('chatmoderator')) { $this->isChatMod = 1; $this->bodyClasses .= ' chat-mod '; } else { $this->isChatMod = 0; } // Adding chatmoderator group for other users. CSS classes added to body tag to hide/show option in menu. $userChangeableGroups = $wgUser->changeableGroups(); if (in_array('chatmoderator', $userChangeableGroups['add'])) { $this->bodyClasses .= ' can-give-chat-mod '; } $this->app->registerHook('MakeGlobalVariablesScript', 'ChatController', 'onMakeGlobalVariablesScript', array(), false, $this); $wgOut->getResourceLoader()->getModule('mediawiki'); $ret = implode("\n", array($wgOut->getHeadLinks(null, true), $wgOut->buildCssLinks(), $wgOut->getHeadScripts(), $wgOut->getHeadItems())); $this->globalVariablesScript = $ret; //Theme Designer stuff $themeSettingObj = new ThemeSettings(); $themeSettings = $themeSettingObj->getSettings(); $this->themeSettings = $themeSettings; $this->wordmarkThumbnailUrl = ''; if ($themeSettings['wordmark-type'] == 'graphic') { $title = Title::newFromText($themeSettings['wordmark-image-name'], NS_FILE); if ($title) { $image = wfFindFile($title); if ($image) { $this->wordmarkThumbnailUrl = $image->createThumb(self::CHAT_WORDMARK_WIDTH, self::CHAT_WORDMARK_HEIGHT); } } if (empty($this->wordmarkThumbnailUrl)) { $this->wordmarkThumbnailUrl = WikiFactory::getLocalEnvURL($themeSettings['wordmark-image-url']); } } wfProfileOut(__METHOD__); }
protected function getAvatarURL(\User $user) { return \AvatarService::getAvatarUrl($user, self::AVATAR_SIZE); }
protected function getSharedUserData($userId, $userName) { wfProfileIn(__METHOD__); $data = array(); $data['id'] = $userId; $data['name'] = $userName; $data['avatar'] = AvatarService::getAvatarUrl($userName, 150); wfProfileOut(__METHOD__); return $data; }
protected function getUserDataForArticles($articles, $revisions) { $ids = !is_array($articles) ? [$articles] : $articles; $result = []; foreach ($revisions as $rev) { $userIds[$rev['rev_page']] = $rev['rev_user']; } if (!empty($userIds)) { $users = (new UserService())->getUsers($userIds); foreach ($users as $user) { $userData[$user->getId()] = ['avatar' => AvatarService::getAvatarUrl($user->getName(), self::DEFAULT_AVATAR_SIZE), 'name' => $user->getName()]; } } foreach ($ids as $pageId) { if (isset($userIds[$pageId]) && isset($userData[$userIds[$pageId]])) { $result[$pageId] = $userData[$userIds[$pageId]]; } else { $result[$pageId] = ['avatar' => null, 'name' => null]; } } return $result; }
public function executeIndex() { wfProfileIn(__METHOD__); $maxElements = 4; global $wgLang, $wgContentNamespaces, $wgMemc, $wgUser; $this->moduleHeader = wfMsg('oasis-activity-header'); if (empty($this->userName)) { $mKey = wfMemcKey('mOasisLatestActivity'); $feedData = $wgMemc->get($mKey); } if (empty($feedData)) { // data provider $includeNamespaces = implode('|', $wgContentNamespaces); $parameters = array('type' => 'widget', 'maxElements' => $maxElements, 'flags' => array('shortlist'), 'uselang' => $wgLang->getCode(), 'includeNamespaces' => $includeNamespaces); $feedProxy = new ActivityFeedAPIProxy($includeNamespaces, $this->userName); $feedProvider = new DataFeedProvider($feedProxy, 1, $parameters); $feedData = $feedProvider->get($maxElements); if (empty($this->userName)) { $wgMemc->set($mKey, $feedData); } } // Time strings are slow to calculate, but we still want them to update frequently (60 seconds) if (empty($this->userName)) { $mKeyTimes = wfMemcKey('mOasisLatestActivity_times', $wgLang->getCode()); $this->changeList = $wgMemc->get($mKeyTimes, array()); } if (empty($this->changeList) && !empty($feedData) && is_array($feedData['results'])) { $changeList = array(); foreach ($feedData['results'] as $change) { $item = array(); $item['time_ago'] = wfTimeFormatAgoOnlyRecent($change['timestamp']); // TODO: format the timestamp on front-end to allow longer caching in memcache? $item['user_name'] = $change['username']; $item['avatar_url'] = AvatarService::getAvatarUrl($item['user_name'], 20); $item['user_href'] = AvatarService::renderLink($item['user_name']); $item['page_title'] = $change['title']; $item['changetype'] = $change['type']; $title = Title::newFromText($change['title'], $change['ns']); if (!empty($change['articleComment']) && !empty($change['url'])) { $item['page_href'] = Xml::element('a', array('href' => $change['url']), $item['page_title']); } else { if (is_object($title)) { $item['page_href'] = Xml::element('a', array('href' => $title->getLocalUrl()), $item['page_title']); } } switch ($change['type']) { case 'new': case 'edit': case 'delete': // different formatting for User Profile Pages if (!empty($this->userName)) { $item['page_href'] = wfMsg("userprofilepage-activity-{$change['type']}", $item['page_href']); $item['changemessage'] = $item['time_ago']; } else { // format message (RT #144814) $item['changemessage'] = wfMsg("oasis-latest-activity-{$change['type']}-details", $item['user_href'], $item['time_ago']); } $item['changeicon'] = $change['type']; break; default: // show just a timestamp $item['changemessage'] = $item['time_ago']; break; } $changeList[] = $item; } $this->changeList = $changeList; if (empty($this->userName)) { $wgMemc->set($mKeyTimes, $this->changeList, 60); } } // Cache the response in CDN and browser $this->response->setCacheValidity(600); wfProfileOut(__METHOD__); }
/** * Add user to aggregated user array * * @param array $commentData - ArticleComment Data * @return string userName */ private function addUser(array $commentData) { $userName = trim($commentData['author']->mName); if (!isset($this->users[$userName])) { $this->users[$userName] = ['id' => (int) $commentData['author']->mId, 'avatar' => AvatarService::getAvatarUrl($commentData['author']->mName, AvatarService::AVATAR_SIZE_MEDIUM), 'url' => $commentData['userurl']]; } return $userName; }
/** * Return information about users present in the chat channel. This method has its internal cache. Method returns * an array, where each of the users is described by the following attributes: * * username - chatter login * * avatarUrl - chatter avatar url * * editCount - number of chatter's edits * * showSince - flag indicating if we can display the information when the chatter joined the wiki * * since_year && since_month - month and year, when chatter joined this wiki * * profileUrl - link to chatter talk page (or message wall, if it's enabled) * * contribsUrl - link to chatter contribution page * @return array array containing chatters info */ public static function getChatUsersInfo() { ChatHelper::info(__METHOD__ . ': Method called'); global $wgReadOnly; wfProfileIn(__METHOD__); $chatters = []; if (empty($wgReadOnly)) { // cache the whole response // individual users are cached anyway, but still we gain performance making just one memcache request instead of several $chatters = WikiaDataAccess::cache(self::getChatUsersMemcKey(), ChatEntryPoint::CHAT_USER_LIST_CACHE, function () { global $wgEnableWallExt; $chatters = []; // Gets array of users currently in chat to populate rail module and user stats menus $chattersIn = NodeApiClient::getChatters(); foreach ($chattersIn as $i => $val) { $chatters[$i] = WikiaDataAccess::cache(wfMemcKey('chatavatars', $val, 'v2'), 60 * 60, function () use($wgEnableWallExt, $val) { $chatter = ['username' => $val, 'avatarUrl' => AvatarService::getAvatarUrl($val, ChatRailController::AVATAR_SIZE)]; // get stats for edit count and member since $user = User::newFromName($val); if ($user instanceof User) { $userStatsService = new UserStatsService($user->getId()); $stats = $userStatsService->getStats(); // edit count $chatter['editCount'] = $stats['edits']; // member since $chatter['showSince'] = $chatter['editCount'] != 0; if ($chatter['showSince']) { $date = getdate(strtotime($stats['date'])); $chatter['since_year'] = $date['year']; $chatter['since_month'] = $date['mon']; } if (!empty($wgEnableWallExt)) { $chatter['profileUrl'] = Title::makeTitle(NS_USER_WALL, $chatter['username'])->getFullURL(); } else { $chatter['profileUrl'] = Title::makeTitle(NS_USER_TALK, $chatter['username'])->getFullURL(); } $chatter['contribsUrl'] = SpecialPage::getTitleFor('Contributions', $chatter['username'])->getFullURL(); } return $chatter; }); } return $chatters; }); } wfProfileOut(__METHOD__); return $chatters; }
/** * This is the ajax-endpoint that the node server will connect to in order to get the currently logged-in user's info. * The node server will pass the same cookies that the client has set, and this will allow this ajax request to be * part of the same sesssion that the user already has going. By doing this, the user's existing wikia login session * can be used, so they don't need to re-login for us to know that they are legitimately authorized to use the chat or not. * * The returned info is just a custom subset of what the node server needs and does not contain an exhaustive list of rights. * * The 'isLoggedIn' field and 'canChat' field of the result should be checked by the calling code before allowing * the user to chat. This is the last line of security against any users attemptin to circumvent our protections. Otherwise, * a banned user could copy the entire client code (HTML/JS/etc.) from an unblocked user, then run that code while logged in as * under a banned account, and they would still be given access. * * The returned 'isChatMod' field is boolean based on whether the user is a chat moderator on the current wiki. * * If the user is not allowed to chat, an error message is returned (which can be shown to the user). */ public static function getUserInfo() { global $wgMemc, $wgServer, $wgArticlePath, $wgRequest, $wgCityId, $wgContLang, $wgIP; wfProfileIn(__METHOD__); $data = $wgMemc->get($wgRequest->getVal('key'), false); if (empty($data)) { return array('errorMsg' => wfMsg('chat-room-is-not-on-this-wiki')); } $user = User::newFromId($data['user_id']); if (empty($user) || !$user->isLoggedIn() || $user->getName() != $wgRequest->getVal('name', '')) { wfProfileOut(__METHOD__); return array('errorMsg' => wfMsg('chat-room-is-not-on-this-wiki')); } $isCanGiveChatMode = false; $userChangeableGroups = $user->changeableGroups(); if (in_array('chatmoderator', $userChangeableGroups['add'])) { $isCanGiveChatMode = true; } // First, check if they can chat on this wiki. $retVal = array('canChat' => Chat::canChat($user), 'isLoggedIn' => $user->isLoggedIn(), 'isChatMod' => $user->isAllowed('chatmoderator'), 'isCanGiveChatMode' => $isCanGiveChatMode, 'isStaff' => $user->isAllowed('chatstaff'), 'username' => $user->getName(), 'avatarSrc' => AvatarService::getAvatarUrl($user->getName(), self::CHAT_AVATAR_DIMENSION), 'editCount' => "", 'since' => '', 'activeBasket' => ChatHelper::getServerBasket(), 'wgCityId' => $wgCityId, 'wgServer' => $wgServer, 'wgArticlePath' => $wgArticlePath); // Figure out the error message to return (i18n is done on this side). if ($retVal['isLoggedIn'] === false) { $retVal['errorMsg'] = wfMsg('chat-no-login'); } else { if ($retVal['canChat'] === false) { $retVal['errorMsg'] = wfMsg('chat-you-are-banned-text'); } } // If the user is approved to chat, make sure the roomId provided is for this wiki. // Users may be banned on the wiki of the room, but not on this wiki for example, so this prevents cross-wiki chat hacks. if ($retVal['canChat']) { $roomId = $wgRequest->getVal('roomId'); $cityIdOfRoom = NodeApiClient::getCityIdForRoom($roomId); if ($wgCityId !== $cityIdOfRoom) { $retVal['canChat'] = false; // don't let the user chat in the room they requested. $retVal['errorMsg'] = wfMsg('chat-room-is-not-on-this-wiki'); } } // If the user can chat, dig up some other stats which are a little more expensive to compute. if ($retVal['canChat']) { $userStatsService = new UserStatsService($user->getId()); $stats = $userStatsService->getStats(); // NOTE: This is attached to the user so it will be in the wiki's content language instead of wgLang (which it normally will). $stats['edits'] = $wgContLang->formatNum($stats['edits']); if (empty($stats['date'])) { // If the user has not edited on this wiki, don't show anything $retVal['since'] = ""; } else { // this results goes to chat server, which obiously has no user lang // so we just return a short month name key - it has to be translated on client side $date = getdate(wfTimestamp(TS_UNIX, $stats['date'])); $retVal['since'] = $date; } $retVal['editCount'] = $stats['edits']; } if ($retVal['isLoggedIn'] && $retVal['canChat']) { // record the IP of the connecting user. // use memcache so we order only one (user, ip) pair each day $ip = $wgRequest->getVal('address'); $memcKey = self::getUserIPMemcKey($data['user_id'], $ip, date("Y-m-d")); $entry = $wgMemc->get($memcKey, false); if (empty($entry)) { $wgMemc->set($memcKey, true, 86400); $log = WF::build('LogPage', array('chatconnect', false, false)); $log->addEntry('chatconnect', SpecialPage::getTitleFor('Chat'), '', array($ip), $user); $dbw = wfGetDB(DB_MASTER); $cuc_id = $dbw->nextSequenceValue('cu_changes_cu_id_seq'); $rcRow = array('cuc_id' => $cuc_id, 'cuc_namespace' => NS_SPECIAL, 'cuc_title' => 'Chat', 'cuc_minor' => 0, 'cuc_user' => $user->getID(), 'cuc_user_text' => $user->getName(), 'cuc_actiontext' => wfMsgForContent('chat-checkuser-join-action'), 'cuc_comment' => '', 'cuc_this_oldid' => 0, 'cuc_last_oldid' => 0, 'cuc_type' => CUC_TYPE_CHAT, 'cuc_timestamp' => $dbw->timestamp(), 'cuc_ip' => IP::sanitizeIP($ip), 'cuc_ip_hex' => $ip ? IP::toHex($ip) : null, 'cuc_xff' => '', 'cuc_xff_hex' => null, 'cuc_agent' => null); $dbw->insert('cu_changes', $rcRow, __METHOD__); $dbw->commit(); } } wfProfileOut(__METHOD__); return $retVal; }
<li class="forum-reply"> <img class="forum-user-avatar" src="<?php echo AvatarService::getAvatarUrl($reply['userName'], 50); ?> "> <div class="forum-user-name"> <a href="<?php echo $reply['userUrl']; ?> "><?php echo $reply['displayName']; ?> </a> </div> <div class="forum-message-body"> <?php echo $reply['messageBody']; ?> <time class="forum-timestamp timeago" datetime="<?php echo $reply['timeStamp']; ?> "><?php echo $reply['timeStamp']; ?> </time> </div> </li>
public function executeIndex() { ChatHelper::info(__METHOD__ . ': Method called'); global $wgUser, $wgFavicon, $wgOut, $wgHooks, $wgSitename; wfProfileIn(__METHOD__); // String replacement logic taken from includes/Skin.php $this->wgFavicon = str_replace('images.wikia.com', 'images1.wikia.nocookie.net', $wgFavicon); $this->mainPageURL = Title::newMainPage()->getLocalURL(); // add messages (fetch them using <script> tag) JSMessages::enqueuePackage('Chat', JSMessages::EXTERNAL); // package defined in Chat_setup.php $this->jsMessagePackagesUrl = JSMessages::getExternalPackagesUrl(); // Variables for this user $this->username = $wgUser->getName(); $this->avatarUrl = AvatarService::getAvatarUrl($this->username, ChatController::CHAT_AVATAR_DIMENSION); // Find the chat for this wiki (or create it, if it isn't there yet). $this->roomId = (int) NodeApiClient::getDefaultRoomId(); // we overwrite here data from redis since it causes a bug DAR-1532 $this->roomName = $wgSitename; $this->roomTopic = wfMsg('chat-default-topic', $wgSitename); $this->chatkey = Chat::echoCookies(); // Set the hostname of the node server that the page will connect to. $chathost = ChatHelper::getChatConfig('ChatHost'); $server = explode(":", $chathost); $this->nodeHostname = $server[0]; $this->nodePort = $server[1]; $chatmain = ChatHelper::getServer('Main'); $this->nodeInstance = $chatmain['serverId']; // Some building block for URLs that the UI needs. $this->pathToProfilePage = Title::makeTitle(!empty($this->wg->EnableWallExt) ? NS_USER_WALL : NS_USER_TALK, '$1')->getFullURL(); $this->pathToContribsPage = SpecialPage::getTitleFor('Contributions', '$1')->getFullURL(); $this->bodyClasses = ""; if ($wgUser->isAllowed('chatmoderator')) { $this->isChatMod = 1; $this->bodyClasses .= ' chat-mod '; } else { $this->isChatMod = 0; } // Adding chatmoderator group for other users. CSS classes added to body tag to hide/show option in menu. $userChangeableGroups = $wgUser->changeableGroups(); if (in_array('chatmoderator', $userChangeableGroups['add'])) { $this->bodyClasses .= ' can-give-chat-mod '; } // set up global js variables just for the chat page $wgHooks['MakeGlobalVariablesScript'][] = array($this, 'onMakeGlobalVariablesScript'); $wgOut->getResourceLoader()->getModule('mediawiki'); $ret = implode("\n", array($wgOut->getHeadLinks(null, true), $wgOut->buildCssLinks(), $wgOut->getHeadScripts(), $wgOut->getHeadItems())); $this->globalVariablesScript = $ret; //Theme Designer stuff $themeSettingObj = new ThemeSettings(); $themeSettings = $themeSettingObj->getSettings(); $this->themeSettings = $themeSettings; $this->wordmarkThumbnailUrl = ''; if ($themeSettings['wordmark-type'] == 'graphic') { $title = Title::newFromText($themeSettings['wordmark-image-name'], NS_FILE); if ($title) { $image = wfFindFile($title); if ($image) { $this->wordmarkThumbnailUrl = $image->createThumb(self::CHAT_WORDMARK_WIDTH, self::CHAT_WORDMARK_HEIGHT); } } if (empty($this->wordmarkThumbnailUrl)) { $this->wordmarkThumbnailUrl = WikiFactory::getLocalEnvURL($themeSettings['wordmark-image-url']); } } // CONN-436: Invalidate Varnish cache for ChatRail:GetUsers ChatRailController::purgeMethod('GetUsers', ['format' => 'json']); wfProfileOut(__METHOD__); }
/** * Prepare a pre-rendered chat entry point for logged-in users */ public static function onMakeGlobalVariablesScript(&$vars) { global $wgUser, $wgLang; if ($wgUser->isLoggedIn()) { $vars['wgWikiaChatUsers'] = ChatEntryPoint::getChatUsersInfo(); if (empty($vars['wgWikiaChatUsers'])) { // we will need it to attract user to join chat $vars['wgWikiaChatProfileAvatarUrl'] = AvatarService::getAvatarUrl($wgUser->getName(), ChatRailController::AVATAR_SIZE); } $vars['wgWikiaChatMonts'] = $wgLang->getMonthAbbreviationsArray(); } else { $vars['wgWikiaChatUsers'] = ''; } $vars['wgWikiaChatWindowFeatures'] = ChatRailController::CHAT_WINDOW_FEATURES; return true; }
/** * @author Jakub Kurcek * @param format string 'rss' or 'atom' */ private function FeedAchivementsLeaderboard($format) { global $wgEnableAchievementsExt, $wgLang; if (empty($wgEnableAchievementsExt)) { $this->showMenu(); } else { // local settings $maxEntries = 20; $howOld = 3; $userAvatarSize = 48; $rankingService = new AchRankingService(); $ranking = $rankingService->getUsersRanking(20); $levels = array(BADGE_LEVEL_PLATINUM, BADGE_LEVEL_GOLD, BADGE_LEVEL_SILVER, BADGE_LEVEL_BRONZE); $recents = array(); $specialPage = SpecialPageFactory::getPage('Leaderboard'); $specialPageTitle = $specialPage->getTitle(); $pageUrl = $specialPageTitle->getFullUrl(); foreach ($levels as $level) { $limit = 3; $blackList = null; if ($level == BADGE_LEVEL_BRONZE) { if ($maxEntries <= 0) { break; } $limit = $maxEntries; $blackList = array(BADGE_WELCOME); } $awardedBadges = $rankingService->getRecentAwardedBadges($level, $limit, $howOld, $blackList); if ($total = count($awardedBadges)) { $recents[$level] = $awardedBadges; $maxEntries -= $total; } } $feedArray = array(); foreach ($ranking as $rank => $rankedUser) { ++$rank; $name = htmlspecialchars($rankedUser->getName()); $feedArray[] = array('title' => $name, 'description' => $wgLang->formatNum($rankedUser->getScore()), 'url' => $pageUrl, 'date' => time(), 'author' => '', '', 'otherTags' => array('media:thumbnail' => AvatarService::getAvatarUrl($rankedUser->getName(), $userAvatarSize))); } $this->showFeed($format, wfMsg('feed-title-leaderboard'), $feedArray); } }
public static function onParserAfterTidy(Parser &$parser, &$text) { global $wgArticleAsJson; wfProfileIn(__METHOD__); if ($wgArticleAsJson && !is_null($parser->getRevisionId())) { $userName = $parser->getRevisionUser(); if (!empty($userName)) { if (User::isIP($userName)) { self::addUserObj(['userId' => 0, 'userName' => $userName, 'userThumbUrl' => AvatarService::getAvatarUrl($userName, AvatarService::AVATAR_SIZE_MEDIUM), 'userPageUrl' => Title::newFromText($userName)->getLocalURL()]); } else { $user = User::newFromName($userName); if ($user instanceof User) { self::addUserObj(['userId' => $user->getId(), 'userName' => $user->getName(), 'userThumbUrl' => AvatarService::getAvatarUrl($user, AvatarService::AVATAR_SIZE_MEDIUM), 'userPageUrl' => $user->getUserPage()->getLocalURL()]); } } } foreach (self::$media as &$media) { self::linkifyMediaCaption($parser, $media); } $text = json_encode(['content' => $text, 'media' => self::$media, 'users' => self::$users]); } wfProfileOut(__METHOD__); return true; }
private function getAvatar($user) { $cut = $this->imageServing->getCut(100, 100, "center", false); return array("name" => 'avatar', "url" => AvatarService::getAvatarUrl($user, $cut)); }
function wfCOPageHeaderIndexAfterExecute(&$controller, &$params) { if (wfCOCheck()) { if (isset($controller->content_actions['delete'])) { $action = $controller->content_actions['delete']; $action['text'] = wfMsgHtml('comments-only-delete-thread'); $controller->actionName = 'delete'; $controller->action = $action; } else { $controller->action = null; $controller->actionName = ''; } $controller->dropdown = array(); if ($controller->revisions) { global $wgTitle; $rev = $wgTitle->getFirstRevision(); if ($rev) { $user = User::newFromId($rev->getUser()); if ($user) { $controller->revisions = array('current' => array('user' => $user->getName(), 'link' => AvatarService::renderLink($user->getName()), 'avatarUrl' => AvatarService::getAvatarUrl($user->getName()), 'timestamp' => wfTimestamp(TS_ISO_8601, $rev->getTimestamp()))); } } } } return true; }
/** * @static * @param Title $fileTitle * @param array $config ( contextWidth, contextHeight, imageMaxWidth, userAvatarWidth ) * TODO - this method is very specific to lightbox. This needs to be refactored back out to lightbox, and return just the basic objects (file, user, tect) * @return array */ public static function getMediaDetail($fileTitle, $config = array()) { $data = array('mediaType' => '', 'videoEmbedCode' => '', 'playerAsset' => '', 'imageUrl' => '', 'fileUrl' => '', 'rawImageUrl' => '', 'description' => '', 'userThumbUrl' => '', 'userId' => '', 'userName' => '', 'userPageUrl' => '', 'articles' => array(), 'providerName' => '', 'videoViews' => 0, 'exists' => false, 'isAdded' => true, 'extraHeight' => 0); if (!empty($fileTitle)) { if ($fileTitle->getNamespace() != NS_FILE) { $fileTitle = Title::newFromText($fileTitle->getDBKey(), NS_FILE); } $file = self::getFileFromTitle($fileTitle, true); if (!empty($file)) { $config = self::getMediaDetailConfig($config); $data['exists'] = true; $data['mediaType'] = self::isFileTypeVideo($file) ? 'video' : 'image'; $width = (int) $file->getWidth(); $height = (int) $file->getHeight(); if ($data['mediaType'] == 'video') { $width = $config['contextWidth'] ? $config['contextWidth'] : $width; $height = $config['contextHeight'] ? $config['contextHeight'] : $height; if (isset($config['maxHeight'])) { $file->setEmbedCodeMaxHeight($config['maxHeight']); } $options = ['autoplay' => true, 'isAjax' => true, 'isInline' => !empty($config['isInline'])]; $data['videoEmbedCode'] = $file->getEmbedCode($width, $options); $data['playerAsset'] = $file->getPlayerAssetUrl(); $data['videoViews'] = MediaQueryService::getTotalVideoViewsByTitle($fileTitle->getDBKey()); $data['providerName'] = $file->getProviderName(); $data['duration'] = $file->getMetadataDuration(); $data['isAdded'] = self::isAdded($file); $mediaPage = self::getMediaPage($fileTitle); // Extra height is needed for lightbox when more elements must be fitted if (strtolower($data['providerName']) == 'crunchyroll') { $data['extraHeight'] = CrunchyrollVideoHandler::CRUNCHYROLL_WIDGET_HEIGHT_PX; } } else { $width = !empty($config['imageMaxWidth']) ? min($config['imageMaxWidth'], $width) : $width; $mediaPage = new ImagePage($fileTitle); } $thumb = $file->transform(array('width' => $width, 'height' => $height), 0); $user = User::newFromId($file->getUser('id')); // get article list $mediaQuery = new ArticlesUsingMediaQuery($fileTitle); $articleList = $mediaQuery->getArticleList(); if ($data['isAdded']) { $data['fileUrl'] = $fileTitle->getFullUrl(); } else { $data['fileUrl'] = self::getFullUrlPremiumVideo($fileTitle->getDBkey()); } $data['imageUrl'] = $thumb->getUrl(); $data['rawImageUrl'] = $file->getUrl(); $data['userId'] = $user->getId(); $data['userName'] = $user->getName(); $data['userThumbUrl'] = AvatarService::getAvatarUrl($user, $config['userAvatarWidth']); $data['userPageUrl'] = $user->getUserPage()->getFullURL(); $data['description'] = $mediaPage->getContent(); $data['articles'] = $articleList; $data['width'] = $width; $data['height'] = $height; } } return $data; }
/** * @desc Renders Wikia Maps placeholder * * @return null|string */ public function mapThumbnail() { $params = $this->getMapPlaceholderParams(); $userName = $params->map->created_by; $isMobile = $this->app->checkskin('wikiamobile'); if ($isMobile) { //proper image is lazy loaded from the thumbnailer $params->map->imagePlaceholder = $this->wg->BlankImgUrl; $params->map->mobile = true; $params->map->href = WikiaMapsSpecialController::getSpecialUrl() . '/' . $params->map->id; } else { $params->map->image = $this->mapsModel->createCroppedThumb($params->map->image, self::DEFAULT_WIDTH, self::DEFAULT_HEIGHT); } $renderParams = $this->mapsModel->getMapRenderParams($params->map->city_id); $params->map->url = $this->mapsModel->getMapRenderUrl([$params->map->id, $params->zoom, $params->lat, $params->lon], $renderParams); $this->setVal('map', (object) $params->map); $this->setVal('params', $params); $this->setVal('created_by', wfMessage('wikia-interactive-maps-parser-tag-created-by', $userName)->text()); $this->setVal('avatarUrl', AvatarService::getAvatarUrl($userName, AvatarService::AVATAR_SIZE_SMALL)); $this->setVal('view', wfMessage('wikia-interactive-maps-parser-tag-view')->plain()); $this->response->setTemplateEngine(WikiaResponse::TEMPLATE_ENGINE_MUSTACHE); if ($isMobile) { $this->overrideTemplate('mapThumbnail_mobile'); } }
/** * Get recent revisions of current article and format them */ protected function getRecentRevisions() { global $wgTitle, $wgMemc; // use service to get data $service = new PageStatsService($wgTitle->getArticleId()); // get info about current revision and list of authors of recent five edits // This key is refreshed by the onArticleSaveComplete() hook $mKey = wfMemcKey('mOasisRecentRevisions2', $wgTitle->getArticleId()); $revisions = $wgMemc->get($mKey); if (empty($revisions)) { $revisions = $service->getCurrentRevision(); // format timestamps, render avatars and user links if (is_array($revisions)) { foreach($revisions as &$revision) { if (isset($revision['user'])) { $revision['avatarUrl'] = AvatarService::getAvatarUrl($revision['user']); $revision['link'] = AvatarService::renderLink($revision['user']); } } } $wgMemc->set($mKey, $revisions); } return $revisions; }