diff --git a/DebugPlugin/controllers/api/PermissionApiController.php b/DebugPlugin/controllers/api/PermissionApiController.php new file mode 100644 index 0000000..dd47f1d --- /dev/null +++ b/DebugPlugin/controllers/api/PermissionApiController.php @@ -0,0 +1,67 @@ +permission('Garden.Settings.Manage'); + if (!Gdn::userModel()->getID($userID)) { + throw notFoundException('User'); + } + $userPermissions = Gdn::userModel()->getPermissions($userID); + $data = [ + 'userPermissions' => $userPermissions, + ]; + return $data; + } + + /** + * Get user permissions for a category + * @param $userID + * @param $categoryID + * @return Data + * @throws \Garden\Web\Exception\HttpException + * @throws \Vanilla\Exception\PermissionException + */ + public function get($userID, $categoryID) { + $this->permission('Garden.Settings.Manage'); + + if (!Gdn::userModel()->getID($userID)) { + throw notFoundException('User'); + } + + $category = CategoryModel::categories($categoryID); + if (!$category) { + throw notFoundException('Category'); + } + $groupID = val('GroupID', $category, null); + $data = [ + 'GroupID' => $groupID, + 'PermsGroupView' => $groupID? GroupModel::getGroupRoleFor($userID, $groupID) : null, + 'PermsDiscussionsView' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.View', true, $userID), + 'PermsDiscussionsAdd' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.Add', true, $userID), + 'PermsDiscussionsEdit' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.Edit', true, $userID), + 'PermsCommentsAdd' => CategoryModel::checkPermission($category, 'Vanilla.Comments.Add', true, $userID), + 'PermsDiscussionsUploads' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.Uploads', true, $userID), + 'PermsCommentsUploads' => CategoryModel::checkPermission($category, 'Vanilla.Comments.Uploads', true, $userID) + ]; + return $data; + } +} \ No newline at end of file diff --git a/DebugPlugin/openapi/permission.yml b/DebugPlugin/openapi/permission.yml new file mode 100644 index 0000000..63c826a --- /dev/null +++ b/DebugPlugin/openapi/permission.yml @@ -0,0 +1,52 @@ +openapi: 3.0.2 +info: Vanilla Permission API +paths: + /permission/{userID}/{categoryID}: + get: + parameters: + - description: UserID to check. + in: path + name: userID + schema: + type: integer + - description: CategoryID to check. + in: path + name: categoryID + schema: + type: integer + responses: + '200': + content: + 'application/json': + schema: + items: + $ref: '#/components/schemas/Records' + type: array + description: Success + tags: + - Data + summary: List records. + /permission/{userID}: + get: + parameters: + - description: UserID to check. + in: path + name: userID + schema: + type: integer + responses: + '200': + content: + 'application/json': + schema: + items: + $ref: '#/components/schemas/Records' + type: array + description: Success + tags: + - Data + summary: List records. +components: + schemas: + Records: + type: object \ No newline at end of file diff --git a/ReplyTo/class.replyto.plugin.php b/ReplyTo/class.replyto.plugin.php index fd402a3..d4d605d 100644 --- a/ReplyTo/class.replyto.plugin.php +++ b/ReplyTo/class.replyto.plugin.php @@ -9,7 +9,6 @@ class ReplyToPlugin extends Gdn_Plugin { const QUERY_PARAMETER_VIEW='view'; const VIEW_FLAT = 'flat'; - const VIEW_TREE = 'tree'; const VIEW_THREADED = 'threaded'; private $replyToModel; @@ -67,12 +66,22 @@ public function postController_render_before($sender) { $this->prepareController($sender); } + /** + * Add View Mode before rendering comments + * @param $sender + * @param $args + */ + public function base_beforeCommentsRender_handler($sender, $args) { + $viewMode = self::getViewMode(); + $sender->setData('ViewMode', $viewMode); + } + /** * Render View options for a discussion * @param $sender * @param $args */ - public function base_Replies_handler($sender, $args){ + public function base_InlineDiscussionOptionsLeft_handler($sender, $args){ $discussion = $sender->data('Discussion'); if (!$discussion) { return; @@ -83,13 +92,13 @@ public function base_Replies_handler($sender, $args){ } $discussionUrl = discussionUrl($discussion, '', '/'); - $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT); + $viewMode = self::getViewMode(); - echo '
View: '; - echo anchor('Flat', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_FLAT, $viewMode == self::VIEW_FLAT?'Active':'').'  |  '; - echo anchor('Threaded', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_THREADED, $viewMode == self::VIEW_THREADED?'Active':'').'  |  '; - echo anchor('Tree', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_TREE, $viewMode == self::VIEW_TREE?'Active':''); - echo '
'; + echo ''; + echo 'View: '; + echo anchor('Threaded', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_THREADED, $viewMode == self::VIEW_THREADED?'ReplyViewOptionLink Active':'ReplyViewOptionLink').'  |  '; + echo anchor('Flat', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_FLAT, $viewMode == self::VIEW_FLAT?'ReplyViewOptionLink Active':'ReplyViewOptionLink'); + echo ''; } /** @@ -98,9 +107,9 @@ public function base_Replies_handler($sender, $args){ * @param $sender */ public function commentModel_afterConstruct_handler(&$sender) { - self::log('commentModel_afterConstruct_handler', ['path'=> Gdn::request()->pathAndQuery()]); - $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT); - if($viewMode == self::VIEW_TREE || $viewMode == self::VIEW_THREADED) { + $viewMode = self::getViewMode(); + + if($viewMode == self::VIEW_THREADED) { $sender->orderBy(array('TreeLeft asc', 'DateInserted asc')); } } @@ -135,13 +144,8 @@ public function commentModel_deleteComment_handler(&$Sender) { } public function discussionController_BeforeCalculatingOffsetLimit_handler($sender, $args) { - if (!Gdn::session()->isValid()) { - return; - } - $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW); - if(!$viewMode) { - return; - } + $viewMode = self::getViewMode(); + // $offsetProvided = $args['OffsetProvided']; $discussion = $args['Discussion']; $offset = & $args['Offset']; $limit = & $args['Limit']; @@ -152,7 +156,6 @@ public function discussionController_BeforeCalculatingOffsetLimit_handler($sende } if($viewMode === self::VIEW_FLAT) { - $offset = 0; $enableAutoOffset = false; } else { // Show all comment on one offset for Tree/Threaded View @@ -176,7 +179,7 @@ public function discussionController_beforeDiscussionRender_handler($sender, $ar return; } - $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT); + $viewMode = self::getViewMode(); if($viewMode == self::VIEW_FLAT) { return; } @@ -196,32 +199,30 @@ public function base_commentOptions_handler($sender, $args) { return; } $discussion = $sender->data('Discussion'); - $isClosed = ((int)$discussion->Closed) == 1; - if ($isClosed) { - return; - } //Check permission - if (isset($discussion->PermissionCategoryID)) { - $CategoryID = val('PermissionCategoryID', $discussion); - } else { - $CategoryID = $discussion->CategoryID; - } + $CategoryID = val('PermissionCategoryID', $discussion)? val('PermissionCategoryID', $discussion):val('CategoryID', $discussion); + $userCanClose = CategoryModel::checkPermission($CategoryID, 'Vanilla.Discussions.Close'); + $userCanComment = CategoryModel::checkPermission($CategoryID, 'Vanilla.Comments.Add'); - // Can the user comment on this category, and is the discussion open for comments? - if (!Gdn::Session()->CheckPermission('Vanilla.Comments.Add', TRUE, 'Category', $CategoryID)) { + $canAddComment = ($discussion->Closed == '1' && $userCanClose) || ($discussion->Closed == '0' && $userCanComment); + if (!$canAddComment) { return; } + // Can the user comment on this category, and is the discussion open for comments? + // if (!Gdn::Session()->CheckPermission('Vanilla.Comments.Add', TRUE, 'Category', $CategoryID)) { + // return; + // } $options = &$args['CommentOptions']; - $comment = &$args['Comment']; + $comment = $args['Comment']; $options['ReplyToComment'] = [ 'Label' => t('Reply'), 'Url' => '/?ParentCommentID='.$comment->CommentID, 'Class' => 'ReplyComment' ]; - $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT); + $viewMode = self::getViewMode(); foreach ($options as $key => $value) { $currentUrl = $options[$key]['Url']; if (strpos($currentUrl, '?') !== false ) { @@ -236,26 +237,70 @@ public function base_commentOptions_handler($sender, $args) { } } + /** + * Add 'Reply' option to discussion. + * + * @param Gdn_Controller $sender + * @param array $args + */ + public function base_inlineDiscussionOptions_handler($sender, $args) { + $discussion = $args['Discussion']; + if (!$discussion) { + return; + } + + if (!Gdn::session()->UserID) { + return; + } + + //Check permission + $CategoryID = val('PermissionCategoryID', $discussion)? val('PermissionCategoryID', $discussion):val('CategoryID', $discussion); + $userCanClose = CategoryModel::checkPermission($CategoryID, 'Vanilla.Discussions.Close'); + $userCanComment = CategoryModel::checkPermission($CategoryID, 'Vanilla.Comments.Add'); + + // See the 'writeCommentForm' method vanilla/applications/vanilla/views/discussion/helper_functions.php + $canAddComment = ($discussion->Closed == '1' && $userCanClose) || ($discussion->Closed == '0' && $userCanComment); + if (!$canAddComment) { + return; + } + + // DropdownModule options + $options = & $args['DiscussionOptions']; + $options->addLink('Reply', url("/", true), 'reply', 'ReplyComment'); + } + /** * Insert the indentation classes into the comment. + * All rendering options should be set before displaying comments * @param $sender * @param $args */ public function base_beforeCommentDisplay_handler($sender, $args) { - ReplyToPlugin::log('base_beforeCommentDisplay_handler', []); - - $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT); - if($viewMode == self::VIEW_FLAT) { - return; - } if($sender->deliveryType() != DELIVERY_TYPE_ALL) { - ReplyToPlugin::log('base_beforeCommentDisplay_handler', ['']); - $this->buildCommentReplyToCssClasses($sender); + // Ajax request to post new comments or update comments + if(isset($_SERVER['HTTP_REFERER'])) { + $previous = $_SERVER['HTTP_REFERER']; + $query = parse_url($previous, PHP_URL_QUERY); + parse_str($query, $params); + $viewMode = $params['view']; + if(!$viewMode) { + $viewMode = self::isPagingUrl($previous) ? self::VIEW_FLAT : self::VIEW_THREADED; + } + $sender->setData('ViewMode', $viewMode); + if($viewMode == self::VIEW_THREADED) { + $this->buildCommentReplyToCssClasses($sender); + } + } + } else { + $viewMode = self::getViewMode(); + if($viewMode == self::VIEW_THREADED) { + $this->buildCommentReplyToCssClasses($sender); + } } $comment = &$args['Comment']; $cssClass = &$args['CssClass']; - $displayBody = &$args['DisplayBody']; - $displayBody = $viewMode == self::VIEW_FLAT || $viewMode == self::VIEW_THREADED; + // $displayBody = &$args['DisplayBody']; + // $displayBody = $viewMode == self::VIEW_FLAT || $viewMode == self::VIEW_THREADED; $cssClass .= (!empty($comment->ReplyToClass)? ' ' . $comment->ReplyToClass : ''); } @@ -330,6 +375,19 @@ private function buildCommentReplyToCssClasses(&$sender){ } } + private static function isPagingUrl($url) { + return preg_match('/\/p\d+$/', $url); + } + + private static function getViewMode(){ + $viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW); + if(!$viewMode) { + $viewMode = self::isPagingUrl(Gdn::request()->path())? self::VIEW_FLAT: self::VIEW_THREADED; + } + + return $viewMode; + } + public static function log($message, $data) { if (c('Debug')) { Logger::event( diff --git a/ReplyTo/design/replyto.css b/ReplyTo/design/replyto.css index 81027a2..bda51b1 100644 --- a/ReplyTo/design/replyto.css +++ b/ReplyTo/design/replyto.css @@ -1,12 +1,15 @@ .ReplyViewOptions { + font-family: roboto, Segoe UI, Helvetica Neue, Helvetica, Raleway, Arial, sans-serif; display: inline-block; line-height: 1.5; } +.MessageList .ItemDiscussion .Item-Body .Controls a.ReplyViewOptionLink, .ReplyViewOptions .ReplyViewOptionLink { + color: #137d60; +} -.ReplyViewOptions a.Active { - color: #696969; - font-weight: 800; +.MessageList .ItemDiscussion .Item-Body .Controls a.ReplyViewOptionLink.Active, .ReplyViewOptions .ReplyViewOptionLink.Active { + color: #555555; } /* Indent comments according to their depth. @@ -53,8 +56,103 @@ li.Item.ReplyToDepth-9 { margin-left: 14em; } -/* Stop indenting any further after 10 levels */ -li.Item.ReplyToDepth-10plus { +li.Item.ReplyToDepth-10 { margin-left: 15em; } +li.Item.ReplyToDepth-11 { + margin-left: 16em; +} + +li.Item.ReplyToDepth-12 { + margin-left: 17em; +} + +li.Item.ReplyToDepth-13 { + margin-left: 18em; +} + +li.Item.ReplyToDepth-14 { + margin-left: 19em; +} + +li.Item.ReplyToDepth-15 { + margin-left: 20em; +} + + +/* Stop indenting any further after 15 levels */ +li.Item.ReplyToDepth-16plus { + margin-left: 20em; +} + +@media screen and (max-width: 960px) { + li.Item.ReplyToDepth-1 { + margin-left: 1em; + } + + li.Item.ReplyToDepth-2 { + margin-left: 1.25em; + } + + li.Item.ReplyToDepth-3 { + margin-left: 1.5em; + } + + li.Item.ReplyToDepth-4 { + margin-left: 1.75em; + } + + li.Item.ReplyToDepth-5 { + margin-left: 2em; + } + + /* Reduce the indenting to single ems after 5 levels */ + + li.Item.ReplyToDepth-6 { + margin-left: 2.25em; + } + + li.Item.ReplyToDepth-7 { + margin-left: 2.5em; + } + + li.Item.ReplyToDepth-8 { + margin-left: 2.75em; + } + + li.Item.ReplyToDepth-9 { + margin-left: 3em; + } + + li.Item.ReplyToDepth-10 { + margin-left: 3.25em; + } + + li.Item.ReplyToDepth-11 { + margin-left: 3.5em; + } + + li.Item.ReplyToDepth-12 { + margin-left: 3.75em; + } + + li.Item.ReplyToDepth-13 { + margin-left: 4em; + } + + li.Item.ReplyToDepth-14 { + margin-left: 4.25em; + } + + li.Item.ReplyToDepth-15 { + margin-left: 4.5em; + } + + + /* Stop indenting any further after 15 levels */ + li.Item.ReplyToDepth-16plus { + margin-left: 5em; + } + +} \ No newline at end of file diff --git a/ReplyTo/js/replyto.js b/ReplyTo/js/replyto.js index 43a48da..5ed35b1 100644 --- a/ReplyTo/js/replyto.js +++ b/ReplyTo/js/replyto.js @@ -7,7 +7,7 @@ jQuery(document).ready(function($) { //If view is not flat, reload a page to rebuild a tree function reloadPage() { var currentView = param(window.location.href, 'view'); - return (currentView == 'tree' || currentView == 'threaded'); + return currentView == 'threaded'; } $(document).on('click','a.ReplyComment', function(ev) { @@ -15,12 +15,22 @@ jQuery(document).ready(function($) { var parent = $(btn).parents('.MainContent'); var commentContainer = $(parent).find('div.CommentForm'); var header = $(commentContainer).find('h2.H'); - $(header).text('Reply to a comment'); // Form var form = $(commentContainer).find('form#Form_Comment'); var href = $(btn).attr('href'); var commentID = param(href,'ParentCommentID'); var hiddenField = $(form).find(':input[type="hidden"]#Form_ParentCommentID') + + var author = ''; + if(commentID == '') { // No Parent Comment, Reply to Discussion + commentID = 0; + author = $(btn).parents('.Discussion').find('.Item-Header.DiscussionHeader .Author .topcoderHandle').text(); + } else { + author = $(btn).parents('.Comment').find('.Item-Header.CommentHeader .Author .topcoderHandle').text(); + } + + $(header).text('Replying to '+ author); + if($(hiddenField).length == 0) { var el = ''; $(form).append(el); @@ -30,15 +40,17 @@ jQuery(document).ready(function($) { var formButtons = $(form).find('.Buttons'); var postCommentButton = $(form).find('.CommentButton'); postCommentButton.val('Post Reply'); - var backButton = $(formButtons).find('span.Back'); + var backButton = $(formButtons).find('.Button.PreviewButton'); var cancelReplyButton = $(formButtons).find('span.Reply'); if($(cancelReplyButton).length == 0) { var cancelReplyButton = 'Cancel Reply'; - $(cancelReplyButton).insertAfter(backButton); + $(cancelReplyButton).insertBefore(backButton); } else { $(cancelReplyButton).show(); } - $(form)[0].scrollIntoView(); + + var ScrollY = $(form).offset().top - 100; + $('html,body').animate({scrollTop: ScrollY}, 800); return false; }); diff --git a/ReplyTo/models/class.replytomodel.php b/ReplyTo/models/class.replytomodel.php index d1712ec..2196267 100644 --- a/ReplyTo/models/class.replytomodel.php +++ b/ReplyTo/models/class.replytomodel.php @@ -293,7 +293,7 @@ public function depthClasses($depth) { // Add some further classes for blocks of each 5 depth levels, so limits can // be set on the way depth is formatted. - for ($i = 1; $i <= 100; $i += 5) { + for ($i = 1; $i <= 20; $i += 5) { if ($depth >= $i) { $Class .= ' ' . $Prefix . '-' . $i . 'plus'; } else { diff --git a/Topcoder/class.topcoder.plugin.php b/Topcoder/class.topcoder.plugin.php index baf8093..0d11db4 100644 --- a/Topcoder/class.topcoder.plugin.php +++ b/Topcoder/class.topcoder.plugin.php @@ -827,6 +827,12 @@ public function userController_UserCell_handler($sender, $args) { GroupID; } } - } else if($args['Controller'] instanceof Groupcontroller) { + } else if($args['Controller'] instanceof GroupController) { if (array_key_exists('groupid', $methodArgs)) { $groupID = (int) $methodArgs['groupid']; } + } else if($args['Controller'] instanceof PostController) { + if (array_key_exists('discussionid', $methodArgs)) { + $discussionID = $methodArgs['discussionid']; + $discussionModel = new DiscussionModel(); + $discussion = $discussionModel->getID($discussionID); + if($discussion->CategoryID){ + $categoryModel = new CategoryModel(); + $category = $categoryModel->getID($discussion->CategoryID); + $groupID = $category->GroupID; + } + } else if (array_key_exists('commentid', $methodArgs)) { + $commentID = $methodArgs['commentid']; + $commentModel = new CommentModel(); + $comment = $commentModel->getID($commentID); + $discussionModel = new DiscussionModel(); + $discussion = $discussionModel->getID($comment->DiscussionID); + if($discussion->CategoryID){ + $categoryModel = new CategoryModel(); + $category = $categoryModel->getID($discussion->CategoryID); + $groupID = $category->GroupID; + } + } } - //} else if($args instanceof CategoriesController) { - //TODO - //} else if ( $args instanceof CategoryController) { - //TODO - //} + if($groupID && $groupID > 0) { $groupModel = new GroupModel(); $group = $groupModel->getByGroupID($groupID); @@ -2011,7 +2035,7 @@ function userPhoto($user, $options = []) { $userLink = userUrl($fullUser); $topcoderProfile = TopcoderPlugin::getTopcoderUser($user); - if($topcoderProfile !== null) { + if($topcoderProfile) { $attributes['target'] = '_blank'; $userLink = TopcoderPlugin::getTopcoderProfileUrl($name); $topcoderPhotoUrl = val('PhotoUrl', $topcoderProfile); @@ -2020,12 +2044,14 @@ function userPhoto($user, $options = []) { } } + $isTopcoderAdmin = val('IsAdmin', $topcoderProfile); $photoUrl = isset($photoUrl) && !empty(trim($photoUrl)) ? $photoUrl: UserModel::getDefaultAvatarUrl(); $href = (val('NoLink', $options)) ? '' : ' href="'.url($userLink).'"'; Gdn::controller()->EventArguments['User'] = $user; Gdn::controller()->EventArguments['Title'] =& $title; Gdn::controller()->EventArguments['Attributes'] =& $attributes; + Gdn::controller()->EventArguments['IsTopcoderAdmin'] =$isTopcoderAdmin; Gdn::controller()->fireEvent('UserPhoto'); return '' @@ -2125,6 +2151,7 @@ function userAnchor($user, $cssClass = null, $options = null) { } Gdn::controller()->EventArguments['User'] = $user; + Gdn::controller()->EventArguments['IsTopcoderAdmin'] =$isTopcoderAdmin; Gdn::controller()->EventArguments['Text'] =& $text; Gdn::controller()->EventArguments['Attributes'] =& $attributes; Gdn::controller()->fireEvent('UserAnchor'); diff --git a/Topcoder/design/topcoder.css b/Topcoder/design/topcoder.css index 8b6e4b0..e91081c 100644 --- a/Topcoder/design/topcoder.css +++ b/Topcoder/design/topcoder.css @@ -42,10 +42,10 @@ a.coderRatingRed:hover, a.coderRatingYellow:hover, a.coderRatingBlue:hover, a.co text-decoration: none !important; } .coderRatingRed:hover, .coderRatingYellow:hover, .coderRatingBlue:hover, .coderRatingGreen:hover, .coderRatingGrey:hover, .coderRatingNone:hover, .topcoderAdmin:hover { - text-decoration: underline !important; + text-decoration: none !important; } .coderRatingRed:active, .coderRatingYellow:active, .coderRatingBlue:active, .coderRatingGreen:active, .coderRatingGrey:active, .coderRatingNone:active, .topcoderAdmin:active { - text-decoration: underline !important; + text-decoration: none !important; } /* Red */ @@ -108,6 +108,18 @@ a.coderRatingRed:hover, a.coderRatingYellow:hover, a.coderRatingBlue:hover, a.co .Flyout.Flyout a.topcoderAdmin, .Flyout.Flyout a.topcoderAdmin:link,.Flyout.Flyout a.topcoderAdmin:visited, .Flyout.Flyout a.topcoderAdmin:hover, .Flyout.Flyout a.topcoderAdmin:active, .userContent p a.topcoderAdmin, .userContent p a.topcoderAdmin:link, .userContent p a.topcoderAdmin:visited, .userContent p a.topcoderAdmin:hover, .userContent p a.topcoderAdmin:active { color: #ff9900 !important; } +a:hover span.topcoderHandle{ + text-decoration: underline; +} + +a span.challengeRoles { + color: black; +} + +a:hover span.challengeRoles { + text-decoration: underline; +} + /* Search breadcrumbs css style */ .Media-Location .Breadcrumbs { diff --git a/Topcoder/views/modules/topcoderme.php b/Topcoder/views/modules/topcoderme.php index 1123f4c..c869990 100644 --- a/Topcoder/views/modules/topcoderme.php +++ b/Topcoder/views/modules/topcoderme.php @@ -108,7 +108,8 @@ // $dropdown->addLinkIf(hasViewProfile(Gdn::session()->UserID), t('View Profile'), '/profile', 'profile.view', '', [], $editModifiers); $preferencesModifiers['listItemCssClasses'] = ['MeButtonMenuItem', 'MeButtonSettingsItem']; - $dropdown->addLinkIf(hasEditProfile(Gdn::session()->UserID), 'Settings', '/profile/preferences', 'profile.preferences', '', [], $preferencesModifiers); + // $dropdown->addLinkIf(hasEditProfile(Gdn::session()->UserID), 'Settings', '/profile/preferences', 'profile.preferences', '', [], $preferencesModifiers); + $dropdown->addLink('Settings', 'https://www.topcoder.com/settings/profile', 'profile.preferences', '', [], $preferencesModifiers); // $applicantModifiers = $ApplicantCount > 0 ? ['badge' => $ApplicantCount] : []; // $applicantModifiers['listItemCssClasses'] = ['link-applicants'];