diff --git a/Page-tracking-extension/content.js b/Page-tracking-extension/content.js index 52f613e..e1ba5a4 100644 --- a/Page-tracking-extension/content.js +++ b/Page-tracking-extension/content.js @@ -7,38 +7,37 @@ $(document).ready(function() { var end; var time_spent; - window.addEventListener('focus', function() { - start = Date.now(); - }); - + // $(window).on('focus', function() { + start = Date.now(); + // }); console.log("start = ", start) - - $(window).on('blur', function() { - end = new Date().getTime(); - }); - - console.log("end = ", end); - time_spent = end - start; - console.log(time_spent/1000) + $(window).on('blur', function() { + end = Date.now(); + console.log("end = ", end); + time_spent = (end - start)/1000; + console.log("time_spent = ", time_spent); + + var evtData = { + "userId": user_id, + "evt_type": "Time Spent", + "pageHTML": document.URL, + "object_id": 0, + "evt_datetime": time_spent, + "evt_timestamp": Date.now() + }; + console.log(evtData); - var evtData = { - "userId": user_id, - "evt_type": "Time Spent", - "pageHTML": document.URL, - "object_id": 0, - "evt_datetime": (time_spent/1000).toString() - }; - - // console.log(evtData); - // Sending data to background.js - chrome.runtime.sendMessage({'evtData': evtData, 'quesData': null}, function(response) { - // console.log(response.BgResponse); + // Sending data to background.js + chrome.runtime.sendMessage({'evtData': evtData, 'quesData': null}, function(response) { + // console.log(response.BgResponse); + }); }); }); + // Question click event handler $(document).ready(function(evt) { var ques_id = document.URL.split('/')[4]; @@ -53,7 +52,8 @@ $(document).ready(function(evt) { "evt_type": "Visited", "pageHTML": document.URL, "object_id": ques_id, - "evt_datetime": date + ' ' + time + "evt_datetime": date + ' ' + time, + "evt_timestamp": Date.now() }; var tagListChildren = document.getElementsByClassName("post-taglist")[0].children; @@ -79,7 +79,6 @@ $(document).ready(function(evt) { "Tags": tags }; - // Sending data to background.js chrome.runtime.sendMessage({'evtData': evtData, 'quesData': quesData}, function(response) { // console.log(response.BgResponse); }); @@ -101,7 +100,8 @@ $('#submit-button').on('click', function() { "evt_type": "Posted Answer to", "pageHTML": document.URL, "object_id": ques_id, - "evt_datetime": date + ' ' + time + "evt_datetime": date + ' ' + time, + "evt_timestamp": Date.now() }; var tagListChildren = document.getElementsByClassName("post-taglist")[0].children; @@ -121,35 +121,32 @@ $('#submit-button').on('click', function() { "object_id": ques_id, "pageHTML": document.URL, "votes": $(".vote-count-post")[0].innerHTML, - "answers": answers, - "views": parseInt($(".label-key")[3].childNodes[1].innerHTML.split(' ')[0].split(',').join('')), + "answers": answers, "views": parseInt($(".label-key")[3].childNodes[1].innerHTML.split(' ')[0].split(',').join('')), "DateTime": $(".label-key")[1].getAttribute("title"), "Tags": tags }; + + chrome.runtime.sendMessage({'evtData': evtData, 'quesData': quesData}, function(response) { + // console.log(response.BgResponse); + }); - // var ansData = { - // "question_id": ques_id, - // "pageHTML": document.URL, - // "content": $('#wmd-preview').eq(0).text(), - // "DateTime": Date.now() - // }; - - // Check for errors and send the data - if($('.wmd-input processed validation-error').length == 0 && $('.message-text').length == 0) { - // Sending data to background.js - console.log("Sending the data"); - chrome.runtime.sendMessage({'evtData': evtData, 'quesData': quesData}, function(response) { - // console.log(response.BgResponse); - }); - } - else { - console.log("Did not send the data"); - } + // Tried to actually send data only after the constraints are removed. But facing problem to check the updated HTML after + // the answer validation is done + // if($('.wmd-input processed validation-error').length == 0 && $('.message-text').length == 0) { + // Sending data to background.js + // console.log("Sending the data"); + // chrome.runtime.sendMessage({'evtData': evtData, 'quesData': quesData}, function(response) { + // // console.log(response.BgResponse); + // }); + // } + // else { + // console.log("Did not send the data"); + // } }); // Share the question tracking -$('.short-link').eq(0).on('click', function() { +$('.short-link').on('click', function() { // console.log("share question"); var ques_id = document.URL.split('/')[4]; @@ -161,10 +158,11 @@ $('.short-link').eq(0).on('click', function() { var evtData = { "userId": user_id, - "evt_type": "Shared Question", + "evt_type": "Shared", "pageHTML": document.URL, - "object_id": ques_id, - "evt_datetime": date + ' ' + time + "object_id": this.getAttribute('href').split('/')[2], + "evt_datetime": date + ' ' + time, + "evt_timestamp": Date.now() }; // Question details @@ -181,7 +179,7 @@ $('.short-link').eq(0).on('click', function() { answers = $(".subheader.answers-subheader")[0].childNodes[1].childNodes[1].innerHTML; var quesData = { - "object_type": "Question", + "object_type": "Q/A", "object_id": ques_id, "pageHTML": document.URL, "votes": $(".vote-count-post")[0].innerHTML, @@ -211,11 +209,10 @@ $(".vote-up-off").on('click', function() { "evt_type": "UpVoted", "pageHTML": document.URL, "object_id": this.previousElementSibling.getAttribute('value'), - "evt_datetime": date + ' ' + time + "evt_datetime": date + ' ' + time, + "evt_timestamp": Date.now() }; - console.log(evtData); - // Sending data to background.js chrome.runtime.sendMessage({'evtData': evtData, 'quesData': null}, function(response) { // console.log(response.BgResponse); }); @@ -236,85 +233,34 @@ $(".vote-down-off").on('click', function() { "evt_type": "DownVoted", "pageHTML": document.URL, "object_id": this.previousElementSibling.previousElementSibling.previousElementSibling.getAttribute('value'), - "evt_datetime": date + ' ' + time + "evt_datetime": date + ' ' + time, + "evt_timestamp": Date.now() }; - console.log(evtData); - // Sending data to background.js chrome.runtime.sendMessage({'evtData': evtData, 'quesData': null}, function(response) { // console.log(response.BgResponse); }); }); - -// // Adding a comment -// var $addCommentLinks = $('.js-add-link.comments-link.disabled-link') - -// for(var i=0; i < $addCommentLinks.length; i++) { - -// // console.log($('#answer-218390').eq(i).find('span.relativetime').eq(0).attr('title')); - -// $addCommentLinks.eq(i).on('click', function() { - -// console.log($addCommentLinks.eq(i)); - -// // var DOMAnswer_id = "#answer-" + ans_id; -// // console.log($(DOMAnswer_id).eq(i).find('span.vote-count-post').eq(0)); - -// // var ques_id = document.URL.split('/')[4]; -// // var user_id = "dummy"; - -// // var evtData = { -// // "userId": user_id, -// // "evt_type": "Add Comment", -// // "pageHTML": document.URL, -// // "question_id": ques_id, -// // "evt_datetime": Date.now() -// // }; - -// // var tags = null - -// // var quesData = { -// // "object_type": "Answer", -// // "object_id": ans_id, -// // "pageHTML": document.URL, -// // "votes": $(DOMAnswer_id).eq(i).find('span.vote-count-post').eq(0).text, -// // "answers": 0, -// // "views": null, -// // "DateTime": $(DOMAnswer_id).eq(i).find('span.relativetime').eq(0).attr('title'), -// // "Tags": tags -// // }; - -// // console.log(quesData); -// }); -// } - -// var addCommentEventHandler = function(ans_id) { +console.log($('.btn')); +$('.btn').on('click', function() { + var ques_id = document.URL.split('/')[4]; + var user_id = "dummy"; -// var ques_id = document.URL.split('/')[4]; -// var user_id = "dummy"; -// var DOMAnswer_id = "#answer-" + ans_id; - -// var evtData = { -// "userId": user_id, -// "evt_type": "Add Comment", -// "pageHTML": document.URL, -// "question_id": ques_id, -// "evt_datetime": Date.now() -// }; - -// var tags = null - -// var quesData = { -// "object_type": "Answer", -// "object_id": ans_id, -// "pageHTML": document.URL, -// "votes": $(DOMAnswer_id).eq(0).find('span.vote-count-post')[0].innerHTML, -// "answers": 0, -// "views": null, -// "DateTime": $(DOMAnswer_id).eq(0).find('span.relativetime').eq(0).attr('title'), -// "Tags": tags -// }; - -// console.log(quesData); -// } + var today = new Date(); + var date = (today.getMonth() + 1) + '-' + (today.getDate()) + '-' + today.getFullYear(); + var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds(); + + var evtData = { + "userId": user_id, + "evt_type": "Asked Question", + "pageHTML": document.URL, + "object_id": 0, + "evt_datetime": date + ' ' + time, + "evt_timestamp": Date.now() + }; + console.log(evtData); + chrome.runtime.sendMessage({'evtData': evtData, 'quesData': null}, function(response) { + // console.log(response.BgResponse); + }); +}); diff --git a/Page-tracking-extension/popup.html b/Page-tracking-extension/popup.html index 82c6048..9e79d5a 100644 --- a/Page-tracking-extension/popup.html +++ b/Page-tracking-extension/popup.html @@ -1,12 +1,12 @@ - GTmetrix Analyzer + Behavioral Logging -

GTmetrix Analyzer

+

Behavioral Logging

\ No newline at end of file diff --git a/UserTracking.db b/UserTracking.db index 6c593b2..4cd4fcb 100644 Binary files a/UserTracking.db and b/UserTracking.db differ diff --git a/app.py b/app.py index 21c80a5..580a6a9 100644 --- a/app.py +++ b/app.py @@ -1,14 +1,14 @@ from flask import Flask, request, render_template, redirect,\ -url_for, session, flash, jsonify + url_for, session, flash, jsonify from flask_sqlalchemy import SQLAlchemy from functools import wraps from flask_cors import CORS import simplejson as json import sqlite3 as sql -import datetime as dt +import datetime import time import os - +import flask_login app = Flask(__name__) CORS(app) @@ -18,8 +18,8 @@ # Create the sqlalchemy object db = SQLAlchemy(app) -# Should be imported after "db" creation as models.py uses db -from models import * +# Global variable +entered_UserId = "" # Login required decorator def login_required(f): @@ -37,18 +37,17 @@ def wrap(*args, **kwargs): @login_required def home(): userDetails = [] + username = request.args.get('userId') with sql.connect("UserTracking.db") as connection: - print "inside db connection" + c = connection.cursor() - c.execute('SELECT evt_type, pageHTML, evt_datetime FROM UserActions where userId = "dummy" and evt_datetime != "NaN" ') + c.execute('SELECT evt_type, pageHTML, evt_datetime FROM UserActions where userId = ? ORDER BY tmStamp DESC', [username]) userDetails = c.fetchall() posts = [] for info in userDetails: - post = info[0] + " --> " + info[1] + " --> " + info[2] - # print post posts.append(post) return render_template("index.html", posts=posts) @@ -58,48 +57,71 @@ def home(): @app.route('/login', methods=['GET', 'POST']) def login(): error = None + with sql.connect("UserTracking.db") as connection: + c = connection.cursor() + + if request.method == 'GET': + # print "INSIDE GET REQUEST" + c.execute('SELECT userId, loginDataTime FROM UserHistory ORDER BY tmStamp DESC') + loginHistory = c.fetchall() + print "loginHistory = ", loginHistory + + logins = [] + for loginHis in loginHistory: + login = loginHis[0] + " --> " + loginHis[1] + logins.append(login) + + print logins + return render_template("login.html", error=error, logins=logins) - if request.method == 'POST': - if request.form['username'] != "admin" or request.form['password'] != "admin": - error = "Invalid credentials. Please try again" - else: - loginStartTime = time.time() - print "curr time = ", str(loginStartTime) - - session['logged_in'] = True - with sql.connect("UserTracking.db") as connection: - c = connection.cursor() - c.execute('SELECT * FROM UserActions where userId = "admin"') - loginInfo = c.fetchall() + with sql.connect("UserTracking.db") as connection: + c = connection.cursor() + + username = request.form['username'] + password = request.form['password'] + + if request.method == 'POST': + validCount = c.execute('SELECT count(password) FROM UserDetails WHERE userId = ? and password = ?', [username, password]).fetchall()[0][0] + print "validCount = ", validCount + + if validCount == 0: + error = "Invalid credentials. Please try again" + else: + session['logged_in'] = True + # Maintain global variable to store current username + global entered_UserId + entered_UserId = username - print "from login", request.form['username'] - return redirect(url_for('home', userId=request.form['username'])) + # Get login time + now = datetime.datetime.now() + curr_time = now.strftime("%Y-%m-%d %I:%M:%S %p") + curr_timestamp = int(time.time()) + print curr_timestamp - return render_template("login.html", error=error) + c.execute('INSERT INTO UserHistory VALUES (?,?,?)', [username, curr_time, curr_timestamp]) + return redirect(url_for('home', userId=request.form['username'])) + + return render_template("login.html", error=error) @app.route('/adduser', methods=['GET', 'POST']) def adduser(): - info = None - - # Post request - if request.method == 'POST': + info = "" - if request.form['username'] == "" or request.form['password'] == "": + if request.method == 'POST': + + if not request.form['username'] or not request.form['password']: info = "Login credentials cannot be empty" else: - loginStartTime = dt.datetime.now() - print str(loginStartTime) - - # session['logged_in'] = True with sql.connect("UserTracking.db") as connection: c = connection.cursor() - c.execute('INSERT INTO UserDetails VALUES(?,?)', [request.form['username'], request.form['password']]) - loginInfo = c.fetchall() - - info = "User created" - print info - print loginInfo + userExists = c.execute('SELECT count(password) FROM UserDetails WHERE userId = ?', [request.form['username']]).fetchall()[0][0] + if userExists != 0: + info = "UserId already exists" + else: + c.execute('INSERT INTO UserDetails VALUES(?,?)', [request.form['username'], request.form['password']]) + loginInfo = c.fetchall() + info = "User created" return render_template("adduser.html", info=info) # Get request @@ -109,16 +131,16 @@ def adduser(): @app.route('/TrackingData', methods=["POST"]) def TrackingData(): + req_json = request.get_json() evtData = req_json['evtData'] quesData = req_json['quesData'] - # print evtData with sql.connect("UserTracking.db") as connection: c = connection.cursor() - c.execute('INSERT INTO UserActions VALUES(?,?,?,?,?)', \ - [evtData['userId'], evtData['evt_type'], evtData['pageHTML'], \ - evtData['object_id'], evtData['evt_datetime']]) + c.execute('INSERT INTO UserActions VALUES(?,?,?,?,?,?)', \ + [entered_UserId, evtData['evt_type'], evtData['pageHTML'], \ + evtData['object_id'], evtData['evt_datetime'], evtData['evt_timestamp']]) # Future work - If object_id already exists, dont insert the column again if quesData != None: c.execute('INSERT INTO ObjectDetails VALUES(?,?,?,?,?,?,?,?)', \ @@ -128,9 +150,6 @@ def TrackingData(): return "" - - - @app.route('/logout') @login_required def logout(): diff --git a/db_create.py b/db_create.py deleted file mode 100644 index 5ea79e7..0000000 --- a/db_create.py +++ /dev/null @@ -1,17 +0,0 @@ -# Import db that is created in app.py -from app import db -# Import schema -from models import UserActions - - -# Create the database and db tables -db.create_all() # Initializes the database based on the - # schema defined in models.py file - -# # Insert -# # db.session.deleteall(BlogPost) -# db.session.add(BlogPost("Good", "I\'m good.")) -# db.session.add(BlogPost("Well", "I\'m well.")) - -# # Commit the changes -# db.session.commit() \ No newline at end of file diff --git a/models.py b/models.py deleted file mode 100644 index 8daacbb..0000000 --- a/models.py +++ /dev/null @@ -1,52 +0,0 @@ -from app import db - -class UserDetails(db.Model): - __tablename__ = "UserDetails" - - # Three variables goes to three columns in the database - user_id = db.Column(db.Integer, primary_key=True) - user_name = db.Column(db.String, nullable=False) - password = db.Column(db.String, nullable=False) - - def __init__(self, user_name, password): - self.user_name = user_name - self.password = password - - def __repr__(self): - return '{}-{}-{}'.format(self.user_id, self.user_name, self.password) - - -class UserHistory(db.Model): - __tablename__ = "UserHistory" - - # Three variables goes to three columns in the database - user_id = db.Column(db.Integer, primary_key=True) - login_date = db.Column(db.String, nullable=False) - login_time = db.Column(db.String, nullable=False) - - def __init__(self, login_date, login_time): - self.login_date = login_date - self.login_time = login_time - - def __repr__(self): - return '{}-{}-{}'.format(self.user_id, self.login_date, self.login_time) - - -class UserActions(db.Model): - __tablename__ = "UserActions" - - # Three variables goes to three columns in the database - ques_id = db.Column(db.Integer, primary_key=True) - votes = db.Column(db.Integer, nullable=False) - answers = db.Column(db.Integer, nullable=False) - views = db.Column(db.Integer, nullable=False) - - def __init__(self, ques_id, votes, answers, views): - self.ques_id = ques_id - self.votes = votes - self.answers = answers - self.views = views - - def __repr__(self): - return '{}-{}-{}-{}'.format(self.ques_id, self.votes, self.answers, self.views) - diff --git a/sql.py b/sql.py index 8d0d1eb..afea4a5 100644 --- a/sql.py +++ b/sql.py @@ -3,16 +3,12 @@ with sql.connect("UserTracking.db") as connection: c = connection.cursor() # c.execute("DROP TABLE UserActions") - c.execute("CREATE TABLE UserActions(userId TEXT, evt_type TEXT, pageHTML TEXT, object_id INT, evt_datetime TEXT)") + c.execute("CREATE TABLE UserActions(userId TEXT, evt_type TEXT, pageHTML TEXT, object_id INT, evt_datetime TEXT, tmStamp INT)") # c.execute("DROP TABLE ObjectDetails") c.execute("CREATE TABLE ObjectDetails(object_type TEXT, object_id INT, pageHTML TEXT, votes INT, answers INT, views INT, create_datetime TEXT, tags TEXT)") # c.execute("DROP TABLE UserHistory") - c.execute("CREATE TABLE UserHistory(userId TEXT, loginDataTime TEXT, logoutDateTime)") + c.execute("CREATE TABLE UserHistory(userId TEXT, loginDataTime TEXT, tmStamp INT)") # c.execute("DROP TABLE UserDetails") c.execute("CREATE TABLE UserDetails(userId TEXT, password TEXT)") - # c.execute("INSERT INTO UserDetails VALUES ('sss', 'qqq')") - # c.execute("INSERT INTO UserDetails VALUES ('aaa', 'bbb')") - # c.execute("INSERT INTO UserDetails VALUES ('ccc', 'ddd')") - \ No newline at end of file diff --git a/static/style.css b/static/style.css index dab82d7..cee153c 100644 --- a/static/style.css +++ b/static/style.css @@ -13,7 +13,7 @@ padding: 50px; .login { margin: 20px auto; -width: 300px; +width: 350px; } .login-screen { @@ -21,13 +21,14 @@ background-color: #FFF; padding: 20px; border-radius: 5px } - + .app-title { text-align: left; color: #777; } .add-user-title { +left-margin: 20px; text-align: right; color: #777; } @@ -35,6 +36,7 @@ color: #777; .login-form { text-align: center; } + .control-group { margin-bottom: 10px; } @@ -43,6 +45,12 @@ margin-bottom: 10px; left-margin: 20px; } +.login-form-scroll { + height:350px; + overflow-y: scroll; + margin: 60px 0; +} + table { border-collapse: separate; border-spacing: 10px 0; diff --git a/templates/adduser.html b/templates/adduser.html index 0f1d9d5..b62ebef 100644 --- a/templates/adduser.html +++ b/templates/adduser.html @@ -43,15 +43,17 @@

+ + + {% if info %} +

{{ info }}

+ {% endif %} - - {% if error %} -

Info: {{ info }}

- {% endif %} + \ No newline at end of file diff --git a/templates/login.html b/templates/login.html index 6c5271d..63a4a7a 100644 --- a/templates/login.html +++ b/templates/login.html @@ -12,10 +12,10 @@ {% if session['logged_in'] %}
You're logged in already!
-

Click here to go to your home page

+

Click here to logout and login with new username

+ {% else %} - - +
-
+
-
-

Users login history

+
- {% if error %} + {% endif %} diff --git a/templates/welcome.html b/templates/welcome.html deleted file mode 100644 index 99edc6d..0000000 --- a/templates/welcome.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "base.html" %} -{% block content %} - -

Welcome to Flask!

-
-

Click here to go home.

- -{% endblock %} \ No newline at end of file