From e42b945b11c7c187e02c5b13cd1727aff78f4424 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 26 Feb 2019 10:16:02 +0100 Subject: [PATCH 01/25] chg: [distributionGraph] Replaced all tabs by spaces --- app/webroot/js/event-distribution-graph.js | 644 ++++++++++----------- 1 file changed, 322 insertions(+), 322 deletions(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 3130df72c..bde0eda46 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -6,364 +6,364 @@ var payload = {}; var distribution_chart; function clickHandlerGraph(evt) { - var firstPoint = distribution_chart.getElementAtEvent(evt)[0]; - var distribution_id; - if (firstPoint) { - var value = distribution_chart.data.datasets[firstPoint._datasetIndex].data[firstPoint._index]; - if (value == 0) { - document.getElementById('attributesFilterField').value = ""; - filterAttributes('all', scope_id); - } else { - distribution_id = distribution_chart.data.distribution[firstPoint._index].value; - var value_to_set = String(distribution_id); - value_to_set += distribution_id == event_distribution ? '|' + '5' : ''; - value_to_set = value_to_set.split('|'); - var rules = { - condition: 'AND', - rules: [ - { - field: 'distribution', - value: value_to_set - } - ] - }; - performQuery(rules); - } - } + var firstPoint = distribution_chart.getElementAtEvent(evt)[0]; + var distribution_id; + if (firstPoint) { + var value = distribution_chart.data.datasets[firstPoint._datasetIndex].data[firstPoint._index]; + if (value == 0) { + document.getElementById('attributesFilterField').value = ""; + filterAttributes('all', scope_id); + } else { + distribution_id = distribution_chart.data.distribution[firstPoint._index].value; + var value_to_set = String(distribution_id); + value_to_set += distribution_id == event_distribution ? '|' + '5' : ''; + value_to_set = value_to_set.split('|'); + var rules = { + condition: 'AND', + rules: [ + { + field: 'distribution', + value: value_to_set + } + ] + }; + performQuery(rules); + } + } } function generate_additional_info(info) { - if (info.length == 0) { - return ""; - } else { - var to_ret = "\n\nInvolved:\n"; - var sel = document.createElement('select'); - sel.classList.add('distributionInfo'); - info.forEach(function(i) { - var opt = document.createElement('option'); - opt.val = i; - opt.innerHTML = i; - sel.appendChild(opt); - }); - return to_ret += sel.outerHTML; - } + if (info.length == 0) { + return ""; + } else { + var to_ret = "\n\nInvolved:\n"; + var sel = document.createElement('select'); + sel.classList.add('distributionInfo'); + info.forEach(function(i) { + var opt = document.createElement('option'); + opt.val = i; + opt.innerHTML = i; + sel.appendChild(opt); + }); + return to_ret += sel.outerHTML; + } } function clickHandlerPbText(evt) { - var distribution_id = evt.target.dataset.distribution; - var value_to_set = String(distribution_id); - var rules = { - condition: 'AND', - rules: [ - { - field: 'distribution', - value: [value_to_set] - } - ] - }; - performQuery(rules); + var distribution_id = evt.target.dataset.distribution; + var value_to_set = String(distribution_id); + var rules = { + condition: 'AND', + rules: [ + { + field: 'distribution', + value: [value_to_set] + } + ] + }; + performQuery(rules); } function clickHandlerPb(evt) { - var distribution_id = $(evt.target).data('distribution'); - var value_to_set = String(distribution_id); - value_to_set = value_to_set.split('|') - var rules = { - condition: 'AND', - rules: [ - { - field: 'distribution', - value: value_to_set - } - ] - }; - performQuery(rules); + var distribution_id = $(evt.target).data('distribution'); + var value_to_set = String(distribution_id); + value_to_set = value_to_set.split('|') + var rules = { + condition: 'AND', + rules: [ + { + field: 'distribution', + value: value_to_set + } + ] + }; + performQuery(rules); } function fill_distri_for_search(start_distri, end_distri) { - var to_ret = ""; - for (var i=start_distri; iDistribution description: ' + distribution[d].desc + generate_additional_info(additionalInfo[d]), - title: distribution[d].key, - container: 'body', - html: true, - template: '' - }); + var spanOffset = spanOffset_orig; + distribution = jQuery.extend({}, distribution); // deep clone distribution object + for (var d in distribution) { + d = parseInt(d); + if (d == 4) { // skip sharing group + continue; + } + // text + var span = document.createElement('span'); + span.classList.add('useCursorPointer', 'pbDistributionText', 'badge'); + span.onclick = clickHandlerPbText; + span.innerHTML = distribution[d].key; + span.setAttribute('data-distribution', d); + span.style.whiteSpace = 'pre-wrap'; + if (maxLevel == d+1) { // current event distribution + span.style.fontSize = 'larger'; + span.style.top = d % 2 == 0 ? pb_top-37+'px' : pb_top+30+'px'; + span.style.boxShadow = '3px 3px 5px 1px rgba(0,0,0,0.6)'; + } else { + span.style.opacity = '0.5'; + span.style.top = d % 2 == 0 ? pb_top-37+'px' : pb_top+30+'px'; + } + pb_container.appendChild(span); + if (d == Object.keys(distribution).length-2) { // last one, move a bit to the left. (-2 because sharing is not considered) + span.style.left = (pbStep*(d+1))+spanOffset-span.clientWidth/2-35 + 'px'; + } else { + span.style.left = (pbStep*(d+1))+spanOffset-span.clientWidth/2 + 'px'; + } + var pop = $(span).popover({ + placement: d % 2 == 0 ? 'top' : 'bottom', + trigger: 'click', + content: 'Distribution description: ' + distribution[d].desc + generate_additional_info(additionalInfo[d]), + title: distribution[d].key, + container: 'body', + html: true, + template: '' + }); - // tick - var span = document.createElement('span'); - span.classList.add('pbDistributionTick'); - spanOffset += (pbStep*(d+1))+spanOffset > pb_container.clientWidth ? -3 : 0; // avoid the tick width to go further than the pb - span.style.left = (pbStep*(d+1))+spanOffset + 'px'; - span.style.top = d % 2 == 0 ? pb_top-15+'px' : pb_top+0+'px'; - if (maxLevel == d+1) { - span.style.opacity = '0.6'; - } else { - span.style.opacity = '0.2'; - } - pb_container.appendChild(span); - } + // tick + var span = document.createElement('span'); + span.classList.add('pbDistributionTick'); + spanOffset += (pbStep*(d+1))+spanOffset > pb_container.clientWidth ? -3 : 0; // avoid the tick width to go further than the pb + span.style.left = (pbStep*(d+1))+spanOffset + 'px'; + span.style.top = d % 2 == 0 ? pb_top-15+'px' : pb_top+0+'px'; + if (maxLevel == d+1) { + span.style.opacity = '0.6'; + } else { + span.style.opacity = '0.2'; + } + pb_container.appendChild(span); + } } $(document).ready(function() { - var pop = $('.distribution_graph').popover({ - title: "Distribution graph [atomic event]", - html: true, - content: function() { return $('#distribution_graph_container').html(); }, - template : '' - }); + var pop = $('.distribution_graph').popover({ + title: "Distribution graph [atomic event]", + html: true, + content: function() { return $('#distribution_graph_container').html(); }, + template : '' + }); - $('body').on('mouseup', function(e) { - if(!$(e.target).hasClass('distributionInfo') && !($(e.target).hasClass('pbDistributionText') || $(e.target).hasClass('sharingGroup_pb_text'))) { - $('.pbDistributionText').popover('hide'); - $('.sharingGroup_pb_text').popover('hide'); - } - }); + $('body').on('mouseup', function(e) { + if(!$(e.target).hasClass('distributionInfo') && !($(e.target).hasClass('pbDistributionText') || $(e.target).hasClass('sharingGroup_pb_text'))) { + $('.pbDistributionText').popover('hide'); + $('.sharingGroup_pb_text').popover('hide'); + } + }); - $('.distribution_graph').click(function() { - if ($(this).data('shown') == 'true') { - $(this).data('shown', 'false'); - return; - } else { - $(this).data('shown', 'true'); - } - $.ajax({ - url: "/events/"+"getDistributionGraph"+"/"+scope_id+"/event.json", - dataType: 'json', - type: 'post', - contentType: 'application/json', - data: JSON.stringify( payload ), - processData: false, - beforeSend: function (XMLHttpRequest) { - $(".loadingPopover").show(); - }, - success: function( data, textStatus, jQxhr ){ - $(".loadingPopover").hide(); + $('.distribution_graph').click(function() { + if ($(this).data('shown') == 'true') { + $(this).data('shown', 'false'); + return; + } else { + $(this).data('shown', 'true'); + } + $.ajax({ + url: "/events/"+"getDistributionGraph"+"/"+scope_id+"/event.json", + dataType: 'json', + type: 'post', + contentType: 'application/json', + data: JSON.stringify( payload ), + processData: false, + beforeSend: function (XMLHttpRequest) { + $(".loadingPopover").show(); + }, + success: function( data, textStatus, jQxhr ){ + $(".loadingPopover").hide(); - // DISTRIBUTION PROGRESSBAR - $('#eventdistri_pb_invalid').tooltip(); - $('#eventdistri_pb').tooltip(); - $('#eventdistri_pb_min').tooltip(); + // DISTRIBUTION PROGRESSBAR + $('#eventdistri_pb_invalid').tooltip(); + $('#eventdistri_pb').tooltip(); + $('#eventdistri_pb_min').tooltip(); - $('#eventdistri_pb_invalid').click(function(evt) { clickHandlerPb(evt); }); - $('#eventdistri_pb').click(function(evt) { clickHandlerPb(evt); }); - $('#eventdistri_pb_min').click(function(evt) { clickHandlerPb(evt); }); - $('#eventdistri_sg_pb').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_pb_invalid').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_pb').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_pb_min').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_sg_pb').click(function(evt) { clickHandlerPb(evt); }); - // pb - var event_dist, min_distri, max_distri; - if (event_distribution == 4) { // if distribution is sharing group, overwrite default behavior - var event_dist = 1; - var min_distri = 0; - var max_distri = 0; - } else { - var event_dist = event_distribution+1; // +1 to reach the first level - var min_distri = get_minimum_distribution(data.event, event_dist)+1; // +1 to reach the first level - var max_distri = get_maximum_distribution(data.event)+1; // +1 to reach the first level - } - add_level_to_pb(data.distributionInfo, data.additionalDistributionInfo, event_dist); + // pb + var event_dist, min_distri, max_distri; + if (event_distribution == 4) { // if distribution is sharing group, overwrite default behavior + var event_dist = 1; + var min_distri = 0; + var max_distri = 0; + } else { + var event_dist = event_distribution+1; // +1 to reach the first level + var min_distri = get_minimum_distribution(data.event, event_dist)+1; // +1 to reach the first level + var max_distri = get_maximum_distribution(data.event)+1; // +1 to reach the first level + } + add_level_to_pb(data.distributionInfo, data.additionalDistributionInfo, event_dist); - var bg_width_step = $('#eventdistri_pb_background').width()/4.0; - $('#eventdistri_pb_min').width(bg_width_step*min_distri + 'px'); - $('#eventdistri_pb_min').data("distribution", fill_distri_for_search(0, min_distri-1)); - $('#eventdistri_pb_min').attr('aria-valuenow', min_distri*25); - $('#eventdistri_pb_min').css("background", "#ffc107"); + var bg_width_step = $('#eventdistri_pb_background').width()/4.0; + $('#eventdistri_pb_min').width(bg_width_step*min_distri + 'px'); + $('#eventdistri_pb_min').data("distribution", fill_distri_for_search(0, min_distri-1)); + $('#eventdistri_pb_min').attr('aria-valuenow', min_distri*25); + $('#eventdistri_pb_min').css("background", "#ffc107"); - $('#eventdistri_pb').width((event_dist)*25+'%'); - $('#eventdistri_pb').data("distribution", fill_distri_for_search(0, event_dist-1)); - $('#eventdistri_pb').attr('aria-valuenow', (event_dist-min_distri)*25); - $('#eventdistri_pb').css("background", "#28a745"); + $('#eventdistri_pb').width((event_dist)*25+'%'); + $('#eventdistri_pb').data("distribution", fill_distri_for_search(0, event_dist-1)); + $('#eventdistri_pb').attr('aria-valuenow', (event_dist-min_distri)*25); + $('#eventdistri_pb').css("background", "#28a745"); - $('#eventdistri_pb_invalid').width((max_distri-event_dist)*25+'%'); - $('#eventdistri_pb_invalid').data("distribution", fill_distri_for_search(event_dist, max_distri-1)); - $('#eventdistri_pb_invalid').attr('aria-valuenow', (max_distri-event_dist)*25); - $('#eventdistri_pb_invalid').css("background", "#dc3545"); + $('#eventdistri_pb_invalid').width((max_distri-event_dist)*25+'%'); + $('#eventdistri_pb_invalid').data("distribution", fill_distri_for_search(event_dist, max_distri-1)); + $('#eventdistri_pb_invalid').attr('aria-valuenow', (max_distri-event_dist)*25); + $('#eventdistri_pb_invalid').css("background", "#dc3545"); - // SHARING GROUPS - var sgNum = data.additionalDistributionInfo[4].length; - var sgPerc = (sgNum/data.allSharingGroup.length)*100; - if (sgPerc > 0) { - $('#eventdistri_sg_pb').width(sgPerc+'%'); - $('#eventdistri_sg_pb').tooltip({ - title: "Distribution among sharing group: "+(sgNum +' / '+ data.allSharingGroup.length) - }); - $('#eventdistri_sg_pb').data("distribution", '4' + (event_distribution==4 ? '|5' : '')); - $('#eventdistri_sg_pb').attr('aria-valuenow', sgPerc); - $('#eventdistri_sg_pb').css("background", "#7a86e0"); - } else { // no sg, hide it and display - $('#eventdistri_sg_pb_background').text("Event not distributed to any sharing group"); - } + // SHARING GROUPS + var sgNum = data.additionalDistributionInfo[4].length; + var sgPerc = (sgNum/data.allSharingGroup.length)*100; + if (sgPerc > 0) { + $('#eventdistri_sg_pb').width(sgPerc+'%'); + $('#eventdistri_sg_pb').tooltip({ + title: "Distribution among sharing group: "+(sgNum +' / '+ data.allSharingGroup.length) + }); + $('#eventdistri_sg_pb').data("distribution", '4' + (event_distribution==4 ? '|5' : '')); + $('#eventdistri_sg_pb').attr('aria-valuenow', sgPerc); + $('#eventdistri_sg_pb').css("background", "#7a86e0"); + } else { // no sg, hide it and display + $('#eventdistri_sg_pb_background').text("Event not distributed to any sharing group"); + } - $('.sharingGroup_pb_text').popover({ - placement: 'bottom', - trigger: 'click', - title: 'Sharing group', - content: 'Distribution description: ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]), - container: 'body', - html: true, - template: '' - }); + $('.sharingGroup_pb_text').popover({ + placement: 'bottom', + trigger: 'click', + title: 'Sharing group', + content: 'Distribution description: ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]), + container: 'body', + html: true, + template: '' + }); - // doughtnut - var doughnutColors = ['#ff0000', '#ff9e00', '#957200', '#008000', 'rgb(122, 134, 224)']; - var doughnut_dataset = [ - { - label: "All", - data: data.event, - hidden: false, - backgroundColor: doughnutColors - }, - { - label: "Attributes", - data: data.attribute, - hidden: false, - backgroundColor: doughnutColors - }, - { - label: "Object attributes", - data: data.obj_attr, - hidden: false, - backgroundColor: doughnutColors - }, + // doughtnut + var doughnutColors = ['#ff0000', '#ff9e00', '#957200', '#008000', 'rgb(122, 134, 224)']; + var doughnut_dataset = [ + { + label: "All", + data: data.event, + hidden: false, + backgroundColor: doughnutColors + }, + { + label: "Attributes", + data: data.attribute, + hidden: false, + backgroundColor: doughnutColors + }, + { + label: "Object attributes", + data: data.obj_attr, + hidden: false, + backgroundColor: doughnutColors + }, - ]; - var ctx = document.getElementById("distribution_graph_canvas"); - ctx.onclick = function(evt) { clickHandlerGraph(evt); }; - distribution_chart = new Chart(ctx, { - type: 'doughnut', - data: { - labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }), - distribution: data.distributionInfo, - datasets: doughnut_dataset, - }, - options: { - title: { - display: false - }, - animation: { - duration: 500 - }, - tooltips: { - callbacks: { - label: function(item, data) { - return data.datasets[item.datasetIndex].label - + " - " + data.labels[item.index] - + ": " + data.datasets[item.datasetIndex].data[item.index]; - } - } - } - }, - }); + ]; + var ctx = document.getElementById("distribution_graph_canvas"); + ctx.onclick = function(evt) { clickHandlerGraph(evt); }; + distribution_chart = new Chart(ctx, { + type: 'doughnut', + data: { + labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }), + distribution: data.distributionInfo, + datasets: doughnut_dataset, + }, + options: { + title: { + display: false + }, + animation: { + duration: 500 + }, + tooltips: { + callbacks: { + label: function(item, data) { + return data.datasets[item.datasetIndex].label + + " - " + data.labels[item.index] + + ": " + data.datasets[item.datasetIndex].data[item.index]; + } + } + } + }, + }); - // create checkboxes - var div = $('
'); - div.addClass('distribution_checkboxes_dataset'); - var distri_graph = $('#eventdistri_graph'); - var distriOffset = distri_graph.offset(); - var distriHeight = distri_graph.height()/2; - div.css({left: '50px'}); - for (var i in doughnut_dataset) { - var item = doughnut_dataset[i]; - var label = $(''); - label.addClass('useCursorPointer'); - label.css({'user-select': 'none'}); - var checkbox = $(''); - checkbox.data('dataset-index', i); - checkbox.prop('checked', true); - checkbox.change(function(evt) { - var clickedIndex = $(this).data('dataset-index'); - var isChecked = $(this).prop('checked'); - distribution_chart.config.data.datasets[clickedIndex].hidden = !isChecked; - distribution_chart.update(); - }); - label.append(checkbox); - label.append(item.label); - div.append(label); - } - distri_graph.append(div); - }, - error: function( jqXhr, textStatus, errorThrown ){ - console.log( errorThrown ); - } - }); - }); + // create checkboxes + var div = $('
'); + div.addClass('distribution_checkboxes_dataset'); + var distri_graph = $('#eventdistri_graph'); + var distriOffset = distri_graph.offset(); + var distriHeight = distri_graph.height()/2; + div.css({left: '50px'}); + for (var i in doughnut_dataset) { + var item = doughnut_dataset[i]; + var label = $(''); + label.addClass('useCursorPointer'); + label.css({'user-select': 'none'}); + var checkbox = $(''); + checkbox.data('dataset-index', i); + checkbox.prop('checked', true); + checkbox.change(function(evt) { + var clickedIndex = $(this).data('dataset-index'); + var isChecked = $(this).prop('checked'); + distribution_chart.config.data.datasets[clickedIndex].hidden = !isChecked; + distribution_chart.update(); + }); + label.append(checkbox); + label.append(item.label); + div.append(label); + } + distri_graph.append(div); + }, + error: function( jqXhr, textStatus, errorThrown ){ + console.log( errorThrown ); + } + }); + }); }); From 2260be4194143e1dce6955a90ca7bed171641954 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 26 Feb 2019 14:40:48 +0100 Subject: [PATCH 02/25] chg: [distributionGraph] Started advanced distribution view --- app/webroot/css/distribution-graph.css | 9 ++++ app/webroot/js/event-distribution-graph.js | 54 +++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/app/webroot/css/distribution-graph.css b/app/webroot/css/distribution-graph.css index d19c6ea22..170e1c4fa 100644 --- a/app/webroot/css/distribution-graph.css +++ b/app/webroot/css/distribution-graph.css @@ -105,3 +105,12 @@ border-radius: 4px; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); } + +.advancedSharingNetwork { + position: absolute; + background: white; + z-index: 1; + border: 1px solid #0088cc; + border-radius: 6px; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); +} diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index bde0eda46..f0f7ea4cc 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -4,6 +4,7 @@ var extended_text = $('#eventdistri_graph').data('extended') == 1 ? true : false var spanOffset_orig = 15; // due to padding var payload = {}; var distribution_chart; +var distributionData; function clickHandlerGraph(evt) { var firstPoint = distribution_chart.getElementAtEvent(evt)[0]; @@ -184,9 +185,58 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { } } + +function showAdvancedSharing() { + var $popover = $('#eventdistri_graph').parent().parent(); + var boundingRect = $popover[0].getBoundingClientRect() + var $div = $('
'); + $div.css({ + left: boundingRect.left + boundingRect.width + 'px', + top: boundingRect.top + 'px', + 'min-width': boundingRect.width, + 'min-height': boundingRect.height + }); + $('body').append($div); + + var nodes = new vis.DataSet([ + {id: 'root', label: 'Event'} + ]); + var edges = new vis.DataSet([]); + + // Community + var nodesToAdd = []; + var edgesToAdd = []; + distributionData.additionalDistributionInfo[1].forEach(function(orgName) { + console.log(orgName); + nodesToAdd.push({ id: orgName, label: orgName }); + edgesToAdd.push({ from: 'root', to: orgName}); + }); + // Connected Community + distributionData.additionalDistributionInfo[2].forEach(function(orgName) { + console.log(orgName); + nodesToAdd.push({ id: orgName, label: orgName }); + edgesToAdd.push({ from: 'root', to: orgName}); + }); + // All Community + distributionData.additionalDistributionInfo[3].forEach(function(orgName) { + nodesToAdd.push({ id: orgName, label: orgName }); + edgesToAdd.push({ from: 'root', to: orgName}); + }); + // Sharing Group + // distributionData.additionalDistributionInfo.4.foreach(function(orgName) { + // `var temp = { id: orgName, label: orgName }; + // toAdd.push(temp); + // });` + + var data = { nodes: nodes, edges: edges }; + var network_options = {}; + var advancedSharingNetwork = new vis.Network(document.getElementById('advancedSharingNetworkContainer'), data, network_options); +} + $(document).ready(function() { + var rightBtn = ''; var pop = $('.distribution_graph').popover({ - title: "Distribution graph [atomic event]", + title: "Distribution graph [atomic event]" + rightBtn, html: true, content: function() { return $('#distribution_graph_container').html(); }, template : '' @@ -217,6 +267,8 @@ $(document).ready(function() { $(".loadingPopover").show(); }, success: function( data, textStatus, jQxhr ){ + console.log(data); + distributionData = data; $(".loadingPopover").hide(); // DISTRIBUTION PROGRESSBAR From 63bc9c596766f30f6eca79015eeb6a7e1241d1f4 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Wed, 27 Feb 2019 11:43:07 +0100 Subject: [PATCH 03/25] chg: [distributionGraph] Continuation of integration, basic distribution is supported - WiP --- app/webroot/js/event-distribution-graph.js | 258 ++++++++++++++++++--- 1 file changed, 231 insertions(+), 27 deletions(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index f0f7ea4cc..ec7b4078e 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -185,56 +185,259 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { } } - -function showAdvancedSharing() { +var a; +var n; +function showAdvancedSharing(clicked) { + $clicked = $(clicked); + var network_active = $clicked.data('networkactive'); + if (network_active !== undefined && network_active === true) { + $('#advancedSharingNetwork').hide('slide', {}, 300); + $clicked.data('networkactive', false); + return; + } else if (network_active !== undefined && network_active === false) { + $('#advancedSharingNetwork').show('slide', {}, 300); + $clicked.data('networkactive', true); + return; + } + $clicked.data('networkactive', true); var $popover = $('#eventdistri_graph').parent().parent(); var boundingRect = $popover[0].getBoundingClientRect() - var $div = $('
'); + var $div = $(''); $div.css({ left: boundingRect.left + boundingRect.width + 'px', top: boundingRect.top + 'px', - 'min-width': boundingRect.width, - 'min-height': boundingRect.height + width: 800 + 'px', + height: 800 + 'px' }); $('body').append($div); + $div.toggle('slide', {}, 300); + var EDGE_LENGTH_HUB = 300; var nodes = new vis.DataSet([ - {id: 'root', label: 'Event'} - ]); - var edges = new vis.DataSet([]); + {id: 'root', group: 'root', x: 0, y: 0, fixed: true}, + {id: 'org-only', label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, + {id: 'this-community', label: 'This community', group: 'root-this-community'}, + {id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}, + {id: 'all-community', label: 'All community', group: 'web'}, + + ]); + var edges = new vis.DataSet([ + {from: 'root', to: 'org-only', length: 30}, + ]); + var toID; + switch (event_distribution) { + case 0: + toID = 'org-only'; + break; + case 1: + toID = 'this-community'; + break; + case 2: + toID = 'connected-community'; + break; + case 3: + toID = 'all-community'; + break; + case 4: + toID = 'sharing-group'; + break; + default: + break; + } + edges.add({from: 'root', to: toID}); - // Community var nodesToAdd = []; var edgesToAdd = []; - distributionData.additionalDistributionInfo[1].forEach(function(orgName) { - console.log(orgName); - nodesToAdd.push({ id: orgName, label: orgName }); - edgesToAdd.push({ from: 'root', to: orgName}); - }); - // Connected Community - distributionData.additionalDistributionInfo[2].forEach(function(orgName) { - console.log(orgName); - nodesToAdd.push({ id: orgName, label: orgName }); - edgesToAdd.push({ from: 'root', to: orgName}); - }); + + // Community + if (event_distribution >= 1) { + inject_this_community_org(nodesToAdd, edgesToAdd, distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); + } + if (event_distribution >= 2) { + // Connected Community + distributionData.additionalDistributionInfo[2].forEach(function(orgName) { + if (orgName === 'This community') { + edgesToAdd.push({from: 'connected-community', to: 'this-community', length: EDGE_LENGTH_HUB}); + } else { + nodesToAdd.push({ + id: 'connected-community_' + orgName, + label: orgName, + group: 'connected-community' + }); + edgesToAdd.push({from: 'connected-community', to: 'connected-community_' + orgName}); + } + }); + } + // All Community - distributionData.additionalDistributionInfo[3].forEach(function(orgName) { - nodesToAdd.push({ id: orgName, label: orgName }); - edgesToAdd.push({ from: 'root', to: orgName}); - }); + if (event_distribution >= 3) { + distributionData.additionalDistributionInfo[3].forEach(function(orgName) { + if (orgName === 'This community') { + edgesToAdd.push({from: 'all-community', to: 'this-community', length: EDGE_LENGTH_HUB}); + } else if (orgName === 'All other communities') { + edgesToAdd.push({from: 'all-community', to: 'connected-community', length: EDGE_LENGTH_HUB}); + } else { + nodesToAdd.push({ + id: 'all-community_' + orgName, + label: orgName, + group: 'all-community' + }); + edgesToAdd.push({from: 'root', to: 'all-community_' + orgName}); + } + }); + } // Sharing Group // distributionData.additionalDistributionInfo.4.foreach(function(orgName) { // `var temp = { id: orgName, label: orgName }; // toAdd.push(temp); // });` + nodes.add(nodesToAdd); + edges.add(edgesToAdd); var data = { nodes: nodes, edges: edges }; - var network_options = {}; - var advancedSharingNetwork = new vis.Network(document.getElementById('advancedSharingNetworkContainer'), data, network_options); + var network_options = { + width: '800px', + height: '800px', + layout: {randomSeed: 0}, + edges: { + arrows: { + to: {enabled: true, scaleFactor:1, type:'arrow'}, + } + }, + physics:{ + barnesHut: { + gravitationalConstant: -2000, + centralGravity: 0.3, + springLength: 150, + springConstant: 0.02, + damping: 0.09, + avoidOverlap: 0 + }, + repulsion: { + centralGravity: 0.2, + springLength: 200, + springConstant: 0.02, + nodeDistance: 200, + damping: 0.15 + }, + + solver: 'barnesHut' + }, + groups: { + 'root': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf10c', + color: '#000000', + size: 30 + }, + font: {size: 30}, + color: '#000000', + }, + 'org-only': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf2c2', + color: '#ff0000', + size: 30 + }, + font: { + size: 14, // px + color: '#ff0000', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#ff0000', + }, + 'root-this-community': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf1e1', + color: '#ff9725', + size: 70 + }, + font: { + size: 18, // px + color: '#ff9725', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#ff9725', + }, + 'this-community': { + font: {color: 'white'}, + color: '#ff9725' + }, + 'root-connected-community': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf0e8', + color: '#9b6e1b', + size: 70 + }, + font: { + size: 18, // px + color: '#9b6e1b', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#9b6e1b', + }, + 'connected-community': { + shape: 'image', + image: '/img/orgs/MISP.png' + }, + 'web': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf0ac', + color: '#007d20', + size: 70 + }, + font: { + size: 18, // px + color: '#007d20', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#007d20', + }, + 'root-sharing-group': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf0c0', + color: '#9b6e1b', + size: 70 + }, + font: { + size: 18, // px + color: '#1369a0', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#1369a0', + } + } + }; + var advancedSharingNetwork = new vis.Network(document.getElementById('advancedSharingNetwork'), data, network_options); + a = nodes; + n = advancedSharingNetwork; +} + +function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { + orgs.forEach(function(orgName) { + nodesToAdd.push({ + id: group + '_' + orgName, + label: orgName, + group: group + }); + edgesToAdd.push({ from: root, to: group + '_' + orgName}); + }); } $(document).ready(function() { - var rightBtn = ''; + var rightBtn = ''; var pop = $('.distribution_graph').popover({ title: "Distribution graph [atomic event]" + rightBtn, html: true, @@ -252,6 +455,7 @@ $(document).ready(function() { $('.distribution_graph').click(function() { if ($(this).data('shown') == 'true') { $(this).data('shown', 'false'); + $('#advancedSharingNetwork').hide('slide', {}, 200, function() { $('#advancedSharingNetwork').remove(); }); return; } else { $(this).data('shown', 'true'); From ef045e01b3d96e5e630aa1f41fe947803bed4f51 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Wed, 27 Feb 2019 15:34:20 +0100 Subject: [PATCH 04/25] chg: [distributionGraph] Added support of sharing group - WiP --- app/Lib/Tools/DistributionGraphTool.php | 6 +- app/webroot/js/event-distribution-graph.js | 101 ++++++++++++++++----- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/app/Lib/Tools/DistributionGraphTool.php b/app/Lib/Tools/DistributionGraphTool.php index 20483d040..075b566f6 100644 --- a/app/Lib/Tools/DistributionGraphTool.php +++ b/app/Lib/Tools/DistributionGraphTool.php @@ -16,8 +16,10 @@ // construct distribution info $this->__json['distributionInfo'] = array(); - $sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'name', 1); - $this->__json['allSharingGroup'] = h(array_values($sgs)); + // $sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'name', 1); + // $this->__json['allSharingGroup'] = h(array_values($sgs)); + $sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'simplified', 1); + $this->__json['allSharingGroup'] = h($sgs); $distributionLevels = $this->__eventModel->distributionLevels; foreach ($distributionLevels as $key => $value) { $this->__json['distributionInfo'][$key] = array('key' => h($value), 'desc' => h($this->__eventModel->distributionDescriptions[$key]['formdesc']), 'value' => h($key)); diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index ec7b4078e..a3a48c639 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -187,6 +187,7 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { } var a; var n; +var cacheAddedOrgName = {}; function showAdvancedSharing(clicked) { $clicked = $(clicked); var network_active = $clicked.data('networkactive'); @@ -215,19 +216,19 @@ function showAdvancedSharing(clicked) { var EDGE_LENGTH_HUB = 300; var nodes = new vis.DataSet([ {id: 'root', group: 'root', x: 0, y: 0, fixed: true}, - {id: 'org-only', label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, - {id: 'this-community', label: 'This community', group: 'root-this-community'}, - {id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}, - {id: 'all-community', label: 'All community', group: 'web'}, + {id: distributionData.additionalDistributionInfo[0][0], label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, + // {id: 'this-community', label: 'This community', group: 'root-this-community'}, + // {id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}, + // {id: 'all-community', label: 'All community', group: 'web'}, ]); var edges = new vis.DataSet([ - {from: 'root', to: 'org-only', length: 30}, + {from: 'root', to: distributionData.additionalDistributionInfo[0][0], length: 30, width: 3}, ]); var toID; switch (event_distribution) { case 0: - toID = 'org-only'; + toID = false; break; case 1: toID = 'this-community'; @@ -244,17 +245,23 @@ function showAdvancedSharing(clicked) { default: break; } - edges.add({from: 'root', to: toID}); + + if (toID !== false) { + edges.add({from: 'root', to: toID, width: 3}); + } var nodesToAdd = []; var edgesToAdd = []; + cacheAddedOrgName[distributionData.additionalDistributionInfo[0][0]] = 1; // Community if (event_distribution >= 1) { inject_this_community_org(nodesToAdd, edgesToAdd, distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); + nodesToAdd.push({id: 'this-community', label: 'This community', group: 'root-this-community'}); } if (event_distribution >= 2) { // Connected Community + nodesToAdd.push({id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}); distributionData.additionalDistributionInfo[2].forEach(function(orgName) { if (orgName === 'This community') { edgesToAdd.push({from: 'connected-community', to: 'this-community', length: EDGE_LENGTH_HUB}); @@ -271,26 +278,46 @@ function showAdvancedSharing(clicked) { // All Community if (event_distribution >= 3) { + nodesToAdd.push({id: 'all-community', label: 'All community', group: 'web'}); distributionData.additionalDistributionInfo[3].forEach(function(orgName) { if (orgName === 'This community') { edgesToAdd.push({from: 'all-community', to: 'this-community', length: EDGE_LENGTH_HUB}); } else if (orgName === 'All other communities') { edgesToAdd.push({from: 'all-community', to: 'connected-community', length: EDGE_LENGTH_HUB}); - } else { - nodesToAdd.push({ - id: 'all-community_' + orgName, - label: orgName, - group: 'all-community' - }); - edgesToAdd.push({from: 'root', to: 'all-community_' + orgName}); } }); } // Sharing Group - // distributionData.additionalDistributionInfo.4.foreach(function(orgName) { - // `var temp = { id: orgName, label: orgName }; - // toAdd.push(temp); - // });` + if (distributionData.event[4] > 0) { + distributionData.allSharingGroup.forEach(function(sg) { + var sgName = sg.SharingGroup.name; + nodesToAdd.push({ + id: 'sharing-group_' + sgName, + label: sgName, + group: 'root-sharing-group' + }); + edgesToAdd.push({from: 'root', to: 'sharing-group_' + sgName, width: 3}); + sg.SharingGroupOrg.forEach(function(org) { + var sgOrgName = org.Organisation.name; + if (cacheAddedOrgName[sgOrgName] === undefined) { + nodesToAdd.push({ + id: sgOrgName, + label: sgOrgName, + group: 'sharing-group' + }); + cacheAddedOrgName[sgOrgName] = 1; + } + edgesToAdd.push({ + from: 'sharing-group_' + sgName, + to: sgOrgName, + arrows: { + to: { enabled: false } + }, + color: { opacity: 0.4 } + }); + }); + }); + } nodes.add(nodesToAdd); edges.add(edgesToAdd); @@ -302,6 +329,12 @@ function showAdvancedSharing(clicked) { edges: { arrows: { to: {enabled: true, scaleFactor:1, type:'arrow'}, + }, + shadow: { + enabled: true, + size: 7, + x: 3, + y: 3 } }, physics:{ @@ -323,6 +356,14 @@ function showAdvancedSharing(clicked) { solver: 'barnesHut' }, + nodes: { + shadow: { + enabled: true, + size: 7, + x: 3, + y: 3 + } + }, groups: { 'root': { shape: 'icon', @@ -330,7 +371,7 @@ function showAdvancedSharing(clicked) { face: 'FontAwesome', code: '\uf10c', color: '#000000', - size: 30 + size: 50 }, font: {size: 30}, color: '#000000', @@ -408,7 +449,7 @@ function showAdvancedSharing(clicked) { icon: { face: 'FontAwesome', code: '\uf0c0', - color: '#9b6e1b', + color: '#1369a0', size: 70 }, font: { @@ -427,12 +468,22 @@ function showAdvancedSharing(clicked) { function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { orgs.forEach(function(orgName) { - nodesToAdd.push({ - id: group + '_' + orgName, - label: orgName, - group: group + if (cacheAddedOrgName[orgName] === undefined) { + nodesToAdd.push({ + id: orgName, + label: orgName, + group: group + }); + cacheAddedOrgName[orgName] = 1; + } + edgesToAdd.push({ + from: root, + to: orgName, + arrows: { + to: { enabled: false } + }, + color: { opacity: 0.4 } }); - edgesToAdd.push({ from: root, to: group + '_' + orgName}); }); } From fd453eafb234d3806e22819e6d2f8e546a94e66f Mon Sep 17 00:00:00 2001 From: mokaddem Date: Wed, 27 Feb 2019 15:54:05 +0100 Subject: [PATCH 05/25] chg: [distributionGraph] Pin node after drag --- app/webroot/js/event-distribution-graph.js | 35 ++++++++++++++-------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index a3a48c639..5d6c2b8b1 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -5,6 +5,10 @@ var spanOffset_orig = 15; // due to padding var payload = {}; var distribution_chart; var distributionData; +var cacheAddedOrgName = {}; +var nodes_distri; +var edges_distri; +var advancedSharingNetwork; function clickHandlerGraph(evt) { var firstPoint = distribution_chart.getElementAtEvent(evt)[0]; @@ -185,9 +189,7 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { } } -var a; -var n; -var cacheAddedOrgName = {}; + function showAdvancedSharing(clicked) { $clicked = $(clicked); var network_active = $clicked.data('networkactive'); @@ -214,7 +216,7 @@ function showAdvancedSharing(clicked) { $div.toggle('slide', {}, 300); var EDGE_LENGTH_HUB = 300; - var nodes = new vis.DataSet([ + nodes_distri = new vis.DataSet([ {id: 'root', group: 'root', x: 0, y: 0, fixed: true}, {id: distributionData.additionalDistributionInfo[0][0], label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, // {id: 'this-community', label: 'This community', group: 'root-this-community'}, @@ -222,7 +224,7 @@ function showAdvancedSharing(clicked) { // {id: 'all-community', label: 'All community', group: 'web'}, ]); - var edges = new vis.DataSet([ + edges_distri = new vis.DataSet([ {from: 'root', to: distributionData.additionalDistributionInfo[0][0], length: 30, width: 3}, ]); var toID; @@ -247,7 +249,7 @@ function showAdvancedSharing(clicked) { } if (toID !== false) { - edges.add({from: 'root', to: toID, width: 3}); + edges_distri.add({from: 'root', to: toID, width: 3}); } var nodesToAdd = []; @@ -319,9 +321,9 @@ function showAdvancedSharing(clicked) { }); } - nodes.add(nodesToAdd); - edges.add(edgesToAdd); - var data = { nodes: nodes, edges: edges }; + nodes_distri.add(nodesToAdd); + edges_distri.add(edgesToAdd); + var data = { nodes: nodes_distri, edges: edges_distri }; var network_options = { width: '800px', height: '800px', @@ -461,9 +463,18 @@ function showAdvancedSharing(clicked) { } } }; - var advancedSharingNetwork = new vis.Network(document.getElementById('advancedSharingNetwork'), data, network_options); - a = nodes; - n = advancedSharingNetwork; + advancedSharingNetwork = new vis.Network(document.getElementById('advancedSharingNetwork'), data, network_options); + + advancedSharingNetwork.on("dragStart", function (params) { + params.nodes.forEach(function(nodeId) { + nodes_distri.update({id: nodeId, fixed: {x: false, y: false}}); + }); + }); + advancedSharingNetwork.on("dragEnd", function (params) { + params.nodes.forEach(function(nodeId) { + nodes_distri.update({id: nodeId, fixed: {x: true, y: true}}); + }); + }); } function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { From daebb1f0e7f1dd2c6e0612a0ddb9473c818f38a7 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Thu, 28 Feb 2019 12:39:40 +0100 Subject: [PATCH 06/25] chg: [distributionGraph] Added interactive plotting feature --- app/webroot/css/distribution-graph.css | 8 +- app/webroot/js/event-distribution-graph.js | 131 +++++++++++++++++---- 2 files changed, 112 insertions(+), 27 deletions(-) diff --git a/app/webroot/css/distribution-graph.css b/app/webroot/css/distribution-graph.css index 170e1c4fa..73429a310 100644 --- a/app/webroot/css/distribution-graph.css +++ b/app/webroot/css/distribution-graph.css @@ -107,8 +107,12 @@ } .advancedSharingNetwork { - position: absolute; - background: white; + position: fixed; + top: 45px; + right: 0px; + height: 800px; + width: 800px; + background: #ffffffcc;; z-index: 1; border: 1px solid #0088cc; border-radius: 6px; diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 5d6c2b8b1..0282072af 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -5,6 +5,8 @@ var spanOffset_orig = 15; // due to padding var payload = {}; var distribution_chart; var distributionData; + +var EDGE_LENGTH_HUB = 300; var cacheAddedOrgName = {}; var nodes_distri; var edges_distri; @@ -194,43 +196,55 @@ function showAdvancedSharing(clicked) { $clicked = $(clicked); var network_active = $clicked.data('networkactive'); if (network_active !== undefined && network_active === true) { - $('#advancedSharingNetwork').hide('slide', {}, 300); + $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 300); $clicked.data('networkactive', false); return; } else if (network_active !== undefined && network_active === false) { - $('#advancedSharingNetwork').show('slide', {}, 300); + $('#advancedSharingNetworkWrapper').show('slide', {direction: 'right'}, 300); $clicked.data('networkactive', true); return; } $clicked.data('networkactive', true); var $popover = $('#eventdistri_graph').parent().parent(); var boundingRect = $popover[0].getBoundingClientRect() - var $div = $(''); - $div.css({ - left: boundingRect.left + boundingRect.width + 'px', - top: boundingRect.top + 'px', - width: 800 + 'px', - height: 800 + 'px' - }); - $('body').append($div); - $div.toggle('slide', {}, 300); + var $div = $(''); + + $('body').append($div); + $div.toggle('slide', {direction: 'right'}, 300); + + construct_network(); +} + +function construct_network(target_distribution, scope_text, overwriteSg) { + if (advancedSharingNetwork !== undefined) { + advancedSharingNetwork.destroy(); + } + if (scope_text == undefined) { + scope_text = 'Event ' + scope_id; + } + $('#sharingNetworkTargetId').val(scope_text); - var EDGE_LENGTH_HUB = 300; nodes_distri = new vis.DataSet([ - {id: 'root', group: 'root', x: 0, y: 0, fixed: true}, + {id: 'root', group: 'root', label: scope_text, x: 0, y: 0, fixed: true}, {id: distributionData.additionalDistributionInfo[0][0], label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, - // {id: 'this-community', label: 'This community', group: 'root-this-community'}, - // {id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}, - // {id: 'all-community', label: 'All community', group: 'web'}, ]); edges_distri = new vis.DataSet([ {from: 'root', to: distributionData.additionalDistributionInfo[0][0], length: 30, width: 3}, ]); - var toID; - switch (event_distribution) { + var toID = false;; + if (target_distribution === undefined || target_distribution == 5) { + target_distribution = event_distribution; + } + switch (target_distribution) { case 0: - toID = false; break; case 1: toID = 'this-community'; @@ -249,7 +263,18 @@ function showAdvancedSharing(clicked) { } if (toID !== false) { - edges_distri.add({from: 'root', to: toID, width: 3}); + var edgeData = {from: 'root', to: toID, width: 3}; + // Event always restrict propagation (sharing group is a special case) + if (target_distribution !== 4 && target_distribution > event_distribution) { + edgeData.label = 'X'; + edgeData.font = { + size: 50, + color: '#ff0000', + strokeWidth: 6, + strokeColor: '#ff0000' + }; + } + edges_distri.add(edgeData); } var nodesToAdd = []; @@ -257,11 +282,11 @@ function showAdvancedSharing(clicked) { cacheAddedOrgName[distributionData.additionalDistributionInfo[0][0]] = 1; // Community - if (event_distribution >= 1) { - inject_this_community_org(nodesToAdd, edgesToAdd, distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); + if (target_distribution >= 1 && target_distribution != 4) { nodesToAdd.push({id: 'this-community', label: 'This community', group: 'root-this-community'}); + inject_this_community_org(nodesToAdd, edgesToAdd, distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); } - if (event_distribution >= 2) { + if (target_distribution >= 2 && target_distribution != 4) { // Connected Community nodesToAdd.push({id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}); distributionData.additionalDistributionInfo[2].forEach(function(orgName) { @@ -279,7 +304,7 @@ function showAdvancedSharing(clicked) { } // All Community - if (event_distribution >= 3) { + if (target_distribution >= 3 && target_distribution != 4) { nodesToAdd.push({id: 'all-community', label: 'All community', group: 'web'}); distributionData.additionalDistributionInfo[3].forEach(function(orgName) { if (orgName === 'This community') { @@ -293,6 +318,10 @@ function showAdvancedSharing(clicked) { if (distributionData.event[4] > 0) { distributionData.allSharingGroup.forEach(function(sg) { var sgName = sg.SharingGroup.name; + if (overwriteSg !== undefined && overwriteSg.indexOf(sgName) == -1) { + return true; + } + nodesToAdd.push({ id: 'sharing-group_' + sgName, label: sgName, @@ -475,8 +504,60 @@ function showAdvancedSharing(clicked) { nodes_distri.update({id: nodeId, fixed: {x: true, y: true}}); }); }); + + $('#interactive_picking_mode').off('change').on('change', function(e) { + var target_id = $(this).val(); + if (this.checked) { + toggleRowListener(true); + } else { + toggleRowListener(false); + construct_network(event_distribution) + } + }); } +function toggleRowListener(toAdd) { + if (toAdd) { + $('#attributes_div table tr').off('click.advancedSharing').on('click.advancedSharing', function() { + var $row = $(this); + var clicked_type = $row.attr('id').split('_')[0]; + var clicked_id = $row.attr('id').split('_')[1]; + // var $dist_cell = $row.find('#'+clicked_type+'_'+clicked_id+'_distribution_solid'); + var $dist_cell = $row.find('div').filter(function() { + return $(this).attr('id') !== undefined && $(this).attr('id').includes(clicked_id+'_distribution'); + }); + + var distribution_value; + var overwriteSg; + switch ($dist_cell.text().trim()) { + case 'Organisation': + distribution_value = 0; + break; + case 'Community': + distribution_value = 1; + break; + case 'Connected': + distribution_value = 2; + break; + case 'All': + distribution_value = 3; + break; + case 'Inherit': + distribution_value = 5; + break; + default: + distribution_value = 4; + overwriteSg = $dist_cell.text().trim(); + break + } + construct_network(distribution_value, clicked_type+' '+clicked_id, [overwriteSg]); + }); + } else { + $('#attributes_div table tr').off('click.advancedSharing'); + } +} + + function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { orgs.forEach(function(orgName) { if (cacheAddedOrgName[orgName] === undefined) { @@ -517,7 +598,7 @@ $(document).ready(function() { $('.distribution_graph').click(function() { if ($(this).data('shown') == 'true') { $(this).data('shown', 'false'); - $('#advancedSharingNetwork').hide('slide', {}, 200, function() { $('#advancedSharingNetwork').remove(); }); + $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 200, function() { $('#advancedSharingNetworkWrapper').remove(); }); return; } else { $(this).data('shown', 'true'); From 3311f5af4b3c46c10e89d85124d5eaba948b856f Mon Sep 17 00:00:00 2001 From: mokaddem Date: Thu, 28 Feb 2019 13:39:53 +0100 Subject: [PATCH 07/25] chg: [distributionGraph] Show `event is empty` if the event is empty --- app/webroot/js/event-distribution-graph.js | 58 +++++++++++++--------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 0282072af..c43c55622 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -614,7 +614,6 @@ $(document).ready(function() { $(".loadingPopover").show(); }, success: function( data, textStatus, jQxhr ){ - console.log(data); distributionData = data; $(".loadingPopover").hide(); @@ -707,31 +706,44 @@ $(document).ready(function() { ]; var ctx = document.getElementById("distribution_graph_canvas"); ctx.onclick = function(evt) { clickHandlerGraph(evt); }; - distribution_chart = new Chart(ctx, { - type: 'doughnut', - data: { - labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }), - distribution: data.distributionInfo, - datasets: doughnut_dataset, - }, - options: { - title: { - display: false + + var count = 0; + for (var i=0, n=data.event.length; i < n; i++) { + count += data.event[i]; + } + if (count > 0) { + distribution_chart = new Chart(ctx, { + type: 'doughnut', + data: { + labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }), + distribution: data.distributionInfo, + datasets: doughnut_dataset, }, - animation: { - duration: 500 - }, - tooltips: { - callbacks: { - label: function(item, data) { - return data.datasets[item.datasetIndex].label - + " - " + data.labels[item.index] - + ": " + data.datasets[item.datasetIndex].data[item.index]; + options: { + title: { + display: false + }, + animation: { + duration: 500 + }, + tooltips: { + callbacks: { + label: function(item, data) { + return data.datasets[item.datasetIndex].label + + " - " + data.labels[item.index] + + ": " + data.datasets[item.datasetIndex].data[item.index]; + } } } - } - }, - }); + }, + }); + } else { + var canvas = ctx; + ctx = canvas.getContext("2d"); + ctx.font = "30px Comic Sans MS"; + ctx.textAlign = "center"; + ctx.fillText("Event is empty", canvas.width/2, canvas.height/2); + } // create checkboxes var div = $('
'); From 8bec4df16d84e96bc6d48a83bc892b3080aa6686 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Thu, 28 Feb 2019 14:55:38 +0100 Subject: [PATCH 08/25] chg: [distributionGraph] Added possibility to focus on an organisation --- app/webroot/css/distribution-graph.css | 4 +++ app/webroot/js/event-distribution-graph.js | 29 ++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/app/webroot/css/distribution-graph.css b/app/webroot/css/distribution-graph.css index 73429a310..bdfbb3296 100644 --- a/app/webroot/css/distribution-graph.css +++ b/app/webroot/css/distribution-graph.css @@ -118,3 +118,7 @@ border-radius: 6px; box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); } + +.positionAbsolute { + position: absolute !important; +} diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index c43c55622..b18ecdf38 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -210,10 +210,11 @@ function showAdvancedSharing(clicked) { var $div = $(''); $('body').append($div); @@ -606,7 +607,7 @@ function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { } $(document).ready(function() { - var rightBtn = ''; + var rightBtn = ''; var pop = $('.distribution_graph').popover({ title: "Distribution graph [atomic event]" + rightBtn, html: true, From aad2060fa208822be164a442c36e8cce16231002 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Thu, 28 Feb 2019 15:42:11 +0100 Subject: [PATCH 11/25] fix: [distributionGraph] Org's name with spaces can be focused --- app/webroot/js/event-distribution-graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 4092a342c..74c82575e 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -357,7 +357,7 @@ function construct_network(target_distribution, scope_text, overwriteSg) { var options = ''; $('#sharingNetworkOrgFinder').empty(); Object.keys(cacheAddedOrgName).forEach(function(org) { - options += ''; + options += ''; }); $('#sharingNetworkOrgFinder').append(options) .trigger('chosen:updated') From 6b6d07abb287397a936d6d7386a9244b686d8ebb Mon Sep 17 00:00:00 2001 From: mokaddem Date: Thu, 28 Feb 2019 16:12:43 +0100 Subject: [PATCH 12/25] fix: [distributionGraph:network] Only use sharing group part of the event --- app/webroot/js/event-distribution-graph.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 74c82575e..3ab07f752 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -322,7 +322,10 @@ function construct_network(target_distribution, scope_text, overwriteSg) { if (distributionData.event[4] > 0) { distributionData.allSharingGroup.forEach(function(sg) { var sgName = sg.SharingGroup.name; - if (overwriteSg !== undefined && overwriteSg.indexOf(sgName) == -1) { + if (overwriteSg === undefined) { // if overwriteSg not set, use the one from the event + overwriteSg = distributionData.additionalDistributionInfo[4]; + } + if (overwriteSg.indexOf(sgName) == -1) { return true; } @@ -385,6 +388,7 @@ function construct_network(target_distribution, scope_text, overwriteSg) { height: '800px', layout: {randomSeed: 0}, edges: { + arrowStrikethrough: false, arrows: { to: {enabled: true, scaleFactor:1, type:'arrow'}, }, @@ -466,7 +470,9 @@ function construct_network(target_distribution, scope_text, overwriteSg) { }, 'this-community': { font: {color: 'white'}, - color: '#ff9725' + color: '#ff9725', + shape: 'box', + margin: 3 }, 'root-connected-community': { shape: 'icon', From 24d8f197eff80a79a6d29d2bee7ac03201811e3c Mon Sep 17 00:00:00 2001 From: mokaddem Date: Fri, 1 Mar 2019 10:56:33 +0100 Subject: [PATCH 13/25] new: [DistributionGraph] Added pie chart on sharing group. fix #4101 --- app/Lib/Tools/DistributionGraphTool.php | 7 ++++ app/webroot/js/event-distribution-graph.js | 38 +++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/Lib/Tools/DistributionGraphTool.php b/app/Lib/Tools/DistributionGraphTool.php index 075b566f6..7f7656d0e 100644 --- a/app/Lib/Tools/DistributionGraphTool.php +++ b/app/Lib/Tools/DistributionGraphTool.php @@ -61,6 +61,12 @@ $this->__json['additionalDistributionInfo'][$distributionLevel] = array(); } $this->__json['additionalDistributionInfo'][$distributionLevel][h($data)] = 0; // set-alike + if ($distributionLevel == 4) { + if (!isset($this->__json['sharingGroupRepartition'][h($data)])) { + $this->__json['sharingGroupRepartition'][h($data)] = 0; + } + $this->__json['sharingGroupRepartition'][h($data)]++; + } } private function __addOtherDistributionInfo() @@ -136,6 +142,7 @@ $this->__json['object'] = $this->init_array_distri(); $this->__json['obj_attr'] = $this->init_array_distri(); $this->__json['additionalDistributionInfo'] = $this->init_array_distri(array()); + $this->__json['sharingGroupRepartition'] = array(); if (empty($event)) { diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 3ab07f752..04155a224 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -56,6 +56,39 @@ function generate_additional_info(info) { } } +function generate_pie_chart(data, placeholder) { + var labels = Object.keys(data); + var dough_data = labels.map(function(l) { + return data[l]; + }); + + if (labels.length == 0) { + return + } else { + var sgDistributionChart = new Chart(placeholder, { + type: 'doughnut', + data: { + labels: labels, + datasets: [{ + data: dough_data, + backgroundColor: labels.map(function(l) { return '#7a86e0'; }) + }], + }, + options: { + title: { + display: false + }, + animation: { + duration: 500 + }, + legend: { + display: false + } + }, + }); + } +} + function clickHandlerPbText(evt) { var distribution_id = evt.target.dataset.distribution; var value_to_set = String(distribution_id); @@ -708,10 +741,13 @@ $(document).ready(function() { placement: 'bottom', trigger: 'click', title: 'Sharing group', - content: 'Distribution description: ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]), + content: 'Distribution description: ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]) + '
', container: 'body', html: true, template: '' + }) + .click(function() { + generate_pie_chart(data.sharingGroupRepartition, document.getElementById('sg_distribution_graph_canvas')); }); // doughtnut From ead0b96e134e9cb1575e5bcde592c2280e22a81b Mon Sep 17 00:00:00 2001 From: mokaddem Date: Fri, 1 Mar 2019 14:55:51 +0100 Subject: [PATCH 14/25] chg: [distributionGraphNetwork] Adjusted gravitationalConstant and mass --- app/Lib/Tools/DistributionGraphTool.php | 2 -- app/webroot/js/event-distribution-graph.js | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Lib/Tools/DistributionGraphTool.php b/app/Lib/Tools/DistributionGraphTool.php index 7f7656d0e..64c3a783c 100644 --- a/app/Lib/Tools/DistributionGraphTool.php +++ b/app/Lib/Tools/DistributionGraphTool.php @@ -16,8 +16,6 @@ // construct distribution info $this->__json['distributionInfo'] = array(); - // $sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'name', 1); - // $this->__json['allSharingGroup'] = h(array_values($sgs)); $sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'simplified', 1); $this->__json['allSharingGroup'] = h($sgs); $distributionLevels = $this->__eventModel->distributionLevels; diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 04155a224..bcf92464c 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -268,7 +268,7 @@ function construct_network(target_distribution, scope_text, overwriteSg) { $('#sharingNetworkTargetId').val(scope_text); nodes_distri = new vis.DataSet([ - {id: 'root', group: 'root', label: scope_text, x: 0, y: 0, fixed: true}, + {id: 'root', group: 'root', label: scope_text, x: 0, y: 0, fixed: true, mass: 20}, {id: distributionData.additionalDistributionInfo[0][0], label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, ]); @@ -434,7 +434,7 @@ function construct_network(target_distribution, scope_text, overwriteSg) { }, physics:{ barnesHut: { - gravitationalConstant: -2000, + gravitationalConstant: -10000, centralGravity: 0.3, springLength: 150, springConstant: 0.02, From 4727628143f2c83b9d2388f34e0524c500476b52 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Fri, 1 Mar 2019 16:18:08 +0100 Subject: [PATCH 15/25] chg: [distributionGraphNetwork] Improved sharing accuracy --- app/webroot/js/event-distribution-graph.js | 107 ++++++++++++++------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index bcf92464c..bc0c92d2b 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -275,43 +275,74 @@ function construct_network(target_distribution, scope_text, overwriteSg) { edges_distri = new vis.DataSet([ {from: 'root', to: distributionData.additionalDistributionInfo[0][0], length: 30, width: 3}, ]); - var toID = false;; if (target_distribution === undefined || target_distribution == 5) { target_distribution = event_distribution; } - switch (target_distribution) { - case 0: - break; - case 1: - toID = 'this-community'; - break; - case 2: - toID = 'connected-community'; - break; - case 3: - toID = 'all-community'; - break; - case 4: - toID = 'sharing-group'; - break; - default: - break; - } - if (toID !== false) { - var edgeData = {from: 'root', to: toID, width: 3}; + if (target_distribution !== 0) { // Event always restrict propagation (sharing group is a special case) - if (target_distribution !== 4 && target_distribution > event_distribution) { - edgeData.label = 'X'; - edgeData.title = 'The distribution of the Event restricts the distribution level of this element'; - edgeData.font = { - size: 50, - color: '#ff0000', - strokeWidth: 6, - strokeColor: '#ff0000' - }; + var temp_target_disti = target_distribution; + if (target_distribution !== 4 && temp_target_disti >= event_distribution) { + while (temp_target_disti >= event_distribution) { + var toID = false; + switch (temp_target_disti) { + case 0: + break; + case 1: + toID = 'this-community'; + break; + case 2: + toID = 'connected-community'; + break; + case 3: + toID = 'all-community'; + break; + case 4: + toID = 'sharing-group'; + break; + default: + break; + } + var edgeData = {from: 'root', to: toID, width: 3}; + if (temp_target_disti != event_distribution) { + edgeData.label = 'X'; + edgeData.title = 'The distribution of the Event restricts the distribution level of this element'; + edgeData.font = { + size: 50, + color: '#ff0000', + strokeWidth: 6, + strokeColor: '#ff0000' + }; + } + if (toID !== false) { + edges_distri.add(edgeData); + } + temp_target_disti--; + } + } else { + switch (temp_target_disti) { + case 0: + break; + case 1: + toID = 'this-community'; + break; + case 2: + toID = 'connected-community'; + break; + case 3: + toID = 'all-community'; + break; + case 4: + toID = 'sharing-group'; + break; + default: + break; + } + var edgeData = {from: 'root', to: toID, width: 3}; + if (toID !== false) { + edges_distri.add(edgeData); + } } - edges_distri.add(edgeData); } var nodesToAdd = []; @@ -319,12 +350,16 @@ function construct_network(target_distribution, scope_text, overwriteSg) { cacheAddedOrgName[distributionData.additionalDistributionInfo[0][0]] = 1; // Community - if (target_distribution >= 1 && target_distribution != 4) { + if (target_distribution >= 1 && target_distribution != 4 + && (distributionData.event[1] > 0 || distributionData.event[2] > 0 || distributionData.event[3] > 0) + ) { nodesToAdd.push({id: 'this-community', label: 'This community', group: 'root-this-community'}); inject_this_community_org(nodesToAdd, edgesToAdd, distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); } - if (target_distribution >= 2 && target_distribution != 4) { - // Connected Community + // Connected Community + if (target_distribution >= 2 && target_distribution != 4 + && (distributionData.event[2] > 0 || distributionData.event[3] > 0) + ) { nodesToAdd.push({id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}); distributionData.additionalDistributionInfo[2].forEach(function(orgName) { if (orgName === 'This community') { @@ -341,7 +376,7 @@ function construct_network(target_distribution, scope_text, overwriteSg) { } // All Community - if (target_distribution >= 3 && target_distribution != 4) { + if (target_distribution >= 3 && target_distribution != 4 && distributionData.event[3] > 0) { nodesToAdd.push({id: 'all-community', label: 'All community', group: 'web'}); distributionData.additionalDistributionInfo[3].forEach(function(orgName) { if (orgName === 'This community') { @@ -418,7 +453,7 @@ function construct_network(target_distribution, scope_text, overwriteSg) { var data = { nodes: nodes_distri, edges: edges_distri }; var network_options = { width: '800px', - height: '800px', + height: '759px', layout: {randomSeed: 0}, edges: { arrowStrikethrough: false, From 0892967c6d32bb219841c565dce707e694c5a18c Mon Sep 17 00:00:00 2001 From: mokaddem Date: Mon, 4 Mar 2019 09:59:28 +0100 Subject: [PATCH 16/25] fix: [distributionGraph-network] fixed sharing group singleton --- app/View/Elements/view_event_distribution_graph.ctp | 3 ++- app/webroot/js/event-distribution-graph.js | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/View/Elements/view_event_distribution_graph.ctp b/app/View/Elements/view_event_distribution_graph.ctp index 0fbd2f64f..298ca7c33 100644 --- a/app/View/Elements/view_event_distribution_graph.ctp +++ b/app/View/Elements/view_event_distribution_graph.ctp @@ -8,7 +8,8 @@
-
+ +
diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index bc0c92d2b..2aef7ff46 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -1,5 +1,6 @@ var scope_id = $('#eventdistri_graph').data('event-id'); var event_distribution = $('#eventdistri_graph').data('event-distribution'); +var event_distribution_text = $('#eventdistri_graph').data('event-distribution-text'); var extended_text = $('#eventdistri_graph').data('extended') == 1 ? true : false; var spanOffset_orig = 15; // due to padding var payload = {}; @@ -645,6 +646,9 @@ function toggleRowListener(toAdd) { break; case 'Inherit': distribution_value = 5; + if (event_distribution == 4) { + overwriteSg = event_distribution_text.trim(); + } break; default: distribution_value = 4; From 6a7efb92c534b1fdfb2cd424466c267189d78195 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Mon, 11 Mar 2019 14:24:15 +0100 Subject: [PATCH 17/25] chg: [distributionGraph] Added bar chart and deferred distribution data fetching process --- app/View/Events/view.ctp | 14 +- app/webroot/js/event-distribution-graph.js | 399 +++++++++++---------- app/webroot/js/misp.js | 39 ++ 3 files changed, 263 insertions(+), 189 deletions(-) diff --git a/app/View/Events/view.ctp b/app/View/Events/view.ctp index 9ccbe1625..6f420a686 100644 --- a/app/View/Events/view.ctp +++ b/app/View/Events/view.ctp @@ -145,15 +145,25 @@ 'key' => __('Distribution'), 'value_class' => ($event['Event']['distribution'] == 0) ? 'privateRedText' : '', 'html' => sprintf( - '%s %s', + '%s %s %s %s', ($event['Event']['distribution'] == 4) ? sprintf('%s', $baseurl . '/sharing_groups/view/', h($event['SharingGroup']['id']), h($event['SharingGroup']['name'])) : h($distributionLevels[$event['Event']['distribution']]), sprintf( - '
%s
', + '', + h($event['Event']['id']) + ), + sprintf( + '
%s
', 'useCursorPointer fa fa-info-circle distribution_graph', h($event['Event']['id']), $this->element('view_event_distribution_graph') + ), + sprintf( + '', + 'Toggle advanced sharing network viewer', + 'fa fa-share-alt useCursorPointer', + 'showAdvancedSharing(this)' ) ) ); diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 2aef7ff46..87e4533e8 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -181,7 +181,7 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { } // text var span = document.createElement('span'); - span.classList.add('useCursorPointer', 'pbDistributionText', 'badge'); + span.classList.add('useCursorPointer', 'pbDistributionText', 'badge', 'toBeCleared'); span.onclick = clickHandlerPbText; span.innerHTML = distribution[d].key; span.setAttribute('data-distribution', d); @@ -212,7 +212,7 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { // tick var span = document.createElement('span'); - span.classList.add('pbDistributionTick'); + span.classList.add('pbDistributionTick', 'toBeCleared'); spanOffset += (pbStep*(d+1))+spanOffset > pb_container.clientWidth ? -3 : 0; // avoid the tick width to go further than the pb span.style.left = (pbStep*(d+1))+spanOffset + 'px'; span.style.top = d % 2 == 0 ? pb_top-15+'px' : pb_top+0+'px'; @@ -258,6 +258,170 @@ function showAdvancedSharing(clicked) { construct_network(); } +function construct_piechart(data) { + $('.toBeCleared').remove(); + + $(".loadingPopover").hide(); + + // DISTRIBUTION PROGRESSBAR + $('#eventdistri_pb_invalid').tooltip(); + $('#eventdistri_pb').tooltip(); + $('#eventdistri_pb_min').tooltip(); + + $('#eventdistri_pb_invalid').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_pb').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_pb_min').click(function(evt) { clickHandlerPb(evt); }); + $('#eventdistri_sg_pb').click(function(evt) { clickHandlerPb(evt); }); + + // pb + var event_dist, min_distri, max_distri; + if (event_distribution == 4) { // if distribution is sharing group, overwrite default behavior + var event_dist = 1; + var min_distri = 0; + var max_distri = 0; + } else { + var event_dist = event_distribution+1; // +1 to reach the first level + var min_distri = get_minimum_distribution(data.event, event_dist)+1; // +1 to reach the first level + var max_distri = get_maximum_distribution(data.event)+1; // +1 to reach the first level + } + add_level_to_pb(data.distributionInfo, data.additionalDistributionInfo, event_dist); + + var bg_width_step = $('#eventdistri_pb_background').width()/4.0; + $('#eventdistri_pb_min').width(bg_width_step*min_distri + 'px'); + $('#eventdistri_pb_min').data("distribution", fill_distri_for_search(0, min_distri-1)); + $('#eventdistri_pb_min').attr('aria-valuenow', min_distri*25); + $('#eventdistri_pb_min').css("background", "#ffc107"); + + $('#eventdistri_pb').width((event_dist)*25+'%'); + $('#eventdistri_pb').data("distribution", fill_distri_for_search(0, event_dist-1)); + $('#eventdistri_pb').attr('aria-valuenow', (event_dist-min_distri)*25); + $('#eventdistri_pb').css("background", "#28a745"); + + $('#eventdistri_pb_invalid').width((max_distri-event_dist)*25+'%'); + $('#eventdistri_pb_invalid').data("distribution", fill_distri_for_search(event_dist, max_distri-1)); + $('#eventdistri_pb_invalid').attr('aria-valuenow', (max_distri-event_dist)*25); + $('#eventdistri_pb_invalid').css("background", "#dc3545"); + + // SHARING GROUPS + var sgNum = data.additionalDistributionInfo[4].length; + var sgPerc = (sgNum/data.allSharingGroup.length)*100; + if (sgPerc > 0) { + $('#eventdistri_sg_pb').width(sgPerc+'%'); + $('#eventdistri_sg_pb').tooltip({ + title: "Distribution among sharing group: "+(sgNum +' / '+ data.allSharingGroup.length) + }); + $('#eventdistri_sg_pb').data("distribution", '4' + (event_distribution==4 ? '|5' : '')); + $('#eventdistri_sg_pb').attr('aria-valuenow', sgPerc); + $('#eventdistri_sg_pb').css("background", "#7a86e0"); + } else { // no sg, hide it and display + $('#eventdistri_sg_pb_background').text("Event not distributed to any sharing group"); + } + + $('.sharingGroup_pb_text').popover({ + placement: 'bottom', + trigger: 'click', + title: 'Sharing group', + content: 'Distribution description: ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]) + '
', + container: 'body', + html: true, + template: '' + }) + .click(function() { + generate_pie_chart(data.sharingGroupRepartition, document.getElementById('sg_distribution_graph_canvas')); + }); + + // doughtnut + var doughnutColors = ['#ff0000', '#ff9e00', '#957200', '#008000', 'rgb(122, 134, 224)']; + var doughnut_dataset = [ + { + label: "All", + data: data.event, + hidden: false, + backgroundColor: doughnutColors + }, + { + label: "Attributes", + data: data.attribute, + hidden: false, + backgroundColor: doughnutColors + }, + { + label: "Object attributes", + data: data.obj_attr, + hidden: false, + backgroundColor: doughnutColors + }, + + ]; + var ctx = document.getElementById("distribution_graph_canvas"); + ctx.onclick = function(evt) { clickHandlerGraph(evt); }; + + var count = 0; + for (var i=0, n=data.event.length; i < n; i++) { + count += data.event[i]; + } + if (count > 0) { + distribution_chart = new Chart(ctx, { + type: 'doughnut', + data: { + labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }), + distribution: data.distributionInfo, + datasets: doughnut_dataset, + }, + options: { + title: { + display: false + }, + animation: { + duration: 500 + }, + tooltips: { + callbacks: { + label: function(item, data) { + return data.datasets[item.datasetIndex].label + + " - " + data.labels[item.index] + + ": " + data.datasets[item.datasetIndex].data[item.index]; + } + } + } + }, + }); + } else { + var canvas = ctx; + ctx = canvas.getContext("2d"); + ctx.font = "30px Comic Sans MS"; + ctx.textAlign = "center"; + ctx.fillText("Event is empty", canvas.width/2, canvas.height/2); + } + + // create checkboxes + var div = $('
'); + div.addClass('distribution_checkboxes_dataset'); + var distri_graph = $('#eventdistri_graph'); + var distriOffset = distri_graph.offset(); + var distriHeight = distri_graph.height()/2; + div.css({left: '50px'}); + for (var i in doughnut_dataset) { + var item = doughnut_dataset[i]; + var label = $(''); + label.addClass('useCursorPointer'); + label.css({'user-select': 'none'}); + var checkbox = $(''); + checkbox.data('dataset-index', i); + checkbox.prop('checked', true); + checkbox.change(function(evt) { + var clickedIndex = $(this).data('dataset-index'); + var isChecked = $(this).prop('checked'); + distribution_chart.config.data.datasets[clickedIndex].hidden = !isChecked; + distribution_chart.update(); + }); + label.append(checkbox); + label.append(item.label); + div.append(label); + } + distri_graph.append(div); +} + function construct_network(target_distribution, scope_text, overwriteSg) { cacheAddedOrgName = {}; if (advancedSharingNetwork !== undefined) { @@ -684,13 +848,56 @@ function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { }); } +function fetchDistributionData(callback) { + $.ajax({ + url: "/events/"+"getDistributionGraph"+"/"+scope_id+"/event.json", + dataType: 'json', + type: 'post', + contentType: 'application/json', + data: JSON.stringify( payload ), + processData: false, + beforeSend: function (XMLHttpRequest) { + $(".loadingPopover").show(); + }, + success: function( data, textStatus, jQxhr ){ + distributionData = data; + if (callback !== undefined) { + callback(data); + } + }, + error: function( jqXhr, textStatus, errorThrown ){ + console.log( errorThrown ); + } + }); +} + +function drawBarChart(data) { + var csv = "scope,val\n"; + var lineCount = 0; + data.event.forEach(function(d, i) { + var scope = data.distributionInfo[i].key; + var val = d; + csv += scope + "," + val + "\n"; + lineCount++; + }) + sparklineBar('#distribution_graph_bar', csv, lineCount); +} + $(document).ready(function() { - var rightBtn = ''; + var rightBtn = '
'; var pop = $('.distribution_graph').popover({ title: "Distribution graph [atomic event]" + rightBtn, html: true, content: function() { return $('#distribution_graph_container').html(); }, template : '' + }).on('shown.bs.popover', function(e) { + if (distributionData !== undefined) { + construct_piechart(distributionData); + } else { + fetchDistributionData(function(data) { construct_piechart(data); }); + } + }).on('hide.bs.popover', function(e) { + // $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 200, function() { $('#advancedSharingNetworkWrapper').remove(); }); }); $('body').on('mouseup', function(e) { @@ -700,189 +907,7 @@ $(document).ready(function() { } }); - $('.distribution_graph').click(function() { - if ($(this).data('shown') == 'true') { - $(this).data('shown', 'false'); - $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 200, function() { $('#advancedSharingNetworkWrapper').remove(); }); - return; - } else { - $(this).data('shown', 'true'); - } - $.ajax({ - url: "/events/"+"getDistributionGraph"+"/"+scope_id+"/event.json", - dataType: 'json', - type: 'post', - contentType: 'application/json', - data: JSON.stringify( payload ), - processData: false, - beforeSend: function (XMLHttpRequest) { - $(".loadingPopover").show(); - }, - success: function( data, textStatus, jQxhr ){ - distributionData = data; - $(".loadingPopover").hide(); - - // DISTRIBUTION PROGRESSBAR - $('#eventdistri_pb_invalid').tooltip(); - $('#eventdistri_pb').tooltip(); - $('#eventdistri_pb_min').tooltip(); - - $('#eventdistri_pb_invalid').click(function(evt) { clickHandlerPb(evt); }); - $('#eventdistri_pb').click(function(evt) { clickHandlerPb(evt); }); - $('#eventdistri_pb_min').click(function(evt) { clickHandlerPb(evt); }); - $('#eventdistri_sg_pb').click(function(evt) { clickHandlerPb(evt); }); - - // pb - var event_dist, min_distri, max_distri; - if (event_distribution == 4) { // if distribution is sharing group, overwrite default behavior - var event_dist = 1; - var min_distri = 0; - var max_distri = 0; - } else { - var event_dist = event_distribution+1; // +1 to reach the first level - var min_distri = get_minimum_distribution(data.event, event_dist)+1; // +1 to reach the first level - var max_distri = get_maximum_distribution(data.event)+1; // +1 to reach the first level - } - add_level_to_pb(data.distributionInfo, data.additionalDistributionInfo, event_dist); - - var bg_width_step = $('#eventdistri_pb_background').width()/4.0; - $('#eventdistri_pb_min').width(bg_width_step*min_distri + 'px'); - $('#eventdistri_pb_min').data("distribution", fill_distri_for_search(0, min_distri-1)); - $('#eventdistri_pb_min').attr('aria-valuenow', min_distri*25); - $('#eventdistri_pb_min').css("background", "#ffc107"); - - $('#eventdistri_pb').width((event_dist)*25+'%'); - $('#eventdistri_pb').data("distribution", fill_distri_for_search(0, event_dist-1)); - $('#eventdistri_pb').attr('aria-valuenow', (event_dist-min_distri)*25); - $('#eventdistri_pb').css("background", "#28a745"); - - $('#eventdistri_pb_invalid').width((max_distri-event_dist)*25+'%'); - $('#eventdistri_pb_invalid').data("distribution", fill_distri_for_search(event_dist, max_distri-1)); - $('#eventdistri_pb_invalid').attr('aria-valuenow', (max_distri-event_dist)*25); - $('#eventdistri_pb_invalid').css("background", "#dc3545"); - - // SHARING GROUPS - var sgNum = data.additionalDistributionInfo[4].length; - var sgPerc = (sgNum/data.allSharingGroup.length)*100; - if (sgPerc > 0) { - $('#eventdistri_sg_pb').width(sgPerc+'%'); - $('#eventdistri_sg_pb').tooltip({ - title: "Distribution among sharing group: "+(sgNum +' / '+ data.allSharingGroup.length) - }); - $('#eventdistri_sg_pb').data("distribution", '4' + (event_distribution==4 ? '|5' : '')); - $('#eventdistri_sg_pb').attr('aria-valuenow', sgPerc); - $('#eventdistri_sg_pb').css("background", "#7a86e0"); - } else { // no sg, hide it and display - $('#eventdistri_sg_pb_background').text("Event not distributed to any sharing group"); - } - - $('.sharingGroup_pb_text').popover({ - placement: 'bottom', - trigger: 'click', - title: 'Sharing group', - content: 'Distribution description: ' + data.distributionInfo[4].desc + generate_additional_info(data.additionalDistributionInfo[4]) + '
', - container: 'body', - html: true, - template: '' - }) - .click(function() { - generate_pie_chart(data.sharingGroupRepartition, document.getElementById('sg_distribution_graph_canvas')); - }); - - // doughtnut - var doughnutColors = ['#ff0000', '#ff9e00', '#957200', '#008000', 'rgb(122, 134, 224)']; - var doughnut_dataset = [ - { - label: "All", - data: data.event, - hidden: false, - backgroundColor: doughnutColors - }, - { - label: "Attributes", - data: data.attribute, - hidden: false, - backgroundColor: doughnutColors - }, - { - label: "Object attributes", - data: data.obj_attr, - hidden: false, - backgroundColor: doughnutColors - }, - - ]; - var ctx = document.getElementById("distribution_graph_canvas"); - ctx.onclick = function(evt) { clickHandlerGraph(evt); }; - - var count = 0; - for (var i=0, n=data.event.length; i < n; i++) { - count += data.event[i]; - } - if (count > 0) { - distribution_chart = new Chart(ctx, { - type: 'doughnut', - data: { - labels: data.distributionInfo.map(function(elem, index) { return [elem.key]; }), - distribution: data.distributionInfo, - datasets: doughnut_dataset, - }, - options: { - title: { - display: false - }, - animation: { - duration: 500 - }, - tooltips: { - callbacks: { - label: function(item, data) { - return data.datasets[item.datasetIndex].label - + " - " + data.labels[item.index] - + ": " + data.datasets[item.datasetIndex].data[item.index]; - } - } - } - }, - }); - } else { - var canvas = ctx; - ctx = canvas.getContext("2d"); - ctx.font = "30px Comic Sans MS"; - ctx.textAlign = "center"; - ctx.fillText("Event is empty", canvas.width/2, canvas.height/2); - } - - // create checkboxes - var div = $('
'); - div.addClass('distribution_checkboxes_dataset'); - var distri_graph = $('#eventdistri_graph'); - var distriOffset = distri_graph.offset(); - var distriHeight = distri_graph.height()/2; - div.css({left: '50px'}); - for (var i in doughnut_dataset) { - var item = doughnut_dataset[i]; - var label = $(''); - label.addClass('useCursorPointer'); - label.css({'user-select': 'none'}); - var checkbox = $(''); - checkbox.data('dataset-index', i); - checkbox.prop('checked', true); - checkbox.change(function(evt) { - var clickedIndex = $(this).data('dataset-index'); - var isChecked = $(this).prop('checked'); - distribution_chart.config.data.datasets[clickedIndex].hidden = !isChecked; - distribution_chart.update(); - }); - label.append(checkbox); - label.append(item.label); - div.append(label); - } - distri_graph.append(div); - }, - error: function( jqXhr, textStatus, errorThrown ){ - console.log( errorThrown ); - } - }); + fetchDistributionData(function(data) { + drawBarChart(data); }); }); diff --git a/app/webroot/js/misp.js b/app/webroot/js/misp.js index 110130852..dcc797bdf 100644 --- a/app/webroot/js/misp.js +++ b/app/webroot/js/misp.js @@ -3998,6 +3998,45 @@ function liveFilter() { } } +function sparklineBar(elemId, data, lineCount) { + data = d3.csv.parse(data); + var y_max = 0; + data.forEach(function(e) { + e = parseInt(e.val); + y_max = e > y_max ? e : y_max; + }); + // y_max = Math.log(y_max) + var WIDTH = 50; + var HEIGHT = 25; + var DATA_COUNT = lineCount; + var BAR_WIDTH = (WIDTH - DATA_COUNT) / DATA_COUNT; + var x = d3.scale.linear().domain([0, DATA_COUNT]).range([0, WIDTH]); + var y = d3.scale.linear().domain([0, y_max]).range([0, HEIGHT]); + + var distributionGraphBarTooltip = d3.select("body").append("div") + .attr("class", "distributionGraphBarTooltip") + .style("opacity", 0); + + var svg = d3.select(elemId).append('svg') + .attr('width', WIDTH) + .attr('height', HEIGHT) + .append('g'); + svg.selectAll('.bar').data(data) + .enter() + .append('g') + .attr('title', function(d, i) { return d.scope + ': ' + d.val }) + .attr('class', 'DGbar') + .append('rect') + .attr('class', 'bar') + .attr('x', function(d, i) { return x(i); }) + .attr('y', function(d, i) { return HEIGHT - y(d.val); }) + .attr('width', BAR_WIDTH) + .attr('height', function(d, i) { return y(d.val); }) + .attr('fill', '#3465a4'); + + $('.DGbar').tooltip({container: 'body'}); +} + (function(){ "use strict"; $(".datepicker").datepicker({ From 968d578e387c84bf87bfe7d81526e74a51c8cb76 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 12 Mar 2019 08:15:27 +0100 Subject: [PATCH 18/25] chg: [distributionNetwork] Integration with event index - WiP --- app/Controller/EventsController.php | 35 +- app/View/Elements/Events/eventIndexTable.ctp | 15 + app/View/Events/index.ctp | 6 + app/View/Events/view.ctp | 7 +- app/webroot/css/distribution-graph.css | 38 ++ app/webroot/js/event-distribution-graph.js | 474 +------------------ cti-python-stix2 | 2 +- 7 files changed, 102 insertions(+), 475 deletions(-) diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php index c80a8d71c..d2e054d0c 100644 --- a/app/Controller/EventsController.php +++ b/app/Controller/EventsController.php @@ -862,6 +862,7 @@ class EventsController extends AppController $this->set('analysisLevels', $this->Event->analysisLevels); $this->set('distributionLevels', $this->Event->distributionLevels); $this->set('shortDist', $this->Event->shortDist); + $this->set('distributionData', $this->genDistributionGraph(0)); if ($this->params['ext'] === 'csv') { App::uses('CsvExport', 'Export'); $export = new CsvExport(); @@ -4661,8 +4662,7 @@ class EventsController extends AppController return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json')); } - public function getDistributionGraph($id, $type = 'event') - { + private function genDistributionGraph($id, $type = 'event', $extended = 0) { $validTools = array('event'); if (!in_array($type, $validTools)) { throw new MethodNotAllowedException(__('Invalid type.')); @@ -4671,9 +4671,6 @@ class EventsController extends AppController $this->loadModel('Organisation'); App::uses('DistributionGraphTool', 'Tools'); $grapher = new DistributionGraphTool(); - $data = $this->request->is('post') ? $this->request->data : array(); - - $extended = isset($this->params['named']['extended']) ? 1 : 0; $servers = $this->Server->find('list', array( 'fields' => array('name'), @@ -4686,6 +4683,34 @@ class EventsController extends AppController $item = utf8_encode($item); } }); + return $json; + } + + public function getDistributionGraph($id, $type = 'event') + { + // $validTools = array('event'); + // if (!in_array($type, $validTools)) { + // throw new MethodNotAllowedException(__('Invalid type.')); + // } + // $this->loadModel('Server'); + // $this->loadModel('Organisation'); + // App::uses('DistributionGraphTool', 'Tools'); + // $grapher = new DistributionGraphTool(); + // + $extended = isset($this->params['named']['extended']) ? 1 : 0; + // + // $servers = $this->Server->find('list', array( + // 'fields' => array('name'), + // )); + // $grapher->construct($this->Event, $servers, $this->Auth->user(), $extended); + // $json = $grapher->get_distributions_graph($id); + // + // array_walk_recursive($json, function (&$item, $key) { + // if (!mb_detect_encoding($item, 'utf-8', true)) { + // $item = utf8_encode($item); + // } + // }); + $json = $this->genDistributionGraph($id, $type, $extended); $this->response->type('json'); return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json')); } diff --git a/app/View/Elements/Events/eventIndexTable.ctp b/app/View/Elements/Events/eventIndexTable.ctp index b5fe45ea9..66cfae051 100644 --- a/app/View/Elements/Events/eventIndexTable.ctp +++ b/app/View/Elements/Events/eventIndexTable.ctp @@ -214,6 +214,15 @@ echo h($shortDist[$event['Event']['distribution']]); endif; ?> + ', + 'Toggle advanced sharing network viewer', + 'fa fa-share-alt useCursorPointer distributionNetworkToggle', + h($event['Event']['distribution']), + h($event['Event']['id']) + ) + ?> , + }); + }); }); diff --git a/app/View/Events/index.ctp b/app/View/Events/index.ctp index 5dc14f5bc..4815c9cef 100644 --- a/app/View/Events/index.ctp +++ b/app/View/Events/index.ctp @@ -136,6 +136,12 @@ }); +Html->script('vis'); + echo $this->Html->css('vis'); + echo $this->Html->css('distribution-graph'); + echo $this->Html->script('network-distribution-graph'); +?> Html->css('query-builder.default'); echo $this->Html->script('query-builder'); echo $this->Html->css('attack_matrix'); + echo $this->Html->script('network-distribution-graph'); ?>
element('view_event_distribution_graph') ), sprintf( - '', + '', 'Toggle advanced sharing network viewer', - 'fa fa-share-alt useCursorPointer', - 'showAdvancedSharing(this)' + 'fa fa-share-alt useCursorPointer' ) ) ); @@ -507,6 +507,7 @@ $(document).ready(function () { $.get("/threads/view//true", function(data) { $("#discussions_div").html(data); }); + }); function enable_correlation_graph() { diff --git a/app/webroot/css/distribution-graph.css b/app/webroot/css/distribution-graph.css index 3f8fa970e..85f5e5682 100644 --- a/app/webroot/css/distribution-graph.css +++ b/app/webroot/css/distribution-graph.css @@ -2,6 +2,44 @@ color: #333333; } +.eventgraph_header { + background: #f9f9f9; + box-shadow: 0px 0px 6px #B2B2B2; + margin-bottom: 2px; + width: 100%; + height: 40px; + overflow: hidden; +} + +select.center-in-network-header { + margin-bottom: 0px; + width: fit-content; +} + +input[type="text"].center-in-network-header { + top: 5px; + margin: 0px; + margin-left: 5px; +} + +input[type="checkbox"].center-in-network-header { + top: 0px; + margin: 0px; + margin-left: 5px; +} + +label.center-in-network-header { + user-select: none; + font-weight: bold; +} + +.center-in-network-header { + position: relative; + display: inline-block; + top: 5px; + margin-left: 5px; +} + .loadingPopover { position: absolute; left: 50%; diff --git a/app/webroot/js/event-distribution-graph.js b/app/webroot/js/event-distribution-graph.js index 87e4533e8..b458e99b6 100644 --- a/app/webroot/js/event-distribution-graph.js +++ b/app/webroot/js/event-distribution-graph.js @@ -7,12 +7,6 @@ var payload = {}; var distribution_chart; var distributionData; -var EDGE_LENGTH_HUB = 300; -var cacheAddedOrgName = {}; -var nodes_distri; -var edges_distri; -var advancedSharingNetwork; - function clickHandlerGraph(evt) { var firstPoint = distribution_chart.getElementAtEvent(evt)[0]; var distribution_id; @@ -226,38 +220,6 @@ function add_level_to_pb(distribution, additionalInfo, maxLevel) { } -function showAdvancedSharing(clicked) { - $clicked = $(clicked); - var network_active = $clicked.data('networkactive'); - if (network_active !== undefined && network_active === true) { - $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 300); - $clicked.data('networkactive', false); - return; - } else if (network_active !== undefined && network_active === false) { - $('#advancedSharingNetworkWrapper').show('slide', {direction: 'right'}, 300); - $clicked.data('networkactive', true); - return; - } - $clicked.data('networkactive', true); - var $popover = $('#eventdistri_graph').parent().parent(); - var boundingRect = $popover[0].getBoundingClientRect() - var $div = $(''); - - $('body').append($div); - $div.toggle('slide', {direction: 'right'}, 300); - - construct_network(); -} - function construct_piechart(data) { $('.toBeCleared').remove(); @@ -422,432 +384,6 @@ function construct_piechart(data) { distri_graph.append(div); } -function construct_network(target_distribution, scope_text, overwriteSg) { - cacheAddedOrgName = {}; - if (advancedSharingNetwork !== undefined) { - advancedSharingNetwork.destroy(); - } - if (scope_text == undefined) { - scope_text = 'Event ' + scope_id; - } - $('#sharingNetworkTargetId').val(scope_text); - - nodes_distri = new vis.DataSet([ - {id: 'root', group: 'root', label: scope_text, x: 0, y: 0, fixed: true, mass: 20}, - {id: distributionData.additionalDistributionInfo[0][0], label: distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, - - ]); - edges_distri = new vis.DataSet([ - {from: 'root', to: distributionData.additionalDistributionInfo[0][0], length: 30, width: 3}, - ]); - if (target_distribution === undefined || target_distribution == 5) { - target_distribution = event_distribution; - } - - if (target_distribution !== 0) { - // Event always restrict propagation (sharing group is a special case) - var temp_target_disti = target_distribution; - if (target_distribution !== 4 && temp_target_disti >= event_distribution) { - while (temp_target_disti >= event_distribution) { - var toID = false; - switch (temp_target_disti) { - case 0: - break; - case 1: - toID = 'this-community'; - break; - case 2: - toID = 'connected-community'; - break; - case 3: - toID = 'all-community'; - break; - case 4: - toID = 'sharing-group'; - break; - default: - break; - } - var edgeData = {from: 'root', to: toID, width: 3}; - if (temp_target_disti != event_distribution) { - edgeData.label = 'X'; - edgeData.title = 'The distribution of the Event restricts the distribution level of this element'; - edgeData.font = { - size: 50, - color: '#ff0000', - strokeWidth: 6, - strokeColor: '#ff0000' - }; - } - if (toID !== false) { - edges_distri.add(edgeData); - } - temp_target_disti--; - } - } else { - switch (temp_target_disti) { - case 0: - break; - case 1: - toID = 'this-community'; - break; - case 2: - toID = 'connected-community'; - break; - case 3: - toID = 'all-community'; - break; - case 4: - toID = 'sharing-group'; - break; - default: - break; - } - var edgeData = {from: 'root', to: toID, width: 3}; - if (toID !== false) { - edges_distri.add(edgeData); - } - } - } - - var nodesToAdd = []; - var edgesToAdd = []; - cacheAddedOrgName[distributionData.additionalDistributionInfo[0][0]] = 1; - - // Community - if (target_distribution >= 1 && target_distribution != 4 - && (distributionData.event[1] > 0 || distributionData.event[2] > 0 || distributionData.event[3] > 0) - ) { - nodesToAdd.push({id: 'this-community', label: 'This community', group: 'root-this-community'}); - inject_this_community_org(nodesToAdd, edgesToAdd, distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); - } - // Connected Community - if (target_distribution >= 2 && target_distribution != 4 - && (distributionData.event[2] > 0 || distributionData.event[3] > 0) - ) { - nodesToAdd.push({id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}); - distributionData.additionalDistributionInfo[2].forEach(function(orgName) { - if (orgName === 'This community') { - edgesToAdd.push({from: 'connected-community', to: 'this-community', length: EDGE_LENGTH_HUB}); - } else { - nodesToAdd.push({ - id: 'connected-community_' + orgName, - label: orgName, - group: 'connected-community' - }); - edgesToAdd.push({from: 'connected-community', to: 'connected-community_' + orgName}); - } - }); - } - - // All Community - if (target_distribution >= 3 && target_distribution != 4 && distributionData.event[3] > 0) { - nodesToAdd.push({id: 'all-community', label: 'All community', group: 'web'}); - distributionData.additionalDistributionInfo[3].forEach(function(orgName) { - if (orgName === 'This community') { - edgesToAdd.push({from: 'all-community', to: 'this-community', length: EDGE_LENGTH_HUB}); - } else if (orgName === 'All other communities') { - edgesToAdd.push({from: 'all-community', to: 'connected-community', length: EDGE_LENGTH_HUB}); - } - }); - } - // Sharing Group - if (distributionData.event[4] > 0) { - distributionData.allSharingGroup.forEach(function(sg) { - var sgName = sg.SharingGroup.name; - if (overwriteSg === undefined) { // if overwriteSg not set, use the one from the event - overwriteSg = distributionData.additionalDistributionInfo[4]; - } - if (overwriteSg.indexOf(sgName) == -1) { - return true; - } - - nodesToAdd.push({ - id: 'sharing-group_' + sgName, - label: sgName, - group: 'root-sharing-group' - }); - edgesToAdd.push({from: 'root', to: 'sharing-group_' + sgName, width: 3}); - sg.SharingGroupOrg.forEach(function(org) { - var sgOrgName = org.Organisation.name; - if (cacheAddedOrgName[sgOrgName] === undefined) { - nodesToAdd.push({ - id: sgOrgName, - label: sgOrgName, - group: 'sharing-group' - }); - cacheAddedOrgName[sgOrgName] = 1; - } - edgesToAdd.push({ - from: 'sharing-group_' + sgName, - to: sgOrgName, - arrows: { - to: { enabled: false } - }, - color: { opacity: 0.4 } - }); - }); - }); - } - - var options = ''; - $('#sharingNetworkOrgFinder').empty(); - Object.keys(cacheAddedOrgName).forEach(function(org) { - options += ''; - }); - $('#sharingNetworkOrgFinder').append(options) - .trigger('chosen:updated') - .chosen({ - inherit_select_classes: true, - no_results_text: "Focus to an organisation", - placeholder_text_single: "Focus to an organisation", - allow_single_deselect: true - }) - .off('change') - .on('change', function(evt, params) { - if (this.value !== '') { - advancedSharingNetwork.focus(this.value, {animation: true}); - advancedSharingNetwork.selectNodes([this.value]); - } else { - advancedSharingNetwork.fit({animation: true}) - } - }); - - nodes_distri.add(nodesToAdd); - edges_distri.add(edgesToAdd); - var data = { nodes: nodes_distri, edges: edges_distri }; - var network_options = { - width: '800px', - height: '759px', - layout: {randomSeed: 0}, - edges: { - arrowStrikethrough: false, - arrows: { - to: {enabled: true, scaleFactor:1, type:'arrow'}, - }, - shadow: { - enabled: true, - size: 7, - x: 3, - y: 3 - } - }, - physics:{ - barnesHut: { - gravitationalConstant: -10000, - centralGravity: 0.3, - springLength: 150, - springConstant: 0.02, - damping: 0.09, - avoidOverlap: 0 - }, - repulsion: { - centralGravity: 0.2, - springLength: 200, - springConstant: 0.02, - nodeDistance: 200, - damping: 0.15 - }, - - solver: 'barnesHut' - }, - nodes: { - shadow: { - enabled: true, - size: 7, - x: 3, - y: 3 - } - }, - groups: { - 'root': { - shape: 'icon', - icon: { - face: 'FontAwesome', - code: '\uf10c', - color: '#000000', - size: 50 - }, - font: {size: 30}, - color: '#000000', - }, - 'org-only': { - shape: 'icon', - icon: { - face: 'FontAwesome', - code: '\uf2c2', - color: '#ff0000', - size: 30 - }, - font: { - size: 14, // px - color: '#ff0000', - background: 'rgba(255, 255, 255, 0.7)' - }, - color: '#ff0000', - }, - 'root-this-community': { - shape: 'icon', - icon: { - face: 'FontAwesome', - code: '\uf1e1', - color: '#ff9725', - size: 70 - }, - font: { - size: 18, // px - color: '#ff9725', - background: 'rgba(255, 255, 255, 0.7)' - }, - color: '#ff9725', - }, - 'this-community': { - font: {color: 'white'}, - color: '#ff9725', - shape: 'box', - margin: 3 - }, - 'root-connected-community': { - shape: 'icon', - icon: { - face: 'FontAwesome', - code: '\uf0e8', - color: '#9b6e1b', - size: 70 - }, - font: { - size: 18, // px - color: '#9b6e1b', - background: 'rgba(255, 255, 255, 0.7)' - }, - color: '#9b6e1b', - }, - 'connected-community': { - shape: 'image', - image: '/img/orgs/MISP.png' - }, - 'web': { - shape: 'icon', - icon: { - face: 'FontAwesome', - code: '\uf0ac', - color: '#007d20', - size: 70 - }, - font: { - size: 18, // px - color: '#007d20', - background: 'rgba(255, 255, 255, 0.7)' - }, - color: '#007d20', - }, - 'root-sharing-group': { - shape: 'icon', - icon: { - face: 'FontAwesome', - code: '\uf0c0', - color: '#1369a0', - size: 70 - }, - font: { - size: 18, // px - color: '#1369a0', - background: 'rgba(255, 255, 255, 0.7)' - }, - color: '#1369a0', - } - } - }; - advancedSharingNetwork = new vis.Network(document.getElementById('advancedSharingNetwork'), data, network_options); - - advancedSharingNetwork.on("dragStart", function (params) { - params.nodes.forEach(function(nodeId) { - nodes_distri.update({id: nodeId, fixed: {x: false, y: false}}); - }); - }); - advancedSharingNetwork.on("dragEnd", function (params) { - params.nodes.forEach(function(nodeId) { - nodes_distri.update({id: nodeId, fixed: {x: true, y: true}}); - }); - }); - - $('#interactive_picking_mode').off('change').on('change', function(e) { - var target_id = $(this).val(); - if (this.checked) { - toggleRowListener(true); - } else { - toggleRowListener(false); - construct_network(event_distribution) - } - }); -} - -function toggleRowListener(toAdd) { - if (toAdd) { - $('#attributes_div table tr').off('click.advancedSharing').on('click.advancedSharing', function() { - var $row = $(this); - var clicked_type = $row.attr('id').split('_')[0]; - var clicked_id = $row.attr('id').split('_')[1]; - // var $dist_cell = $row.find('#'+clicked_type+'_'+clicked_id+'_distribution_solid'); - var $dist_cell = $row.find('div').filter(function() { - return $(this).attr('id') !== undefined && $(this).attr('id').includes(clicked_id+'_distribution'); - }); - - var distribution_value; - var overwriteSg; - switch ($dist_cell.text().trim()) { - case 'Organisation': - distribution_value = 0; - break; - case 'Community': - distribution_value = 1; - break; - case 'Connected': - distribution_value = 2; - break; - case 'All': - distribution_value = 3; - break; - case 'Inherit': - distribution_value = 5; - if (event_distribution == 4) { - overwriteSg = event_distribution_text.trim(); - } - break; - default: - distribution_value = 4; - overwriteSg = $dist_cell.text().trim(); - break - } - construct_network(distribution_value, clicked_type+' '+clicked_id, [overwriteSg]); - }); - } else { - $('#attributes_div table tr').off('click.advancedSharing'); - } -} - - -function inject_this_community_org(nodesToAdd, edgesToAdd, orgs, group, root) { - orgs.forEach(function(orgName) { - if (cacheAddedOrgName[orgName] === undefined) { - nodesToAdd.push({ - id: orgName, - label: orgName, - group: group - }); - cacheAddedOrgName[orgName] = 1; - } - edgesToAdd.push({ - from: root, - to: orgName, - arrows: { - to: { enabled: false } - }, - color: { opacity: 0.4 } - }); - }); -} - function fetchDistributionData(callback) { $.ajax({ url: "/events/"+"getDistributionGraph"+"/"+scope_id+"/event.json", @@ -894,10 +430,11 @@ $(document).ready(function() { if (distributionData !== undefined) { construct_piechart(distributionData); } else { - fetchDistributionData(function(data) { construct_piechart(data); }); + fetchDistributionData(function(data) { + construct_piechart(data); + }); } }).on('hide.bs.popover', function(e) { - // $('#advancedSharingNetworkWrapper').hide('slide', {direction: 'right'}, 200, function() { $('#advancedSharingNetworkWrapper').remove(); }); }); $('body').on('mouseup', function(e) { @@ -909,5 +446,10 @@ $(document).ready(function() { fetchDistributionData(function(data) { drawBarChart(data); + $('#showAdvancedSharingButton').distributionNetwork({ + event_distribution: event_distribution, + distributionData: data, + scope_id: scope_id + }); }); }); diff --git a/cti-python-stix2 b/cti-python-stix2 index 469d17bce..407f346eb 160000 --- a/cti-python-stix2 +++ b/cti-python-stix2 @@ -1 +1 @@ -Subproject commit 469d17bceeed65373da3ac3b4f96600dfea8ca68 +Subproject commit 407f346eb8118d57b43035ef0da47e2ff77ed00e From 4104860246febf6145324694e64844e7a847cbba Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 12 Mar 2019 08:16:14 +0100 Subject: [PATCH 19/25] chg: [distributionNetwork] Added missing JS --- app/webroot/js/network-distribution-graph.js | 553 +++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 app/webroot/js/network-distribution-graph.js diff --git a/app/webroot/js/network-distribution-graph.js b/app/webroot/js/network-distribution-graph.js new file mode 100644 index 000000000..bc774e5de --- /dev/null +++ b/app/webroot/js/network-distribution-graph.js @@ -0,0 +1,553 @@ +/* +* +*/ + +(function(factory) { + "use strict"; + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (window.jQuery && !window.jQuery.fn.DistributionNetwork) { + factory(window.jQuery); + } + } + (function($) { + 'use strict'; + + // DistributionNetwork object + var DistributionNetwork = function(container, options) { + this._default_options = { + network_options: { + width: '800px', + height: '759px', + layout: {randomSeed: 0}, + edges: { + arrowStrikethrough: false, + arrows: { + to: {enabled: true, scaleFactor:1, type:'arrow'}, + }, + shadow: { + enabled: true, + size: 7, + x: 3, + y: 3 + } + }, + physics:{ + barnesHut: { + gravitationalConstant: -10000, + centralGravity: 0.3, + springLength: 150, + springConstant: 0.02, + damping: 0.09, + avoidOverlap: 0 + }, + repulsion: { + centralGravity: 0.2, + springLength: 200, + springConstant: 0.02, + nodeDistance: 200, + damping: 0.15 + }, + + solver: 'barnesHut' + }, + nodes: { + shadow: { + enabled: true, + size: 7, + x: 3, + y: 3 + } + }, + groups: { + 'root': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf10c', + color: '#000000', + size: 50 + }, + font: {size: 30}, + color: '#000000', + }, + 'org-only': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf2c2', + color: '#ff0000', + size: 30 + }, + font: { + size: 14, // px + color: '#ff0000', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#ff0000', + }, + 'root-this-community': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf1e1', + color: '#ff9725', + size: 70 + }, + font: { + size: 18, // px + color: '#ff9725', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#ff9725', + }, + 'this-community': { + font: {color: 'white'}, + color: '#ff9725', + shape: 'box', + margin: 3 + }, + 'root-connected-community': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf0e8', + color: '#9b6e1b', + size: 70 + }, + font: { + size: 18, // px + color: '#9b6e1b', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#9b6e1b', + }, + 'connected-community': { + shape: 'image', + image: '/img/orgs/MISP.png' + }, + 'web': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf0ac', + color: '#007d20', + size: 70 + }, + font: { + size: 18, // px + color: '#007d20', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#007d20', + }, + 'root-sharing-group': { + shape: 'icon', + icon: { + face: 'FontAwesome', + code: '\uf0c0', + color: '#1369a0', + size: 70 + }, + font: { + size: 18, // px + color: '#1369a0', + background: 'rgba(255, 255, 255, 0.7)' + }, + color: '#1369a0', + } + } + }, + EDGE_LENGTH_HUB: 300, + }; + + this.container = $(container); + this._validateOptions(options); + + this.network_wrapper = false; + this.options = $.extend({}, this._default_options, options); + this.event_distribution = this.options.event_distribution; + this.scope_id = this.options.scope_id; + this.distributionData = this.options.distributionData; + this.active = false; + this.network; + this.nodes_distri; + this.edges_distri; + this.cacheAddedOrgName = {}; + + this._constructUI(); + this._registerListener(); + }; + + DistributionNetwork.prototype = { + constructor: DistributionNetwork, + + _validateOptions: function(options) { + if (options.event_distribution === undefined) { + // try to fetch is from the container + var event_distribution = this.container.data('event-distribution'); + if (event_distribution !== undefined) { + options.event_distribution = event_distribution; + } else { + throw "Event distribution not set"; + } + } + if (options.distributionData === undefined) { + throw "Distribution data not set"; + } + if (options.scope_id === undefined) { + // try to fetch is from the container + var scope_id = this.container.data('scope-id'); + if (scope_id !== undefined) { + options.scope_id = scope_id; + } else { + throw "Scope id is not set"; + } + } + }, + + _registerListener: function() { + var that = this; + this.container.click(function() { + $('#sharingNetworkWrapper').toggle('slide', {direction: 'right'}, 300); + that._construct_network(); + }); + + }, + + dismissNetwork: function() { + $('#sharingNetworkWrapper').hide('slide', {direction: 'right'}, 300); + }, + + _constructUI: function() { + var that = this; + if ($('#sharingNetworkWrapper').length > 0) { + return; // Wrapper already exists + } + var $div = $(''); + this.network_wrapper = $div; + $div.find('#closeButton').click(function() { + that.dismissNetwork(); + }); + $('body').append($div); + }, + + _construct_network: function(target_distribution, scope_text, overwriteSg) { + var that = this; + if (this.network !== undefined) { + this.network.destroy(); + } + if (scope_text == undefined) { + scope_text = 'Event ' + this.options.scope_id; + } + $('#sharingNetworkTargetId').val(scope_text); + + this.nodes_distri = new vis.DataSet([ + {id: 'root', group: 'root', label: scope_text, x: 0, y: 0, fixed: true, mass: 20}, + {id: this.distributionData.additionalDistributionInfo[0][0], label: this.distributionData.additionalDistributionInfo[0][0], group: 'org-only'}, + + ]); + this.edges_distri = new vis.DataSet([ + {from: 'root', to: this.distributionData.additionalDistributionInfo[0][0], length: 30, width: 3}, + ]); + if (target_distribution === undefined || target_distribution == 5) { + target_distribution = this.event_distribution; + } + + console.log(this.distributionData); + if (target_distribution !== 0) { + // Event always restrict propagation (sharing group is a special case) + var temp_target_disti = target_distribution; + if (target_distribution !== 4 && temp_target_disti >= this.event_distribution) { + while (temp_target_disti >= this.event_distribution) { + var toID = false; + switch (temp_target_disti) { + case 0: + break; + case 1: + toID = 'this-community'; + break; + case 2: + toID = 'connected-community'; + break; + case 3: + toID = 'all-community'; + break; + case 4: + toID = 'sharing-group'; + break; + default: + break; + } + var edgeData = {from: 'root', to: toID, width: 3}; + if (temp_target_disti != this.event_distribution) { + edgeData.label = 'X'; + edgeData.title = 'The distribution of the Event restricts the distribution level of this element'; + edgeData.font = { + size: 50, + color: '#ff0000', + strokeWidth: 6, + strokeColor: '#ff0000' + }; + } + if (toID !== false) { + this.edges_distri.add(edgeData); + } + temp_target_disti--; + } + } else { + switch (temp_target_disti) { + case 0: + break; + case 1: + toID = 'this-community'; + break; + case 2: + toID = 'connected-community'; + break; + case 3: + toID = 'all-community'; + break; + case 4: + toID = 'sharing-group'; + break; + default: + break; + } + var edgeData = {from: 'root', to: toID, width: 3}; + if (toID !== false) { + this.edges_distri.add(edgeData); + } + } + } + + var nodesToAdd = []; + var edgesToAdd = []; + this.cacheAddedOrgName[this.distributionData.additionalDistributionInfo[0][0]] = 1; + + // Community + if (target_distribution >= 1 && target_distribution != 4 + && (this.distributionData.event[1] > 0 || this.distributionData.event[2] > 0 || this.distributionData.event[3] > 0) + ) { + nodesToAdd.push({id: 'this-community', label: 'This community', group: 'root-this-community'}); + this._inject_this_community_org(nodesToAdd, edgesToAdd, this.distributionData.additionalDistributionInfo[1], 'this-community', 'this-community'); + } + // Connected Community + if (target_distribution >= 2 && target_distribution != 4 + && (this.distributionData.event[2] > 0 || this.distributionData.event[3] > 0) + ) { + nodesToAdd.push({id: 'connected-community', label: 'Connected community', group: 'root-connected-community'}); + this.distributionData.additionalDistributionInfo[2].forEach(function(orgName) { + if (orgName === 'This community') { + edgesToAdd.push({from: 'connected-community', to: 'this-community', length: that.options.EDGE_LENGTH_HUB}); + } else { + nodesToAdd.push({ + id: 'connected-community_' + orgName, + label: orgName, + group: 'connected-community' + }); + edgesToAdd.push({from: 'connected-community', to: 'connected-community_' + orgName}); + } + }); + } + + // All Community + if (target_distribution >= 3 && target_distribution != 4 && this.distributionData.event[3] > 0) { + nodesToAdd.push({id: 'all-community', label: 'All community', group: 'web'}); + this.distributionData.additionalDistributionInfo[3].forEach(function(orgName) { + if (orgName === 'This community') { + edgesToAdd.push({from: 'all-community', to: 'this-community', length: that.options.EDGE_LENGTH_HUB}); + } else if (orgName === 'All other communities') { + edgesToAdd.push({from: 'all-community', to: 'connected-community', length: that.options.EDGE_LENGTH_HUB}); + } + }); + } + // Sharing Group + if (this.distributionData.event[4] > 0) { + this.distributionData.allSharingGroup.forEach(function(sg) { + var sgName = sg.SharingGroup.name; + if (overwriteSg === undefined) { // if overwriteSg not set, use the one from the event + overwriteSg = that.distributionData.additionalDistributionInfo[4]; + } + if (overwriteSg.indexOf(sgName) == -1) { + return true; + } + + nodesToAdd.push({ + id: 'sharing-group_' + sgName, + label: sgName, + group: 'root-sharing-group' + }); + edgesToAdd.push({from: 'root', to: 'sharing-group_' + sgName, width: 3}); + sg.SharingGroupOrg.forEach(function(org) { + var sgOrgName = org.Organisation.name; + if (that.cacheAddedOrgName[sgOrgName] === undefined) { + nodesToAdd.push({ + id: sgOrgName, + label: sgOrgName, + group: 'sharing-group' + }); + that.cacheAddedOrgName[sgOrgName] = 1; + } + edgesToAdd.push({ + from: 'sharing-group_' + sgName, + to: sgOrgName, + arrows: { + to: { enabled: false } + }, + color: { opacity: 0.4 } + }); + }); + }); + } + + var options = ''; + $('#sharingNetworkOrgFinder').empty(); + Object.keys(this.cacheAddedOrgName).forEach(function(org) { + options += ''; + }); + $('#sharingNetworkOrgFinder').append(options) + .trigger('chosen:updated') + .chosen({ + inherit_select_classes: true, + no_results_text: "Focus to an organisation", + placeholder_text_single: "Focus to an organisation", + allow_single_deselect: true + }) + .off('change') + .on('change', function(evt, params) { + if (this.value !== '') { + if (that.nodes_distri.get(this.value) !== null) { + that.network.focus(this.value, {animation: true}); + that.network.selectNodes([this.value]); + } + } else { + that.network.fit({animation: true}) + } + }); + + this.nodes_distri.add(nodesToAdd); + this.edges_distri.add(edgesToAdd); + var data = { nodes: this.nodes_distri, edges: this.edges_distri }; + this.network = new vis.Network(document.getElementById('advancedSharingNetwork'), data, this.options.network_options); + + this.network.on("dragStart", function (params) { + params.nodes.forEach(function(nodeId) { + that.nodes_distri.update({id: nodeId, fixed: {x: false, y: false}}); + }); + }); + this.network.on("dragEnd", function (params) { + params.nodes.forEach(function(nodeId) { + that.nodes_distri.update({id: nodeId, fixed: {x: true, y: true}}); + }); + }); + + $('#interactive_picking_mode').off('change').on('change', function(e) { + var target_id = $(this).val(); + if (this.checked) { + that._toggleRowListener(true); + } else { + that._toggleRowListener(false); + that._construct_network(this.event_distribution) + } + }); + }, + + _toggleRowListener: function(toAdd) { + var that = this; + if (toAdd) { + $('#attributes_div table tr').off('click.advancedSharing').on('click.advancedSharing', function() { + var $row = $(this); + var clicked_type = $row.attr('id').split('_')[0]; + var clicked_id = $row.attr('id').split('_')[1]; + // var $dist_cell = $row.find('#'+clicked_type+'_'+clicked_id+'_distribution_solid'); + var $dist_cell = $row.find('div').filter(function() { + return $(this).attr('id') !== undefined && $(this).attr('id').includes(clicked_id+'_distribution'); + }); + + var distribution_value; + var overwriteSg; + switch ($dist_cell.text().trim()) { + case 'Organisation': + distribution_value = 0; + break; + case 'Community': + distribution_value = 1; + break; + case 'Connected': + distribution_value = 2; + break; + case 'All': + distribution_value = 3; + break; + case 'Inherit': + distribution_value = 5; + if (that.event_distribution == 4) { + overwriteSg = that.event_distribution_text.trim(); + } + break; + default: + distribution_value = 4; + overwriteSg = $dist_cell.text().trim(); + break + } + that._construct_network(distribution_value, clicked_type+' '+clicked_id, [overwriteSg]); + }); + } else { + $('#attributes_div table tr').off('click.advancedSharing'); + } + }, + + _inject_this_community_org: function(nodesToAdd, edgesToAdd, orgs, group, root) { + var that = this; + orgs.forEach(function(orgName) { + if (that.cacheAddedOrgName[orgName] === undefined) { + nodesToAdd.push({ + id: orgName, + label: orgName, + group: group + }); + that.cacheAddedOrgName[orgName] = 1; + } + edgesToAdd.push({ + from: root, + to: orgName, + arrows: { + to: { enabled: false } + }, + color: { opacity: 0.4 } + }); + }); + }, + + }; + + $.distributionNetwork = DistributionNetwork; + $.fn.distributionNetwork = function(option) { + var pickedArgs = arguments; + + return this.each(function() { + var $this = $(this), + inst = $this.data('distributionNetwork'), + options = ((typeof option === 'object') ? option : {}); + if ((!inst) && (typeof option !== 'string')) { + $this.data('distributionNetwork', new DistributionNetwork(this, options)); + } else { + if (typeof option === 'string') { + inst[option].apply(inst, Array.prototype.slice.call(pickerArgs, 1)); + } + } + }); + }; + + $.fn.distributionNetwork.constructor = DistributionNetwork; + })); From 8a5cce8cb314c4501ca078c352bd7403a1fb25ef Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 12 Mar 2019 10:46:46 +0100 Subject: [PATCH 20/25] chg: [distributionNetwork] Improved consistency in event index and improved UX - WiP --- app/Controller/EventsController.php | 2 +- app/Lib/Tools/DistributionGraphTool.php | 28 +++++++++-------- app/View/Elements/Events/eventIndexTable.ctp | 3 +- app/webroot/js/misp.js | 1 - app/webroot/js/network-distribution-graph.js | 32 +++++++++++++++++--- 5 files changed, 45 insertions(+), 21 deletions(-) diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php index d2e054d0c..599e30074 100644 --- a/app/Controller/EventsController.php +++ b/app/Controller/EventsController.php @@ -862,7 +862,7 @@ class EventsController extends AppController $this->set('analysisLevels', $this->Event->analysisLevels); $this->set('distributionLevels', $this->Event->distributionLevels); $this->set('shortDist', $this->Event->shortDist); - $this->set('distributionData', $this->genDistributionGraph(0)); + $this->set('distributionData', $this->genDistributionGraph(-1)); if ($this->params['ext'] === 'csv') { App::uses('CsvExport', 'Export'); $export = new CsvExport(); diff --git a/app/Lib/Tools/DistributionGraphTool.php b/app/Lib/Tools/DistributionGraphTool.php index 64c3a783c..98f03b2c9 100644 --- a/app/Lib/Tools/DistributionGraphTool.php +++ b/app/Lib/Tools/DistributionGraphTool.php @@ -130,11 +130,6 @@ public function get_distributions_graph($id) { - $event = $this->__get_event($id); - $eventDist = $event['distribution']; - $eventSGName = $event['SharingGroupName']; - $this->__eventDistribution = $eventDist; - $this->__eventSharingGroupName = $eventSGName; $this->__json['event'] = $this->init_array_distri(); $this->__json['attribute'] = $this->init_array_distri(); $this->__json['object'] = $this->init_array_distri(); @@ -142,6 +137,21 @@ $this->__json['additionalDistributionInfo'] = $this->init_array_distri(array()); $this->__json['sharingGroupRepartition'] = array(); + $this->__addOtherDistributionInfo(); + + // transform set into array + foreach (array_keys($this->__json['additionalDistributionInfo']) as $d) { + $this->__json['additionalDistributionInfo'][$d] = array_keys($this->__json['additionalDistributionInfo'][$d]); + } + + if ($id === -1) { + return $this->__json; + } + $event = $this->__get_event($id); + $eventDist = $event['distribution']; + $eventSGName = $event['SharingGroupName']; + $this->__eventDistribution = $eventDist; + $this->__eventSharingGroupName = $eventSGName; if (empty($event)) { return $this->__json; @@ -195,14 +205,6 @@ unset($this->__json['distributionInfo'][5]); // inherit event. - - $this->__addOtherDistributionInfo(); - - // transform set into array - foreach (array_keys($this->__json['additionalDistributionInfo']) as $d) { - $this->__json['additionalDistributionInfo'][$d] = array_keys($this->__json['additionalDistributionInfo'][$d]); - } - return $this->__json; } diff --git a/app/View/Elements/Events/eventIndexTable.ctp b/app/View/Elements/Events/eventIndexTable.ctp index 66cfae051..7af5ee352 100644 --- a/app/View/Elements/Events/eventIndexTable.ctp +++ b/app/View/Elements/Events/eventIndexTable.ctp @@ -216,10 +216,11 @@ ?> ', + '', 'Toggle advanced sharing network viewer', 'fa fa-share-alt useCursorPointer distributionNetworkToggle', h($event['Event']['distribution']), + $event['Event']['distribution'] == 4 ? h($event['SharingGroup']['name']) : h($shortDist[$event['Event']['distribution']]), h($event['Event']['id']) ) ?> diff --git a/app/webroot/js/misp.js b/app/webroot/js/misp.js index dcc797bdf..b13ad37dc 100644 --- a/app/webroot/js/misp.js +++ b/app/webroot/js/misp.js @@ -4005,7 +4005,6 @@ function sparklineBar(elemId, data, lineCount) { e = parseInt(e.val); y_max = e > y_max ? e : y_max; }); - // y_max = Math.log(y_max) var WIDTH = 50; var HEIGHT = 25; var DATA_COUNT = lineCount; diff --git a/app/webroot/js/network-distribution-graph.js b/app/webroot/js/network-distribution-graph.js index bc774e5de..122b50618 100644 --- a/app/webroot/js/network-distribution-graph.js +++ b/app/webroot/js/network-distribution-graph.js @@ -166,10 +166,10 @@ this.network_wrapper = false; this.options = $.extend({}, this._default_options, options); + this.event_distribution = this.options.event_distribution; this.scope_id = this.options.scope_id; this.distributionData = this.options.distributionData; - this.active = false; this.network; this.nodes_distri; this.edges_distri; @@ -186,12 +186,16 @@ if (options.event_distribution === undefined) { // try to fetch is from the container var event_distribution = this.container.data('event-distribution'); - if (event_distribution !== undefined) { + var event_distribution_name = this.container.data('event-distribution-name'); + if (event_distribution !== undefined && event_distribution_name !== undefined) { options.event_distribution = event_distribution; + options.event_distribution_name = event_distribution_name; + this._adjust_sharing_numbers(options) } else { - throw "Event distribution not set"; + throw "Event distribution or Org not set"; } } + if (options.distributionData === undefined) { throw "Distribution data not set"; } @@ -206,11 +210,28 @@ } }, + _adjust_sharing_numbers: function (options) { + var sum = options.distributionData.event.reduce(function(pv, cv) { return pv + cv; }, 0); + if (sum == 0) { // if event does not contain anything (or we don't know about its content) + options.distributionData.event[options.event_distribution] = 1; + } + if (options.event_distribution == 4) { + options.distributionData.additionalDistributionInfo[4].push(options.event_distribution_name); + } + }, + _registerListener: function() { var that = this; this.container.click(function() { $('#sharingNetworkWrapper').toggle('slide', {direction: 'right'}, 300); that._construct_network(); + + $('body').off('keyup.distributionNetwork').on('keyup.distributionNetwork', function(e) { + if (e.keyCode == 27) { // ESC + $('body').off('keyup.distributionNetwork'); + that.dismissNetwork(); + } + }); }); }, @@ -263,7 +284,6 @@ target_distribution = this.event_distribution; } - console.log(this.distributionData); if (target_distribution !== 0) { // Event always restrict propagation (sharing group is a special case) var temp_target_disti = target_distribution; @@ -361,7 +381,9 @@ } // All Community - if (target_distribution >= 3 && target_distribution != 4 && this.distributionData.event[3] > 0) { + if (target_distribution >= 3 && target_distribution != 4 + && this.distributionData.event[3] > 0 + ) { nodesToAdd.push({id: 'all-community', label: 'All community', group: 'web'}); this.distributionData.additionalDistributionInfo[3].forEach(function(orgName) { if (orgName === 'This community') { From d67af3c4dde353730304acca6d1bd320da0581de Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 12 Mar 2019 10:59:51 +0100 Subject: [PATCH 21/25] fix: [distributionGraph] Transform associative array into regular array --- app/Lib/Tools/DistributionGraphTool.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Lib/Tools/DistributionGraphTool.php b/app/Lib/Tools/DistributionGraphTool.php index 98f03b2c9..c99da884f 100644 --- a/app/Lib/Tools/DistributionGraphTool.php +++ b/app/Lib/Tools/DistributionGraphTool.php @@ -205,6 +205,9 @@ unset($this->__json['distributionInfo'][5]); // inherit event. + // transform set into array for SG (other are already done) + $this->__json['additionalDistributionInfo'][4] = array_keys($this->__json['additionalDistributionInfo'][4]); + return $this->__json; } From 05edf15e43d2f1c4faa4fefc466d7275543588fd Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 12 Mar 2019 11:38:52 +0100 Subject: [PATCH 22/25] fix: [disitributionNetwork] Empty cached org on redraw --- app/webroot/js/network-distribution-graph.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/webroot/js/network-distribution-graph.js b/app/webroot/js/network-distribution-graph.js index 122b50618..6b82ce987 100644 --- a/app/webroot/js/network-distribution-graph.js +++ b/app/webroot/js/network-distribution-graph.js @@ -266,6 +266,7 @@ var that = this; if (this.network !== undefined) { this.network.destroy(); + this.cacheAddedOrgName = {}; } if (scope_text == undefined) { scope_text = 'Event ' + this.options.scope_id; From d9ca64b37f6cd77ea6f4744916ce4b5b73248e8c Mon Sep 17 00:00:00 2001 From: mokaddem Date: Tue, 12 Mar 2019 14:47:34 +0100 Subject: [PATCH 23/25] chg: [distributionNetwork] Prevent interactive picking in event index --- app/webroot/js/network-distribution-graph.js | 25 +++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/webroot/js/network-distribution-graph.js b/app/webroot/js/network-distribution-graph.js index 6b82ce987..ffa7b4831 100644 --- a/app/webroot/js/network-distribution-graph.js +++ b/app/webroot/js/network-distribution-graph.js @@ -245,16 +245,22 @@ if ($('#sharingNetworkWrapper').length > 0) { return; // Wrapper already exists } - var $div = $('
'; + $div = $($div); this.network_wrapper = $div; $div.find('#closeButton').click(function() { that.dismissNetwork(); @@ -488,11 +494,14 @@ _toggleRowListener: function(toAdd) { var that = this; if (toAdd) { - $('#attributes_div table tr').off('click.advancedSharing').on('click.advancedSharing', function() { + var $table = $('#attributes_div table tr'); + if ($table.length == 0) { + return; + } + $table.off('click.advancedSharing').on('click.advancedSharing', function() { var $row = $(this); var clicked_type = $row.attr('id').split('_')[0]; var clicked_id = $row.attr('id').split('_')[1]; - // var $dist_cell = $row.find('#'+clicked_type+'_'+clicked_id+'_distribution_solid'); var $dist_cell = $row.find('div').filter(function() { return $(this).attr('id') !== undefined && $(this).attr('id').includes(clicked_id+'_distribution'); }); From b8334521d34572461557ed55b630d41741bb0522 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Fri, 15 Mar 2019 11:52:37 +0100 Subject: [PATCH 24/25] chg: Updated comments --- app/Controller/EventsController.php | 21 --------------------- app/Lib/Tools/DistributionGraphTool.php | 2 +- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php index 381173841..40148c1b7 100644 --- a/app/Controller/EventsController.php +++ b/app/Controller/EventsController.php @@ -4694,28 +4694,7 @@ class EventsController extends AppController public function getDistributionGraph($id, $type = 'event') { - // $validTools = array('event'); - // if (!in_array($type, $validTools)) { - // throw new MethodNotAllowedException(__('Invalid type.')); - // } - // $this->loadModel('Server'); - // $this->loadModel('Organisation'); - // App::uses('DistributionGraphTool', 'Tools'); - // $grapher = new DistributionGraphTool(); - // $extended = isset($this->params['named']['extended']) ? 1 : 0; - // - // $servers = $this->Server->find('list', array( - // 'fields' => array('name'), - // )); - // $grapher->construct($this->Event, $servers, $this->Auth->user(), $extended); - // $json = $grapher->get_distributions_graph($id); - // - // array_walk_recursive($json, function (&$item, $key) { - // if (!mb_detect_encoding($item, 'utf-8', true)) { - // $item = utf8_encode($item); - // } - // }); $json = $this->genDistributionGraph($id, $type, $extended); $this->response->type('json'); return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json')); diff --git a/app/Lib/Tools/DistributionGraphTool.php b/app/Lib/Tools/DistributionGraphTool.php index c99da884f..6cc41ec18 100644 --- a/app/Lib/Tools/DistributionGraphTool.php +++ b/app/Lib/Tools/DistributionGraphTool.php @@ -205,7 +205,7 @@ unset($this->__json['distributionInfo'][5]); // inherit event. - // transform set into array for SG (other are already done) + // transform set into array for SG (others are already done) $this->__json['additionalDistributionInfo'][4] = array_keys($this->__json['additionalDistributionInfo'][4]); return $this->__json; From aa03357aaa7d69d6441ffe100d78de0d1a5dfbb3 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Fri, 15 Mar 2019 15:32:18 +0100 Subject: [PATCH 25/25] fix: [ACL] Whitelisted `genDistributionGraph` --- app/Controller/Component/ACLComponent.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Controller/Component/ACLComponent.php b/app/Controller/Component/ACLComponent.php index ed2a1a0ab..8532ecb83 100644 --- a/app/Controller/Component/ACLComponent.php +++ b/app/Controller/Component/ACLComponent.php @@ -115,6 +115,7 @@ class ACLComponent extends Component 'getEventGraphReferences' => array('*'), 'getEventGraphTags' => array('*'), 'getEventGraphGeneric' => array('*'), + 'genDistributionGraph' => array('*'), 'getDistributionGraph' => array('*'), 'getReferenceData' => array('*'), 'getReferences' => array('*'),