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 test
pull/32/head
iglocska 2020-09-28 01:25:07 +02:00
parent 5859c1baa2
commit 4fd2c3b548
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
24 changed files with 647 additions and 105 deletions

View File

@ -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 */;

View File

@ -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', [

View File

@ -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)

View File

@ -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');
}

View File

@ -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');
}
}

View File

@ -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');
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Model\Entity;
use App\Model\Entity\AppModel;
use Cake\ORM\Entity;
class MetaField extends AppModel
{
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Model\Entity;
use App\Model\Entity\AppModel;
use Cake\ORM\Entity;
class MetaTemplate extends AppModel
{
}

View File

@ -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' => [

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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');
}

View File

@ -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 ;
}
}

View File

@ -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')
)
)
));
]
]
]);

View File

@ -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'
]
]);
?>

View File

@ -29,6 +29,7 @@
'field' => 'type'
)
),
'metaFields' => empty($metaFields) ? [] : $metaFields,
'submit' => array(
'action' => $this->request->getParam('action')
)

View File

@ -44,6 +44,7 @@ echo $this->element(
'scope' => 'organisations'
]
],
'metaFields' => empty($metaFields) ? [] : $metaFields,
'children' => []
]
);

View File

@ -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;
}

View File

@ -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>' : ''
);
}

View File

@ -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));
}
}
}

View File

@ -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'])) {

View File

@ -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) {

View File

@ -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>