/** * * * @param $Sender * @param $Args * @throws Gdn_UserException */ public function commentModel_afterSaveComment_handler($Sender, $Args) { if (!$this->socialSharing()) { return; } if (!$this->accessToken()) { return; } $ShareFacebook = valr('FormPostValues.ShareFacebook', $Args); if ($ShareFacebook) { $Row = $Args['FormPostValues']; $DiscussionModel = new DiscussionModel(); $Discussion = $DiscussionModel->getID(val('DiscussionID', $Row)); if (!$Discussion) { die('no discussion'); } $Url = DiscussionUrl($Discussion, '', true); $Message = SliceParagraph(Gdn_Format::plainText($Row['Body'], $Row['Format']), 160); if ($this->accessToken()) { $R = $this->api('/me/feed', array('link' => $Url, 'message' => $Message)); } } }
/** * Examines the page at $Url for title, description & images. Be sure to check the resultant array for any Exceptions that occurred while retrieving the page. * @param string $Url The url to examine. * @param integer $Timeout How long to allow for this request. Default Garden.SocketTimeout or 1, 0 to never timeout. Default is 0. * @return array an array containing Url, Title, Description, Images (array) and Exception (if there were problems retrieving the page). */ function FetchPageInfo($Url, $Timeout = 3) { $PageInfo = array('Url' => $Url, 'Title' => '', 'Description' => '', 'Images' => array(), 'Exception' => FALSE); try { if (!defined('HDOM_TYPE_ELEMENT')) { require_once PATH_LIBRARY . '/vendors/simplehtmldom/simple_html_dom.php'; } $PageHtml = ProxyRequest($Url, $Timeout, TRUE); $Dom = str_get_html($PageHtml); if (!$Dom) { throw new Exception('Failed to load page for parsing.'); } /* Sample Facebook Open Graph code: <meta property="og:title" content="60 degrees in February" /> <meta property="og:url" content="http://karinemily.wordpress.com/2012/02/02/60-degrees-in-february/" /> <meta property="og:description" content="and Philadelphia explodes with babies, puppies, and hipsters." /> <meta property="og:site_name" content="K a r i ' s" /> <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0132.jpg?w=300&h=300" /> <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0214.jpg?w=300&h=300" /> <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0213.jpg?w=300&h=300" /> <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0221-version-2.jpg?w=300&h=300" /> */ // FIRST PASS: Look for open graph title, desc, images $PageInfo['Title'] = DomGetContent($Dom, 'meta[property=og:title]'); Trace('Getting og:description'); $PageInfo['Description'] = DomGetContent($Dom, 'meta[property=og:description]'); foreach ($Dom->find('meta[property=og:image]') as $Image) { if (isset($Image->content)) { $PageInfo['Images'][] = $Image->content; } } // SECOND PASS: Look in the page for title, desc, images if ($PageInfo['Title'] == '') { $PageInfo['Title'] = $Dom->find('title', 0)->plaintext; } if ($PageInfo['Description'] == '') { Trace('Getting meta description'); $PageInfo['Description'] = DomGetContent($Dom, 'meta[name=description]'); } // THIRD PASS: Look in the page contents if ($PageInfo['Description'] == '') { foreach ($Dom->find('p') as $element) { Trace('Looking at p for description.'); if (strlen($element->plaintext) > 150) { $PageInfo['Description'] = $element->plaintext; break; } } if (strlen($PageInfo['Description']) > 400) { $PageInfo['Description'] = SliceParagraph($PageInfo['Description'], 400); } } // Final: Still nothing? remove limitations if ($PageInfo['Description'] == '') { foreach ($Dom->find('p') as $element) { Trace('Looking at p for description (no restrictions)'); if (trim($element->plaintext) != '') { $PageInfo['Description'] = $element->plaintext; break; } } } // Page Images if (count($PageInfo['Images']) == 0) { $Images = DomGetImages($Dom, $Url); $PageInfo['Images'] = array_values($Images); } $PageInfo['Title'] = HtmlEntityDecode($PageInfo['Title']); $PageInfo['Description'] = HtmlEntityDecode($PageInfo['Description']); } catch (Exception $ex) { $PageInfo['Exception'] = $ex->getMessage(); } return $PageInfo; }
/** * * * @param PostController $Sender * @param type $RecordType * @param type $ID * @throws type */ public function postController_twitter_create($Sender, $RecordType, $ID) { if (!$this->socialReactions()) { throw permissionException(); } // if (!Gdn::request()->isPostBack()) // throw permissionException('Javascript'); $Row = GetRecord($RecordType, $ID, true); if ($Row) { // Grab the tweet message. switch (strtolower($RecordType)) { case 'discussion': $Message = Gdn_Format::plainText($Row['Name'], 'Text'); break; case 'comment': default: $Message = Gdn_Format::plainText($Row['Body'], $Row['Format']); } $Elips = '...'; $Message = preg_replace('`\\s+`', ' ', $Message); // if (function_exists('normalizer_is_normalized')) { // // Slice the string to 119 characters (21 reservered for the url. // if (!normalizer_is_normalized($Message)) // $Message = Normalizer::normalize($Message, Normalizer::FORM_D); // $Elips = Normalizer::normalize($Elips, Normalizer::FORM_D); // } $Max = 140; $LinkLen = 22; $Max -= $LinkLen; $Message = SliceParagraph($Message, $Max); if (strlen($Message) > $Max) { $Message = substr($Message, 0, $Max - strlen($Elips)) . $Elips; } // echo $Message.strlen($Message); if ($this->accessToken()) { Gdn::controller()->setData('Message', $Message); $Message .= ' ' . $Row['ShareUrl']; $R = $this->api('/statuses/update.json', array('status' => $Message), 'POST'); $Sender->setJson('R', $R); $Sender->informMessage(t('Thanks for sharing!')); } else { $Get = array('text' => $Message, 'url' => $Row['ShareUrl']); $Url = "https://twitter.com/share?" . http_build_query($Get); redirect($Url); } } $Sender->render('Blank', 'Utility', 'Dashboard'); }
/** * Examine a page at {@link $Url} for title, description & images. * * Be sure to check the resultant array for any Exceptions that occurred while retrieving the page. * * @param string $url The url to examine. * @param integer $timeout How long to allow for this request. * Default Garden.SocketTimeout or 1, 0 to never timeout. Default is 0. * @param bool $sendCookies Whether or not to send browser cookies with the request. * @return array Returns an array containing Url, Title, Description, Images (array) and Exception * (if there were problems retrieving the page). */ function fetchPageInfo($url, $timeout = 3, $sendCookies = false) { $PageInfo = array('Url' => $url, 'Title' => '', 'Description' => '', 'Images' => array(), 'Exception' => false); try { // Make sure the URL is valid. $urlParts = parse_url($url); if ($urlParts === false || !in_array(val('scheme', $urlParts), array('http', 'https'))) { throw new Exception('Invalid URL.', 400); } if (!defined('HDOM_TYPE_ELEMENT')) { require_once PATH_LIBRARY . '/vendors/simplehtmldom/simple_html_dom.php'; } $Request = new ProxyRequest(); $PageHtml = $Request->Request(array('URL' => $url, 'Timeout' => $timeout, 'Cookies' => $sendCookies)); if (!$Request->status()) { throw new Exception('Couldn\'t connect to host.', 400); } $Dom = str_get_html($PageHtml); if (!$Dom) { throw new Exception('Failed to load page for parsing.'); } // FIRST PASS: Look for open graph title, desc, images $PageInfo['Title'] = domGetContent($Dom, 'meta[property=og:title]'); Trace('Getting og:description'); $PageInfo['Description'] = domGetContent($Dom, 'meta[property=og:description]'); foreach ($Dom->find('meta[property=og:image]') as $Image) { if (isset($Image->content)) { $PageInfo['Images'][] = $Image->content; } } // SECOND PASS: Look in the page for title, desc, images if ($PageInfo['Title'] == '') { $PageInfo['Title'] = $Dom->find('title', 0)->plaintext; } if ($PageInfo['Description'] == '') { Trace('Getting meta description'); $PageInfo['Description'] = domGetContent($Dom, 'meta[name=description]'); } // THIRD PASS: Look in the page contents if ($PageInfo['Description'] == '') { foreach ($Dom->find('p') as $element) { Trace('Looking at p for description.'); if (strlen($element->plaintext) > 150) { $PageInfo['Description'] = $element->plaintext; break; } } if (strlen($PageInfo['Description']) > 400) { $PageInfo['Description'] = SliceParagraph($PageInfo['Description'], 400); } } // Final: Still nothing? remove limitations if ($PageInfo['Description'] == '') { foreach ($Dom->find('p') as $element) { Trace('Looking at p for description (no restrictions)'); if (trim($element->plaintext) != '') { $PageInfo['Description'] = $element->plaintext; break; } } } // Page Images if (count($PageInfo['Images']) == 0) { $Images = domGetImages($Dom, $url); $PageInfo['Images'] = array_values($Images); } $PageInfo['Title'] = htmlEntityDecode($PageInfo['Title']); $PageInfo['Description'] = htmlEntityDecode($PageInfo['Description']); } catch (Exception $ex) { $PageInfo['Exception'] = $ex->getMessage(); } return $PageInfo; }
/** * Default single discussion display. * * @since 2.0.0 * @access public * * @param int $DiscussionID Unique discussion ID * @param string $DiscussionStub URL-safe title slug * @param int $Page The current page of comments */ public function Index($DiscussionID = '', $DiscussionStub = '', $Page = '') { // Setup head $Session = Gdn::Session(); $this->AddJsFile('jquery.autogrow.js'); $this->AddJsFile('discussion.js'); $this->AddJsFile('autosave.js'); Gdn_Theme::Section('Discussion'); // Load the discussion record $DiscussionID = is_numeric($DiscussionID) && $DiscussionID > 0 ? $DiscussionID : 0; if (!array_key_exists('Discussion', $this->Data)) { $this->SetData('Discussion', $this->DiscussionModel->GetID($DiscussionID), TRUE); } if (!is_object($this->Discussion)) { throw new Exception(sprintf(T('%s Not Found'), T('Discussion')), 404); } // Define the query offset & limit. $Limit = C('Vanilla.Comments.PerPage', 30); $OffsetProvided = $Page != ''; list($Offset, $Limit) = OffsetLimit($Page, $Limit); // Check permissions $this->Permission('Vanilla.Discussions.View', TRUE, 'Category', $this->Discussion->PermissionCategoryID); $this->SetData('CategoryID', $this->CategoryID = $this->Discussion->CategoryID, TRUE); $this->SetData('Breadcrumbs', CategoryModel::GetAncestors($this->CategoryID)); $Category = CategoryModel::Categories($this->Discussion->CategoryID); if ($CategoryCssClass = GetValue('CssClass', $Category)) { Gdn_Theme::Section($CategoryCssClass); } // Setup $this->Title($this->Discussion->Name); // Actual number of comments, excluding the discussion itself. $ActualResponses = $this->Discussion->CountComments; $this->Offset = $Offset; if (C('Vanilla.Comments.AutoOffset')) { // if ($this->Discussion->CountCommentWatch > 1 && $OffsetProvided == '') // $this->AddDefinition('ScrollTo', 'a[name=Item_'.$this->Discussion->CountCommentWatch.']'); if (!is_numeric($this->Offset) || $this->Offset < 0 || !$OffsetProvided) { // Round down to the appropriate offset based on the user's read comments & comments per page $CountCommentWatch = $this->Discussion->CountCommentWatch > 0 ? $this->Discussion->CountCommentWatch : 0; if ($CountCommentWatch > $ActualResponses) { $CountCommentWatch = $ActualResponses; } // (((67 comments / 10 perpage) = 6.7) rounded down = 6) * 10 perpage = offset 60; $this->Offset = floor($CountCommentWatch / $Limit) * $Limit; } if ($ActualResponses <= $Limit) { $this->Offset = 0; } if ($this->Offset == $ActualResponses) { $this->Offset -= $Limit; } } else { if ($this->Offset == '') { $this->Offset = 0; } } if ($this->Offset < 0) { $this->Offset = 0; } $LatestItem = $this->Discussion->CountCommentWatch; if ($LatestItem === NULL) { $LatestItem = 0; } elseif ($LatestItem < $this->Discussion->CountComments) { $LatestItem += 1; } $this->SetData('_LatestItem', $LatestItem); // Set the canonical url to have the proper page title. $this->CanonicalUrl(DiscussionUrl($this->Discussion, PageNumber($this->Offset, $Limit, 0, FALSE))); // Url(ConcatSep('/', 'discussion/'.$this->Discussion->DiscussionID.'/'. Gdn_Format::Url($this->Discussion->Name), PageNumber($this->Offset, $Limit, TRUE, Gdn::Session()->UserID != 0)), TRUE), Gdn::Session()->UserID == 0); // Load the comments $this->SetData('Comments', $this->CommentModel->Get($DiscussionID, $Limit, $this->Offset)); $PageNumber = PageNumber($this->Offset, $Limit); $this->SetData('Page', $PageNumber); $this->_SetOpenGraph(); include_once PATH_LIBRARY . '/vendors/simplehtmldom/simple_html_dom.php'; if ($PageNumber == 1) { $this->Description(SliceParagraph(Gdn_Format::PlainText($this->Discussion->Body, $this->Discussion->Format), 160)); // Add images to head for open graph $Dom = str_get_html(Gdn_Format::To($this->Discussion->Body, $this->Discussion->Format)); } else { $this->Data['Title'] .= sprintf(T(' - Page %s'), PageNumber($this->Offset, $Limit)); $FirstComment = $this->Data('Comments')->FirstRow(); $FirstBody = GetValue('Body', $FirstComment); $FirstFormat = GetValue('Format', $FirstComment); $this->Description(SliceParagraph(Gdn_Format::PlainText($FirstBody, $FirstFormat), 160)); // Add images to head for open graph $Dom = str_get_html(Gdn_Format::To($FirstBody, $FirstFormat)); } if ($Dom) { foreach ($Dom->find('img') as $img) { if (isset($img->src)) { $this->Image($img->src); } } } // Make sure to set the user's discussion watch records $this->CommentModel->SetWatch($this->Discussion, $Limit, $this->Offset, $this->Discussion->CountComments); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->EventArguments['PagerType'] = 'Pager'; $this->FireEvent('BeforeBuildPager'); $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this); $this->Pager->ClientID = 'Pager'; $this->Pager->Configure($this->Offset, $Limit, $ActualResponses, array('DiscussionUrl')); $this->Pager->Record = $this->Discussion; PagerModule::Current($this->Pager); $this->FireEvent('AfterBuildPager'); // Define the form for the comment input $this->Form = Gdn::Factory('Form', 'Comment'); $this->Form->Action = Url('/vanilla/post/comment/'); $this->DiscussionID = $this->Discussion->DiscussionID; $this->Form->AddHidden('DiscussionID', $this->DiscussionID); $this->Form->AddHidden('CommentID', ''); // Look in the session stash for a comment $StashComment = $Session->Stash('CommentForDiscussionID_' . $this->Discussion->DiscussionID, '', FALSE); if ($StashComment) { $this->Form->SetFormValue('Body', $StashComment); } // Retrieve & apply the draft if there is one: if (Gdn::Session()->UserID) { $DraftModel = new DraftModel(); $Draft = $DraftModel->Get($Session->UserID, 0, 1, $this->Discussion->DiscussionID)->FirstRow(); $this->Form->AddHidden('DraftID', $Draft ? $Draft->DraftID : ''); if ($Draft && !$this->Form->IsPostBack()) { $this->Form->SetValue('Body', $Draft->Body); $this->Form->SetValue('Format', $Draft->Format); } } // Deliver JSON data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->SetJson('LessRow', $this->Pager->ToString('less')); $this->SetJson('MoreRow', $this->Pager->ToString('more')); $this->View = 'comments'; } // Inform moderator of checked comments in this discussion $CheckedComments = $Session->GetAttribute('CheckedComments', array()); if (count($CheckedComments) > 0) { ModerationController::InformCheckedComments($this); } // Add modules $this->AddModule('DiscussionFilterModule'); $this->AddModule('NewDiscussionModule'); $this->AddModule('CategoriesModule'); $this->AddModule('BookmarkedModule'); $this->CanEditComments = Gdn::Session()->CheckPermission('Vanilla.Comments.Edit', TRUE, 'Category', 'any') && C('Vanilla.AdminCheckboxes.Use'); // Report the discussion id so js can use it. $this->AddDefinition('DiscussionID', $DiscussionID); $this->FireEvent('BeforeDiscussionRender'); $this->Render(); }
/** * * * @param PostController $Sender * @param type $RecordType * @param type $ID * @throws type */ public function postController_googlePlus_create($Sender, $RecordType, $ID) { $Row = GetRecord($RecordType, $ID); if ($Row) { $Message = SliceParagraph(Gdn_Format::plainText($Row['Body'], $Row['Format']), 160); $Get = array('url' => $Row['ShareUrl']); $Url = 'https://plus.google.com/share?' . http_build_query($Get); redirect($Url); } $Sender->render('Blank', 'Utility', 'Dashboard'); }
/** * * @param PostController $Sender * @param type $RecordType * @param type $ID * @throws type */ public function PostController_Facebook_Create($Sender, $RecordType, $ID) { if (!$this->SocialReactions()) { throw PermissionException(); } // if (!Gdn::Request()->IsPostBack()) // throw PermissionException('Javascript'); $Row = GetRecord($RecordType, $ID); if ($Row) { $Message = SliceParagraph(Gdn_Format::PlainText($Row['Body'], $Row['Format']), 160); if ($this->AccessToken() && $Sender->Request->IsPostBack()) { $R = $this->API('/me/feed', array('link' => $Row['ShareUrl'], 'message' => $Message)); $Sender->SetJson('R', $R); $Sender->InformMessage(T('Thanks for sharing!')); } else { // http://www.facebook.com/dialog/feed?app_id=231546166870342&redirect_uri=http%3A%2F%2Fvanillicon.com%2Fredirect%2Ffacebook%3Fhash%3Daad66afb13105676dffa79bfe2b8595f&link=http%3A%2F%2Fvanillicon.com&picture=http%3A%2F%2Fvanillicon.com%2Faad66afb13105676dffa79bfe2b8595f.png&name=Vanillicon&caption=What%27s+Your+Vanillicon+Look+Like%3F&description=Vanillicons+are+unique+avatars+generated+by+your+name+or+email+that+are+free+to+make+%26+use+around+the+web.+Create+yours+now%21 $Get = array('app_id' => C('Plugins.Facebook.ApplicationID'), 'link' => $Row['ShareUrl'], 'name' => Gdn_Format::PlainText($Row['Name'], 'Text'), 'description' => $Message, 'redirect_uri' => Url('/post/shared/facebook', TRUE)); $Url = 'http://www.facebook.com/dialog/feed?' . http_build_query($Get); Redirect($Url); } } $Sender->Render('Blank', 'Utility', 'Dashboard'); }
/** * Examine a page at {@link $Url} for title, description & images. * * Be sure to check the resultant array for any Exceptions that occurred while retrieving the page. * * @param string $url The url to examine. * @param integer $timeout How long to allow for this request. * Default Garden.SocketTimeout or 1, 0 to never timeout. Default is 0. * @param bool $sendCookies Whether or not to send browser cookies with the request. * @return array Returns an array containing Url, Title, Description, Images (array) and Exception * (if there were problems retrieving the page). */ function fetchPageInfo($url, $timeout = 3, $sendCookies = false) { $PageInfo = array('Url' => $url, 'Title' => '', 'Description' => '', 'Images' => array(), 'Exception' => false); try { // Make sure the URL is valid. $urlParts = parse_url($url); if ($urlParts === false || !in_array(val('scheme', $urlParts), array('http', 'https'))) { throw new Exception('Invalid URL.', 400); } $Request = new ProxyRequest(); $PageHtml = $Request->Request(array('URL' => $url, 'Timeout' => $timeout, 'Cookies' => $sendCookies, 'Redirects' => true)); if (!$Request->status()) { throw new Exception('Couldn\'t connect to host.', 400); } $Dom = pQuery::parseStr($PageHtml); if (!$Dom) { throw new Exception('Failed to load page for parsing.'); } // FIRST PASS: Look for open graph title, desc, images $PageInfo['Title'] = domGetContent($Dom, 'meta[property="og:title"]'); Trace('Getting og:description'); $PageInfo['Description'] = domGetContent($Dom, 'meta[property="og:description"]'); foreach ($Dom->query('meta[property="og:image"]') as $Image) { if ($Image->attr('content')) { $PageInfo['Images'][] = $Image->attr('content'); } } // SECOND PASS: Look in the page for title, desc, images if ($PageInfo['Title'] == '') { $PageInfo['Title'] = $Dom->query('title')->text(); } if ($PageInfo['Description'] == '') { Trace('Getting meta description'); $PageInfo['Description'] = domGetContent($Dom, 'meta[name="description"]'); } // THIRD PASS: Look in the page contents if ($PageInfo['Description'] == '') { foreach ($Dom->query('p') as $element) { Trace('Looking at p for description.'); if (strlen($element->plaintext) > 150) { $PageInfo['Description'] = $element->text(); break; } } if (strlen($PageInfo['Description']) > 400) { $PageInfo['Description'] = SliceParagraph($PageInfo['Description'], 400); } } // Final: Still nothing? remove limitations if ($PageInfo['Description'] == '') { foreach ($Dom->query('p') as $element) { Trace('Looking at p for description (no restrictions)'); if (trim($element->text()) != '') { $PageInfo['Description'] = $element->text(); break; } } } // Page Images if (count($PageInfo['Images']) == 0) { $Images = domGetImages($Dom, $url); $PageInfo['Images'] = array_values($Images); } $PageInfo['Title'] = htmlEntityDecode($PageInfo['Title']); $PageInfo['Description'] = htmlEntityDecode($PageInfo['Description']); } catch (Exception $ex) { $PageInfo['Exception'] = $ex->getMessage(); } return $PageInfo; }
/** * Loads default page view. * * @param string $PageUrlCode ; Unique page URL stub identifier. */ public function Index($PageUrlCode = '') { $this->Page = $this->PageModel->GetByUrlCode($PageUrlCode); // Require the custom view permission if it exists. // Otherwise, the page is public by default. $ViewPermissionName = 'BasicPages.' . $PageUrlCode . '.View'; if (array_key_exists($ViewPermissionName, Gdn::PermissionModel()->PermissionColumns())) { $this->Permission($ViewPermissionName); } // If page doesn't exist. if ($this->Page == null) { throw new Exception(sprintf(T('%s Not Found'), T('Page')), 404); return null; } $this->SetData('Page', $this->Page, false); // Add body CSS class. $this->CssClass = 'Page-' . $this->Page->UrlCode; if (IsMobile()) { $this->CssClass .= ' PageMobile'; } // Set the canonical URL to have the proper page link. $this->CanonicalUrl(PageModel::PageUrl($this->Page)); // Add modules $this->AddModule('GuestModule'); $this->AddModule('SignedInModule'); // Add CSS files $this->AddCssFile('page.css'); $this->AddModule('NewDiscussionModule'); $this->AddModule('DiscussionFilterModule'); $this->AddModule('BookmarkedModule'); $this->AddModule('DiscussionsModule'); $this->AddModule('RecentActivityModule'); // Setup head. if (!$this->Data('Title')) { $Title = C('Garden.HomepageTitle'); $DefaultControllerDestination = Gdn::Router()->GetDestination('DefaultController'); if ($Title != '' && strpos($DefaultControllerDestination, 'page/' . $this->Page->UrlCode) !== false) { // If the page is set as DefaultController. $this->Title($Title, ''); // Add description meta tag. $this->Description(C('Garden.Description', null)); } else { // If the page is NOT the DefaultController. $this->Title($this->Page->Name); // Add description meta tag. $this->Description(SliceParagraph(Gdn_Format::PlainText($this->Page->Body, $this->Page->Format), 160)); } } $this->Render(); }