new: [metaFields] system added
- rework of several internal libraries - append custom fields to objects - templating system to assist users, using JSON files - mapped the FIRST directory as a first testpull/32/head
parent
5859c1baa2
commit
4fd2c3b548
|
@ -61,7 +61,7 @@ CREATE TABLE `alignments` (
|
|||
KEY `organisation_id` (`organisation_id`),
|
||||
CONSTRAINT `alignments_ibfk_1` FOREIGN KEY (`individual_id`) REFERENCES `individuals` (`id`),
|
||||
CONSTRAINT `alignments_ibfk_2` FOREIGN KEY (`organisation_id`) REFERENCES `organisations` (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -74,18 +74,20 @@ DROP TABLE IF EXISTS `auth_keys`;
|
|||
CREATE TABLE `auth_keys` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`authkey` varchar(40) CHARACTER SET ascii DEFAULT NULL,
|
||||
`authkey` varchar(72) CHARACTER SET ascii DEFAULT NULL,
|
||||
`authkey_start` varchar(4) CHARACTER SET ascii DEFAULT NULL,
|
||||
`authkey_end` varchar(4) CHARACTER SET ascii DEFAULT NULL,
|
||||
`created` int(10) unsigned NOT NULL,
|
||||
`valid_until` int(10) unsigned NOT NULL,
|
||||
`expiration` int(10) unsigned NOT NULL,
|
||||
`user_id` int(10) unsigned NOT NULL,
|
||||
`comment` text COLLATE utf8mb4_unicode_ci,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `authkey` (`authkey`),
|
||||
KEY `authkey_start` (`authkey_start`),
|
||||
KEY `authkey_end` (`authkey_end`),
|
||||
KEY `created` (`created`),
|
||||
KEY `valid_until` (`valid_until`),
|
||||
KEY `user_id` (`user_id`),
|
||||
CONSTRAINT `auth_keys_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
KEY `expiration` (`expiration`),
|
||||
KEY `user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -102,17 +104,17 @@ CREATE TABLE `broods` (
|
|||
`url` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`description` text COLLATE utf8mb4_unicode_ci,
|
||||
`organisation_id` int(10) unsigned NOT NULL,
|
||||
`alignment_id` int(10) unsigned NOT NULL,
|
||||
`trusted` tinyint(1) DEFAULT NULL,
|
||||
`pull` tinyint(1) DEFAULT NULL,
|
||||
`skip_proxy` tinyint(1) DEFAULT NULL,
|
||||
`authkey` varchar(40) CHARACTER SET ascii DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `uuid` (`uuid`),
|
||||
KEY `name` (`name`),
|
||||
KEY `url` (`url`),
|
||||
KEY `authkey` (`authkey`),
|
||||
KEY `alignment_id` (`alignment_id`),
|
||||
CONSTRAINT `broods_ibfk_1` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`)
|
||||
KEY `organisation_id` (`organisation_id`),
|
||||
FOREIGN KEY (`organisation_id`) REFERENCES `organisations` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
|
@ -136,7 +138,7 @@ CREATE TABLE `encryption_keys` (
|
|||
KEY `uuid` (`uuid`),
|
||||
KEY `type` (`type`),
|
||||
KEY `expires` (`expires`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -181,7 +183,7 @@ CREATE TABLE `individuals` (
|
|||
KEY `email` (`email`),
|
||||
KEY `first_name` (`first_name`),
|
||||
KEY `last_name` (`last_name`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -226,7 +228,7 @@ CREATE TABLE `organisations` (
|
|||
KEY `nationality` (`nationality`),
|
||||
KEY `sector` (`sector`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -245,7 +247,7 @@ CREATE TABLE `roles` (
|
|||
PRIMARY KEY (`id`),
|
||||
KEY `name` (`name`),
|
||||
KEY `uuid` (`uuid`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -317,6 +319,54 @@ CREATE TABLE `sharing_group_orgs` (
|
|||
KEY `organisation_id` (`organisation_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `meta_fields` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`scope` varchar(191) NOT NULL,
|
||||
`parent_id` int(10) unsigned NOT NULL,
|
||||
`field` varchar(191) NOT NULL,
|
||||
`value` varchar(191) NOT NULL,
|
||||
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `scope` (`scope`),
|
||||
KEY `uuid` (`uuid`),
|
||||
KEY `parent_id` (`parent_id`),
|
||||
KEY `field` (`field`),
|
||||
KEY `value` (`value`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `meta_templates` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`scope` varchar(191) NOT NULL,
|
||||
`name` varchar(191) NOT NULL,
|
||||
`namespace` varchar(191) NOT NULL,
|
||||
`description` text,
|
||||
`version` varchar(191) NOT NULL,
|
||||
`uuid` varchar(40) CHARACTER SET ascii,
|
||||
`source` varchar(191),
|
||||
`enabled` tinyint(1) DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `scope` (`scope`),
|
||||
KEY `source` (`source`),
|
||||
KEY `name` (`name`),
|
||||
KEY `namespace` (`namespace`),
|
||||
KEY `version` (`version`),
|
||||
KEY `uuid` (`uuid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `meta_template_fields` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`field` varchar(191) NOT NULL,
|
||||
`type` varchar(191) NOT NULL,
|
||||
`meta_template_id` int(10) unsigned NOT NULL,
|
||||
`regex` text,
|
||||
`multiple` tinyint(1) DEFAULT 0,
|
||||
`enabled` tinyint(1) DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `meta_template_id` FOREIGN KEY (`meta_template_id`) REFERENCES `meta_templates` (`id`),
|
||||
KEY `field` (`field`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
|
|
|
@ -61,9 +61,13 @@ class AppController extends Controller
|
|||
$this->loadComponent('ParamHandler', [
|
||||
'request' => $this->request
|
||||
]);
|
||||
$this->loadModel('MetaFields');
|
||||
$this->loadModel('MetaTemplates');
|
||||
$this->loadComponent('CRUD', [
|
||||
'request' => $this->request,
|
||||
'table' => $this->{$this->modelClass}
|
||||
'table' => $this->{$this->modelClass},
|
||||
'MetaFields' => $this->MetaFields,
|
||||
'MetaTemplates' => $this->MetaTemplates
|
||||
]);
|
||||
$this->loadComponent('Authentication.Authentication');
|
||||
$this->loadComponent('ACL', [
|
||||
|
|
|
@ -31,6 +31,17 @@ class ACLComponent extends Component
|
|||
// $action == array('AND' => []) - roles with all permissions in the array have access
|
||||
// If we add any new functionality to MISP and we don't add it to this list, it will only be visible to site admins.
|
||||
private $aclList = array(
|
||||
'Broods' => [
|
||||
'add' => ['perm_admin'],
|
||||
'delete' => ['perm_admin'],
|
||||
'edit' => ['perm_admin'],
|
||||
'index' => ['perm_admin'],
|
||||
'view' => ['perm_admin']
|
||||
],
|
||||
'Instance' => [
|
||||
'home' => ['*'],
|
||||
'status' => ['*']
|
||||
],
|
||||
'Pages' => [
|
||||
'display' => ['*']
|
||||
],
|
||||
|
@ -42,7 +53,13 @@ class ACLComponent extends Component
|
|||
'login' => ['*'],
|
||||
'logout' => ['*'],
|
||||
'view' => ['*']
|
||||
]
|
||||
],
|
||||
'MetaTemplates' => [
|
||||
'view' => ['perm_admin'],
|
||||
'enable' => ['perm_admin'],
|
||||
'disable' => ['perm_admin'],
|
||||
'update' => ['perm_admin'],
|
||||
]
|
||||
);
|
||||
|
||||
private function __checkLoggedActions($user, $controller, $action)
|
||||
|
|
|
@ -17,6 +17,8 @@ class CRUDComponent extends Component
|
|||
$this->request = $config['request'];
|
||||
$this->TableAlias = $this->Table->getAlias();
|
||||
$this->ObjectAlias = \Cake\Utility\Inflector::singularize($this->TableAlias);
|
||||
$this->MetaFields = $config['MetaFields'];
|
||||
$this->MetaTemplates = $config['MetaTemplates'];
|
||||
}
|
||||
|
||||
public function index(array $options): void
|
||||
|
@ -34,11 +36,6 @@ class CRUDComponent extends Component
|
|||
if (!empty($options['contain'])) {
|
||||
$query->contain($options['contain']);
|
||||
}
|
||||
if (!empty($conditions)) {
|
||||
$query->where([
|
||||
'OR' => $conditions
|
||||
]);
|
||||
}
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$data = $query->all();
|
||||
$this->Controller->restResponsePayload = $this->Controller->RestResponse->viewData($data, 'json');
|
||||
|
@ -49,8 +46,30 @@ class CRUDComponent extends Component
|
|||
}
|
||||
}
|
||||
|
||||
private function getMetaTemplates()
|
||||
{
|
||||
$metaFields = [];
|
||||
if (!empty($this->Table->metaFields)) {
|
||||
$metaQuery = $this->MetaTemplates->find();
|
||||
$metaQuery->where([
|
||||
'scope' => $this->Table->metaFields,
|
||||
//'enabled' => 1
|
||||
]);
|
||||
$metaQuery->contain(['MetaTemplateFields']);
|
||||
$metaTemplates = $metaQuery->all();
|
||||
foreach ($metaTemplates as $metaTemplate) {
|
||||
foreach ($metaTemplate->meta_template_fields as $field) {
|
||||
$metaFields[$field['field']] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->Controller->set('metaFields', $metaFields);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function add(array $params = []): void
|
||||
{
|
||||
$this->getMetaTemplates();
|
||||
$data = $this->Table->newEmptyEntity();
|
||||
if ($this->request->is('post')) {
|
||||
$input = $this->request->getData();
|
||||
|
@ -62,6 +81,9 @@ class CRUDComponent extends Component
|
|||
$data = $this->Table->patchEntity($data, $input);
|
||||
if ($this->Table->save($data)) {
|
||||
$message = __('{0} added.', $this->ObjectAlias);
|
||||
if (!empty($input['metaFields'])) {
|
||||
$this->saveMetaFields($data->id, $input);
|
||||
}
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($data, 'json');
|
||||
} else {
|
||||
|
@ -72,7 +94,7 @@ class CRUDComponent extends Component
|
|||
$this->Controller->render($params['displayOnSuccess']);
|
||||
return;
|
||||
}
|
||||
$this->Controller->redirect(['action' => 'index']);
|
||||
$this->Controller->redirect(['action' => 'view', $data->id]);
|
||||
}
|
||||
} else {
|
||||
$message = __('{0} could not be added.', $this->ObjectAlias);
|
||||
|
@ -86,12 +108,33 @@ class CRUDComponent extends Component
|
|||
$this->Controller->set('entity', $data);
|
||||
}
|
||||
|
||||
private function saveMetaFields($id, $input)
|
||||
{
|
||||
foreach ($input['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;
|
||||
$this->MetaFields->save($temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(int $id, array $params = []): void
|
||||
{
|
||||
if (empty($id)) {
|
||||
throw new NotFoundException(__('Invalid {0}.', $this->ObjectAlias));
|
||||
}
|
||||
$this->getMetaTemplates();
|
||||
$data = $this->Table->get($id, isset($params['get']) ? $params['get'] : []);
|
||||
$data = $this->getMetaFields($id, $data);
|
||||
if ($this->request->is(['post', 'put'])) {
|
||||
$input = $this->request->getData();
|
||||
if (!empty($params['override'])) {
|
||||
|
@ -102,11 +145,15 @@ class CRUDComponent extends Component
|
|||
$this->Table->patchEntity($data, $this->request->getData());
|
||||
if ($this->Table->save($data)) {
|
||||
$message = __('{0} updated.', $this->ObjectAlias);
|
||||
if (!empty($input['metaFields'])) {
|
||||
$this->MetaFields->deleteAll(['scope' => $this->Table->metaFields, 'parent_id' => $data->id]);
|
||||
$this->saveMetaFields($data->id, $input);
|
||||
}
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($data, 'json');
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
$this->Controller->redirect(['action' => 'index']);
|
||||
$this->Controller->redirect(['action' => 'view', $id]);
|
||||
}
|
||||
} else {
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
|
@ -114,9 +161,22 @@ class CRUDComponent extends Component
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->Controller->set('entity', $data);
|
||||
}
|
||||
|
||||
public function getMetaFields($id, $data)
|
||||
{
|
||||
$query = $this->MetaFields->find();
|
||||
$query->where(['scope' => $this->Table->metaFields, 'parent_id' => $id]);
|
||||
$metaFields = $query->all();
|
||||
$data['metaFields'] = [];
|
||||
foreach($metaFields as $metaField) {
|
||||
$data['metaFields'][$metaField->field] = $metaField->value;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function view(int $id, array $params = []): void
|
||||
{
|
||||
if (empty($id)) {
|
||||
|
@ -124,6 +184,7 @@ class CRUDComponent extends Component
|
|||
}
|
||||
|
||||
$data = $this->Table->get($id, $params);
|
||||
$data = $this->getMetaFields($id, $data);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->Controller->RestResponse->viewData($data, 'json');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Text;
|
||||
use \Cake\Database\Expression\QueryExpression;
|
||||
|
||||
class MetaTemplateFieldsController extends AppController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$this->CRUD->index([
|
||||
'filters' => ['field', 'type', 'meta_template_id'],
|
||||
'quickFilters' => ['field', 'type']
|
||||
]);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Administration');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Text;
|
||||
use \Cake\Database\Expression\QueryExpression;
|
||||
|
||||
class MetaTemplatesController extends AppController
|
||||
{
|
||||
public function update()
|
||||
{
|
||||
$result = $this->MetaTemplates->update();
|
||||
return $this->RestResponse->viewData($result, 'json');
|
||||
}
|
||||
|
||||
public function status()
|
||||
{
|
||||
$data = file_get_contents(APP . 'VERSION.json');
|
||||
$data = json_decode($data, true);
|
||||
$data['user'] = $this->ACL->getUser();
|
||||
return $this->RestResponse->viewData($data, 'json');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->CRUD->index([
|
||||
'filters' => ['name', 'uuid', 'scope'],
|
||||
'quickFilters' => ['name', 'uuid', 'scope'],
|
||||
'contain' => ['MetaTemplateFields']
|
||||
]);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('alignmentScope', 'individuals');
|
||||
$this->set('metaGroup', 'Administration');
|
||||
}
|
||||
|
||||
public function view($id)
|
||||
{
|
||||
$this->CRUD->view($id, [
|
||||
'contain' => ['MetaTemplateFields']
|
||||
]);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Administration');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Entity;
|
||||
|
||||
use App\Model\Entity\AppModel;
|
||||
use Cake\ORM\Entity;
|
||||
|
||||
class MetaField extends AppModel
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Entity;
|
||||
|
||||
use App\Model\Entity\AppModel;
|
||||
use Cake\ORM\Entity;
|
||||
|
||||
class MetaTemplate extends AppModel
|
||||
{
|
||||
|
||||
}
|
|
@ -189,6 +189,28 @@ class AppTable extends Table
|
|||
'skipTopMenu' => 1
|
||||
]
|
||||
]
|
||||
],
|
||||
'MetaTemplates' => [
|
||||
'label' => __('Meta Field Templates'),
|
||||
'url' => '/metaTemplates/index',
|
||||
'children' => [
|
||||
'index' => [
|
||||
'url' => '/metaTemplates/index',
|
||||
'label' => __('List Meta Templates')
|
||||
],
|
||||
'view' => [
|
||||
'url' => '/metaTemplates/view/{{id}}',
|
||||
'label' => __('View Meta Template'),
|
||||
'actions' => ['delete', 'edit', 'view'],
|
||||
'skipTopMenu' => 1
|
||||
],
|
||||
'delete' => [
|
||||
'url' => '/metaTemplates/delete/{{id}}',
|
||||
'label' => __('Delete Meta Template'),
|
||||
'actions' => ['delete', 'edit', 'view'],
|
||||
'skipTopMenu' => 1
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
'Cerebrate' => [
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
|
||||
class MetaFieldsTable extends AppTable
|
||||
{
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->addBehavior('UUID');
|
||||
$this->setDisplayField('field');
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
$validator
|
||||
->notEmptyString('scope')
|
||||
->notEmptyString('field')
|
||||
->notEmptyString('uuid')
|
||||
->notEmptyString('value')
|
||||
->requirePresence(['scope', 'field', 'value', 'uuid'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
|
||||
class MetaTemplateFieldsTable extends AppTable
|
||||
{
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->BelongsTo(
|
||||
'MetaTemplates'
|
||||
);
|
||||
$this->setDisplayField('field');
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
$validator
|
||||
->notEmptyString('field')
|
||||
->notEmptyString('type')
|
||||
->numeric('meta_template_id')
|
||||
->notBlank('meta_template_id')
|
||||
->requirePresence(['meta_template_id', 'field', 'type'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
|
||||
class MetaTemplatesTable extends AppTable
|
||||
{
|
||||
public $metaFields = true;
|
||||
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->hasMany(
|
||||
'MetaTemplateFields',
|
||||
[
|
||||
'foreignKey' => 'meta_template_id'
|
||||
]
|
||||
);
|
||||
$this->setDisplayField('field');
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
$validator
|
||||
->notEmptyString('scope')
|
||||
->notEmptyString('name')
|
||||
->notEmptyString('namespace')
|
||||
->notEmptyString('uuid')
|
||||
->notEmptyString('version')
|
||||
->notEmptyString('source')
|
||||
->requirePresence(['scope', 'source', 'version', 'uuid', 'name', 'namespace'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
$paths = [
|
||||
ROOT . '/libraries/default/meta_fields/',
|
||||
ROOT . '/libraries/custom/meta_fields/'
|
||||
];
|
||||
$files_processed = [];
|
||||
foreach ($paths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$files = scandir($path);
|
||||
foreach ($files as $k => $file) {
|
||||
if (substr($file, -5) === '.json') {
|
||||
$files_processed[] = $file;
|
||||
$this->loadMetaFile($path . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $files_processed;
|
||||
}
|
||||
|
||||
public function loadMetaFile(String $filePath)
|
||||
{
|
||||
if (file_exists($filePath)) {
|
||||
$contents = file_get_contents($filePath);
|
||||
$metaTemplate = json_decode($contents, true);
|
||||
if (!empty($metaTemplate) && !empty($metaTemplate['uuid']) && !empty($metaTemplate['version'])) {
|
||||
$query = $this->find();
|
||||
$query->where(['uuid' => $metaTemplate['uuid']]);
|
||||
$template = $query->first();
|
||||
if (empty($template)) {
|
||||
$template = $this->newEntity($metaTemplate);
|
||||
$result = $this->save($template);
|
||||
if (!$result) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($template->version >= $metaTemplate['version']) {
|
||||
return true;
|
||||
}
|
||||
foreach (['version', 'source', 'name', 'namespace', 'scope', 'description'] as $field) {
|
||||
$template->{$field} = $metaTemplate[$field];
|
||||
}
|
||||
$result = $this->save($template);
|
||||
if (!$result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
$this->MetaTemplateFields->deleteAll(['meta_template_id' => $template->id]);
|
||||
foreach ($metaTemplate['metaFields'] as $metaField) {
|
||||
$metaField['meta_template_id'] = $template->id;
|
||||
$metaField = $this->MetaTemplateFields->newEntity($metaField);
|
||||
$this->MetaTemplateFields->save($metaField);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@ use Cake\Validation\Validator;
|
|||
|
||||
class OrganisationsTable extends AppTable
|
||||
{
|
||||
public $metaFields = 'organisation';
|
||||
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
|
@ -25,6 +27,13 @@ class OrganisationsTable extends AppTable
|
|||
'conditions' => ['owner_type' => 'organisation']
|
||||
]
|
||||
);
|
||||
$this->hasMany(
|
||||
'MetaFields',
|
||||
[
|
||||
'foreignKey' => 'parent_id',
|
||||
'conditions' => ['scope' => 'organisation']
|
||||
]
|
||||
);
|
||||
$this->setDisplayField('name');
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\View\Helper;
|
||||
|
||||
use Cake\View\Helper;
|
||||
use Cake\Utility\Hash;
|
||||
|
||||
class MetaFieldsHelper extends Helper
|
||||
{
|
||||
public function generate($form, $metaField)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'data' => array(
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'description' => __('Authkeys are used for API access. A user can have more than one authkey, so if you would like to use separate keys per tool that queries Cerebrate, add additional keys. Use the comment field to make identifying your keys easier.'),
|
||||
'fields' => array(
|
||||
array(
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'user_id',
|
||||
'label' => __('User'),
|
||||
'options' => $dropdownData['user'],
|
||||
'type' => 'dropdown'
|
||||
),
|
||||
array(
|
||||
],
|
||||
[
|
||||
'field' => 'comment'
|
||||
),
|
||||
array(
|
||||
],
|
||||
[
|
||||
'field' => 'expiration',
|
||||
'label' => 'Expiration'
|
||||
)
|
||||
),
|
||||
'submit' => array(
|
||||
]
|
||||
],
|
||||
'submit' => [
|
||||
'action' => $this->request->getParam('action')
|
||||
)
|
||||
)
|
||||
));
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?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'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => __('Field'),
|
||||
'sort' => 'field',
|
||||
'data_path' => 'field',
|
||||
],
|
||||
[
|
||||
'name' => __('Type'),
|
||||
'sort' => 'type',
|
||||
'data_path' => 'type',
|
||||
],
|
||||
[
|
||||
'name' => __('Multiple values'),
|
||||
'sort' => 'multiple',
|
||||
'data_path' => 'multiple',
|
||||
'field' => 'textarea'
|
||||
],
|
||||
[
|
||||
'name' => __('Validation regex'),
|
||||
'sort' => 'regex',
|
||||
'data_path' => 'regex'
|
||||
]
|
||||
],
|
||||
'title' => __('Meta Template Fields'),
|
||||
'description' => __('The various fields that the given template contans. When a meta template is enabled, the fields are automatically appended to the appropriate object.'),
|
||||
'pull' => 'right'
|
||||
]
|
||||
]);
|
||||
?>
|
|
@ -29,6 +29,7 @@
|
|||
'field' => 'type'
|
||||
)
|
||||
),
|
||||
'metaFields' => empty($metaFields) ? [] : $metaFields,
|
||||
'submit' => array(
|
||||
'action' => $this->request->getParam('action')
|
||||
)
|
||||
|
|
|
@ -44,6 +44,7 @@ echo $this->element(
|
|||
'scope' => 'organisations'
|
||||
]
|
||||
],
|
||||
'metaFields' => empty($metaFields) ? [] : $metaFields,
|
||||
'children' => []
|
||||
]
|
||||
);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
if (is_array($fieldData)) {
|
||||
if (empty($fieldData['type'])) {
|
||||
$fieldData['type'] = 'text';
|
||||
}
|
||||
$fieldTemplate = 'genericField';
|
||||
if (file_exists(ROOT . '/templates/element/genericElements/Form/Fields/' . $fieldData['type'] . 'Field.php')) {
|
||||
$fieldTemplate = $fieldData['type'] . 'Field';
|
||||
}
|
||||
if (empty($fieldData['label'])) {
|
||||
$fieldData['label'] = \Cake\Utility\Inflector::humanize($fieldData['field']);
|
||||
}
|
||||
if (!empty($fieldDesc[$fieldData['field']])) {
|
||||
$fieldData['label'] .= $this->element(
|
||||
'genericElements/Form/formInfo', array(
|
||||
'field' => $fieldData,
|
||||
'fieldDesc' => $fieldDesc[$fieldData['field']],
|
||||
'modelForForm' => $modelForForm
|
||||
)
|
||||
);
|
||||
}
|
||||
$params = array();
|
||||
if (!empty($fieldData['class'])) {
|
||||
if (is_array($fieldData['class'])) {
|
||||
$class = implode(' ', $fieldData['class']);
|
||||
} else {
|
||||
$class = $fieldData['class'];
|
||||
}
|
||||
$params['class'] = $class;
|
||||
} else {
|
||||
$params['class'] = '';
|
||||
}
|
||||
if (empty($fieldData['type']) || $fieldData['type'] !== 'checkbox' ) {
|
||||
$params['class'] .= ' form-control';
|
||||
}
|
||||
//$params['class'] = sprintf('form-control %s', $params['class']);
|
||||
foreach ($fieldData as $k => $fd) {
|
||||
if (!isset($simpleFieldWhitelist) || in_array($k, $simpleFieldWhitelist) || strpos($k, 'data-') === 0) {
|
||||
$params[$k] = $fd;
|
||||
}
|
||||
}
|
||||
$temp = $this->element('genericElements/Form/Fields/' . $fieldTemplate, array(
|
||||
'fieldData' => $fieldData,
|
||||
'params' => $params
|
||||
));
|
||||
if (!empty($fieldData['hidden'])) {
|
||||
$temp = '<span class="hidden">' . $temp . '</span>';
|
||||
}
|
||||
echo $temp;
|
||||
// $fieldsArrayForPersistence []= $modelForForm . \Cake\Utility\Inflector::camelize($fieldData['field']);
|
||||
} else {
|
||||
echo $fieldData;
|
||||
}
|
|
@ -16,10 +16,10 @@
|
|||
h(\Cake\Utility\Inflector::singularize(\Cake\Utility\Inflector::classify($this->request->getParam('controller')))) :
|
||||
h($data['model']);
|
||||
$fieldsString = '';
|
||||
$simpleFieldWhitelist = array(
|
||||
$simpleFieldWhitelist = [
|
||||
'default', 'type', 'placeholder', 'label', 'empty', 'rows', 'div', 'required'
|
||||
);
|
||||
$fieldsArrayForPersistence = array();
|
||||
];
|
||||
//$fieldsArrayForPersistence = array();
|
||||
if (empty($data['url'])) {
|
||||
$data['url'] = ["controller" => $this->request->getParam('controller'), "action" => $this->request->getParam('url')];
|
||||
}
|
||||
|
@ -47,67 +47,29 @@
|
|||
if (isset($fieldData['requirements']) && !$fieldData['requirements']) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($fieldData)) {
|
||||
if (empty($fieldData['type'])) {
|
||||
$fieldData['type'] = 'text';
|
||||
}
|
||||
$fieldTemplate = 'genericField';
|
||||
if (file_exists(ROOT . '/templates/element/genericElements/Form/Fields/' . $fieldData['type'] . 'Field.php')) {
|
||||
$fieldTemplate = $fieldData['type'] . 'Field';
|
||||
}
|
||||
if (empty($fieldData['label'])) {
|
||||
$fieldData['label'] = \Cake\Utility\Inflector::humanize($fieldData['field']);
|
||||
}
|
||||
if (!empty($fieldDesc[$fieldData['field']])) {
|
||||
$fieldData['label'] .= $this->element(
|
||||
'genericElements/Form/formInfo', array(
|
||||
'field' => $fieldData,
|
||||
'fieldDesc' => $fieldDesc[$fieldData['field']],
|
||||
'modelForForm' => $modelForForm
|
||||
)
|
||||
);
|
||||
}
|
||||
$params = array();
|
||||
if (!empty($fieldData['class'])) {
|
||||
if (is_array($fieldData['class'])) {
|
||||
$class = implode(' ', $fieldData['class']);
|
||||
} else {
|
||||
$class = $fieldData['class'];
|
||||
}
|
||||
$params['class'] = $class;
|
||||
} else {
|
||||
$params['class'] = '';
|
||||
}
|
||||
if (empty($fieldData['type']) || $fieldData['type'] !== 'checkbox' ) {
|
||||
$params['class'] .= ' form-control';
|
||||
}
|
||||
//$params['class'] = sprintf('form-control %s', $params['class']);
|
||||
foreach ($fieldData as $k => $fd) {
|
||||
if (in_array($k, $simpleFieldWhitelist) || strpos($k, 'data-') === 0) {
|
||||
$params[$k] = $fd;
|
||||
}
|
||||
}
|
||||
$temp = $this->element('genericElements/Form/Fields/' . $fieldTemplate, array(
|
||||
$fieldsString .= $this->element(
|
||||
'genericElements/Form/fieldScaffold', [
|
||||
'fieldData' => $fieldData,
|
||||
'params' => $params
|
||||
));
|
||||
if (!empty($fieldData['hidden'])) {
|
||||
$temp = '<span class="hidden">' . $temp . '</span>';
|
||||
}
|
||||
$fieldsString .= $temp;
|
||||
$fieldsArrayForPersistence []= $modelForForm . \Cake\Utility\Inflector::camelize($fieldData['field']);
|
||||
} else {
|
||||
$fieldsString .= $fieldData;
|
||||
}
|
||||
'form' => $this->Form,
|
||||
'simpleFieldWhitelist' => $simpleFieldWhitelist
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
$metaFieldString = '';
|
||||
if (!empty($data['metaFields'])) {
|
||||
foreach ($data['metaFields'] as $metaField) {
|
||||
$metaFieldString .= $metaField;
|
||||
$metaField['label'] = \Cake\Utility\Inflector::humanize($metaField['field']);
|
||||
$metaField['field'] = 'metaFields.' . $metaField['field'];
|
||||
$metaFieldString .= $this->element(
|
||||
'genericElements/Form/fieldScaffold', [
|
||||
'fieldData' => $metaField->toArray(),
|
||||
'form' => $this->Form
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
$submitButtonData = array('model' => $modelForForm, 'formRandomValue' => $formRandomValue);
|
||||
$submitButtonData = ['model' => $modelForForm, 'formRandomValue' => $formRandomValue];
|
||||
if (!empty($data['submit'])) {
|
||||
$submitButtonData = array_merge($submitButtonData, $data['submit']);
|
||||
}
|
||||
|
@ -125,7 +87,7 @@
|
|||
$actionName = h(\Cake\Utility\Inflector::humanize($this->request->getParam('action')));
|
||||
$modelName = h(\Cake\Utility\Inflector::humanize(\Cake\Utility\Inflector::singularize($this->request->getParam('controller'))));
|
||||
if (!empty($ajax)) {
|
||||
echo $this->element('genericElements/genericModal', array(
|
||||
echo $this->element('genericElements/genericModal', [
|
||||
'title' => empty($data['title']) ? sprintf('%s %s', $actionName, $modelName) : h($data['title']),
|
||||
'body' => sprintf(
|
||||
'%s%s%s%s%s%s',
|
||||
|
@ -136,15 +98,20 @@
|
|||
$ajaxFlashMessage,
|
||||
$formCreate,
|
||||
$fieldsString,
|
||||
$formEnd,
|
||||
$metaFieldString
|
||||
$this->element(
|
||||
'genericElements/accordion_scaffold', [
|
||||
'body' => $metaFieldString,
|
||||
'title' => 'Meta fields'
|
||||
]
|
||||
),
|
||||
$formEnd
|
||||
),
|
||||
'actionButton' => $this->element('genericElements/Form/submitButton', $submitButtonData),
|
||||
'class' => 'modal-lg'
|
||||
));
|
||||
]);
|
||||
} else {
|
||||
echo sprintf(
|
||||
'%s<h2>%s</h2>%s%s%s%s%s%s%s%s',
|
||||
'%s<h2>%s</h2>%s%s%s%s%s%s%s%s%s',
|
||||
empty($ajax) ? '<div class="col-8">' : '',
|
||||
empty($data['title']) ? sprintf('%s %s', $actionName, $modelName) : h($data['title']),
|
||||
$formCreate,
|
||||
|
@ -154,9 +121,16 @@
|
|||
$data['description']
|
||||
),
|
||||
$fieldsString,
|
||||
$this->element(
|
||||
'genericElements/accordion_scaffold', [
|
||||
'body' => $metaFieldString,
|
||||
'title' => 'Meta fields'
|
||||
]
|
||||
),
|
||||
$this->element('genericElements/Form/submitButton', $submitButtonData),
|
||||
//$metaFieldString,
|
||||
$formEnd,
|
||||
$metaFieldString,
|
||||
'<br /><br />',
|
||||
empty($ajax) ? '</div>' : ''
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
<?php
|
||||
debug($row);
|
||||
debug($row['organisation']);
|
||||
debug($this->Hash->extract($row, 'organisation'));
|
||||
debug($field['data_path']);
|
||||
$orgs = $this->Hash->extract($row, $field['data_path']);
|
||||
if (!isset($field['fields']['allow_picture'])) {
|
||||
$field['fields']['allow_picture'] = true;
|
||||
|
@ -16,7 +20,7 @@
|
|||
$i++;
|
||||
if (!empty($org['id']) || !empty($org['name'])) {
|
||||
if ($field['fields']['allow_picture'] && !empty($org['id'])) {
|
||||
echo $this->OrgImg->getOrgImg(array('name' => $org['name'], 'id' => $org['id'], 'size' => 24));
|
||||
//echo $this->OrgImg->getOrgImg(array('name' => $org['name'], 'id' => $org['id'], 'size' => 24));
|
||||
} else {
|
||||
echo sprintf(
|
||||
'<a href="%s/organisations/view/%s">%s</a>',
|
||||
|
@ -30,7 +34,7 @@
|
|||
}
|
||||
} else {
|
||||
if ($field['fields']['allow_picture']) {
|
||||
echo $this->OrgImg->getOrgImg(array('name' => $field['fields']['default_org'], 'size' => 24));
|
||||
//echo $this->OrgImg->getOrgImg(array('name' => $field['fields']['default_org'], 'size' => 24));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?php
|
||||
$value = Cake\Utility\Hash::extract($data, $field['path']);
|
||||
$string = empty($value[0]) ? '' : $value[0];
|
||||
if (!empty($field['raw'])) {
|
||||
$string = $field['raw'];
|
||||
} else {
|
||||
$value = Cake\Utility\Hash::extract($data, $field['path']);
|
||||
$string = empty($value[0]) ? '' : $value[0];
|
||||
}
|
||||
if (!empty($field['url'])) {
|
||||
if (!empty($field['url_vars'])) {
|
||||
if (!is_array($field['url_vars'])) {
|
||||
|
|
|
@ -43,6 +43,23 @@
|
|||
);
|
||||
}
|
||||
}
|
||||
if (!empty($data['metaFields'])) {
|
||||
foreach ($data['metaFields'] as $metaField => $value) {
|
||||
$listElements .= sprintf(
|
||||
'<tr class="row"><td class="col-sm-2 font-weight-bold">%s</td><td class="col-sm-10">%s</td></tr>',
|
||||
h($metaField),
|
||||
$this->element(
|
||||
'/genericElements/SingleViews/Fields/genericField',
|
||||
[
|
||||
'data' => $value,
|
||||
'field' => [
|
||||
'raw' => $value
|
||||
]
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
$ajaxLists = '';
|
||||
if (!empty($children)) {
|
||||
foreach ($children as $child) {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$randomId = Cake\Utility\Security::randomString(8);
|
||||
?>
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header" id="heading-<?= $randomId ?>">
|
||||
<h5 class="mb0"><a href="#" class="btn btn-link" data-toggle="collapse" data-target="#view-child-<?= $randomId ?>" aria-expanded="true" aria-controls="collapseOne"><?= h($title) ?></a></h5>
|
||||
</div>
|
||||
<div class="collapse collapsed" id="view-child-<?= $randomId ?>" data-parent="#accordion" labelledby="heading-<?= $randomId ?>">
|
||||
<div id="view-child-body-<?= $randomId ?>" class="card-body" data-load-on="ready"><?= $body ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue