/**
  * Use 404 handler to look for a SimplePage.
  */
 public function gdn_dispatcher_notFound_handler($dispatcher, $args)
 {
     $requestUri = Gdn::Request()->Path();
     $discussionModel = new DiscussionModel();
     $result = $discussionModel->GetWhere(array('Type' => 'SimplePage', 'ForeignID' => $requestUri))->FirstRow(DATASET_TYPE_ARRAY);
     // Page exists with requested slug, so dispatch; no redirect.
     if ($discussionID = val('DiscussionID', $result)) {
         SaveToConfig('SimplePage.Found', true, false);
         Gdn::Dispatcher()->Dispatch('/discussion/' . $discussionID);
         exit;
     }
 }
 /**
  * Default all discussions view: chronological by most recent comment.
  *
  * @since 2.0.0
  * @access public
  *
  * @param int $Page Multiplied by PerPage option to determine offset.
  */
 public function Index($Page = FALSE)
 {
     // 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;
     }
     Gdn_Theme::Section('DiscussionList');
     // Determine offset from $Page
     list($Offset, $Limit) = OffsetLimit($Page, C('Vanilla.Discussions.PerPage', 30));
     $Page = PageNumber($Offset, $Limit);
     // Allow page manipulation
     $this->EventArguments['Page'] =& $Page;
     $this->EventArguments['Offset'] =& $Offset;
     $this->EventArguments['Limit'] =& $Limit;
     $this->FireEvent('AfterPageCalculation');
     // Set canonical URL
     $this->CanonicalUrl(Url(ConcatSep('/', 'discussions', PageNumber($Offset, $Limit, TRUE, FALSE)), TRUE));
     // We want to limit the number of pages on large databases because requesting a super-high page can kill the db.
     $MaxPages = C('Vanilla.Discussions.MaxPages');
     if ($MaxPages && $Page > $MaxPages) {
         throw NotFoundException();
     }
     // Setup head.
     if (!$this->Data('Title')) {
         $Title = C('Garden.HomepageTitle');
         $DefaultControllerRoute = val('Destination', Gdn::Router()->GetRoute('DefaultController'));
         if ($Title && $DefaultControllerRoute == 'discussions') {
             $this->Title($Title, '');
         } else {
             $this->Title(T('Recent Discussions'));
         }
     }
     if (!$this->Description()) {
         $this->Description(C('Garden.Description', NULL));
     }
     if ($this->Head) {
         $this->Head->AddRss(Url('/discussions/feed.rss', TRUE), $this->Head->Title());
     }
     // Add modules
     $this->AddModule('DiscussionFilterModule');
     $this->AddModule('NewDiscussionModule');
     $this->AddModule('CategoriesModule');
     $this->AddModule('BookmarkedModule');
     $this->SetData('Breadcrumbs', array(array('Name' => T('Recent Discussions'), 'Url' => '/discussions')));
     // Set criteria & get discussions data
     $this->SetData('Category', FALSE, TRUE);
     $DiscussionModel = new DiscussionModel();
     $DiscussionModel->Watching = TRUE;
     // Get Discussion Count
     $CountDiscussions = $DiscussionModel->GetCount();
     if ($MaxPages) {
         $CountDiscussions = min($MaxPages * $Limit, $CountDiscussions);
     }
     $this->SetData('CountDiscussions', $CountDiscussions);
     // Get Announcements
     $this->AnnounceData = $Offset == 0 ? $DiscussionModel->GetAnnouncements() : FALSE;
     $this->SetData('Announcements', $this->AnnounceData !== FALSE ? $this->AnnounceData : array(), TRUE);
     // Get Discussions
     $this->DiscussionData = $DiscussionModel->GetWhere(FALSE, $Offset, $Limit);
     $this->SetData('Discussions', $this->DiscussionData, TRUE);
     $this->SetJson('Loading', $Offset . ' to ' . $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, 'discussions/%1$s');
     if (!$this->Data('_PagerUrl')) {
         $this->SetData('_PagerUrl', 'discussions/{Page}');
     }
     $this->SetData('_Page', $Page);
     $this->SetData('_Limit', $Limit);
     $this->FireEvent('AfterBuildPager');
     // 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';
     }
     $this->Render();
 }
 /**
  * Default all discussions view: chronological by most recent comment.
  * 
  * @since 2.0.0
  * @access public
  * 
  * @param int $Page Multiplied by PerPage option to determine offset.
  */
 public function Index($Page = FALSE)
 {
     // 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;
     }
     Gdn_Theme::Section('DiscussionList');
     // Determine offset from $Page
     list($Offset, $Limit) = OffsetLimit($Page, C('Vanilla.Discussions.PerPage', 30));
     $Page = PageNumber($Offset, $Limit);
     $this->CanonicalUrl(Url(ConcatSep('/', 'discussions', PageNumber($Offset, $Limit, TRUE, FALSE)), TRUE));
     // Setup head.
     if (!$this->Data('Title')) {
         $Title = C('Garden.HomepageTitle');
         if ($Title) {
             $this->Title($Title, '');
         } else {
             $this->Title(T('Recent Discussions'));
         }
     }
     if (!$this->Description()) {
         $this->Description(C('Garden.Description', NULL));
     }
     if ($this->Head) {
         $this->Head->AddRss(Url('/discussions/feed.rss', TRUE), $this->Head->Title());
     }
     // Add modules
     $this->AddModule('DiscussionFilterModule');
     $this->AddModule('NewDiscussionModule');
     $this->AddModule('CategoriesModule');
     $this->AddModule('BookmarkedModule');
     $this->SetData('Breadcrumbs', array(array('Name' => T('Recent Discussions'), 'Url' => '/discussions')));
     // Set criteria & get discussions data
     $this->SetData('Category', FALSE, TRUE);
     $DiscussionModel = new DiscussionModel();
     $DiscussionModel->Watching = TRUE;
     // Get Discussion Count
     $CountDiscussions = $DiscussionModel->GetCount();
     $this->SetData('CountDiscussions', $CountDiscussions);
     // Get Announcements
     $this->AnnounceData = $Offset == 0 ? $DiscussionModel->GetAnnouncements() : FALSE;
     $this->SetData('Announcements', $this->AnnounceData !== FALSE ? $this->AnnounceData : array(), TRUE);
     // Get Discussions
     $this->DiscussionData = $DiscussionModel->GetWhere(FALSE, $Offset, $Limit);
     $this->SetData('Discussions', $this->DiscussionData, TRUE);
     $this->SetJson('Loading', $Offset . ' to ' . $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, 'discussions/%1$s');
     if (!$this->Data('_PagerUrl')) {
         $this->SetData('_PagerUrl', 'discussions/{Page}');
     }
     $this->SetData('_Page', $Page);
     $this->SetData('_Limit', $Limit);
     $this->FireEvent('AfterBuildPager');
     // 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';
     }
     // Set a definition of the user's current timezone from the db. jQuery
     // will pick this up, compare to the browser, and update the user's
     // timezone if necessary.
     $CurrentUser = Gdn::Session()->User;
     if (is_object($CurrentUser)) {
         $ClientHour = $CurrentUser->HourOffset + date('G', time());
         $this->AddDefinition('SetClientHour', $ClientHour);
     }
     $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')
 {
     if ($CategoryIdentifier == '') {
         // Figure out which category layout to choose (Defined on "Homepage" settings page).
         $Layout = C('Vanilla.Categories.Layout');
         switch ($Layout) {
             case 'mixed':
                 $this->View = 'discussions';
                 $this->Discussions();
                 break;
             case 'table':
                 $this->Table();
                 break;
             default:
                 $this->View = 'all';
                 $this->All();
                 break;
         }
         return;
     } else {
         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;
         }
         $Category = CategoryModel::Categories($CategoryIdentifier);
         if (empty($Category)) {
             if ($CategoryIdentifier) {
                 throw NotFoundException();
             }
         }
         $Category = (object) $Category;
         Gdn_Theme::Section($Category->CssClass);
         // Load the breadcrumbs.
         $this->SetData('Breadcrumbs', CategoryModel::GetAncestors(GetValue('CategoryID', $Category)));
         $this->SetData('Category', $Category, TRUE);
         // Load the subtree.
         if (C('Vanilla.ExpandCategories')) {
             $Categories = CategoryModel::GetSubtree($CategoryIdentifier);
         } else {
             $Categories = array($Category);
         }
         $this->SetData('Categories', $Categories);
         // Setup head
         $this->AddCssFile('vanilla.css');
         $this->Menu->HighlightRoute('/discussions');
         if ($this->Head) {
             $this->AddJsFile('discussions.js');
             $this->AddJsFile('bookmark.js');
             $this->AddJsFile('options.js');
             $this->Head->AddRss($this->SelfUrl . '/feed.rss', $this->Head->Title());
         }
         $this->Title(GetValue('Name', $Category, ''));
         $this->Description(GetValue('Description', $Category), TRUE);
         // Set CategoryID
         $CategoryID = GetValue('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 = ConsolidateArrayValuesByKey($this->Data('Categories'), 'CategoryID');
         $Wheres = array('d.CategoryID' => $CategoryIDs);
         $this->SetData('_ShowCategoryLink', count($CategoryIDs) > 1);
         // Check permission
         $this->Permission('Vanilla.Discussions.View', TRUE, 'Category', GetValue('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;
         }
         $CountDiscussions = $DiscussionModel->GetCount($Wheres);
         $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->Pager = $PagerFactory->GetPager('Pager', $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);
         // 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';
         // 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();
     }
 }
 protected function PollFeed($FeedURL, $LastImportDate)
 {
     $Pr = new ProxyRequest();
     $FeedRSS = $Pr->Request(array('URL' => $FeedURL));
     if (!$FeedRSS) {
         return FALSE;
     }
     $RSSData = simplexml_load_string($FeedRSS);
     if (!$RSSData) {
         return FALSE;
     }
     $Channel = GetValue('channel', $RSSData, FALSE);
     if (!$Channel) {
         return FALSE;
     }
     if (!array_key_exists('item', $Channel)) {
         return FALSE;
     }
     $Feed = $this->GetFeed($FeedURL, FALSE);
     $DiscussionModel = new DiscussionModel();
     $DiscussionModel->SpamCheck = FALSE;
     $LastPublishDate = GetValue('LastPublishDate', $Feed, date('c'));
     $LastPublishTime = strtotime($LastPublishDate);
     $FeedLastPublishTime = 0;
     foreach (GetValue('item', $Channel) as $Item) {
         $FeedItemGUID = trim((string) GetValue('guid', $Item));
         if (empty($FeedItemGUID)) {
             Trace('guid is not set in each item of the RSS.  Will attempt to use link as unique identifier.');
             $FeedItemGUID = GetValue('link', $Item);
         }
         $FeedItemID = substr(md5($FeedItemGUID), 0, 30);
         $ItemPubDate = (string) GetValue('pubDate', $Item, NULL);
         if (is_null($ItemPubDate)) {
             $ItemPubTime = time();
         } else {
             $ItemPubTime = strtotime($ItemPubDate);
         }
         if ($ItemPubTime > $FeedLastPublishTime) {
             $FeedLastPublishTime = $ItemPubTime;
         }
         if ($ItemPubTime < $LastPublishTime && !$Feed['Historical']) {
             continue;
         }
         $ExistingDiscussion = $DiscussionModel->GetWhere(array('ForeignID' => $FeedItemID));
         if ($ExistingDiscussion && $ExistingDiscussion->NumRows()) {
             continue;
         }
         $this->EventArguments['Publish'] = TRUE;
         $this->EventArguments['FeedURL'] = $FeedURL;
         $this->EventArguments['Feed'] =& $Feed;
         $this->EventArguments['Item'] =& $Item;
         $this->FireEvent('FeedItem');
         if (!$this->EventArguments['Publish']) {
             continue;
         }
         $StoryTitle = array_shift($Trash = explode("\n", (string) GetValue('title', $Item)));
         $StoryBody = (string) GetValue('description', $Item);
         $StoryPublished = date("Y-m-d H:i:s", $ItemPubTime);
         $ParsedStoryBody = $StoryBody;
         $ParsedStoryBody = '<div class="AutoFeedDiscussion">' . $ParsedStoryBody . '</div> <br /><div class="AutoFeedSource">Source: ' . $FeedItemGUID . '</div>';
         $DiscussionData = array('Name' => $StoryTitle, 'Format' => 'Html', 'CategoryID' => $Feed['Category'], 'ForeignID' => substr($FeedItemID, 0, 30), 'Body' => $ParsedStoryBody);
         // Post as Minion (if one exists) or the system user
         if (Gdn::PluginManager()->CheckPlugin('Minion')) {
             $Minion = Gdn::PluginManager()->GetPluginInstance('MinionPlugin');
             $InsertUserID = $Minion->GetMinionUserID();
         } else {
             $InsertUserID = Gdn::UserModel()->GetSystemUserID();
         }
         $DiscussionData[$DiscussionModel->DateInserted] = $StoryPublished;
         $DiscussionData[$DiscussionModel->InsertUserID] = $InsertUserID;
         $DiscussionData[$DiscussionModel->DateUpdated] = $StoryPublished;
         $DiscussionData[$DiscussionModel->UpdateUserID] = $InsertUserID;
         $this->EventArguments['FeedDiscussion'] =& $DiscussionData;
         $this->FireEvent('Publish');
         if (!$this->EventArguments['Publish']) {
             continue;
         }
         $InsertID = $DiscussionModel->Save($DiscussionData);
         $this->EventArguments['DiscussionID'] = $InsertID;
         $this->EventArguments['Vaidation'] = $DiscussionModel->Validation;
         $this->FireEvent('Published');
         // Reset discussion validation
         $DiscussionModel->Validation->Results(TRUE);
     }
     $FeedKey = self::EncodeFeedKey($FeedURL);
     $this->UpdateFeed($FeedKey, array('LastImport' => date('Y-m-d H:i:s'), 'LastPublishDate' => date('c', $FeedLastPublishTime)));
 }
 /**
  * Sync a file to its discussion.
  *
  * @param $Code string
  * @parm $Name string
  * @param $Body string
  */
 public function SyncDocDiscussion($Code, $Name, $Body, $CategoryID)
 {
     $DiscussionModel = new DiscussionModel();
     $Document = $DiscussionModel->GetWhere(array('DocumentCode' => $Code))->FirstRow();
     if (!$Document) {
         // Create discussion
         $DiscussionModel->Save(array('Name' => $Name, 'Body' => $Body, 'CategoryID' => $CategoryID, 'Format' => 'Markdown', 'Type' => 'Doc', 'InsertUserID' => Gdn::UserModel()->GetSystemUserID(), 'DocumentCode' => $Code));
     } else {
         // Blindly update the discussion
         $DiscussionModel->Update(array('Name' => $Name, 'Body' => $Body, 'CategoryID' => $CategoryID), array('DiscussionID' => GetValue('DiscussionID', $Document)));
     }
 }
   public function Commit() {
      
      if (is_null($this->Type))
         throw new Exception(T("Adding a Regarding event requires a type."));

      if (is_null($this->ForeignType))
         throw new Exception(T("Adding a Regarding event requires a foreign association type."));

      if (is_null($this->ForeignID))
         throw new Exception(T("Adding a Regarding event requires a foreign association id."));

      if (is_null($this->Comment))
         throw new Exception(T("Adding a Regarding event requires a comment."));

      if (is_null($this->UserID))
         $this->UserID = Gdn::Session()->UserID;

      $RegardingModel = new RegardingModel();
      
      $CollapseMode = C('Garden.Regarding.AutoCollapse', TRUE);
      $Collapse = FALSE;
      if ($CollapseMode) {
         // Check for an existing report of this type
         $ExistingRegardingEntity = $RegardingModel->GetRelated($this->Type, $this->ForeignType, $this->ForeignID);
         if ($ExistingRegardingEntity !== FALSE)
            $Collapse = TRUE;
      }
      
      if (!$Collapse) {
         // Create a new Regarding entry
         $RegardingID = $RegardingModel->Save(array(
            'Type'            => $this->Type,
            'ForeignType'     => $this->ForeignType,
            'ForeignID'       => $this->ForeignID,
            'InsertUserID'    => $this->UserID,
            'DateInserted'    => date('Y-m-d H:i:s'),

            'ParentType'      => $this->ParentType,
            'ParentID'        => $this->ParentID,
            'ForeignURL'      => $this->ForeignURL,
            'Comment'         => $this->Comment,
            'OriginalContent' => $this->OriginalContent
         ));
      }
      
      // Handle collaborations
      
      // Don't error on foreach
      if (!is_array($this->CollaborativeActions))
         $this->CollaborativeActions = array();
      
      foreach ($this->CollaborativeActions as $Action) {
         $ActionType = GetValue('Type', $Action);
         switch ($ActionType) {
            case 'discussion':
               $DiscussionModel = new DiscussionModel();
               
               if (!$Collapse) {
                  $CategoryID = GetValue('Parameters', $Action);
               
                  // Make a new discussion
                  $DiscussionID = $DiscussionModel->Save(array(
                     'Name'         => $this->CollaborativeTitle,
                     'CategoryID'   => $CategoryID,
                     'Body'         => $this->OriginalContent,
                     'InsertUserID' => GetValue('InsertUserID', $this->SourceElement),
                     'Announce'     => 0,
                     'Close'        => 0,
                     'RegardingID'  => $RegardingID
                  ));
               } else {
                  // Add a comment to the existing discussion
                  
                  // First, find out which discussion it was, based on RegardingID
                  $Discussion = $DiscussionModel->GetWhere(array('RegardingID' => GetValue('RegardingID', $ExistingRegardingEntity, FALSE)))->FirstRow(DATASET_TYPE_ARRAY);
                  if ($Discussion !== FALSE) {
                     $CommentModel = new CommentModel();
                     $CommentID = $CommentModel->Save(array(
                        'DiscussionID' => GetValue('DiscussionID', $Discussion),
                        'Body'         => $this->Comment,
                        'InsertUserID' => $this->UserID
                     ));
                  }
               }
               
               break;

            case 'conversation':
                  
               $ConversationModel = new ConversationModel();
               $ConversationMessageModel = new ConversationMessageModel();
               
               $Users = GetValue('Parameters', $Action);
               $UserList = explode(',', $Users);
               if (!sizeof($UserList))
                  throw new Exception(sprintf(T("The userlist provided for collaboration on '%s:%s' is invalid.", $this->Type, $this->ForeignType)));
               
               $ConversationID = $ConversationModel->Save(array(
                  'To'              => 'Admins',
                  'Body'            => $this->CollaborativeTitle,
                  'RecipientUserID' => $UserList,
                  'RegardingID'     => $RegardingID
               ), $ConversationMessageModel);
               
               break;
         }
      }

      return TRUE;
   }
 /**
  * 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(GetValue('CategoryID', $Category)));
         $this->SetData('Category', $Category, TRUE);
         $this->Title(htmlspecialchars(GetValue('Name', $Category, '')));
         $this->Description(GetValue('Description', $Category), TRUE);
         if ($Category->DisplayAs == 'Categories') {
             if (GetValue('Depth', $Category) > 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();
                         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.
         if (C('Vanilla.ExpandCategories')) {
             $Categories = CategoryModel::GetSubtree($CategoryIdentifier);
         } else {
             $Categories = array($Category);
         }
         $this->SetData('Categories', $Categories);
         // Setup head
         $this->AddCssFile('vanilla.css');
         $this->Menu->HighlightRoute('/discussions');
         if ($this->Head) {
             $this->AddJsFile('discussions.js');
             $this->Head->AddRss($this->SelfUrl . '/feed.rss', $this->Head->Title());
         }
         // Set CategoryID
         $CategoryID = GetValue('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 = ConsolidateArrayValuesByKey($this->Data('Categories'), 'CategoryID');
         $Wheres = array('d.CategoryID' => $CategoryIDs);
         $this->SetData('_ShowCategoryLink', count($CategoryIDs) > 1);
         // Check permission
         $this->Permission('Vanilla.Discussions.View', TRUE, 'Category', GetValue('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);
         // 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->Pager = $PagerFactory->GetPager('Pager', $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);
         // 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();
     }
 }
 /**
  *
  *
  * @param $Filename
  * @param $Get
  * @return bool|string
  */
 public function filenameRedirect($Filename, $Get)
 {
     trace(['Filename' => $Filename, 'Get' => $Get], 'Testing');
     $Filename = strtolower($Filename);
     array_change_key_case($Get);
     if (!isset(self::$Files[$Filename])) {
         return false;
     }
     $Row = self::$Files[$Filename];
     if (is_callable($Row)) {
         // Use a callback to determine the translation.
         $Row = call_user_func_array($Row, [&$Get]);
     }
     trace($Get, 'New Get');
     // Translate all of the get parameters into new parameters.
     $Vars = array();
     foreach ($Get as $Key => $Value) {
         if (!isset($Row[$Key])) {
             continue;
         }
         $Opts = (array) $Row[$Key];
         if (isset($Opts['Filter'])) {
             // Call the filter function to change the value.
             $R = call_user_func($Opts['Filter'], $Value, $Opts[0]);
             if (is_array($R)) {
                 if (isset($R[0])) {
                     // The filter can change the column name too.
                     $Opts[0] = $R[0];
                     $Value = $R[1];
                 } else {
                     // The filter can return return other variables too.
                     $Vars = array_merge($Vars, $R);
                     $Value = null;
                 }
             } else {
                 $Value = $R;
             }
         }
         if ($Value !== null) {
             $Vars[$Opts[0]] = $Value;
         }
     }
     trace($Vars, 'Translated Arguments');
     // Now let's see what kind of record we have.
     // We'll check the various primary keys in order of importance.
     $Result = false;
     if (isset($Vars['CommentID'])) {
         trace("Looking up comment {$Vars['CommentID']}.");
         $CommentModel = new CommentModel();
         // If a legacy slug is provided (assigned during a merge), attempt to lookup the comment using it
         if (isset($Get['legacy']) && Gdn::Structure()->Table('Comment')->ColumnExists('ForeignID')) {
             $Comment = $CommentModel->GetWhere(['ForeignID' => $Get['legacy'] . '-' . $Vars['CommentID']])->FirstRow();
         } else {
             $Comment = $CommentModel->GetID($Vars['CommentID']);
         }
         if ($Comment) {
             $Result = CommentUrl($Comment, '//');
         }
     } elseif (isset($Vars['DiscussionID'])) {
         trace("Looking up discussion {$Vars['DiscussionID']}.");
         $DiscussionModel = new DiscussionModel();
         $DiscussionID = $Vars['DiscussionID'];
         $Discussion = false;
         if (is_numeric($DiscussionID)) {
             // If a legacy slug is provided (assigned during a merge), attempt to lookup the discussion using it
             if (isset($Get['legacy']) && Gdn::Structure()->Table('Discussion')->ColumnExists('ForeignID')) {
                 $Discussion = $DiscussionModel->GetWhere(['ForeignID' => $Get['legacy'] . '-' . $DiscussionID])->FirstRow();
             } else {
                 $Discussion = $DiscussionModel->GetID($Vars['DiscussionID']);
             }
         } else {
             // This is a slug style discussion ID. Let's see if there is a UrlCode column in the discussion table.
             $DiscussionModel->DefineSchema();
             if ($DiscussionModel->Schema->FieldExists('Discussion', 'UrlCode')) {
                 $Discussion = $DiscussionModel->GetWhere(['UrlCode' => $DiscussionID])->FirstRow();
             }
         }
         if ($Discussion) {
             $Result = DiscussionUrl($Discussion, self::pageNumber($Vars, 'Vanilla.Comments.PerPage'), '//');
         }
     } elseif (isset($Vars['UserID'])) {
         trace("Looking up user {$Vars['UserID']}.");
         $User = Gdn::UserModel()->GetID($Vars['UserID']);
         if ($User) {
             $Result = Url(UserUrl($User), '//');
         }
     } elseif (isset($Vars['TagID'])) {
         $Tag = TagModel::instance()->GetID($Vars['TagID']);
         if ($Tag) {
             $Result = TagUrl($Tag, self::pageNumber($Vars, 'Vanilla.Discussions.PerPage'), '//');
         }
     } elseif (isset($Vars['CategoryID'])) {
         trace("Looking up category {$Vars['CategoryID']}.");
         // If a legacy slug is provided (assigned during a merge), attempt to lookup the category ID based on it
         if (isset($Get['legacy']) && Gdn::Structure()->Table('Category')->ColumnExists('ForeignID')) {
             $CategoryModel = new CategoryModel();
             $Category = $CategoryModel->GetWhere(['ForeignID' => $Get['legacy'] . '-' . $Vars['CategoryID']])->FirstRow();
         } else {
             $Category = CategoryModel::Categories($Vars['CategoryID']);
         }
         if ($Category) {
             $Result = categoryUrl($Category, self::pageNumber($Vars, 'Vanilla.Discussions.PerPage'), '//');
         }
     } elseif (isset($Vars['CategoryCode'])) {
         trace("Looking up category {$Vars['CategoryCode']}.");
         $category = CategoryModel::instance()->getByCode($Vars['CategoryCode']);
         if ($category) {
             $pageNumber = self::pageNumber($Vars, 'Vanilla.Discussions.PerPage');
             if ($pageNumber > 1) {
                 $pageParam = '?Page=' . $pageNumber;
             } else {
                 $pageParam = null;
             }
             $Result = categoryUrl($category, '', '//') . $pageParam;
         }
     }
     return $Result;
 }