new: [Cerebrate] initial Cerebrate model

pull/9455/head
Christophe Vandeplas 2023-12-17 11:38:39 +00:00
parent 315a9ace96
commit 4de93d3bd2
6 changed files with 938 additions and 0 deletions

View File

@ -0,0 +1,127 @@
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Core\Configure;
/**
* Cerebrates Controller
*
* @property \App\Model\Table\CerebratesTable $Cerebrates
* @method \App\Model\Entity\Cerebrate[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
*/
class CerebratesController extends AppController
{
/**
* Index method
*
* @return \Cake\Http\Response|null|void Renders view
*/
public function index()
{
$params = [
'contain' => ['Organisations'],
'filters' => ['name', 'url', 'uuid'],
'quickFilters' => ['name']
];
$this->CRUD->index($params);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
}
/**
* View method
*
* @param string|null $id Cerebrate id.
* @return \Cake\Http\Response|null|void Renders view
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function view($id = null)
{
$this->CRUD->view($id,
['contain' => ['Organisations']]
);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
$this->set('id', $id);
}
/**
* Add method
*
* @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise.
*/
public function add()
{
$params = [];
$this->CRUD->add($params);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
$orgs = $this->Cerebrates->Organisations->find('list', [
'recursive' => -1,
'fields' => ['id', 'name'],
'order' => ['lower(name)' => 'ASC']
]);
$dropdownData = [
'org_id' => $orgs
];
$this->set(compact('dropdownData'));
}
/**
* Edit method
*
* @param string|null $id Cerebrate id.
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise.
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function edit($id = null)
{
$params = [];
$this->CRUD->edit($id, $params);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
$orgs = $this->Cerebrates->Organisations->find('list', [
'recursive' => -1,
'fields' => ['id', 'name'],
'order' => ['lower(name)' => 'ASC']
]);
$dropdownData = [
'org_id' => $orgs
];
$this->set(compact('dropdownData'));
$this->render('add');
}
/**
* Delete method
*
* @param string|null $id Cerebrate id.
* @return \Cake\Http\Response|null|void Redirects to index.
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function delete($id = null)
{
$this->CRUD->delete($id);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
}
}

View File

@ -0,0 +1,447 @@
<?php
namespace App\Model\Entity;
use App\Model\Entity\AppModel;
/**
* Cerebrate Entity
*
* @property int $id
* @property string $name
* @property string $url
* @property string|resource $authkey
* @property bool|null $open
* @property int $org_id
* @property bool|null $pull_orgs
* @property bool|null $pull_sharing_groups
* @property bool|null $self_signed
* @property string|null $cert_file
* @property string|null $client_cert_file
* @property bool $internal
* @property bool $skip_proxy
* @property string|null $description
*/
class Cerebrate extends AppModel
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* @var array<string, bool>
*/
protected $_accessible = [
'name' => true,
'url' => true,
'authkey' => true,
'open' => true,
'org_id' => true,
'pull_orgs' => true,
'pull_sharing_groups' => true,
'self_signed' => true,
'cert_file' => true,
'client_cert_file' => true,
'internal' => true,
'skip_proxy' => true,
'description' => true,
];
public function queryInstance($options)
{
// FIXME chri - convert this to an entity model where the entity already contains the data, and not the $options
// $url = $options['cerebrate']['Cerebrate']['url'] . $options['path'];
// $url_params = [];
// $HttpSocket = $this->setupHttpSocket($options['cerebrate']);
// $request = $this->setupSyncRequest($options['cerebrate'], 'Cerebrate');
// try {
// if (!empty($options['type']) && $options['type'] === 'post') {
// $response = $HttpSocket->post($url, json_encode($options['body']), $request);
// } else {
// $response = $HttpSocket->get(
// $url,
// (isset($options['params']) ? $options['params'] : []),
// $request
// );
// }
// if ($response->isOk()) {
// return json_decode($response->body, true);
// }
// } catch (SocketException $e) {
// throw new BadRequestException(__('Something went wrong. Error returned: %s', $e->getMessage));
// }
// if ($response->code === 403 || $response->code === 401) {
// throw new ForbiddenException(__('Authentication failed.'));
// }
// throw new BadRequestException(__('Something went wrong with the request or the remote side is having issues.'));
}
public function convertOrg($org_data) {
// $mapping = [
// 'name' => [
// 'field' => 'name',
// 'required' => 1
// ],
// 'uuid' => [
// 'field' => 'uuid',
// 'required' => 1
// ],
// 'nationality' => [
// 'field' => 'nationality'
// ],
// 'sector' => [
// 'field' => 'sector'
// ],
// 'type' => [
// 'field' => 'type'
// ]
// ];
// $org = [];
// foreach ($mapping as $cerebrate_field => $field_data) {
// if (empty($org_data[$cerebrate_field])) {
// if (!empty($field_data['required'])) {
// return false;
// } else {
// continue;
// }
// }
// $org[$field_data['field']] = $org_data[$cerebrate_field];
// }
// return $org;
}
public function saveRemoteOrgs($orgs)
{
// $outcome = [
// 'add' => 0,
// 'edit' => 0,
// 'fails' => 0
// ];
// foreach ($orgs as $org) {
// $isEdit = false;
// $noChange = false;
// $result = $this->captureOrg($org, $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 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) {
// $existingOrg = $this->Organisation->find('first', [
// 'recursive' => -1,
// 'conditions' => ['Organisation.uuid' => $org['uuid']]
// ]);
// if (!empty($existingOrg)) {
// $fieldsToSave = ['name', 'sector', 'nationality', 'type'];
// unset($org['uuid']);
// $dirty = false;
// foreach ($fieldsToSave as $fieldToSave) {
// if (!empty($org[$fieldToSave])) {
// if ($existingOrg['Organisation'][$fieldToSave] !== $org[$fieldToSave]) {
// if ($fieldToSave === 'name') {
// if ($this->__compareNames($existingOrg['Organisation']['name'], $org[$fieldToSave])) {
// continue;
// }
// }
// $existingOrg['Organisation'][$fieldToSave] = $org[$fieldToSave];
// $dirty = true;
// }
// }
// }
// $orgToSave = $existingOrg['Organisation'];
// $edit = true;
// } else {
// $dirty = true;
// $fieldsToSave = ['name', 'uuid', 'sector', 'nationality', 'type'];
// $orgToSave = [];
// foreach ($fieldsToSave as $fieldToSave) {
// if (!empty($org[$fieldToSave])) {
// $orgToSave[$fieldToSave] = $org[$fieldToSave];
// }
// }
// $this->Organisation->create();
// }
// if ($dirty) {
// $nameCheck = $this->Organisation->find('first', [
// 'recursive' => -1,
// 'conditions' => ['Organisation.name' => $orgToSave['name']],
// 'fields' => ['Organisation.id']
// ]);
// if (!empty($nameCheck)) {
// $orgToSave['name'] = $orgToSave['name'] . '_' . mt_rand(0, 9999);
// }
// $result = $this->Organisation->save($orgToSave);
// if ($result) {
// return $this->Organisation->find('first', [
// 'recursive' => -1,
// 'conditions' => ['Organisation.id' => $this->Organisation->id]
// ]);
// } else {
// return __('The organisation could not be saved.');
// }
// } else {
// $noChange = true;
// return $existingOrg['Organisation'];
// }
// }
// return __('The retrieved data isn\'t a valid organisation.');
}
/*
* Checks remote for the current status of each organisation
* Adds the exists_locally field with a boolean status
* If exists_loally is true, adds a list with the differences (keynames)
*/
public function checkRemoteOrgs($orgs)
{
// $uuids = Hash::extract($orgs, '{n}.uuid');
// $existingOrgs = $this->Organisation->find('all', [
// 'recursive' => -1,
// 'conditions' => [
// 'Organisation.uuid' => $uuids
// ]
// ]);
// $rearranged = [];
// foreach ($existingOrgs as $existingOrg) {
// $rearranged[$existingOrg['Organisation']['uuid']] = $existingOrg['Organisation'];
// }
// unset($existingOrgs);
// $fieldsToCheck = ['name', 'sector', 'type', 'nationality'];
// foreach ($orgs as $k => $org) {
// $orgs[$k]['exists_locally'] = false;
// if (isset($rearranged[$org['uuid']])) {
// $orgs[$k]['exists_locally'] = true;
// $orgs[$k]['differences'] = [];
// foreach ($fieldsToCheck as $fieldToCheck) {
// if (
// !(empty($orgs[$k][$fieldToCheck]) && empty($rearranged[$org['uuid']][$fieldToCheck])) &&
// $orgs[$k][$fieldToCheck] !== $rearranged[$org['uuid']][$fieldToCheck]
// ) {
// if ($fieldToCheck === 'name') {
// if ($this->__compareNames($rearranged[$org['uuid']][$fieldToCheck], $orgs[$k][$fieldToCheck])) {
// continue;
// }
// }
// $orgs[$k]['differences'][] = $fieldToCheck;
// }
// }
// }
// }
// return $orgs;
}
private function __compareNames($name1, $name2)
{
// if (preg_match('/\_[0-9]{4}$/i', $name1)) {
// if (substr($name1, 0, -5) === $name2) {
// return true;
// } else {
// return false;
// }
// }
// 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.');
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace App\Model\Table;
use App\Model\Table\AppTable;
use ArrayObject;
use Cake\Datasource\EntityInterface;
use Cake\Event\Event;
use Cake\Event\EventInterface;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\Validation\Validator;
/**
* Cerebrates Model
*
* @method \App\Model\Entity\Cerebrate newEmptyEntity()
* @method \App\Model\Entity\Cerebrate newEntity(array $data, array $options = [])
* @method \App\Model\Entity\Cerebrate[] newEntities(array $data, array $options = [])
* @method \App\Model\Entity\Cerebrate get($primaryKey, $options = [])
* @method \App\Model\Entity\Cerebrate findOrCreate($search, ?callable $callback = null, $options = [])
* @method \App\Model\Entity\Cerebrate patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
* @method \App\Model\Entity\Cerebrate[] patchEntities(iterable $entities, array $data, array $options = [])
* @method \App\Model\Entity\Cerebrate|false save(\Cake\Datasource\EntityInterface $entity, $options = [])
* @method \App\Model\Entity\Cerebrate saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = [])
* @method \App\Model\Entity\Cerebrate[]|\Cake\Datasource\ResultSetInterface|false saveMany(iterable $entities, $options = [])
* @method \App\Model\Entity\Cerebrate[]|\Cake\Datasource\ResultSetInterface saveManyOrFail(iterable $entities, $options = [])
* @method \App\Model\Entity\Cerebrate[]|\Cake\Datasource\ResultSetInterface|false deleteMany(iterable $entities, $options = [])
* @method \App\Model\Entity\Cerebrate[]|\Cake\Datasource\ResultSetInterface deleteManyOrFail(iterable $entities, $options = [])
*/
class CerebratesTable extends AppTable
{
/**
* Initialize method
*
* @param array $config The configuration for the Table.
* @return void
*/
public function initialize(array $config): void
{
parent::initialize($config);
$this->addBehavior('UUID');
$this->addBehavior('AuditLog');
$this->addBehavior('EncryptedFields', ['fields' => ['authkey']]);
$this->belongsTo(
'Organisations',
[
'dependent' => false,
'cascadeCallbacks' => false,
'foreignKey' => 'org_id',
'propertyName' => 'Organisation'
]
);
$this->setTable('cerebrates');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
}
/**
* Default validation rules.
*
* @param \Cake\Validation\Validator $validator Validator instance.
* @return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator): Validator
{
$validator
->scalar('name')
->maxLength('name', 191)
->requirePresence('name', 'create')
->notEmptyString('name');
$validator
->scalar('url')
->maxLength('url', 255)
->requirePresence('url', 'create')
->notEmptyString('url')
->url('url');
$validator
->requirePresence('authkey', 'create')
->notEmptyString('authkey');
$validator
->boolean('open')
->allowEmptyString('open');
$validator
->integer('org_id')
->requirePresence('org_id', 'create')
->notEmptyString('org_id');
$validator
->boolean('pull_orgs')
->allowEmptyString('pull_orgs');
$validator
->boolean('pull_sharing_groups')
->allowEmptyString('pull_sharing_groups');
$validator
->boolean('self_signed')
->allowEmptyString('self_signed');
$validator
->scalar('cert_file')
->maxLength('cert_file', 255)
->allowEmptyFile('cert_file');
$validator
->scalar('client_cert_file')
->maxLength('client_cert_file', 255)
->allowEmptyFile('client_cert_file');
$validator
->boolean('internal')
->notEmptyString('internal');
$validator
->boolean('skip_proxy')
->notEmptyString('skip_proxy');
$validator
->scalar('description')
->allowEmptyString('description');
return $validator;
}
}

View File

@ -0,0 +1,53 @@
<?php
$modelForForm = 'Cerebrates';
$edit = $this->request->getParam('action') === 'edit' ? true : false;
$fields = [
[
'field' => 'name',
'class' => 'span6'
],
[
'field' => 'url',
'class' => 'span6'
],
[
'field' => 'authkey',
'class' => 'span6',
'autocomplete' => 'off',
'type' => 'text'
],
[
'field' => 'org_id',
'label' => 'Owner Organisation',
'options' => $dropdownData['org_id'],
'class' => 'span6',
'type' => 'dropdown'
],
[
'field' => 'description',
'type' => 'textarea',
'class' => 'input span6'
],
[
'field' => 'pull_orgs',
'label' => __('Pull Organisations'),
'type' => 'checkbox',
],
[
'field' => 'pull_sharing_groups',
'label' => __('Pull Sharing Groups'),
'type' => 'checkbox',
]
];
echo $this->element('genericElements/Form/genericForm', [
'data' => [
'description' => false,
'model' => 'Cerebrate',
'title' => $edit ? __('Edit Cerebrate connection') : __('Add Cerebrate connection'),
'fields' => $fields,
'submit' => [
'action' => $this->request->getParam('action'),
'ajaxSubmit' => 'submitGenericFormInPlace();'
]
]
]);

View File

@ -0,0 +1,113 @@
<?php
$fields = [
[
'name' => __('ID'),
'sort' => 'id',
'class' => 'short',
'data_path' => 'id'
],
[
'name' => __('Owner Org'),
'sort' => 'Organisation',
'data_path' => 'Organisation',
'element' => 'org'
],
[
'name' => __('Name'),
'sort' => 'name',
'data_path' => 'name'
],
[
'name' => __('URL'),
'sort' => 'url',
'data_path' => 'url'
],
[
'name' => __('Description'),
'sort' => 'description',
'data_path' => 'description'
],
[
'name' => __('Pull Orgs'),
'sort' => 'pull_orgs',
'data_path' => 'pull_orgs',
'element' => 'boolean'
],
[
'name' => __('Pull SGs'),
'sort' => 'pull_sharing_groups',
'data_path' => 'pull_sharing_groups',
'element' => 'boolean'
]
];
use Cake\Core\Configure;
echo $this->element('genericElements/IndexTable/index_table', [
'data' => [
'data' => $data,
'top_bar' => [
'children' => [
[
'type' => 'simple',
'children' => [
'data' => [
'type' => 'simple',
'icon' => 'plus',
'text' => __('Add Cerebrate'),
'class' => 'btn btn-primary',
'popover_url' => '/cerebrates/add',
'button' => [
'icon' => 'plus',
]
]
]
],
[
'type' => 'search',
'button' => __('Search'),
'placeholder' => __('Enter value to search'),
'data' => '',
'searchKey' => 'value',
'allowFilering' => true
],
[
'type' => 'table_action',
],
]
],
'fields' => $fields,
'title' => __('Linked Cerebrates'),
'description' => __('You can connect your MISP to one or several Cerebrate instances to act as lookup directories for organisation and sharing group information.'),
'actions' => [
[
'url' => '/cerebrates/view',
'url_params_data_paths' => ['id'],
'icon' => 'eye'
],
[
'open_modal' => '/cerebrates/pull_orgs/[onclick_params_data_path]',
'onclick_params_data_path' => 'id',
'title' => __('Pull all organisations'),
'icon' => 'arrow-circle-down'
],
[
'open_modal' => '/cerebrates/pull_sgs/[onclick_params_data_path]',
'onclick_params_data_path' => 'id',
'title' => __('Pull all sharing groups'),
'icon' => 'arrow-circle-down'
],
[
'open_modal' => '/cerebrates/edit/[onclick_params_data_path]',
'modal_params_data_path' => 'id',
'icon' => 'edit'
],
[
'open_modal' => '/cerebrates/delete/[onclick_params_data_path]',
'modal_params_data_path' => 'id',
'icon' => 'trash'
]
]
]
]);

View File

@ -0,0 +1,68 @@
<?php
echo $this->element(
'/genericElements/SingleViews/single_view',
[
'title' => __('Cerebrate {0}', h($entity->name)),
'data' => $entity,
'fields' => [
[
'key' => __('Id'),
'path' => 'id'
],
[
'key' => __('Name'),
'path' => 'name'
],
[
'key' => __('URL'),
'path' => 'url',
'url' => '{{0}}',
'url_vars' => ['url']
],
[
'key' => __('Owner Organisation'),
'path' => 'org_id',
'pathName' => 'Organisation.name',
'type' => 'model',
'model' => 'organisations'
],
[
'key' => __('Description'),
'path' => 'description'
],
],
// 'side_panels' => [ // FIXME chri missing side-panel
// [
// 'type' => 'logo',
// 'source' => '/img/cerebrate.png',
// 'url' => 'https://github.com/cerebrate-project/cerebrate',
// 'title' => __('The Cerebrate Project'),
// 'img' => [
// 'css' => [
// 'width' => '150px',
// 'height' => '150px'
// ],
// ],
// 'div' => [
// 'css' => [
// 'text-align' => 'right'
// ]
// ]
// ]
// ],
'children' => [
[
'url' => '/cerebrates/preview_orgs/{{0}}/',
'url_params' => ['id'],
'title' => __('Organisations'),
// FIXME chri - 'elementId' => 'preview_orgs_container'
],
[
'url' => '/cerebrates/preview_sharing_groups/{{0}}/',
'url_params' => ['id'],
'title' => __('Sharing Groups'),
// FIXME chri - 'elementId' => 'preview_sgs_container' FIXME chri
],
]
]
);