/** * User management list. * * @since 2.0.0 * @access public * @param mixed $Keywords Term or array of terms to filter list of users. * @param int $Page Page number. * @param string $Order Sort order for list. */ public function index($Keywords = '', $Page = '', $Order = '') { $this->permission(array('Garden.Users.Add', 'Garden.Users.Edit', 'Garden.Users.Delete'), '', false); // Page setup $this->addJsFile('jquery.gardenmorepager.js'); $this->addJsFile('user.js'); $this->title(t('Users')); $this->addSideMenu('dashboard/user'); // Form setup $this->Form->Method = 'get'; // Input Validation. list($Offset, $Limit) = offsetLimit($Page, PagerModule::$DefaultPageSize); if (!$Keywords) { $Keywords = $this->Form->getFormValue('Keywords'); if ($Keywords) { $Offset = 0; } } if (!is_string($Keywords)) { $Keywords = ''; } // Put the Keyword back in the form if ($Keywords) { $this->Form->setFormValue('Keywords', $Keywords); } $UserModel = new UserModel(); //$Like = trim($Keywords) == '' ? FALSE : array('u.Name' => $Keywords, 'u.Email' => $Keywords); list($Offset, $Limit) = offsetLimit($Page, 30); $Filter = $this->_GetFilter(); if ($Filter) { $Filter['Keywords'] = $Keywords; } else { $Filter = array('Keywords' => (string) $Keywords); } $Filter['Optimize'] = $this->PastUserThreshold(); // Sorting if (in_array($Order, array('DateInserted', 'DateFirstVisit', 'DateLastActive'))) { $Order = 'u.' . $Order; $OrderDir = 'desc'; } else { $Order = 'u.Name'; $OrderDir = 'asc'; } // Get user list $this->UserData = $UserModel->Search($Filter, $Order, $OrderDir, $Limit, $Offset); $this->setData('Users', $this->UserData); if ($this->PastUserThreshold()) { $this->setData('_CurrentRecords', $this->UserData->count()); } else { $this->setData('RecordCount', $UserModel->SearchCount($Filter)); } RoleModel::SetUserRoles($this->UserData->result()); // Deliver json data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL && $this->_DeliveryMethod == DELIVERY_METHOD_XHTML) { $this->setJson('LessRow', $this->Pager->toString('less')); $this->setJson('MoreRow', $this->Pager->toString('more')); $this->View = 'users'; } $this->render(); }
/** * Default search functionality. * * @since 2.0.0 * @access public * @param int $Page Page number. */ public function index($Page = '') { $this->addJsFile('search.js'); $this->title(t('Search')); saveToConfig('Garden.Format.EmbedSize', '160x90', false); Gdn_Theme::section('SearchResults'); list($Offset, $Limit) = offsetLimit($Page, c('Garden.Search.PerPage', 20)); $this->setData('_Limit', $Limit); $Search = $this->Form->getFormValue('Search'); $Mode = $this->Form->getFormValue('Mode'); if ($Mode) { $this->SearchModel->ForceSearchMode = $Mode; } try { $ResultSet = $this->SearchModel->Search($Search, $Offset, $Limit); } catch (Gdn_UserException $Ex) { $this->Form->addError($Ex); $ResultSet = array(); } catch (Exception $Ex) { LogException($Ex); $this->Form->addError($Ex); $ResultSet = array(); } Gdn::userModel()->joinUsers($ResultSet, array('UserID')); // Fix up the summaries. $SearchTerms = explode(' ', Gdn_Format::text($Search)); foreach ($ResultSet as &$Row) { $Row['Summary'] = SearchExcerpt(Gdn_Format::plainText($Row['Summary'], $Row['Format']), $SearchTerms); $Row['Summary'] = Emoji::instance()->translateToHtml($Row['Summary']); $Row['Format'] = 'Html'; } $this->setData('SearchResults', $ResultSet, true); $this->setData('SearchTerm', Gdn_Format::text($Search), true); if ($ResultSet) { $NumResults = count($ResultSet); } else { $NumResults = 0; } if ($NumResults == $Offset + $Limit) { $NumResults++; } // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->Pager = $PagerFactory->GetPager('MorePager', $this); $this->Pager->MoreCode = 'More Results'; $this->Pager->LessCode = 'Previous Results'; $this->Pager->ClientID = 'Pager'; $this->Pager->configure($Offset, $Limit, $NumResults, 'dashboard/search/%1$s/%2$s/?Search=' . Gdn_Format::url($Search)); // if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { // $this->setJson('LessRow', $this->Pager->toString('less')); // $this->setJson('MoreRow', $this->Pager->toString('more')); // $this->View = 'results'; // } $this->canonicalUrl(url('search', true)); $this->render(); }
/** * Default search functionality. * * @since 2.0.0 * @access public * @param int $Page Page number. */ public function index($Page = '') { $this->addJsFile('search.js'); $this->title(t('Search')); saveToConfig('Garden.Format.EmbedSize', '160x90', false); Gdn_Theme::section('SearchResults'); list($Offset, $Limit) = offsetLimit($Page, c('Garden.Search.PerPage', 20)); $this->setData('_Limit', $Limit); $Search = $this->Form->getFormValue('Search'); $Mode = $this->Form->getFormValue('Mode'); if ($Mode) { $this->SearchModel->ForceSearchMode = $Mode; } try { $ResultSet = $this->SearchModel->search($Search, $Offset, $Limit); } catch (Gdn_UserException $Ex) { $this->Form->addError($Ex); $ResultSet = array(); } catch (Exception $Ex) { LogException($Ex); $this->Form->addError($Ex); $ResultSet = array(); } Gdn::userModel()->joinUsers($ResultSet, array('UserID')); // Fix up the summaries. $SearchTerms = explode(' ', Gdn_Format::text($Search)); foreach ($ResultSet as &$Row) { $Row['Summary'] = searchExcerpt(htmlspecialchars(Gdn_Format::plainText($Row['Summary'], $Row['Format'])), $SearchTerms); $Row['Summary'] = Emoji::instance()->translateToHtml($Row['Summary']); $Row['Format'] = 'Html'; } $this->setData('SearchResults', $ResultSet, true); $this->setData('SearchTerm', Gdn_Format::text($Search), true); $this->setData('_CurrentRecords', count($ResultSet)); $this->canonicalUrl(url('search', true)); $this->render(); }
/** * * * @param array $Options * @throws Exception */ public static function write($Options = array()) { static $WriteCount = 0; if (!self::$_CurrentPager) { if (is_a($Options, 'Gdn_Controller')) { self::$_CurrentPager = new PagerModule($Options); $Options = array(); } else { self::$_CurrentPager = new PagerModule(val('Sender', $Options, Gdn::controller())); } } $Pager = self::$_CurrentPager; $Pager->Wrapper = val('Wrapper', $Options, $Pager->Wrapper); $Pager->MoreCode = val('MoreCode', $Options, $Pager->MoreCode); $Pager->LessCode = val('LessCode', $Options, $Pager->LessCode); $Pager->ClientID = val('ClientID', $Options, $Pager->ClientID); $Pager->Limit = val('Limit', $Options, $Pager->Controller()->data('_Limit', $Pager->Limit)); $Pager->HtmlBefore = val('HtmlBefore', $Options, val('HtmlBefore', $Pager, '')); $Pager->CurrentRecords = val('CurrentRecords', $Options, $Pager->Controller()->data('_CurrentRecords', $Pager->CurrentRecords)); // Try and figure out the offset based on the parameters coming in to the controller. if (!$Pager->Offset) { $Page = $Pager->Controller()->Request->get('Page', false); if (!$Page) { $Page = 'p1'; foreach ($Pager->Controller()->RequestArgs as $Arg) { if (preg_match('`p\\d+`', $Arg)) { $Page = $Arg; break; } } } list($Offset, $Limit) = offsetLimit($Page, $Pager->Limit); $TotalRecords = val('RecordCount', $Options, $Pager->Controller()->data('RecordCount', false)); $Get = $Pager->Controller()->Request->get(); unset($Get['Page'], $Get['DeliveryType'], $Get['DeliveryMethod']); $Url = val('Url', $Options, $Pager->Controller()->SelfUrl . '?Page={Page}&' . http_build_query($Get)); $Pager->configure($Offset, $Limit, $TotalRecords, $Url); } elseif ($Url = val('Url', $Options)) { $Pager->Url = $Url; } echo $Pager->toString($WriteCount > 0 ? 'more' : 'less'); $WriteCount++; // list($Offset, $Limit) = offsetLimit(GetValue, 20); // $Pager->configure( // $Offset, // $Limit, // $TotalAddons, // "/settings/addons/$Section?Page={Page}" // ); // $Sender->setData('_Pager', $Pager); }
/** * Manage user bans (add, edit, delete, list). * * @since 2.0.18 * @access public * @param string $Action Add, edit, delete, or none. * @param string $Search Term to filter ban list by. * @param int $Page Page number. * @param int $ID Ban ID we're editing or deleting. */ public function bans($Action = '', $Search = '', $Page = '', $ID = '') { $this->permission('Garden.Settings.Manage'); // Page setup $this->addSideMenu(); $this->title(t('Banning Options')); $this->addJsFile('bans.js'); list($Offset, $Limit) = offsetLimit($Page, 20); $BanModel = new BanModel(); $this->_BanModel = $BanModel; switch (strtolower($Action)) { case 'add': case 'edit': $this->Form->setModel($BanModel); if ($this->Form->authenticatedPostBack()) { if ($ID) { $this->Form->setFormValue('BanID', $ID); } try { // Save the ban. $NewID = $this->Form->save(); } catch (Exception $Ex) { $this->Form->addError($Ex); } } else { if ($ID) { $this->Form->setData($BanModel->getID($ID)); } } $this->setData('_BanTypes', array('IPAddress' => t('IP Address'), 'Email' => t('Email'), 'Name' => t('Name'))); $this->View = 'Ban'; break; case 'delete': if ($this->Form->authenticatedPostBack()) { $BanModel->delete(array('BanID' => $ID)); $this->View = 'BanDelete'; } break; default: $Bans = $BanModel->getWhere(array(), 'BanType, BanValue', 'asc', $Limit, $Offset)->resultArray(); $this->setData('Bans', $Bans); break; } $this->render(); }
/** * Alternate version of Index that uses the embed master view. * * @param int $DiscussionID Unique identifier, if discussion has been created. * @param string $DiscussionStub Deprecated. * @param int $Offset * @param int $Limit */ public function embed($DiscussionID = '', $DiscussionStub = '', $Offset = '', $Limit = '') { $this->title(t('Comments')); // Add theme data $this->Theme = c('Garden.CommentsTheme', $this->Theme); Gdn_Theme::section('Comments'); // Force view options $this->MasterView = 'empty'; $this->CanEditComments = false; // Don't show the comment checkboxes on the embed comments page // Add some css to help with the transparent bg on embedded comments if ($this->Head) { $this->Head->addString('<style type="text/css"> body { background: transparent !important; } </style>'); } // Javascript files & options $this->addJsFile('jquery.gardenmorepager.js'); $this->addJsFile('jquery.autosize.min.js'); $this->addJsFile('discussion.js'); $this->removeJsFile('autosave.js'); $this->addDefinition('DoInform', '0'); // Suppress inform messages on embedded page. $this->addDefinition('SelfUrl', Gdn::request()->PathAndQuery()); $this->addDefinition('Embedded', true); // Define incoming variables (prefer querystring parameters over method parameters) $DiscussionID = is_numeric($DiscussionID) && $DiscussionID > 0 ? $DiscussionID : 0; $DiscussionID = getIncomingValue('vanilla_discussion_id', $DiscussionID); $Offset = getIncomingValue('Offset', $Offset); $Limit = getIncomingValue('Limit', $Limit); $vanilla_identifier = getIncomingValue('vanilla_identifier', ''); // Only allow vanilla identifiers of 32 chars or less - md5 if larger if (strlen($vanilla_identifier) > 32) { $vanilla_identifier = md5($vanilla_identifier); } $vanilla_type = getIncomingValue('vanilla_type', 'page'); $vanilla_url = getIncomingValue('vanilla_url', ''); $vanilla_category_id = getIncomingValue('vanilla_category_id', ''); $ForeignSource = array('vanilla_identifier' => $vanilla_identifier, 'vanilla_type' => $vanilla_type, 'vanilla_url' => $vanilla_url, 'vanilla_category_id' => $vanilla_category_id); $this->setData('ForeignSource', $ForeignSource); // Set comment sorting $SortComments = c('Garden.Embed.SortComments') == 'desc' ? 'desc' : 'asc'; $this->setData('SortComments', $SortComments); // Retrieve the discussion record $Discussion = false; if ($DiscussionID > 0) { $Discussion = $this->DiscussionModel->getID($DiscussionID); } elseif ($vanilla_identifier != '' && $vanilla_type != '') { $Discussion = $this->DiscussionModel->GetForeignID($vanilla_identifier, $vanilla_type); } // Set discussion data if we have one for this page if ($Discussion) { // Allow Vanilla.Comments.View to be defined to limit access to embedded comments only. // Otherwise, go with normal discussion view permissions. Either will do. $this->permission(array('Vanilla.Discussions.View', 'Vanilla.Comments.View'), false, 'Category', $Discussion->PermissionCategoryID); $this->setData('Discussion', $Discussion, true); $this->setData('DiscussionID', $Discussion->DiscussionID, true); $this->title($Discussion->Name); // Actual number of comments, excluding the discussion itself $ActualResponses = $Discussion->CountComments; // Define the query offset & limit if (!is_numeric($Limit) || $Limit < 0) { $Limit = c('Garden.Embed.CommentsPerPage', 30); } $OffsetProvided = $Offset != ''; list($Offset, $Limit) = offsetLimit($Offset, $Limit); $this->Offset = $Offset; if (c('Vanilla.Comments.AutoOffset')) { if ($ActualResponses <= $Limit) { $this->Offset = 0; } if ($this->Offset == $ActualResponses) { $this->Offset -= $Limit; } } elseif ($this->Offset == '') { $this->Offset = 0; } if ($this->Offset < 0) { $this->Offset = 0; } // Set the canonical url to have the proper page title. $this->canonicalUrl(discussionUrl($Discussion, pageNumber($this->Offset, $Limit))); // Load the comments. $CurrentOrderBy = $this->CommentModel->orderBy(); if (stringBeginsWith(GetValueR('0.0', $CurrentOrderBy), 'c.DateInserted')) { $this->CommentModel->orderBy('c.DateInserted ' . $SortComments); // allow custom sort } $this->setData('Comments', $this->CommentModel->get($Discussion->DiscussionID, $Limit, $this->Offset), true); if (count($this->CommentModel->where()) > 0) { $ActualResponses = false; } $this->setData('_Count', $ActualResponses); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->EventArguments['PagerType'] = 'MorePager'; $this->fireEvent('BeforeBuildPager'); $this->Pager = $PagerFactory->getPager($this->EventArguments['PagerType'], $this); $this->Pager->ClientID = 'Pager'; $this->Pager->MoreCode = 'More Comments'; $this->Pager->configure($this->Offset, $Limit, $ActualResponses, 'discussion/embed/' . $Discussion->DiscussionID . '/' . Gdn_Format::url($Discussion->Name) . '/%1$s'); $this->Pager->CurrentRecords = $this->Comments->numRows(); $this->fireEvent('AfterBuildPager'); } // Define the form for the comment input $this->Form = Gdn::Factory('Form', 'Comment'); $this->Form->Action = url('/post/comment/'); $this->Form->addHidden('CommentID', ''); $this->Form->addHidden('Embedded', 'true'); // Tell the post controller that this is an embedded page (in case there are custom views it needs to pick up from a theme). $this->Form->addHidden('DisplayNewCommentOnly', 'true'); // Only load/display the new comment after posting (don't load all new comments since the page last loaded). // Grab the page title if ($this->Request->get('title')) { $this->Form->setValue('Name', $this->Request->get('title')); } // Set existing DiscussionID for comment form if ($Discussion) { $this->Form->addHidden('DiscussionID', $Discussion->DiscussionID); } foreach ($ForeignSource as $Key => $Val) { // Drop the foreign source information into the form so it can be used if creating a discussion $this->Form->addHidden($Key, $Val); // Also drop it into the definitions so it can be picked up for stashing comments $this->addDefinition($Key, $Val); } // Retrieve & apply the draft if there is one: $Draft = false; if (Gdn::session()->UserID && $Discussion) { $DraftModel = new DraftModel(); $Draft = $DraftModel->get(Gdn::session()->UserID, 0, 1, $Discussion->DiscussionID)->firstRow(); $this->Form->addHidden('DraftID', $Draft ? $Draft->DraftID : ''); } if ($Draft) { $this->Form->setFormValue('Body', $Draft->Body); } else { // Look in the session stash for a comment $StashComment = Gdn::session()->getPublicStash('CommentForForeignID_' . $ForeignSource['vanilla_identifier']); if ($StashComment) { $this->Form->setValue('Body', $StashComment); $this->Form->setFormValue('Body', $StashComment); } } // Deliver JSON data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { if ($this->Discussion) { $this->setJson('LessRow', $this->Pager->toString('less')); $this->setJson('MoreRow', $this->Pager->toString('more')); } $this->View = 'comments'; } // Ordering note for JS if ($SortComments == 'desc') { $this->addDefinition('PrependNewComments', '1'); } // Report the discussion id so js can use it. if ($Discussion) { $this->addDefinition('DiscussionID', $Discussion->DiscussionID); } $this->fireEvent('BeforeDiscussionRender'); $this->render(); }
/** * User management list. * * @since 2.0.0 * @access public * @param mixed $Keywords Term or array of terms to filter list of users. * @param int $Page Page number. * @param string $Order Sort order for list. */ public function index($Keywords = '', $Page = '', $Order = '') { $this->permission(array('Garden.Users.Add', 'Garden.Users.Edit', 'Garden.Users.Delete'), '', false); // Page setup $this->addJsFile('jquery.gardenmorepager.js'); $this->addJsFile('user.js'); $this->title(t('Users')); $this->setHighlightRoute('dashboard/user'); Gdn_Theme::section('Moderation'); // Form setup $this->Form->Method = 'get'; // Input Validation. list($Offset, $Limit) = offsetLimit($Page, PagerModule::$DefaultPageSize); if (!$Keywords) { $Keywords = $this->Form->getFormValue('Keywords'); if ($Keywords) { $Offset = 0; } } if (!is_string($Keywords)) { $Keywords = ''; } // Put the Keyword back in the form if ($Keywords) { $this->Form->setFormValue('Keywords', $Keywords); } $UserModel = new UserModel(); list($Offset, $Limit) = offsetLimit($Page, 30); // Determine our data filters. $Filter = $this->_getFilter(); if ($Filter) { $Filter['Keywords'] = $Keywords; } else { $Filter = array('Keywords' => (string) $Keywords); } $Filter['Optimize'] = Gdn::userModel()->pastUserThreshold(); // Sorting if (in_array($Order, array('DateInserted', 'DateFirstVisit', 'DateLastActive'))) { $Order = 'u.' . $Order; $OrderDir = 'desc'; } else { $Order = 'u.Name'; $OrderDir = 'asc'; } // Get user list $this->UserData = $UserModel->search($Filter, $Order, $OrderDir, $Limit, $Offset); $this->setData('Users', $this->UserData); // Figure out our number of results and users. $showUserCount = $this->UserData->count(); if (!Gdn::userModel()->pastUserThreshold()) { // Pfft, query that sucker however you want. $this->setData('RecordCount', $UserModel->searchCount($Filter)); } else { // We have a user search, so at least set enough data for the Next pager. if ($showUserCount) { $this->setData('_CurrentRecords', $showUserCount); } else { // No search was done. Just give the total users overall. First, zero-out our pager. $this->setData('_CurrentRecords', 0); if (!Gdn::userModel()->pastUserMegaThreshold()) { // Restoring this semi-optimized counter is our compromise to let non-mega sites know their exact total users. $this->setData('UserCount', $UserModel->getCount()); } else { // Dang, yo. Get a table status guess instead of really counting. $this->setData('UserEstimate', Gdn::userModel()->countEstimate()); } } } // Add roles to the user data. RoleModel::setUserRoles($this->UserData->result()); // Deliver json data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL && $this->_DeliveryMethod == DELIVERY_METHOD_XHTML) { $this->setJson('LessRow', $this->Pager->toString('less')); $this->setJson('MoreRow', $this->Pager->toString('more')); $this->View = 'users'; } $this->render(); }
/** * View spam logs. * * @since 2.0.? * @access public * * @param int $Page Page number. */ public function spam($Page = '') { $this->permission(array('Garden.Moderation.Manage', 'Moderation.Spam.Manage'), false); list($Offset, $Limit) = offsetLimit($Page, 10); $this->setData('Title', t('Spam Queue')); $Where = array('Operation' => array('Spam')); $RecordCount = $this->LogModel->getCountWhere($Where); $this->setData('RecordCount', $RecordCount); if ($Offset >= $RecordCount) { $Offset = $RecordCount - $Limit; } $Log = $this->LogModel->getWhere($Where, 'LogID', 'Desc', $Offset, $Limit); $this->setData('Log', $Log); if ($this->deliveryType() == DELIVERY_TYPE_VIEW) { $this->View = 'Table'; } $this->addSideMenu('dashboard/log/spam'); $this->render(); }
/** * Discussions filter: Unresolved. * * @return void */ public function discussionsController_unresolved_create($sender, $args) { $sender->permission('Plugins.Resolved.Manage'); $page = val(0, $args, 0); // Determine offset from $Page list($page, $limit) = offsetLimit($page, C('Vanilla.Discussions.PerPage', 30)); // Validate $Page if (!is_numeric($page) || $page < 0) { $page = 0; } $discussionModel = new DiscussionModel(); $wheres = array('d.Resolved' => '0'); // Hack in our wheregroup. Gdn::sql()->beginWhereGroup()->whereNotIn('d.Type', array('page', 'Report', 'poll', 'SimplePage'))->orWhere('d.Type is null')->endWhereGroup(); $sender->DiscussionData = $discussionModel->Get($page, $limit, $wheres); $sender->setData('Discussions', $sender->DiscussionData); $countDiscussions = $discussionModel->GetCount($wheres); $sender->setData('CountDiscussions', $countDiscussions); $sender->Category = false; $sender->setJson('Loading', $page . ' to ' . $limit); // Build a pager $pagerFactory = new Gdn_PagerFactory(); $sender->EventArguments['PagerType'] = 'Pager'; $sender->fireEvent('BeforeBuildBookmarkedPager'); $sender->Pager = $pagerFactory->getPager($sender->EventArguments['PagerType'], $sender); $sender->Pager->ClientID = 'Pager'; $sender->Pager->configure($page, $limit, $countDiscussions, 'discussions/unresolved/%1$s'); if (!$sender->data('_PagerUrl')) { $sender->setData('_PagerUrl', 'discussions/unresolved/{Page}'); } $sender->setData('_Page', $page); $sender->setData('_Limit', $limit); $sender->fireEvent('AfterBuildBookmarkedPager'); // Deliver JSON data if necessary if ($sender->deliveryType() != DELIVERY_TYPE_ALL) { $sender->setJson('LessRow', $sender->Pager->toString('less')); $sender->setJson('MoreRow', $sender->Pager->toString('more')); $sender->View = 'discussions'; } // Add modules $sender->addModule('DiscussionFilterModule'); $sender->addModule('NewDiscussionModule'); $sender->addModule('CategoriesModule'); // Render default view $sender->setData('Title', T('Unresolved')); $sender->setData('Breadcrumbs', array(array('Name' => T('Unresolved'), 'Url' => '/discussions/unresolved'))); $sender->render('index'); }
/** * Display discussions started by the user. * * @since 2.0.0 * @access public * * @param int $Offset Number of discussions to skip. */ public function mine($Page = 'p1') { $this->permission('Garden.SignIn.Allow'); Gdn_Theme::section('DiscussionList'); // Set criteria & get discussions data list($Offset, $Limit) = offsetLimit($Page, c('Vanilla.Discussions.PerPage', 30)); $Session = Gdn::session(); $Wheres = array('d.InsertUserID' => $Session->UserID); $DiscussionModel = new DiscussionModel(); $this->DiscussionData = $DiscussionModel->get($Offset, $Limit, $Wheres); $this->setData('Discussions', $this->DiscussionData); $CountDiscussions = $this->setData('CountDiscussions', $DiscussionModel->getCount($Wheres)); $this->View = 'index'; if (c('Vanilla.Discussions.Layout') === 'table') { $this->View = 'table'; } // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->EventArguments['PagerType'] = 'MorePager'; $this->fireEvent('BeforeBuildMinePager'); $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this); $this->Pager->MoreCode = 'More Discussions'; $this->Pager->LessCode = 'Newer Discussions'; $this->Pager->ClientID = 'Pager'; $this->Pager->configure($Offset, $Limit, $CountDiscussions, 'discussions/mine/%1$s'); $this->setData('_PagerUrl', 'discussions/mine/{Page}'); $this->setData('_Page', $Page); $this->setData('_Limit', $Limit); $this->fireEvent('AfterBuildMinePager'); // 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 = 'discussions'; } // Add modules $this->addModule('DiscussionFilterModule'); $this->addModule('NewDiscussionModule'); $this->addModule('CategoriesModule'); $this->addModule('BookmarkedModule'); // Render view $this->setData('Title', t('My Discussions')); $this->setData('Breadcrumbs', array(array('Name' => t('My Discussions'), 'Url' => '/discussions/mine'))); $this->render(); }
/** * Manage the category hierarchy. * * @param string $parent The URL slug of a parent category if looking at a sub tree. */ public function categories($parent = '') { $this->permission(['Garden.Community.Manage', 'Garden.Settings.Manage'], false); $this->setHighlightRoute('vanilla/settings/categories'); // Make sure we are reading the categories from the database only. $collection = $this->CategoryModel->createCollection(Gdn::sql(), new Gdn_Dirtycache()); $allowSorting = true; $usePagination = false; $perPage = 30; $page = Gdn::request()->get('Page', Gdn::request()->get('page', null)); list($offset, $limit) = offsetLimit($page, $perPage); if (!empty($parent)) { $categoryRow = $collection->get((string) $parent); if (empty($categoryRow)) { throw notFoundException('Category'); } $this->setData('Category', $categoryRow); $parentID = $categoryRow['CategoryID']; $parentDisplayAs = val('DisplayAs', $categoryRow); } else { $parentID = -1; $parentDisplayAs = CategoryModel::getRootDisplayAs(); } if (in_array($parentDisplayAs, ['Flat'])) { $allowSorting = false; $usePagination = true; } if ($parentDisplayAs === 'Flat') { $categories = $this->CategoryModel->getTreeAsFlat($parentID, $offset, $limit); } else { $categories = $collection->getTree($parentID, ['maxdepth' => 10, 'collapsecategories' => true]); } $this->setData('ParentID', $parentID); $this->setData('Categories', $categories); $this->setData('_Limit', $perPage); $this->setData('_CurrentRecords', count($categories)); if ($parentID > 0) { $ancestors = $collection->getAncestors($parentID, true); $this->setData('Ancestors', $ancestors); } $this->setData('AllowSorting', $allowSorting); $this->setData('UsePagination', $usePagination); $this->addDefinition('AllowSorting', $allowSorting); $this->addJsFile('category-settings.js'); $this->addJsFile('manage-categories.js'); $this->addJsFile('jquery.nestable.js'); require_once $this->fetchViewLocation('category-settings-functions'); $this->addAsset('Content', $this->fetchView('symbols')); $this->render(); }
/** * Default activity stream. * * @since 2.0.0 * @access public * * @param int $Offset Number of activity items to skip. */ public function index($Filter = false, $Page = false) { switch (strtolower($Filter)) { case 'mods': $this->title(t('Recent Moderator Activity')); $this->permission('Garden.Moderation.Manage'); $NotifyUserID = ActivityModel::NOTIFY_MODS; break; case 'admins': $this->title(t('Recent Admin Activity')); $this->permission('Garden.Settings.Manage'); $NotifyUserID = ActivityModel::NOTIFY_ADMINS; break; case '': case 'feed': // rss feed $Filter = 'public'; $this->title(t('Recent Activity')); $this->permission('Garden.Activity.View'); $NotifyUserID = ActivityModel::NOTIFY_PUBLIC; break; default: throw notFoundException(); } // Which page to load list($Offset, $Limit) = offsetLimit($Page, c('Garden.Activities.PerPage', 30)); $Offset = is_numeric($Offset) ? $Offset : 0; if ($Offset < 0) { $Offset = 0; } // Page meta. $this->addJsFile('activity.js'); if ($this->Head) { $this->Head->addRss(url('/activity/feed.rss', true), $this->Head->title()); } // Comment submission $Session = Gdn::session(); $Comment = $this->Form->getFormValue('Comment'); $Activities = $this->ActivityModel->getWhere(array('NotifyUserID' => $NotifyUserID), '', '', $Limit, $Offset)->resultArray(); $this->ActivityModel->joinComments($Activities); $this->setData('Filter', strtolower($Filter)); $this->setData('Activities', $Activities); $this->addModule('ActivityFilterModule'); $this->View = 'all'; $this->render(); }
/** * Show all discussions in a particular category. * * @since 2.0.0 * @access public * * @param string $CategoryIdentifier Unique category slug or ID. * @param int $Offset Number of discussions to skip. */ public function index($CategoryIdentifier = '', $Page = '0') { // Figure out which category layout to choose (Defined on "Homepage" settings page). $Layout = c('Vanilla.Categories.Layout'); if ($CategoryIdentifier == '') { switch ($Layout) { case 'mixed': $this->View = 'discussions'; $this->Discussions(); break; case 'table': $this->table(); break; default: $this->View = 'all'; $this->All(); break; } return; } else { $Category = CategoryModel::categories($CategoryIdentifier); if (empty($Category)) { // Try lowercasing before outright failing $LowerCategoryIdentifier = strtolower($CategoryIdentifier); if ($LowerCategoryIdentifier != $CategoryIdentifier) { $Category = CategoryModel::categories($LowerCategoryIdentifier); if ($Category) { redirect("/categories/{$LowerCategoryIdentifier}", 301); } } throw notFoundException(); } $Category = (object) $Category; Gdn_Theme::section($Category->CssClass); // Load the breadcrumbs. $this->setData('Breadcrumbs', CategoryModel::GetAncestors(val('CategoryID', $Category))); $this->setData('Category', $Category, true); $this->title(htmlspecialchars(val('Name', $Category, ''))); $this->Description(val('Description', $Category), true); if ($Category->DisplayAs == 'Categories') { if (val('Depth', $Category) > c('Vanilla.Categories.NavDepth', 0)) { // Headings don't make sense if we've cascaded down one level. saveToConfig('Vanilla.Categories.DoHeadings', false, false); } trace($this->deliveryMethod(), 'delivery method'); trace($this->deliveryType(), 'delivery type'); trace($this->SyndicationMethod, 'syndication'); if ($this->SyndicationMethod != SYNDICATION_NONE) { // RSS can't show a category list so just tell it to expand all categories. saveToConfig('Vanilla.ExpandCategories', true, false); } else { // This category is an overview style category and displays as a category list. switch ($Layout) { case 'mixed': $this->View = 'discussions'; $this->Discussions($CategoryIdentifier); break; case 'table': $this->table($CategoryIdentifier); break; default: $this->View = 'all'; $this->All($CategoryIdentifier); break; } return; } } Gdn_Theme::section('DiscussionList'); // Figure out which discussions layout to choose (Defined on "Homepage" settings page). $Layout = c('Vanilla.Discussions.Layout'); switch ($Layout) { case 'table': if ($this->SyndicationMethod == SYNDICATION_NONE) { $this->View = 'table'; } break; default: // $this->View = 'index'; break; } // Load the subtree. $Categories = CategoryModel::GetSubtree($CategoryIdentifier, false); $this->setData('Categories', $Categories); // Setup head $this->Menu->highlightRoute('/discussions'); if ($this->Head) { $this->addJsFile('discussions.js'); $this->Head->AddRss($this->SelfUrl . '/feed.rss', $this->Head->title()); } // Set CategoryID $CategoryID = val('CategoryID', $Category); $this->setData('CategoryID', $CategoryID, true); // Add modules $this->addModule('NewDiscussionModule'); $this->addModule('DiscussionFilterModule'); $this->addModule('CategoriesModule'); $this->addModule('BookmarkedModule'); // Get a DiscussionModel $DiscussionModel = new DiscussionModel(); $CategoryIDs = array($CategoryID); if (c('Vanilla.ExpandCategories')) { $CategoryIDs = array_merge($CategoryIDs, array_column($this->data('Categories'), 'CategoryID')); } $Wheres = array('d.CategoryID' => $CategoryIDs); $this->setData('_ShowCategoryLink', count($CategoryIDs) > 1); // Check permission $this->permission('Vanilla.Discussions.View', true, 'Category', val('PermissionCategoryID', $Category)); // Set discussion meta data. $this->EventArguments['PerPage'] = c('Vanilla.Discussions.PerPage', 30); $this->fireEvent('BeforeGetDiscussions'); list($Offset, $Limit) = offsetLimit($Page, $this->EventArguments['PerPage']); if (!is_numeric($Offset) || $Offset < 0) { $Offset = 0; } $Page = PageNumber($Offset, $Limit); // Allow page manipulation $this->EventArguments['Page'] =& $Page; $this->EventArguments['Offset'] =& $Offset; $this->EventArguments['Limit'] =& $Limit; $this->fireEvent('AfterPageCalculation'); // We want to limit the number of pages on large databases because requesting a super-high page can kill the db. $MaxPages = c('Vanilla.Categories.MaxPages'); if ($MaxPages && $Page > $MaxPages) { throw notFoundException(); } $CountDiscussions = $DiscussionModel->getCount($Wheres); if ($MaxPages && $MaxPages * $Limit < $CountDiscussions) { $CountDiscussions = $MaxPages * $Limit; } $this->setData('CountDiscussions', $CountDiscussions); $this->setData('_Limit', $Limit); // We don't wan't child categories in announcements. $Wheres['d.CategoryID'] = $CategoryID; $AnnounceData = $Offset == 0 ? $DiscussionModel->GetAnnouncements($Wheres) : new Gdn_DataSet(); $this->setData('AnnounceData', $AnnounceData, true); $Wheres['d.CategoryID'] = $CategoryIDs; $this->DiscussionData = $this->setData('Discussions', $DiscussionModel->getWhere($Wheres, $Offset, $Limit)); // 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($Offset, $Limit, $CountDiscussions, array('CategoryUrl')); $this->Pager->Record = $Category; PagerModule::Current($this->Pager); $this->setData('_Page', $Page); $this->setData('_Limit', $Limit); $this->fireEvent('AfterBuildPager'); // Set the canonical Url. $this->canonicalUrl(CategoryUrl($Category, PageNumber($Offset, $Limit))); // Change the controller name so that it knows to grab the discussion views $this->ControllerName = 'DiscussionsController'; // Pick up the discussions class $this->CssClass = 'Discussions Category-' . GetValue('UrlCode', $Category); // 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 = 'discussions'; } // Render default view. $this->fireEvent('BeforeCategoriesRender'); $this->render(); } }
/** * Filter the list of addons. * * @param string $FilterToType AddonModel::$TypesPlural and 'plugins,applications'. * @param string $Sort Order addons by popularity or recency. * @param string $Page Which page to display. */ public function browse($FilterToType = '', $Sort = '', $Page = '') { // Create a virtual type called 'apps' as a stand-in for both plugins & applications. if ($FilterToType == 'apps') { $FilterToType = 'plugins,applications'; } // Implement user prefs $Session = Gdn::session(); if ($Session->isValid()) { if ($FilterToType != '') { $Session->setPreference('Addons.FilterType', $FilterToType); } //if ($VanillaVersion != '') { $Session->setPreference('Addons.FilterVanilla', '2'); //} if ($Sort != '') { $Session->setPreference('Addons.Sort', $Sort); } $FilterToType = $Session->getPreference('Addons.FilterType', 'all'); $VanillaVersion = $Session->getPreference('Addons.FilterVanilla', '2'); $Sort = $Session->getPreference('Addons.Sort', 'recent'); } $allowedFilters = AddonModel::$TypesPlural + ['plugins,applications' => true]; if (!array_key_exists($FilterToType, $allowedFilters)) { $FilterToType = 'all'; } if ($Sort != 'popular') { $Sort = 'recent'; } if (!in_array($VanillaVersion, array('1', '2'))) { $VanillaVersion = '2'; } $this->Version = $VanillaVersion; $this->Sort = $Sort; $this->FilterChecked = 'checked'; $this->addJsFile('jquery.gardenmorepager.js'); $this->addJsFile('browse.js'); list($Offset, $Limit) = offsetLimit($Page, c('Garden.Search.PerPage', 20)); $this->Filter = $FilterToType; if ($this->Filter == 'themes') { $Title = 'Browse Themes'; } elseif ($this->Filter == 'plugins,applications') { $Title = 'Browse Plugins & Applications'; } else { $Title = 'Browse Addons'; } $this->setData('Title', $Title); $Search = GetIncomingValue('Keywords', ''); $this->buildBrowseWheres($Search); $SortField = $Sort == 'recent' ? 'DateUpdated' : 'CountDownloads'; $ResultSet = $this->AddonModel->getWhere(false, $SortField, 'desc', $Limit, $Offset); $this->setData('Addons', $ResultSet); $this->buildBrowseWheres($Search); $NumResults = $this->AddonModel->getCount(false); $this->setData('TotalAddons', $NumResults); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $Pager = $PagerFactory->getPager('Pager', $this); $Pager->MoreCode = '›'; $Pager->LessCode = '‹'; $Pager->ClientID = 'Pager'; $Pager->configure($Offset, $Limit, $NumResults, 'addon/browse/' . $FilterToType . '/' . $Sort . '/%1$s/?Keywords=' . urlencode($Search)); $this->setData('_Pager', $Pager); if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->setJson('MoreRow', $Pager->toString('more')); } $this->addModule('AddonHelpModule'); $this->render(); }
/** * Manage user bans (add, edit, delete, list). * * @since 2.0.18 * @access public * @param string $Action Add, edit, delete, or none. * @param string $Search Term to filter ban list by. * @param int $Page Page number. * @param int $ID Ban ID we're editing or deleting. */ public function bans($Action = '', $Search = '', $Page = '', $ID = '') { $this->permission('Garden.Settings.Manage'); // Page setup $this->title(t('Banning Options')); list($Offset, $Limit) = offsetLimit($Page, 20); $BanModel = $this->getBanModel(); switch (strtolower($Action)) { case 'add': case 'edit': $this->Form->setModel($BanModel); if ($this->Form->authenticatedPostBack()) { if ($ID) { $this->Form->setFormValue('BanID', $ID); } // Trim the ban value to avoid obvious mismatches. $banValue = trim($this->Form->getFormValue('BanValue')); $this->Form->setFormValue('BanValue', $banValue); // We won't let you HAL 9000 the entire crew. $crazyBans = ['*', '*@*', '*.*', '*.*.*', '*.*.*.*']; if (in_array($banValue, $crazyBans)) { $this->Form->addError("I'm sorry Dave, I'm afraid I can't do that."); } try { // Save the ban. $NewID = $this->Form->save(); } catch (Exception $Ex) { $this->Form->addError($Ex); } } else { if ($ID) { $this->Form->setData($BanModel->getID($ID)); } } $this->setData('_BanTypes', array('IPAddress' => t('IP Address'), 'Email' => t('Email'), 'Name' => t('Name'))); $this->View = 'Ban'; break; case 'delete': if ($this->Form->authenticatedPostBack()) { $BanModel->delete(array('BanID' => $ID)); $this->View = 'BanDelete'; } break; default: $Bans = $BanModel->getWhere(array(), 'BanType, BanValue', 'asc', $Limit, $Offset)->resultArray(); $this->setData('Bans', $Bans); break; } Gdn_Theme::section('Moderation'); $this->render(); }
/** * Show notifications for current user. * * @since 2.0.0 * @access public * @param int $Page Number to skip (paging). */ public function notifications($Page = false) { $this->permission('Garden.SignIn.Allow'); $this->editMode(false); list($Offset, $Limit) = offsetLimit($Page, 30); $this->getUserInfo(); $this->_setBreadcrumbs(t('Notifications'), '/profile/notifications'); $this->SetTabView('Notifications'); $Session = Gdn::session(); $this->ActivityModel = new ActivityModel(); // Drop notification count back to zero. $this->ActivityModel->MarkRead($Session->UserID); // Get notifications data. $Activities = $this->ActivityModel->getNotifications($Session->UserID, $Offset, $Limit)->resultArray(); $this->ActivityModel->joinComments($Activities); $this->setData('Activities', $Activities); unset($Activities); //$TotalRecords = $this->ActivityModel->GetCountNotifications($Session->UserID); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->Pager = $PagerFactory->GetPager('MorePager', $this); $this->Pager->MoreCode = 'More'; $this->Pager->LessCode = 'Newer Notifications'; $this->Pager->ClientID = 'Pager'; $this->Pager->configure($Offset, $Limit, false, 'profile/notifications/%1$s/'); // 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')); if ($Offset > 0) { $this->View = 'activities'; $this->ControllerName = 'Activity'; } } $this->render(); }
/** * List all tags and allow searching * * @param SettingsController $Sender */ public function settingsController_tagging_create($Sender, $Search = null, $Type = null, $Page = null) { $Sender->title('Tagging'); $Sender->addSideMenu('settings/tagging'); $Sender->addJSFile('tagadmin.js', 'plugins/Tagging'); $SQL = Gdn::sql(); // Get all tag types $TagModel = TagModel::instance(); $TagTypes = $TagModel->getTagTypes(); $Sender->Form->Method = 'get'; $Sender->Form->InputPrefix = ''; list($Offset, $Limit) = offsetLimit($Page, 100); $Sender->setData('_Limit', $Limit); if ($Search) { $SQL->like('FullName', $Search, 'right'); } // This type doesn't actually exist, but it will represent the // blank types in the column. if (strtolower($Type) == 'tags') { $Type = ''; } if (!$Search) { if ($Type !== null) { if ($Type === 'null') { $Type = null; } $SQL->where('Type', $Type); } elseif ($Type == '') { $SQL->where('Type', ''); } } else { $Type = 'Search Results'; // This is made up, and exists so search results can be placed in // their own tab. $TagTypes[$Type] = array('key' => $Type); } $TagTypes = array_change_key_case($TagTypes, CASE_LOWER); // Store type for view $TagType = !empty($Type) ? $Type : 'Tags'; $Sender->setData('_TagType', $TagType); // Store tag types $Sender->setData('_TagTypes', $TagTypes); // Determine if new tags can be added for the current type. $CanAddTags = !empty($TagTypes[$Type]['addtag']) && $TagTypes[$Type]['addtag'] ? 1 : 0; $CanAddTags &= CheckPermission('Plugins.Tagging.Add'); $Sender->setData('_CanAddTags', $CanAddTags); $Data = $SQL->select('t.*')->from('Tag t')->orderBy('t.FullName', 'asc')->orderBy('t.CountDiscussions', 'desc')->limit($Limit, $Offset)->get()->resultArray(); $Sender->setData('Tags', $Data); if ($Search) { $SQL->like('Name', $Search, 'right'); } // Make sure search uses its own search type, so results appear // in their own tab. $Sender->Form->Action = url('/settings/tagging/?type=' . $TagType); // Search results pagination will mess up a bit, so don't provide a type // in the count. $RecordCountWhere = array('Type' => $Type); if ($Type == '') { $RecordCountWhere = array('Type' => ''); } if ($Search) { $RecordCountWhere = array(); } $Sender->setData('RecordCount', $SQL->getCount('Tag', $RecordCountWhere)); $Sender->render('tagging', '', 'plugins/Tagging'); }
/** * Show all conversations for the currently authenticated user. * * @since 2.0.0 * @access public * * @param string $Page */ public function all($Page = '') { $Session = Gdn::session(); $this->title(t('Inbox')); Gdn_Theme::section('ConversationList'); list($Offset, $Limit) = offsetLimit($Page, c('Conversations.Conversations.PerPage', 50)); // Calculate offset $this->Offset = $Offset; $UserID = $this->Request->get('userid', Gdn::session()->UserID); if ($UserID != Gdn::session()->UserID) { if (!c('Conversations.Moderation.Allow', false)) { throw permissionException(); } $this->permission('Conversations.Moderation.Manage'); } $conversations = $this->ConversationModel->get2($UserID, $Offset, $Limit)->resultArray(); $this->EventArguments['Conversations'] =& $conversations; $this->fireEvent('beforeMessagesAll'); $this->setData('Conversations', $conversations); // Get Conversations Count //$CountConversations = $this->ConversationModel->getCount($UserID); //$this->setData('CountConversations', $CountConversations); // Build the pager if (!$this->data('_PagerUrl')) { $this->setData('_PagerUrl', 'messages/all/{Page}'); } $this->setData('_Page', $Page); $this->setData('_Limit', $Limit); $this->setData('_CurrentRecords', count($conversations)); // Deliver json data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL && $this->_DeliveryMethod == DELIVERY_METHOD_XHTML) { $this->setJson('LessRow', $this->Pager->toString('less')); $this->setJson('MoreRow', $this->Pager->toString('more')); $this->View = 'conversations'; } // Build and display page. $this->render(); }
/** * Creates virtual 'Discussions' method in ProfileController. * * @since 2.0.0 * @package Vanilla * * @param ProfileController $Sender ProfileController. */ public function profileController_discussions_create($Sender, $UserReference = '', $Username = '', $Page = '', $UserID = '') { $Sender->editMode(false); // Tell the ProfileController what tab to load $Sender->getUserInfo($UserReference, $Username, $UserID); $Sender->_setBreadcrumbs(t('Discussions'), userUrl($Sender->User, '', 'discussions')); $Sender->setTabView('Discussions', 'Profile', 'Discussions', 'Vanilla'); $Sender->CountCommentsPerPage = c('Vanilla.Comments.PerPage', 30); list($Offset, $Limit) = offsetLimit($Page, c('Vanilla.Discussions.PerPage', 30)); $DiscussionModel = new DiscussionModel(); $Discussions = $DiscussionModel->getByUser($Sender->User->UserID, $Limit, $Offset, false, Gdn::session()->UserID); $CountDiscussions = $Offset + $DiscussionModel->LastDiscussionCount + 1; $Sender->DiscussionData = $Sender->setData('Discussions', $Discussions); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $Sender->Pager = $PagerFactory->getPager('MorePager', $Sender); $Sender->Pager->MoreCode = 'More Discussions'; $Sender->Pager->LessCode = 'Newer Discussions'; $Sender->Pager->ClientID = 'Pager'; $Sender->Pager->configure($Offset, $Limit, $CountDiscussions, userUrl($Sender->User, '', 'discussions') . '?page={Page}'); // Deliver JSON data if necessary if ($Sender->deliveryType() != DELIVERY_TYPE_ALL && $Offset > 0) { $Sender->setJson('LessRow', $Sender->Pager->toString('less')); $Sender->setJson('MoreRow', $Sender->Pager->toString('more')); $Sender->View = 'discussions'; } // Set the HandlerType back to normal on the profilecontroller so that it fetches it's own views $Sender->HandlerType = HANDLER_TYPE_NORMAL; // Do not show discussion options $Sender->ShowOptions = false; if ($Sender->Head) { // These pages offer only duplicate content to search engines and are a bit slow. $Sender->Head->addTag('meta', array('name' => 'robots', 'content' => 'noindex,noarchive')); } // Render the ProfileController $Sender->render(); }
/** * Show all discussions in a particular category. * * @since 2.0.0 * @access public * * @param string $CategoryIdentifier Unique category slug or ID. * @param int $Offset Number of discussions to skip. */ public function index($CategoryIdentifier = '', $Page = '0') { // Figure out which category layout to choose (Defined on "Homepage" settings page). $Layout = c('Vanilla.Categories.Layout'); if ($CategoryIdentifier == '') { switch ($Layout) { case 'mixed': $this->View = 'discussions'; $this->discussions(); break; case 'table': $this->table(); break; default: $this->View = 'all'; $this->all('', CategoryModel::getRootDisplayAs()); break; } return; } else { $Category = CategoryModel::categories($CategoryIdentifier); if (empty($Category)) { throw notFoundException(); } $Category = (object) $Category; Gdn_Theme::section($Category->CssClass); // Load the breadcrumbs. $this->setData('Breadcrumbs', CategoryModel::getAncestors(val('CategoryID', $Category))); $this->setData('Category', $Category, true); $this->title(htmlspecialchars(val('Name', $Category, ''))); $this->description(val('Description', $Category), true); switch ($Category->DisplayAs) { case 'Flat': case 'Heading': case 'Categories': $stopHeadings = val('Depth', $Category) > CategoryModel::instance()->getNavDepth(); CategoryModel::instance()->setStopHeadingsCalculation($stopHeadings); if ($this->SyndicationMethod != SYNDICATION_NONE) { // RSS can't show a category list so just tell it to expand all categories. saveToConfig('Vanilla.ExpandCategories', true, false); } else { // This category is an overview style category and displays as a category list. switch ($Layout) { case 'mixed': $this->View = 'discussions'; $this->discussions($CategoryIdentifier); break; case 'table': $this->table($CategoryIdentifier, $Category->DisplayAs); break; default: $this->View = 'all'; $this->All($CategoryIdentifier, $Category->DisplayAs); break; } return; } break; } Gdn_Theme::section('DiscussionList'); // Figure out which discussions layout to choose (Defined on "Homepage" settings page). $Layout = c('Vanilla.Discussions.Layout'); switch ($Layout) { case 'table': if ($this->SyndicationMethod == SYNDICATION_NONE) { $this->View = 'table'; } break; default: // $this->View = 'index'; break; } $this->setData('CategoryTree', $this->getCategoryTree($CategoryIdentifier, val('DisplayAs', $Category))); // Add a backwards-compatibility shim for the old categories. $this->categoriesCompatibilityCallback = function () use($CategoryIdentifier) { $categories = CategoryModel::getSubtree($CategoryIdentifier, false); return $categories; }; // Setup head $this->Menu->highlightRoute('/discussions'); if ($this->Head) { $this->addJsFile('discussions.js'); $this->Head->addRss(categoryUrl($Category) . '/feed.rss', $this->Head->title()); } // Set CategoryID $CategoryID = val('CategoryID', $Category); $this->setData('CategoryID', $CategoryID, true); // Add modules $this->addModule('NewDiscussionModule'); $this->addModule('DiscussionFilterModule'); $this->addModule('CategoriesModule'); $this->addModule('BookmarkedModule'); // Get a DiscussionModel $DiscussionModel = new DiscussionModel(); $DiscussionModel->setSort(Gdn::request()->get()); $DiscussionModel->setFilters(Gdn::request()->get()); $this->setData('Sort', $DiscussionModel->getSort()); $this->setData('Filters', $DiscussionModel->getFilters()); $CategoryIDs = array($CategoryID); if (c('Vanilla.ExpandCategories')) { $CategoryIDs = array_merge($CategoryIDs, array_column($this->data('Categories'), 'CategoryID')); } $Wheres = array('d.CategoryID' => $CategoryIDs); $this->setData('_ShowCategoryLink', count($CategoryIDs) > 1); // Check permission $this->permission('Vanilla.Discussions.View', true, 'Category', val('PermissionCategoryID', $Category)); // Set discussion meta data. $this->EventArguments['PerPage'] = c('Vanilla.Discussions.PerPage', 30); $this->fireEvent('BeforeGetDiscussions'); list($Offset, $Limit) = offsetLimit($Page, $this->EventArguments['PerPage']); if (!is_numeric($Offset) || $Offset < 0) { $Offset = 0; } $Page = PageNumber($Offset, $Limit); // Allow page manipulation $this->EventArguments['Page'] =& $Page; $this->EventArguments['Offset'] =& $Offset; $this->EventArguments['Limit'] =& $Limit; $this->fireEvent('AfterPageCalculation'); // We want to limit the number of pages on large databases because requesting a super-high page can kill the db. $MaxPages = c('Vanilla.Categories.MaxPages'); if ($MaxPages && $Page > $MaxPages) { throw notFoundException(); } $CountDiscussions = $DiscussionModel->getCount($Wheres); if ($MaxPages && $MaxPages * $Limit < $CountDiscussions) { $CountDiscussions = $MaxPages * $Limit; } $this->setData('CountDiscussions', $CountDiscussions); $this->setData('_Limit', $Limit); // We don't wan't child categories in announcements. $Wheres['d.CategoryID'] = $CategoryID; $AnnounceData = $DiscussionModel->getAnnouncements($Wheres, $Offset, $Limit); $this->AnnounceData = $this->setData('Announcements', $AnnounceData); $Wheres['d.CategoryID'] = $CategoryIDs; // RSS should include announcements. if ($this->SyndicationMethod !== SYNDICATION_NONE) { $Wheres['Announce'] = 'all'; } $this->DiscussionData = $this->setData('Discussions', $DiscussionModel->getWhereRecent($Wheres, $Limit, $Offset)); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $url = CategoryUrl($CategoryIdentifier); $this->EventArguments['PagerType'] = 'Pager'; $this->fireEvent('BeforeBuildPager'); if (!$this->data('_PagerUrl')) { $this->setData('_PagerUrl', $url . '/{Page}'); } $queryString = DiscussionModel::getSortFilterQueryString($DiscussionModel->getSort(), $DiscussionModel->getFilters()); $this->setData('_PagerUrl', $this->data('_PagerUrl') . $queryString); $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this); $this->Pager->ClientID = 'Pager'; $this->Pager->configure($Offset, $Limit, $CountDiscussions, $this->data('_PagerUrl')); $this->Pager->Record = $Category; PagerModule::current($this->Pager); $this->setData('_Page', $Page); $this->setData('_Limit', $Limit); $this->fireEvent('AfterBuildPager'); // Set the canonical Url. $this->canonicalUrl(categoryUrl($Category, pageNumber($Offset, $Limit))); // Change the controller name so that it knows to grab the discussion views $this->ControllerName = 'DiscussionsController'; // Pick up the discussions class $this->CssClass = 'Discussions Category-' . val('UrlCode', $Category); // 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 = 'discussions'; } // Render default view. $this->fireEvent('BeforeCategoriesRender'); $this->render(); } }