From 579c98dcdb3a5995a54d90b40918745211bad980 Mon Sep 17 00:00:00 2001 From: Axel Stohn Date: Sun, 14 May 2023 10:02:13 -0700 Subject: [PATCH 1/8] Removed unused code and removed pagination --- Controller/GrouperGroupsController.php | 242 ++---------------- Model/GrouperGroup.php | 331 +++---------------------- 2 files changed, 48 insertions(+), 525 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index b024ef6..ccba290 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -46,15 +46,6 @@ class GrouperGroupsController extends GrouperLiteAppController public $name = 'GrouperGroups'; - //Unfortunately we cannot go below 20 since that is the default and if change to below 20 will not show - //page navigation unless change record count and go back to lower number on Display record selection!! Sucks! - public $paginate = array( - //Default records per page. - 'limit' => 20, - 'maxlimit' => 100, - 'page' => 1 - ); - /** * Overrides parent beforeFilter to verify that Session contains the correct API settings. * @@ -404,13 +395,10 @@ public function removeSubscriber() */ public function groupOwner() { - $this->set('title', _txt('pl.grouperlite.title.groupowner')); - //Set initial settings for pagination + //Set initial setting $scope = [ - 'userId' => $this->userId, - 'page' => ($this->passedArgs['page'] ?? $this->paginate['page']), - 'limit' => ($this->passedArgs['limit'] ?? $this->paginate['limit']), + 'userId' => $this->userId ]; if (isset($this->request->data['search']) || isset($this->request->query['search'])) { @@ -428,7 +416,7 @@ public function groupOwner() $scope['searchcriteria'] = $searchCriteria; $scope['searchpage'] = 'ownerGroups'; - $data = $this->Paginator->paginate('GrouperGroup', $scope); + $data = $this->GrouperGroup->getSearchedGroups($scope); $this->set('groupsowners', $data); @@ -443,7 +431,7 @@ public function groupOwner() try { $scope['method'] = 'ownerGroups'; - $data = $this->Paginator->paginate('GrouperGroup', $scope); + $data = $this->GrouperGroup->ownerGroups($scope); $this->set('groupsowners', $data); @@ -479,13 +467,9 @@ public function groupOwner() */ public function groupMember() { - $this->set('title', _txt('pl.grouperlite.title.groupmember')); - - //Set initial settings for pagination + //Set initial setting $scope = [ - 'userId' => $this->userId, - 'page' => ($this->passedArgs['page'] ?? $this->paginate['page']), - 'limit' => ($this->passedArgs['limit'] ?? $this->paginate['limit']), + 'userId' => $this->userId ]; if (isset($this->request->data['search']) || isset($this->request->query['search'])) { @@ -504,7 +488,7 @@ public function groupMember() $scope['searchpage'] = 'filteredMemberOfGroups'; $scope['ContainsWG'] = true; - $data = $this->Paginator->paginate('GrouperGroup', $scope); + $data = $this->GrouperGroup->getSearchedGroups($scope); $finalData = $this->breakoutGroups($data); @@ -524,7 +508,7 @@ public function groupMember() //Add setting for Group Membership $scope['method'] = 'filteredMemberOfGroups'; - $data = $this->Paginator->paginate('GrouperGroup', $scope); + $data = $this->GrouperGroup->filteredMemberOfGroups($scope); $finalData = $this->breakoutGroups($data); @@ -558,14 +542,10 @@ public function groupMember() */ public function groupOptin() { - $this->set('title', _txt('pl.grouperlite.title.groupoptin')); - - //Set initial settings for pagination + //Set initial setting $scope = [ - 'userId' => $this->userId, - 'page' => ($this->passedArgs['page'] ?? $this->paginate['page']), - 'limit' => ($this->passedArgs['limit'] ?? $this->paginate['limit']), + 'userId' => $this->userId ]; if (isset($this->request->data['search']) || isset($this->request->query['search'])) { @@ -583,7 +563,7 @@ public function groupOptin() $scope['searchcriteria'] = $searchCriteria; $scope['searchpage'] = 'optinGroups'; - $data = $this->Paginator->paginate('GrouperGroup', $scope); + $data = $this->GrouperGroup->getSearchedGroups($scope); $this->set('groupoptins', $data); @@ -600,7 +580,7 @@ public function groupOptin() //Add settings for optinGroups $scope['method'] = 'optinGroups'; - $data = $this->Paginator->paginate('GrouperGroup', $scope); + $data = $this->GrouperGroup->optinGroups($scope); $this->set('groupoptins', $data); @@ -624,6 +604,7 @@ public function groupOptin() $this->set('config', $config); } + /** * Create a new Grouper Group via Grouper Template * Note: This is tightly coupled code to requirements, so view is hardcoded to reflect current reqs. Will need @@ -653,61 +634,6 @@ public function groupCreateTemplate() $this->set('title', _txt('pl.grouperlite.title.templatecreate')); } - /** - * ======================== NOT BEING USED ======================== - * - * Delete a Grouper Group via Grouper Template - */ - public function groupDeleteTemplate() - { - if (!$this->GrouperGroup->deleteGroupWithTemplate($this->userId, $this->request->data)) { - $this->Flash->set("Error in deleting group!", array('key' => 'error')); - return $this->redirect(array('action' => 'groupoptin')); - } - - $this->set('title', _txt('pl.grouperlite.title.templatecreate')); - } - - /** - * ======================== NOT BEING USED ======================== - * - * @return CakeResponse|void|null - * @deprecated - * - */ - public function groupCreate() - { - if ($this->request->is('post')) { - if (!$this->GrouperGroup->createUpdateGroup($this->userId, $this->request->data)) { - $this->Flash->set("Error in creating group!", array('key' => 'error')); - } else { - $this->Flash->set("Your Group has been created!", array('key' => 'success')); - } - return $this->redirect(array('action' => 'groupOwner')); - } - - $this->set('title', _txt('pl.grouperlite.title.groupcreate')); - $this->set('grouperstems', $this->GrouperGroup->getOwnedStems($this->userId)); - } - - - /** - * ======================== NOT BEING USED ======================== - * - * @return CakeResponse|null - */ - public function groupDelete() - { - if (!$this->GrouperGroup->deleteGroup($this->userId, $this->request->data)) { - $this->Flash->set("Error in deleting group!", array('key' => 'error')); - } else { - $this->Flash->set("Your Group has been deleted!", array('key' => 'success')); - } - - $this->set('grouperstems', $this->GrouperGroup->getOwnedStems($this->userId)); - return $this->redirect(array('action' => 'groupOwner')); - } - /** * Process to join a group displayed on the "Optin" page @@ -789,18 +715,18 @@ function isAuthorized() //TODO - This is needed for my dev enviro since I do not log in via I2 IdP // BEGIN =============================================== - /* + if ($this->Session->check('Auth.User.username')) { $this->userId = $this->Session->read('Auth.User.username'); } - */ + // END =============================================== //TODO - Need to make the following code configurable in getting the user ID. In this case the code is // specific to the needs of I2. // BEGIN =============================================== - + /* $uid=$this->Session->read('Auth.User.co_person_id'); $username=$this->Session->read('Auth.User.username'); error_log("HUBING ================ " . $username); @@ -839,7 +765,7 @@ function isAuthorized() } else { $this->userId = $this->getUserId($uid); $this->Session->write('Plugin.Grouper.UserId', $this->userId); - } + } */ // END =============================================== @@ -858,9 +784,6 @@ function isAuthorized() $p['findSubscriber'] = true; $p['removeSubscriber'] = true; $p['groupoptin'] = true; - $p['emaillistsoptin'] = true; - $p['emaillistsmember'] = true; - $p['emaillistsmanage'] = true; $p['groupcreate'] = true; $p['groupdelete'] = true; $p['joingroup'] = true; @@ -872,137 +795,6 @@ function isAuthorized() return ($p[$this->action]); } - public function emaillistsOptin() - { - $this->set('title', _txt('pl.grouperlite.title.emaillists-join')); - - //Set initial settings for pagination - $scope = [ - 'userId' => $this->userId, - 'page' => ($this->passedArgs['page'] ?? $this->paginate['page']), - 'limit' => ($this->passedArgs['limit'] ?? $this->paginate['limit']), - ]; - - if (isset($this->request->data['search'])) { - $searchCriteria = urldecode($this->request->data['search']); - $this->set('searchcriteria', $searchCriteria); - - try { - //Add setting for Group Membership - $scope['method'] = 'getSearchedGroups'; - $scope['searchcriteria'] = $searchCriteria; - $scope['searchpage'] = 'optinEmailGroups'; - $scope['emailonly'] = true; - - $data = $this->Paginator->paginate('GrouperGroup', $scope); - - $this->set('emailgroups', $data); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ' Search: ' . var_export($e->getMessage(), true)); - - $this->Flash->set("Your Email Optin List cannot be found, please try again later.", array('key' => 'error')); - $this->set('emailgroups', array()); - return; - } - } else { - try { - //Add setting for Group Membership - $scope['method'] = 'optinEmailGroups'; - $scope['emailonly'] = true; - - $data = $this->Paginator->paginate('GrouperGroup', $scope); - - $this->set('emailgroups', $data); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ' Search: ' . var_export($e->getMessage(), true)); - - $this->Flash->set("An error occurred with the Optin Email Lists, please try again later.", array('key' => 'error')); - $this->set('emailgroups', array()); - return; - } - } - - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); - $this->set('isTemplateUser', $this->GrouperGroup->isTemplateUser($this->userId)); - $this->set('isGrouperVisible', $this->GrouperGroup->isGrouperVisible($this->userId)); - } - - public function emaillistsMember() - { - $this->set('title', _txt('pl.grouperlite.title.emaillists-member')); - - //Set initial settings for pagination - $scope = [ - 'userId' => $this->userId, - 'page' => ($this->passedArgs['page'] ?? $this->paginate['page']), - 'limit' => ($this->passedArgs['limit'] ?? $this->paginate['limit']), - ]; - - if (isset($this->request->data['search'])) { - $searchCriteria = urldecode($this->request->data['search']); - $this->set('searchcriteria', $searchCriteria); - - try { - //Add setting for Group Membership - $scope['method'] = 'getSearchedGroups'; - $scope['searchcriteria'] = $searchCriteria; - $scope['searchpage'] = 'filteredMemberOfEmails'; - $scope['emailonly'] = true; - - $data = $this->Paginator->paginate('GrouperGroup', $scope); - - $this->set('emailgroups', $data); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ' Search: ' . var_export($e->getMessage(), true)); - - $this->Flash->set("Your Email Group cannot be found, please try again later.", array('key' => 'error')); - $this->set('emailgroups', array()); - return; - } - } else { - try { - //Add setting for Group Membership - $scope['method'] = 'filteredMemberOfEmails'; - $scope['emailonly'] = true; - - $data = $this->Paginator->paginate('GrouperGroup', $scope); - - $this->set('emailgroups', $data); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ' Search: ' . var_export($e->getMessage(), true)); - - $this->Flash->set("Your Email Group cannot be found, please try again later.", array('key' => 'error')); - $this->set('emailgroups', array()); - return; - } - } - - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); - $this->set('isTemplateUser', $this->GrouperGroup->isTemplateUser($this->userId)); - $this->set('isGrouperVisible', $this->GrouperGroup->isGrouperVisible($this->userId)); - } - - public function emaillistsManage() - { - $this->set('title', _txt('pl.grouperlite.title.emaillists-manage')); - // mock data - $this->set('group', array( - 'member' => true, - 'name' => 'Email List 1', - 'domain' => 'internet2', - 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', - 'enabled' => 'T' - )); - - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); - $this->set('isTemplateUser', $this->GrouperGroup->isTemplateUser($this->userId)); - $this->set('isGrouperVisible', $this->GrouperGroup->isGrouperVisible($this->userId)); - } - private function getUserId($id) { diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index 2a390d1..90ee0f7 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -171,6 +171,7 @@ private function initApi() } /** + * NOT BEING USED * Listing of members in an email group * * @param array $conditions Listing of conditions for display of records, including UserId @@ -178,27 +179,27 @@ private function initApi() * @throws GrouperLiteException * */ - public function filteredMemberOfEmails(array $conditions) - { - $this->initApi(); - - try { - $memberOfEmails = $this->filteredMemberOfGroups($conditions); - - // Strip out all Groups that are not in app:sympa Stem/Directory - foreach ($memberOfEmails as $key => $value) { - if (strpos(strtolower($value['name']), $this->emailStem) === false) { - unset($memberOfEmails[$key]); - } - } - return array_values($memberOfEmails); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - - } +// public function filteredMemberOfEmails(array $conditions) +// { +// $this->initApi(); +// +// try { +// $memberOfEmails = $this->filteredMemberOfGroups($conditions); +// +// // Strip out all Groups that are not in app:sympa Stem/Directory +// foreach ($memberOfEmails as $key => $value) { +// if (strpos(strtolower($value['name']), $this->emailStem) === false) { +// unset($memberOfEmails[$key]); +// } +// } +// return array_values($memberOfEmails); +// +// } catch (Exception $e) { +// CakeLog::write('error', __METHOD__ . ': An error occurred'); +// throw $e; +// } +// +// } /** * Return all Groups that a User belongs to in Grouper. @@ -234,7 +235,8 @@ public function filteredMemberOfGroups(array $conditions) } } - return array_values($memberOfGroups); + $groupResults = array_values($memberOfGroups); + return $this->getFriendlyWorkingGroupName($groupResults, 'member'); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); @@ -330,7 +332,8 @@ public function ownerGroups(array $conditions) $this->initApi(); try { - return $this->grouperAPI->getOwnedGroups($conditions); + $resultSet = $this->grouperAPI->getOwnedGroups($conditions); + return $this->getFriendlyName(array_values($resultSet)); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); @@ -460,9 +463,8 @@ public function optinGroups(array $conditions) } } } - //$finalSet = $this->paginateRecords($joinOrLeave, $conditions); - return array_values($joinOrLeave); + return $this->getFriendlyName(array_values($joinOrLeave)); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); @@ -600,56 +602,19 @@ public function getSearchedGroups(array $conditions) } } - return $returnResults; - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - } - - /** - * Method needed to support Pagination - * Adjusted to fit the data source being the Grouper API vs DB calls - * - * @param array $conditions Listing of conditions for display of records with pagination - * @return array Records requested by user with pagination support - * @throws Exception Captured in Controller - * - */ - public function paginate($conditions) - { - try { - //Pull out the method that should be run. - $method = $conditions['method']; - - $resultSet = $this->$method($conditions); - - if (isset($conditions['emailonly']) && $conditions['emailonly']) { - if ($method == 'getSearchedGroups' || $method == 'filteredMemberOfEmails') { - $friendlyResults = $this->getFriendlyEmailName($resultSet, 'member'); - } else { - $friendlyResults = $this->getFriendlyEmailName($resultSet, ''); - } - + if(isset($conditions['']) && $conditions['getSearchedGroups']){ + return $this->getFriendlyWorkingGroupName($returnResults, 'member'); } else { - if (isset($conditions['ContainsWG']) && $method == 'getSearchedGroups') { - $friendlyResults = $this->getFriendlyWorkingGroupName($resultSet, 'member'); - } elseif ($method == 'filteredMemberOfGroups') { - $friendlyResults = $this->getFriendlyWorkingGroupName($resultSet, 'member'); - } else { - $friendlyResults = $this->getFriendlyName(array_values($resultSet)); - } + return $returnResults; } - return $this->paginateRecords($friendlyResults, $conditions); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': An error occurred'); throw $e; } - } + /** * Return array of Working Groups for display on coManage site. * Logic is for each WG to have one key=>value of main WG name, then array of all associated @@ -812,238 +777,4 @@ private function getFriendlyName(array $groups) return $groups; } - /** - * Parses returned records to display only requested records for pagination. - * - * @param array $recSet All Grouper Records associated to User's request - * @param array $conditions Listing of conditions for display of records with pagination - * @return array Records requested by user with pagination support - * - */ - private function paginateRecords(array $recSet, array $conditions) - { - - //set for pagination record count - $this->totalRecords = count($recSet); - - //Return all, if requested - if (strtolower($conditions['limit']) == 'all') { - return $recSet; - } - - //Now slice recordset to return correct set of records. - $page = $conditions['page'] - 1; - $limit = $conditions['limit']; - if ($page == 0) { - $start = 0; - } else { - $start = $page * $limit; - } - $end = $start + $limit; - - return array_slice($recSet, $start, $end); - } - - /** - * Needed method to support Cake's pagination in the views - * - * @param null $conditions Listing of conditions for display of records with pagination - * @param int $recursive - * @param array $extra - * @return int Total number of Grouper Records returned by Grouper API call - * - */ - public function paginateCount($conditions = null, $recursive = 0, $extra = array()) - { - return $this->totalRecords; - } - - /** - * ======================== NOT BEING USED ======================== - * - * This is specifically for email listings only tabs/pages, that are now not being used. - * - * Process that parses the email list and makes it more user friendly - * @lists. - * - * @param array $groups - Array of email lists - * @param $method - User who is accessing, if plain member remove admin and owner email lists. - * @return array - Array of friendly email lists - */ - private function getFriendlyEmailName(array $groups, $method) - { - - $arrayIndex = 0; - foreach ($groups as &$group) { - if ($method == 'member') { - if ($group['extension'] == 'admins' || $group['extension'] == 'owners') { - unset($groups[$arrayIndex]); - } - } - $stems = explode(':', $group['name']); - $sectionCount = count($stems) - 2; - $groupName = $stems[$sectionCount]; - $domain = $stems[2]; - if (strtolower($domain) == 'incommon') { - $address = $groupName . '@lists.incommon.org'; - } elseif (strtolower($domain) == 'internet2') { - $address = $groupName . '@lists.internet2.edu'; - } else { - $address = $groupName . '@lists.' . strtolower($domain) . '.org'; - } - $group['friendlyEmail'] = $address; - $arrayIndex += 1; - } - return $groups; - } - - /** - * ======================== NOT BEING USED ======================== - * - * Used to be used for Grouper group information page. leaving in case want to reincorporate. - * - * Gets the Grouper Groups params and values as well as its associated attributes. - * - * @param string $groupName Name of Group, do not confuse with DisplayName field! - * @return array A set of attributes associated to a specific Grouper Group - * @throws GrouperLiteException - */ - public function groupDescriptions(string $groupName) - { - $this->initApi(); - - try { - $args = array(); - $args['groupName'] = $groupName; - - $groupDescription = $this->grouperAPI->getGrouperGroupInfo($args); - $groupDescription[0]['friendlyName'] = $groupDescription[0]['displayName']; - - return $groupDescription; - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - - } - - /** - * ======================== NOT BEING USED ======================== - * - * List of Email Groups a user can opt into. - * - * @param array $conditions Listing of conditions for display of records, including UserId - * @return array Listing of Optin email groups available in Groupe - * @throws GrouperLiteException Captured in Controller - * - */ - public function optinEmailGroups(array $conditions) - { - $this->initApi(); - - try { - $allGroups = $this->optinGroups($conditions); - - // Strip out all Groups that are not in Sympa Stem/Directory - foreach ($allGroups as $key => $value) { - if (strpos($value['name'], $this->emailStem) === false) { - unset($allGroups[$key]); - } - } - - return array_values($allGroups); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - } - - /** - * ======================== NOT BEING USED ======================== - * - * Delete a Grouper Group using the Template methodology in Grouper - * - * @param string $userId Id of User - * @param array $groupData Data needed to delete a Grouper Group via Template - * @return bool True if successfully deleted record - * @throws GrouperLiteException - * - */ - public function deleteGroupWithTemplate(string $userId, array $groupData) - { - $this->initApi(); - - try { - $args = array(); - $args['userId'] = $userId; - $args['workingGroupExt'] = $groupData['workingGroupExt']; - - // Reset Session variable that shows if User is an owner or not - $this->resetUserOwner(); - - return $this->grouperAPI->deleteGroupWithTemplate($args); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - - } - - /** - * ======================== NOT BEING USED ======================== - * - * Creates/Updates a new Grouper Group not WG Template related - * - * @param string $userId Id of user - * @param array $data Data from form to Save in Grouper as a Group - * @return bool True if saved | False if already created - * @throws GrouperLiteException - * - */ - public function createUpdateGroup(string $userId, array $data) - { - $this->initApi(); - - try { - $args = $data; - $args['userId'] = $userId; - - // Reset Session variable that shows if User is an owner or not - $this->resetUserOwner(); - - return $this->grouperAPI->createUpdateGroup($args); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - } - - /** - * ======================== NOT BEING USED ======================== - * - * Get Grouper Stems where User has authority to create a Grouper Group - * - * @param string $userId Id of User - * @return array Stem records - * @throws GrouperLiteException - */ - public function getOwnedStems(string $userId) - { - $this->initApi(); - - try { - $args = array(); - $args['userId'] = $userId; - - return $this->grouperAPI->getOwnedStems($args); - - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': An error occurred'); - throw $e; - } - } } From 30c423dcbea8332bc433f7c4658dc13c382d4f5d Mon Sep 17 00:00:00 2001 From: Axel Stohn Date: Sun, 14 May 2023 10:35:34 -0700 Subject: [PATCH 2/8] WIP - added Ajax call for config and also Ajax'd owned groups method --- Controller/GrouperGroupsController.php | 91 +++++++++++++------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index ccba290..9a611fe 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -116,6 +116,32 @@ public function index() ); } + /** + * Gets basic configuration for user/app via AJAX call access + * @return void + */ + public function getBaseConfig() { + + if ($this->request->is('ajax')) { + $this->response->disableCache(); + } + + $config = [ + "grouperbaseurl" => $this->Session->read('Plugin.Grouper.Api.grouperUrl'), + "isuserowner" => $this->GrouperGroup->isUserOwner($this->userId), + "isTemplateUser" => $this->GrouperGroup->isTemplateUser($this->userId), + "isGrouperVisible" => $this->GrouperGroup->isGrouperVisible($this->userId), + "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), + "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), + "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), + 'co' => CakeSession::read('Plugin.Grouper.Api.co') + ]; + + $this->response->type('json'); + $this->set(compact('config')); + $this->set('_serialize', 'config'); + } + /** * Show all members of a group @@ -150,6 +176,7 @@ public function groupSubscribers() $this->Flash->set(_txt('pl.grouperlite.message.flash.group-detail-members-failed'), array('key' => 'error')); } + if(count($subscribers) < 1){ $this->response->type('json'); $this->response->statusCode(404); @@ -395,18 +422,17 @@ public function removeSubscriber() */ public function groupOwner() { + if ($this->request->is('ajax')) { + $this->response->disableCache(); + } //Set initial setting $scope = [ 'userId' => $this->userId ]; - if (isset($this->request->data['search']) || isset($this->request->query['search'])) { - if(isset($this->request->data['search'])){ - $searchCriteria = urldecode($this->request->data['search']); - } else { - $searchCriteria = urldecode($this->request->query['search']); - } + if (isset($this->request->query['search'])) { + $searchCriteria = urldecode($this->request->query['search']); $this->set('searchcriteria', $searchCriteria); @@ -416,14 +442,15 @@ public function groupOwner() $scope['searchcriteria'] = $searchCriteria; $scope['searchpage'] = 'ownerGroups'; - $data = $this->GrouperGroup->getSearchedGroups($scope); - - $this->set('groupsowners', $data); + $groupowners = $this->GrouperGroup->getSearchedGroups($scope); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ' Search: ' . var_export($e->getMessage(), true)); - + $this->response->type('json'); + $this->response->statusCode(500); + $this->response->send(); $this->set('groupsowners', array()); + $this->Flash->set(_txt('pl.grouperlite.message.flash.owner-group-failed'), array('key' => 'error')); return; } @@ -431,32 +458,21 @@ public function groupOwner() try { $scope['method'] = 'ownerGroups'; - $data = $this->GrouperGroup->ownerGroups($scope); - - $this->set('groupsowners', $data); + $groupowners = $this->GrouperGroup->ownerGroups($scope); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - + $this->response->type('json'); + $this->response->statusCode(500); + $this->response->send(); $this->set('groupsowners', array()); - $this->set('wgowners', array()); + $this->Flash->set(_txt('pl.grouperlite.message.flash.owner-group-failed'), array('key' => 'error')); return; } - } - - $this->set('grouperbaseurl', $this->Session->read('Plugin.Grouper.Api.grouperUrl')); - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); - $this->set('isTemplateUser', $this->GrouperGroup->isTemplateUser($this->userId)); - $this->set('isGrouperVisible', $this->GrouperGroup->isGrouperVisible($this->userId)); - $config = [ - "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), - "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), - "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), - 'co' => CakeSession::read('Plugin.Grouper.Api.co') - ]; - $this->set('config', $config); + $this->set(compact('groupowners')); + $this->set('_serialize', 'groupowners'); } @@ -775,17 +791,16 @@ function isAuthorized() $p = array(); $p['index'] = true; - $p['groupinfo'] = true; $p['membersingroup'] = true; $p['groupowner'] = true; $p['groupmember'] = true; + $p['getBaseConfig'] = true; $p['groupSubscribers'] = true; $p['addSubscriber'] = true; $p['findSubscriber'] = true; $p['removeSubscriber'] = true; $p['groupoptin'] = true; $p['groupcreate'] = true; - $p['groupdelete'] = true; $p['joingroup'] = true; $p['leavegroup'] = true; $p['groupcreatetemplate'] = true; @@ -838,21 +853,5 @@ private function breakoutGroups(array $recordSet, $type = 'basic') ); } - /** - * Eliminating canned description added by Grouper on creation of a WG in Grouper - * - * @param $description - * @return string - * - */ - private function hackDescription($description) - { - //Verify description has period in it. - if (strpos($description, ".") === false) { - return $description; - } - $newString = substr($description, strpos($description, ".") + 1); - return trim($newString); - } } \ No newline at end of file From 3c6ecf227df612325e1bec1c8b7b758fd0f1d78d Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 15 May 2023 09:26:09 -0700 Subject: [PATCH 3/8] Implemented vue.js payout --- Controller/GrouperGroupsController.php | 24 ++- View/Elements/Components/vue-table.ctp | 17 ++ View/GrouperGroups/groupmember.ctp | 2 - View/GrouperGroups/index.ctp | 149 ++++++++++++++ webroot/css/co-grouper-plugin.css | 43 ++-- webroot/css/empty | 0 webroot/files/groupmember.json | 207 +++++++++++++++++++ webroot/files/groupoptin.json | 17 ++ webroot/files/groupowner.json | 29 +++ webroot/js/grouper-groups-view.js | 270 +++++++++++++++---------- webroot/js/pagecount.js | 23 +++ webroot/js/pagination.js | 60 ++++++ webroot/js/search-groups.js | 38 ++++ webroot/js/search.js | 17 -- 14 files changed, 747 insertions(+), 149 deletions(-) create mode 100644 View/GrouperGroups/index.ctp delete mode 100644 webroot/css/empty create mode 100644 webroot/files/groupmember.json create mode 100644 webroot/files/groupoptin.json create mode 100644 webroot/files/groupowner.json create mode 100644 webroot/js/pagecount.js create mode 100644 webroot/js/pagination.js create mode 100644 webroot/js/search-groups.js delete mode 100644 webroot/js/search.js diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index b024ef6..301b045 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -120,9 +120,19 @@ private function setConnection() */ public function index() { - return $this->redirect( - array('controller' => 'grouper_groups', 'action' => 'groupmember') - ); + $this->set('title', _txt('pl.grouperlite.title.groupmember')); + + $config = [ + "grouperbaseurl" => $this->Session->read('Plugin.Grouper.Api.grouperUrl'), + "isuserowner" => $this->GrouperGroup->isUserOwner($this->userId), + "isTemplateUser" => $this->GrouperGroup->isTemplateUser($this->userId), + "isGrouperVisible" => $this->GrouperGroup->isGrouperVisible($this->userId), + "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), + "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), + "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), + 'co' => CakeSession::read('Plugin.Grouper.Api.co') + ]; + $this->set('config', $config); } @@ -471,12 +481,12 @@ public function groupOwner() $this->set('config', $config); } - /** * Returns all Groups that the User is a member of in Grouper * This includes self-joined Optin Groups, as well as required Groups User cannot leave * */ + public function groupMember() { $this->set('title', _txt('pl.grouperlite.title.groupmember')); @@ -789,18 +799,16 @@ function isAuthorized() //TODO - This is needed for my dev enviro since I do not log in via I2 IdP // BEGIN =============================================== - /* if ($this->Session->check('Auth.User.username')) { $this->userId = $this->Session->read('Auth.User.username'); } - */ // END =============================================== //TODO - Need to make the following code configurable in getting the user ID. In this case the code is // specific to the needs of I2. // BEGIN =============================================== - + /* $uid=$this->Session->read('Auth.User.co_person_id'); $username=$this->Session->read('Auth.User.username'); error_log("HUBING ================ " . $username); @@ -841,7 +849,7 @@ function isAuthorized() $this->Session->write('Plugin.Grouper.UserId', $this->userId); } // END =============================================== - + */ // Determine what operations this user can perform // Construct the permission set for this user, which will also be passed to the view. diff --git a/View/Elements/Components/vue-table.ctp b/View/Elements/Components/vue-table.ctp index 957ae03..af8e203 100644 --- a/View/Elements/Components/vue-table.ctp +++ b/View/Elements/Components/vue-table.ctp @@ -51,6 +51,23 @@ add: "webroot ?>grouper_lite/grouper_groups/addSubscriber", group: "webroot ?>grouper_lite/grouper_groups/groupSubscribers", }, + tabs: [ + { + order: 1, + label: "", + id: 'memberships' + }, + { + order: 2, + label: "", + id: 'join' + }, + { + order: 3, + label: "", + id: 'manage' + }, + ] }, mounted() { if (!this.owner) { diff --git a/View/GrouperGroups/groupmember.ctp b/View/GrouperGroups/groupmember.ctp index b12cdd4..7bbee89 100644 --- a/View/GrouperGroups/groupmember.ctp +++ b/View/GrouperGroups/groupmember.ctp @@ -1,8 +1,6 @@ extend('/GrouperGroups/base'); ?> Html->addCrumb(_txt('pl.grouperlite.nav.memberships')); ?> -element('GrouperLite.Components/navigation-groups', array('active' => 'groupmember')); ?> -element('GrouperLite.Components/search', array('active' => 'groupmember')); ?> element('GrouperLite.Components/vue-table', array( 'groupData' => json_encode(array( diff --git a/View/GrouperGroups/index.ctp b/View/GrouperGroups/index.ctp new file mode 100644 index 0000000..f521323 --- /dev/null +++ b/View/GrouperGroups/index.ctp @@ -0,0 +1,149 @@ + +extend('/GrouperGroups/base'); ?> +Html->addCrumb(_txt('pl.grouperlite.nav.memberships')); ?> + + + + + + +
+
+ + + +
+
diff --git a/webroot/css/co-grouper-plugin.css b/webroot/css/co-grouper-plugin.css index b69165b..5a2586c 100644 --- a/webroot/css/co-grouper-plugin.css +++ b/webroot/css/co-grouper-plugin.css @@ -31,23 +31,23 @@ a { margin-right: 2px; } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link { padding: 0.75rem 2rem; transition: background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1); border-radius: 0; } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link:not(.active) { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link:not(.active) { color: white; background: var(--primary); } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link:not(.active):hover { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link:not(.active):hover { border-color: black; background: black; } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link:not(.active):focus { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link:not(.active):focus { border-color: transparent; } @@ -225,6 +225,7 @@ a.list-group-item-action:hover .fa { background-color: var(--primary); color: white; padding: 2px; + border-radius: 0; } .grouper .counter { @@ -232,25 +233,36 @@ a.list-group-item-action:hover .fa { font-size: 0.9rem; } -.grouper .pagination a { - color: white; +.grouper .pagination .pagination-item:not(:last-child) { + border-right: 1px solid rgba(255, 255, 255, 0.5); } .grouper .pagination .pagination-element:not(.pagination-numbers):not(.pagination-limit) { - padding: 0.5rem; margin-right: 0.5rem; } -.grouper .pagination .pagination-element.pagination-limit { - padding: 0 1rem; +.grouper .pagination .pagination-item-list { + display: flex; } -.grouper .pagination .pagination-element.pagination-numbers { - margin-right: 1rem; +.grouper .pagination .pagination-item .pagination-item-btn { + padding: 0.5rem 1rem; + color: white; + border: none; + background: none; } -.grouper .pagination .pagination-element.pagination-numbers-link:not(:first-child) { - border-left: 1px solid rgba(255, 255, 255, 0.5); +.grouper .pagination .pagination-item .pagination-item-btn:hover { + background: rgba(255, 255, 255, 0.1); +} + +.grouper .pagination .pagination-item.pagination-item-list .pagination-item-btn.current { + background: white; + color: var(--primary); +} + +.grouper .pagination .pagination-element.pagination-numbers { + margin-right: 1rem; } .grouper .pagination .pagination-element.pagination-numbers .pagination-numbers-list>span { @@ -263,11 +275,6 @@ a.list-group-item-action:hover .fa { padding: 0.5rem 1rem; } -.grouper .pagination .pagination-element.pagination-numbers .pagination-numbers-list .current.pagination-numbers-item { - background: white; - color: var(--primary); -} - .grouper .pagination .pagination-element.pagination-form * { margin: 0 0.5rem 0 0; } diff --git a/webroot/css/empty b/webroot/css/empty deleted file mode 100644 index e69de29..0000000 diff --git a/webroot/files/groupmember.json b/webroot/files/groupmember.json new file mode 100644 index 0000000..2d50459 --- /dev/null +++ b/webroot/files/groupmember.json @@ -0,0 +1,207 @@ +{ + "adhoc": [ + { + "extension": "admins", + "displayName": "app:Confluence:UniconTestAxel123:admins", + "description": "Admins of confluence space for working group. UniconTestAxel123", + "uuid": "1a0cc0cde33b4556b0565aa1f9c11f7a", + "enabled": "T", + "displayExtension": "admins", + "name": "app:Confluence:UniconTestAxel123:admins", + "typeOfGroup": "group", + "idIndex": "19473", + "optOut": false, + "friendlyName": "admins" + }, + { + "extension": "subscribers", + "displayName": "app:sympa:incommon:AdminTestWG:AdminTest WG subscribers", + "description": "Subscribers list receives working group emails. Test Create of a WG by an Admin", + "uuid": "2e421ab17fc94537a6efcdc38580a093", + "enabled": "T", + "displayExtension": "AdminTest WG subscribers", + "name": "app:sympa:incommon:AdminTestWG:subscribers", + "typeOfGroup": "group", + "idIndex": "19403", + "optOut": false, + "friendlyName": "AdminTest WG subscribers" + }, + { + "extension": "subscribers", + "displayName": "app:sympa:incommon:Bills Group:subscribers", + "description": "Subscribers list receives working group emails. Bills Working Group for testing and splunking", + "uuid": "a564f37496524696b486cffbddabd09d", + "enabled": "T", + "displayExtension": "subscribers", + "name": "app:sympa:incommon:BillsGroup:subscribers", + "typeOfGroup": "group", + "idIndex": "19123", + "optOut": false, + "friendlyName": "subscribers" + }, + { + "extension": "subscribers", + "displayName": "app:sympa:incommon:incommon-comanage:subscribers", + "uuid": "108785997dd7427ca06d5cdb0991cbad", + "enabled": "T", + "displayExtension": "subscribers", + "name": "app:sympa:incommon:incommon-comanage:subscribers", + "typeOfGroup": "group", + "idIndex": "19995", + "optOut": false, + "friendlyName": "subscribers" + }, + { + "extension": "subscriber", + "displayName": "app:sympa:internet2:d_iam_c:Drew's IAM Committee Subscriber", + "description": "Mailing List: Drew's IAM Committee", + "uuid": "3f4c50ee4ce542a6911dfd7cc4191799", + "enabled": "T", + "displayExtension": "Drew's IAM Committee Subscriber", + "name": "app:sympa:internet2:d_iam_c:subscriber", + "typeOfGroup": "group", + "idIndex": "21843", + "optOut": false, + "friendlyName": "Drew's IAM Committee Subscriber" + }, + { + "extension": "users", + "displayName": "ref:InCommon-collab:AdminTestWG:AdminTestWG users", + "description": "This is the AdminTestWG user group", + "uuid": "f092236c89254dc6b7f180706a5c5ad3", + "enabled": "T", + "displayExtension": "AdminTestWG users", + "name": "ref:incommon-collab:AdminTestWG:users", + "typeOfGroup": "group", + "idIndex": "19400", + "optOut": true, + "friendlyName": "AdminTestWG users" + }, + { + "extension": "users", + "displayName": "ref:InCommon-collab:BillsGroup:BillsGroupUsers", + "description": "Bills Group of Users", + "uuid": "215aead1b2a14464a65ce3723f326414", + "enabled": "T", + "displayExtension": "BillsGroupUsers", + "name": "ref:incommon-collab:BillsGroup:users", + "typeOfGroup": "group", + "idIndex": "20042", + "optOut": true, + "friendlyName": "BillsGroupUsers" + }, + { + "extension": "COmanage-UsersGroup-Members", + "displayName": "ref:InCommon-collab:COmanage:COmanage-UsersGroup-Members", + "description": "COmanage Users Group Members", + "uuid": "3ce99f5fc09c42968fae4afe5e63831d", + "enabled": "T", + "displayExtension": "COmanage-UsersGroup-Members", + "name": "ref:incommon-collab:COmanage:COmanage-UsersGroup-Members", + "typeOfGroup": "group", + "idIndex": "19996", + "optOut": true, + "friendlyName": "COmanage-UsersGroup-Members" + }, + { + "extension": "member", + "displayName": "ref:InCommon-collab:Drew's IAM Committee:Drew's IAM Committee Member", + "description": "Drew's IAM Committee member.", + "uuid": "1eafe705651c41fc8e6c50dc753c0891", + "enabled": "T", + "displayExtension": "Drew's IAM Committee Member", + "name": "ref:incommon-collab:d_iam_c:member", + "typeOfGroup": "group", + "idIndex": "20536", + "optOut": true, + "friendlyName": "Drew's IAM Committee Member" + }, + { + "extension": "users", + "displayName": "ref:InCommon-collab:UniconTestAxel333:UniconTestAxel333 users", + "description": "Users role means members of the working group with access to collaboration tools. UniconTestAxel333", + "uuid": "5b84ccacb8a940409f5e126ecabbb9e2", + "enabled": "T", + "displayExtension": "UniconTestAxel333 users", + "name": "ref:incommon-collab:UniconTestAxel333:users", + "typeOfGroup": "group", + "idIndex": "19481", + "optOut": true, + "friendlyName": "UniconTestAxel333 users" + }, + { + "extension": "subscriber", + "displayName": "sandbox:sympa:service:mailing_list:internet2:IAM Fans:IAM Fans Subscriber", + "description": "Mailing list for people who are Identity and Access Mangement fanatics", + "alternateName": "sandbox:sympa:service:mailing_list:internet2:iam_fans:iam_fans_subscriber", + "uuid": "0b23539aa1954f3e8cdd619d3f9e02b6", + "enabled": "T", + "displayExtension": "IAM Fans Subscriber", + "name": "sandbox:sympa:service:mailing_list:internet2:iam_fans:subscriber", + "typeOfGroup": "group", + "idIndex": "19208", + "optOut": true, + "friendlyName": "IAM Fans Subscriber" + }, + { + "extension": "user", + "displayName": "test:OptInOptOut:OptInOptOut User", + "description": "This group can be used in general to be provided privs for opting in and out just for folks in the group vs every entity", + "alternateName": "test:optinOptout", + "uuid": "13bed1e3e58148ec87400c43c9c3c824", + "enabled": "T", + "displayExtension": "OptInOptOut User", + "name": "test:optinoptout:user", + "typeOfGroup": "group", + "idIndex": "19109", + "optOut": true, + "friendlyName": "OptInOptOut User" + } + ], + "working": [ + { + "WGName": "AdminTestWG", + "WGShowName": "AdminTestWG", + "Groups": [ + { + "extension": "users", + "displayName": "app:Confluence:AdminTestWG:users", + "description": "Users of confluence space for working group. Test Create of a WG by an Admin", + "uuid": "caf29f77fdb948eb90a43756f8b3434a", + "enabled": "T", + "displayExtension": "users", + "name": "app:Confluence:AdminTestWG:users", + "typeOfGroup": "group", + "idIndex": "19405", + "optOut": false, + "WGName": "AdminTestWG", + "WGShowName": "AdminTestWG", + "WGRole": "users", + "WGApp": "Confluence" + } + ] + }, + { + "WGName": "BillsGroup", + "WGShowName": "Bills Group", + "Groups": [ + { + "extension": "users", + "displayName": "app:Confluence:Bills Group:users", + "description": "Users of confluence space for working group. Bills Working Group for testing and splunking", + "uuid": "d991a05d5e85494db17e09cc46af7274", + "enabled": "T", + "displayExtension": "users", + "name": "app:Confluence:BillsGroup:users", + "typeOfGroup": "group", + "idIndex": "19125", + "optOut": false, + "WGName": "BillsGroup", + "WGShowName": "Bills Group", + "WGRole": "users", + "WGApp": "Confluence" + } + ] + } + ] +} \ No newline at end of file diff --git a/webroot/files/groupoptin.json b/webroot/files/groupoptin.json new file mode 100644 index 0000000..de7d1a9 --- /dev/null +++ b/webroot/files/groupoptin.json @@ -0,0 +1,17 @@ +{ + "adhoc": [ + { + "extension": "users", + "displayName": "ref:InCommon-collab:UniconTestAxel123:UniconTestAxel123 users", + "description": "Users role means members of the working group with access to collaboration tools. UniconTestAxel123", + "uuid": "ac1641e827894283a8b7259a6549ce5c", + "enabled": "T", + "displayExtension": "UniconTestAxel123 users", + "name": "ref:incommon-collab:UniconTestAxel123:users", + "typeOfGroup": "group", + "idIndex": "19469", + "friendlyName": "UniconTestAxel123 users" + } + ], + "working": [] +} \ No newline at end of file diff --git a/webroot/files/groupowner.json b/webroot/files/groupowner.json new file mode 100644 index 0000000..7292441 --- /dev/null +++ b/webroot/files/groupowner.json @@ -0,0 +1,29 @@ +{ + "adhoc": [ + { + "extension": "admins", + "displayName": "app:Confluence:UniconTestAxel123:admins", + "description": "Admins of confluence space for working group. UniconTestAxel123", + "uuid": "1a0cc0cde33b4556b0565aa1f9c11f7a", + "enabled": "T", + "displayExtension": "admins", + "name": "app:Confluence:UniconTestAxel123:admins", + "typeOfGroup": "group", + "idIndex": "19473", + "friendlyName": "admins" + }, + { + "extension": "users", + "displayName": "app:Confluence:UniconTestAxel123:users", + "description": "Users of confluence space for working group. UniconTestAxel123", + "uuid": "43b9782ef93f47afa4d75d9911248720", + "enabled": "T", + "displayExtension": "users", + "name": "app:Confluence:UniconTestAxel123:users", + "typeOfGroup": "group", + "idIndex": "19474", + "friendlyName": "users" + } + ], + "working": [] +} \ No newline at end of file diff --git a/webroot/js/grouper-groups-view.js b/webroot/js/grouper-groups-view.js index 15baf5b..d426943 100644 --- a/webroot/js/grouper-groups-view.js +++ b/webroot/js/grouper-groups-view.js @@ -1,28 +1,51 @@ import Collapse from './collapse.js'; import Popover from './popover.js'; import Members from './members.js'; +import Search from './search-groups.js'; +import PageCount from './pagecount.js'; +import Pagination from './pagination.js'; export default { + directives: { + Popover + }, props: { - groups: Object, - columns: Object, config: Object, action: { type: String, - default: 'leave' + default: 'leavegroup' }, url: String, owner: Boolean, grouper: String, }, - inject: ['txt'], + inject: ['txt', 'tabs', 'columns'], + data() { + return { + active: 'memberships', + keyword: '', + loading: false, + error: null, + groups: { + adhoc: [], + working: [] + } + } + }, components: { Collapse, - Members + Members, + Search, + PageCount, + Pagination }, computed: { + cols() { + const ids = (!this.owner) ? this.tab.columns.filter(c => c.value !== 'role') : this.tab.columns; + return this.columns.filter(c => ids.indexOf(c.value) > -1); + }, numColumns() { - return this.columns.length; + return this.cols.length; }, collapsed() { return this.config.collapsed; @@ -32,131 +55,170 @@ export default { }, status() { return this.columns.some(c => c.value === 'status'); + }, + tab() { + return this.tabs.find(t => t.id === this.active); } }, - directives: { - Popover + watch: { + active(newActive) { + const { api } = this.tabs.find(t => t.id === newActive); + this.loadGroups(api); + } }, methods: { + search(query) { + this.keyword = query; + }, showSubscribers(group) { this.$refs.members.show(group); }, showOptAction(group) { - if (this.config.optAction === 'leavegroup'){ + if (this.tab.action === 'leavegroup'){ return group.optOut; } else { - return this.config.hasOwnProperty('optAction') && this.config.optAction !== 'none'; + return this.tab.action && this.tab.action !== 'none'; } + }, + async loadGroups(api, keyword) { + this.loading = true; + this.error = null; + const resp = await fetch(`${api}?keyword=${keyword}`, { + headers: { + "Accept": "application/json", + // 'Content-Type': 'application/x-www-form-urlencoded', + }, + method: "GET" + }); + if (resp.ok) { + this.groups = await resp.json(); + } else { + this.error = resp; + } + this.loading = false; } }, + mounted() { + this.loadGroups(this.tab.api); + }, template: /*html*/` - - + + + + +
- + - - - - - - - - - - - - - - - - -
{{ column.label }}{{ column.label }}
- -
- -
None
+ + ` } \ No newline at end of file diff --git a/webroot/js/pagecount.js b/webroot/js/pagecount.js new file mode 100644 index 0000000..f021ded --- /dev/null +++ b/webroot/js/pagecount.js @@ -0,0 +1,23 @@ +export default { + props: { + first: { + type: Number, + default: 0 + }, + last: { + type: Number, + default: 10 + }, + total: { + type: Number, + default: 100 + } + }, + template: /*html*/` +
+
+ Viewing {{first}}-{{last}} of {{total}} +
+
+ ` +} diff --git a/webroot/js/pagination.js b/webroot/js/pagination.js new file mode 100644 index 0000000..7f80259 --- /dev/null +++ b/webroot/js/pagination.js @@ -0,0 +1,60 @@ +export default { + props: { + current: { + type: Number, + default: 1 + } + }, + inject: ['txt'], + data() { + return { + query: '' + } + }, + methods: { + change() { + + } + }, + computed: { + numbers() { + return 5; + } + }, + mounted() { }, + template: /*html*/` + + ` +} + + diff --git a/webroot/js/search-groups.js b/webroot/js/search-groups.js new file mode 100644 index 0000000..3485bef --- /dev/null +++ b/webroot/js/search-groups.js @@ -0,0 +1,38 @@ +export default { + props: { + + }, + inject: ['txt'], + data() { + return { + query: '' + } + }, + methods: { + search(event, q) { + event.preventDefault(); + this.$emit('search', q); + } + }, + mounted() { }, + template: /*html*/` + + ` +} \ No newline at end of file diff --git a/webroot/js/search.js b/webroot/js/search.js deleted file mode 100644 index c74ddc2..0000000 --- a/webroot/js/search.js +++ /dev/null @@ -1,17 +0,0 @@ -export default { - props: { - - }, - data() { - return {} - }, - methods: { - - }, - mounted() { - - }, - template: /*html*/` - - ` -} \ No newline at end of file From 4656fe181dadf581d5ced24499286c466e1569a5 Mon Sep 17 00:00:00 2001 From: Axel Stohn Date: Mon, 15 May 2023 14:16:33 -0700 Subject: [PATCH 4/8] Changed major calls to AJAX --- Controller/GrouperGroupsController.php | 226 +++++++++++-------------- Model/GrouperGroup.php | 33 ---- 2 files changed, 102 insertions(+), 157 deletions(-) diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index af237b7..e3832c6 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -56,7 +56,7 @@ public function beforeFilter() { parent::beforeFilter(); - $this->Security->unlockedActions = array('removeSubscriber', 'addSubscriber'); + $this->Security->unlockedActions = array('removeSubscriber', 'addSubscriber', 'joinGroup', 'leaveGroup'); //Need to find which plugin instance choosing, if more than one from cm_co_grouper_lites // table being used in COmanage. @@ -126,33 +126,6 @@ public function index() $this->set('config', $config); } - /** - * Gets basic configuration for user/app via AJAX call access - * @return void - */ - public function getBaseConfig() { - - if ($this->request->is('ajax')) { - $this->response->disableCache(); - } - - $config = [ - "grouperbaseurl" => $this->Session->read('Plugin.Grouper.Api.grouperUrl'), - "isuserowner" => $this->GrouperGroup->isUserOwner($this->userId), - "isTemplateUser" => $this->GrouperGroup->isTemplateUser($this->userId), - "isGrouperVisible" => $this->GrouperGroup->isGrouperVisible($this->userId), - "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), - "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), - "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), - 'co' => CakeSession::read('Plugin.Grouper.Api.co') - ]; - - $this->response->type('json'); - $this->set(compact('config')); - $this->set('_serialize', 'config'); - } - - /** * Show all members of a group * Called from all pages via AJAX call @@ -490,20 +463,19 @@ public function groupOwner() * This includes self-joined Optin Groups, as well as required Groups User cannot leave * */ - public function groupMember() { + if ($this->request->is('ajax')) { + $this->response->disableCache(); + } + //Set initial setting $scope = [ 'userId' => $this->userId ]; - if (isset($this->request->data['search']) || isset($this->request->query['search'])) { - if(isset($this->request->data['search'])){ - $searchCriteria = urldecode($this->request->data['search']); - } else { - $searchCriteria = urldecode($this->request->query['search']); - } + if (isset($this->request->query['search'])) { + $searchCriteria = urldecode($this->request->query['search']); $this->set('searchcriteria', $searchCriteria); @@ -518,15 +490,18 @@ public function groupMember() $finalData = $this->breakoutGroups($data); - $this->set('groupmemberships', $finalData['adHocGroups']); - $this->set('wgmemberships', $finalData['workingGroups']); + $groupmemberships = $finalData['adHocGroups']; + $wgmemberships = $finalData['workingGroups']; } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ' Search: ' . var_export($e->getMessage(), true)); - - $this->Flash->set("Your Search Group cannot be found, please try again later.", array('key' => 'error')); + $this->response->type('json'); + $this->response->statusCode(500); + $this->response->send(); $this->set('groupmemberships', array()); $this->set('wgmemberships', array()); + + $this->Flash->set("Your Search Group cannot be found, please try again later.", array('key' => 'error')); return; } } else { @@ -538,29 +513,26 @@ public function groupMember() $finalData = $this->breakoutGroups($data); - $this->set('groupmemberships', $finalData['adHocGroups']); - $this->set('wgmemberships', $finalData['workingGroups']); + $groupmemberships = $finalData['adHocGroups']; + $wgmemberships = $finalData['workingGroups']; } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - - $this->Flash->set("Your Member Group cannot be found, please try again later.", array('key' => 'error')); + $this->response->type('json'); + $this->response->statusCode(500); + $this->response->send(); $this->set('groupmemberships', array()); $this->set('wgmemberships', array()); + + $this->Flash->set("Your Member Group cannot be found, please try again later.", array('key' => 'error')); return; } } - $this->set('grouperbaseurl', $this->Session->read('Plugin.Grouper.Api.grouperUrl')); - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); - $this->set('isTemplateUser', $this->GrouperGroup->isTemplateUser($this->userId)); - $this->set('isGrouperVisible', $this->GrouperGroup->isGrouperVisible($this->userId)); - $config = [ - "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), - "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), - "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), - 'co' => CakeSession::read('Plugin.Grouper.Api.co') - ]; - $this->set('config', $config); + + $this->set(compact('groupmemberships')); + $this->set(compact('wgmemberships')); + $this->set('_serialize', 'groupmemberships'); + $this->set('_serialize', 'wgmemberships'); } /** @@ -568,18 +540,17 @@ public function groupMember() */ public function groupOptin() { + if ($this->request->is('ajax')) { + $this->response->disableCache(); + } //Set initial setting $scope = [ 'userId' => $this->userId ]; - if (isset($this->request->data['search']) || isset($this->request->query['search'])) { - if(isset($this->request->data['search'])){ - $searchCriteria = urldecode($this->request->data['search']); - } else { - $searchCriteria = urldecode($this->request->query['search']); - } + if (isset($this->request->query['search'])) { + $searchCriteria = urldecode($this->request->query['search']); $this->set('searchcriteria', $searchCriteria); @@ -589,16 +560,16 @@ public function groupOptin() $scope['searchcriteria'] = $searchCriteria; $scope['searchpage'] = 'optinGroups'; - $data = $this->GrouperGroup->getSearchedGroups($scope); - - $this->set('groupoptins', $data); + $groupoptins = $this->GrouperGroup->getSearchedGroups($scope); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . 'Search: ' . var_export($e->getMessage(), true)); + $this->response->type('json'); + $this->response->statusCode(500); + $this->response->send(); + $this->set('groupoptins', array()); $this->Flash->set("Your Optin Group Search cannot be found, please try again later.", array('key' => 'error')); - $this->set('groupoptins', array()); - $this->set('wgoptins', array()); return; } } else { @@ -606,28 +577,21 @@ public function groupOptin() //Add settings for optinGroups $scope['method'] = 'optinGroups'; - $data = $this->GrouperGroup->optinGroups($scope); - - $this->set('groupoptins', $data); + $groupoptins = $this->GrouperGroup->optinGroups($scope); } catch (Exception $e) { CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - $this->Flash->set("An error occurred with the Optin Groups, please try again later.", array('key' => 'error')); + $this->response->type('json'); + $this->response->statusCode(500); + $this->response->send(); $this->set('groupoptins', array()); - $this->set('wgoptins', array()); + + $this->Flash->set("An error occurred with the Optin Groups, please try again later.", array('key' => 'error')); return; } } - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); - $this->set('isTemplateUser', $this->GrouperGroup->isTemplateUser($this->userId)); - $this->set('isGrouperVisible', $this->GrouperGroup->isGrouperVisible($this->userId)); - $config = [ - "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), - "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), - "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), - 'co' => CakeSession::read('Plugin.Grouper.Api.co') - ]; - $this->set('config', $config); + $this->set(compact('groupoptins')); + $this->set('_serialize', 'groupoptins'); } @@ -668,28 +632,38 @@ public function groupCreateTemplate() */ public function joinGroup() { - if ($this->request->is('post')) { - $name = $this->request->data['GroupName']; - $display = $this->request->data['GroupDisplayName']; + $name = urldecode($this->request->query['GroupName']); + $display = urldecode($this->request->query['GroupDisplayName']); - try { - if ($this->GrouperGroup->joinGroup($this->userId, $name)) { - $this->Flash->set( - _txt('pl.grouperlite.message.flash.join-group-success', array(filter_var($display, FILTER_SANITIZE_SPECIAL_CHARS))), - array('key' => 'success') - ); - } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-failed', array(filter_var($display, FILTER_SANITIZE_SPECIAL_CHARS))), array('key' => 'error')); - } - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error'), array('key' => 'error')); + if ($this->request->is('ajax')) { + $this->response->disableCache(); + } + + try { + if ($this->GrouperGroup->joinGroup($this->userId, $name)) { + $this->Flash->set( + _txt('pl.grouperlite.message.flash.join-group-success', array(filter_var($display, FILTER_SANITIZE_SPECIAL_CHARS))), + array('key' => 'success') + ); + $resultAdd = "Success"; + } else { + $this->response->type('json'); + $this->response->statusCode(401); + $this->response->body(json_encode(array('status' => 'ERROR', 'message' => 'NOT ADDED'))); + $this->response->send(); + $resultAdd = ''; } - } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error')); + } catch (Exception $e) { + CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); + $this->response->type('json'); + $this->response->statusCode(404); + $this->response->body(json_encode(array('status' => 'ERROR', 'message' => 'EXCEPTION'))); + $this->response->send(); + $resultAdd = ''; } - return $this->redirect(array('action' => 'groupoptin')); + $this->set(compact('resultAdd')); + $this->set('_serialize', 'resultAdd'); } /** @@ -699,29 +673,34 @@ public function joinGroup() */ public function leaveGroup() { - if ($this->request->is('post')) { - $name = $this->request->data['GroupName']; - $display = $this->request->data['GroupDisplayName']; + $name = urldecode($this->request->query['GroupName']); + $display = urldecode($this->request->query['GroupDisplayName']); - try { - if ($this->GrouperGroup->leaveGroup($this->userId, $name)) { - $this->Flash->set( - _txt('pl.grouperlite.message.flash.leave-group-success', array(filter_var($display, FILTER_SANITIZE_SPECIAL_CHARS))), - array('key' => 'success') - ); - } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-failed', array(filter_var($display, FILTER_SANITIZE_SPECIAL_CHARS))), array('key' => 'error')); - } - } catch (Exception $e) { - CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); - $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-error'), array('key' => 'error')); - } + if ($this->request->is('ajax')) { + $this->response->disableCache(); + } - } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-error'), array('key' => 'error')); + try { + if ($this->GrouperGroup->leaveGroup($this->userId, $name)) { + $resultRemove = "Success"; + } else { + $this->response->type('json'); + $this->response->statusCode(401); + $this->response->body(json_encode(array('status' => 'ERROR', 'message' => 'NOT DELETED'))); + $this->response->send(); + $resultRemove = ''; + } + } catch (Exception $e) { + CakeLog::write('error', __METHOD__ . ': ' . var_export($e->getMessage(), true)); + $this->response->type('json'); + $this->response->statusCode(404); + $this->response->body(json_encode(array('status' => 'ERROR', 'message' => 'EXCEPTION'))); + $this->response->send(); + $resultRemove = ''; } - return $this->redirect(array('action' => 'groupmember')); + $this->set(compact('resultRemove')); + $this->set('_serialize', 'resultRemove'); } /** @@ -802,18 +781,17 @@ function isAuthorized() $p = array(); $p['index'] = true; - $p['membersingroup'] = true; - $p['groupowner'] = true; - $p['groupmember'] = true; + $p['groupOwner'] = true; + $p['groupMember'] = true; $p['getBaseConfig'] = true; $p['groupSubscribers'] = true; $p['addSubscriber'] = true; $p['findSubscriber'] = true; $p['removeSubscriber'] = true; - $p['groupoptin'] = true; - $p['groupcreate'] = true; - $p['joingroup'] = true; - $p['leavegroup'] = true; + $p['groupOptin'] = true; + $p['groupCreate'] = true; + $p['joinGroup'] = true; + $p['leaveGroup'] = true; $p['groupcreatetemplate'] = true; $this->set('permissions', $p); diff --git a/Model/GrouperGroup.php b/Model/GrouperGroup.php index 90ee0f7..21e2157 100644 --- a/Model/GrouperGroup.php +++ b/Model/GrouperGroup.php @@ -154,7 +154,6 @@ public function isGrouperVisible(string $userId) } } - /** * Used to instantiate API class * @@ -170,37 +169,6 @@ private function initApi() } } - /** - * NOT BEING USED - * Listing of members in an email group - * - * @param array $conditions Listing of conditions for display of records, including UserId - * @return array List of members that belong to email group - * @throws GrouperLiteException - * - */ -// public function filteredMemberOfEmails(array $conditions) -// { -// $this->initApi(); -// -// try { -// $memberOfEmails = $this->filteredMemberOfGroups($conditions); -// -// // Strip out all Groups that are not in app:sympa Stem/Directory -// foreach ($memberOfEmails as $key => $value) { -// if (strpos(strtolower($value['name']), $this->emailStem) === false) { -// unset($memberOfEmails[$key]); -// } -// } -// return array_values($memberOfEmails); -// -// } catch (Exception $e) { -// CakeLog::write('error', __METHOD__ . ': An error occurred'); -// throw $e; -// } -// -// } - /** * Return all Groups that a User belongs to in Grouper. * Will also add OptOut Groups and flag them as joined so can display Optout option in UI. @@ -614,7 +582,6 @@ public function getSearchedGroups(array $conditions) } } - /** * Return array of Working Groups for display on coManage site. * Logic is for each WG to have one key=>value of main WG name, then array of all associated From 84ac69703f9a722c96cfcbc0345583b546f7c898 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 16 May 2023 14:42:56 -0700 Subject: [PATCH 5/8] Updated views with pagination and search box --- Controller/GrouperGroupsController.php | 70 +- View/GrouperGroups/base.ctp | 2 +- View/GrouperGroups/index.ctp | 116 +- webroot/css/co-grouper-plugin.css | 15 +- webroot/files/groupoptin.json | 31 +- webroot/files/groupowner.json | 55 +- webroot/js/bootstrap.bundle.js | 7031 ------------------------ webroot/js/grouper-groups-view.js | 133 +- webroot/js/groups-table.js | 119 + webroot/js/groups.js | 108 + webroot/js/jquery-3.5.1.min.js | 2 - webroot/js/loader.js | 19 + webroot/js/pagecount.js | 6 + webroot/js/pagination.js | 79 +- webroot/js/search-groups.js | 38 - webroot/js/tabs/tab.js | 18 + webroot/js/tabs/tabs.js | 44 + webroot/js/typeahead.bundle.js | 2451 --------- 18 files changed, 609 insertions(+), 9728 deletions(-) delete mode 100644 webroot/js/bootstrap.bundle.js create mode 100644 webroot/js/groups-table.js create mode 100644 webroot/js/groups.js delete mode 100644 webroot/js/jquery-3.5.1.min.js create mode 100644 webroot/js/loader.js delete mode 100644 webroot/js/search-groups.js create mode 100644 webroot/js/tabs/tab.js create mode 100644 webroot/js/tabs/tabs.js delete mode 100644 webroot/js/typeahead.bundle.js diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index e3832c6..1e6df11 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -56,7 +56,15 @@ public function beforeFilter() { parent::beforeFilter(); - $this->Security->unlockedActions = array('removeSubscriber', 'addSubscriber', 'joinGroup', 'leaveGroup'); + $this->Security->unlockedActions = array( + 'removeSubscriber', + 'addSubscriber', + 'joinGroup', + 'leaveGroup', + 'groupMember', + 'groupOptin', + 'groupOwner' + ); //Need to find which plugin instance choosing, if more than one from cm_co_grouper_lites // table being used in COmanage. @@ -104,12 +112,7 @@ private function setConnection() $this->Session->write('Plugin.Grouper.Api.defaultCollapse', $connectionInfo['CoGrouperLite']['default_collapse']); } - /** - * No true Index page, so sent to default page of My Membership - * - * @return CakeResponse Redirect to MyMembership page - */ - public function index() + private function getConfig() { $this->set('title', _txt('pl.grouperlite.title.groupmember')); @@ -121,9 +124,42 @@ public function index() "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), - 'co' => CakeSession::read('Plugin.Grouper.Api.co') + 'co' => CakeSession::read('Plugin.Grouper.Api.co'), + 'glid' => isset($this->passedArgs['glid']), ]; - $this->set('config', $config); + + return $config; + } + + /** + * No true Index page, so sent to default page of My Membership + * + * @return CakeResponse Redirect to MyMembership page + */ + public function index() + { + $this->set('config', $this->getConfig()); + } + + public function groupMember() + { + $this->set('config', $this->getConfig()); + $this->set('page', 'groupmember'); + $this->render('index'); + } + + public function groupOptin() + { + $this->set('config', $this->getConfig()); + $this->set('page', 'groupoptin'); + $this->render('index'); + } + + public function groupOwner() + { + $this->set('config', $this->getConfig()); + $this->set('page', 'groupowner'); + $this->render('index'); } /** @@ -403,7 +439,7 @@ public function removeSubscriber() /** * Listing of all Grouper Groups owned/admin by User Or search those Grouper Groups */ - public function groupOwner() + public function groupOwnerApi() { if ($this->request->is('ajax')) { $this->response->disableCache(); @@ -463,7 +499,7 @@ public function groupOwner() * This includes self-joined Optin Groups, as well as required Groups User cannot leave * */ - public function groupMember() + public function groupMemberApi() { if ($this->request->is('ajax')) { $this->response->disableCache(); @@ -538,7 +574,7 @@ public function groupMember() /** * Display all Groups a User can Join */ - public function groupOptin() + public function groupOptinApi() { if ($this->request->is('ajax')) { $this->response->disableCache(); @@ -781,14 +817,18 @@ function isAuthorized() $p = array(); $p['index'] = true; - $p['groupOwner'] = true; - $p['groupMember'] = true; + $p['groupowner'] = true; + $p['groupownerapi'] = true; + $p['groupoptin'] = true; + $p['groupoptinapi'] = true; + $p['groupmember'] = true; + $p['groupmemberapi'] = true; $p['getBaseConfig'] = true; $p['groupSubscribers'] = true; $p['addSubscriber'] = true; $p['findSubscriber'] = true; $p['removeSubscriber'] = true; - $p['groupOptin'] = true; + $p['groupCreate'] = true; $p['joinGroup'] = true; $p['leaveGroup'] = true; diff --git a/View/GrouperGroups/base.ctp b/View/GrouperGroups/base.ctp index 56147b1..8038bc6 100644 --- a/View/GrouperGroups/base.ctp +++ b/View/GrouperGroups/base.ctp @@ -36,4 +36,4 @@ $this->Html->addCrumb(_txt('pl.grouperlite.crumb.root'), array('controller' => ' fetch('content'); ?> - + \ No newline at end of file diff --git a/View/GrouperGroups/index.ctp b/View/GrouperGroups/index.ctp index f521323..7e5553e 100644 --- a/View/GrouperGroups/index.ctp +++ b/View/GrouperGroups/index.ctp @@ -7,45 +7,42 @@ 0): ?> import GrouperGroupsView from 'webroot ?>grouper_lite/js/grouper-groups-view.js?time='; - import GrouperGroupsView from 'webroot ?>grouper_lite/js/grouper-groups-view.js'; + import GrouperGroupsView from 'webroot ?>grouper_lite/js/grouper-groups-view.js?time='; - - const columns = 'name', 'label' => _txt('pl.grouperlite.table.name')), - array('value' => 'role', 'label' => _txt('pl.grouperlite.table.role')), - array('value' => 'description', 'label' => _txt('pl.grouperlite.table.description')), - array('value' => 'status', 'label' => _txt('pl.grouperlite.table.status')), - array('value' => 'action', 'label' => _txt('pl.grouperlite.table.action')), - ))) ?> - + + const app = Vue.createApp({ - data() { - return { - config: { - adhocHeading: "", - wgHeading: "", - collapsed: , - optAction: "", - members: , - add: - }, - owner: , - url: "", - } - }, provide: { + collapsed: , + optAction: "", + allowAddSubscribers: , + owner: , + url: "", + grouperUrl: "", + page: "", txt: { + adhocHeading: "", + wgHeading: "", search: "", searchForGroups: "", + display: "", + records: "", first: "", last: "", previous: "", next: "", groups: "", + grouper: "", leave: "", zero: { description: "", + records: "" }, members: "", email: "", @@ -56,10 +53,23 @@ noaccess: "", empty: "", join: "", + tabs: { + memberships: "", + optin: "", + owner: "", + }, + columns: _txt('pl.grouperlite.table.name'), + 'role' => _txt('pl.grouperlite.table.role'), + 'description' => _txt('pl.grouperlite.table.description'), + 'status' => _txt('pl.grouperlite.table.status'), + 'action' => _txt('pl.grouperlite.table.action'), + ))) ?>, }, - columns, + api: { co: , + gl: , mode: "", base: "webroot ?>grouper_lite/grouper_groups", find: "Html->url( @@ -71,43 +81,18 @@ remove: "webroot ?>grouper_lite/grouper_groups/removeSubscriber", add: "webroot ?>grouper_lite/grouper_groups/addSubscriber", group: "webroot ?>grouper_lite/grouper_groups/groupSubscribers", + memberships: "webroot ?>grouper_lite/grouper_groups/groupmemberapi/co:/glid:", + optin: "webroot ?>grouper_lite/grouper_groups/groupoptinapi/co:/glid:", + owner: "webroot ?>grouper_lite/grouper_groups/groupownerapi/co:/glid:", }, - tabs: [ - { - order: 1, - label: "", - id: 'memberships', - api: "webroot ?>grouper_lite/files/groupmember.json?time=", - columns: ['name', 'role', 'description', 'action'], - members: true, - action: 'leavegroup', - addSubscribers: false - }, - { - order: 2, - label: "", - id: 'join', - api: "webroot ?>grouper_lite/files/groupoptin.json?time=", - columns: ['name', 'description', 'action'], - members: false, - action: 'joingroup', - addSubscribers: false - }, - { - order: 3, - label: "", - id: 'manage', - api: "webroot ?>grouper_lite/files/groupowner.json?time=", - columns: ['name', 'role', 'description', 'status', 'action'], - members: true, - addSubscribers: true - }, - ] }, components: { GrouperGroupsView } - }).mount('#grouper-lite-widget'); + }); + + app.config.unwrapInjectedRef = true; + app.mount('#grouper-lite-widget');