mirror of https://github.com/MISP/misp-dashboard
feature: Added draft of timeline which shows event overtime. The event
currently span consecutive days (if it has been seen).pull/29/head
parent
ef6f9190b2
commit
5de0d31818
|
@ -158,3 +158,43 @@ class Trendings_helper:
|
|||
tagSet.add(tag['name'])
|
||||
to_ret[self.keyTag] = list(tagSet)
|
||||
return to_ret
|
||||
|
||||
# In contrary of getGenericTrending, it regroups items in the format: {item, start: timestamp1, end: timestamp2}
|
||||
# so that it can be displayed easily on the timeline.
|
||||
def getGenericTrendingOvertime(self, dateS, dateE, trendingType=None, topNum=0):
|
||||
trendingType = self.keyEvent
|
||||
dico_items = {}
|
||||
to_format = []
|
||||
prev_days = (dateE - dateS).days
|
||||
# get data
|
||||
for curDate in util.getXPrevDaysSpan(dateE, prev_days):
|
||||
keyname = "{}:{}".format(trendingType, util.getDateStrFormat(curDate))
|
||||
data = self.serv_redis_db.zrange(keyname, 0, topNum-1, desc=True, withscores=True)
|
||||
data = [ [record[0].decode('utf8'), record[1]] for record in data ]
|
||||
data = data if data is not None else []
|
||||
to_format.append([util.getTimestamp(curDate), data])
|
||||
|
||||
for timestamp, array in to_format:
|
||||
for item, _ in array:
|
||||
if item not in dico_items:
|
||||
dico_items[item] = []
|
||||
dico_items[item].append(timestamp)
|
||||
|
||||
# sort timestamps in correct order
|
||||
for item in dico_items.keys():
|
||||
dico_items[item].sort()
|
||||
# dico_items have the form: {item: [t1,t2,t4], ...}
|
||||
to_ret = []
|
||||
ONEDAY = 60*60*24
|
||||
for item, timestamps in dico_items.items():
|
||||
obj = {'name': item, 'start': timestamps[0]-ONEDAY, 'end': timestamps[0]}
|
||||
for t in timestamps:
|
||||
if t-obj['end'] > ONEDAY: #new entry
|
||||
to_ret.append(obj)
|
||||
obj['start'] = t-ONEDAY
|
||||
obj['end'] = t
|
||||
else: # contrinue entry
|
||||
obj['end'] = t
|
||||
to_ret.append(obj)
|
||||
|
||||
return to_ret
|
||||
|
|
|
@ -108,4 +108,9 @@ mv temp/jquery-punchcard/src/punchcard.js ./static/js
|
|||
mv temp/jquery-punchcard/src/punchcard.css ./static/css
|
||||
wget https://momentjs.com/downloads/moment.js -O ./static/js/moment.js
|
||||
|
||||
# timeline
|
||||
VISJS_VERSION="4.21.0"
|
||||
https://cdnjs.cloudflare.com/ajax/libs/vis/${VISJS_VERSION}/vis.min.js
|
||||
https://cdnjs.cloudflare.com/ajax/libs/vis/${VISJS_VERSION}/vis.min.css
|
||||
|
||||
rm -rf ./temp
|
||||
|
|
12
server.py
12
server.py
|
@ -536,5 +536,17 @@ def getTypeaheadData():
|
|||
data = trendings_helper.getTypeaheadData(dateS, dateE)
|
||||
return jsonify(data)
|
||||
|
||||
@app.route("/_getGenericTrendingOvertime")
|
||||
def getGenericTrendingOvertime():
|
||||
try:
|
||||
dateS = datetime.datetime.fromtimestamp(float(request.args.get('dateS')))
|
||||
dateE = datetime.datetime.fromtimestamp(float(request.args.get('dateE')))
|
||||
except:
|
||||
dateS = datetime.datetime.now() - datetime.timedelta(days=7)
|
||||
dateE = datetime.datetime.now()
|
||||
|
||||
data = trendings_helper.getGenericTrendingOvertime(dateS, dateE)
|
||||
return jsonify(data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='localhost', port=8001, threaded=True)
|
||||
|
|
|
@ -9,6 +9,7 @@ var tagPie = ["#tagPie"];
|
|||
var tagLine = ["#tagLine"];
|
||||
var sightingLineWidget;
|
||||
var discLine = ["#discussionLine"];
|
||||
var timeline;
|
||||
var allData;
|
||||
var globalColorMapping = {};
|
||||
|
||||
|
@ -103,6 +104,8 @@ var typeaheadOption_tag = {
|
|||
updateLineForLabel(tagLine, tag, undefined, url_getTrendingTag);
|
||||
}
|
||||
}
|
||||
var timeline_option = {};
|
||||
|
||||
|
||||
/* FUNCTIONS */
|
||||
function getColor(label) {
|
||||
|
@ -396,6 +399,29 @@ function updateDisc() {
|
|||
});
|
||||
}
|
||||
|
||||
function updateTimeline() {
|
||||
$.getJSON( url_getGenericTrendingOvertime+"?dateS="+parseInt(dateStart.getTime()/1000)+"&dateE="+parseInt(dateEnd.getTime()/1000), function( data ) {
|
||||
var items = [];
|
||||
var i = 1;
|
||||
for (var obj of data) {
|
||||
if (obj.end == obj.start) { console.log(obj);}
|
||||
items.push({
|
||||
id: i,
|
||||
content: obj.name,
|
||||
start: obj.start*1000,
|
||||
end: obj.end*1000
|
||||
});
|
||||
i++;
|
||||
}
|
||||
items = new vis.DataSet(items);
|
||||
if (timeline === undefined) { // create timeline
|
||||
timeline = new vis.Timeline(document.getElementById('timeline'), items, timeline_option);
|
||||
} else { // update
|
||||
timeline.setItems(items);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dateChanged() {
|
||||
dateStart = datePickerWidgetStart.datepicker( "getDate" );
|
||||
dateEnd = datePickerWidgetEnd.datepicker( "getDate" );
|
||||
|
@ -404,6 +430,7 @@ function dateChanged() {
|
|||
updatePieLine(tagPie, tagLine, url_getTrendingTag);
|
||||
updateSignthingsChart();
|
||||
updateDisc();
|
||||
updateTimeline();
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
|
@ -426,6 +453,7 @@ $(document).ready(function () {
|
|||
updatePieLine(tagPie, tagLine, url_getTrendingTag)
|
||||
updateSignthingsChart();
|
||||
updateDisc();
|
||||
updateTimeline();
|
||||
|
||||
$( "#num_selector" ).change(function() {
|
||||
var sel = parseInt($( this ).val());
|
||||
|
@ -437,5 +465,4 @@ $(document).ready(function () {
|
|||
position: "absolute",
|
||||
display: "none",
|
||||
}).appendTo("body");
|
||||
|
||||
});
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
<link href="{{ url_for('static', filename='css/jquery-ui.min.css') }}" rel="stylesheet" type="text/css" />
|
||||
<script src="{{ url_for('static', filename='js/jquery-ui.min.js') }}"></script>
|
||||
|
||||
<link href="{{ url_for('static', filename='css/vis.min.css') }}" rel="stylesheet" type="text/css" />
|
||||
<script src="{{ url_for('static', filename='js/vis.min.js') }}"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<style>
|
||||
|
@ -206,6 +209,17 @@ small {
|
|||
</div>
|
||||
</div><!-- /.col-lg-12 -->
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default" style="">
|
||||
<div class="panel-heading" style="font-weight: bold;">
|
||||
<b>Timeline</b>
|
||||
</div>
|
||||
<div class="panel-body" style="">
|
||||
<div id="timeline" style="width:100%; height: 100%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.col-lg-12 -->
|
||||
|
||||
</div><!-- /.row -->
|
||||
|
||||
</div> <!-- /.container-fluid -->
|
||||
|
@ -226,6 +240,7 @@ small {
|
|||
var url_getTrendingTag = "{{ url_for('getTrendingTags') }}";
|
||||
var url_getTrendingSightings = "{{ url_for('getTrendingSightings') }}";
|
||||
var url_getTrendingDisc = "{{ url_for('getTrendingDisc') }}";
|
||||
var url_getGenericTrendingOvertime = "{{ url_for('getGenericTrendingOvertime') }}";
|
||||
|
||||
var url_getTypeaheadData = "{{ url_for('getTypeaheadData') }}";
|
||||
|
||||
|
|
Loading…
Reference in New Issue