Merge branch 'main' of github.com:cerebrate-project/cerebrate into namespaced-metatemplates
commit
41ca17ef36
templates
element/genericElements
IndexTable/Fields
ListTopBar
genericTemplates
webroot/js
|
@ -78,7 +78,7 @@ class AppController extends Controller
|
|||
Configure::write('DebugKit.panels', ['DebugKit.Packages' => true]);
|
||||
Configure::write('DebugKit.forceEnable', true);
|
||||
}
|
||||
|
||||
$this->loadComponent('CustomPagination');
|
||||
/*
|
||||
* Enable the following component for recommended CakePHP form protection settings.
|
||||
* see https://book.cakephp.org/4/en/controllers/components/form-protection.html
|
||||
|
@ -112,6 +112,7 @@ class AppController extends Controller
|
|||
$this->set('ajax', $this->request->is('ajax'));
|
||||
$this->request->getParam('prefix');
|
||||
$this->set('darkMode', !empty(Configure::read('Cerebrate.dark')));
|
||||
$this->set('baseurl', empty(Configure::read('baseurl')) ? '' : Configure::read('baseurl'));
|
||||
}
|
||||
|
||||
private function authApiUser(): void
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Text;
|
||||
use \Cake\Database\Expression\QueryExpression;
|
||||
|
||||
class BroodsController extends AppController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$this->CRUD->index([
|
||||
'filters' => ['name', 'uuid', 'url', 'description', 'Organisations.id', 'trusted', 'pull', 'authkey'],
|
||||
'quickFilters' => ['name', 'uuid', 'description'],
|
||||
'contain' => ['Organisations']
|
||||
]);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Sync');
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
$this->CRUD->add();
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Sync');
|
||||
$this->loadModel('Organisations');
|
||||
$dropdownData = [
|
||||
'organisation' => $this->Organisations->find('list', [
|
||||
'sort' => ['name' => 'asc']
|
||||
])
|
||||
];
|
||||
$this->set(compact('dropdownData'));
|
||||
}
|
||||
|
||||
public function view($id)
|
||||
{
|
||||
$this->CRUD->view($id, ['contain' => ['Organisations']]);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Sync');
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$this->CRUD->edit($id);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Sync');
|
||||
$this->render('add');
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$this->CRUD->delete($id);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Sync');
|
||||
}
|
||||
|
||||
public function testConnection($id)
|
||||
{
|
||||
$status = $this->Broods->queryStatus($id);
|
||||
return $this->RestResponse->viewData($status, 'json');
|
||||
}
|
||||
|
||||
public function previewIndex($id, $scope)
|
||||
{
|
||||
if (!in_array($scope, ['organisations', 'individuals', 'sharingGroups'])) {
|
||||
throw new MethodNotAllowedException(__('Invalid scope. Valid options are: organisations, individuals, sharing_groups'));
|
||||
}
|
||||
$filter = $this->request->getQuery('quickFilter');
|
||||
$data = $this->Broods->queryIndex($id, $scope, $filter);
|
||||
if (!is_array($data)) {
|
||||
$data = [];
|
||||
}
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->RestResponse->viewData($data, 'json');
|
||||
} else {
|
||||
$data = $this->CustomPagination->paginate($data);
|
||||
$this->set('data', $data);
|
||||
$this->set('brood_id', $id);
|
||||
if ($this->request->is('ajax')) {
|
||||
$this->viewBuilder()->disableAutoLayout();
|
||||
}
|
||||
$this->set('metaGroup', 'Sync');
|
||||
$this->render('preview_' . $scope);
|
||||
}
|
||||
}
|
||||
|
||||
public function downloadOrg($brood_id, $org_id)
|
||||
{
|
||||
$result = $this->Broods->downloadOrg($brood_id, $org_id);
|
||||
$success = __('Organisation fetched from remote.');
|
||||
$fail = __('Could not save the remote organisation');
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
if ($result) {
|
||||
return $this->RestResponse->saveSuccessResponse('Brood', 'downloadOrg', $brood_id, 'json', $success);
|
||||
} else {
|
||||
return $this->RestResponse->saveFailResponse('Brood', 'downloadOrg', $brood_id, $fail, 'json');
|
||||
}
|
||||
} else {
|
||||
if ($result) {
|
||||
$this->Flash->success($success);
|
||||
} else {
|
||||
$this->Flash->error($fail);
|
||||
}
|
||||
$this->redirect($this->referer());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -534,6 +534,43 @@ class ACLComponent extends Component
|
|||
]
|
||||
]
|
||||
],
|
||||
'Sync' => [
|
||||
'Broods' => [
|
||||
'label' => __('Broods'),
|
||||
'url' => '/broods/index',
|
||||
'children' => [
|
||||
'index' => [
|
||||
'url' => '/broods/index',
|
||||
'label' => __('List broods')
|
||||
],
|
||||
'add' => [
|
||||
'url' => '/broods/add',
|
||||
'label' => __('Add brood'),
|
||||
'popup' => 1
|
||||
],
|
||||
'view' => [
|
||||
'url' => '/broods/view/{{id}}',
|
||||
'label' => __('View brood'),
|
||||
'actions' => ['delete', 'edit', 'view'],
|
||||
'skipTopMenu' => 1
|
||||
],
|
||||
'edit' => [
|
||||
'url' => '/broods/edit/{{id}}',
|
||||
'label' => __('Edit brood'),
|
||||
'actions' => ['edit', 'delete', 'view'],
|
||||
'skipTopMenu' => 1,
|
||||
'popup' => 1
|
||||
],
|
||||
'delete' => [
|
||||
'url' => '/broods/delete/{{id}}',
|
||||
'label' => __('Delete brood'),
|
||||
'actions' => ['delete', 'edit', 'view'],
|
||||
'skipTopMenu' => 1,
|
||||
'popup' => 1
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
'Administration' => [
|
||||
'Roles' => [
|
||||
'label' => __('Roles'),
|
||||
|
|
|
@ -90,7 +90,12 @@ class CRUDComponent extends Component
|
|||
$this->Controller->set('fields', $params['fields']);
|
||||
}
|
||||
if ($this->request->is('post')) {
|
||||
$patchEntityParams = [];
|
||||
$patchEntityParams = [
|
||||
'associated' => []
|
||||
];
|
||||
if (!empty($params['id'])) {
|
||||
unset($params['id']);
|
||||
}
|
||||
$input = $this->__massageInput($params);
|
||||
if (!empty($params['fields'])) {
|
||||
$patchEntityParams['fields'] = $params['fields'];
|
||||
|
@ -156,33 +161,7 @@ class CRUDComponent extends Component
|
|||
|
||||
private function saveMetaFields($id, $input)
|
||||
{
|
||||
foreach ($input['metaFields'] as $templateID => $metaFields) {
|
||||
$metaTemplates = $this->MetaTemplates->find()->where([
|
||||
'id' => $templateID,
|
||||
'enabled' => 1
|
||||
])->contain(['MetaTemplateFields'])->first();
|
||||
$fieldNameToId = [];
|
||||
foreach ($metaTemplates->meta_template_fields as $i => $metaTemplateField) {
|
||||
$fieldNameToId[$metaTemplateField->field] = $metaTemplateField->id;
|
||||
}
|
||||
foreach ($metaFields as $metaField => $values) {
|
||||
if (!is_array($values)) {
|
||||
$values = [$values];
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
if ($value !== '') {
|
||||
$temp = $this->MetaFields->newEmptyEntity();
|
||||
$temp->field = $metaField;
|
||||
$temp->value = $value;
|
||||
$temp->scope = $this->Table->metaFields;
|
||||
$temp->parent_id = $id;
|
||||
$temp->meta_template_id = $templateID;
|
||||
$temp->meta_template_field_id = $fieldNameToId[$metaField];
|
||||
$this->MetaFields->save($temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->Table->saveMetaFields($id, $input);
|
||||
}
|
||||
|
||||
private function __massageInput($params)
|
||||
|
@ -215,7 +194,9 @@ class CRUDComponent extends Component
|
|||
$this->Controller->set('fields', $params['fields']);
|
||||
}
|
||||
if ($this->request->is(['post', 'put'])) {
|
||||
$patchEntityParams = [];
|
||||
$patchEntityParams = [
|
||||
'associated' => []
|
||||
];
|
||||
$input = $this->__massageInput($params);
|
||||
if (!empty($params['fields'])) {
|
||||
$patchEntityParams['fields'] = $params['fields'];
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\Component;
|
||||
|
||||
use Cake\Controller\Component;
|
||||
use Cake\Controller\ComponentRegistry;
|
||||
use Cake\Http\Exception\NotFoundException;
|
||||
use InvalidArgumentException;
|
||||
use Cake\Controller\Component\PaginatorComponent;
|
||||
use Cake\Utility\Hash;
|
||||
|
||||
class CustomPaginationComponent extends Component
|
||||
{
|
||||
|
||||
public function __construct(ComponentRegistry $registry, array $config = [])
|
||||
{
|
||||
parent::__construct($registry, $config);
|
||||
}
|
||||
|
||||
protected $defaults = [
|
||||
'limit' => 10,
|
||||
'direction' => 'asc'
|
||||
];
|
||||
|
||||
protected $settings = [
|
||||
|
||||
];
|
||||
|
||||
protected $validFields = [
|
||||
'limit',
|
||||
'page',
|
||||
'sort',
|
||||
'direction'
|
||||
];
|
||||
|
||||
public function paginate(array $data): array
|
||||
{
|
||||
|
||||
$request = $this->_registry->getController()->getRequest();
|
||||
$params = $request->getQueryParams();
|
||||
$settings = $this->defaults;
|
||||
foreach ($this->validFields as $validField) {
|
||||
if (isset($params[$validField])) {
|
||||
$settings[$validField] = $params[$validField];
|
||||
}
|
||||
}
|
||||
$count = count($data);
|
||||
if (!empty($settings['sort'])) {
|
||||
$data = $this->_sortData($data, $settings);
|
||||
}
|
||||
if (!empty($settings['limit'])) {
|
||||
$data = $this->_truncateData($data, $settings);
|
||||
}
|
||||
$this->_setPagingParams($settings, $count, count($data));
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function _sortData(array $data, array &$settings): array
|
||||
{
|
||||
return Hash::sort($data, '{n}.' . $settings['sort'], strtolower($settings['direction']));
|
||||
}
|
||||
|
||||
protected function _truncateData(array $data, array $settings): array
|
||||
{
|
||||
$page = $settings['page'] ?? 1;
|
||||
$limit = $settings['limit'] ?? 50;
|
||||
$offset = ($page - 1) * $limit;
|
||||
return array_slice($data, $offset, $limit);
|
||||
}
|
||||
|
||||
protected function _setPagingParams(array $settings, int $count, int $currentCount): void
|
||||
{
|
||||
$controller = $this->getController();
|
||||
$request = $controller->getRequest();
|
||||
$limit = $settings['limit'] ?? 0;
|
||||
$pageCount = empty($settings['limit']) ? 1 : ceil($count/$limit);
|
||||
$page = $settings['page'] ?? 1;
|
||||
$start = $end = 0;
|
||||
$prevPage = $page > 1;
|
||||
$nextPage = true;
|
||||
if ($count) {
|
||||
$nextPage = $count > ($page * $limit);
|
||||
}
|
||||
if ($currentCount > 0) {
|
||||
$start = (($page - 1) * $limit) + 1;
|
||||
$end = $start + $currentCount - 1;
|
||||
}
|
||||
$paging = [
|
||||
'count' => $count,
|
||||
'current' => $currentCount,
|
||||
'perPage' => $limit,
|
||||
'page' => $page,
|
||||
'requestedPage' => $settings['page'] ?? 1,
|
||||
'pageCount' => $pageCount,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'prevPage' => $page > 1,
|
||||
'nextPage' => $nextPage
|
||||
];
|
||||
$paging = ['organisations' => $paging + $settings];
|
||||
$controller->setRequest($request->withAttribute('paging', $paging));
|
||||
}
|
||||
}
|
|
@ -22,5 +22,24 @@ class AlignmentsTable extends AppTable
|
|||
->notEmptyString('organisation_id')
|
||||
->requirePresence(['individual_id', 'organisation_id'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
|
||||
public function setAlignment($organisation_id, $individual_id, $type): void
|
||||
{
|
||||
$query = $this->find();
|
||||
$query->where([
|
||||
'organisation_id' => $organisation_id,
|
||||
'individual_id' => $individual_id
|
||||
]);
|
||||
$existingAlignment = $query->first();
|
||||
if (empty($existingAlignment)) {
|
||||
$alignment = $this->newEmptyEntity();
|
||||
$data = [
|
||||
'organisation_id' => $organisation_id,
|
||||
'individual_id' => $individual_id,
|
||||
'type' => $type
|
||||
];
|
||||
$this->patchEntity($alignment, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,44 @@ use Cake\ORM\Table;
|
|||
use Cake\Validation\Validator;
|
||||
use Cake\Core\Configure;
|
||||
use Cake\Core\Configure\Engine\PhpConfig;
|
||||
use Cake\ORM\TableRegistry;
|
||||
|
||||
class AppTable extends Table
|
||||
{
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
}
|
||||
|
||||
public function saveMetaFields($id, $input)
|
||||
{
|
||||
$this->MetaFields = TableRegistry::getTableLocator()->get('MetaFields');
|
||||
$this->MetaTemplates = TableRegistry::getTableLocator()->get('MetaTemplates');
|
||||
foreach ($input['metaFields'] as $templateID => $metaFields) {
|
||||
$metaTemplates = $this->MetaTemplates->find()->where([
|
||||
'id' => $templateID,
|
||||
'enabled' => 1
|
||||
])->contain(['MetaTemplateFields'])->first();
|
||||
$fieldNameToId = [];
|
||||
foreach ($metaTemplates->meta_template_fields as $i => $metaTemplateField) {
|
||||
$fieldNameToId[$metaTemplateField->field] = $metaTemplateField->id;
|
||||
}
|
||||
foreach ($metaFields as $metaField => $values) {
|
||||
if (!is_array($values)) {
|
||||
$values = [$values];
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
if ($value !== '') {
|
||||
$temp = $this->MetaFields->newEmptyEntity();
|
||||
$temp->field = $metaField;
|
||||
$temp->value = $value;
|
||||
$temp->scope = $this->Table->metaFields;
|
||||
$temp->parent_id = $id;
|
||||
$temp->meta_template_id = $templateID;
|
||||
$temp->meta_template_field_id = $fieldNameToId[$metaField];
|
||||
$this->MetaFields->save($temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
use Cake\Http\Client;
|
||||
use Cake\ORM\TableRegistry;
|
||||
use Cake\Error\Debugger;
|
||||
|
||||
class BroodsTable extends AppTable
|
||||
{
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->addBehavior('UUID');
|
||||
$this->BelongsTo(
|
||||
'Organisations'
|
||||
);
|
||||
$this->setDisplayField('name');
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
return $validator;
|
||||
}
|
||||
|
||||
public function queryStatus($id)
|
||||
{
|
||||
$brood = $this->find()->where(['id' => $id])->first();
|
||||
$http = new Client();
|
||||
$start = microtime(true);
|
||||
$response = $http->get($brood['url'] . '/instance/status.json', [], [
|
||||
'headers' => [
|
||||
'Authorization' => $brood['authkey'],
|
||||
'Accept' => 'Application/json',
|
||||
'Content-type' => 'Application/json'
|
||||
]
|
||||
]);
|
||||
$ping = ((int)(100 * (microtime(true) - $start)));
|
||||
$errors = [
|
||||
403 => [
|
||||
'error' => __('Authentication failure'),
|
||||
'reason' => __('Invalid user credentials.')
|
||||
],
|
||||
405 => [
|
||||
'error' => __('Insufficient privileges'),
|
||||
'reason' => __('The remote user account doesn\'t have the required privileges to synchronise.')
|
||||
],
|
||||
500 => [
|
||||
'error' => __('Internal error'),
|
||||
'reason' => __('Something is probably broken on the remote side. Get in touch with the instance owner.')
|
||||
]
|
||||
];
|
||||
$result = [
|
||||
'code' => $response->getStatusCode()
|
||||
];
|
||||
if ($response->isOk()) {
|
||||
$raw = $response->getJson();
|
||||
$result['response']['role'] = $raw['user']['role'];
|
||||
$result['response']['user'] = $raw['user']['username'];
|
||||
$result['response']['application'] = $raw['application'];
|
||||
$result['response']['version'] = $raw['version'];
|
||||
$result['ping'] = $ping;
|
||||
} else {
|
||||
$result['error'] = $errors[$result['code']]['error'];
|
||||
$result['reason'] = $errors[$result['code']]['reason'];
|
||||
$result['ping'] = $ping;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function queryIndex($id, $scope, $filter)
|
||||
{
|
||||
$brood = $this->find()->where(['id' => $id])->first();
|
||||
if (empty($brood)) {
|
||||
throw new NotFoundException(__('Brood not found'));
|
||||
}
|
||||
$http = new Client();
|
||||
$filterQuery = empty($filter) ? '' : '?quickFilter=' . urlencode($filter);
|
||||
$response = $http->get($brood['url'] . '/' . $scope . '/index.json' . $filterQuery , [], [
|
||||
'headers' => [
|
||||
'Authorization' => $brood['authkey'],
|
||||
'Accept' => 'Application/json',
|
||||
'Content-type' => 'Application/json'
|
||||
]
|
||||
]);
|
||||
if ($response->isOk()) {
|
||||
return $response->getJson();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function downloadOrg($brood_id, $org_id)
|
||||
{
|
||||
$query = $this->find();
|
||||
$brood = $query->where(['id' => $brood_id])->first();
|
||||
if (empty($brood)) {
|
||||
throw new NotFoundException(__('Brood not found'));
|
||||
}
|
||||
$http = new Client();
|
||||
$response = $http->get($brood['url'] . '/organisations/view/' . $org_id . '/index.json' , [], [
|
||||
'headers' => [
|
||||
'Authorization' => $brood['authkey'],
|
||||
'Accept' => 'Application/json',
|
||||
'Content-type' => 'Application/json'
|
||||
]
|
||||
]);
|
||||
if ($response->isOk()) {
|
||||
$org = $response->getJson();
|
||||
$this->Organisation = TableRegistry::getTableLocator()->get('Organisations');
|
||||
$result = $this->Organisation->captureOrg($org);
|
||||
return $result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,4 +44,51 @@ class IndividualsTable extends AppTable
|
|||
->requirePresence(['email'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
|
||||
public function captureIndividual($individual): ?int
|
||||
{
|
||||
if (!empty($individual['uuid'])) {
|
||||
$existingIndividual = $this->find()->where([
|
||||
'uuid' => $individual['uuid']
|
||||
])->first();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (empty($existingIndividual)) {
|
||||
$entity = $this->newEntity($individual, ['associated' => []]);
|
||||
if (!$this->save($entity)) {
|
||||
return null;
|
||||
}
|
||||
$individual = $entity;
|
||||
} else {
|
||||
$reserved = ['id', 'uuid', 'metaFields'];
|
||||
foreach ($individual as $field => $value) {
|
||||
if (in_array($field, $reserved)) {
|
||||
continue;
|
||||
}
|
||||
$existingIndividual->$field = $value;
|
||||
}
|
||||
if (!$this->save($existingIndividual, ['associated' => false])) {
|
||||
return null;
|
||||
}
|
||||
$individual = $existingIndividua;
|
||||
}
|
||||
$this->postCaptureActions($individual);
|
||||
return $individual->id;
|
||||
}
|
||||
|
||||
public function postCaptureActions($individual): void
|
||||
{
|
||||
if (!empty($individual['metaFields'])) {
|
||||
$this->saveMetaFields($id, $individual);
|
||||
}
|
||||
if (!empty($individual['alignments'])) {
|
||||
foreach ($individual['alignments'] as $alignment) {
|
||||
$org_id = $this->Organisation->captureOrg($alignment['organisation']);
|
||||
if ($org_id) {
|
||||
$this->Alignments->setAlignment($org_id, $individual->id, $alignment['type']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,16 @@ namespace App\Model\Table;
|
|||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
use Cake\Error\Debugger;
|
||||
|
||||
class OrganisationsTable extends AppTable
|
||||
{
|
||||
public $metaFields = 'organisation';
|
||||
|
||||
protected $_accessible = [
|
||||
'id' => false
|
||||
];
|
||||
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
|
@ -47,4 +52,47 @@ class OrganisationsTable extends AppTable
|
|||
->requirePresence(['name', 'uuid'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
|
||||
public function captureOrg($org): ?int
|
||||
{
|
||||
if (!empty($org['id'])) {
|
||||
unset($org['id']);
|
||||
}
|
||||
if (!empty($org['uuid'])) {
|
||||
$existingOrg = $this->find()->where([
|
||||
'uuid' => $org['uuid']
|
||||
])->first();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (empty($existingOrg)) {
|
||||
$data = $this->newEmptyEntity();
|
||||
$data = $this->patchEntity($data, $org, ['associated' => []]);
|
||||
if (!$this->save($data)) {
|
||||
return null;
|
||||
}
|
||||
$savedOrg = $data;
|
||||
} else {
|
||||
$reserved = ['id', 'uuid', 'metaFields'];
|
||||
foreach ($org as $field => $value) {
|
||||
if (in_array($field, $reserved)) {
|
||||
continue;
|
||||
}
|
||||
$existingOrg->$field = $value;
|
||||
}
|
||||
if (!$this->save($existingOrg)) {
|
||||
return null;
|
||||
}
|
||||
$savedOrg = $existingOrg;
|
||||
}
|
||||
$this->postCaptureActions($savedOrg->id, $org);
|
||||
return $savedOrg->id;
|
||||
}
|
||||
|
||||
public function postCaptureActions($id, $org)
|
||||
{
|
||||
if (!empty($org['metaFields'])) {
|
||||
$this->saveMetaFields($id, $org);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
$modelForForm = 'Individuals';
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'data' => array(
|
||||
'description' => __('Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in genral require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them.'),
|
||||
'model' => 'Organisations',
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'name'
|
||||
),
|
||||
array(
|
||||
'field' => 'url',
|
||||
'label' => __('URL')
|
||||
),
|
||||
array(
|
||||
'field' => 'authkey',
|
||||
'label' => 'Authkey',
|
||||
'type' => 'authkey',
|
||||
'default' => ''
|
||||
),
|
||||
array(
|
||||
'field' => 'description',
|
||||
'type' => 'textarea'
|
||||
),
|
||||
array(
|
||||
'field' => 'organisation_id',
|
||||
'label' => __('Owner organisation'),
|
||||
'options' => $dropdownData['organisation'],
|
||||
'type' => 'dropdown'
|
||||
),
|
||||
array(
|
||||
'field' => 'trusted',
|
||||
'label' => __('Trusted upstream source'),
|
||||
'type' => 'checkbox'
|
||||
),
|
||||
array(
|
||||
'field' => 'pull',
|
||||
'label' => __('Enable pulling of trust information'),
|
||||
'type' => 'checkbox'
|
||||
),
|
||||
array(
|
||||
'field' => 'skip_proxy',
|
||||
'label' => 'Skip proxy',
|
||||
'type' => 'checkbox'
|
||||
)
|
||||
),
|
||||
'submit' => array(
|
||||
'action' => $this->request->getParam('action')
|
||||
)
|
||||
)
|
||||
));
|
||||
?>
|
||||
</div>
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'simple',
|
||||
'children' => [
|
||||
'data' => [
|
||||
'type' => 'simple',
|
||||
'text' => __('Add brood'),
|
||||
'class' => 'btn btn-primary',
|
||||
'popover_url' => '/broods/add'
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'data_path' => 'id',
|
||||
],
|
||||
[
|
||||
'name' => __('Name'),
|
||||
'sort' => 'name',
|
||||
'data_path' => 'name',
|
||||
],
|
||||
[
|
||||
'name' => 'Connection test',
|
||||
'data_path' => 'id',
|
||||
'element' => 'connection_test'
|
||||
],
|
||||
[
|
||||
'name' => __('Url'),
|
||||
'sort' => 'url',
|
||||
'data_path' => 'url',
|
||||
],
|
||||
[
|
||||
'name' => __('Description'),
|
||||
'data_path' => 'description',
|
||||
],
|
||||
[
|
||||
'name' => __('Owner Organisation'),
|
||||
'sort' => 'organisation.name',
|
||||
'data_path' => 'organisation',
|
||||
'element' => 'org'
|
||||
]
|
||||
],
|
||||
'title' => __('Broods Index'),
|
||||
'description' => __('Cerebrate can connect to other Cerebrate instances to exchange trust information and to instrument interconnectivity between connected local tools. Each such Cerebrate instance with its connected tools is considered to be a brood.'),
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/broods/view',
|
||||
'url_params_data_paths' => ['id'],
|
||||
'icon' => 'eye'
|
||||
],
|
||||
[
|
||||
'onclick' => 'populateAndLoadModal(\'/broods/edit/[onclick_params_data_path]\');',
|
||||
'onclick_params_data_path' => 'id',
|
||||
'icon' => 'edit'
|
||||
],
|
||||
[
|
||||
'onclick' => 'populateAndLoadModal(\'/broods/delete/[onclick_params_data_path]\');',
|
||||
'onclick_params_data_path' => 'id',
|
||||
'icon' => 'trash'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
?>
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value',
|
||||
'additionalUrlParams' => $brood_id . '/individuals'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'data_path' => 'id',
|
||||
],
|
||||
[
|
||||
'name' => __('Email'),
|
||||
'sort' => 'email',
|
||||
'data_path' => 'email',
|
||||
],
|
||||
[
|
||||
'name' => __('First Name'),
|
||||
'sort' => 'first_name',
|
||||
'data_path' => 'first_name',
|
||||
],
|
||||
[
|
||||
'name' => __('Last Name'),
|
||||
'sort' => 'last_name',
|
||||
'data_path' => 'last_name',
|
||||
],
|
||||
[
|
||||
'name' => __('Alignments'),
|
||||
'data_path' => 'alignments',
|
||||
'element' => 'alignments',
|
||||
'scope' => 'organisation'
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'sort' => 'uuid',
|
||||
'data_path' => 'uuid',
|
||||
'placeholder' => __('Leave empty to auto generate')
|
||||
],
|
||||
],
|
||||
'title' => __('Individuals Index'),
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/broods/downloadIndividual/' . $brood_id,
|
||||
'url_params_data_paths' => ['id'],
|
||||
'title' => __('Download'),
|
||||
'icon' => 'download'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
?>
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value',
|
||||
'additionalUrlParams' => $brood_id . '/organisations'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'id',
|
||||
],
|
||||
[
|
||||
'name' => __('Name'),
|
||||
'class' => 'short',
|
||||
'data_path' => 'name',
|
||||
'sort' => 'name'
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'class' => 'short',
|
||||
'data_path' => 'uuid',
|
||||
],
|
||||
[
|
||||
'name' => __('URL'),
|
||||
'class' => 'short',
|
||||
'data_path' => 'url',
|
||||
],
|
||||
[
|
||||
'name' => __('Nationality'),
|
||||
'data_path' => 'nationality',
|
||||
'sort' => 'nationality'
|
||||
],
|
||||
[
|
||||
'name' => __('Sector'),
|
||||
'data_path' => 'sector',
|
||||
'sort' => 'sector'
|
||||
],
|
||||
[
|
||||
'name' => __('Type'),
|
||||
'data_path' => 'type',
|
||||
'sort' => 'type'
|
||||
]
|
||||
],
|
||||
'title' => __('Organisation Index'),
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/broods/downloadOrg/' . $brood_id,
|
||||
'url_params_data_paths' => ['id'],
|
||||
'title' => __('Download'),
|
||||
'icon' => 'download'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
?>
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value',
|
||||
'additionalUrlParams' => $brood_id . '/sharingGroups'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'id',
|
||||
],
|
||||
[
|
||||
'name' => __('Name'),
|
||||
'class' => 'short',
|
||||
'data_path' => 'name',
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'sort' => 'uuid',
|
||||
'class' => 'short',
|
||||
'data_path' => 'uuid',
|
||||
]
|
||||
],
|
||||
'title' => __('Sharing Groups Index'),
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/broods/downloadSharingGroup/' . $brood_id,
|
||||
'url_params_data_paths' => ['id'],
|
||||
'title' => __('Download'),
|
||||
'icon' => 'download'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
?>
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
echo $this->element(
|
||||
'/genericElements/SingleViews/single_view',
|
||||
[
|
||||
'title' => __('Cererate Brood View'),
|
||||
'data' => $entity,
|
||||
'fields' => [
|
||||
[
|
||||
'key' => __('ID'),
|
||||
'path' => 'id'
|
||||
],
|
||||
[
|
||||
'key' => __('Name'),
|
||||
'path' => 'name'
|
||||
],
|
||||
[
|
||||
'key' => __('Url'),
|
||||
'path' => 'url'
|
||||
],
|
||||
[
|
||||
'key' => __('Description'),
|
||||
'path' => 'description'
|
||||
],
|
||||
[
|
||||
'key' => __('Owner'),
|
||||
'path' => 'organisation.name'
|
||||
]
|
||||
],
|
||||
'metaFields' => empty($metaFields) ? [] : $metaFields,
|
||||
'children' => [
|
||||
[
|
||||
'url' => '/Broods/previewIndex/{{0}}/organisations',
|
||||
'url_params' => ['id'],
|
||||
'title' => __('Organisations')
|
||||
],
|
||||
[
|
||||
'url' => '/Broods/previewIndex/{{0}}/individuals',
|
||||
'url_params' => ['id'],
|
||||
'title' => __('Individuals')
|
||||
],
|
||||
[
|
||||
'url' => '/Broods/previewIndex/{{0}}/sharingGroups',
|
||||
'url_params' => ['id'],
|
||||
'title' => __('Sharing groups')
|
||||
]
|
||||
]
|
||||
]
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
$data = $this->Hash->extract($row, $field['data_path'])[0];
|
||||
echo sprintf(
|
||||
'<div id="connection_test_%s"><span role="button" tabindex="0" aria-label="%s" title="%s" class="btn btn-primary btn-sm" onClick="%s">%s</span></div>',
|
||||
h($data),
|
||||
__('Test the connection to the remote instance'),
|
||||
__('Test the connection to the remote instance'),
|
||||
sprintf(
|
||||
"testConnection('%s');",
|
||||
h($data)
|
||||
),
|
||||
__('Run')
|
||||
);
|
||||
?>
|
|
@ -1,9 +1,5 @@
|
|||
<?php
|
||||
debug($row);
|
||||
debug($row['organisation']);
|
||||
debug($this->Hash->extract($row, 'organisation'));
|
||||
debug($field['data_path']);
|
||||
$orgs = $this->Hash->extract($row, $field['data_path']);
|
||||
$orgs = $row[$field['data_path']];
|
||||
if (!isset($field['fields']['allow_picture'])) {
|
||||
$field['fields']['allow_picture'] = true;
|
||||
}
|
||||
|
@ -11,8 +7,8 @@ debug($field['data_path']);
|
|||
$field['fields']['default_org'] = '';
|
||||
}
|
||||
if (!empty($orgs)) {
|
||||
if (!isset($orgs[0])) {
|
||||
$orgs = array($orgs);
|
||||
if (!empty($orgs['id'])) {
|
||||
$orgs = [$orgs];
|
||||
}
|
||||
$count = count($orgs);
|
||||
$i = 0;
|
||||
|
@ -20,6 +16,11 @@ debug($field['data_path']);
|
|||
$i++;
|
||||
if (!empty($org['id']) || !empty($org['name'])) {
|
||||
if ($field['fields']['allow_picture'] && !empty($org['id'])) {
|
||||
echo sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$baseurl . '/organisations/view/' . h($org['id']),
|
||||
h($org['name'])
|
||||
);
|
||||
//echo $this->OrgImg->getOrgImg(array('name' => $org['name'], 'id' => $org['id'], 'size' => 24));
|
||||
} else {
|
||||
echo sprintf(
|
||||
|
@ -34,6 +35,11 @@ debug($field['data_path']);
|
|||
}
|
||||
} else {
|
||||
if ($field['fields']['allow_picture']) {
|
||||
echo sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$baseurl . '/organisations/view/' . h($org['id']),
|
||||
h($org['name'])
|
||||
);
|
||||
//echo $this->OrgImg->getOrgImg(array('name' => $field['fields']['default_org'], 'size' => 24));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,14 +43,23 @@
|
|||
$(document).ready(function() {
|
||||
var controller = '<?= $this->request->getParam('controller') ?>';
|
||||
var action = '<?= $this->request->getParam('action') ?>';
|
||||
var additionalUrlParams = '';
|
||||
<?php
|
||||
if (!empty($data['additionalUrlParams'])) {
|
||||
echo sprintf(
|
||||
'additionalUrlParams = \'/%s\';',
|
||||
h($data['additionalUrlParams'])
|
||||
);
|
||||
}
|
||||
?>
|
||||
var randomValue = '<?= h($tableRandomValue) ?>';
|
||||
$('#quickFilterButton-' + randomValue).click(function() {
|
||||
var url = '/' + controller + '/' + action + '?quickFilter=' + encodeURIComponent($('#quickFilterField-<?= h($tableRandomValue) ?>').val());
|
||||
var url = '/' + controller + '/' + action + additionalUrlParams + '?quickFilter=' + encodeURIComponent($('#quickFilterField-<?= h($tableRandomValue) ?>').val());
|
||||
executePagination(randomValue, url);
|
||||
});
|
||||
$('#quickFilterField').on('keypress', function (e) {
|
||||
if(e.which === 13) {
|
||||
var url = '/' + controller + '/' + action + '?quickFilter=' + encodeURIComponent($('#quickFilterField-<?= h($tableRandomValue) ?>').val());
|
||||
var url = '/' + controller + '/' + action + additionalUrlParams + '?quickFilter=' + encodeURIComponent($('#quickFilterField-<?= h($tableRandomValue) ?>').val());
|
||||
executePagination(randomValue, url);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$this->Form->postLink(
|
||||
'',
|
||||
$path,
|
||||
['data' => [$fieldName => $currentValue]]
|
||||
);
|
||||
?>
|
|
@ -26,9 +26,41 @@ function executeStateDependencyChecks(dependenceSourceSelector) {
|
|||
});
|
||||
}
|
||||
|
||||
function testConnection(id) {
|
||||
$.ajax({
|
||||
url: '/broods/testConnection/' + id,
|
||||
type: 'GET',
|
||||
beforeSend: function () {
|
||||
$("#connection_test_" + id).html('Running test...');
|
||||
},
|
||||
error: function(){
|
||||
$("#connection_test_" + id).html('<span class="red bold">Internal error</span>');
|
||||
},
|
||||
success: function(result) {
|
||||
var html = '';
|
||||
if (result['error']) {
|
||||
html += '<strong>Status</strong>: <span class="text-danger">OK</span> (' + $("<span>").text(result['ping']).html() + ' ms)<br />';
|
||||
html += '<strong>Status</strong>: <span class="text-danger">Error: ' + result['error'] + '</span>';
|
||||
html += '<strong>Reason</strong>: <span class="text-danger">' + result['reason'] + '</span>';
|
||||
} else {
|
||||
html += '<strong>Status</strong>: <span class="text-success">OK</span> (' + $("<span>").text(result['ping']).html() + ' ms)<br />';
|
||||
html += '<strong>Remote</strong>: ' + $("<span>").text(result['response']['application']).html() + ' v' + $("<span>").text(result['response']['version']).html() + '<br />';
|
||||
html += '<strong>User</strong>: ' + $("<span>").text(result['response']['user']).html() + ' (' + $("<span>").text(result['response']['role']['name']).html() + ')' + '<br />';
|
||||
var canSync = result['response']['role']['perm_admin'] || result['response']['role']['perm_sync'];
|
||||
if (canSync) {
|
||||
html += '<strong>Sync permission</strong>: <span class="text-success">Yes</span><br />';
|
||||
} else {
|
||||
html += '<strong>Sync permission</strong>: <span class="text-danger">No</span><br />';
|
||||
}
|
||||
}
|
||||
$("#connection_test_" + id).html(html);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var UI
|
||||
$(document).ready(() => {
|
||||
if (typeof UIFactory !== "undefined") {
|
||||
UI = new UIFactory()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue