From bcf801e1bdb10561000da35e7c579c02e47393f2 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Mon, 6 Sep 2021 16:28:23 +0200 Subject: [PATCH] new: [cerebrate:pull_sg] Pull sharing groups from a cerebrate instance --- app/Controller/CerebratesController.php | 116 ++++++++++- app/Model/Cerebrate.php | 189 +++++++++++++++++- app/View/Cerebrates/index.ctp | 9 + .../Cerebrates/preview_sharing_groups.ctp | 90 +++++++++ app/View/Cerebrates/view.ctp | 8 +- 5 files changed, 405 insertions(+), 7 deletions(-) create mode 100644 app/View/Cerebrates/preview_sharing_groups.ctp diff --git a/app/Controller/CerebratesController.php b/app/Controller/CerebratesController.php index 07e801ac4..5b64e3b74 100644 --- a/app/Controller/CerebratesController.php +++ b/app/Controller/CerebratesController.php @@ -115,7 +115,7 @@ class CerebratesController extends AppController $result = $this->Cerebrate->saveRemoteOrgs($result); $message = __('Added %s new organisations, updated %s existing organisations, %s failures.', $result['add'], $result['edit'], $result['fails']); if ($this->_isRest()) { - return $this->RestResponse->saveSuccessResponse('Cerebrates', 'pull_orgs', $cerebrate_id . '/' . $org_id, false, $message); + return $this->RestResponse->saveSuccessResponse('Cerebrates', 'pull_orgs', $cerebrate_id, false, $message); } else { $this->Flash->success($message); $this->redirect($this->referer()); @@ -128,10 +128,46 @@ class CerebratesController extends AppController $this->layout = 'ajax'; $this->render('/genericTemplates/confirm'); } + } + public function pull_sgs($id) + { + $this->set('menuData', ['menuList' => 'sync', 'menuItem' => 'previewCerebrateSgs']); + $cerebrate = $this->Cerebrate->find('first', [ + 'recursive' => -1, + 'conditions' => ['Cerebrate.id' => $id] + ]); + if (empty($cerebrate)) { + throw new NotFoundException(__('Invalid Cerebrate instance ID provided.')); + } - - + if ($this->request->is('post')) { + $result = $this->Cerebrate->queryInstance([ + 'cerebrate' => $cerebrate, + 'path' => '/sharingGroups/index', + 'params' => $this->IndexFilter->harvestParameters([ + 'name', + 'uuid', + 'quickFilter' + ]), + 'type' => 'GET' + ]); + $result = $this->Cerebrate->saveRemoteSgs($result, $this->Auth->user()); + $message = __('Added %s new sharing groups, updated %s existing sharing groups, %s failures.', $result['add'], $result['edit'], $result['fails']); + if ($this->_isRest()) { + return $this->RestResponse->saveSuccessResponse('Cerebrates', 'pull_sgs', $cerebrate_id, false, $message); + } else { + $this->Flash->success($message); + $this->redirect($this->referer()); + } + } else { + $this->set('id', $cerebrate['Cerebrate']['id']); + $this->set('title', __('Sync sharing group information')); + $this->set('question', __('Are you sure you want to download and add / update the remote sharing group from the Cerebrate node?')); + $this->set('actionName', __('Pull all')); + $this->layout = 'ajax'; + $this->render('/genericTemplates/confirm'); + } } public function preview_orgs($id) @@ -186,7 +222,7 @@ class CerebratesController extends AppController if (is_array($saveResult)) { return $this->RestResponse->viewData($saveResult, $this->response->type()); } else { - return $this->RestResponse->saveFailResponse('Cerebrates', 'download_org', $cerebrate_id . '/' . $org_id, $aveResult); + return $this->RestResponse->saveFailResponse('Cerebrates', 'download_org', $cerebrate_id . '/' . $org_id, $saveResult); } } else { if (is_array($saveResult)) { @@ -205,4 +241,76 @@ class CerebratesController extends AppController $this->render('/genericTemplates/confirm'); } } + + public function preview_sharing_groups($id) + { + $this->set('menuData', ['menuList' => 'sync', 'menuItem' => 'previewCerebrateSGs']); + $cerebrate = $this->Cerebrate->find('first', [ + 'recursive' => -1, + 'conditions' => ['Cerebrate.id' => $id] + ]); + if (empty($cerebrate)) { + throw new NotFoundException(__('Invalid Cerebrate instance ID provided.')); + } + $result = $this->Cerebrate->queryInstance([ + 'cerebrate' => $cerebrate, + 'path' => '/sharingGroups/index', + 'params' => $this->IndexFilter->harvestParameters([ + 'name', + 'uuid', + 'quickFilter' + ]), + 'type' => 'GET' + ]); + $result = $this->Cerebrate->checkRemoteSharingGroups($result); + if ($this->_isRest()) { + return $this->RestResponse->viewData($result, $this->response->type()); + } else { + App::uses('CustomPaginationTool', 'Tools'); + $customPagination = new CustomPaginationTool(); + $customPagination->truncateAndPaginate($result, $this->params, false, true); + $this->set('data', $result); + $this->set('cerebrate', $cerebrate); + } + } + + public function download_sg($cerebrate_id, $sg_id) + { + if ($this->request->is('post')) { + $cerebrate = $this->Cerebrate->find('first', [ + 'recursive' => -1, + 'conditions' => ['Cerebrate.id' => $cerebrate_id] + ]); + if (empty($cerebrate)) { + throw new NotFoundException(__('Invalid Cerebrate instance ID provided.')); + } + $result = $this->Cerebrate->queryInstance([ + 'cerebrate' => $cerebrate, + 'path' => '/sharingGroups/view/' . $sg_id, + 'type' => 'GET' + ]); + $saveResult = $this->Cerebrate->captureSg($result, $this->Auth->user()); + if ($this->_isRest()) { + if (is_array($saveResult)) { + return $this->RestResponse->viewData($saveResult, $this->response->type()); + } else { + return $this->RestResponse->saveFailResponse('Cerebrates', 'download_sg', $cerebrate_id . '/' . $sg_id, $saveResult); + } + } else { + if (is_array($saveResult)) { + $this->Flash->success(__('Sharing Group downloaded.')); + } else { + $this->Flash->error($saveResult); + } + $this->redirect($this->referer()); + } + } else { + $this->set('id', $cerebrate_id); + $this->set('title', __('Download sharing group information')); + $this->set('question', __('Are you sure you want to download and add / update the remote sharing group?')); + $this->set('actionName', __('Download')); + $this->layout = 'ajax'; + $this->render('/genericTemplates/confirm'); + } + } } diff --git a/app/Model/Cerebrate.php b/app/Model/Cerebrate.php index 8fdc3da1d..125bd450d 100644 --- a/app/Model/Cerebrate.php +++ b/app/Model/Cerebrate.php @@ -109,6 +109,32 @@ class Cerebrate extends AppModel return $outcome; } + public function saveRemoteSgs($sgs, $user) + { + $outcome = [ + 'add' => 0, + 'edit' => 0, + 'fails' => 0 + ]; + foreach ($sgs as $sg) { + $isEdit = false; + $noChange = false; + $result = $this->captureSg($sg, $user, $isEdit, $noChange); + if (!is_array($result)) { + $outcome['fails'] += 1; + } else { + if ($isEdit) { + if (!$noChange) { + $outcome['edit'] += 1; + } + } else { + $outcome['add'] += 1; + } + } + } + return $outcome; + } + public function captureOrg($org_data, &$edit=false, &$noChange=false) { $org = $this->convertOrg($org_data); if ($org) { @@ -226,6 +252,165 @@ class Cerebrate extends AppModel } return false; } -} -?> + private function __compareMembers($existingMembers, $remoteMembers) + { + $memberFound = []; + $memberNotFound = []; + foreach ($remoteMembers as $remoteMember) { + $found = false; + foreach ($existingMembers as $existingMember) { + if ($existingMember['uuid'] == $remoteMember['uuid']) { + $found = true; + $memberFound[] = $remoteMember['uuid']; + break; + } + } + if (!$found) { + $memberNotFound[] = $remoteMember['uuid']; + } + } + return empty($memberNotFound); + } + + /* + * Checks remote for the current status of each sharing groups + * Adds the exists_locally field with a boolean status + * If exists_loally is true, adds a list with the differences (keynames) + */ + public function checkRemoteSharingGroups($sgs) + { + $this->SharingGroup = ClassRegistry::init('SharingGroup'); + $uuids = Hash::extract($sgs, '{n}.uuid'); + $existingSgs = $this->SharingGroup->find('all', [ + 'recursive' => -1, + 'contain' => [ + 'SharingGroupOrg' => ['Organisation'], + 'Organisation', + ], + 'conditions' => [ + 'SharingGroup.uuid' => $uuids + ], + ]); + $rearranged = []; + foreach ($existingSgs as $existingSg) { + $existingSg['SharingGroup']['SharingGroupOrg'] = $existingSg['SharingGroupOrg']; + $existingSg['SharingGroup']['Organisation'] = $existingSg['Organisation']; + $rearranged[$existingSg['SharingGroup']['uuid']] = $existingSg['SharingGroup']; + } + unset($existingSgs); + $fieldsToCheck = ['name', 'releasability', 'description']; + foreach ($sgs as $k => $sg) { + $sgs[$k]['exists_locally'] = false; + if (isset($rearranged[$sg['uuid']])) { + $sgs[$k]['exists_locally'] = true; + $sgs[$k]['differences'] = $this->compareSgs($rearranged[$sg['uuid']], $sgs[$k]); + } + } + return $sgs; + } + + private function compareSgs($existingSg, $remoteSg) + { + $differences = []; + $fieldsToCheck = ['name', 'releasability', 'description']; + + foreach ($fieldsToCheck as $fieldToCheck) { + if ( + !(empty($remoteSg[$fieldToCheck]) && empty($existingSg[$fieldToCheck])) && + $remoteSg[$fieldToCheck] !== $existingSg[$fieldToCheck] + ) { + if ($fieldToCheck === 'name') { + if ($this->__compareNames($existingSg[$fieldToCheck], $remoteSg[$fieldToCheck])) { + continue; + } + } + $differences[] = $fieldToCheck; + } + } + if (!$this->__compareMembers(Hash::extract($existingSg['SharingGroupOrg'], '{n}.Organisation'), $remoteSg['sharing_group_orgs'])) { + $differences[] = 'members'; + } + return $differences; + } + + private function convertSg($sg_data) + { + $mapping = [ + 'name' => [ + 'field' => 'name', + 'required' => 1 + ], + 'uuid' => [ + 'field' => 'uuid', + 'required' => 1 + ], + 'releasability' => [ + 'field' => 'releasability' + ], + 'description' => [ + 'field' => 'description' + ], + ]; + $sg = []; + foreach ($mapping as $cerebrate_field => $field_data) { + if (empty($sg_data[$cerebrate_field])) { + if (!empty($field_data['required'])) { + return false; + } else { + continue; + } + } + $sg[$field_data['field']] = $sg_data[$cerebrate_field]; + } + $sg['SharingGroupOrg'] = []; + if (!empty($sg_data['sharing_group_orgs'])) { + $sg['SharingGroupOrg'] = $sg_data['sharing_group_orgs']; + foreach ($sg['SharingGroupOrg'] as $k => $org) { + if (isset($org['_joinData'])) { + unset($sg['SharingGroupOrg'][$k]['_joinData']); + } + if (!isset($org['extend'])) { + $sg['SharingGroupOrg'][$k]['extend'] = false; + } + } + } + return $sg; + } + + public function captureSg($sg_data, $user, &$edit=false, &$noChange=false) { + $this->SharingGroup = ClassRegistry::init('SharingGroup'); + $sg = $this->convertSg($sg_data); + if ($sg) { + $existingSg = $this->SharingGroup->find('first', [ + 'recursive' => -1, + 'contain' => [ + 'SharingGroupOrg' => ['Organisation'], + 'Organisation', + ], + 'conditions' => [ + 'SharingGroup.uuid' => $sg_data['uuid'] + ], + ]); + if (!empty($existingSg)) { + $edit = true; + } + $captureResult = $this->SharingGroup->captureSG($sg, $user, false); + if (!empty($captureResult)) { + $savedSg = $this->SharingGroup->find('first', [ + 'recursive' => -1, + 'contain' => [ + 'SharingGroupOrg' => ['Organisation'], + 'Organisation', + ], + 'conditions' => [ + 'SharingGroup.id' => $captureResult + ], + ]); + return $savedSg; + } + return __('The organisation could not be saved.'); + } + return __('The retrieved data isn\'t a valid sharing group.'); + } +} diff --git a/app/View/Cerebrates/index.ctp b/app/View/Cerebrates/index.ctp index bc7324ed4..f026cb7db 100644 --- a/app/View/Cerebrates/index.ctp +++ b/app/View/Cerebrates/index.ctp @@ -92,6 +92,15 @@ 'title' => __('Pull all organisations'), 'icon' => 'arrow-circle-down' ], + [ + 'onclick' => sprintf( + 'openGenericModal(\'%s/cerebrates/pull_sgs/[onclick_params_data_path]\');', + $baseurl + ), + 'onclick_params_data_path' => 'Cerebrate.id', + 'title' => __('Pull all sharing groups'), + 'icon' => 'arrow-circle-down' + ], [ 'url' => $baseurl . '/cerebrates/edit', 'url_params_data_paths' => ['Cerebrate.id'], diff --git a/app/View/Cerebrates/preview_sharing_groups.ctp b/app/View/Cerebrates/preview_sharing_groups.ctp new file mode 100644 index 000000000..bd4aba2ac --- /dev/null +++ b/app/View/Cerebrates/preview_sharing_groups.ctp @@ -0,0 +1,90 @@ + __('Id'), + 'sort' => 'id', + 'data_path' => 'id' + ], + [ + 'name' => __('Status'), + 'sort' => 'exists_locally', + 'element' => 'remote_status', + 'data_path' => '' + ], + [ + 'name' => __('UUID'), + 'sort' => 'uuid', + 'data_path' => 'uuid' + ], + [ + 'name' => __('Name'), + 'sort' => 'name', + 'data_path' => 'name' + ], + [ + 'name' => __('Releasability'), + 'sort' => 'releasability', + 'data_path' => 'releasability' + ], + [ + 'name' => __('Description'), + 'sort' => 'description', + 'data_path' => 'description' + ], + [ + 'name' => __('# Member'), + 'element' => 'custom', + 'function' => function($row) { + return count($row['sharing_group_orgs']); + } + ], + ]; + + echo $this->element('genericElements/IndexTable/scaffold', [ + 'scaffold_data' => [ + 'data' => [ + 'data' => $data, + 'top_bar' => [ + 'pull' => 'right', + 'children' => [ + [ + 'type' => 'search', + 'button' => __('Filter'), + 'placeholder' => __('Enter value to search'), + 'data' => '', + 'preserve_url_params' => [$cerebrate['Cerebrate']['id']], + 'searchKey' => 'quickFilter' + ] + ] + ], + 'fields' => $fields, + 'title' => empty($ajax) ? __( + 'Sharing group list via Cerebrate %s (%s)', + h($cerebrate['Cerebrate']['id']), + h($cerebrate['Cerebrate']['name']) + ) : false, + 'description' => empty($ajax) ? __('Preview of the sharing group known to the remote Cerebrate instance.') : false, + 'actions' => [ + [ + 'onclick' => sprintf( + 'openGenericModal(\'%s/cerebrates/download_sg/%s/[onclick_params_data_path]\');', + $baseurl, + h($cerebrate['Cerebrate']['id']) + ), + 'onclick_params_data_path' => 'id', + 'icon' => 'download', + 'title' => __('Fetch sharing group object') + ] + ], + 'paginatorOptions' => [ + 'url' => [$cerebrate['Cerebrate']['id']] + ], + 'persistUrlParams' => [0, 'quickFilter'] + ], + 'containerId' => 'preview_sgs_container' + ] + ]); +?> + diff --git a/app/View/Cerebrates/view.ctp b/app/View/Cerebrates/view.ctp index 9548f392a..6ebaa1af9 100644 --- a/app/View/Cerebrates/view.ctp +++ b/app/View/Cerebrates/view.ctp @@ -56,7 +56,13 @@ echo $this->element( 'url_params' => ['Cerebrate.id'], 'title' => __('Organisations'), 'elementId' => 'preview_orgs_container' - ] + ], + [ + 'url' => '/cerebrates/preview_sharing_groups/{{0}}/', + 'url_params' => ['Cerebrate.id'], + 'title' => __('Sharing Groups'), + 'elementId' => 'preview_sgs_container' + ], ] ] );