mirror of https://github.com/MISP/misp-dashboard
Started support of organisation trophies
parent
1b9f9bd452
commit
0bc0683924
|
@ -65,6 +65,25 @@ regularlyDays=7
|
|||
[HonorBadge]
|
||||
1=Has made at least one pull request on the MISP project
|
||||
2=Is a donator for the MISP project
|
||||
3=Has published content upvoted by the community
|
||||
4=Has published valuable content for the community
|
||||
5=Has published loads of valuable content for the community
|
||||
|
||||
[HonorTrophy]
|
||||
0=No trophy
|
||||
1=Novice
|
||||
2=Beginner
|
||||
3=Intermediate
|
||||
4=Competent
|
||||
5=Experienced
|
||||
6=Talented
|
||||
7=Skilled
|
||||
8=Advanced
|
||||
9=Expert
|
||||
10=Master
|
||||
|
||||
[HonorTrophyCateg]
|
||||
categ=["internal_reference", "targeting_data", "antivirus_detection", "payload_delivery", "artifacts_dropped", "payload_installation", "persistence_mechanism", "network_activity", "payload_type", "attribution", "external_analysis", "financial_fraud", "support_Tool", "social_network", "person", "other" ]
|
||||
|
||||
[additionalInfo]
|
||||
textsArray=["Proposals means either edition, acceptation or rejection", "Recent events means event aged of one month at max", "Regularly means at least one per week" ,"Heavily means at least 10 per week", "Classification means correct tagging", "The contribution rank is set such that it equals to: rank=requirement_fulfilled-requirement_not_fulfilled"]
|
||||
|
|
|
@ -22,6 +22,12 @@ class Contributor_helper:
|
|||
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))
|
||||
|
||||
self.trophyNum = len(self.cfg_org_rank.options('HonorTrophyCateg'))
|
||||
self.categories_in_trophy = json.loads(self.cfg_org_rank.get('HonorTrophyCateg', 'categ'))
|
||||
self.trophy_title = {}
|
||||
for trophyNum in range(0, len(self.cfg_org_rank.options('HonorTrophy'))): #get Num of trophy
|
||||
self.trophy_title[trophyNum] = self.cfg_org_rank.get('HonorTrophy', str(trophyNum))
|
||||
|
||||
#GLOBAL RANKING
|
||||
self.org_rank_maxLevel = self.cfg_org_rank.getint('rankTitle', 'maxLevel')
|
||||
self.org_rank = {}
|
||||
|
@ -218,6 +224,17 @@ class Contributor_helper:
|
|||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
self.serv_redis_db.delete(keyname.format(org=org, orgCateg='BADGE_'+str(badgeNum)))
|
||||
|
||||
''' TROPHIES '''
|
||||
def getOrgTrophies(self, org):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
trophy = []
|
||||
for i in range(1, self.trophyNum+1):
|
||||
key = keyname.format(org=org, orgCateg='TROPHY_'+str(i))
|
||||
trophy_Pnts = self.serv_redis_db.get(key)
|
||||
if trophy_Pnts is not None: #existing
|
||||
trophy.append(trophy_Pnts)
|
||||
return trophy
|
||||
|
||||
''' MONTHLY CONTRIBUTION '''
|
||||
def getOrgPntFromRedis(self, org, date):
|
||||
keyCateg = 'CONTRIB_DAY'
|
||||
|
@ -583,3 +600,12 @@ class Contributor_helper:
|
|||
else:
|
||||
honorBadge.append(0)
|
||||
return honorBadge
|
||||
|
||||
def TEST_getOrgTrophies(self, org):
|
||||
keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
|
||||
trophy = []
|
||||
for categ in self.categories_in_trophy:
|
||||
key = keyname.format(org=org, orgCateg='TROPHY_'+categ)
|
||||
trophy_Pnts = random.randint(0,10)
|
||||
trophy.append({'categName': categ, 'rank': trophy_Pnts})
|
||||
return trophy
|
||||
|
|
18
server.py
18
server.py
|
@ -149,7 +149,7 @@ def geo():
|
|||
@app.route("/contrib")
|
||||
def contrib():
|
||||
categ_list = contributor_helper.categories_in_datatable
|
||||
categ_list_str = [ s[0].upper() + s[1:].replace('_', ' ') for s in contributor_helper.categories_in_datatable]
|
||||
categ_list_str = [ s[0].upper() + s[1:].replace('_', ' ') for s in categ_list]
|
||||
categ_list_points = [contributor_helper.DICO_PNTS_REWARD[categ] for categ in categ_list]
|
||||
|
||||
org_rank = contributor_helper.org_rank
|
||||
|
@ -163,6 +163,10 @@ def contrib():
|
|||
org_honor_badge_title_list = [ [num, text] for num, text in contributor_helper.org_honor_badge_title.items()]
|
||||
org_honor_badge_title_list.sort(key=lambda x: x[0])
|
||||
|
||||
trophy_categ_list = contributor_helper.categories_in_trophy
|
||||
trophy_categ_list_str = [ s[0].upper() + s[1:].replace('_', ' ') for s in trophy_categ_list]
|
||||
trophy_title = contributor_helper.trophy_title
|
||||
|
||||
currOrg = request.args.get('org')
|
||||
if currOrg is None:
|
||||
currOrg = ""
|
||||
|
@ -179,6 +183,10 @@ def contrib():
|
|||
org_rank_additional_text=org_rank_additional_text,
|
||||
org_honor_badge_title=json.dumps(org_honor_badge_title),
|
||||
org_honor_badge_title_list=org_honor_badge_title_list,
|
||||
trophy_categ_list=json.dumps(trophy_categ_list),
|
||||
trophy_categ_list_id=trophy_categ_list,
|
||||
trophy_categ_list_str=trophy_categ_list_str,
|
||||
trophy_title=json.dumps(trophy_title),
|
||||
min_between_reload=cfg.getint('CONTRIB', 'min_between_reload')
|
||||
)
|
||||
|
||||
|
@ -376,5 +384,13 @@ def getHonorBadges():
|
|||
org = ''
|
||||
return jsonify(contributor_helper.getOrgHonorBadges(org))
|
||||
|
||||
@app.route("/_getTrophies")
|
||||
def getTrophies():
|
||||
try:
|
||||
org = request.args.get('org')
|
||||
except:
|
||||
org = ''
|
||||
return jsonify(contributor_helper.TEST_getOrgTrophies(org))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='localhost', port=8001, threaded=True)
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
height: auto;
|
||||
}
|
||||
|
||||
tr > td > label > input.radioTrophy {
|
||||
margin: auto;
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.successCell {
|
||||
background-color: #dff0d8 !important
|
||||
}
|
||||
|
@ -16,8 +22,24 @@
|
|||
border: 1px solid #caccce;
|
||||
}
|
||||
|
||||
.circleBadgeSmall {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
border-radius: 25px;
|
||||
background-color: #e1e1e1;
|
||||
border: 1px solid #caccce;
|
||||
vertical-align: middle;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
||||
.grayscale { filter: grayscale(100%); }
|
||||
|
||||
.circlBadgeAcquired {
|
||||
box-shadow: 0px 0px 15px #0000ff
|
||||
/*box-shadow: 0px 0px 15px #0000ff*/
|
||||
box-shadow: 0px 0px 3px #1b6a92, 0px 0px 10px #2fa1db;
|
||||
}
|
||||
|
||||
.questionBadgeText {
|
||||
|
|
|
@ -452,6 +452,23 @@ function updateProgressHeader(org) {
|
|||
}
|
||||
});
|
||||
|
||||
// set trophies if acquired
|
||||
$.getJSON( url_getTrophies+'?org='+org, function( data ) {
|
||||
var source = url_baseTrophyLogo+0+'.png'
|
||||
for(var i=0; i<trophy_categ_list.length; i++) { // remove
|
||||
categ = trophy_categ_list[i];
|
||||
$('#trophy_'+categ).attr('src', source);
|
||||
$('#trophy_'+categ).attr('title', "");
|
||||
}
|
||||
for(var i=0; i<data.length; i++) { // add
|
||||
categ = data[i].categName;
|
||||
rank = data[i].rank;
|
||||
source = url_baseTrophyLogo+rank+'.png'
|
||||
$('#trophy_'+categ).attr('src', source);
|
||||
$('#trophy_'+categ).attr('title', trophy_title[rank]);
|
||||
}
|
||||
});
|
||||
|
||||
//update overtake points
|
||||
updateOvertakePnts();
|
||||
|
||||
|
@ -565,6 +582,10 @@ $(document).ready(function() {
|
|||
//FIXME: timeout used to wait that all datatables are draw.
|
||||
setTimeout( function() { updateProgressHeader(currOrg); }, 500);
|
||||
|
||||
$('#trophyForm input').on('change', function() {
|
||||
alert($('input[name=radioTrophyName]:checked', '#trophyForm').val());
|
||||
});
|
||||
|
||||
source_lastContrib = new EventSource(url_eventStreamLastContributor);
|
||||
source_lastContrib.onmessage = function(event) {
|
||||
var json = jQuery.parseJSON( event.data );
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Modal -->
|
||||
<div id="myModal" class="modal fade" role="dialog">
|
||||
<!-- Modal Rank -->
|
||||
<div id="myModalRank" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog modal-lg" style="width: 1500px;">
|
||||
|
||||
<!-- Modal content-->
|
||||
|
@ -159,10 +159,78 @@
|
|||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal trophy -->
|
||||
<div id="myModalTrophy" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog modal-lg" style="width: 1500px;">
|
||||
<!-- Modal content-->
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" style="float: left;">Trophies and badges</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h4>Badges:</h4>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Badge</th>
|
||||
<th>Requirement</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id='bodyTableBadgeModal'>
|
||||
{% for item in org_honor_badge_title_list %}
|
||||
<tr>
|
||||
<td>
|
||||
<div id="divBadge_{{ loop.index }}" class="circleBadgeSmall circlBadgeAcquired">
|
||||
<img height='32px' width='32px' class="" style="margin-top: 3px;" src="{{ url_for('static', filename='pics/MISPHonorableIcons/1.svg')[:-5]}}{{ item[0] }}.svg" type='image/svg' style="margin: auto;"</img>
|
||||
</div>
|
||||
</td>
|
||||
<td style="padding-left: 15px;">{{ item[1] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p style="font-size: 18px; display: inline;">Trophies: </p><p style="display: inline;">Shows your skills in information sharing </p><i> (earned via upvotes or sightings from other organisation)</i>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for categ in trophy_categ_list_str %}
|
||||
<th>{{ categ }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id='bodyTableTrophyModal'>
|
||||
<form id="trophyForm">
|
||||
<tr>
|
||||
{% for categ in trophy_categ_list_id %}
|
||||
<td>
|
||||
<label style="cursor: pointer; display: block; margin-left: auto; margin-right: auto;">
|
||||
<input class="radioTrophy" type="radio" name="radioTrophyName" value="{{categ}}"/>
|
||||
<img id='trophy_{{categ}}' style="display: block; margin-left: auto; margin-right: auto;" height="64" width="64" src="{{ url_for('static', filename='pics/MISPTrophy/0.png') }}" type='image/png'>
|
||||
</label>
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</from>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="wrapper">
|
||||
|
||||
<!-- Navigation -->
|
||||
|
@ -190,7 +258,8 @@
|
|||
<div class='textTopHeader' style="padding-top: 9px;">
|
||||
<input type="text" id="orgName" data-provide="typeahead" size="20" style="margin-bottom: 5px;">
|
||||
</div>
|
||||
<button type="button" class="questionBadgeDiv fa fa-question-circle" data-toggle="modal" data-target="#myModal"></button>
|
||||
<button type="button" class="questionBadgeDiv fa fa-question-circle" title="Ranking information" data-toggle="modal" data-target="#myModalRank"></button>
|
||||
<button type="button" class="questionBadgeDiv fa fa-trophy" title="Trophies and badges" data-toggle="modal" data-target="#myModalTrophy"></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>
|
||||
|
@ -384,12 +453,16 @@
|
|||
var url_getOrgRank = "{{ url_for('getOrgRank') }}";
|
||||
var url_getContributionOrgStatus = "{{ url_for('getContributionOrgStatus') }}";
|
||||
var url_getHonorBadges = "{{ url_for('getHonorBadges') }}";
|
||||
var url_getTrophies = "{{ url_for('getTrophies')}}"
|
||||
|
||||
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') }}";
|
||||
url_baseOrgRankLogo = url_baseOrgRankLogo.substring(0, url_baseOrgRankLogo.length-5);
|
||||
var url_baseHonorLogo = "{{ url_for('static', filename='pics/MISPHonorableIcons/1.svg') }}";
|
||||
url_baseHonorLogo = url_baseHonorLogo.substring(0, url_baseHonorLogo.length-5);
|
||||
var url_baseTrophyLogo = "{{ url_for('static', filename='pics/MISPTrophy/1.png') }}";
|
||||
url_baseTrophyLogo = url_baseTrophyLogo.substring(0, url_baseTrophyLogo.length-5);
|
||||
|
||||
/* DATA FROM CONF */
|
||||
var currOrg = "{{ currOrg }}";
|
||||
|
@ -399,6 +472,8 @@
|
|||
var org_rank_obj = JSON.parse('{{ org_rank_json|safe }}');
|
||||
var org_honor_badge_title = JSON.parse('{{ org_honor_badge_title|safe }}');
|
||||
var numberOfBadges = {{ org_honor_badge_title_list|length }};
|
||||
var trophy_categ_list = JSON.parse('{{ trophy_categ_list|safe }}');
|
||||
var trophy_title = JSON.parse('{{ trophy_title|safe }}');
|
||||
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/contrib.js') }}"></script>
|
||||
|
|
Loading…
Reference in New Issue