Started support of organisation trophies

pull/7/head
Sami Mokaddem 2017-11-13 12:57:05 +01:00
parent 1b9f9bd452
commit 0bc0683924
6 changed files with 185 additions and 6 deletions

View File

@ -65,6 +65,25 @@ regularlyDays=7
[HonorBadge] [HonorBadge]
1=Has made at least one pull request on the MISP project 1=Has made at least one pull request on the MISP project
2=Is a donator for 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] [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"] 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"]

View File

@ -22,6 +22,12 @@ class Contributor_helper:
for badgeNum in range(1, self.honorBadgeNum+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)) 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 #GLOBAL RANKING
self.org_rank_maxLevel = self.cfg_org_rank.getint('rankTitle', 'maxLevel') self.org_rank_maxLevel = self.cfg_org_rank.getint('rankTitle', 'maxLevel')
self.org_rank = {} self.org_rank = {}
@ -218,6 +224,17 @@ class Contributor_helper:
keyname = 'CONTRIB_ORG:{org}:{orgCateg}' keyname = 'CONTRIB_ORG:{org}:{orgCateg}'
self.serv_redis_db.delete(keyname.format(org=org, orgCateg='BADGE_'+str(badgeNum))) 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 ''' ''' MONTHLY CONTRIBUTION '''
def getOrgPntFromRedis(self, org, date): def getOrgPntFromRedis(self, org, date):
keyCateg = 'CONTRIB_DAY' keyCateg = 'CONTRIB_DAY'
@ -583,3 +600,12 @@ class Contributor_helper:
else: else:
honorBadge.append(0) honorBadge.append(0)
return honorBadge 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

View File

@ -149,7 +149,7 @@ def geo():
@app.route("/contrib") @app.route("/contrib")
def contrib(): def contrib():
categ_list = contributor_helper.categories_in_datatable 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] categ_list_points = [contributor_helper.DICO_PNTS_REWARD[categ] for categ in categ_list]
org_rank = contributor_helper.org_rank 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 = [ [num, text] for num, text in contributor_helper.org_honor_badge_title.items()]
org_honor_badge_title_list.sort(key=lambda x: x[0]) 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') currOrg = request.args.get('org')
if currOrg is None: if currOrg is None:
currOrg = "" currOrg = ""
@ -179,6 +183,10 @@ def contrib():
org_rank_additional_text=org_rank_additional_text, org_rank_additional_text=org_rank_additional_text,
org_honor_badge_title=json.dumps(org_honor_badge_title), org_honor_badge_title=json.dumps(org_honor_badge_title),
org_honor_badge_title_list=org_honor_badge_title_list, 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') min_between_reload=cfg.getint('CONTRIB', 'min_between_reload')
) )
@ -376,5 +384,13 @@ def getHonorBadges():
org = '' org = ''
return jsonify(contributor_helper.getOrgHonorBadges(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__': if __name__ == '__main__':
app.run(host='localhost', port=8001, threaded=True) app.run(host='localhost', port=8001, threaded=True)

View File

@ -3,6 +3,12 @@
height: auto; height: auto;
} }
tr > td > label > input.radioTrophy {
margin: auto;
margin-bottom: 5px;
display: block;
}
.successCell { .successCell {
background-color: #dff0d8 !important background-color: #dff0d8 !important
} }
@ -16,8 +22,24 @@
border: 1px solid #caccce; 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 { .circlBadgeAcquired {
box-shadow: 0px 0px 15px #0000ff /*box-shadow: 0px 0px 15px #0000ff*/
box-shadow: 0px 0px 3px #1b6a92, 0px 0px 10px #2fa1db;
} }
.questionBadgeText { .questionBadgeText {

View File

@ -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 //update overtake points
updateOvertakePnts(); updateOvertakePnts();
@ -565,6 +582,10 @@ $(document).ready(function() {
//FIXME: timeout used to wait that all datatables are draw. //FIXME: timeout used to wait that all datatables are draw.
setTimeout( function() { updateProgressHeader(currOrg); }, 500); 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 = new EventSource(url_eventStreamLastContributor);
source_lastContrib.onmessage = function(event) { source_lastContrib.onmessage = function(event) {
var json = jQuery.parseJSON( event.data ); var json = jQuery.parseJSON( event.data );

View File

@ -46,8 +46,8 @@
</head> </head>
<body> <body>
<!-- Modal --> <!-- Modal Rank -->
<div id="myModal" class="modal fade" role="dialog"> <div id="myModalRank" class="modal fade" role="dialog">
<div class="modal-dialog modal-lg" style="width: 1500px;"> <div class="modal-dialog modal-lg" style="width: 1500px;">
<!-- Modal content--> <!-- Modal content-->
@ -159,10 +159,78 @@
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div> </div>
</div> </div>
</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">&times;</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"> <div id="wrapper">
<!-- Navigation --> <!-- Navigation -->
@ -190,7 +258,8 @@
<div class='textTopHeader' style="padding-top: 9px;"> <div class='textTopHeader' style="padding-top: 9px;">
<input type="text" id="orgName" data-provide="typeahead" size="20" style="margin-bottom: 5px;"> <input type="text" id="orgName" data-provide="typeahead" size="20" style="margin-bottom: 5px;">
</div> </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()"> <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> <object id='orgContributionRank' height=32 width=64 class="centerInBtn"></object>
<strong id="orgText" class="centerInBtn"></strong> <strong id="orgText" class="centerInBtn"></strong>
@ -384,12 +453,16 @@
var url_getOrgRank = "{{ url_for('getOrgRank') }}"; var url_getOrgRank = "{{ url_for('getOrgRank') }}";
var url_getContributionOrgStatus = "{{ url_for('getContributionOrgStatus') }}"; var url_getContributionOrgStatus = "{{ url_for('getContributionOrgStatus') }}";
var url_getHonorBadges = "{{ url_for('getHonorBadges') }}"; var url_getHonorBadges = "{{ url_for('getHonorBadges') }}";
var url_getTrophies = "{{ url_for('getTrophies')}}"
var url_baseRankMonthlyLogo = "{{ url_for('static', filename='pics/rankingMISPMonthly/1.svg') }}"; var url_baseRankMonthlyLogo = "{{ url_for('static', filename='pics/rankingMISPMonthly/1.svg') }}";
url_baseRankMonthlyLogo = url_baseRankMonthlyLogo.substring(0, url_baseRankMonthlyLogo.length-5); url_baseRankMonthlyLogo = url_baseRankMonthlyLogo.substring(0, url_baseRankMonthlyLogo.length-5);
var url_baseOrgRankLogo = "{{ url_for('static', filename='pics/rankingMISPOrg/1.svg') }}"; var url_baseOrgRankLogo = "{{ url_for('static', filename='pics/rankingMISPOrg/1.svg') }}";
url_baseOrgRankLogo = url_baseOrgRankLogo.substring(0, url_baseOrgRankLogo.length-5); url_baseOrgRankLogo = url_baseOrgRankLogo.substring(0, url_baseOrgRankLogo.length-5);
var url_baseHonorLogo = "{{ url_for('static', filename='pics/MISPHonorableIcons/1.svg') }}"; var url_baseHonorLogo = "{{ url_for('static', filename='pics/MISPHonorableIcons/1.svg') }}";
url_baseHonorLogo = url_baseHonorLogo.substring(0, url_baseHonorLogo.length-5); 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 */ /* DATA FROM CONF */
var currOrg = "{{ currOrg }}"; var currOrg = "{{ currOrg }}";
@ -399,6 +472,8 @@
var org_rank_obj = JSON.parse('{{ org_rank_json|safe }}'); var org_rank_obj = JSON.parse('{{ org_rank_json|safe }}');
var org_honor_badge_title = JSON.parse('{{ org_honor_badge_title|safe }}'); var org_honor_badge_title = JSON.parse('{{ org_honor_badge_title|safe }}');
var numberOfBadges = {{ org_honor_badge_title_list|length }}; 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>
<script src="{{ url_for('static', filename='js/contrib.js') }}"></script> <script src="{{ url_for('static', filename='js/contrib.js') }}"></script>