mirror of https://github.com/MISP/misp-dashboard
Added display of conribution rank statys + acquired badges
parent
a9d5ca5657
commit
605538ce97
|
@ -35,6 +35,11 @@ maxLevel=16
|
|||
15=32768
|
||||
16=65536
|
||||
|
||||
[rankRequirementsMisc]
|
||||
heavilyCount=10
|
||||
recentDays=31
|
||||
regularlyDays=7
|
||||
|
||||
[rankRequirementsText]
|
||||
1=Contributing via sighting at least once a year
|
||||
2=Contributing via attributes or objects to events at least once a year
|
||||
|
|
|
@ -13,8 +13,13 @@ class Contributor_helper:
|
|||
self.cfg_org_rank.read(os.path.join(os.environ['DASH_CONFIG'], 'ranking.cfg'))
|
||||
|
||||
#honorBadge
|
||||
self.honorBadgeNum = len(self.cfg_org_rank.options('HonorBadge'))
|
||||
self.heavilyCount = self.cfg_org_rank.getint('rankRequirementsMisc', 'heavilyCount')
|
||||
self.recentDays = self.cfg_org_rank.getint('rankRequirementsMisc', 'recentDays')
|
||||
self.regularlyDays = self.cfg_org_rank.getint('rankRequirementsMisc', 'regularlyDays')
|
||||
|
||||
self.org_honor_badge_title = {}
|
||||
for badgeNum in range(1, len(self.cfg_org_rank.options('HonorBadge'))+1): #get Num of honorBadge
|
||||
for badgeNum in range(1, self.honorBadgeNum+1): #get Num of honorBadge
|
||||
self.org_honor_badge_title[badgeNum] = self.cfg_org_rank.get('HonorBadge', str(badgeNum))
|
||||
|
||||
#GLOBAL RANKING
|
||||
|
@ -51,6 +56,11 @@ class Contributor_helper:
|
|||
self.rankMultiplier = cfg.getfloat('CONTRIB' ,'rankMultiplier')
|
||||
self.levelMax = 16
|
||||
|
||||
|
||||
''' HELPER '''
|
||||
def getOrgLogoFromRedis(self, org):
|
||||
return "{}/img/orgs/{}.png".format(self.misp_web_url, org)
|
||||
|
||||
def getZrange(self, keyCateg, date, topNum, endSubkey=""):
|
||||
date_str = util.getDateStrFormat(date)
|
||||
keyname = "{}:{}{}".format(keyCateg, date_str, endSubkey)
|
||||
|
@ -58,6 +68,64 @@ class Contributor_helper:
|
|||
data = [ [record[0].decode('utf8'), record[1]] for record in data ]
|
||||
return data
|
||||
|
||||
''' CONTRIBUTION RANK '''
|
||||
# return: [final_rank, requirement_fulfilled, requirement_not_fulfilled]
|
||||
def getOrgContributionRank(self, org):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
final_rank = 0
|
||||
requirement_fulfilled = []
|
||||
requirement_not_fulfilled = []
|
||||
for i in range(1, self.org_rank_maxLevel+1):
|
||||
key = keyname.format(org=org, orgCateg='CONTRIB_REQ_'+str(i))
|
||||
if self.serv_redis_db.get(key) is None: #non existing
|
||||
requirement_not_fulfilled.append(i)
|
||||
else:
|
||||
requirement_fulfilled.append(i)
|
||||
final_rank += 1
|
||||
num_of_previous_req_not_fulfilled = len([x for x in requirement_not_fulfilled if x<final_rank])
|
||||
final_rank = final_rank - num_of_previous_req_not_fulfilled
|
||||
return [final_rank, requirement_fulfilled, requirement_not_fulfilled]
|
||||
|
||||
def giveContribRankToOrg(self, org, rankNum):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
serv_redis_db.set(keyname.format(org=orgName, orgCateg='CONTRIB_REQ_'+str(rankNum)), 1)
|
||||
|
||||
def removeContribRankFromOrg(self, org, rankNum):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
serv_redis_db.delete(keyname.format(org=orgName, orgCateg='CONTRIB_REQ_'+str(rankNum)))
|
||||
|
||||
# 1 for fulfilled, 0 for not fulfilled, -1 for not relevant
|
||||
def getCurrentContributionStatus(self, org):
|
||||
final_rank, requirement_fulfilled, requirement_not_fulfilled = self.getOrgContributionRank(org)
|
||||
to_ret = {}
|
||||
for i in range(1, self.org_rank_maxLevel+1):
|
||||
if i in requirement_fulfilled:
|
||||
to_ret[i] = 1
|
||||
elif i in requirement_not_fulfilled and i<=final_rank:
|
||||
to_ret[i] = 0
|
||||
else:
|
||||
to_ret[i] = -1
|
||||
return to_ret
|
||||
|
||||
''' HONOR BADGES '''
|
||||
def getOrgHonorBadges(self, org):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
honorBadge = []
|
||||
for i in range(1, self.honorBadgeNum+1):
|
||||
key = keyname.format(org=org, orgCateg='BADGE_'+str(i))
|
||||
if self.serv_redis_db.get(key) is not None: #existing
|
||||
honorBadge.append(i)
|
||||
return honorBadge
|
||||
|
||||
def giveBadgeToOrg(self, org, badgeNum):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
serv_redis_db.set(keyname.format(org=orgName, orgCateg='BADGE_'+str(badgeNum)), 1)
|
||||
|
||||
def removeBadgeFromOrg(self, org, badgeNum):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
serv_redis_db.delete(keyname.format(org=orgName, orgCateg='BADGE_'+str(badgeNum)))
|
||||
|
||||
''' MONTHLY CONTRIBUTION '''
|
||||
def getOrgPntFromRedis(self, org, date):
|
||||
keyCateg = 'CONTRIB_DAY'
|
||||
scoreSum = 0
|
||||
|
@ -74,8 +142,6 @@ class Contributor_helper:
|
|||
ptns = self.getOrgPntFromRedis(org, date)
|
||||
return self.getTrueRank(ptns)
|
||||
|
||||
def getOrgLogoFromRedis(self, org):
|
||||
return "{}/img/orgs/{}.png".format(self.misp_web_url, org)
|
||||
|
||||
def getLastContributorsFromRedis(self):
|
||||
date = datetime.datetime.now()
|
||||
|
@ -344,3 +410,50 @@ class Contributor_helper:
|
|||
def TEST_getAllOrgFromRedis(self):
|
||||
data2 = ['CIRCL', 'CASES', 'SMILE' ,'ORG4' ,'ORG5', 'SUPER HYPER LONG ORGINZATION NAME', 'Org3', 'MISP']
|
||||
return data2
|
||||
|
||||
def TEST_getCurrentOrgRankFromRedis(self, org):
|
||||
date = datetime.datetime.now()
|
||||
points = random.randint(1,2**self.levelMax)
|
||||
remainingPts = self.getRemainingPoints(points)
|
||||
data = {
|
||||
'org': org,
|
||||
'points': points,
|
||||
'rank': self.getRankLevel(points),
|
||||
'remainingPts': remainingPts['remainingPts'],
|
||||
'stepPts': remainingPts['stepPts'],
|
||||
}
|
||||
return data
|
||||
|
||||
def TEST_getCurrentContributionStatus(self, org):
|
||||
num = random.randint(1, self.org_rank_maxLevel)
|
||||
requirement_fulfilled = [x for x in range(1,num+1)]
|
||||
requirement_not_fulfilled = [x for x in range(num,self.org_rank_maxLevel+1-num)]
|
||||
|
||||
num2 = random.randint(1, self.org_rank_maxLevel)
|
||||
if num2 < num-1:
|
||||
to_swap = requirement_fulfilled[num2]
|
||||
del requirement_fulfilled[num2]
|
||||
requirement_not_fulfilled = [to_swap] + requirement_not_fulfilled
|
||||
|
||||
final_rank = len(requirement_fulfilled)
|
||||
to_ret = {}
|
||||
for i in range(1, self.org_rank_maxLevel+1):
|
||||
if i in requirement_fulfilled:
|
||||
to_ret[i] = 1
|
||||
elif i in requirement_not_fulfilled and i<=final_rank:
|
||||
to_ret[i] = 0
|
||||
else:
|
||||
to_ret[i] = -1
|
||||
return {'rank': final_rank, 'status': to_ret}
|
||||
|
||||
def TEST_getOrgHonorBadges(self, org):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
honorBadge = []
|
||||
for i in range(1, self.honorBadgeNum+1):
|
||||
key = keyname.format(org=org, orgCateg='BADGE_'+str(i))
|
||||
if random.randint(0,1) == 1: #existing
|
||||
honorBadge.append(1)
|
||||
else:
|
||||
honorBadge.append(0)
|
||||
print(honorBadge)
|
||||
return honorBadge
|
||||
|
|
18
server.py
18
server.py
|
@ -350,7 +350,23 @@ def getOrgRank():
|
|||
org = request.args.get('org')
|
||||
except:
|
||||
org = ''
|
||||
return jsonify(contributor_helper.getCurrentOrgRankFromRedis(org))
|
||||
return jsonify(contributor_helper.TEST_getCurrentOrgRankFromRedis(org))
|
||||
|
||||
@app.route("/_getContributionOrgStatus")
|
||||
def getContributionOrgStatus():
|
||||
try:
|
||||
org = request.args.get('org')
|
||||
except:
|
||||
org = ''
|
||||
return jsonify(contributor_helper.TEST_getCurrentContributionStatus(org))
|
||||
|
||||
@app.route("/_getHonorBadges")
|
||||
def getHonorBadges():
|
||||
try:
|
||||
org = request.args.get('org')
|
||||
except:
|
||||
org = ''
|
||||
return jsonify(contributor_helper.TEST_getOrgHonorBadges(org))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='localhost', port=8001, threaded=True)
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
border: 1px solid #caccce;
|
||||
}
|
||||
|
||||
.circlBadgeAcquired {
|
||||
box-shadow: 0px 0px 15px #0000ff
|
||||
}
|
||||
|
||||
.questionBadgeText {
|
||||
left: -15%;
|
||||
position: relative;
|
||||
|
|
|
@ -342,6 +342,41 @@ function updateProgressHeader(org) {
|
|||
if(this.data()[5] == data.org) { row.classList.add('selectedOrgInTable'); } else { row.classList.remove('selectedOrgInTable'); }
|
||||
});
|
||||
});
|
||||
|
||||
// colorize row contribution rank help
|
||||
$.getJSON( url_getContributionOrgStatus+'?org='+org, function( data ) {
|
||||
var status = data['status'];
|
||||
var curContributionOrgRank = data['rank'];
|
||||
if (curContributionOrgRank == 0) {
|
||||
$('#orgContributionRank').attr('data', '');
|
||||
} else {
|
||||
$('#orgContributionRank').attr('data', url_baseOrgRankLogo+curContributionOrgRank+'.svg');
|
||||
}
|
||||
for (var row of $('#bodyTablerankingModal')[0].children) {
|
||||
row = $(row);
|
||||
var rank = row.data('rank');
|
||||
if(status[rank] == 0){
|
||||
row.addClass("danger");
|
||||
} else if(status[rank] == 1) {
|
||||
row.addClass("success");
|
||||
} else {
|
||||
row.removeClass("success");
|
||||
row.removeClass("success");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.getJSON( url_getHonorBadges+'?org='+org, function( data ) {
|
||||
console.log(data);
|
||||
for(var i=0; i<data.length; i++) {
|
||||
console.log('#divBadge_'+(i+1));
|
||||
if (data[i] == 1) {
|
||||
$('#divBadge_'+(i+1)).addClass('circlBadgeAcquired');
|
||||
} else {
|
||||
$('#divBadge_'+(i+1)).removeClass('circlBadgeAcquired');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showOnlyOrg() {
|
||||
|
|
|
@ -96,9 +96,9 @@
|
|||
<th>Contribution requirement</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody id='bodyTablerankingModal'>
|
||||
{% for item in org_rank_list %}
|
||||
<tr>
|
||||
<tr data-rank={{ loop.index }}>
|
||||
<td style='padding: 0px; text-align: right;'><img height='35px' width='70px' style="margin-right: 20px;" src="{{ url_for('static', filename='pics/rankingMISPOrg/1.svg')[:-5]}}{{ item[0] }}.svg" type='image/svg' style="margin: auto;"</img></td>
|
||||
<td>{{ item[1] }}</td>
|
||||
<td>{{ item[2] }}</td>
|
||||
|
@ -121,7 +121,7 @@
|
|||
{% for item in org_honor_badge_title_list %}
|
||||
<tr style="height: 85px">
|
||||
<td>
|
||||
<div class="circleBadge">
|
||||
<div id="divBadge_{{ loop.index }}" class="circleBadge">
|
||||
<img height='64px' width='64px' style="margin-top: 5px;" src="{{ url_for('static', filename='pics/MISPHonorableIcons/1.svg')[:-5]}}{{ item[0] }}.svg" type='image/svg' style="margin: auto;"</img>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -171,6 +171,7 @@
|
|||
</div>
|
||||
<button type="button" class="questionBadgeDiv" data-toggle="modal" data-target="#myModal"><i class="fa fa-question-circle questionBadgeText"></i></button>
|
||||
<button id="btnCurrRank" class='btn btn-default popOverBtn' data-container='body' data-toggle='popover' style="display: none; margin-left: 20px;" onclick="showOnlyOrg()">
|
||||
<object id='orgContributionRank' height=32 width=64 class="centerInBtn"></object>
|
||||
<strong id="orgText" class="centerInBtn"></strong>
|
||||
<div id="orgRankDiv" class='textTopHeader' style="padding-top: 0px; position: relative; width: 40px; height: 40px;"></div>
|
||||
<div class='' style="float: left; padding: 10px;">
|
||||
|
@ -351,6 +352,8 @@
|
|||
var url_eventStreamLastContributor = "{{ url_for('getLastContributor') }}";
|
||||
var url_getAllOrg = "{{ url_for('getAllOrg') }}";
|
||||
var url_getOrgRank = "{{ url_for('getOrgRank') }}";
|
||||
var url_getContributionOrgStatus = "{{ url_for('getContributionOrgStatus') }}";
|
||||
var url_getHonorBadges = "{{ url_for('getHonorBadges') }}";
|
||||
var url_baseRankMonthlyLogo = "{{ url_for('static', filename='pics/rankingMISPMonthly/1.svg') }}";
|
||||
url_baseRankMonthlyLogo = url_baseRankMonthlyLogo.substring(0, url_baseRankMonthlyLogo.length-5);
|
||||
var url_baseOrgRankLogo = "{{ url_for('static', filename='pics/rankingMISPOrg/1.svg') }}";
|
||||
|
|
|
@ -26,6 +26,7 @@ CHANNELDISP = cfg.get('RedisMap', 'channelDisp')
|
|||
CHANNEL_PROC = cfg.get('RedisMap', 'channelProc')
|
||||
PATH_TO_DB = cfg.get('RedisMap', 'pathMaxMindDB')
|
||||
|
||||
|
||||
DEFAULT_PNTS_REWARD = cfg.get('CONTRIB', 'default_pnts_per_contribution')
|
||||
categories_in_datatable = json.loads(cfg.get('CONTRIB', 'categories_in_datatable'))
|
||||
DICO_PNTS_REWARD = {}
|
||||
|
@ -47,6 +48,8 @@ serv_redis_db = redis.StrictRedis(
|
|||
port=cfg.getint('RedisGlobal', 'port'),
|
||||
db=cfg.getint('RedisDB', 'db'))
|
||||
|
||||
contributor_helper = contributor_helper.Contributor_helper(serv_redis_db, cfg)
|
||||
|
||||
reader = geoip2.database.Reader(PATH_TO_DB)
|
||||
|
||||
def getDateStrFormat(date):
|
||||
|
@ -154,10 +157,11 @@ def updateOrgRank(orgName, pnts_to_add, contribType, eventTime, isClassified):
|
|||
#update total points
|
||||
serv_redis_db.set(keyname.format(org=orgName, orgCateg='points'), pnts_to_add)
|
||||
#update contribution Requirement
|
||||
heavilyCount = 10
|
||||
recentDays = 31
|
||||
regularlyDays = 7
|
||||
heavilyCount = contributor_helper.heavilyCount
|
||||
recentDays = contributor_helper.recentDays
|
||||
regularlyDays = contributor_helper.regularlyDays
|
||||
isRecent = True if (datetime.datetime.now() - eventTime).days > recentDays
|
||||
|
||||
contrib = [] #[[contrib_level, contrib_ttl], [], ...]
|
||||
if contribType == 'sighting':
|
||||
#[contrib_level, contrib_ttl]
|
||||
|
@ -189,7 +193,7 @@ def updateOrgRank(orgName, pnts_to_add, contribType, eventTime, isClassified):
|
|||
if contribType == 'event' and eventWeekCount>heavilyCount and isClassified:
|
||||
contrib.append([14, ONE_DAY*regularlyDays])
|
||||
|
||||
for rankReq, ttl:
|
||||
for rankReq, ttl in contrib:
|
||||
serv_redis_db.set(keyname.format(org=orgName, orgCateg='CONTRIB_REQ_'+str(rankReq)), 1)
|
||||
serv_redis_db.expire(keyname.format(org=orgName, orgCateg='CONTRIB_REQ_'+str(i)), ttl)
|
||||
|
||||
|
|
Loading…
Reference in New Issue