Gets either all of the categories or a single category.
public function index() { $vars = array_merge(array('cid' => -1, 'original' => -1, 'order' => 'hot'), $_GET); $total = BlogModel::blogs($vars, true); $Page = new Newpage($total, 10); $this->assign('page', $Page->getPage()); $this->assign($vars); $categories = CategoryModel::categories(); $this->assign('categories', $categories); $blogs = BlogModel::blogs($vars, false, $Page->limit); foreach ($blogs as &$row) { $row['content'] = strip_tags($row['content']); $row['user'] = model('User')->formatForApi($row, $row['uid']); } $this->assign('blogs', $blogs); $hot = BlogModel::hotBlogs(5); foreach ($hot as &$row) { $row['user'] = model('User')->formatForApi($row, $row['uid']); } $this->assign('hot_blogs', $hot); //$hot_users = UserModel::hotUsers(5); $hot_users = BlogModel::hotUsers(5); if (is_array($hot_users) and $hot_users) { foreach ($hot_users as &$user) { $user = model('User')->formatForApi($user, $user['uid']); } } //$this->ajaxReturn($hot_users); $this->assign('hot_users', $hot_users); $this->display(); }
/** * Get data for the configured category. * * @return array|null Array if the configured category is valid. Otherwise, null. */ public function getCategory() { if (!isset($this->category)) { $this->category = CategoryModel::categories($this->categoryID); } return $this->category; }
/** * Render the module. * * @return string */ public function toString() { // Set CategoryID if we have one. if ($this->CategoryID === null) { $this->CategoryID = Gdn::controller()->data('Category.CategoryID', false); } // Allow plugins and themes to modify parameters. Gdn::controller()->EventArguments['NewDiscussionModule'] =& $this; Gdn::controller()->fireEvent('BeforeNewDiscussionButton'); // Make sure the user has the most basic of permissions first. $PermissionCategory = CategoryModel::permissionCategory($this->CategoryID); if ($this->CategoryID) { $Category = CategoryModel::categories($this->CategoryID); $HasPermission = Gdn::session()->checkPermission('Vanilla.Discussions.Add', true, 'Category', val('CategoryID', $PermissionCategory)); } else { $HasPermission = Gdn::session()->checkPermission('Vanilla.Discussions.Add', true, 'Category', 'any'); } // Determine if this is a guest & we're using "New Discussion" button as call to action. $PrivilegedGuest = $this->ShowGuests && !Gdn::session()->isValid(); // No module for you! if (!$HasPermission && !$PrivilegedGuest) { return ''; } // Grab the allowed discussion types. $DiscussionTypes = CategoryModel::allowedDiscussionTypes($PermissionCategory); foreach ($DiscussionTypes as $Key => $Type) { if (isset($Type['AddPermission']) && !Gdn::session()->checkPermission($Type['AddPermission'])) { unset($DiscussionTypes[$Key]); continue; } $Url = val('AddUrl', $Type); if (!$Url) { continue; } if (isset($Category)) { $Url .= '/' . rawurlencode(val('UrlCode', $Category)); } // Present a signin redirect for a $PrivilegedGuest. if (!$HasPermission) { $Url = $this->GuestUrl . '?Target=' . $Url; } $this->addButton(t(val('AddText', $Type)), $Url); } // Add QueryString to URL if one is defined. if ($this->QueryString && $HasPermission) { foreach ($this->Buttons as &$Row) { $Row['Url'] .= (strpos($Row['Url'], '?') !== false ? '&' : '?') . $this->QueryString; } } return parent::toString(); }
/** * Get the data for this module. */ protected function getData() { // Allow plugins to set different data. $this->fireEvent('GetData'); if ($this->Data) { return; } $Categories = CategoryModel::categories(); $Categories2 = $Categories; // Filter out the categories we aren't watching. foreach ($Categories2 as $i => $Category) { if (!$Category['PermsDiscussionsView'] || !$Category['Following']) { unset($Categories[$i]); } } $Data = new Gdn_DataSet($Categories); $Data->DatasetType(DATASET_TYPE_ARRAY); $Data->DatasetType(DATASET_TYPE_OBJECT); $this->Data = $Data; }
/** * * * @param DiscussionsController $sender Sending controller instance. * @param array $args Event arguments. */ public function discussionsController_unanswered_create($sender, $args) { $sender->View = 'Index'; $sender->setData('_PagerUrl', 'discussions/unanswered/{Page}'); // Be sure to display every unanswered question (ie from groups) $categories = CategoryModel::categories(); $this->EventArguments['Categories'] =& $categories; $this->fireEvent('UnansweredBeforeSetCategories'); $sender->setCategoryIDs(array_keys($categories)); $sender->index(val(0, $args, 'p1')); $this->InUnanswered = true; }
/** * Get what messages are active for a template location. * * @param $Location * @param array $Exceptions * @param null $CategoryID * @return array|null */ public function getMessagesForLocation($Location, $Exceptions = array('[Base]'), $CategoryID = null) { $Session = Gdn::session(); $Prefs = $Session->getPreference('DismissedMessages', array()); if (count($Prefs) == 0) { $Prefs[] = 0; } $category = null; if (!empty($CategoryID)) { $category = CategoryModel::categories($CategoryID); } $Exceptions = array_map('strtolower', $Exceptions); list($Application, $Controller, $Method) = explode('/', strtolower($Location)); if (Gdn::cache()->activeEnabled()) { // Get the messages from the cache. $Messages = self::messages(); $Result = array(); foreach ($Messages as $MessageID => $Message) { if (in_array($MessageID, $Prefs) || !$Message['Enabled']) { continue; } $MApplication = strtolower($Message['Application']); $MController = strtolower($Message['Controller']); $MMethod = strtolower($Message['Method']); $Visible = false; if (in_array($MController, $Exceptions)) { $Visible = true; } elseif ($MApplication == $Application && $MController == $Controller && $MMethod == $Method) { $Visible = true; } $Visible = $Visible && self::inCategory($CategoryID, val('CategoryID', $Message), val('IncludeSubcategories', $Message)); if ($category !== null) { $Visible &= CategoryModel::checkPermission($category, 'Vanilla.Discussions.View'); } if ($Visible) { $Result[] = $Message; } } return $Result; } $Result = $this->SQL->select()->from('Message')->where('Enabled', '1')->beginWhereGroup()->whereIn('Controller', $Exceptions)->orOp()->beginWhereGroup()->orWhere('Application', $Application)->where('Controller', $Controller)->where('Method', $Method)->endWhereGroup()->endWhereGroup()->whereNotIn('MessageID', $Prefs)->orderBy('Sort', 'asc')->get()->resultArray(); $Result = array_filter($Result, function ($Message) use($Session, $category) { $visible = MessageModel::inCategory(val('CategoryID', $category, null), val('CategoryID', $Message), val('IncludeSubcategories', $Message)); if ($category !== null) { $visible = $visible && $Session->checkPermission('Vanilla.Discussions.View', true, 'Category', $category['PermissionCategoryID']); } return $visible; }); return $Result; }
/** * Editing a category. * * @since 2.0.0 * @access public * * @param int $CategoryID Unique ID of the category to be updated. */ public function editCategory($CategoryID = '') { // Check permission $this->permission('Garden.Community.Manage'); // Set up models $RoleModel = new RoleModel(); $PermissionModel = Gdn::permissionModel(); $this->Form->setModel($this->CategoryModel); if (!$CategoryID && $this->Form->authenticatedPostBack()) { if ($ID = $this->Form->getFormValue('CategoryID')) { $CategoryID = $ID; } } // Get category data $this->Category = $this->CategoryModel->getID($CategoryID); if (!$this->Category) { throw notFoundException('Category'); } $this->Category->CustomPermissions = $this->Category->CategoryID == $this->Category->PermissionCategoryID; // Set up head $this->addJsFile('jquery.alphanumeric.js'); $this->addJsFile('categories.js'); $this->addJsFile('jquery.gardencheckboxgrid.js'); $this->title(t('Edit Category')); $this->addSideMenu('vanilla/settings/managecategories'); // Make sure the form knows which item we are editing. $this->Form->addHidden('CategoryID', $CategoryID); $this->setData('CategoryID', $CategoryID); // Load all roles with editable permissions $this->RoleArray = $RoleModel->getArray(); $this->fireEvent('AddEditCategory'); if ($this->Form->authenticatedPostBack()) { $this->setupDiscussionTypes($this->Category); $Upload = new Gdn_Upload(); $TmpImage = $Upload->validateUpload('PhotoUpload', false); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->generateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Save the uploaded image $Parts = $Upload->saveAs($TmpImage, $ImageBaseName); $this->Form->setFormValue('Photo', $Parts['SaveName']); } $this->Form->setFormValue('CustomPoints', (bool) $this->Form->getFormValue('CustomPoints')); if ($this->Form->save()) { $Category = CategoryModel::categories($CategoryID); $this->setData('Category', $Category); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { redirect('vanilla/settings/managecategories'); } } } else { $this->Form->setData($this->Category); $this->setupDiscussionTypes($this->Category); $this->Form->setValue('CustomPoints', $this->Category->PointsCategoryID == $this->Category->CategoryID); } // Get all of the currently selected role/permission combinations for this junction. $Permissions = $PermissionModel->getJunctionPermissions(array('JunctionID' => $CategoryID), 'Category', '', array('AddDefaults' => !$this->Category->CustomPermissions)); $Permissions = $PermissionModel->unpivotPermissions($Permissions, true); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $this->setData('PermissionData', $Permissions, true); } // Render default view $this->render(); }
/** * Delete a comment. * * This is a hard delete that completely removes it from the database. * Events: DeleteComment, BeforeDeleteComment. * * @since 2.0.0 * @access public * * @param int $CommentID Unique ID of the comment to be deleted. * @param array $Options Additional options for the delete. * @param bool Always returns TRUE. */ public function delete($CommentID, $Options = array()) { $this->EventArguments['CommentID'] = $CommentID; $Comment = $this->getID($CommentID, DATASET_TYPE_ARRAY); if (!$Comment) { return false; } $Discussion = $this->SQL->getWhere('Discussion', array('DiscussionID' => $Comment['DiscussionID']))->firstRow(DATASET_TYPE_ARRAY); // Decrement the UserDiscussion comment count if the user has seen this comment $Offset = $this->GetOffset($CommentID); $this->SQL->update('UserDiscussion')->set('CountComments', 'CountComments - 1', false)->where('DiscussionID', $Comment['DiscussionID'])->where('CountComments >', $Offset)->put(); $this->EventArguments['Discussion'] = $Discussion; $this->fireEvent('DeleteComment'); $this->fireEvent('BeforeDeleteComment'); // Log the deletion. $Log = val('Log', $Options, 'Delete'); LogModel::insert($Log, 'Comment', $Comment, val('LogOptions', $Options, array())); // Delete the comment. $this->SQL->delete('Comment', array('CommentID' => $CommentID)); // Update the comment count $this->UpdateCommentCount($Discussion, array('Slave' => false)); // Update the user's comment count $this->UpdateUser($Comment['InsertUserID']); // Update the category. $Category = CategoryModel::categories(val('CategoryID', $Discussion)); if ($Category && $Category['LastCommentID'] == $CommentID) { $CategoryModel = new CategoryModel(); $CategoryModel->SetRecentPost($Category['CategoryID']); } // Clear the page cache. $this->RemovePageCache($Comment['DiscussionID']); return true; }
/** * Whether we are in (or optionally below) a category. * * @param int $NeedleCategoryID * @param int $HaystackCategoryID * @param bool $IncludeSubcategories * @return bool */ protected static function inCategory($NeedleCategoryID, $HaystackCategoryID, $IncludeSubcategories = false) { if (!$HaystackCategoryID) { return true; } if ($NeedleCategoryID == $HaystackCategoryID) { return true; } if ($IncludeSubcategories) { $Cat = CategoryModel::categories($NeedleCategoryID); for ($i = 0; $i < 10; $i++) { if (!$Cat) { break; } if ($Cat['CategoryID'] == $HaystackCategoryID) { return true; } $Cat = CategoryModel::categories($Cat['ParentCategoryID']); } } return false; }
/** * Form to edit an existing message. * * @since 2.0.0 * @access public */ public function edit($MessageID = '') { $this->addJsFile('jquery.autosize.min.js'); $this->addJsFile('messages.js'); $this->permission('Garden.Community.Manage'); $this->addSideMenu('dashboard/message'); // Generate some Controller & Asset data arrays $this->setData('Locations', $this->_getLocationData()); $this->AssetData = $this->_getAssetData(); // Set the model on the form. $this->Form->setModel($this->MessageModel); $this->Message = $this->MessageModel->getID($MessageID); $this->Message = $this->MessageModel->defineLocation($this->Message); // Make sure the form knows which item we are editing. if (is_numeric($MessageID) && $MessageID > 0) { $this->Form->addHidden('MessageID', $MessageID); } $CategoriesData = CategoryModel::categories(); $Categories = array(); foreach ($CategoriesData as $Row) { if ($Row['CategoryID'] < 0) { continue; } $Categories[$Row['CategoryID']] = str_repeat(' ', max(0, $Row['Depth'] - 1)) . $Row['Name']; } $this->setData('Categories', $Categories); // If seeing the form for the first time... if (!$this->Form->authenticatedPostBack()) { $this->Form->setData($this->Message); } else { if ($MessageID = $this->Form->save()) { // Reset the message cache $this->MessageModel->setMessageCache(); // Redirect $this->informMessage(t('Your changes have been saved.')); //$this->RedirectUrl = url('dashboard/message'); } } $this->render(); }
function writeDiscussion($Discussion, &$Sender, &$Session) { $CssClass = CssClass($Discussion); $DiscussionUrl = $Discussion->Url; $Category = CategoryModel::categories($Discussion->CategoryID); if ($Session->UserID) { $DiscussionUrl .= '#latest'; } $Sender->EventArguments['DiscussionUrl'] =& $DiscussionUrl; $Sender->EventArguments['Discussion'] =& $Discussion; $Sender->EventArguments['CssClass'] =& $CssClass; $First = UserBuilder($Discussion, 'First'); $Last = UserBuilder($Discussion, 'Last'); $Sender->EventArguments['FirstUser'] =& $First; $Sender->EventArguments['LastUser'] =& $Last; $Sender->fireEvent('BeforeDiscussionName'); $DiscussionName = $Discussion->Name; if ($DiscussionName == '') { $DiscussionName = t('Blank Discussion Topic'); } $Sender->EventArguments['DiscussionName'] =& $DiscussionName; static $FirstDiscussion = TRUE; if (!$FirstDiscussion) { $Sender->fireEvent('BetweenDiscussion'); } else { $FirstDiscussion = FALSE; } $Discussion->CountPages = ceil($Discussion->CountComments / $Sender->CountCommentsPerPage); ?> <li id="Discussion_<?php echo $Discussion->DiscussionID; ?> " class="<?php echo $CssClass; ?> "> <?php if (!property_exists($Sender, 'CanEditDiscussions')) { $Sender->CanEditDiscussions = val('PermsDiscussionsEdit', CategoryModel::categories($Discussion->CategoryID)) && c('Vanilla.AdminCheckboxes.Use'); } $Sender->fireEvent('BeforeDiscussionContent'); // WriteOptions($Discussion, $Sender, $Session); ?> <span class="Options"> <?php echo OptionsList($Discussion); echo BookmarkButton($Discussion); ?> </span> <div class="ItemContent Discussion"> <div class="Title"> <?php echo AdminCheck($Discussion, array('', ' ')) . anchor($DiscussionName, $DiscussionUrl); $Sender->fireEvent('AfterDiscussionTitle'); ?> </div> <div class="Meta Meta-Discussion"> <?php WriteTags($Discussion); ?> <span class="MItem MCount ViewCount"><?php printf(PluralTranslate($Discussion->CountViews, '%s view html', '%s views html', t('%s view'), t('%s views')), BigPlural($Discussion->CountViews, '%s view')); ?> </span> <span class="MItem MCount CommentCount"><?php printf(PluralTranslate($Discussion->CountComments, '%s comment html', '%s comments html', t('%s comment'), t('%s comments')), BigPlural($Discussion->CountComments, '%s comment')); ?> </span> <span class="MItem MCount DiscussionScore Hidden"><?php $Score = $Discussion->Score; if ($Score == '') { $Score = 0; } printf(Plural($Score, '%s point', '%s points', BigPlural($Score, '%s point'))); ?> </span> <?php echo NewComments($Discussion); $Sender->fireEvent('AfterCountMeta'); if ($Discussion->LastCommentID != '') { echo ' <span class="MItem LastCommentBy">' . sprintf(t('Most recent by %1$s'), userAnchor($Last)) . '</span> '; echo ' <span class="MItem LastCommentDate">' . Gdn_Format::date($Discussion->LastDate, 'html') . '</span>'; } else { echo ' <span class="MItem LastCommentBy">' . sprintf(t('Started by %1$s'), userAnchor($First)) . '</span> '; echo ' <span class="MItem LastCommentDate">' . Gdn_Format::date($Discussion->FirstDate, 'html'); if ($Source = val('Source', $Discussion)) { echo ' ' . sprintf(t('via %s'), t($Source . ' Source', $Source)); } echo '</span> '; } if ($Sender->data('_ShowCategoryLink', true) && c('Vanilla.Categories.Use') && $Category) { echo wrap(Anchor(htmlspecialchars($Discussion->Category), CategoryUrl($Discussion->CategoryUrlCode)), 'span', array('class' => 'MItem Category ' . $Category['CssClass'])); } $Sender->fireEvent('DiscussionMeta'); ?> </div> </div> <?php $Sender->fireEvent('AfterDiscussionContent'); ?> </li> <?php }
/** * Pre-populate the form with values from the query string. * * @param Gdn_Form $Form * @param bool $LimitCategories Whether to turn off the category dropdown if there is only one category to show. */ protected function populateForm($Form) { $Get = $this->Request->get(); $Get = array_change_key_case($Get); $Values = arrayTranslate($Get, array('name' => 'Name', 'tags' => 'Tags', 'body' => 'Body')); foreach ($Values as $Key => $Value) { $Form->setValue($Key, $Value); } if (isset($Get['category'])) { $Category = CategoryModel::categories($Get['category']); if ($Category && $Category['PermsDiscussionsAdd']) { $Form->setValue('CategoryID', $Category['CategoryID']); } } }
</thead> <tbody> <?php $Alt = FALSE; foreach ($this->MessageData->result() as $Message) { $Message = $this->MessageModel->DefineLocation($Message); $Alt = $Alt ? FALSE : TRUE; ?> <tr id="<?php echo $Message->MessageID; echo $Alt ? '" class="Alt' : ''; ?> "> <td class="Info nowrap"><?php printf(t('%1$s on %2$s'), arrayValue($Message->AssetTarget, $this->_GetAssetData(), 'Custom Location'), arrayValue($Message->Location, $this->_GetLocationData(), 'Custom Page')); if (val('CategoryID', $Message) && ($Category = CategoryModel::categories($Message->CategoryID))) { echo '<div>' . anchor($Category['Name'], CategoryUrl($Category)); if (val('IncludeSubcategories', $Message)) { echo ' ' . t('and subcategories'); } echo '</div>'; } ?> <div> <strong><?php echo $Message->Enabled == '1' ? t('Enabled') : t('Disabled'); ?> </strong> <?php echo anchor(t('Edit'), '/dashboard/message/edit/' . $Message->MessageID, 'EditMessage SmallButton'); echo anchor(t('Delete'), '/dashboard/message/delete/' . $Message->MessageID . '/' . $Session->TransientKey(), 'DeleteMessage SmallButton');
/** * Add a method to the ModerationController to handle merging discussions. * * @param Gdn_Controller $Sender */ public function moderationController_mergeDiscussions_create($Sender) { $Session = Gdn::session(); $Sender->Form = new Gdn_Form(); $Sender->title(t('Merge Discussions')); $DiscussionModel = new DiscussionModel(); $CheckedDiscussions = Gdn::userModel()->getAttribute($Session->User->UserID, 'CheckedDiscussions', array()); if (!is_array($CheckedDiscussions)) { $CheckedDiscussions = array(); } $DiscussionIDs = $CheckedDiscussions; $Sender->setData('DiscussionIDs', $DiscussionIDs); $CountCheckedDiscussions = count($DiscussionIDs); $Sender->setData('CountCheckedDiscussions', $CountCheckedDiscussions); $Discussions = $DiscussionModel->SQL->whereIn('DiscussionID', $DiscussionIDs)->get('Discussion')->resultArray(); $Sender->setData('Discussions', $Discussions); // Make sure none of the selected discussions are ghost redirects. $discussionTypes = array_column($Discussions, 'Type'); if (in_array('redirect', $discussionTypes)) { throw Gdn_UserException('You cannot merge redirects.', 400); } // Perform the merge if ($Sender->Form->authenticatedPostBack()) { // Create a new discussion record $MergeDiscussion = false; $MergeDiscussionID = $Sender->Form->getFormValue('MergeDiscussionID'); foreach ($Discussions as $Discussion) { if ($Discussion['DiscussionID'] == $MergeDiscussionID) { $MergeDiscussion = $Discussion; break; } } $RedirectLink = $Sender->Form->getFormValue('RedirectLink'); if ($MergeDiscussion) { $ErrorCount = 0; // Verify that the user has permission to perform the merge. $Category = CategoryModel::categories($MergeDiscussion['CategoryID']); if ($Category && !$Category['PermsDiscussionsEdit']) { throw permissionException('Vanilla.Discussions.Edit'); } $DiscussionModel->defineSchema(); $MaxNameLength = val('Length', $DiscussionModel->Schema->getField('Name')); // Assign the comments to the new discussion record $DiscussionModel->SQL->update('Comment')->set('DiscussionID', $MergeDiscussionID)->whereIn('DiscussionID', $DiscussionIDs)->put(); $CommentModel = new CommentModel(); foreach ($Discussions as $Discussion) { if ($Discussion['DiscussionID'] == $MergeDiscussionID) { continue; } // Create a comment out of the discussion. $Comment = arrayTranslate($Discussion, array('Body', 'Format', 'DateInserted', 'InsertUserID', 'InsertIPAddress', 'DateUpdated', 'UpdateUserID', 'UpdateIPAddress', 'Attributes', 'Spam', 'Likes', 'Abuse')); $Comment['DiscussionID'] = $MergeDiscussionID; $CommentModel->Validation->results(true); $CommentID = $CommentModel->save($Comment); if ($CommentID) { // Move any attachments (FileUpload plugin awareness) if (class_exists('MediaModel')) { $MediaModel = new MediaModel(); $MediaModel->reassign($Discussion['DiscussionID'], 'discussion', $CommentID, 'comment'); } if ($RedirectLink) { // The discussion needs to be changed to a moved link. $RedirectDiscussion = array('Name' => SliceString(sprintf(t('Merged: %s'), $Discussion['Name']), $MaxNameLength), 'Type' => 'redirect', 'Body' => formatString(t('This discussion has been <a href="{url,html}">merged</a>.'), array('url' => DiscussionUrl($MergeDiscussion))), 'Format' => 'Html'); $DiscussionModel->setField($Discussion['DiscussionID'], $RedirectDiscussion); $CommentModel->updateCommentCount($Discussion['DiscussionID']); $CommentModel->removePageCache($Discussion['DiscussionID']); } else { // Delete discussion that was merged. $DiscussionModel->delete($Discussion['DiscussionID']); } } else { $Sender->informMessage($CommentModel->Validation->resultsText()); $ErrorCount++; } } // Update counts on all affected discussions. $CommentModel->updateCommentCount($MergeDiscussionID); $CommentModel->removePageCache($MergeDiscussionID); // Clear selections Gdn::userModel()->saveAttribute($Session->UserID, 'CheckedDiscussions', false); ModerationController::informCheckedDiscussions($Sender); if ($ErrorCount == 0) { $Sender->jsonTarget('', '', 'Refresh'); } } } $Sender->render('MergeDiscussions', '', 'plugins/SplitMerge'); }
/** * Load discussions for a specific tag. * @param DiscussionsController $Sender */ public function discussionsController_Tagged_create($Sender) { Gdn_Theme::section('DiscussionList'); $Args = $Sender->RequestArgs; $Get = array_change_key_case($Sender->Request->get()); if ($UseCategories = c('Plugins.Tagging.UseCategories')) { // The url is in the form /category/tag/p1 $CategoryCode = val(0, $Args); $Tag = val(1, $Args); $Page = val(2, $Args); } else { // The url is in the form /tag/p1 $CategoryCode = ''; $Tag = val(0, $Args); $Page = val(1, $Args); } // Look for explcit values. $CategoryCode = val('category', $Get, $CategoryCode); $Tag = val('tag', $Get, $Tag); $Page = val('page', $Get, $Page); $Category = CategoryModel::categories($CategoryCode); $Tag = stringEndsWith($Tag, '.rss', true, true); list($Offset, $Limit) = offsetLimit($Page, c('Vanilla.Discussions.PerPage', 30)); $MultipleTags = strpos($Tag, ',') !== false; $Sender->setData('Tag', $Tag, true); $TagModel = TagModel::instance(); $RecordCount = false; if (!$MultipleTags) { $Tags = $TagModel->getWhere(array('Name' => $Tag))->resultArray(); if (count($Tags) == 0) { throw notFoundException('Page'); } if (count($Tags) > 1) { foreach ($Tags as $TagRow) { if ($TagRow['CategoryID'] == val('CategoryID', $Category)) { break; } } } else { $TagRow = array_pop($Tags); } $Tags = $TagModel->getRelatedTags($TagRow); $RecordCount = $TagRow['CountDiscussions']; $Sender->setData('CountDiscussions', $RecordCount); $Sender->setData('Tags', $Tags); $Sender->setData('Tag', $TagRow); $ChildTags = $TagModel->getChildTags($TagRow['TagID']); $Sender->setData('ChildTags', $ChildTags); } $Sender->title(htmlspecialchars($TagRow['FullName'])); $UrlTag = rawurlencode($Tag); if (urlencode($Tag) == $Tag) { $Sender->canonicalUrl(url(ConcatSep('/', "/discussions/tagged/{$UrlTag}", PageNumber($Offset, $Limit, true)), true)); $FeedUrl = url(ConcatSep('/', "/discussions/tagged/{$UrlTag}/feed.rss", PageNumber($Offset, $Limit, true, false)), '//'); } else { $Sender->canonicalUrl(url(ConcatSep('/', 'discussions/tagged', PageNumber($Offset, $Limit, true)) . '?Tag=' . $UrlTag, true)); $FeedUrl = url(ConcatSep('/', 'discussions/tagged', PageNumber($Offset, $Limit, true, false), 'feed.rss') . '?Tag=' . $UrlTag, '//'); } if ($Sender->Head) { $Sender->addJsFile('discussions.js'); $Sender->Head->addRss($FeedUrl, $Sender->Head->title()); } if (!is_numeric($Offset) || $Offset < 0) { $Offset = 0; } // Add Modules $Sender->addModule('NewDiscussionModule'); $Sender->addModule('DiscussionFilterModule'); $Sender->addModule('BookmarkedModule'); $Sender->setData('Category', false, true); $Sender->AnnounceData = false; $Sender->setData('Announcements', array(), true); $DiscussionModel = new DiscussionModel(); $TagModel->setTagSql($DiscussionModel->SQL, $Tag, $Limit, $Offset, $Sender->Request->get('op', 'or')); $Sender->DiscussionData = $DiscussionModel->get($Offset, $Limit, array('Announce' => 'all')); $Sender->setData('Discussions', $Sender->DiscussionData, true); $Sender->setJson('Loading', $Offset . ' to ' . $Limit); // Build a pager. $PagerFactory = new Gdn_PagerFactory(); $Sender->Pager = $PagerFactory->GetPager('Pager', $Sender); $Sender->Pager->ClientID = 'Pager'; $Sender->Pager->configure($Offset, $Limit, $RecordCount, ''); $Sender->View = c('Vanilla.Discussions.Layout'); /* // If these don't equal, then there is a category that should be inserted. if ($UseCategories && $Category && $TagRow['FullName'] != val('Name', $Category)) { $Sender->Data['Breadcrumbs'][] = array('Name' => $Category['Name'], 'Url' => TagUrl($TagRow)); } $Sender->Data['Breadcrumbs'][] = array('Name' => $TagRow['FullName'], 'Url' => ''); */ // Render the controller. $this->View = c('Vanilla.Discussions.Layout') == 'table' ? 'table' : 'index'; $Sender->render($this->View, 'discussions', 'vanilla'); }
<?php $Category = $this->data('Category'); if (!$Category) { return; } $SubCategories = CategoryModel::MakeTree(CategoryModel::categories(), $Category); if (!$SubCategories) { return; } require_once $this->fetchViewLocation('helper_functions', 'categories', 'vanilla'); ?> <h2 class="ChildCategories-Title Hidden"><?php echo t('Child Categories'); ?> </h2> <ul class="DataList ChildCategoryList"> <?php foreach ($SubCategories as $Row) { if (!$Row['PermsDiscussionsView'] || $Row['Archived']) { continue; } $Row['Depth'] = 1; ?> <li id="Category_<?php echo $Row['CategoryID']; ?> " class="Item Category"> <div class="ItemContent Category"> <h3 class="CategoryName TitleWrap"><?php echo anchor(htmlspecialchars($Row['Name']), $Row['Url'], 'Title');
function getDiscussionOptions($Discussion = null) { $Options = array(); $Sender = Gdn::controller(); $Session = Gdn::session(); if ($Discussion == null) { $Discussion = $Sender->data('Discussion'); } $CategoryID = val('CategoryID', $Discussion); if (!$CategoryID && property_exists($Sender, 'Discussion')) { $CategoryID = val('CategoryID', $Sender->Discussion); } $PermissionCategoryID = val('PermissionCategoryID', $Discussion, val('PermissionCategoryID', $Discussion)); // Build the $Options array based on current user's permission. // Can the user edit the discussion? $CanEdit = DiscussionModel::canEdit($Discussion, $TimeLeft); if ($CanEdit) { if ($TimeLeft) { $TimeLeft = ' (' . Gdn_Format::Seconds($TimeLeft) . ')'; } $Options['EditDiscussion'] = array('Label' => t('Edit') . $TimeLeft, 'Url' => '/post/editdiscussion/' . $Discussion->DiscussionID); } // Can the user announce? if ($Session->checkPermission('Vanilla.Discussions.Announce', TRUE, 'Category', $PermissionCategoryID)) { $Options['AnnounceDiscussion'] = array('Label' => t('Announce'), 'Url' => '/discussion/announce?discussionid=' . $Discussion->DiscussionID . '&Target=' . urlencode($Sender->SelfUrl . '#Head'), 'Class' => 'AnnounceDiscussion Popup'); } // Can the user sink? if ($Session->checkPermission('Vanilla.Discussions.Sink', TRUE, 'Category', $PermissionCategoryID)) { $NewSink = (int) (!$Discussion->Sink); $Options['SinkDiscussion'] = array('Label' => t($Discussion->Sink ? 'Unsink' : 'Sink'), 'Url' => "/discussion/sink?discussionid={$Discussion->DiscussionID}&sink={$NewSink}", 'Class' => 'SinkDiscussion Hijack'); } // Can the user close? if ($Session->checkPermission('Vanilla.Discussions.Close', TRUE, 'Category', $PermissionCategoryID)) { $NewClosed = (int) (!$Discussion->Closed); $Options['CloseDiscussion'] = array('Label' => t($Discussion->Closed ? 'Reopen' : 'Close'), 'Url' => "/discussion/close?discussionid={$Discussion->DiscussionID}&close={$NewClosed}", 'Class' => 'CloseDiscussion Hijack'); } if ($CanEdit && valr('Attributes.ForeignUrl', $Discussion)) { $Options['RefetchPage'] = array('Label' => t('Refetch Page'), 'Url' => '/discussion/refetchpageinfo.json?discussionid=' . $Discussion->DiscussionID, 'Class' => 'RefetchPage Hijack'); } // Can the user move? if ($CanEdit && $Session->checkPermission('Garden.Moderation.Manage')) { $Options['MoveDiscussion'] = array('Label' => t('Move'), 'Url' => '/moderation/confirmdiscussionmoves?discussionid=' . $Discussion->DiscussionID, 'Class' => 'MoveDiscussion Popup'); } // Can the user delete? if ($Session->checkPermission('Vanilla.Discussions.Delete', TRUE, 'Category', $PermissionCategoryID)) { $Category = CategoryModel::categories($CategoryID); $Options['DeleteDiscussion'] = array('Label' => t('Delete Discussion'), 'Url' => '/discussion/delete?discussionid=' . $Discussion->DiscussionID . '&target=' . urlencode(CategoryUrl($Category)), 'Class' => 'DeleteDiscussion Popup'); } // DEPRECATED (as of 2.1) $Sender->EventArguments['Type'] = 'Discussion'; // Allow plugins to add options. $Sender->EventArguments['DiscussionOptions'] =& $Options; $Sender->EventArguments['Discussion'] = $Discussion; $Sender->fireEvent('DiscussionOptions'); return $Options; }
/** * Determine if we have permission to view this content. * * @param $ContentItem * @return bool */ protected function securityFilter($ContentItem) { $CategoryID = val('CategoryID', $ContentItem, null); if (is_null($CategoryID) || $CategoryID === false) { return false; } $Category = CategoryModel::categories($CategoryID); $CanView = val('PermsDiscussionsView', $Category); if (!$CanView) { return false; } return true; }
/** * * * @return bool */ public function updateCounts() { // This option could take a while so set the timeout. set_time_limit(60 * 5); // Define the necessary SQL. $Sqls = array(); if (!$this->importExists('Discussion', 'LastCommentID')) { $Sqls['Discussion.LastCommentID'] = $this->GetCountSQL('max', 'Discussion', 'Comment'); } if (!$this->importExists('Discussion', 'DateLastComment')) { $Sqls['Discussion.DateLastComment'] = "update :_Discussion d\n left join :_Comment c\n on d.LastCommentID = c.CommentID\n set d.DateLastComment = coalesce(c.DateInserted, d.DateInserted)"; } if (!$this->importExists('Discussion', 'LastCommentUserID')) { $Sqls['Discussion.LastCommentUseID'] = "update :_Discussion d\n join :_Comment c\n on d.LastCommentID = c.CommentID\n set d.LastCommentUserID = c.InsertUserID"; } if (!$this->importExists('Discussion', 'Body')) { // Update the body of the discussion if it isn't there. if (!$this->importExists('Discussion', 'FirstCommentID')) { $Sqls['Discussion.FirstCommentID'] = $this->GetCountSQL('min', 'Discussion', 'Comment', 'FirstCommentID', 'CommentID'); } $Sqls['Discussion.Body'] = "update :_Discussion d\n join :_Comment c\n on d.FirstCommentID = c.CommentID\n set d.Body = c.Body, d.Format = c.Format"; if ($this->importExists('Media') && Gdn::structure()->TableExists('Media')) { // Comment Media has to go onto the discussion. $Sqls['Media.Foreign'] = "update :_Media m\n join :_Discussion d\n on d.FirstCommentID = m.ForeignID and m.ForeignTable = 'comment'\n set m.ForeignID = d.DiscussionID, m.ForeignTable = 'discussion'"; } $Sqls['Comment.FirstComment.Delete'] = "delete c.*\n from :_Comment c\n inner join :_Discussion d\n on d.FirstCommentID = c.CommentID"; } if (!$this->importExists('Discussion', 'CountComments')) { $Sqls['Discussion.CountComments'] = $this->GetCountSQL('count', 'Discussion', 'Comment'); } if ($this->importExists('UserDiscussion') && !$this->importExists('UserDiscussion', 'CountComments') && $this->importExists('UserDiscussion', 'DateLastViewed')) { $Sqls['UserDiscussuion.CountComments'] = "update :_UserDiscussion ud\n set CountComments = (\n select count(c.CommentID)\n from :_Comment c\n where c.DiscussionID = ud.DiscussionID\n and c.DateInserted <= ud.DateLastViewed)"; } if ($this->importExists('Tag') && $this->importExists('TagDiscussion')) { $Sqls['Tag.CoundDiscussions'] = $this->GetCountSQL('count', 'Tag', 'TagDiscussion', 'CountDiscussions', 'TagID'); } if ($this->importExists('Poll') && Gdn::structure()->TableExists('Poll')) { $Sqls['PollOption.CountVotes'] = $this->GetCountSQL('count', 'PollOption', 'PollVote', 'CountVotes', 'PollOptionID'); $Sqls['Poll.CountOptions'] = $this->GetCountSQL('count', 'Poll', 'PollOption', 'CountOptions', 'PollID'); $Sqls['Poll.CountVotes'] = $this->GetCountSQL('sum', 'Poll', 'PollOption', 'CountVotes', 'CountVotes', 'PollID'); } if ($this->importExists('Activity', 'ActivityType')) { $Sqls['Activity.ActivityTypeID'] = "\n update :_Activity a\n join :_ActivityType t\n on a.ActivityType = t.Name\n set a.ActivityTypeID = t.ActivityTypeID"; } if ($this->importExists('Tag') && $this->importExists('TagDiscussion')) { $Sqls['Tag.CoundDiscussions'] = $this->GetCountSQL('count', 'Tag', 'TagDiscussion', 'CountDiscussions', 'TagID'); } $Sqls['Category.CountDiscussions'] = $this->GetCountSQL('count', 'Category', 'Discussion'); $Sqls['Category.CountComments'] = $this->GetCountSQL('sum', 'Category', 'Discussion', 'CountComments', 'CountComments'); if (!$this->importExists('Category', 'PermissionCategoryID')) { $Sqls['Category.PermissionCategoryID'] = "update :_Category set PermissionCategoryID = -1"; } if ($this->importExists('Conversation') && $this->importExists('ConversationMessage')) { $Sqls['Conversation.FirstMessageID'] = $this->GetCountSQL('min', 'Conversation', 'ConversationMessage', 'FirstMessageID', 'MessageID'); if (!$this->importExists('Conversation', 'CountMessages')) { $Sqls['Conversation.CountMessages'] = $this->GetCountSQL('count', 'Conversation', 'ConversationMessage', 'CountMessages', 'MessageID'); } if (!$this->importExists('Conversation', 'LastMessageID')) { $Sqls['Conversation.LastMessageID'] = $this->GetCountSQL('max', 'Conversation', 'ConversationMessage', 'LastMessageID', 'MessageID'); } if (!$this->importExists('Conversation', 'DateUpdated')) { $Sqls['Converstation.DateUpdated'] = "update :_Conversation c join :_ConversationMessage m on c.LastMessageID = m.MessageID set c.DateUpdated = m.DateInserted"; } if ($this->importExists('UserConversation')) { if (!$this->importExists('UserConversation', 'LastMessageID')) { if ($this->importExists('UserConversation', 'DateLastViewed')) { // Get the value from the DateLastViewed. $Sqls['UserConversation.LastMessageID'] = "update :_UserConversation uc\n set LastMessageID = (\n select max(MessageID)\n from :_ConversationMessage m\n where m.ConversationID = uc.ConversationID\n and m.DateInserted >= uc.DateLastViewed)"; } else { // Get the value from the conversation. // In this case just mark all of the messages read. $Sqls['UserConversation.LastMessageID'] = "update :_UserConversation uc\n join :_Conversation c\n on c.ConversationID = uc.ConversationID\n set uc.CountReadMessages = c.CountMessages,\n uc.LastMessageID = c.LastMessageID"; } } elseif (!$this->importExists('UserConversation', 'DateLastViewed')) { // We have the last message so grab the date from that. $Sqls['UserConversation.DateLastViewed'] = "update :_UserConversation uc\n join :_ConversationMessage m\n on m.ConversationID = uc.ConversationID\n and m.MessageID = uc.LastMessageID\n set uc.DateLastViewed = m.DateInserted"; } } } // User counts. if (!$this->importExists('User', 'DateFirstVisit')) { $Sqls['User.DateFirstVisit'] = 'update :_User set DateFirstVisit = DateInserted'; } if (!$this->importExists('User', 'CountDiscussions')) { $Sqls['User.CountDiscussions'] = $this->GetCountSQL('count', 'User', 'Discussion', 'CountDiscussions', 'DiscussionID', 'UserID', 'InsertUserID'); } if (!$this->importExists('User', 'CountComments')) { $Sqls['User.CountComments'] = $this->GetCountSQL('count', 'User', 'Comment', 'CountComments', 'CommentID', 'UserID', 'InsertUserID'); } if (!$this->importExists('User', 'CountBookmarks')) { $Sqls['User.CountBookmarks'] = "update :_User u\n set CountBookmarks = (\n select count(ud.DiscussionID)\n from :_UserDiscussion ud\n where ud.Bookmarked = 1\n and ud.UserID = u.UserID\n )"; } // if (!$this->importExists('User', 'CountUnreadConversations')) { // $Sqls['User.CountUnreadConversations'] = // 'update :_User u // set u.CountUnreadConversations = ( // select count(c.ConversationID) // from :_Conversation c // inner join :_UserConversation uc // on c.ConversationID = uc.ConversationID // where uc.UserID = u.UserID // and uc.CountReadMessages < c.CountMessages // )'; // } // The updates start here. $CurrentSubstep = val('CurrentSubstep', $this->Data, 0); // $Sqls2 = array(); // $i = 1; // foreach ($Sqls as $Name => $Sql) { // $Sqls2[] = "/* $i. $Name */\n" // .str_replace(':_', $this->Database->DatabasePrefix, $Sql) // .";\n"; // $i++; // } // throw new Exception(implode("\n", $Sqls2)); // Execute the SQL. $Keys = array_keys($Sqls); for ($i = $CurrentSubstep; $i < count($Keys); $i++) { $this->Data['CurrentStepMessage'] = sprintf(t('%s of %s'), $CurrentSubstep + 1, count($Keys)); $Sql = $Sqls[$Keys[$i]]; $this->query($Sql); if ($this->Timer->ElapsedTime() > $this->MaxStepTime) { $this->Data['CurrentSubstep'] = $i + 1; return false; } } if (isset($this->Data['CurrentSubstep'])) { unset($this->Data['CurrentSubstep']); } $this->Data['CurrentStepMessage'] = ''; // Update the url codes of categories. if (!$this->importExists('Category', 'UrlCode')) { $Categories = CategoryModel::categories(); $TakenCodes = array(); foreach ($Categories as $Category) { $UrlCode = urldecode(Gdn_Format::url($Category['Name'])); if (strlen($UrlCode) > 50) { $UrlCode = 'c' . $Category['CategoryID']; } elseif (is_numeric($UrlCode)) { $UrlCode = 'c' . $UrlCode; } if (in_array($UrlCode, $TakenCodes)) { $ParentCategory = CategoryModel::categories($Category['ParentCategoryID']); if ($ParentCategory && $ParentCategory['CategoryID'] != -1) { $UrlCode = Gdn_Format::url($ParentCategory['Name']) . '-' . $UrlCode; } if (in_array($UrlCode, $TakenCodes)) { $UrlCode = $Category['CategoryID']; } } $TakenCodes[] = $UrlCode; Gdn::sql()->put('Category', array('UrlCode' => $UrlCode), array('CategoryID' => $Category['CategoryID'])); } } // Rebuild the category tree. $CategoryModel = new CategoryModel(); $CategoryModel->RebuildTree(); $this->SetCategoryPermissionIDs(); return true; }
/** * Form to ask for the destination of the move, confirmation and permission check. */ public function confirmDiscussionMoves($DiscussionID = null) { $Session = Gdn::session(); $this->Form = new Gdn_Form(); $DiscussionModel = new DiscussionModel(); $CategoryModel = new CategoryModel(); $this->title(t('Confirm')); if ($DiscussionID) { $CheckedDiscussions = (array) $DiscussionID; $ClearSelection = false; } else { $CheckedDiscussions = Gdn::userModel()->getAttribute($Session->User->UserID, 'CheckedDiscussions', array()); if (!is_array($CheckedDiscussions)) { $CheckedDiscussions = array(); } $ClearSelection = true; } $DiscussionIDs = $CheckedDiscussions; $CountCheckedDiscussions = count($DiscussionIDs); $this->setData('CountCheckedDiscussions', $CountCheckedDiscussions); // Check for edit permissions on each discussion $AllowedDiscussions = array(); $DiscussionData = $DiscussionModel->SQL->select('DiscussionID, Name, DateLastComment, CategoryID, CountComments')->from('Discussion')->whereIn('DiscussionID', $DiscussionIDs)->get(); $DiscussionData = Gdn_DataSet::Index($DiscussionData->resultArray(), array('DiscussionID')); foreach ($DiscussionData as $DiscussionID => $Discussion) { $Category = CategoryModel::categories($Discussion['CategoryID']); if ($Category && $Category['PermsDiscussionsEdit']) { $AllowedDiscussions[] = $DiscussionID; } } $this->setData('CountAllowed', count($AllowedDiscussions)); $CountNotAllowed = $CountCheckedDiscussions - count($AllowedDiscussions); $this->setData('CountNotAllowed', $CountNotAllowed); if ($this->Form->authenticatedPostBack()) { // Retrieve the category id $CategoryID = $this->Form->getFormValue('CategoryID'); $Category = CategoryModel::categories($CategoryID); $RedirectLink = $this->Form->getFormValue('RedirectLink'); // User must have add permission on the target category if (!$Category['PermsDiscussionsAdd']) { throw forbiddenException('@' . t('You do not have permission to add discussions to this category.')); } $AffectedCategories = array(); // Iterate and move. foreach ($AllowedDiscussions as $DiscussionID) { $Discussion = val($DiscussionID, $DiscussionData); // Create the shadow redirect. if ($RedirectLink) { $DiscussionModel->defineSchema(); $MaxNameLength = val('Length', $DiscussionModel->Schema->GetField('Name')); $RedirectDiscussion = array('Name' => SliceString(sprintf(t('Moved: %s'), $Discussion['Name']), $MaxNameLength), 'DateInserted' => $Discussion['DateLastComment'], 'Type' => 'redirect', 'CategoryID' => $Discussion['CategoryID'], 'Body' => formatString(t('This discussion has been <a href="{url,html}">moved</a>.'), array('url' => DiscussionUrl($Discussion))), 'Format' => 'Html', 'Closed' => true); // Pass a forced input formatter around this exception. if (c('Garden.ForceInputFormatter')) { $InputFormat = c('Garden.InputFormatter'); saveToConfig('Garden.InputFormatter', 'Html', false); } $RedirectID = $DiscussionModel->save($RedirectDiscussion); // Reset the input formatter if (c('Garden.ForceInputFormatter')) { saveToConfig('Garden.InputFormatter', $InputFormat, false); } if (!$RedirectID) { $this->Form->setValidationResults($DiscussionModel->validationResults()); break; } } $DiscussionModel->setField($DiscussionID, 'CategoryID', $CategoryID); if (!isset($AffectedCategories[$Discussion['CategoryID']])) { $AffectedCategories[$Discussion['CategoryID']] = array(-1, -$Discussion['CountComments']); } else { $AffectedCategories[$Discussion['CategoryID']][0] -= 1; $AffectedCategories[$Discussion['CategoryID']][1] -= $Discussion['CountComments']; } if (!isset($AffectedCategories[$CategoryID])) { $AffectedCategories[$CategoryID] = array(1, $Discussion['CountComments']); } else { $AffectedCategories[$CategoryID][0] += 1; $AffectedCategories[$CategoryID][1] += $Discussion['CountComments']; } } // Update recent posts and counts on all affected categories. foreach ($AffectedCategories as $CategoryID => $Counts) { $CategoryModel->SetRecentPost($CategoryID); $CategoryModel->SQL->update('Category')->set('CountDiscussions', 'CountDiscussions' . ($Counts[0] < 0 ? ' - ' : ' + ') . abs($Counts[0]), false)->set('CountComments', 'CountComments' . ($Counts[1] < 0 ? ' - ' : ' + ') . abs($Counts[1]), false)->where('CategoryID', $CategoryID)->put(); } // Clear selections. if ($ClearSelection) { Gdn::userModel()->saveAttribute($Session->UserID, 'CheckedDiscussions', false); ModerationController::InformCheckedDiscussions($this); } if ($this->Form->errorCount() == 0) { $this->jsonTarget('', '', 'Refresh'); } } $this->render(); }
/** * Allows user to announce or unannounce a discussion. * * If the discussion isn't announced, this announces it. * If it is already announced, this unannounces it. * Announced discussions stay at the top of the discussions * list regardless of how long ago the last comment was. * * @since 2.0.0 * @access public * * @param int $DiscussionID Unique discussion ID. * @param string $TransientKey Single-use hash to prove intent. */ public function announce($DiscussionID = '', $Target = '') { $Discussion = $this->DiscussionModel->getID($DiscussionID); if (!$Discussion) { throw notFoundException('Discussion'); } $this->permission('Vanilla.Discussions.Announce', true, 'Category', $Discussion->PermissionCategoryID); if ($this->Form->authenticatedPostBack()) { // Save the property. $CacheKeys = array($this->DiscussionModel->getAnnouncementCacheKey(), $this->DiscussionModel->getAnnouncementCacheKey(val('CategoryID', $Discussion))); $this->DiscussionModel->SQL->cache($CacheKeys); $this->DiscussionModel->SetProperty($DiscussionID, 'Announce', (int) $this->Form->getFormValue('Announce', 0)); if ($Target) { $this->RedirectUrl = url($Target); } } else { if (!$Discussion->Announce) { $Discussion->Announce = 2; } $this->Form->setData($Discussion); } $Discussion = (array) $Discussion; $Category = CategoryModel::categories($Discussion['CategoryID']); $this->setData('Discussion', $Discussion); $this->setData('Category', $Category); $this->title(t('Announce')); $this->render(); }
/** * Modify CountUnreadComments to account for DateAllViewed. * * Required in DiscussionModel->get() just before the return: * $this->EventArguments['Data'] = $Data; * $this->fireEvent('AfterAddColumns'); * @link http://vanillaforums.org/discussion/13227 * @since 1.0 * @access public */ public function discussionModel_setCalculatedFields_handler($Sender) { // Only for members if (!Gdn::session()->isValid()) { return; } // Recalculate New count with each category's DateMarkedRead $Discussion =& $Sender->EventArguments['Discussion']; $Category = CategoryModel::categories($Discussion->CategoryID); $CategoryLastDate = Gdn_Format::toTimestamp($Category["DateMarkedRead"]); if ($CategoryLastDate != 0) { $this->checkDiscussionDate($Discussion, $CategoryLastDate); } }
public function incrementNewDiscussion($Discussion) { if (is_numeric($Discussion)) { $Discussion = $this->getID($Discussion); } if (!$Discussion) { return; } $this->SQL->update('Category')->set('CountDiscussions', 'CountDiscussions + 1', false)->set('LastDiscussionID', val('DiscussionID', $Discussion))->set('LastCommentID', null)->set('LastDateInserted', val('DateInserted', $Discussion))->where('CategoryID', val('CategoryID', $Discussion))->put(); $Category = CategoryModel::categories(val('CategoryID', $Discussion)); if ($Category) { CategoryModel::SetCache($Category['CategoryID'], array('CountDiscussions' => $Category['CountDiscussions'] + 1, 'LastDiscussionID' => val('DiscussionID', $Discussion), 'LastCommentID' => null, 'LastDateInserted' => val('DateInserted', $Discussion), 'LastTitle' => Gdn_Format::text(val('Name', $Discussion, t('No Title'))), 'LastUserID' => val('InsertUserID', $Discussion), 'LastDiscussionUserID' => val('InsertUserID', $Discussion), 'LastUrl' => DiscussionUrl($Discussion, false, '//') . '#latest')); } }
echo $this->Form->bodyBox('Body', array('Table' => 'Comment', 'tabindex' => 1, 'FileUpload' => true)); echo '<div class="CommentOptions List Inline">'; $this->fireEvent('AfterBodyField'); echo '</div>'; echo "<div class=\"Buttons\">\n"; $this->fireEvent('BeforeFormButtons'); $CancelText = t('Home'); $CancelClass = 'Back'; if (!$NewOrDraft || $Editing) { $CancelText = t('Cancel'); $CancelClass = 'Cancel'; } echo '<span class="' . $CancelClass . '">'; echo anchor($CancelText, '/'); if ($CategoryID = $this->data('Discussion.CategoryID')) { $Category = CategoryModel::categories($CategoryID); if ($Category) { echo ' <span class="Bullet">•</span> ' . anchor(htmlspecialchars($Category['Name']), categoryUrl($Category)); } } echo '</span>'; $ButtonOptions = array('class' => 'Button Primary CommentButton'); $ButtonOptions['tabindex'] = 1; if (!$Editing && $Session->isValid()) { echo ' ' . anchor(t('Preview'), '#', 'Button PreviewButton') . "\n"; echo ' ' . anchor(t('Edit'), '#', 'Button WriteButton Hidden') . "\n"; if ($NewOrDraft) { echo ' ' . anchor(t('Save Draft'), '#', 'Button DraftButton') . "\n"; } } if ($Session->isValid()) {
function writeTableRow($Row, $Depth = 1) { $Children = $Row['Children']; $WriteChildren = FALSE; if (!empty($Children)) { if ($Depth + 1 >= c('Vanilla.Categories.MaxDisplayDepth')) { $WriteChildren = 'list'; } else { $WriteChildren = 'rows'; } } $H = 'h' . ($Depth + 1); ?> <tr class="<?php echo CssClass($Row); ?> "> <td class="CategoryName"> <div class="Wrap"> <?php echo GetOptions($Row); echo CategoryPhoto($Row); echo "<{$H}>"; echo anchor(htmlspecialchars($Row['Name']), $Row['Url']); Gdn::controller()->EventArguments['Category'] = $Row; Gdn::controller()->fireEvent('AfterCategoryTitle'); echo "</{$H}>"; ?> <div class="CategoryDescription"> <?php echo $Row['Description']; ?> </div> <?php if ($WriteChildren === 'list') { ?> <div class="ChildCategories"> <?php echo wrap(t('Child Categories') . ': ', 'b'); echo CategoryString($Children, $Depth + 1); ?> </div> <?php } ?> </div> </td> <td class="BigCount CountDiscussions"> <div class="Wrap"> <?php // echo "({$Row['CountDiscussions']})"; echo BigPlural($Row['CountAllDiscussions'], '%s discussion'); ?> </div> </td> <td class="BigCount CountComments"> <div class="Wrap"> <?php // echo "({$Row['CountComments']})"; echo BigPlural($Row['CountAllComments'], '%s comment'); ?> </div> </td> <td class="BlockColumn LatestPost"> <div class="Block Wrap"> <?php if ($Row['LastTitle']) { ?> <?php echo userPhoto($Row, array('Size' => 'Small', 'Px' => 'Last')); echo anchor(SliceString(Gdn_Format::text($Row['LastTitle']), 100), $Row['LastUrl'], 'BlockTitle LatestPostTitle', array('title' => html_entity_decode($Row['LastTitle']))); ?> <div class="Meta"> <?php echo userAnchor($Row, 'UserLink MItem', 'Last'); ?> <span class="Bullet">•</span> <?php echo anchor(Gdn_Format::date($Row['LastDateInserted'], 'html'), $Row['LastUrl'], 'CommentDate MItem'); if (isset($Row['LastCategoryID'])) { $LastCategory = CategoryModel::categories($Row['LastCategoryID']); echo ' <span>', sprintf('in %s', anchor($LastCategory['Name'], CategoryUrl($LastCategory, '', '//'))), '</span>'; } ?> </div> <?php } ?> </div> </td> </tr> <?php if ($WriteChildren === 'rows') { foreach ($Children as $ChildRow) { WriteTableRow($ChildRow, $Depth + 1); } } }
/** * Show all (nested) categories. * * @param string $Category The url code of the parent category. * @since 2.0.17 * @access public */ public function all($Category = '') { // Setup head. $this->Menu->highlightRoute('/discussions'); if (!$this->title()) { $Title = c('Garden.HomepageTitle'); if ($Title) { $this->title($Title, ''); } else { $this->title(t('All Categories')); } } Gdn_Theme::section('CategoryList'); if (!$Category) { $this->Description(c('Garden.Description', null)); } $this->setData('Breadcrumbs', CategoryModel::GetAncestors(val('CategoryID', $this->data('Category')))); // Set the category follow toggle before we load category data so that it affects the category query appropriately. $CategoryFollowToggleModule = new CategoryFollowToggleModule($this); $CategoryFollowToggleModule->SetToggle(); // Get category data $this->CategoryModel->Watching = !Gdn::session()->GetPreference('ShowAllCategories'); if ($Category) { $Subtree = CategoryModel::GetSubtree($Category, false); $this->setData('Category', CategoryModel::categories($this->data('Category.CategoryID'))); $CategoryIDs = consolidateArrayValuesByKey($Subtree, 'CategoryID'); $Categories = $this->CategoryModel->GetFull($CategoryIDs)->resultArray(); } else { $Categories = $this->CategoryModel->GetFull()->resultArray(); } $this->setData('Categories', $Categories); // Add modules $this->addModule('NewDiscussionModule'); $this->addModule('DiscussionFilterModule'); $this->addModule('BookmarkedModule'); $this->addModule($CategoryFollowToggleModule); $this->canonicalUrl(url('/categories', true)); $Location = $this->fetchViewLocation('helper_functions', 'categories', false, false); if ($Location) { include_once $Location; } $this->render(); }
/** * Return a url for a category. This function is in here and not functions.general so that plugins can override. * * @param array $Category * @return string */ function categoryUrl($Category, $Page = '', $WithDomain = true) { if (is_string($Category)) { $Category = CategoryModel::categories($Category); } $Category = (array) $Category; $Result = '/categories/' . rawurlencode($Category['UrlCode']); if ($Page && $Page > 1) { $Result .= '/p' . $Page; } return Url($Result, $WithDomain); }
/** * 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(); } }
/** * Writes a discussion in table row format. */ function writeDiscussionRow($Discussion, $Sender, $Session) { if (!property_exists($Sender, 'CanEditDiscussions')) { $Sender->CanEditDiscussions = val('PermsDiscussionsEdit', CategoryModel::categories($Discussion->CategoryID)) && c('Vanilla.AdminCheckboxes.Use'); } $CssClass = CssClass($Discussion); $DiscussionUrl = $Discussion->Url; if ($Session->UserID) { $DiscussionUrl .= '#latest'; } $Sender->EventArguments['DiscussionUrl'] =& $DiscussionUrl; $Sender->EventArguments['Discussion'] =& $Discussion; $Sender->EventArguments['CssClass'] =& $CssClass; $First = UserBuilder($Discussion, 'First'); if ($Discussion->LastUserID) { $Last = UserBuilder($Discussion, 'Last'); } else { $Last = $First; } $Sender->EventArguments['FirstUser'] =& $First; $Sender->EventArguments['LastUser'] =& $Last; $Sender->fireEvent('BeforeDiscussionName'); $DiscussionName = $Discussion->Name; // If there are no word character detected in the title treat it as if it is blank. if (!preg_match('/\\w/u', $DiscussionName)) { $DiscussionName = t('Blank Discussion Topic'); } $Sender->EventArguments['DiscussionName'] =& $DiscussionName; static $FirstDiscussion = true; if (!$FirstDiscussion) { $Sender->fireEvent('BetweenDiscussion'); } else { $FirstDiscussion = false; } $Discussion->CountPages = ceil($Discussion->CountComments / $Sender->CountCommentsPerPage); $FirstPageUrl = DiscussionUrl($Discussion, 1); $LastPageUrl = DiscussionUrl($Discussion, val('CountPages', $Discussion)) . '#latest'; ?> <tr id="Discussion_<?php echo $Discussion->DiscussionID; ?> " class="<?php echo $CssClass; ?> "> <?php $Sender->fireEvent('BeforeDiscussionContent'); ?> <?php echo AdminCheck($Discussion, array('<td class="CheckBoxColumn"><div class="Wrap">', '</div></td>')); ?> <td class="DiscussionName"> <div class="Wrap"> <span class="Options"> <?php echo OptionsList($Discussion); echo BookmarkButton($Discussion); ?> </span> <?php $Sender->fireEvent('BeforeDiscussionTitle'); echo anchor($DiscussionName, $DiscussionUrl, 'Title') . ' '; $Sender->fireEvent('AfterDiscussionTitle'); WriteMiniPager($Discussion); echo NewComments($Discussion); if ($Sender->data('_ShowCategoryLink', true)) { echo CategoryLink($Discussion, ' ' . t('in') . ' '); } // Other stuff that was in the standard view that you may want to display: echo '<div class="Meta Meta-Discussion">'; WriteTags($Discussion); echo '</div>'; // if ($Source = val('Source', $Discussion)) // echo ' '.sprintf(t('via %s'), t($Source.' Source', $Source)); // ?> </div> </td> <td class="BlockColumn BlockColumn-User FirstUser"> <div class="Block Wrap"> <?php echo userPhoto($First, array('Size' => 'Small')); echo userAnchor($First, 'UserLink BlockTitle'); echo '<div class="Meta">'; echo anchor(Gdn_Format::date($Discussion->FirstDate, 'html'), $FirstPageUrl, 'CommentDate MItem'); echo '</div>'; ?> </div> </td> <td class="BigCount CountComments"> <div class="Wrap"> <?php // Exact Number // echo number_format($Discussion->CountComments); // Round Number echo BigPlural($Discussion->CountComments, '%s comment'); ?> </div> </td> <td class="BigCount CountViews"> <div class="Wrap"> <?php // Exact Number // echo number_format($Discussion->CountViews); // Round Number echo BigPlural($Discussion->CountViews, '%s view'); ?> </div> </td> <td class="BlockColumn BlockColumn-User LastUser"> <div class="Block Wrap"> <?php if ($Last) { echo userPhoto($Last, array('Size' => 'Small')); echo userAnchor($Last, 'UserLink BlockTitle'); echo '<div class="Meta">'; echo anchor(Gdn_Format::date($Discussion->LastDate, 'html'), $LastPageUrl, 'CommentDate MItem'); echo '</div>'; } else { echo ' '; } ?> </div> </td> </tr> <?php }
/** * Adds email notification options to profiles. * * @since 2.0.0 * @package Vanilla * * @param ProfileController $Sender */ public function profileController_afterPreferencesDefined_handler($Sender) { $Sender->Preferences['Notifications']['Email.DiscussionComment'] = t('Notify me when people comment on my discussions.'); $Sender->Preferences['Notifications']['Email.BookmarkComment'] = t('Notify me when people comment on my bookmarked discussions.'); $Sender->Preferences['Notifications']['Email.Mention'] = t('Notify me when people mention me.'); $Sender->Preferences['Notifications']['Email.ParticipateComment'] = t('Notify me when people comment on discussions I\'ve participated in.'); $Sender->Preferences['Notifications']['Popup.DiscussionComment'] = t('Notify me when people comment on my discussions.'); $Sender->Preferences['Notifications']['Popup.BookmarkComment'] = t('Notify me when people comment on my bookmarked discussions.'); $Sender->Preferences['Notifications']['Popup.Mention'] = t('Notify me when people mention me.'); $Sender->Preferences['Notifications']['Popup.ParticipateComment'] = t('Notify me when people comment on discussions I\'ve participated in.'); if (Gdn::session()->checkPermission('Garden.AdvancedNotifications.Allow')) { $PostBack = $Sender->Form->authenticatedPostBack(); $Set = array(); // Add the category definitions to for the view to pick up. $DoHeadings = c('Vanilla.Categories.DoHeadings'); // Grab all of the categories. $Categories = array(); $Prefixes = array('Email.NewDiscussion', 'Popup.NewDiscussion', 'Email.NewComment', 'Popup.NewComment'); foreach (CategoryModel::categories() as $Category) { if (!$Category['PermsDiscussionsView'] || $Category['Depth'] <= 0 || $Category['Depth'] > 2 || $Category['Archived']) { continue; } $Category['Heading'] = $DoHeadings && $Category['Depth'] <= 1; $Categories[] = $Category; if ($PostBack) { foreach ($Prefixes as $Prefix) { $FieldName = "{$Prefix}.{$Category['CategoryID']}"; $Value = $Sender->Form->getFormValue($FieldName, null); if (!$Value) { $Value = null; } $Set[$FieldName] = $Value; } } } $Sender->setData('CategoryNotifications', $Categories); if ($PostBack) { UserModel::setMeta($Sender->User->UserID, $Set, 'Preferences.'); } } }