mirror of https://github.com/MISP/misp-dashboard
Merge branch 'users' into trendings
commit
e3a63e863f
10
server.py
10
server.py
|
@ -487,6 +487,16 @@ def getLoginVSCOntribution():
|
||||||
data = users_helper.getLoginVSCOntribution(date)
|
data = users_helper.getLoginVSCOntribution(date)
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
@app.route("/_getUserLoginsAndContribOvertime")
|
||||||
|
def getUserLoginsAndContribOvertime():
|
||||||
|
try:
|
||||||
|
date = datetime.datetime.fromtimestamp(float(request.args.get('date')))
|
||||||
|
except:
|
||||||
|
date = datetime.datetime.now()
|
||||||
|
|
||||||
|
data = users_helper.getUserLoginsAndContribOvertime(date)
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
''' TRENDINGS '''
|
''' TRENDINGS '''
|
||||||
@app.route("/_getTrendingEvents")
|
@app.route("/_getTrendingEvents")
|
||||||
def getTrendingEvents():
|
def getTrendingEvents():
|
||||||
|
|
|
@ -527,8 +527,14 @@ function updateProgressHeader(org) {
|
||||||
categ = trophy_categ_list[i];
|
categ = trophy_categ_list[i];
|
||||||
$('#trophy_'+categ).attr('src', source);
|
$('#trophy_'+categ).attr('src', source);
|
||||||
$('#trophy_'+categ).attr('title', "");
|
$('#trophy_'+categ).attr('title', "");
|
||||||
$('#trophy_'+categ).popover("destroy")
|
try { // in case popover not created
|
||||||
|
var pop = $('#trophy_'+categ).data('bs.popover');
|
||||||
|
pop.destroy();
|
||||||
|
} catch(err) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
setTimeout(function() { // avoid race condition with destroy
|
||||||
for(var i=0; i<data.length; i++) { // add
|
for(var i=0; i<data.length; i++) { // add
|
||||||
categ = data[i].categ;
|
categ = data[i].categ;
|
||||||
rank = data[i].trophy_true_rank;
|
rank = data[i].trophy_true_rank;
|
||||||
|
@ -538,6 +544,7 @@ function updateProgressHeader(org) {
|
||||||
$('#trophy_'+categ).attr('title', trophy_title[rank]);
|
$('#trophy_'+categ).attr('title', trophy_title[rank]);
|
||||||
$('#trophy_'+categ).popover({title: trophy_title[rank], content: 'Level: '+rank+' ('+trophy_points+' points)', trigger: "hover", placement: "bottom"});
|
$('#trophy_'+categ).popover({title: trophy_title[rank], content: 'Level: '+rank+' ('+trophy_points+' points)', trigger: "hover", placement: "bottom"});
|
||||||
}
|
}
|
||||||
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
//update overtake points
|
//update overtake points
|
||||||
|
|
|
@ -123,13 +123,25 @@ function updateDateOvertime() {
|
||||||
} else {
|
} else {
|
||||||
date.setTime(date.getTime() + (24*60*60*1000-1)); // include data of selected date
|
date.setTime(date.getTime() + (24*60*60*1000-1)); // include data of selected date
|
||||||
}
|
}
|
||||||
$.getJSON( url_getUserLoginsOvertime+"?date="+parseInt(date.getTime()/1000), function( data ) {
|
$.getJSON( url_getUserLoginsAndContribOvertime+"?date="+parseInt(date.getTime()/1000), function( data ) {
|
||||||
temp = [];
|
console.log(data);
|
||||||
|
data_log = data['login'];
|
||||||
|
data_contrib = data['contrib'];
|
||||||
|
temp_log = [];
|
||||||
var i=0;
|
var i=0;
|
||||||
for (item of data) {
|
for (item of data_log) {
|
||||||
temp.push([new Date(item[0]*1000), item[1]]);
|
var date = new Date(item[0]*1000);
|
||||||
|
date = new Date(date.valueOf() - date.getTimezoneOffset() * 60000); // center the data around the day
|
||||||
|
temp_log.push([date, item[1]]);
|
||||||
}
|
}
|
||||||
toPlot = [{label: 'Login overtime', data: temp}];
|
temp_contrib= [];
|
||||||
|
var i=0;
|
||||||
|
for (item of data_contrib) {
|
||||||
|
var date = new Date(item[0]*1000);
|
||||||
|
date = new Date(date.valueOf() - date.getTimezoneOffset() * 60000); // center the data around the day
|
||||||
|
temp_contrib.push([date, item[1]]);
|
||||||
|
}
|
||||||
|
toPlot = [{label: 'Login', data: temp_log}, {label: 'Contribution', data: temp_contrib}];
|
||||||
if (!(overtimeWidget === undefined)) {
|
if (!(overtimeWidget === undefined)) {
|
||||||
overtimeWidget.setData(toPlot);
|
overtimeWidget.setData(toPlot);
|
||||||
overtimeWidget.setupGrid();
|
overtimeWidget.setupGrid();
|
||||||
|
|
|
@ -167,7 +167,7 @@ small {
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="panel panel-default" style="">
|
<div class="panel panel-default" style="">
|
||||||
<div class="panel-heading bg-info" style="font-weight: bold;">
|
<div class="panel-heading bg-info" style="font-weight: bold;">
|
||||||
<b>Login overtime</b>
|
<b title="Login is unique per organisation during one hour, contribution is unique per organisation during the day">Login and contribution overtime</b>
|
||||||
<strong class='leftSepa textTopHeader' style="float: none; padding: 11px;">Dates:
|
<strong class='leftSepa textTopHeader' style="float: none; padding: 11px;">Dates:
|
||||||
<input type="text" id="datepickerOvertimeLogin" size="10" style="">
|
<input type="text" id="datepickerOvertimeLogin" size="10" style="">
|
||||||
</strong>
|
</strong>
|
||||||
|
@ -195,7 +195,7 @@ small {
|
||||||
var url_getUserLogins = "{{ url_for('getUserLogins') }}";
|
var url_getUserLogins = "{{ url_for('getUserLogins') }}";
|
||||||
var url_getTopOrglogin = "{{ url_for('getTopOrglogin') }}";
|
var url_getTopOrglogin = "{{ url_for('getTopOrglogin') }}";
|
||||||
var url_getLoginVSCOntribution = "{{ url_for('getLoginVSCOntribution') }}";
|
var url_getLoginVSCOntribution = "{{ url_for('getLoginVSCOntribution') }}";
|
||||||
var url_getUserLoginsOvertime = "{{ url_for('getUserLoginsOvertime') }}";
|
var url_getUserLoginsAndContribOvertime = "{{ url_for('getUserLoginsAndContribOvertime') }}";
|
||||||
|
|
||||||
/* DATA FROM CONF */
|
/* DATA FROM CONF */
|
||||||
|
|
||||||
|
|
|
@ -136,13 +136,22 @@ class Users_helper:
|
||||||
data = [data[6]]+data[:6]
|
data = [data[6]]+data[:6]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getUserLoginsOvertime(self, date, prev_days=6):
|
def getUserLoginsAndContribOvertime(self, date, prev_days=6):
|
||||||
|
dico_hours_contrib = {}
|
||||||
dico_hours = {}
|
dico_hours = {}
|
||||||
for curDate in util.getXPrevHoursSpan(date, prev_days*24):
|
for curDate in util.getXPrevHoursSpan(date, prev_days*24):
|
||||||
dico_hours[util.getTimestamp(curDate)] = 0 # populate with empty data
|
dico_hours[util.getTimestamp(curDate)] = 0 # populate with empty data
|
||||||
|
dico_hours_contrib[util.getTimestamp(curDate)] = 0 # populate with empty data
|
||||||
|
|
||||||
for curDate in util.getXPrevDaysSpan(date, prev_days):
|
for curDate in util.getXPrevDaysSpan(date, prev_days):
|
||||||
timestamps = self.getUserLogins(curDate)
|
timestamps = self.getUserLogins(curDate)
|
||||||
|
keyname = "CONTRIB_DAY:{}".format(util.getDateStrFormat(curDate))
|
||||||
|
|
||||||
|
orgs_contri = self.serv_redis_db.zrange(keyname, 0, -1, desc=True, withscores=False)
|
||||||
|
orgs_contri_num = len(orgs_contri)
|
||||||
|
for curDate in util.getHoursSpanOfDate(curDate, adaptToFitCurrentTime=True): #fill hole day
|
||||||
|
dico_hours_contrib[util.getTimestamp(curDate)] = orgs_contri_num
|
||||||
|
|
||||||
for timestamp in timestamps: # sum occurence during the current hour
|
for timestamp in timestamps: # sum occurence during the current hour
|
||||||
dateTimestamp = datetime.datetime.fromtimestamp(float(timestamp))
|
dateTimestamp = datetime.datetime.fromtimestamp(float(timestamp))
|
||||||
dateTimestamp = dateTimestamp.replace(minute=0, second=0, microsecond=0)
|
dateTimestamp = dateTimestamp.replace(minute=0, second=0, microsecond=0)
|
||||||
|
@ -152,9 +161,18 @@ class Users_helper:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Format data
|
# Format data
|
||||||
|
# login
|
||||||
|
to_ret = {}
|
||||||
data = []
|
data = []
|
||||||
for curDate, occ in dico_hours.items():
|
for curDate, occ in dico_hours.items():
|
||||||
data.append([curDate, occ])
|
data.append([curDate, occ])
|
||||||
|
|
||||||
data.sort(key=lambda x: x[0])
|
data.sort(key=lambda x: x[0])
|
||||||
return data
|
to_ret['login'] = data
|
||||||
|
# contrib
|
||||||
|
data = []
|
||||||
|
for curDate, occ in dico_hours_contrib.items():
|
||||||
|
data.append([curDate, occ])
|
||||||
|
data.sort(key=lambda x: x[0])
|
||||||
|
to_ret['contrib'] = data
|
||||||
|
|
||||||
|
return to_ret
|
||||||
|
|
12
util.py
12
util.py
|
@ -35,6 +35,18 @@ def getXPrevHoursSpan(date, hours):
|
||||||
to_return.append(de - datetime.timedelta(hours=i))
|
to_return.append(de - datetime.timedelta(hours=i))
|
||||||
return to_return
|
return to_return
|
||||||
|
|
||||||
|
def getHoursSpanOfDate(date, adaptToFitCurrentTime=True, daySpanned=6):
|
||||||
|
ds = date
|
||||||
|
ds = ds.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
to_return = []
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
for i in range(0, 24):
|
||||||
|
the_date = ds + datetime.timedelta(hours=i)
|
||||||
|
if the_date > now or the_date < now - datetime.timedelta(days=daySpanned): # avoid going outside
|
||||||
|
continue
|
||||||
|
to_return.append(the_date)
|
||||||
|
return to_return
|
||||||
|
|
||||||
def getDateStrFormat(date):
|
def getDateStrFormat(date):
|
||||||
return str(date.year)+str(date.month).zfill(2)+str(date.day).zfill(2)
|
return str(date.year)+str(date.month).zfill(2)+str(date.day).zfill(2)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue