diff --git a/INSTALL/mysql.sql b/INSTALL/mysql.sql index 545df65..4566f4c 100644 --- a/INSTALL/mysql.sql +++ b/INSTALL/mysql.sql @@ -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 */; -- @@ -308,7 +310,7 @@ CREATE TABLE `sharing_groups` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE `sharing_group_orgs` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `sharing_group_id` int(10) unsigned NOT NULL, `organisation_id` int(10) unsigned NOT NULL, `deleted` tinyint(1) DEFAULT 0, @@ -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 */; diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index 9a47987..e740edd 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -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', [ diff --git a/src/Controller/Component/ACLComponent.php b/src/Controller/Component/ACLComponent.php index 6353613..da06db1 100644 --- a/src/Controller/Component/ACLComponent.php +++ b/src/Controller/Component/ACLComponent.php @@ -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) diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php index 77dec7b..8a4ce5e 100644 --- a/src/Controller/Component/CRUDComponent.php +++ b/src/Controller/Component/CRUDComponent.php @@ -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'); } diff --git a/src/Controller/MetaTemplateFieldsController.php b/src/Controller/MetaTemplateFieldsController.php new file mode 100644 index 0000000..c25b8b4 --- /dev/null +++ b/src/Controller/MetaTemplateFieldsController.php @@ -0,0 +1,23 @@ +CRUD->index([ + 'filters' => ['field', 'type', 'meta_template_id'], + 'quickFilters' => ['field', 'type'] + ]); + if ($this->ParamHandler->isRest()) { + return $this->restResponsePayload; + } + $this->set('metaGroup', 'Administration'); + } +} diff --git a/src/Controller/MetaTemplatesController.php b/src/Controller/MetaTemplatesController.php new file mode 100644 index 0000000..a44a7f9 --- /dev/null +++ b/src/Controller/MetaTemplatesController.php @@ -0,0 +1,50 @@ +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'); + } +} diff --git a/src/Model/Entity/MetaField.php b/src/Model/Entity/MetaField.php new file mode 100644 index 0000000..e091629 --- /dev/null +++ b/src/Model/Entity/MetaField.php @@ -0,0 +1,11 @@ + 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' => [ diff --git a/src/Model/Table/MetaFieldsTable.php b/src/Model/Table/MetaFieldsTable.php new file mode 100644 index 0000000..e0abcab --- /dev/null +++ b/src/Model/Table/MetaFieldsTable.php @@ -0,0 +1,28 @@ +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; + } +} diff --git a/src/Model/Table/MetaTemplateFieldsTable.php b/src/Model/Table/MetaTemplateFieldsTable.php new file mode 100644 index 0000000..4237be4 --- /dev/null +++ b/src/Model/Table/MetaTemplateFieldsTable.php @@ -0,0 +1,30 @@ +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; + } +} diff --git a/src/Model/Table/MetaTemplatesTable.php b/src/Model/Table/MetaTemplatesTable.php new file mode 100644 index 0000000..74c6eb0 --- /dev/null +++ b/src/Model/Table/MetaTemplatesTable.php @@ -0,0 +1,100 @@ +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; + } + + } +} diff --git a/src/Model/Table/OrganisationsTable.php b/src/Model/Table/OrganisationsTable.php index cf41ae6..146d715 100644 --- a/src/Model/Table/OrganisationsTable.php +++ b/src/Model/Table/OrganisationsTable.php @@ -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'); } diff --git a/src/View/Helper/MetaFieldsHelper.php b/src/View/Helper/MetaFieldsHelper.php new file mode 100644 index 0000000..2bd2239 --- /dev/null +++ b/src/View/Helper/MetaFieldsHelper.php @@ -0,0 +1,14 @@ +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') - ) - ) -)); + ] + ] +]); diff --git a/templates/MetaTemplateFields/index.php b/templates/MetaTemplateFields/index.php new file mode 100644 index 0000000..7e88292 --- /dev/null +++ b/templates/MetaTemplateFields/index.php @@ -0,0 +1,45 @@ +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' + ] +]); +?> diff --git a/templates/Organisations/add.php b/templates/Organisations/add.php index 77d4ca8..37fefe7 100644 --- a/templates/Organisations/add.php +++ b/templates/Organisations/add.php @@ -29,6 +29,7 @@ 'field' => 'type' ) ), + 'metaFields' => empty($metaFields) ? [] : $metaFields, 'submit' => array( 'action' => $this->request->getParam('action') ) diff --git a/templates/Organisations/view.php b/templates/Organisations/view.php index e8351ef..d1986ec 100644 --- a/templates/Organisations/view.php +++ b/templates/Organisations/view.php @@ -44,6 +44,7 @@ echo $this->element( 'scope' => 'organisations' ] ], + 'metaFields' => empty($metaFields) ? [] : $metaFields, 'children' => [] ] ); diff --git a/templates/element/genericElements/Form/fieldScaffold.php b/templates/element/genericElements/Form/fieldScaffold.php new file mode 100644 index 0000000..4258ce0 --- /dev/null +++ b/templates/element/genericElements/Form/fieldScaffold.php @@ -0,0 +1,53 @@ +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 = '' . $temp . ''; + } + echo $temp; + // $fieldsArrayForPersistence []= $modelForForm . \Cake\Utility\Inflector::camelize($fieldData['field']); + } else { + echo $fieldData; + } diff --git a/templates/element/genericElements/Form/genericForm.php b/templates/element/genericElements/Form/genericForm.php index 938d92e..d2d3b8d 100644 --- a/templates/element/genericElements/Form/genericForm.php +++ b/templates/element/genericElements/Form/genericForm.php @@ -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 = '' . $temp . ''; - } - $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