mirror of https://github.com/MISP/MISP
new: Various object template improvements
- allow multiple versions of a template to be stored at the same time - select which version is the primary version of a template - disable/enable templates - edit objects with one of the older versions of a template if the object's version requires that - various UI / bug fixespull/2489/head
parent
9eb3ea2114
commit
bb99706cf3
|
@ -513,6 +513,7 @@ CREATE TABLE IF NOT EXISTS object_templates (
|
|||
`version` int(11) NOT NULL,
|
||||
`requirements` text COLLATE utf8_bin,
|
||||
`fixed` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`active` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id),
|
||||
INDEX `user_id` (`user_id`),
|
||||
INDEX `org_id` (`org_id`),
|
||||
|
|
|
@ -20,8 +20,10 @@ class ObjectTemplatesController extends AppController {
|
|||
$this->ObjectTemplate->populateIfEmpty($this->Auth->user());
|
||||
$templates_raw = $this->ObjectTemplate->find('all', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('ObjectTemplate.active' => 1),
|
||||
'fields' => array('id', 'meta-category', 'name', 'description', 'org_id'),
|
||||
'contain' => array('Organisation.name')
|
||||
'contain' => array('Organisation.name'),
|
||||
'sort' => array('ObjectTemplate.name asc')
|
||||
));
|
||||
$templates = array('all' => array());
|
||||
foreach ($templates_raw as $k => $template) {
|
||||
|
@ -30,6 +32,9 @@ class ObjectTemplatesController extends AppController {
|
|||
$templates[$templates_raw[$k]['ObjectTemplate']['meta-category']][] = $template['ObjectTemplate'];
|
||||
$templates['all'][] = $template['ObjectTemplate'];
|
||||
}
|
||||
foreach ($templates as $category => $template_list) {
|
||||
$templates[$category] = Hash::sort($templates[$category], '{n}.name');
|
||||
}
|
||||
$template_categories = array_keys($templates);
|
||||
$this->layout = false;
|
||||
$this->set('template_categories', $template_categories);
|
||||
|
@ -61,6 +66,29 @@ class ObjectTemplatesController extends AppController {
|
|||
}
|
||||
}
|
||||
|
||||
public function delete($id) {
|
||||
if (!$this->request->is('post') && !$this->request->is('put') && !$this->request->is('delete')) {
|
||||
throw new MethodNotAllowedException();
|
||||
}
|
||||
$this->ObjectTemplate->id = $id;
|
||||
if (!$this->ObjectTemplate->exists()) {
|
||||
throw new NotFoundException('Invalid ObjectTemplate');
|
||||
}
|
||||
if ($this->ObjectTemplate->delete()) {
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->saveSuccessResponse('ObjectTemplates', 'admin_delete', $id, $this->response->type());
|
||||
} else {
|
||||
$this->Session->setFlash(__('ObjectTemplate deleted'));
|
||||
}
|
||||
}
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->saveFailResponse('ObjectTemplates', 'admin_delete', $id, $this->ObjectTemplate->validationErrors, $this->response->type());
|
||||
} else {
|
||||
$this->Session->setFlash('ObjectTemplate could not be deleted');
|
||||
}
|
||||
$this->redirect($this->referer());
|
||||
}
|
||||
|
||||
public function viewElements($id, $context = 'all') {
|
||||
$elements = $this->ObjectTemplate->ObjectTemplateElement->find('all', array(
|
||||
'conditions' => array('ObjectTemplateElement.object_template_id' => $id)
|
||||
|
@ -70,7 +98,13 @@ class ObjectTemplatesController extends AppController {
|
|||
$this->render('ajax/view_elements');
|
||||
}
|
||||
|
||||
public function index() {
|
||||
public function index($all = false) {
|
||||
if (!$all || !$this->_isSiteAdmin()) {
|
||||
$this->paginate['conditions'][] = array('ObjectTemplate.active' => 1);
|
||||
$this->set('all', false);
|
||||
} else {
|
||||
$this->set('all', true);
|
||||
}
|
||||
if ($this->_isRest()) {
|
||||
$rules = $this->paginate;
|
||||
unset($rules['limit']);
|
||||
|
@ -78,6 +112,7 @@ class ObjectTemplatesController extends AppController {
|
|||
$objectTemplates = $this->ObjectTemplate->find('all', $rules);
|
||||
return $this->RestResponse->viewData($objectTemplates, $this->response->type());
|
||||
} else {
|
||||
$this->paginate['order'] = array('ObjectTemplate.name' => 'ASC');
|
||||
$objectTemplates = $this->paginate();
|
||||
$this->set('list', $objectTemplates);
|
||||
}
|
||||
|
@ -147,4 +182,21 @@ class ObjectTemplatesController extends AppController {
|
|||
}
|
||||
$this->redirect(array('controller' => 'ObjectTemplates', 'action' => 'index'));
|
||||
}
|
||||
|
||||
public function activate() {
|
||||
$id = $this->request->data['ObjectTemplate']['data'];
|
||||
if (!is_numeric($id)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Template not found.')), 'status' => 200, 'type' => 'json'));
|
||||
$result = $this->ObjectTemplate->setActive($id);
|
||||
if ($result === false) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Template\'s state could not be toggeled.')), 'status' => 200, 'type' => 'json'));
|
||||
}
|
||||
$message = (($result == 1) ? 'activated' : 'disabled');
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Template ' . $message . '.')), 'status' => 200, 'type' => 'json'));
|
||||
}
|
||||
|
||||
public function getToggleField() {
|
||||
if (!$this->request->is('ajax')) throw new MethodNotAllowedException('This action is available via AJAX only.');
|
||||
$this->layout = 'ajax';
|
||||
$this->render('ajax/getToggleField');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,14 +87,29 @@ class ObjectsController extends AppController {
|
|||
throw new NotFoundException('Invalid event.');
|
||||
}
|
||||
$eventId = $event['Event']['id'];
|
||||
$template = $this->MispObject->ObjectTemplate->find('first', array(
|
||||
$templates = $this->MispObject->ObjectTemplate->find('all', array(
|
||||
'conditions' => array('ObjectTemplate.id' => $templateId),
|
||||
'recursive' => -1,
|
||||
'contain' => array(
|
||||
'ObjectTemplateElement'
|
||||
)
|
||||
));
|
||||
$template_version = false;
|
||||
$template = false;
|
||||
foreach ($templates as $temp) {
|
||||
if (!empty($template_version)) {
|
||||
if (intval($template['ObjectTemplate']['version']) > intval($template_version)) {
|
||||
$template = $temp;
|
||||
}
|
||||
} else {
|
||||
$template = $temp;
|
||||
}
|
||||
}
|
||||
$error = false;
|
||||
if (empty($template)) {
|
||||
$error = 'No valid template found to edit the object.';
|
||||
}
|
||||
|
||||
// If we have received a POST request
|
||||
if ($this->request->is('post')) {
|
||||
if (isset($this->request->data['request'])) {
|
||||
|
|
|
@ -779,6 +779,7 @@ class AppModel extends Model {
|
|||
`version` int(11) NOT NULL,
|
||||
`requirements` text COLLATE utf8_bin,
|
||||
`fixed` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`active` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id),
|
||||
INDEX `user_id` (`user_id`),
|
||||
INDEX `org_id` (`org_id`),
|
||||
|
|
|
@ -22,10 +22,6 @@ class ObjectTemplate extends AppModel {
|
|||
)
|
||||
);
|
||||
public $hasMany = array(
|
||||
'Attribute' => array(
|
||||
'className' => 'Attribute',
|
||||
'dependent' => true,
|
||||
),
|
||||
'ObjectTemplateElement' => array(
|
||||
'className' => 'ObjectTemplateElement',
|
||||
'dependent' => true,
|
||||
|
@ -65,14 +61,18 @@ class ObjectTemplate extends AppModel {
|
|||
$file->close();
|
||||
if (!isset($template['version'])) $template['version'] = 1;
|
||||
$current = $this->find('first', array(
|
||||
'fields' => array('MAX(version) AS version', 'uuid'),
|
||||
'conditions' => array('uuid' => $template['uuid']),
|
||||
'recursive' => -1
|
||||
'recursive' => -1,
|
||||
'group' => array('uuid')
|
||||
));
|
||||
if (!empty($current)) $current['ObjectTemplate']['version'] = $current[0]['version'];
|
||||
if (empty($current) || $template['version'] > $current['ObjectTemplate']['version']) {
|
||||
$result = $this->__updateObjectTemplate($template, $current, $user);
|
||||
if ($result === true) {
|
||||
$updated['success'][$result] = array('name' => $template['name'], 'new' => $template['version']);
|
||||
if (!empty($current)) $updated['success'][$result]['old'] = $current['ObjectTemplate']['version'];
|
||||
$temp = array('name' => $template['name'], 'new' => $template['version']);
|
||||
if (!empty($current)) $temp['old'] = $current['ObjectTemplate']['version'];
|
||||
$updated['success'][] = $temp;
|
||||
} else {
|
||||
$updated['fails'][] = array('name' => $template['name'], 'fail' => json_encode($result));
|
||||
}
|
||||
|
@ -90,65 +90,23 @@ class ObjectTemplate extends AppModel {
|
|||
$template['requirements'][$field] = $template[$field];
|
||||
}
|
||||
}
|
||||
if (empty($current)) {
|
||||
$template['user_id'] = $user['id'];
|
||||
$template['org_id'] = $user['org_id'];
|
||||
$template['fixed'] = 1;
|
||||
$this->create();
|
||||
$result = $this->save($template);
|
||||
} else {
|
||||
$fieldsToUpdate = array('version', 'description', 'meta-category', 'name', 'requirements', 'fixed');
|
||||
foreach ($fieldsToUpdate as $field) {
|
||||
if (isset($template[$field]) && $current['ObjectTemplate'][$field] != $template[$field]) {
|
||||
$current['ObjectTemplate'][$field] = $template[$field];
|
||||
}
|
||||
}
|
||||
$result = $this->save($current);
|
||||
}
|
||||
$template['user_id'] = $user['id'];
|
||||
$template['org_id'] = $user['org_id'];
|
||||
$template['fixed'] = 1;
|
||||
$this->create();
|
||||
$result = $this->save($template);
|
||||
if (!$result) {
|
||||
return $this->validationErrors;
|
||||
}
|
||||
$id = $this->id;
|
||||
$existingTemplateElementsTemp = $this->ObjectTemplateElement->find('all', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('object_template_id' => $id)
|
||||
));
|
||||
$existingTemplateElements = array();
|
||||
if (!empty($existingTemplateElementsTemp)) {
|
||||
foreach ($existingTemplateElementsTemp as $k => $v) {
|
||||
$existingTemplateElements[$v['ObjectTemplateElement']['object_relation']] = $v['ObjectTemplateElement'];
|
||||
}
|
||||
}
|
||||
unset($existingTemplateElementsTemp);
|
||||
$this->setActive($id);
|
||||
$fieldsToCompare = array('object_relation', 'type', 'ui-priority', 'categories', 'sane_default', 'values_list', 'multiple');
|
||||
foreach ($template['attributes'] as $k => $attribute) {
|
||||
$attribute['object_relation'] = $k;
|
||||
$attribute = $this->__convertJSONToElement($attribute);
|
||||
if (isset($existingTemplateElements[$k])) {
|
||||
$update_required = false;
|
||||
foreach ($fieldsToCompare as $field) {
|
||||
if (isset($attribute[$field])) {
|
||||
if ($existingTemplateElements[$k][$field] != $attribute[$field]) {
|
||||
$update_required = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($update_required) {
|
||||
$attribute['id'] = $existingTemplateElements[$k]['id'];
|
||||
$attribute['object_template_id'] = $id;
|
||||
$result = $this->ObjectTemplateElement->save(array('ObjectTemplateElement' => $attribute));
|
||||
}
|
||||
if (isset($existingTemplateElements[$k])) unset($existingTemplateElements[$k]);
|
||||
} else {
|
||||
$this->ObjectTemplateElement->create();
|
||||
$attribute['object_template_id'] = $id;
|
||||
$result = $this->ObjectTemplateElement->save(array('ObjectTemplateElement' => $attribute));
|
||||
}
|
||||
}
|
||||
if (!empty($existingTemplateElements)) {
|
||||
foreach ($existingTemplateElements as $k2 => $v2) {
|
||||
$this->ObjectTemplateElement->delete($v2['id']);
|
||||
}
|
||||
$this->ObjectTemplateElement->create();
|
||||
$attribute['object_template_id'] = $id;
|
||||
$result = $this->ObjectTemplateElement->save(array('ObjectTemplateElement' => $attribute));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -232,4 +190,33 @@ class ObjectTemplate extends AppModel {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setActive($id) {
|
||||
$template = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('ObjectTemplate.id' => $id)
|
||||
));
|
||||
if (empty($template)) return false;
|
||||
if ($template['ObjectTemplate']['active']) {
|
||||
$template['ObjectTemplate']['active'] = 0;
|
||||
$this->save($template);
|
||||
return 0;
|
||||
}
|
||||
$similar_templates = $this->find('all', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'ObjectTemplate.uuid' => $template['ObjectTemplate']['uuid'],
|
||||
'NOT' => array(
|
||||
'ObjectTemplate.id' => $template['ObjectTemplate']['id']
|
||||
)
|
||||
)
|
||||
));
|
||||
$template['ObjectTemplate']['active'] = 1;
|
||||
$this->save($template);
|
||||
foreach ($similar_templates as $st) {
|
||||
$st['ObjectTemplate']['active'] = 0;
|
||||
$this->save($st);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,15 @@ class ObjectTemplateElement extends AppModel {
|
|||
|
||||
public function afterFind($results, $primary = false) {
|
||||
foreach ($results as $k => $result) {
|
||||
$results[$k]['ObjectTemplateElement']['categories'] = json_decode($results[$k]['ObjectTemplateElement']['categories'], true);
|
||||
$results[$k]['ObjectTemplateElement']['values_list'] = json_decode($results[$k]['ObjectTemplateElement']['values_list'], true);
|
||||
$results[$k]['ObjectTemplateElement']['sane_default'] = json_decode($results[$k]['ObjectTemplateElement']['sane_default'], true);
|
||||
if (isset($results[$k]['ObjectTemplateElement']['categories'])) {
|
||||
$results[$k]['ObjectTemplateElement']['categories'] = json_decode($results[$k]['ObjectTemplateElement']['categories'], true);
|
||||
}
|
||||
if (isset($results[$k]['ObjectTemplateElement']['values_list'])) {
|
||||
$results[$k]['ObjectTemplateElement']['values_list'] = json_decode($results[$k]['ObjectTemplateElement']['values_list'], true);
|
||||
}
|
||||
if (isset($results[$k]['ObjectTemplateElement']['sane_default'])) {
|
||||
$results[$k]['ObjectTemplateElement']['sane_default'] = json_decode($results[$k]['ObjectTemplateElement']['sane_default'], true);
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
echo $this->Form->create('ObjectTemplate', array('url' => '/ObjectTemplates/activate', 'id' => 'ObjectTemplateIndexForm'));
|
||||
echo $this->Form->input('data', array('label' => false, 'style' => 'display:none;'));
|
||||
echo $this->Form->end();
|
|
@ -16,8 +16,34 @@
|
|||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="hiddenFormDiv">
|
||||
<?php
|
||||
if ($isSiteAdmin) {
|
||||
echo $this->Form->create('ObjectTemplate', array('url' => '/ObjectTemplates/activate'));
|
||||
echo $this->Form->input('data', array('label' => false, 'style' => 'display:none;'));
|
||||
echo $this->Form->end();
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="tabMenuFixedContainer" style="display:inline-block;">
|
||||
<?php
|
||||
if ($isSiteAdmin):
|
||||
?>
|
||||
<span role="button" tabindex="0" aria-label="Enabled" title="Enabled" class="tabMenuFixed tabMenuFixedCenter tabMenuSides useCursorPointer <?php if (!$all) echo 'tabMenuActive';?>" onClick="window.location='/objectTemplates/index'">Enabled</span>
|
||||
<span role="button" tabindex="0" aria-label="All" title="All" class="tabMenuFixed tabMenuFixedCenter tabMenuSides useCursorPointer <?php if ($all) echo 'tabMenuActive';?>" onClick="window.location='/objectTemplates/index/all'">All</span>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<?php
|
||||
if ($isSiteAdmin):
|
||||
?>
|
||||
<th><?php echo $this->Paginator->sort('active');?></th>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<th><?php echo $this->Paginator->sort('id');?></th>
|
||||
<th><?php echo $this->Paginator->sort('name');?></th>
|
||||
<th><?php echo $this->Paginator->sort('uuid');?></th>
|
||||
|
@ -33,6 +59,15 @@ foreach ($list as $template):
|
|||
$td_attributes = 'ondblclick="document.location.href =\'/objectTemplates/view/' . h($template['ObjectTemplate']['id']) . '\'"';
|
||||
?>
|
||||
<tr>
|
||||
<?php
|
||||
if ($isSiteAdmin):
|
||||
?>
|
||||
<td class="short" <?php echo $td_attributes; ?>>
|
||||
<input id="checkBox_<?php echo h($template['ObjectTemplate']['id']); ?>" type="checkbox" onClick="toggleSetting(event, 'activate_object_template', '<?php echo h($template['ObjectTemplate']['id']); ?>')" <?php echo $template['ObjectTemplate']['active'] ? 'checked' : ''; ?>/>
|
||||
</td>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<td class="short" <?php echo $td_attributes; ?>><?php echo h($template['ObjectTemplate']['id']); ?></td>
|
||||
<td class="shortish" <?php echo $td_attributes; ?>>
|
||||
<?php
|
||||
|
@ -67,6 +102,11 @@ foreach ($list as $template):
|
|||
</td>
|
||||
<td class="short action-links">
|
||||
<a href='/objectTemplates/view/<?php echo $template['ObjectTemplate']['id']; ?>' class = "icon-list-alt" title = "View"></a>
|
||||
<?php
|
||||
if ($isSiteAdmin):
|
||||
echo $this->Form->postLink('', array('action' => 'delete', $template['ObjectTemplate']['id']), array('class' => 'icon-trash', 'title' => 'Delete'), __('Are you sure you want to delete template # %s?', $template['ObjectTemplate']['id']));
|
||||
endif;
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
|
@ -88,7 +128,6 @@ endforeach; ?>
|
|||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('side_menu', array('menuList' => 'objectTemplates', 'menuItem' => 'index'));
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<dt>Object Template</dt>
|
||||
<dd>
|
||||
<?php
|
||||
echo Inflector::humanize(h($template['ObjectTemplate']['name']));
|
||||
echo Inflector::humanize(h($template['ObjectTemplate']['name'])) . ' v' . h($template['ObjectTemplate']['version']);
|
||||
?>
|
||||
|
||||
</dd>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d34dd5fb606f1c4d882733d16c16103fe429991c
|
||||
Subproject commit 10b21c6aacb536e7646158f950e6ad972293c830
|
|
@ -162,6 +162,12 @@ function toggleSetting(e, setting, id) {
|
|||
replacementForm = '/favourite_tags/getToggleField/';
|
||||
searchString = 'Adding';
|
||||
break;
|
||||
case 'activate_object_template':
|
||||
formID = '#ObjectTemplateIndexForm';
|
||||
dataDiv = '#ObjectTemplateData';
|
||||
replacementForm = '/ObjectTemplates/getToggleField/';
|
||||
searchString = 'activated';
|
||||
break;
|
||||
}
|
||||
$(dataDiv).val(id);
|
||||
var formData = $(formID).serialize();
|
||||
|
@ -3210,6 +3216,11 @@ $('.add_object_attribute_row').click(function() {
|
|||
});
|
||||
});
|
||||
|
||||
$('.quickToggleCheckbox').toggle(function() {
|
||||
var url = $(this).data('checkbox-url');
|
||||
|
||||
});
|
||||
|
||||
(function(){
|
||||
"use strict";
|
||||
$(".datepicker").datepicker({
|
||||
|
|
Loading…
Reference in New Issue