/** * Deny access to private support discussions. */ public function DiscussionController_Render_Before($Sender, $Args) { // Get category & discussion data $Category = CategoryModel::Categories($Sender->Data('CategoryID')); $Discussion = CategoryModel::Categories($Sender->Data('CategoryID')); // Evaluate conditions $Private = GetValue('PrivateSupport', $Category) ? TRUE : FALSE; $Mine = GetValue('InsertUserID', $Discussion) == Gdn::Session()->UserID ? TRUE : FALSE; // Deny access to private support discussions if (!$Mine && $Private) { $Sender->Permission('Garden.Moderation.Manage'); } }
/** * 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', GetValue('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; } // If user !$HasPermission, they are $PrivilegedGuest so redirect to $GuestUrl. $Url = $HasPermission ? GetValue('AddUrl', $Type) : $this->GuestUrl; if (!$Url) { continue; } if (isset($Category) && $HasPermission) { $Url .= '/' . rawurlencode(GetValue('UrlCode', $Category)); } $this->AddButton(T(GetValue('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(); }
public function __construct($Sender = '', $ApplicationFolder = '') { $this->Data = FALSE; $NoFollowing = TRUE; if (C('Vanilla.Categories.Use') == TRUE) { // Load categories with respect to view permissions $Categories = CategoryModel::Categories(); $Categories2 = $Categories; foreach ($Categories2 as $i => $Category) { if (!$Category['PermsDiscussionsView']) { unset($Categories[$i]); } elseif (!$Category['Following']) { $NoFollowing = FALSE; } } // delete view filter if no categories are hidden $Session = Gdn::Session(); if ($NoFollowing && $Session->IsValid()) { $Session->SetPreference('ShowAllCategories', TRUE); } // set categories to data $Data = new Gdn_DataSet($Categories); $Data->DatasetType(DATASET_TYPE_ARRAY); $Data->DatasetType(DATASET_TYPE_OBJECT); $this->Data['Categories'] = $Data; // calculate additional needed data $this->Data['CategoryID'] = isset($Sender->CategoryID) ? $Sender->CategoryID : ''; $this->Data['OnCategories'] = strtolower($Sender->ControllerName) == 'categoriescontroller' && !is_numeric($this->Data['CategoryID']); $this->Data['ShowAllCategoriesPref'] = $Session->GetPreference('ShowAllCategories'); $this->Data['Url'] = Gdn::Request()->Path(); if ($this->Data['Url'] == '') { $this->Data['Url'] = '/'; } $this->Data['ShowAllCategoriesUrl'] = Gdn::Request()->Url('categories/settoggle?ShowAllCategories=true&Target=' . $this->Data['Url']); $this->Data['ShowFollowedCategoriesUrl'] = Gdn::Request()->Url('categories/settoggle?ShowAllCategories=false&Target=' . $this->Data['Url']); $this->Data['TKey'] = urlencode(Gdn::Session()->TransientKey()); $this->Data['ValidSession'] = $Session->UserID > 0 && $Session->ValidateTransientKey($this->Data['TKey']); $this->Data['MaxDepth'] = C('Vanilla.Categories.MaxDisplayDepth'); $this->Data['DoHeadings'] = C('Vanilla.Categories.DoHeadings'); } parent::__construct($Sender, $ApplicationFolder); }
public function __construct($Sender = '') { // Load categories $this->Data = FALSE; if (C('Vanilla.Categories.Use') == TRUE && !C('Vanilla.Categories.HideModule')) { $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; } parent::__construct($Sender); }
public function ToString() { if ($this->CategoryID === NULL) { $this->CategoryID = Gdn::Controller()->Data('Category.CategoryID', FALSE); } 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', GetValue('CategoryID', $PermissionCategory)); } else { $HasPermission = Gdn::Session()->CheckPermission('Vanilla.Discussions.Add', TRUE, 'Category', 'any'); } if (!$HasPermission) { 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 = GetValue('AddUrl', $Type); if (!$Url) { continue; } if (isset($Category)) { $Url .= '/' . rawurlencode(GetValue('UrlCode', $Category)); } $this->AddButton(T(GetValue('AddText', $Type)), $Url); } if ($this->QueryString) { foreach ($this->Buttons as &$Row) { $Row['Url'] .= (strpos($Row['Url'], '?') !== FALSE ? '&' : '?') . $this->QueryString; } } return parent::ToString(); }
protected 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; }
public function PostController_BeforeBodyInput_Handler($Sender) { # If the script ID is passed in, it will be hardcoded to category 4. if ($this->ScriptIDPassed($Sender)) { return; } echo '<div class="P">'; echo '<div class="Category">'; echo $Sender->Form->Label('Category', 'CategoryID'), ' '; echo '<br>'; $SelectedCategory = GetValue('CategoryID', $Sender->Category); foreach (CategoryModel::Categories() as $c) { # -1 is the root if ($c['CategoryID'] != -1) { #4 is Style Reviews, which should only by used when script id is passed (and skips this anyway) or by mods if ($c['CategoryID'] != 4 || Gdn::Session()->CheckPermission('Vanilla.Discussions.Edit')) { echo '<input name="CategoryID" id="category-' . $c['CategoryID'] . '" type="radio" value="' . $c['CategoryID'] . '"' . ($SelectedCategory == $c['CategoryID'] ? ' checked' : '') . '><label for="category-' . $c['CategoryID'] . '">' . $c['Name'] . ' - ' . $c['Description'] . '</label><br>'; } } } #echo $Sender->Form->CategoryDropDown('CategoryID', array('Value' => GetValue('CategoryID', $this->Category))); echo '</div>'; echo '</div>'; }
/** * 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); // 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 = GetValue('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'); }
/** * Writes a discussion in table row format. */ function WriteDiscussionRow($Discussion, &$Sender, &$Session, $Alt2) { if (!property_exists($Sender, 'CanEditDiscussions')) { $Sender->CanEditDiscussions = GetValue('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 ($DiscussionName == '') { $DiscussionName = T('Blank Discussion Topic'); } $Sender->EventArguments['DiscussionName'] =& $DiscussionName; $Discussion->CountPages = ceil($Discussion->CountComments / $Sender->CountCommentsPerPage); $FirstPageUrl = DiscussionUrl($Discussion, 1); $LastPageUrl = DiscussionUrl($Discussion, FALSE) . '#latest'; ?> <tr id="Discussion_<?php echo $Discussion->DiscussionID; ?> " class="<?php echo $CssClass; ?> "> <?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 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 = GetValue('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 }
// $CommentOptions = array('MultiLine' => TRUE, 'format' => GetValueR('Comment.Format', $this)); $this->FireEvent('BeforeBodyField'); echo $this->Form->BodyBox('Body', array('Table' => 'Comment', 'tabindex' => 1)); $this->FireEvent('AfterBodyField'); 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($Category['Name'], $Category['Url']); } } echo '</span>'; $ButtonOptions = array('class' => 'Button Primary CommentButton'); $ButtonOptions['tabindex'] = 2; /* Caused non-root users to not be able to add comments. Must take categories into account. Look at CheckPermission for more information. if (!Gdn::Session()->CheckPermission('Vanilla.Comment.Add')) $ButtonOptions['Disabled'] = 'disabled'; */ if (!$Editing && $Session->IsValid()) { echo Anchor(T('Preview'), '#', 'PreviewButton') . "\n";
/** * 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 = GetValue(0, $Args); $Tag = GetValue(1, $Args); $Page = GetValue(2, $Args); } else { // The url is in the form /tag/p1 $CategoryCode = ''; $Tag = GetValue(0, $Args); $Page = GetValue(1, $Args); } // Look for explcit values. $CategoryCode = GetValue('category', $Get, $CategoryCode); $Tag = GetValue('tag', $Get, $Tag); $Page = GetValue('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'] == GetValue('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'] != GetValue('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'); }
/** * Grab and update the category cache * * @since 2.0.18 * @access public * @param int $ID * @param array $Data */ public static function setCache($ID = false, $Data = false) { self::instance()->collection->refreshCache((int) $ID); $Categories = Gdn::cache()->get(self::CACHE_KEY); self::$Categories = null; if (!$Categories) { return; } // Extract actual category list, remove key if malformed if (!$ID || !is_array($Categories) || !array_key_exists('categories', $Categories)) { Gdn::cache()->remove(self::CACHE_KEY); return; } $Categories = $Categories['categories']; // Check for category in list, otherwise remove key if not found if (!array_key_exists($ID, $Categories)) { Gdn::cache()->remove(self::CACHE_KEY); return; } $Category = $Categories[$ID]; $Category = array_merge($Category, $Data); $Categories[$ID] = $Category; // Update memcache entry self::$Categories = $Categories; unset($Categories); self::BuildCache($ID); self::JoinUserData(self::$Categories, true); }
/** * Delete a comment. * * This is a hard delete that completely removes it from the database. * Events: DeleteComment. * * @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->FireEvent('DeleteComment'); // Log the deletion. $Log = GetValue('Log', $Options, 'Delete'); LogModel::Insert($Log, 'Comment', $Comment, GetValue('LogOptions', $Options, array())); // Delete the comment. $this->SQL->Delete('Comment', array('CommentID' => $CommentID)); // Update the comment count $this->UpdateCommentCount($Discussion); // Update the user's comment count $this->UpdateUser($Comment['InsertUserID']); // Update the category. $Category = CategoryModel::Categories(GetValue('CategoryID', $Discussion)); if ($Category && $Category['LastCommentID'] == $CommentID) { $CategoryModel = new CategoryModel(); $CategoryModel->SetRecentPost($Category['CategoryID']); } // Clear the page cache. $this->RemovePageCache($Comment['DiscussionID']); return TRUE; }
/** * Grab and update the category cache * * @since 2.0.18 * @access public * @param int $ID * @param array $Data */ public static function SetCache($ID = FALSE, $Data = FALSE) { $Categories = Gdn::Cache()->Get(self::CACHE_KEY); self::$Categories = NULL; if (!$Categories) { return; } if (!$ID || !is_array($Categories)) { Gdn::Cache()->Remove(self::CACHE_KEY); return; } if (!array_key_exists($ID, $Categories)) { Gdn::Cache()->Remove(self::CACHE_KEY); return; } $Category = $Categories[$ID]; $Category = array_merge($Category, $Data); $Categories[$ID] = $Category; self::$Categories = $Categories; unset($Categories); self::BuildCache(); self::JoinUserData(self::$Categories, TRUE); }
/** * 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.Settings.Manage'); // Set up models $RoleModel = new RoleModel(); $PermissionModel = Gdn::PermissionModel(); $this->Form->SetModel($this->CategoryModel); if (!$CategoryID && $this->Form->IsPostBack()) { if ($ID = $this->Form->GetFormValue('CategoryID')) { $CategoryID = $ID; } } // Get category data $this->Category = $this->CategoryModel->GetID($CategoryID); $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->IsPostBack() == FALSE) { $this->Form->SetData($this->Category); $this->SetupDiscussionTypes($this->Category); $this->Form->SetValue('CustomPoints', $this->Category->PointsCategoryID == $this->Category->CategoryID); } else { $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'); } } } // 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(); }
/** * @param Gdn_Controller $Sender * @param type $Args */ public function UtilityController_SiteMapIndex_Create($Sender) { // Clear the session to mimic a crawler. Gdn::Session()->Start(0, FALSE, FALSE); $Sender->DeliveryMethod(DELIVERY_METHOD_XHTML); $Sender->DeliveryType(DELIVERY_TYPE_VIEW); $Sender->SetHeader('Content-Type', 'text/xml'); $SiteMaps = array(); if (class_exists('CategoryModel')) { $Categories = CategoryModel::Categories(); foreach ($Categories as $Category) { if (!$Category['PermsDiscussionsView'] || $Category['CategoryID'] < 0 || $Category['CountDiscussions'] == 0) { continue; } $SiteMap = array('Loc' => Url('/sitemap-category-' . rawurlencode($Category['UrlCode'] ? $Category['UrlCode'] : $Category['CategoryID']) . '.xml', TRUE), 'LastMod' => $Category['DateLastComment'], 'ChangeFreq' => '', 'Priority' => ''); $SiteMaps[] = $SiteMap; } } $Sender->SetData('SiteMaps', $SiteMaps); $Sender->Render('SiteMapIndex', '', 'plugins/Sitemaps'); }
/** * 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); // 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; } } 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'); } // 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'); } // 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->RedirectUrl = Url("/discussion/{$MergeDiscussionID}/" . Gdn_Format::Url($MergeDiscussion['Name'])); } } } $Sender->Render('MergeDiscussions', '', 'plugins/SplitMerge'); }
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\r\n left join :_Comment c\r\n on d.LastCommentID = c.CommentID\r\n set d.DateLastComment = coalesce(c.DateInserted, d.DateInserted)"; } if (!$this->ImportExists('Discussion', 'CountBookmarks')) { $Sqls['Discussion.CountBookmarks'] = "update :_Discussion d\r\n set CountBookmarks = (\r\n select count(ud.DiscussionID)\r\n from :_UserDiscussion ud\r\n where ud.Bookmarked = 1\r\n and ud.DiscussionID = d.DiscussionID\r\n )"; } if (!$this->ImportExists('Discussion', 'LastCommentUserID')) { $Sqls['Discussion.LastCommentUseID'] = "update :_Discussion d\r\n join :_Comment c\r\n on d.LastCommentID = c.CommentID\r\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\r\n join :_Comment c\r\n on d.FirstCommentID = c.CommentID\r\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\r\n join :_Discussion d\r\n on d.FirstCommentID = m.ForeignID and m.ForeignTable = 'comment'\r\n set m.ForeignID = d.DiscussionID, m.ForeignTable = 'discussion'"; } $Sqls['Comment.FirstComment.Delete'] = "delete c.*\r\n from :_Comment c\r\n inner join :_Discussion d\r\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\r\n set CountComments = (\r\n select count(c.CommentID)\r\n from :_Comment c\r\n where c.DiscussionID = ud.DiscussionID\r\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'] = "\r\n update :_Activity a\r\n join :_ActivityType t\r\n on a.ActivityType = t.Name\r\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\r\n set LastMessageID = (\r\n select max(MessageID)\r\n from :_ConversationMessage m\r\n where m.ConversationID = uc.ConversationID\r\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\r\n join :_Conversation c\r\n on c.ConversationID = uc.ConversationID\r\n set uc.CountReadMessages = c.CountMessages,\r\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\r\n join :_ConversationMessage m\r\n on m.ConversationID = uc.ConversationID\r\n and m.MessageID = uc.LastMessageID\r\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\r\n set CountBookmarks = (\r\n select count(ud.DiscussionID)\r\n from :_UserDiscussion ud\r\n where ud.Bookmarked = 1\r\n and ud.UserID = u.UserID\r\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 = GetValue('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 = $Category['CategoryID']; } 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; }
/** * Check whether a user has access to view discussions in a particular category. * * @since 2.0.18 * @example $UserModel->GetCategoryViewPermission($UserID, $CategoryID). * * @param $Sender UserModel. * @return bool Whether user has permission. */ public function UserModel_GetCategoryViewPermission_Create($Sender) { static $PermissionModel = NULL; $UserID = ArrayValue(0, $Sender->EventArguments, ''); $CategoryID = ArrayValue(1, $Sender->EventArguments, ''); if ($UserID && $CategoryID) { if ($PermissionModel === NULL) { $PermissionModel = new PermissionModel(); } $Category = CategoryModel::Categories($CategoryID); if ($Category) { $PermissionCategoryID = $Category['PermissionCategoryID']; } else { $PermissionCategoryID = -1; } $Result = $PermissionModel->GetUserPermissions($UserID, 'Vanilla.Discussions.View', 'Category', 'PermissionCategoryID', 'CategoryID', $PermissionCategoryID); return GetValue('Vanilla.Discussions.View', GetValue(0, $Result), FALSE) ? TRUE : FALSE; } return FALSE; }
/** * * @param type $Discussion * @param type $NotifiedUsers * @param ActivityModel $ActivityModel */ public function NotifyNewDiscussion($Discussion, $ActivityModel, $Activity) { if (is_numeric($Discussion)) { $Discussion = $this->GetID($Discussion); } $CategoryID = GetValue('CategoryID', $Discussion); // Figure out the category that governs this notification preference. $i = 0; $Category = CategoryModel::Categories($CategoryID); if (!$Category) { return; } while ($Category['Depth'] > 2 && $i < 20) { if (!$Category || $Category['Archived']) { return; } $i++; $Category = CategoryModel::Categories($Category['ParentCategoryID']); } // Grab all of the users that need to be notified. $Data = $this->SQL->WhereIn('Name', array('Preferences.Email.NewDiscussion.' . $Category['CategoryID'], 'Preferences.Popup.NewDiscussion.' . $Category['CategoryID']))->Get('UserMeta')->ResultArray(); // decho($Data, 'Data'); $NotifyUsers = array(); foreach ($Data as $Row) { if (!$Row['Value']) { continue; } $UserID = $Row['UserID']; $Name = $Row['Name']; if (strpos($Name, '.Email.') !== FALSE) { $NotifyUsers[$UserID]['Emailed'] = ActivityModel::SENT_PENDING; } elseif (strpos($Name, '.Popup.') !== FALSE) { $NotifyUsers[$UserID]['Notified'] = ActivityModel::SENT_PENDING; } } // decho($NotifyUsers); $InsertUserID = GetValue('InsertUserID', $Discussion); foreach ($NotifyUsers as $UserID => $Prefs) { if ($UserID == $InsertUserID) { continue; } $Activity['NotifyUserID'] = $UserID; $Activity['Emailed'] = GetValue('Emailed', $Prefs, FALSE); $Activity['Notified'] = GetValue('Notified', $Prefs, FALSE); $ActivityModel->Queue($Activity); // decho($Activity, 'die'); } // die(); }
/** * 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); }
function WriteDiscussion($Discussion, &$Sender, &$Session, $Alt2) { static $Alt = FALSE; $CssClass = 'Item'; $CssClass .= $Discussion->Bookmarked == '1' ? ' Bookmarked' : ''; $CssClass .= $Alt ? ' Alt ' : ''; $Alt = !$Alt; $CssClass .= $Discussion->Announce == '1' ? ' Announcement' : ''; $CssClass .= $Discussion->Dismissed == '1' ? ' Dismissed' : ''; $CssClass .= $Discussion->InsertUserID == $Session->UserID ? ' Mine' : ''; $CssClass .= $Discussion->CountUnreadComments > 0 && $Session->IsValid() ? ' New' : ''; $DiscussionUrl = '/discussion/' . $Discussion->DiscussionID . '/' . Gdn_Format::Url($Discussion->Name) . ($Discussion->CountCommentWatch > 0 && C('Vanilla.Comments.AutoOffset') && $Session->UserID > 0 ? '/#Item_' . $Discussion->CountCommentWatch : ''); // $DiscussionUrl = $Discussion->Url; $Sender->EventArguments['DiscussionUrl'] =& $DiscussionUrl; $Sender->EventArguments['Discussion'] =& $Discussion; $Sender->EventArguments['CssClass'] =& $CssClass; $First = UserBuilder($Discussion, 'First'); $Last = UserBuilder($Discussion, '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; } ?> <li class="<?php echo $CssClass; ?> "> <?php if (!property_exists($Sender, 'CanEditDiscussions')) { $Sender->CanEditDiscussions = GetValue('PermsDiscussionsEdit', CategoryModel::Categories($Discussion->CategoryID)) && C('Vanilla.AdminCheckboxes.Use'); } $Sender->FireEvent('BeforeDiscussionContent'); WriteOptions($Discussion, $Sender, $Session); ?> <div class="ItemContent Discussion"> <?php echo Anchor($DiscussionName, $DiscussionUrl, 'Title'); ?> <?php $Sender->FireEvent('AfterDiscussionTitle'); ?> <div class="Meta"> <?php $Sender->FireEvent('BeforeDiscussionMeta'); ?> <?php if ($Discussion->Announce == '1') { ?> <span class="Tag Announcement"><?php echo T('Announcement'); ?> </span> <?php } ?> <?php if ($Discussion->Closed == '1') { ?> <span class="Tag Closed"><?php echo T('Closed'); ?> </span> <?php } ?> <span class="MItem CommentCount"><?php printf(Plural($Discussion->CountComments, '%s comment', '%s comments'), $Discussion->CountComments); if ($Session->IsValid() && $Discussion->CountUnreadComments > 0) { echo ' <strong class="HasNew">' . Plural($Discussion->CountUnreadComments, '%s new', '%s new plural') . '</strong>'; } ?> </span> <?php $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) . '</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); if ($Source = GetValue('Source', $Discussion)) { echo ' ' . sprintf(T('via %s'), T($Source . ' Source', $Source)); } echo '</span> '; } if (C('Vanilla.Categories.Use') && $Discussion->CategoryUrlCode != '') { echo ' ' . Wrap(Anchor($Discussion->Category, '/categories/' . rawurlencode($Discussion->CategoryUrlCode)), 'span', array('class' => 'Tag Category')); } $Sender->FireEvent('DiscussionMeta'); ?> </div> </div> </li> <?php }
public static function CategoryUrl($Category, $Page = '', $WithDomain = TRUE) { if (function_exists('CategoryUrl')) { return CategoryUrl($Category, $Page, $WithDomain); } 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); }
<div class="Excerpt"><?php echo Anchor(nl2br(SliceString(Gdn_Format::Text($Row->Summary, FALSE), 250)), $Row->Url); ?> </div> <div class="Meta"> <span><?php printf(T('by %s'), UserAnchor($Row)); ?> </span> <span><?php echo Gdn_Format::Date($Row->DateInserted); ?> </span> <?php if (isset($Row->CategoryID)) { $Category = CategoryModel::Categories($Row->CategoryID); if ($Category !== NULL) { $Url = Url('categories/' . $Category['UrlCode']); echo "<span><a class='Category' href='{$Url}'>{$Category['Name']}</a></span>"; } } ?> <span><?php echo Anchor(T('permalink'), $Row->Url); ?> </span> </div> </div> </li> <?php }
/** * 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.Messages.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(); }
/** * 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']); } } }
/** * 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']['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.'); // if (Gdn::Session()->CheckPermission('Garden.AdvancedNotifications.Allow')) { // $Sender->Preferences['Notifications']['Email.NewDiscussion'] = array(T('Notify me when people start new discussions.'), 'Meta'); // $Sender->Preferences['Notifications']['Email.NewComment'] = array(T('Notify me when people comment on a discussion.'), 'Meta'); //// $Sender->Preferences['Notifications']['Popup.NewDiscussion'] = T('Notify me when people start new discussions.'); // } if (Gdn::Session()->CheckPermission('Garden.AdvancedNotifications.Allow')) { $PostBack = $Sender->Form->IsPostBack(); $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.'); } } }
/** * 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(); } }
/** * Returns XHTML for a select list containing categories that the user has * permission to use. * * @param array $FieldName An array of category data to render. * @param array $Options An associative array of options for the select. Here * is a list of "special" options and their default values: * * Attribute Options Default * ------------------------------------------------------------------------ * Value The ID of the category that FALSE * is selected. * IncludeNull Include a blank row? TRUE * CategoryData Custom set of categories to CategoryModel::Categories() * display. * * @return string */ public function CategoryDropDown($FieldName = 'CategoryID', $Options = FALSE) { $Value = ArrayValueI('Value', $Options); // The selected category id $CategoryData = GetValue('CategoryData', $Options, CategoryModel::Categories()); // Sanity check if (is_object($CategoryData)) { $CategoryData = (array) $CategoryData; } else { if (!is_array($CategoryData)) { $CategoryData = array(); } } $Permission = GetValue('Permission', $Options, 'add'); // Respect category permissions (remove categories that the user shouldn't see). $SafeCategoryData = array(); foreach ($CategoryData as $CategoryID => $Category) { if ($Permission == 'add' && !$Category['PermsDiscussionsAdd']) { continue; } if ($Value != $CategoryID) { if ($Category['CategoryID'] <= 0 || !$Category['PermsDiscussionsView']) { continue; } if ($Category['Archived']) { continue; } } $SafeCategoryData[$CategoryID] = $Category; } // Opening select tag $Return = '<select'; $Return .= $this->_IDAttribute($FieldName, $Options); $Return .= $this->_NameAttribute($FieldName, $Options); $Return .= $this->_AttributesToString($Options); $Return .= ">\n"; // Get value from attributes if ($Value === FALSE) { $Value = $this->GetValue($FieldName); } if (!is_array($Value)) { $Value = array($Value); } // Prevent default $Value from matching key of zero $HasValue = $Value !== array(FALSE) && $Value !== array('') ? TRUE : FALSE; // Start with null option? $IncludeNull = GetValue('IncludeNull', $Options); if ($IncludeNull === TRUE) { $Return .= '<option value="">' . T('Select a category...') . '</option>'; } elseif (is_array($IncludeNull)) { $Return .= "<option value=\"{$IncludeNull[0]}\">{$IncludeNull[1]}</option>\n"; } elseif ($IncludeNull) { $Return .= "<option value=\"\">{$IncludeNull}</option>\n"; } elseif (!$HasValue) { $Return .= '<option value=""></option>'; } // Show root categories as headings (ie. you can't post in them)? $DoHeadings = GetValue('Headings', $Options, C('Vanilla.Categories.DoHeadings')); // If making headings disabled and there was no default value for // selection, make sure to select the first non-disabled value, or the // browser will auto-select the first disabled option. $ForceCleanSelection = $DoHeadings && !$HasValue && !$IncludeNull; // Write out the category options if (is_array($SafeCategoryData)) { foreach ($SafeCategoryData as $CategoryID => $Category) { $Depth = GetValue('Depth', $Category, 0); $Disabled = $Depth == 1 && $DoHeadings; $Selected = in_array($CategoryID, $Value) && $HasValue; if ($ForceCleanSelection && $Depth > 1) { $Selected = TRUE; $ForceCleanSelection = FALSE; } $Return .= '<option value="' . $CategoryID . '"'; if ($Disabled) { $Return .= ' disabled="disabled"'; } else { if ($Selected) { $Return .= ' selected="selected"'; } } // only allow selection if NOT disabled $Name = htmlspecialchars(GetValue('Name', $Category, 'Blank Category Name')); if ($Depth > 1) { $Name = str_repeat(' ', 4 * ($Depth - 1)) . $Name; // $Name = str_replace(' ', ' ', $Name); } $Return .= '>' . $Name . "</option>\n"; } } return $Return . '</select>'; }
/** * 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('Announcements', 'Announcements_' . GetValue('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(); }