From c1105aba73c42e3358a4ce310211fed439d9b3cb Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Wed, 15 Nov 2017 09:36:44 +0100 Subject: [PATCH] Added login overtime + users_helper script --- server.py | 40 ++++++------------ templates/users.html | 96 +++++++++++++++++++++++++++++++++++--------- users_helper.py | 73 +++++++++++++++++++++++++++++++++ util.py | 13 +++++- zmq_subscriber.py | 8 ++-- 5 files changed, 177 insertions(+), 53 deletions(-) create mode 100644 users_helper.py diff --git a/server.py b/server.py index 9999d37..a45f663 100755 --- a/server.py +++ b/server.py @@ -11,6 +11,7 @@ import os import util import contributor_helper +import users_helper configfile = os.path.join(os.environ['DASH_CONFIG'], 'config.cfg') cfg = configparser.ConfigParser() @@ -32,6 +33,7 @@ serv_redis_db = redis.StrictRedis( db=cfg.getint('RedisDB', 'db')) contributor_helper = contributor_helper.Contributor_helper(serv_redis_db, cfg) +users_helper = users_helper.Users_helper(serv_redis_db, cfg) subscriber_log = redis_server_log.pubsub(ignore_subscribe_messages=True) subscriber_log.psubscribe(cfg.get('RedisLog', 'channel')) @@ -206,35 +208,17 @@ def getUserLogins(): except: date = datetime.datetime.now() - keyname = "USER_LOGIN:{}" - prev_days = 6 - week = {} - for curDate in util.getXPrevDaysSpan(date, prev_days): - timestamps = serv_redis_db.smembers(keyname.format(util.getDateStrFormat(curDate))) - timestamps = [int(timestamp.decode('utf8')) for timestamp in timestamps] - day = {} - for timestamp in timestamps: - date = datetime.datetime.fromtimestamp(float(timestamp)) - if date.hour not in day: - day[date.hour] = 0 - day[date.hour] += 1 - week[curDate.weekday()] = day + data = users_helper.getUserLoginsForPunchCard(date) + return jsonify(data) - # Format data - data = [] - for d in range(7): - try: - to_append = [] - for h in range(24): - try: - to_append.append(week[d][h]) - except KeyError: - to_append.append(0) - # swap 24 and 1. (punchcard starts at 1h) - temp = to_append[1:]+[to_append[0]] - data.append(temp) - except KeyError: - data.append([0 for x in range(24)]) +@app.route("/_getUserLoginsOvertime") +def getUserLoginsOvertime(): + try: + date = datetime.datetime.fromtimestamp(float(request.args.get('date'))) + except: + date = datetime.datetime.now() + + data = users_helper.getUserLoginsOvertime(date) return jsonify(data) ''' INDEX ''' diff --git a/templates/users.html b/templates/users.html index 7779528..bd6345f 100644 --- a/templates/users.html +++ b/templates/users.html @@ -24,6 +24,7 @@ + @@ -104,29 +105,50 @@ small {
-
-
-
- Punch card - login -
-
-
-
-
-
+
+
+
+
+ Punch card - login +
+
+
+
+
+
-
-
-
- Contribution after login (API vs non-API) -
-
-
-
-
-
+
+
+
+ Top login per organisation +
+
+
+
+
+ +
+
+ Contribution after login (API vs non-API) +
+
+
+
+
+
+
+
+
+ Login overtime +
+
+
+
+
+
+
@@ -178,6 +200,40 @@ small { }); }); + $.getJSON( "{{ url_for('getUserLogins') }}", function( data ) { + data = [{label: 'org1', data:[ Math.floor(Math.random() * 100) + 1]}, + {label: 'org2', data:[ Math.floor(Math.random() * 100) + 1]}, + {label: 'org3', data:[ Math.floor(Math.random() * 100) + 1]}] + $.plot('#barChart', data, { + series: { + pie: { + innerRadius: 0.5, + show: true + } + } + }); + }); + + $.getJSON( "{{ url_for('getUserLoginsOvertime') }}", function( data ) { + temp = []; + var i=0; + for (item of data) { + temp.push([new Date(item[0]*1000), item[1]]); + } + console.log(temp); + data = {label: 'Login overtime', data: temp} + $.plot('#lineChart', [data], { + lines: { + show: true, + steps: true, + fill: true + }, + xaxis: { + mode: "time", + minTickSize: [1, "hour"], + } + }); + }); }); diff --git a/users_helper.py b/users_helper.py new file mode 100644 index 0000000..caf4914 --- /dev/null +++ b/users_helper.py @@ -0,0 +1,73 @@ +import math, random +import os +import json +import datetime, time + +import util + +class Users_helper: + def __init__(self, serv_redis_db, cfg): + self.serv_redis_db = serv_redis_db + self.cfg = cfg + + def add_user_login(self, timestamp): + timestampDate = datetime.datetime.fromtimestamp(float(timestamp)) + timestampDate_str = util.getDateStrFormat(timestampDate) + keyname = "{}:{}".format('USER_LOGIN', timestampDate_str) + self.serv_redis_db.sadd(keyname, timestamp) + + def getUserLogins(self, date): + keyname = "USER_LOGIN:{}" + timestamps = self.serv_redis_db.smembers(keyname.format(util.getDateStrFormat(date))) + timestamps = [int(timestamp.decode('utf8')) for timestamp in timestamps] + return timestamps + + def getUserLoginsForPunchCard(self, date, prev_days=6): + week = {} + for curDate in util.getXPrevDaysSpan(date, prev_days): + timestamps = self.getUserLogins(curDate) + day = {} + for timestamp in timestamps: + date = datetime.datetime.fromtimestamp(float(timestamp)) + if date.hour not in day: + day[date.hour] = 0 + day[date.hour] += 1 + week[curDate.weekday()] = day + + # Format data + data = [] + for d in range(7): + try: + to_append = [] + for h in range(24): + try: + to_append.append(week[d][h]) + except KeyError: + to_append.append(0) + # swap 24 and 1. (punchcard starts at 1h) + temp = to_append[1:]+[to_append[0]] + data.append(temp) + except KeyError: # no data + data.append([0 for x in range(24)]) + + return data + + def getUserLoginsOvertime(self, date, prev_days=6): + dico_hours = {} + for curDate in util.getXPrevHoursSpan(date, prev_days*24): + dico_hours[util.getTimestamp(curDate)] = 0 # populate with empty data + + for curDate in util.getXPrevDaysSpan(date, prev_days): + timestamps = self.getUserLogins(curDate) + for timestamp in timestamps: # sum occurence during the current hour + date = datetime.datetime.fromtimestamp(float(timestamp)) + date = date.replace(minute=0, second=0, microsecond=0) + dico_hours[util.getTimestamp(date)] += 1 + + # Format data + data = [] + for date, occ in dico_hours.items(): + data.append([date, occ]) + + data.sort(key=lambda x: x[0]) + return data diff --git a/util.py b/util.py index 8518554..535480e 100644 --- a/util.py +++ b/util.py @@ -24,8 +24,19 @@ def getXPrevDaysSpan(date, days): to_return.append(de - datetime.timedelta(days=i)) return to_return +def getXPrevHoursSpan(date, hours): + de = date + de = de.replace(minute=0, second=0, microsecond=0) + ds = de - datetime.timedelta(hours=hours) + + delta = de - ds + to_return = [] + for i in range(0, int(delta.total_seconds()/3600)+1): + to_return.append(de - datetime.timedelta(hours=i)) + return to_return + def getDateStrFormat(date): return str(date.year)+str(date.month).zfill(2)+str(date.day).zfill(2) def getTimestamp(date): - return time.mktime(date.timetuple()) + return int(time.mktime(date.timetuple())) diff --git a/zmq_subscriber.py b/zmq_subscriber.py index 263a977..4369814 100755 --- a/zmq_subscriber.py +++ b/zmq_subscriber.py @@ -16,6 +16,7 @@ import geoip2.database import util import contributor_helper +import users_helper configfile = os.path.join(os.environ['DASH_CONFIG'], 'config.cfg') cfg = configparser.ConfigParser() @@ -53,6 +54,7 @@ serv_redis_db = redis.StrictRedis( db=cfg.getint('RedisDB', 'db')) contributor_helper = contributor_helper.Contributor_helper(serv_redis_db, cfg) +users_helper = users_helper.Users_helper(serv_redis_db, cfg) reader = geoip2.database.Reader(PATH_TO_DB) @@ -194,10 +196,8 @@ def handler_user(zmq_name, jsondata): timestamp = json_user['current_login'] except KeyError: return - now = datetime.datetime.now() - today_str = util.getDateStrFormat(now) - keyname = "{}:{}".format('USER_LOGIN', today_str) - serv_redis_db.sadd(keyname, timestamp) + if timestamp != 0: # "invited_by": "xxxx" ??? + users_helper.add_user_login(timestamp) def handler_conversation(zmq_name, jsonevent): try: #only consider POST, not THREAD