chg: [UI] Inline attribute detaching

pull/8297/head
Jakub Onderka 2022-04-24 18:29:32 +02:00
parent d3770295cc
commit 270080bce4
7 changed files with 182 additions and 137 deletions

View File

@ -547,100 +547,30 @@ class GalaxyClustersController extends AppController
public function detach($target_id, $target_type, $tag_id)
{
$this->loadModel('Event');
if ($target_type == 'attribute') {
$attribute = $this->Event->Attribute->find('first', array(
'recursive' => -1,
'fields' => array('id', 'event_id'),
'conditions' => array('Attribute.id' => $target_id)
));
if (empty($attribute)) {
throw new MethodNotAllowedException('Invalid Attribute.');
}
$event_id = $attribute['Attribute']['event_id'];
} elseif ($target_type == 'event') {
$event_id = $target_id;
} elseif ($target_type === 'tag_collection') {
// pass
} else {
throw new MethodNotAllowedException('Invalid options');
if ($this->request->is("ajax") && $this->request->is("get")) {
$this->set("url", $this->request->url);
return $this->render("/Elements/emtpyForm", false);
}
if ($target_type === 'tag_collection') {
$tag_collection = $this->GalaxyCluster->Tag->TagCollectionTag->TagCollection->fetchTagCollection($this->Auth->user(), array(
'conditions' => array('TagCollection.id' => $target_id),
'contain' => array('Organisation', 'TagCollectionTag' => array('Tag'))
));
if (empty($tag_collection)) {
throw new MethodNotAllowedException('Invalid Tag Collection');
}
$tag_collection = $tag_collection[0];
if (!$this->_isSiteAdmin()) {
if (!$this->userRole['perm_tag_editor'] || $this->Auth->user('org_id') !== $tag_collection['TagCollection']['org_id']) {
throw new MethodNotAllowedException('Invalid Tag Collection');
}
}
} else {
$this->Event->id = $event_id;
$this->Event->recursive = -1;
$event = $this->Event->read(array(), $event_id);
if (empty($event)) {
throw new MethodNotAllowedException('Invalid Event.');
}
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
throw new MethodNotAllowedException('Invalid Event.');
}
}
}
$this->request->allowMethod(["post"]);
if ($target_type == 'attribute') {
$existingTargetTag = $this->Event->Attribute->AttributeTag->find('first', array(
'conditions' => array('AttributeTag.tag_id' => $tag_id, 'AttributeTag.attribute_id' => $target_id),
'recursive' => -1,
'contain' => array('Tag')
));
} elseif ($target_type == 'event') {
$existingTargetTag = $this->Event->EventTag->find('first', array(
'conditions' => array('EventTag.tag_id' => $tag_id, 'EventTag.event_id' => $target_id),
'recursive' => -1,
'contain' => array('Tag')
));
} elseif ($target_type == 'tag_collection') {
$existingTargetTag = $this->GalaxyCluster->Tag->TagCollectionTag->find('first', array(
'conditions' => array('TagCollectionTag.tag_id' => $tag_id, 'TagCollectionTag.tag_collection_id' => $target_id),
'recursive' => -1,
'contain' => array('Tag')
));
}
if (empty($existingTargetTag)) {
$this->Flash->error('Galaxy not attached.');
} else {
$cluster = $this->GalaxyCluster->find('first', array(
'recursive' => -1,
'conditions' => array('GalaxyCluster.tag_name' => $existingTargetTag['Tag']['name'])
));
if ($target_type == 'event') {
$result = $this->Event->EventTag->delete($existingTargetTag['EventTag']['id']);
} elseif ($target_type == 'attribute') {
$result = $this->Event->Attribute->AttributeTag->delete($existingTargetTag['AttributeTag']['id']);
} elseif ($target_type == 'tag_collection') {
$result = $this->GalaxyCluster->Tag->TagCollectionTag->delete($existingTargetTag['TagCollectionTag']['id']);
}
if ($result) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Event->save($event);
$this->Flash->success('Galaxy successfully detached.');
$this->Log = ClassRegistry::init('Log');
$logTitle = 'Detached ' . $cluster['GalaxyCluster']['value'] . ' (' . $cluster['GalaxyCluster']['id'] . ') from ' . $target_type . ' (' . $target_id . ')';
$this->Log->createLogEntry($this->Auth->user(), 'galaxy', ucfirst($target_type), $target_id, $logTitle);
try {
$this->GalaxyCluster->Galaxy->detachClusterByTagId($this->Auth->user(), $target_id, $target_type, $tag_id);
} catch (NotFoundException $e) {
if (!$this->request->is("ajax")) {
$this->Flash->error($e->getMessage());
} else {
$this->Flash->error('Could not detach galaxy from event.');
throw $e;
}
}
$message = __('Galaxy successfully detached.');
if ($this->request->is("ajax")) {
return $this->RestResponse->viewData(["saved" => true, "check_publish" => true, "success" => $message], "json");
}
$this->Flash->success($message);
$this->redirect($this->referer());
}

View File

@ -544,6 +544,111 @@ class Galaxy extends AppModel
}
}
/**
* @param array $user
* @param int $targetId
* @param string $targetType
* @param int $tagId
* @return void
* @throws Exception
*/
public function detachClusterByTagId(array $user, $targetId, $targetType, $tagId)
{
if ($targetType === 'attribute') {
$attribute = $this->GalaxyCluster->Tag->EventTag->Event->Attribute->find('first', array(
'recursive' => -1,
'fields' => array('id', 'event_id'),
'conditions' => array('Attribute.id' => $targetId)
));
if (empty($attribute)) {
throw new NotFoundException('Invalid Attribute.');
}
$event_id = $attribute['Attribute']['event_id'];
} elseif ($targetType === 'event') {
$event_id = $targetId;
} elseif ($targetType !== 'tag_collection') {
throw new NotFoundException('Invalid options');
}
if ($targetType === 'tag_collection') {
$tag_collection = $this->GalaxyCluster->Tag->TagCollectionTag->TagCollection->fetchTagCollection($user, array(
'conditions' => array('TagCollection.id' => $targetId),
'recusive' => -1,
));
if (empty($tag_collection)) {
throw new NotFoundException('Invalid Tag Collection');
}
$tag_collection = $tag_collection[0];
if (!$user["Role"]["perm_site_admin"]) {
if (!$user["Role"]['perm_tag_editor'] || $user['org_id'] !== $tag_collection['TagCollection']['org_id']) {
throw new NotFoundException('Invalid Tag Collection');
}
}
} else {
$event = $this->GalaxyCluster->Tag->EventTag->Event->fetchSimpleEvent($user, $event_id);
if (empty($event)) {
throw new NotFoundException('Invalid Event.');
}
if (!$user["Role"]["perm_site_admin"] && !$user["Role"]['perm_sync']) {
if (!$user["Role"]['perm_tagger'] || ($user['org_id'] !== $event['Event']['org_id'] && $user['org_id'] !== $event['Event']['orgc_id'])) {
throw new NotFoundException('Invalid Event.');
}
}
}
if ($targetType === 'attribute') {
$existingTargetTag = $this->GalaxyCluster->Tag->AttributeTag->find('first', array(
'conditions' => array('AttributeTag.tag_id' => $tagId, 'AttributeTag.attribute_id' => $targetId),
'recursive' => -1,
'contain' => array('Tag')
));
} elseif ($targetType === 'event') {
$existingTargetTag = $this->GalaxyCluster->Tag->EventTag->find('first', array(
'conditions' => array('EventTag.tag_id' => $tagId, 'EventTag.event_id' => $targetId),
'recursive' => -1,
'contain' => array('Tag')
));
} elseif ($targetType === 'tag_collection') {
$existingTargetTag = $this->GalaxyCluster->Tag->TagCollectionTag->find('first', array(
'conditions' => array('TagCollectionTag.tag_id' => $tagId, 'TagCollectionTag.tag_collection_id' => $targetId),
'recursive' => -1,
'contain' => array('Tag')
));
}
if (empty($existingTargetTag)) {
throw new NotFoundException('Galaxy not attached.');
}
$cluster = $this->GalaxyCluster->find('first', array(
'recursive' => -1,
'conditions' => array('GalaxyCluster.tag_name' => $existingTargetTag['Tag']['name'])
));
if (empty($cluster)) {
throw new NotFoundException("Tag is not cluster");
}
if ($targetType === 'event') {
$result = $this->GalaxyCluster->Tag->EventTag->delete($existingTargetTag['EventTag']['id']);
} elseif ($targetType === 'attribute') {
$result = $this->GalaxyCluster->Tag->AttributeTag->delete($existingTargetTag['AttributeTag']['id']);
} elseif ($targetType === 'tag_collection') {
$result = $this->GalaxyCluster->Tag->TagCollectionTag->delete($existingTargetTag['TagCollectionTag']['id']);
}
if (!$result) {
throw new RuntimeException('Could not detach galaxy from event.');
}
if ($targetType !== 'tag_collection') {
$event['Event']['published'] = 0;
$event['Event']['timestamp'] = time();
$this->GalaxyCluster->Tag->EventTag->Event->save($event);
}
$logTitle = 'Detached ' . $cluster['GalaxyCluster']['value'] . ' (' . $cluster['GalaxyCluster']['id'] . ') from ' . $targetType . ' (' . $targetId . ')';
$this->loadLog()->createLogEntry($user, 'galaxy', ucfirst($targetType), $targetId, $logTitle);
}
public function getMitreAttackGalaxyId($type="mitre-attack-pattern", $namespace="mitre-attack")
{
$galaxy = $this->find('first', array(

View File

@ -4,6 +4,7 @@ App::uses('TmpFileTool', 'Tools');
/**
* @property Tag $Tag
* @property Galaxy $Galaxy
* @property GalaxyClusterRelation $GalaxyClusterRelation
* @property GalaxyElement $GalaxyElement
*/

View File

@ -114,7 +114,6 @@
// Generate tooltip information
//
var formInfoValues = new Array();
var fieldsArrayAttribute = new Array('AttributeDistribution', 'AttributeComment', 'AttributeToIds');
<?php
foreach ($distributionDescriptions as $type => $def) {
$info = isset($def['formdesc']) ? $def['formdesc'] : $def['desc'];

View File

@ -0,0 +1,3 @@
<?php
echo $this->Form->create(false, ['id' => false, 'url' => $url]);
echo $this->Form->end();

View File

@ -58,7 +58,7 @@ $generatePopover = function (array $cluster) use ($normalizeKey) {
}
$popover = '<h4 class="blue" style="white-space: nowrap">' . h($cluster['value']) . '</h4>';
foreach ($clusterFields as $clusterField) {
$key = '<span class="blue bold">' . h($normalizeKey($clusterField['key'])) . '</span>';
$key = '<b class="blue">' . h($normalizeKey($clusterField['key'])) . '</b>';
if (is_array($clusterField['value'])) {
if ($clusterField['key'] === 'country') {
$value = [];
@ -102,18 +102,16 @@ $generatePopover = function (array $cluster) use ($normalizeKey) {
<a href="<?= $baseurl ?>/events/index/searchtag:<?= h($cluster['tag_id']) ?>" class="black fa fa-list" title="<?= __('View all events containing this cluster') ?>" aria-label="<?= __('View all events containing this cluster') ?>"></a>
<?php endif ;?>
<?php if ($editButtonsEnabled || ($editButtonsLocalEnabled && $cluster['local'])) {
echo $this->Form->create(false, [
'id' => false, // prevent duplicate ids
'url' => $baseurl . '/galaxy_clusters/detach/' . ucfirst(h($target_id)) . '/' . h($target_type) . '/' . $cluster['tag_id'],
'style' => 'display: inline-block; margin: 0px;'
]);
echo sprintf(
'<a href="#" class="black fa fa-trash useCursorPointer" role="button" tabindex="0" aria-label="%s" title="%s" onclick="popoverConfirm(this);"></a>',
__('Detach'),
__('Are you sure you want to detach %s from this event?', h($cluster['value']))
);
echo $this->Form->end();
}
$url = $baseurl . '/galaxy_clusters/detach/' . intval($target_id) . '/' . h($target_type) . '/' . $cluster['tag_id'];
echo sprintf(
'<a href="%s" class="black fa fa-trash" role="button" tabindex="0" aria-label="%s" title="%s" onclick="confirmClusterDetach(this, \'%s\', %s);"></a>',
$url,
__('Detach'),
__('Are you sure you want to detach %s from this event?', h($cluster['value'])),
h($target_type),
intval($target_id)
);
}
?>
</li>
<?php endforeach; ?>

View File

@ -1064,10 +1064,10 @@ function loadGalaxies(id, scope) {
$.ajax({
dataType:"html",
cache: false,
success:function (data) {
if (scope == 'event') {
success: function (data) {
if (scope === 'event') {
$("#galaxies_div").html(data);
} else if (scope == 'attribute') {
} else if (scope === 'attribute') {
$("#attribute_" + id + "_galaxy").html(data);
}
},
@ -1816,56 +1816,65 @@ function popoverPopupNew(clicked, url) {
});
}
function confirmClusterDetach(clicked, target_type, target_id) {
popoverConfirm(clicked, undefined, undefined, function (data) {
handleGenericAjaxResponse(data);
if (target_type === "event") {
loadGalaxies(target_id, 'event');
} else if (target_type === "attribute") {
loadGalaxies(target_id, 'attribute');
} else {
location.reload();
}
})
}
// create a confirm popover on the clicked html node.
function popoverConfirm(clicked, message, placement) {
function popoverConfirm(clicked, message, placement, callback) {
event.preventDefault();
var $clicked = $(clicked);
var popoverContent = '<div>';
popoverContent += message === undefined ? '' : '<p>' + message + '</p>';
popoverContent += '<button id="popoverConfirmOK" class="btn btn-primary" style="margin-right: 5px;" onclick=submitPopover(this)>Yes</button>';
popoverContent += '<button class="btn btn-inverse" style="float: right;" onclick=cancelPrompt()>Cancel</button>';
popoverContent += '<button id="popoverConfirmOK" class="btn btn-primary" style="margin-right: 5px;">Yes</button>';
popoverContent += '<button class="btn btn-inverse" style="float: right;" onclick="cancelPrompt()">Cancel</button>';
popoverContent += '</div>';
openPopover($clicked, popoverContent, undefined, placement);
$("#popoverConfirmOK")
.focus()
.bind("keydown", function(e) {
if (e.ctrlKey && (e.keyCode == 13 || e.keyCode == 10)) {
$(this).click();
}
if(e.keyCode == 27) { // ESC
} else if (e.keyCode == 27) { // ESC
$clicked.popover('destroy');
}
}).click(function() {
var href = $clicked.attr("href");
// Load form to get new token
fetchFormDataAjax(href, function (form) {
var $form = $(form);
xhr({
data: $form.serialize(),
success: function (data) {
if (callback !== undefined) {
callback(data);
} else {
location.reload();
}
},
complete: function() {
$(".loading").hide();
$("#popover_form").fadeOut();
$("#gray_out").fadeOut();
},
type: "post",
url: $form.attr('action')
});
})
});
}
function submitPopover(clicked) {
var $clicked = $(clicked);
var $form = $clicked.closest('form');
if ($form.length === 0) { // popover container is body, submit from original node
var dismissid = $clicked.closest('div.popover').attr('data-dismissid');
$form = $('[data-dismissid="' + dismissid + '"]').closest('form');
}
if ($form.data('ajax')) {
xhr({
data: $form.serialize(),
success:function () {
location.reload();
},
complete:function() {
$(".loading").hide();
$("#popover_form").fadeOut();
$("#gray_out").fadeOut();
$('#temp').remove();
},
type:"post",
url: $form.attr('action')
});
} else {
$form.submit();
}
}
function simplePopup(url, requestType, data) {
requestType = requestType === undefined ? 'GET' : requestType
data = data === undefined ? [] : data