Several features finished

- first version of templating system complete
- first version of freetext importer complete
- first version of mass attribute replace tool complete

- some UI changes
pull/274/head^2
iglocska 2014-07-19 15:09:37 +02:00
parent 893ef5a129
commit ab5b9a9dae
13 changed files with 318 additions and 14 deletions

View File

@ -1697,9 +1697,13 @@ class AttributesController extends AppController {
}
public function generateCorrelation() {
$start = microtime(true);
if (!self::_isSiteAdmin()) throw new NotFoundException();
$k = $this->Attribute->generateCorrelation();
$this->Session->setFlash(__('All done. ' . $k . ' attributes processed.'));
$time_elapsed_us = microtime(true) - $start;
debug($time_elapsed_us);
throw new Exception();
$this->redirect(array('controller' => 'pages', 'action' => 'display', 'administration'));
}
@ -1794,4 +1798,118 @@ class AttributesController extends AppController {
$fieldURL = ucfirst($field);
$this->render('ajax/attributeEdit' . $fieldURL . 'Form');
}
public function attributeReplace($id) {
if (!$this->userRole['perm_add']) {
throw new MethodNotAllowedException('Event not found or you don\'t have permissions to create attributes');
}
$event = $this->Attribute->Event->find('first', array(
'conditions' => array('Event.id' => $id),
'fields' => array('id', 'orgc', 'distribution'),
'recursive' => -1
));
if (empty($event) || (!$this->_isSiteAdmin() && ($event['Event']['orgc'] != $this->Auth->user('org') || !$this->userRole['perm_add']))) throw new MethodNotAllowedException('Event not found or you don\'t have permissions to create attributes');
$this->set('event_id', $id);
if ($this->request->is('get')) {
$this->layout = 'ajax';
$this->request->data['Attribute']['event_id'] = $id;
// combobox for types
$types = array_keys($this->Attribute->typeDefinitions);
$types = $this->_arrayToValuesIndexArray($types);
$this->set('types', $types);
// combobos for categories
$categories = $this->Attribute->validate['category']['rule'][1];
array_pop($categories);
$categories = $this->_arrayToValuesIndexArray($categories);
$this->set('categories', compact('categories'));
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
}
if ($this->request->is('post')) {
if (!$this->request->is('ajax')) throw new MethodNotAllowedException('This action can only be accessed via AJAX.');
$newValues = explode(PHP_EOL, $this->request->data['Attribute']['value']);
$category = $this->request->data['Attribute']['category'];
$type = $this->request->data['Attribute']['type'];
$to_ids = $this->request->data['Attribute']['to_ids'];
if (!$this->_isSiteAdmin() && $this->Auth->user('org') != $event['Event']['orgc'] && !$this->userRole['perm_add']) throw new MethodNotAllowedException('You are not authorised to do that.');
$oldAttributes = $this->Attribute->find('all', array(
'conditions' => array(
'event_id' => $id,
'category' => $category,
'type' => $type,
),
'fields' => array('id', 'event_id', 'category', 'type', 'value'),
'recursive' => -1,
));
$results = array('untouched' => count($oldAttributes), 'created' => 0, 'deleted' => 0, 'createdFail' => 0, 'deletedFail' => 0);
foreach ($newValues as &$value) {
$value = trim($value);
$found = false;
foreach ($oldAttributes as &$old) {
if ($value == $old['Attribute']['value']) {
$found = true;
}
}
if (!$found) {
$attribute = array(
'value' => $value,
'event_id' => $id,
'category' => $category,
'type' => $type,
'distribution' => $event['Event']['distribution'],
'to_ids' => $to_ids,
);
$this->Attribute->create();
if ($this->Attribute->save(array('Attribute' => $attribute))) {
$results['created']++;
} else {
$results['createdFail']++;
}
}
}
foreach ($oldAttributes as &$old) {
if (!in_array($old['Attribute']['value'], $newValues)) {
if ($this->Attribute->delete($old['Attribute']['id'])) {
$results['deleted']++;
$results['untouched']--;
} else {
$results['deletedFail']++;
}
}
}
$message = '';
$success = true;
if (($results['created'] > 0 || $results['deleted'] > 0) && $results['createdFail'] == 0 && $results['deletedFail'] == 0) {
$message .= 'Update completed without any issues.';
} else {
$message .= 'Update completed with some errors.';
$success = false;
}
if ($results['created']) $message .= $results['created'] . ' attribute' . $this->__checkCountForOne($results['created']) . ' created. ';
if ($results['createdFail']) $message .= $results['createdFail'] . ' attribute' . $this->__checkCountForOne($results['createdFail']) . ' could not be created. ';
if ($results['deleted']) $message .= $results['deleted'] . ' attribute' . $this->__checkCountForOne($results['deleted']) . ' deleted.';
if ($results['deletedFail']) $message .= $results['deletedFail'] . ' attribute' . $this->__checkCountForOne($results['deletedFail']) . ' could not be deleted. ';
$message .= $results['untouched'] . ' attributes left untouched. ';
$this->autoRender = false;
$this->layout = 'ajax';
if ($success) return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $message)),'status'=>200));
else return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => $message)),'status'=>200));
}
}
private function __checkCountForOne($number) {
if ($number != 1) return 's';
return '';
}
}

View File

@ -2332,7 +2332,6 @@ class EventsController extends AppController {
$this->set('defaultCategories', $defaultCategories);
$this->set('typeCategoryMapping', $typeCategoryMapping);
$this->set('resultArray', $resultArray);
//$this->autoRender = false;
$this->render('free_text_results');
}
}
@ -2364,5 +2363,5 @@ class EventsController extends AppController {
} else {
throw new MethodNotAllowedException();
}
}
}
}

View File

@ -970,6 +970,7 @@ class Attribute extends AppModel {
'Attribute.type !=' => 'comment',
)),
'recursive' => 0,
//'contain' => 'Event',
//'fields' => '', // we want to have the Attribute AND Event, so do not filter here
);
// search for the related attributes for that "value(1|2)"

View File

@ -0,0 +1,153 @@
<div class="attribute_replace">
<?php
echo $this->Form->create('Attribute', array('id'));
?>
<fieldset>
<legend><?php echo __('Attribute Replace Tool'); ?></legend>
<div class="add_attribute_fields">
<p>Choose a category and a type, then paste a list of IOCs that match the selection into the field below. This will delete all of the attributes not found in the new inserted list, whilst creating the attributes that are in the new list but don't exist as attributes. Found matches will be left untouched.</p>
<?php
echo $this->Form->hidden('event_id');
echo $this->Form->input('category', array(
'empty' => '(choose one)'
));
echo $this->Form->input('type', array(
'empty' => '(first choose category)'
));
echo $this->Form->input('to_ids', array(
'type' => 'checkbox',
'label' => 'Mark all new attributes as to IDS',
));
echo $this->Form->input('value', array(
'type' => 'textarea',
'error' => array('escape' => false),
'div' => 'input clear',
'class' => 'input-xxlarge',
'label' => 'Values'
));
$this->Js->get('#AttributeCategory')->event('change', 'formCategoryChanged("#AttributeCategory")');
?>
<div class="input clear"></div>
</div>
</fieldset>
<p style="color:red;font-weight:bold;display:none;" id="warning-message">Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.</p>
<div class="overlay_spacing">
<table>
<tr>
<td style="vertical-align:top">
<span id="submitButton" class="btn btn-primary" onClick="submitPopoverForm('<?php echo $event_id;?>', 'replaceAttributes')">Submit</span>
</td>
<td style="width:540px;">
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message">Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.</p>
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="cancel_attribute_add">Cancel</span>
</td>
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
</div>
<script type="text/javascript">
//
//Generate Category / Type filtering array
//
var category_type_mapping = new Array();
<?php
foreach ($categoryDefinitions as $category => $def) {
echo "category_type_mapping['" . addslashes($category) . "'] = {";
$first = true;
foreach ($def['types'] as $type) {
if ($first) $first = false;
else echo ', ';
echo "'" . addslashes($type) . "' : '" . addslashes($type) . "'";
}
echo "}; \n";
}
?>
function formCategoryChanged(id) {
// fill in the types
var options = $('#AttributeType').prop('options');
$('option', $('#AttributeType')).remove();
$.each(category_type_mapping[$('#AttributeCategory').val()], function(val, text) {
options[options.length] = new Option(text, val);
});
// enable the form element
$('#AttributeType').prop('disabled', false);
}
//
//Generate tooltip information
//
var formInfoValues = new Array();
var fieldsArray = new Array('AttributeCategory', 'AttributeType');
<?php
foreach ($typeDefinitions as $type => $def) {
$info = isset($def['formdesc']) ? $def['formdesc'] : $def['desc'];
echo "formInfoValues['" . addslashes($type) . "'] = \"" . addslashes($info) . "\";\n"; // as we output JS code we need to add slashes
}
foreach ($categoryDefinitions as $category => $def) {
$info = isset($def['formdesc']) ? $def['formdesc'] : $def['desc'];
echo "formInfoValues['" . addslashes($category) . "'] = \"" . addslashes($info) . "\";\n"; // as we output JS code we need to add slashes
}
?>
$(document).ready(function() {
$("#AttributeType, #AttributeCategory").on('mouseover', function(e) {
var $e = $(e.target);
if ($e.is('option')) {
$('#'+e.currentTarget.id).popover('destroy');
$('#'+e.currentTarget.id).popover({
trigger: 'focus',
placement: 'right',
container: 'body',
content: formInfoValues[$e.val()],
}).popover('show');
}
});
$("input, label").on('mouseleave', function(e) {
$('#'+e.currentTarget.id).popover('destroy');
});
$("input, label").on('mouseover', function(e) {
var $e = $(e.target);
$('#'+e.currentTarget.id).popover('destroy');
$('#'+e.currentTarget.id).popover({
trigger: 'focus',
placement: 'right',
container: 'body',
}).popover('show');
});
// workaround for browsers like IE and Chrome that do now have an onmouseover on the 'options' of a select.
// disadvangate is that user needs to click on the item to see the tooltip.
// no solutions exist, except to generate the select completely using html.
$("#AttributeType, #AttributeCategory").on('change', function(e) {
if (this.id === "AttributeCategory") {
var select = document.getElementById("AttributeCategory");
if (select.value === 'Attribution' || select.value === 'Targeting data') {
$("#warning-message").show();
} else {
$("#warning-message").hide();
}
}
var $e = $(e.target);
$('#'+e.currentTarget.id).popover('destroy');
$('#'+e.currentTarget.id).popover({
trigger: 'focus',
placement: 'right',
container: 'body',
content: formInfoValues[$e.val()],
}).popover('show');
});
$('#cancel_attribute_add').click(function() {
cancelPopoverForm();
});
});
</script>
<?php echo $this->Js->writeBuffer(); // Write cached scripts

View File

@ -65,6 +65,7 @@
<div class="tabMenu tabMenuToolsBlock noPrint">
<span id="create-button" title="Populate using a template" class="icon-list-alt useCursorPointer" onClick="getPopup(<?php echo $event['Event']['id']; ?>, 'templates', 'templateChoices');"></span>
<span id="freetext-button" title="Populate using the freetext import tool" class="icon-exclamation-sign useCursorPointer" onClick="getPopup(<?php echo $event['Event']['id']; ?>, 'events', 'freeTextImport');"></span>
<span id="attribute-replace-button" title="Replace all attributes of a category/type combination within the event" class="icon-random useCursorPointer" onClick="getPopup(<?php echo $event['Event']['id']; ?>, 'attributes', 'attributeReplace');"></span>
</div>
<?php endif; ?>
<table class="table table-striped table-condensed">

View File

@ -128,9 +128,13 @@ if ($object['objectType'] == 1) {
</div>
</td>
<td class="<?php echo $extra; ?> shortish">
<?php
$turnRed = '';
if ($object['objectType'] == 0 && $object['distribution'] == 0) $turnRed = 'style="color:red"';
?>
<div id = "<?php echo $currentType . '_' . $object['id'] . '_distribution_placeholder'; ?>" class = "inline-field-placeholder"></div>
<div id = "<?php echo $currentType . '_' . $object['id'] . '_distribution_solid'; ?>" class="inline-field-solid" onClick="activateField('<?php echo $currentType; ?>', '<?php echo $object['id']; ?>', 'distribution', <?php echo $event['Event']['id'];?>);">
<?php if ($object['objectType'] != 1 && $object['objectType'] != 2) echo h($distributionLevels[$object['distribution']]); ?>&nbsp;
<div id = "<?php echo $currentType . '_' . $object['id'] . '_distribution_solid'; ?>" <?php echo $turnRed; ?> class="inline-field-solid" onClick="activateField('<?php echo $currentType; ?>', '<?php echo $object['id']; ?>', 'distribution', <?php echo $event['Event']['id'];?>);">
<?php if ($object['objectType'] == 0) echo h($distributionLevels[$object['distribution']]); ?>&nbsp;
</div>
</td>
<td class="short action-links <?php echo $extra;?>">

View File

@ -6,13 +6,14 @@
if ($menuItem === 'addAttribute' ||
$menuItem === 'addAttachment' ||
$menuItem === 'addIOC' ||
$menuItem === 'addThreatConnect'
$menuItem === 'addThreatConnect' ||
$menuItem === 'populateFromtemplate'
) {
// we can safely assume that mayModify is true if comming from these actions, as they require it in the controller and the user has already passed that check
$mayModify = true;
if ($isAclPublish) $mayPublish = true;
}
?>
?>
<li <?php if ($menuItem === 'viewEvent') echo 'class="active"';?>><a href="/events/view/<?php echo $event['Event']['id'];?>">View Event</a></li>
<li <?php if ($menuItem === 'eventLog') echo 'class="active"';?>><a href="/logs/event_index/<?php echo $event['Event']['id'];?>">View Event History</a></li>
<?php if ($isSiteAdmin || (isset($mayModify) && $mayModify)): ?>
@ -23,6 +24,9 @@
<li <?php if ($menuItem === 'addAttachment') echo 'class="active"';;?>><a href="/attributes/add_attachment/<?php echo $event['Event']['id'];?>">Add Attachment</a></li>
<li <?php if ($menuItem === 'addIOC') echo 'class="active"';?>><a href="/events/addIOC/<?php echo $event['Event']['id'];?>">Populate from OpenIOC</a></li>
<li <?php if ($menuItem === 'addThreatConnect') echo 'class="active"';?>><a href="/attributes/add_threatconnect/<?php echo $event['Event']['id']; ?>">Populate from ThreatConnect</a></li>
<?php if ($menuItem === 'populateFromtemplate'): ?>
<li class="active"><a href="/templates/populateEventFromTemplate/<?php echo $template_id . '/' . $event['Event']['id']; ?>">Populate From Template</a></li>
<?php endif; ?>
<?php elseif (!isset($mayModify) || !$mayModify): ?>
<li class="divider"></li>
<li <?php if ($menuItem === 'proposeAttribute') echo 'class="active"';?>><a href="/shadow_attributes/add/<?php echo $event['Event']['id'];?>">Propose Attribute</a></li>

View File

@ -27,7 +27,7 @@ echo $this->Form->create('Attribute', array('id'));
<button id="submitButton" class="btn btn-primary">Submit</button>
</td>
<td style="width:540px;">
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message">Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.</p>
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message"></p>
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="cancel_attribute_add">Cancel</span>

View File

@ -23,7 +23,7 @@
echo $this->Form->input('Attribute.' . $k . '.value', array(
'label' => false,
'type' => 'hidden',
'value' => $item['value'],
'value' => h($item['value']),
));
?>
<td><?php echo h($item['value']); ?></td>

View File

@ -102,11 +102,19 @@ $mayPublish = ($isAclPublish && $event['Event']['orgc'] == $me['org']);
<?php echo nl2br(h($event['Event']['info'])); ?>
&nbsp;
</dd>
<?php if ($isAclPublish && $event['Event']['published'] == 0) :?>
<dt class="visibleDL">Published</dt>
<dd class="visibleDL">
<?php echo ($event['Event']['published'] == 1 ? 'Yes' : 'No'); ?>
&nbsp;
</dd>
<?php else: ?>
<dt>Published</dt>
<dd style="color: red;">
<dd style="color: <?php echo ($event['Event']['published'] == 1 ? 'green' : 'red'); ?>">
<b><?php echo ($event['Event']['published'] == 1 ? 'Yes' : 'No'); ?></b>
&nbsp;
</dd>
<?php endif; ?>
</dl>
</div>

View File

@ -22,6 +22,9 @@ echo $this->Form->button('Add', array('class' => 'btn btn-primary'));
echo $this->Form->end();
?>
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'event', 'menuItem' => 'populateFromtemplate', 'event' => array('Event' => array('id' => $event_id)), 'template_id' => $template_id));
?>
<script type="text/javascript">
$(document).ready(function() {
<?php if (isset($fileArray)): ?>

View File

@ -1200,11 +1200,21 @@ a.proposal_link_red:hover {
}
.drop {
min-height: 150px;
width: 250px;
border: 1px solid blue;
margin: 10px;
padding: 10px;
min-height: 150px;
width: 250px;
border: 1px solid blue;
margin: 10px;
padding: 10px;
}
.visibleDL {
background-color: red !important;
color: white;
font-weight: bold;
}
.red {
color: red;
}
@-webkit-keyframes rotation {

View File

@ -422,6 +422,9 @@ function submitPopoverForm(context_id, referer, update_context_id) {
context_id = update_context_id;
contextNamingConvention = 'TemplateElementFile';
break;
case 'replaceAttributes':
url = "/attributes/attributeReplace/" + context_id;
break;
}
if (url !== null) {