From dbe4b711fe88f0aa98888606687632463dd526d6 Mon Sep 17 00:00:00 2001 From: Bogdanova Olga Date: Sun, 15 Nov 2020 21:35:57 +0300 Subject: [PATCH 1/2] Fixed issues-178 with permissions --- addon.json | 2 + class.groups.plugin.php | 161 +++++++++------------- controllers/api/GroupsApiController.php | 5 +- controllers/class.groupcontroller.php | 11 +- models/class.groupmodel.php | 170 +++++++++++++++--------- structure.php | 120 +++-------------- views/group/helper_functions.php | 11 +- views/group/index.php | 2 + views/groups/index.php | 3 + 9 files changed, 205 insertions(+), 280 deletions(-) diff --git a/addon.json b/addon.json index 3e3602a..11dd2a8 100644 --- a/addon.json +++ b/addon.json @@ -12,6 +12,8 @@ "settingsPermission": "Garden.Settings.Manage", "registerPermissions": [ "Groups.Group.Add", + "Groups.Group.Edit", + "Groups.Group.Delete", "Groups.Moderation.Manage", "Groups.EmailInvitations.Add", "Groups.Category.Manage" diff --git a/class.groups.plugin.php b/class.groups.plugin.php index 6162773..993839c 100644 --- a/class.groups.plugin.php +++ b/class.groups.plugin.php @@ -17,6 +17,8 @@ class GroupsPlugin extends Gdn_Plugin { const GROUPS_ROUTE = '/groups'; const GROUP_ROUTE = '/group/'; const GROUPS_GROUP_ADD_PERMISSION = 'Groups.Group.Add'; + const GROUPS_GROUP_EDIT_PERMISSION = 'Groups.Group.Edit'; + const GROUPS_GROUP_DELETE_PERMISSION = 'Groups.Group.Delete'; const GROUPS_CATEGORY_MANAGE_PERMISSION = 'Groups.Category.Manage'; const GROUPS_MODERATION_MANAGE_PERMISSION = 'Groups.Moderation.Manage'; const GROUPS_EMAIL_INVITATIONS_PERMISSION = 'Groups.EmailInvitations.Add'; @@ -155,25 +157,43 @@ public function onDisable() { // nothing } + public function categoryModel_beforeSaveCategory_handler($sender, $args){ + + } + public function base_render_before($sender) { $sender->addJsFile('vendors/prettify/prettify.js', 'plugins/Groups'); $sender->addJsFile('dashboard.js', 'plugins/Groups'); - if(inSection('CategoryList')) { - $categoryTree = $sender->data('CategoryTree'); - $selectedCategory = $sender->data('Category'); - if($categoryTree) { - $displayedCategoryTree = $this->groupModel->checkGroupCategoryPermissions($categoryTree); - $sender->setData('CategoryTree', $displayedCategoryTree); - } + $categoryModel = new CategoryModel(); + + self::log('a list of IDs of categories visible to the current user', ['visibleCategories' => $categoryModel->getVisibleCategories([])]); - if($selectedCategory) { - $displayedCategory = $this->groupModel->checkGroupCategoryPermissions($selectedCategory); - $sender->setData('Category', $displayedCategory); - } - } } + public function base_groupOptionsDropdown_handler($sender, $args){ + $group = $args['Group']; + $currentTopcoderProjectRoles = $sender->Data['ChallengeCurrentUserProjectRoles']; + $groupModel = new GroupModel(); + $groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); + $groupID = $group->GroupID; + $canEdit = $groupModel->canEdit($group) ; + $canDelete = $groupModel->canDelete($group) ; + $canLeave = $groupModel->canLeave($group); + $canInviteMember = $groupModel->canInviteNewMember($group); + $canManageMembers = $groupModel->canManageMembers($group); + $canManageCategories = $groupModel->canManageCategories($group); + $canFollow = $groupModel->canFollowGroup($group); + $canWatch = $groupModel->canWatchGroup($group); + $hasFollowed = $groupModel->hasFollowedGroup($group); + $hasWatched = $groupModel->hasWatchedGroup($group); + + // self::log('base_groupOptionsDropdown_handler', ['Group' => $group->GroupID, + // 'currentUserTopcoderProjectRoles' =>$currentTopcoderProjectRoles, + // 'canDelete' => $canDelete, 'canEdit' => $canEdit, 'canLeave' => $canLeave, + // 'canInviteMember' =>$canInviteMember, 'canManageMembers' => $canManageMembers, 'canManageCategories ' => + // $canManageCategories, 'canFollow' => $canFollow ]); + } /** * Load CSS into head for the plugin @@ -198,82 +218,12 @@ public function settingsController_groups_create($sender) { $cf->renderAll(); } - private function discussionModelWhere($requestPath, $args){ - GroupsPlugin::log('discussionModelWhere:enter', ['Wheres'=> $args['Wheres']]); - $wheres = []; - if(array_key_exists('Wheres', $args)) { - $wheres = &$args['Wheres']; - } - if(strpos($requestPath, 'discussions/mine') === 0) { - // show all my discussions - } else if (strpos($requestPath, 'discussions/bookmarked') === 0) { - // show all bookmarked by default - } else if (strpos($requestPath, 'discussions') === 0) { - $wheres['d.GroupID'] = ['is null']; - } else if (strpos($requestPath, 'categories') === 0) { - //checkPermissions - $groupModel = new GroupModel(); - $userGroups = $groupModel->memberOf(Gdn::session()->UserID); - $publicGroupIDs = $groupModel->getAllPublicGroupIDs(); - $userGroupsIDs = array(); - foreach ($userGroups as $userGroup) { - array_push($userGroupsIDs, $userGroup->GroupID); - } - $showGroupsIDs = array_merge($userGroupsIDs, $publicGroupIDs); - self::log('discussionModelWhere', ['userGroups' => $userGroups, 'publicGroupsIDs'=> $publicGroupIDs, 'showGroupIDs' => $showGroupsIDs]); - $wheres['d.GroupID'] = $showGroupsIDs; - $wheres['Groups'] = 'all'; - } - - GroupsPlugin::log('discussionModelWhere:exit', ['Updated Wheres'=> $wheres]); - - } - - public function discussionModel_beforeGet_handler($sender, $args) { - GroupsPlugin::log('discussionModel_beforeGet_handler', []); - $this->discussionModelWhere(Gdn::request()->path(), $args); - } - - public function discussionModel_beforeGetCount_handler($sender, $args){ - GroupsPlugin::log('discussionModel_beforeGetCount_handler'); - $this->discussionModelWhere(Gdn::request()->path(), $args); - } - - public function discussionModel_beforeGetAnnouncements_handler($sender, $args){ - GroupsPlugin::log('discussionModel_beforeGetAnnouncements_handler'); - //FIX: it throws exceptions - // $this->discussionModelWhere(Gdn::request()->path(), $args); - } - - /** - * Show categories based on group membership - * @param $sender - * @param $args - */ - public function base_beforeCategoryDropDown_handler($sender, $args) { - self::log('base_beforeCategoryDropDown_hander', ['args' => $args]); - $options = &$args['Options']; - $categoryData = val('CategoryData', $options); - - // Grab the category data. - if (!$categoryData) { - $categoryData = CategoryModel::getByPermission( - 'Discussions.Add', - null, - val('Filter', $options, ['Archived' => 0]), - val('PermFilter', $options, []) - ); - - $displayedCategories = $this->groupModel->checkGroupCategoryPermissions($categoryData); - $options['CategoryData'] = $displayedCategories; - return; - } - } - public function discussionController_render_before($sender, $args) { $Discussion = $sender->data('Discussion'); if($Discussion && $Discussion->GroupID != null) { $groupModel = new GroupModel(); + $currentTopcoderProjectRoles = $sender->Data['ChallengeCurrentUserProjectRoles']; + $groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); $Group = $groupModel->getByGroupID($Discussion->GroupID); if (!$groupModel->canView($Group)) { throw permissionException(); @@ -300,11 +250,13 @@ public function base_BeforeCommentForm_handler($sender, $args) { */ public function base_discussionOptionsDropdown_handler($sender, $args){ $Discussion = $args['Discussion']; + $currentTopcoderProjectRoles = $sender->Data['ChallengeCurrentUserProjectRoles']; if($Discussion) { $groupModel = new GroupModel(); + $groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); + $canView = $groupModel->canView($Discussion); $canEdit = $groupModel->canEditDiscussion($Discussion); $canDelete = $groupModel->canDeleteDiscussion($Discussion); - $canDismiss = $groupModel->canDismissDiscussion($Discussion); $canAnnounce = $groupModel->canAnnounceDiscussion($Discussion); $canSink = $groupModel->canSinkDiscussion($Discussion); @@ -346,8 +298,9 @@ public function base_discussionOptionsDropdown_handler($sender, $args){ } self::log('discussionController_discussionOptionsDropdown_handler', ['Discussion' => $Discussion->DiscussionID, - 'canDelete' => $canDelete, 'canEdit' => $canEdit, 'canDiscmiss' => $canDismiss, - 'canAnnounce' =>$canAnnounce, 'canSink' => $canSink, 'canMove' => $canMove, 'canFetch' => $canRefetch ]); + 'currentUserTopcoderProjectRoles' =>$currentTopcoderProjectRoles, 'canView' => $canView, + 'canDelete' => $canDelete, 'canEdit' => $canEdit, 'canDismiss' => $canDismiss, + 'canAnnounce' =>$canAnnounce, 'canSink' => $canSink, 'canMove' => $canMove, 'canReFetch' => $canRefetch ]); } } @@ -571,9 +524,9 @@ public function base_userAnchor_handler($sender, $args){ if($sender instanceof DiscussionController || $sender instanceof GroupController) { $user = $args['User']; $anchorText = &$args['Text']; - $resources = $sender->data('Resources'); - $roleResources = $sender->data('RoleResources'); - $anchorText = $anchorText . $this->getTopcoderRoles($user, $resources, $roleResources); + $resources = $sender->data('ChallengeResources'); + $roleResources = $sender->data('ChallengeRoleResources'); + $anchorText = $anchorText . $this->topcoderProjectRolesText($user, $resources, $roleResources); } } @@ -586,16 +539,29 @@ public function base_userPhoto_handler($sender, $args){ if($sender instanceof DiscussionController || $sender instanceof GroupController) { $user = $args['User']; $anchorText = &$args['Title']; - $resources = $sender->data('Resources'); - $roleResources = $sender->data('RoleResources'); - $anchorText = $anchorText . $this->getTopcoderRoles($user, $resources, $roleResources); + $resources = $sender->data('ChallengeResources'); + $roleResources = $sender->data('ChallengeRoleResources'); + $anchorText = $anchorText . $this->topcoderProjectRolesText($user, $resources, $roleResources); } } - private function getTopcoderRoles($user, $resources = null, $roleResources = null) { + private function topcoderProjectRolesText($user, $resources = null, $roleResources = null) { + $roles = $this->getTopcoderProjectRoles($user, $resources, $roleResources); + return count($roles) > 0 ? '(' . implode(', ', $roles) . ')' : ''; + + } + + /** + * Get a list of Topcoder Project Roles for an user + * @param $user object User + * @param array $resources + * @param array $roleResources + * @return array + */ + private function getTopcoderProjectRoles($user, $resources = null, $roleResources = null) { $topcoderUsername = val('Name', $user, t('Unknown')); + $roles = []; if (isset($resources) && isset($roleResources)) { - $roles = []; $allResourcesByMember = array_filter($resources, function ($k) use ($topcoderUsername) { return $k->memberHandle == $topcoderUsername; }); @@ -605,11 +571,8 @@ private function getTopcoderRoles($user, $resources = null, $roleResources = nul }); array_push($roles, reset($roleResource)->name); } - return count($roles) > 0 ? '(' . implode(', ', $roles) . ')' : ''; - } - - return ''; + return $roles; } /** diff --git a/controllers/api/GroupsApiController.php b/controllers/api/GroupsApiController.php index 4a68840..5f8beb2 100644 --- a/controllers/api/GroupsApiController.php +++ b/controllers/api/GroupsApiController.php @@ -203,7 +203,6 @@ public function post_members($id, array $body) { * @throws NotFoundException if the group or user could not be found. */ public function delete_members($id, $userid) { - $this->permission(); $this->idUserIdParamSchema()->setDescription('Remove a member from a group.'); $this->schema([], 'out'); @@ -218,9 +217,9 @@ public function delete_members($id, $userid) { throw new NotFoundException('User'); } - if(!$this->groupModel->canRemoveMember($group)) { + if(!$this->groupModel->canRemoveMember($group)) { throw new ClientException('Don\'t have permissions to remove this member from the group.'); - } + } $this->groupModel->removeMember($group->GroupID, $user->UserID); } diff --git a/controllers/class.groupcontroller.php b/controllers/class.groupcontroller.php index 33a9616..5fa3dbc 100644 --- a/controllers/class.groupcontroller.php +++ b/controllers/class.groupcontroller.php @@ -394,7 +394,7 @@ public function follow($GroupID) { } $this->setData('Group', $Group); if ($this->Form->authenticatedPostBack(true)) { - $this->GroupModel->followGroup($Group); + $this->GroupModel->followGroup($Group, Gdn::session()->UserID); $this->setRedirectTo('group/' . $GroupID); } $this->render(); @@ -412,7 +412,7 @@ public function unfollow($GroupID) { } $this->setData('Group', $Group); if ($this->Form->authenticatedPostBack(true)) { - $this->GroupModel->unfollowGroup($Group); + $this->GroupModel->unfollowGroup($Group, Gdn::session()->UserID); $this->setRedirectTo('group/'.$GroupID); } $this->render(); @@ -430,7 +430,7 @@ public function watch($GroupID) { } $this->setData('Group', $Group); if ($this->Form->authenticatedPostBack(true)) { - $this->GroupModel->watchGroup($Group); + $this->GroupModel->watchGroup($Group, Gdn::session()->UserID); $this->setRedirectTo('group/' . $GroupID); } $this->render(); @@ -449,7 +449,7 @@ public function unwatch($GroupID) { } $this->setData('Group', $Group); if ($this->Form->authenticatedPostBack(true)) { - $this->GroupModel->unwatchGroup($Group); + $this->GroupModel->unwatchGroup($Group, Gdn::session()->UserID); $this->setRedirectTo('group/'.$GroupID); } $this->render(); @@ -742,7 +742,7 @@ public function setDiscussionData($Group,$Announce = '0') { public function category($GroupID) { $Group = $this->findGroup($GroupID); - if(!$this->GroupModel->canManageCategories()) { + if(!$this->GroupModel->canManageCategories($Group)) { throw permissionException(); } @@ -754,6 +754,7 @@ public function category($GroupID) { $this->Form->addHidden('DisplayAs', 'Discussions'); $this->Form->addHidden('AllowFileUploads',1); $this->Form->addHidden('UrlCode',''); + $this->Form->addHidden('GroupID',$GroupID); if ($this->Form->authenticatedPostBack(true)) { $this->Form->setFormValue('UrlCode', $Group->ChallengeID.'-'.$slugify->slugify($this->Form->getValue('Name'), '-')); $newCategoryID = $this->Form->save(); diff --git a/models/class.groupmodel.php b/models/class.groupmodel.php index 6d93241..60dfb50 100644 --- a/models/class.groupmodel.php +++ b/models/class.groupmodel.php @@ -16,6 +16,8 @@ class GroupModel extends Gdn_Model { const ROLE_LEADER = 'leader'; + private $currentUserTopcoderProjectRoles = []; + /** * Class constructor. Defines the related database table name. */ @@ -24,6 +26,10 @@ public function __construct() { $this->fireEvent('Init'); } + public function setCurrentUserTopcoderProjectRoles($topcoderProjectRoles = []){ + $this->currentUserTopcoderProjectRoles = $topcoderProjectRoles; + } + /** * Clear the groups cache. */ @@ -32,37 +38,6 @@ public function clearCache() { Gdn::cache()->remove($key); } - /** - * Define a group. - * - * @param $values - */ - public function define($values) { - if (array_key_exists('GroupID', $values)) { - $groupID = $values['GroupID']; - unset($values['GroupID']); - - $this->SQL->replace('Group', $values, ['GroupID' => $groupID], true); - } else { - // Check to see if there is a group with the same name. - $groupID = $this->SQL->getWhere('Group', ['Name' => $values['Name']])->value('GroupID', null); - - if (is_null($groupID)) { - // Figure out the next group ID. - $maxGroupID = $this->SQL->select('r.GroupID', 'MAX')->from('Group r')->get()->value('GroupID', 0); - $groupID = $maxGroupID + 1; - $values['GroupID'] = $groupID; - - // Insert the group. - $this->SQL->insert('Group', $values); - } else { - // Update the group. - $this->SQL->update('Group', $values, ['GroupID' => $groupID])->put(); - } - } - $this->clearCache(); - } - /** * Get max pages * @return int @@ -336,6 +311,23 @@ public function countMyGroups($where =[]) { return $data === false ? 0 : $data->Count; } + public function checkPermission($userID,$groupID,$permissions = null, $fullMatch = false){ + if(is_array($permissions)) { + return $this->isMemberOfGroup($userID,$groupID) && GDN::session()->checkPermission( + $permissions,$fullMatch); + } else if(is_string($permissions)) { + return $this->isMemberOfGroup($userID,$groupID) && GDN::session()->checkPermission( + [$permissions],$fullMatch); + } + + return $this->isMemberOfGroup($userID,$groupID) || GDN::session()->checkPermission([ + GroupsPlugin::GROUPS_GROUP_ADD_PERMISSION, + GroupsPlugin::GROUPS_CATEGORY_MANAGE_PERMISSION, + GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION, + GroupsPlugin::GROUPS_EMAIL_INVITATIONS_PERMISSION + ],$fullMatch); + } + /** * Join a new member * @param $GroupID @@ -346,6 +338,8 @@ public function join($GroupID, $UserID){ $Fields = ['Role' => GroupModel::ROLE_MEMBER, 'GroupID' => $GroupID,'UserID' => $UserID, 'DateInserted' => Gdn_Format::toDateTime()]; if( $this->SQL->getWhere('UserGroup', ['GroupID' => $GroupID,'UserID' => $UserID])->numRows() == 0) { $this->SQL->insert('UserGroup', $Fields); + $this->followGroup($GroupID, $UserID); + $this->watchGroup($GroupID, $UserID); $this->notifyJoinGroup($GroupID, $UserID); } } @@ -408,7 +402,23 @@ public function setRole($GroupID, $MemberID, $Role){ * @return bool|Gdn_DataSet|object|string|void */ public function removeMember($GroupID, $MemberID){ + $result = $this->unbookmarkGroupDiscussions($GroupID, $MemberID); + $this->unwatchGroup($GroupID, $MemberID); + $this->unfollowGroup($GroupID, $MemberID); return $this->SQL->delete('UserGroup', ['GroupID' => $GroupID, 'UserID' => $MemberID]); + + } + + private function unbookmarkGroupDiscussions($GroupID, $MemberID) { + $this->SQL->update( + 'UserDiscussion ud', + ['Bookmarked'=>0] + )->leftJoin('Discussion d', 'ud.DiscussionID = d.DiscussionID') + ->where('ud.UserID', $MemberID) + ->where('d.GroupID', $GroupID)->put(); + // Update the user's bookmark count + $discussionModel = new DiscussionModel(); + $discussionModel->setUserBookmarkCount($MemberID); } /** @@ -699,7 +709,11 @@ public function hasWatchedGroup($group) { * Follow all group's categories * */ - public function followGroup($group) { + public function followGroup($group, $userID) { + if(is_numeric($group) && $group > 0) { + $group = $this->getByGroupID($group); + } + if($group->ChallengeID) { $categoryModel = new CategoryModel(); $groupCategory = $categoryModel->getByCode($group->ChallengeID); @@ -711,7 +725,7 @@ public function followGroup($group) { } foreach($categoryIDs as $categoryID) { - $categoryModel->follow(Gdn::session()->UserID, $categoryID, true); + $categoryModel->follow($userID, $categoryID, true); } } } @@ -720,7 +734,11 @@ public function followGroup($group) { * Unfollow all group's categories * */ - public function unfollowGroup($group) { + public function unfollowGroup($group, $userID) { + if(is_numeric($group) && $group > 0) { + $group = $this->getByGroupID($group); + } + if($group->ChallengeID) { $categoryModel = new CategoryModel(); $groupCategory = $categoryModel->getByCode($group->ChallengeID); @@ -732,7 +750,7 @@ public function unfollowGroup($group) { } foreach($categoryIDs as $categoryID) { - $categoryModel->follow(Gdn::session()->UserID, $categoryID, false); + $categoryModel->follow($userID, $categoryID, false); } } } @@ -741,7 +759,11 @@ public function unfollowGroup($group) { * Watch all group's categories * @param $group */ - public function watchGroup($group) { + public function watchGroup($group, $userID) { + if(is_numeric($group) && $group > 0) { + $group = $this->getByGroupID($group); + } + if($group->ChallengeID) { $categoryModel = new CategoryModel(); $groupCategory = $categoryModel->getByCode($group->ChallengeID); @@ -751,7 +773,7 @@ public function watchGroup($group) { } else { $categoryIDs = [$groupCategory->CategoryID]; } - $categoryModel->setCategoryMetaData($categoryIDs, Gdn::session()->UserID, 1); + $categoryModel->setCategoryMetaData($categoryIDs, $userID, 1); } } @@ -759,7 +781,11 @@ public function watchGroup($group) { * Unwatch all group's categories * @param $group */ - public function unwatchGroup($group) { + public function unwatchGroup($group, $userID) { + if(is_numeric($group) && $group > 0) { + $group = $this->getByGroupID($group); + } + if($group->ChallengeID) { $categoryModel = new CategoryModel(); $groupCategory = $categoryModel->getByCode($group->ChallengeID); @@ -769,7 +795,7 @@ public function unwatchGroup($group) { } else { $categoryIDs = [$groupCategory->CategoryID]; } - $categoryModel->setCategoryMetaData($categoryIDs, Gdn::session()->UserID, null); + $categoryModel->setCategoryMetaData($categoryIDs, $userID, null); } } @@ -786,12 +812,28 @@ public function canAddGroup() { * Check manage group category permission * */ - public function canManageCategories() { - return Gdn::session()->checkPermission(GroupsPlugin::GROUPS_CATEGORY_MANAGE_PERMISSION); + public function canManageCategories($group) { + return $this->isProjectCopilot() || $this->isProjectManager() || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_CATEGORY_MANAGE_PERMISSION); + } + + private function isProjectCopilot() { + return $this->checkTopcoderProjectRole(RoleModel::ROLE_TOPCODER_PROJECT_COPILOT); + } + + private function isProjectManager(){ + return $this->checkTopcoderProjectRole(RoleModel::ROLE_TOPCODER_PROJECT_MANAGER); + } + + private function isProjectObserver(){ + return $this->checkTopcoderProjectRole(RoleModel::ROLE_TOPCODER_PROJECT_OBSERVER); } + private function checkTopcoderProjectRole($topcoderProjectRole){ + return in_array($topcoderProjectRole, $this->currentUserTopcoderProjectRoles); + } /** + * * Check edit group permission * */ @@ -800,6 +842,8 @@ public function canEdit($group) { $groupRole = val('Role', $result, null); if($groupRole == GroupModel::ROLE_LEADER || Gdn::session()->UserID == $group->OwnerID || + $this->isProjectCopilot() || $this->isProjectManager() || + Gdn::session()->checkPermission(GroupsPlugin::GROUPS_GROUP_EDIT_PERMISSION) || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { return true; } @@ -812,7 +856,7 @@ public function canEdit($group) { * */ public function canDelete($group){ - return Gdn::session()->UserID == $group->OwnerID; + return Gdn::session()->UserID == $group->OwnerID || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_GROUP_DELETE_PERMISSION); } /** @@ -918,7 +962,8 @@ public function canAddDiscussion($group) { public function canAddAnnouncement($group) { $result = $this->getGroupRoleFor(Gdn::session()->UserID, $group->GroupID); $groupRole = val('Role', $result, null); - if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID == $group->OwnerID) { + if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID == $group->OwnerID + || $this->isProjectCopilot() || $this->isProjectManager()) { return true; } return false; @@ -954,7 +999,7 @@ public function canEditDiscussion($discussion) { $result = $this->getGroupRoleFor(Gdn::session()->UserID, $groupID); $groupRole = val('Role', $result, null); - if(($canEditDiscussion && $groupRole && $discussion->InsertUserID == Gdn::session()->UserID) + if(($groupRole && $discussion->InsertUserID == Gdn::session()->UserID) || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { return true; } @@ -983,8 +1028,9 @@ public function canDismissDiscussion($discussion) { $group = $this->getByGroupID($groupID); $result = $this->getGroupRoleFor(Gdn::session()->UserID, $groupID); $groupRole = val('Role', $result, null); - if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID === $group->OwnerID - || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { + if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID === $group->OwnerID || + $this->isProjectCopilot() || $this->isProjectManager() || + Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { return true; } return false; @@ -1008,8 +1054,10 @@ public function canAnnounceDiscussion($discussion) { $group = $this->getByGroupID($groupID); $result = $this->getGroupRoleFor(Gdn::session()->UserID, $groupID); $groupRole = val('Role', $result, null); - if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID === $group->OwnerID - || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { + if($groupRole === GroupModel::ROLE_LEADER || + Gdn::session()->UserID === $group->OwnerID || + $this->isProjectCopilot() || $this->isProjectManager() || + Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { return true; } return false; @@ -1057,8 +1105,10 @@ public function canSinkDiscussion($discussion) { $group = $this->getByGroupID($groupID); $result = $this->getGroupRoleFor(Gdn::session()->UserID, $groupID); $groupRole = val('Role', $result, null); - if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID === $group->OwnerID - || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { + if($groupRole === GroupModel::ROLE_LEADER || + Gdn::session()->UserID === $group->OwnerID || + $this->isProjectCopilot() || $this->isProjectManager() || + Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { return true; } return false; @@ -1082,8 +1132,10 @@ public function canCloseDiscussion($discussion) { $group = $this->getByGroupID($groupID); $result = $this->getGroupRoleFor(Gdn::session()->UserID, $groupID); $groupRole = val('Role', $result, null); - if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID === $group->OwnerID - || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { + if($groupRole === GroupModel::ROLE_LEADER || + Gdn::session()->UserID === $group->OwnerID || + $this->isProjectCopilot() || $this->isProjectManager() || + Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { return true; } return false; @@ -1095,19 +1147,6 @@ public function canCloseDiscussion($discussion) { */ public function canMoveDiscussion($discussion) { // Don't move any discussions - /* - $groupID = $discussion->GroupID; - if(!$groupID ) { - return $this->canEditDiscussion($discussion); - } - - $group = $this->getByGroupID($groupID); - $result = $this->getGroupRoleFor(Gdn::session()->UserID, $groupID); - $groupRole = val('Role', $result, null); - if($groupRole === GroupModel::ROLE_LEADER || Gdn::session()->UserID === $group->OwnerID - || Gdn::session()->checkPermission(GroupsPlugin::GROUPS_MODERATION_MANAGE_PERMISSION)) { - return true; - } */ return false; } @@ -1165,7 +1204,6 @@ public function sendInviteEmail($GroupID, $userID) { } } - public function notifyNewGroup($groupID, $groupName) { $activityModel = Gdn::getContainer()->get(ActivityModel::class); $data = [ diff --git a/structure.php b/structure.php index 0be0237..ff047b8 100644 --- a/structure.php +++ b/structure.php @@ -40,22 +40,6 @@ ->column('ChallengeID', 'varchar(36)', true ) ->column('ChallengeUrl', 'varchar(255)', true) ->set($Explicit, $Drop); -} else { - // Updated columns if the table exist. It can be removed after deploying - $Construct - ->primaryKey('GroupID') - ->column('Name', 'varchar(100)') - ->column('Description', 'varchar(500)', true) - ->column('Type', [GroupModel::TYPE_PUBLIC, GroupModel::TYPE_PRIVATE, GroupModel::TYPE_SECRET], true) - ->column('Deletable', 'tinyint(1)', '1') - ->column('Closed', 'tinyint(1)', '0') - ->column('DateInserted', 'datetime', false, 'index') - ->column('Icon', 'varchar(255)', true) - ->column('Banner', 'varchar(255)', true) - ->column('OwnerID', 'int', false, 'key') - ->column('ChallengeID', 'varchar(36)', true ) - ->column('ChallengeUrl', 'varchar(255)', true) - ->set(true, false); } @@ -75,12 +59,21 @@ // Upgrade Vanilla tables // +// Add 'GroupID' in Category +$Construct->table('Category'); +$CategoryExists = $Construct->tableExists(); +$GroupIDExists = $Construct->columnExists('GroupID'); + +if($CategoryExists && !$GroupIDExists) { + $Construct->column('GroupID', 'int', true, 'key'); + $Construct->set($Explicit, $Drop); +} $Construct->table('Discussion'); $DiscussionExists = $Construct->tableExists(); $GroupIDExists = $Construct->columnExists('GroupID'); -if(!$GroupIDExists) { +if($DiscussionExists && !$GroupIDExists) { $Construct->column('GroupID', 'int', true, 'key'); $Construct->set($Explicit, $Drop); } @@ -90,102 +83,19 @@ // The Groups category with custom permissions - $PermissionModel = Gdn::permissionModel(); $RoleModel = new RoleModel(); $RoleModel->Database = $Database; $RoleModel->SQL = $SQL; -// Flush permissions cache & loaded updated schema. -$PermissionModel->clearPermissions(); - // If this is our initial Vanilla setup or the Group plugin -$PermissionModel->define(['Groups.Group.Add', +$PermissionModel->define([ + 'Groups.Group.Add', + 'Groups.Group.Delete', + 'Groups.Group.Edit', + 'Groups.Category.Manage', 'Groups.Moderation.Manage', 'Groups.EmailInvitations.Add'] ); -// Flush permissions cache & loaded updated schema. -$PermissionModel->clearPermissions(); - -// Update global permissions for Administrator roles -$adminRoles = $RoleModel->getByType(RoleModel::TYPE_ADMINISTRATOR)->resultArray(); -foreach ($adminRoles as $role) { - // It returns all permission: global/default category/custom category - $permissions = $PermissionModel->getPermissions($role['RoleID']); - foreach ($permissions as $permission) { - Logger::event( - 'groups_plugin', - Logger::INFO, - 'permissions', - ['role' => $role['RoleID'] , 'value' => $permission] - ); - if((array_key_exists('JunctionID', $permission))){ - continue; - } - if(array_key_exists('PermissionID', $permission)) { - $permission['Groups.Group.Add'] = 1; - $permission['Groups.Moderation.Manage'] = 0; - $permission['Groups.EmailInvitations.Add'] = 1; - $PermissionModel->save($permission); - } - - } -} - -// Update global permissions for Moderator roles -$moderatorRoles = $RoleModel->getByType(RoleModel::TYPE_MODERATOR)->resultArray(); -foreach ($moderatorRoles as $role) { - // It returns all permission: global/default category/custom category - $permissions = $PermissionModel->getPermissions($role['RoleID']); - foreach ($permissions as $permission) { - if((array_key_exists('JunctionID', $permission))){ - continue; - } - if(array_key_exists('PermissionID', $permission)) { - $permission['Groups.Group.Add'] = 0; - $permission['Groups.Moderation.Manage'] = 1; - $permission['Groups.EmailInvitations.Add'] = 0; - $PermissionModel->save($permission); - } - } -} - - -$PermissionModel->Database = Gdn::database(); -$PermissionModel->SQL = $SQL; - -// Update default category permissions for Administrator/Moderator/Member roles -$roleTypes = [RoleModel::TYPE_ADMINISTRATOR, RoleModel::TYPE_MODERATOR, RoleModel::TYPE_MEMBER]; - -foreach ($roleTypes as $roleType) { - $roles = $RoleModel->getByType($roleType)->resultArray(); - foreach ($roles as $role) { - $permissions = $PermissionModel->getPermissions($role['RoleID']); - foreach ($permissions as $permission) { - Logger::event( - 'groups_plugin', - Logger::INFO, - 'permissions:updated', - ['role' => $role['RoleID'] , 'value' => $permission] - ); - if(array_key_exists('PermissionID', $permission)) { - $permission['Vanilla.Discussions.View'] = 1; - $permission['Vanilla.Discussions.Add'] = 1; - $permission['Vanilla.Discussions.Edit'] = 1; - $permission['Vanilla.Discussions.Announce'] = 1; // Must be 1. Member role might be a leader of the Group. This permission is required to create announcements. - $permission['Vanilla.Discussions.Sink'] = $role['Type'] == RoleModel::TYPE_MODERATOR || $role['Type'] == RoleModel::TYPE_ADMINISTRATOR ? 1 : 0; - $permission['Vanilla.Discussions.Close'] = $role['Type'] == RoleModel::TYPE_MODERATOR || $role['Type'] == RoleModel::TYPE_ADMINISTRATOR ? 1 : 0; - $permission['Vanilla.Discussions.Delete'] = $role['Type'] == RoleModel::TYPE_MODERATOR || $role['Type'] == RoleModel::TYPE_ADMINISTRATOR ? 1 : 0; - $permission['Vanilla.Comments.Add'] = 1; - $permission['Vanilla.Comments.Edit'] = 0; - $permission['Vanilla.Comments.Delete'] = 0; - $PermissionModel->save($permission); - } - } - } -} - -// Force the user permissions to refresh. -$PermissionModel->clearPermissions(); // Insert some activity types diff --git a/views/group/helper_functions.php b/views/group/helper_functions.php index e3c0140..f9311c0 100644 --- a/views/group/helper_functions.php +++ b/views/group/helper_functions.php @@ -45,8 +45,9 @@ function getRoleInGroupForCurrentUser($groupId, $groups = null) { function getGroupOptionsDropdown($group = null) { $dropdown = new DropdownModule('dropdown', '', 'OptionsMenu'); $sender = Gdn::controller(); - $session = Gdn::session(); $groupModel = new GroupModel(); + $currentTopcoderProjectRoles = Gdn::controller()->data('ChallengeCurrentUserProjectRoles'); + $groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); if ($group == null) { $group = $sender->data('Group'); } @@ -57,7 +58,7 @@ function getGroupOptionsDropdown($group = null) { $canLeave = $groupModel->canLeave($group); $canInviteMember = $groupModel->canInviteNewMember($group); $canManageMembers = $groupModel->canManageMembers($group); - $canManageCategories = $groupModel->canManageCategories(); + $canManageCategories = $groupModel->canManageCategories($group); $canFollow = $groupModel->canFollowGroup($group); $canWatch = $groupModel->canWatchGroup($group); $hasFollowed = $groupModel->hasFollowedGroup($group); @@ -73,6 +74,10 @@ function getGroupOptionsDropdown($group = null) { ->addLinkIf($hasFollowed, t('Unfollow Categories'), '/group/unfollow/'.$groupID, 'unfollow', 'UnfollowGroup Popup') ->addLinkIf($canWatch && !$hasWatched, t('Watch Categories'), '/group/watch/'.$groupID, 'watch','WatchGroup Popup') ->addLinkIf($hasWatched, t('Unwatch Categories'), '/group/unwatch/'.$groupID, 'unwatch', 'UnwatchGroup Popup'); + // Allow plugins to edit the dropdown. + $sender->EventArguments['GroupOptionsDropdown'] = &$dropdown; + $sender->EventArguments['Group'] = $group; + $sender->fireEvent('GroupOptionsDropdown'); return $dropdown; } } @@ -110,6 +115,8 @@ function writeGroupMembersWithPhoto($members) { */ function writeGroupMembersWithDetails($members, $group) { $groupModel = new GroupModel(); + $currentTopcoderProjectRoles = Gdn::controller()->data('ChallengeCurrentUserProjectRoles'); + $groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); foreach ($members as $member) { $memberObj = (object)$member; diff --git a/views/group/index.php b/views/group/index.php index e51f2cb..d8efcc9 100644 --- a/views/group/index.php +++ b/views/group/index.php @@ -16,6 +16,8 @@ $TotalMembers = $this->data('TotalMembers'); $bannerCssClass = $Group->Banner ? 'HasBanner':'NoBanner'; $groupModel = new GroupModel(); +$currentTopcoderProjectRoles = Gdn::controller()->data('ChallengeCurrentUserProjectRoles'); +$groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); ?> diff --git a/views/groups/index.php b/views/groups/index.php index 3a5631c..5cf54f0 100644 --- a/views/groups/index.php +++ b/views/groups/index.php @@ -1,6 +1,9 @@ data('ChallengeCurrentUserProjectRoles'); +$groupModel->setCurrentUserTopcoderProjectRoles($currentTopcoderProjectRoles); + $canAddGroup = $groupModel->canAddGroup(); include_once $this->fetchViewLocation('helper_functions'); From d8b0b06db3c48d6ba56113d693f1c3318c86f7bb Mon Sep 17 00:00:00 2001 From: Bogdanova Olga Date: Sun, 15 Nov 2020 23:12:07 +0300 Subject: [PATCH 2/2] Issues-144 --- class.groups.plugin.php | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/class.groups.plugin.php b/class.groups.plugin.php index 993839c..ea897b6 100644 --- a/class.groups.plugin.php +++ b/class.groups.plugin.php @@ -157,8 +157,27 @@ public function onDisable() { // nothing } - public function categoryModel_beforeSaveCategory_handler($sender, $args){ - + /** + * Add challenge/Group name in discussion item + * @param $sender + * @param $args + */ + public function discussionsController_beforeDiscussionMetaData_handler($sender, $args){ + if($args['Discussion']) { + $discussion = $args['Discussion']; + if ($discussion->GroupID) { + $result = '/group/' . $discussion->GroupID; + $url = url($result, true); + $groupModel = new GroupModel(); + $group = $groupModel->getByGroupID($discussion->GroupID); + echo '
'. + ''. + 'Challenge: '. + ''.anchor($group->Name, $url).''. + ''. + '
'; + } + } } public function base_render_before($sender) {