From 257f12aa06503fa581ad30365e1c75b9ba220337 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Thu, 23 May 2019 19:49:59 +0530 Subject: [PATCH 1/7] User Submission History and User Stats User Submission History and User Stats --- server.py | 42 ++++++++++++++++++++++ views/stats.html | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 views/stats.html diff --git a/server.py b/server.py index 2c20ab1..8af37d8 100644 --- a/server.py +++ b/server.py @@ -81,6 +81,48 @@ def home(): def dashboard(): return bottle.template("dashboard.html", contests=contests) +@app.get("/stats") +@login_required +def statistics(): + with shelve.open(database_path) as submission_record: + sub_history = [ + ( + user, + [ + attempt + for attempt in submissions + ] + ) + for user, submissions in submission_record.items() + ] + sub_stats = [ + ( + user, + len( + [ + attempt.question + for attempt in submissions + if not(attempt.is_correct) + ] + ), + len( + [ + attempt.question + for attempt in submissions + if attempt.is_correct + ] + ), + len( + [ + attempt.question + for attempt in submissions + ] + ) + ) + for user, submissions in submission_record.items() + ] + return bottle.template("stats.html", sub_history=sub_history, sub_stats=sub_stats) + @app.get("/contest//") @login_required diff --git a/views/stats.html b/views/stats.html new file mode 100644 index 0000000..d4e6489 --- /dev/null +++ b/views/stats.html @@ -0,0 +1,92 @@ +% include('base.html', title="User Statistics") + +
+
+

User Statistics

+
+ + + + + + +
Submission History
+ + + + + + + + + + + % for name,attempts in sub_history : + % for records in attempts : + + + + + + + + + % end + % end + +
UsernameQuestion NumberTime submittedCorrect/Not CorrectContest
{{name}}{{records.question}}{{records.time.strftime("%d-%m-%Y %H:%M")}}{{records.is_correct}}{{records.contest}}
+ + + + + + +
Submission Statistics
+ % for name,incorrect,correct,total in sub_stats : + + + + + + + + + + + +
Total Submissions : {{total}}
+ % end + + + + +
+ \ No newline at end of file From 3f8059d86f53efb0c6accf45a021c6ddd2d366be Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Fri, 24 May 2019 00:18:31 +0530 Subject: [PATCH 2/7] Updated to include new db changes and user specific data Updated to include new db changes and user specific data --- server.py | 380 ++++++++++++++++++++++++------------------- views/dashboard.html | 5 +- views/stats.html | 46 +++--- 3 files changed, 242 insertions(+), 189 deletions(-) diff --git a/server.py b/server.py index 8af37d8..2b31447 100644 --- a/server.py +++ b/server.py @@ -1,60 +1,122 @@ import bottle import os, sys, datetime import string, random - -from collections import defaultdict, namedtuple -import shelve +from peewee import * path = os.path.abspath(__file__) dir_path = os.path.dirname(path) app = bottle.Bottle() -database_path = "submission_record.db" -user_db = "user_record.db" -sessions_db = "session_record.db" -questions = {} -contests = {} +DATABASE_NAME = "data.db" question_dir = "files/questions" -Question = namedtuple("Question", "output statement") -Submission = namedtuple("Submission", "question time output is_correct contest") -Contest = namedtuple("Contest", "description questions start_time end_time") -User = namedtuple("User", "password") +db = SqliteDatabase(DATABASE_NAME) + + +class User(Model): + username = CharField(unique=True) + password = CharField() + + class Meta: + database = db + + +class Session(Model): + def random_token(): + return "".join([random.choice(string.ascii_letters) for _ in range(20)]) + + token = CharField(unique=True, default=random_token) + user = ForeignKeyField(User) + + class Meta: + database = db + + +class Contest(Model): + code = CharField(unique=True) + description = CharField() + start_time = DateTimeField() + end_time = DateTimeField() + + class Meta: + database = db + -# dummy contests -contests["PRACTICE"] = Contest( +class Question(Model): + q_no = IntegerField(unique=True) + author = ForeignKeyField(User) + + class Meta: + database = db + + +class ContestProblems(Model): + contest = ForeignKeyField(Contest, backref="questions") + question = ForeignKeyField(Question) + + class Meta: + database = db + indexes = ((("contest", "question"), True),) + + +class Submission(Model): + user = ForeignKeyField(User) + time = DateTimeField() + contestProblem = ForeignKeyField(ContestProblems) + is_correct = BooleanField() + + class Meta: + database = db + indexes = ((("user", "time"), True),) + + +db.connect() +db.create_tables([User, Session, Submission, ContestProblems, Contest, Question]) + + +# dummy contest data +practiceContest = Contest.get_or_create( + code="PRACTICE", description="practice questions", - questions=[1, 2], start_time=datetime.datetime(day=1, month=1, year=1), end_time=datetime.datetime(day=1, month=1, year=9999), ) -contests["PASTCONTEST"] = Contest( +pastContest = Contest.get_or_create( + code="PASTCONTEST", description="somewhere in the past", - questions=[1, 2], start_time=datetime.datetime(day=1, month=11, year=2018), end_time=datetime.datetime(day=1, month=12, year=2018), ) -contests["ONGOINGCONTEST"] = Contest( +ongoingContest = Contest.get_or_create( + code="ONGOINGCONTEST", description="somewhere in the present", - questions=[3, 4], start_time=datetime.datetime(day=1, month=4, year=2019), end_time=datetime.datetime(day=1, month=6, year=2019), ) -contests["FUTURECONTEST"] = Contest( +futureContest = Contest.get_or_create( + code="FUTURECONTEST", description="somewhere in the future", - questions=[5, 6], start_time=datetime.datetime(day=1, month=1, year=2020), end_time=datetime.datetime(day=1, month=10, year=2020), ) -for i in os.listdir(question_dir): - if not i.isdigit(): - continue - with open(os.path.join(question_dir, i, "output.txt"), "rb") as fl: - output = fl.read() - with open(os.path.join(question_dir, i, "statement.txt"), "r") as fl: - statement = fl.read() - questions[i] = Question(output=output, statement=statement) +test = User.get_or_create(username="test", password="test") + +q1 = Question.get_or_create(q_no=1, author=test[0]) +q2 = Question.get_or_create(q_no=2, author=test[0]) +q3 = Question.get_or_create(q_no=3, author=test[0]) +q4 = Question.get_or_create(q_no=4, author=test[0]) +q5 = Question.get_or_create(q_no=5, author=test[0]) +q6 = Question.get_or_create(q_no=6, author=test[0]) + +ContestProblems.get_or_create(contest=practiceContest[0], question=q1[0]) +ContestProblems.get_or_create(contest=practiceContest[0], question=q2[0]) +ContestProblems.get_or_create(contest=pastContest[0], question=q1[0]) +ContestProblems.get_or_create(contest=pastContest[0], question=q2[0]) +ContestProblems.get_or_create(contest=ongoingContest[0], question=q3[0]) +ContestProblems.get_or_create(contest=ongoingContest[0], question=q4[0]) +ContestProblems.get_or_create(contest=futureContest[0], question=q5[0]) +ContestProblems.get_or_create(contest=futureContest[0], question=q6[0]) def login_required(function): @@ -62,8 +124,10 @@ def login_redirect(*args, **kwargs): if not logggedIn(): return bottle.template("home.html", message="Login required.") return function(*args, **kwargs) + return login_redirect + @app.route("/") def changePath(): return bottle.redirect("/home") @@ -79,59 +143,58 @@ def home(): @app.get("/dashboard") @login_required def dashboard(): + contests = Contest.select().order_by(Contest.start_time) return bottle.template("dashboard.html", contests=contests) @app.get("/stats") @login_required def statistics(): - with shelve.open(database_path) as submission_record: - sub_history = [ - ( - user, - [ - attempt - for attempt in submissions - ] - ) - for user, submissions in submission_record.items() - ] - sub_stats = [ - ( - user, - len( - [ - attempt.question - for attempt in submissions - if not(attempt.is_correct) - ] - ), - len( - [ - attempt.question - for attempt in submissions - if attempt.is_correct - ] - ), - len( - [ - attempt.question - for attempt in submissions - ] - ) - ) - for user, submissions in submission_record.items() - ] - return bottle.template("stats.html", sub_history=sub_history, sub_stats=sub_stats) - + sub_history = [] + sub_stats_correct = [] + sub_stats_total = [] + sub_history_temp = Submission.select(Contest.code, ContestProblems.question, Submission.time, Submission.is_correct)\ + .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) \ + .join(Session, on=(Submission.user == Session.user))\ + .switch() \ + .join(Contest, on=(ContestProblems.contest == Contest.id)) \ + .order_by(Submission.time.desc()) + for sub in sub_history_temp.tuples(): + sub_history.append(sub) + sub_stats_correct_temp = ( + Submission.select( + fn.count(Submission.is_correct) + ) + .where((Submission.is_correct == True)) + .join(Session, on=(Submission.user == Session.user)) + ) + for sub in sub_stats_correct_temp.tuples(): + sub_stats_correct.append(sub) + sub_stats_total_temp = ( + Submission.select( + fn.count(Submission.is_correct) + ) + .join(Session, on=(Submission.user == Session.user)) + ) + for sub in sub_stats_total_temp.tuples(): + sub_stats_total.append(sub) + return bottle.template("stats.html", sub_history=sub_history, sub_stats_correct=sub_stats_correct, sub_stats_total=sub_stats_total) @app.get("/contest//") @login_required -def contest(code, number): - if not code in contests: - return "Contest does not exist" - if contests[code].start_time > datetime.datetime.now(): +def question(code, number): + if ( + not ContestProblems.select() + .where((Contest.code == code) & (Question.q_no == int(number))) + .join(Contest, on=(ContestProblems.contest == Contest.id)) + .join(Question, on=(ContestProblems.question == Question.q_no)) + .exists() + ): + return bottle.abort(404, "no such contest problem") + contest = Contest.get(Contest.code == code) + if contest.start_time > datetime.datetime.now(): return "The contest had not started yet." - statement = questions[number].statement + with open(os.path.join(question_dir, number, "statement.txt"), "rb") as fl: + statement = fl.read() return bottle.template( "question.html", question_number=number, contest=code, question=statement ) @@ -140,11 +203,13 @@ def contest(code, number): @app.get("/contest/") @login_required def contest(code): - if not code in contests: - return "Contest does not exist" - if contests[code].start_time > datetime.datetime.now(): + try: + contest = Contest.get(Contest.code == code) + except Contest.DoesNotExist: + return bottle.abort(404, "no such contest") + if contest.start_time > datetime.datetime.now(): return "The contest had not started yet." - return bottle.template("contest.html", code=code, contest=contests[code]) + return bottle.template("contest.html", contest=contest, questions=contest.questions) @app.get("/question/") @@ -159,74 +224,66 @@ def server_static(filepath): @app.get("/ranking/") def contest_ranking(code): - with shelve.open(database_path) as submission_record: - order = [ - ( - user, - len( - set( - [ - attempt.question - for attempt in submissions - if ( - attempt.is_correct - and (int(attempt.question) in contests[code].questions) - and attempt.contest == code - and attempt.time <= contests[code].end_time - and attempt.time >= contests[code].start_time - ) - ] - ) - ), - ) - for user, submissions in submission_record.items() - ] - order.sort(key=lambda x: x[1], reverse=True) - order = [entry for entry in order if entry[1] > 0] - order = [(user, score, rank) for rank, (user, score) in enumerate(order, start=1)] + order = ( + Submission.select( + User.username, fn.count(Submission.contestProblem.distinct()).alias("score") + ) + .where( + (Submission.is_correct == True) + & (ContestProblems.contest == Contest.get(Contest.code == code)) + ) + .join(User, on=(Submission.user == User.id)) + .switch() + .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) + .group_by(Submission.user) + .order_by(fn.count(Submission.contestProblem.distinct()).desc()) + ) + order = list(order.tuples()) + order = [ + (username, score, rank) for rank, (username, score) in enumerate(order, start=1) + ] return bottle.template("rankings.html", people=order) @app.get("/ranking") def rankings(): - with shelve.open(database_path) as submission_record: - order = [ - ( - user, - len( - set( - [ - attempt.question - for attempt in submissions - if attempt.is_correct - ] - ) - ), - ) - for user, submissions in submission_record.items() - ] - order.sort(key=lambda x: x[1], reverse=True) - order = [(user, score, rank) for rank, (user, score) in enumerate(order, start=1)] - return template("rankings.html", people=order) + order = ( + Submission.select( + User.username, fn.count(Submission.contestProblem.distinct()).alias("score") + ) + .where((Submission.is_correct == True)) + .join(User, on=(Submission.user == User.id)) + .switch() + .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) + .group_by(Submission.user) + .order_by(fn.count(Submission.contestProblem.distinct()).desc()) + ) + order = list(order.tuples()) + order = [ + (username, score, rank) for rank, (username, score) in enumerate(order, start=1) + ] + return bottle.template("rankings.html", people=order) def logggedIn(): if not bottle.request.get_cookie("s_id"): return False - with shelve.open(sessions_db) as sessions: - return bottle.request.get_cookie("s_id") in sessions + return ( + Session.select() + .where(Session.token == bottle.request.get_cookie("s_id")) + .exists() + ) def createSession(username): - session_id = "".join( - random.choice(string.ascii_letters + string.digits) for i in range(20) - ) + try: + session = Session.create(user=User.get(User.username == username)) + except IntegrityError: + return bottle.abort(500, "Error! Please try again.") bottle.response.set_cookie( "s_id", - session_id, + session.token, expires=datetime.datetime.now() + datetime.timedelta(days=30), ) - with shelve.open(sessions_db) as sessions: - sessions[session_id] = username return bottle.redirect("/dashboard") @@ -234,11 +291,12 @@ def createSession(username): def login(): username = bottle.request.forms.get("username") password = bottle.request.forms.get("password") - with shelve.open(user_db) as users: - if not username in users: - return bottle.template("home.html", message="User does not exist.") - if users[username].password != password: - return bottle.template("home.html", message="Incorrect password.") + if ( + not User.select() + .where((User.username == username) & (User.password == password)) + .exists() + ): + return bottle.template("home.html", message="Invalid credentials.") return createSession(username) @@ -246,20 +304,18 @@ def login(): def register(): username = bottle.request.forms.get("username") password = bottle.request.forms.get("password") - with shelve.open(user_db) as users: - if username in users: - return bottle.template( - "home.html", - message="Username already exists. Select a different username", - ) - users[username] = User(password=password) + try: + User.create(username=username, password=password) + except IntegrityError: + return bottle.template( + "home.html", message="Username already exists. Select a different username" + ) return createSession(username) @app.get("/logout") def logout(): - with shelve.open(sessions_db) as sessions: - del sessions[bottle.request.get_cookie("s_id")] + Session.delete().where(Session.token == bottle.request.get_cookie("s_id")).execute() bottle.response.delete_cookie("s_id") return bottle.redirect("/home") @@ -267,30 +323,27 @@ def logout(): @app.post("/check//") @login_required def file_upload(code, number): - with shelve.open(sessions_db) as sessions: - u_name = sessions[bottle.request.get_cookie("s_id")] + try: + contestProblem = ContestProblems.get( + ContestProblems.contest == Contest.get(Contest.code == code), + ContestProblems.question == Question.get(Question.q_no == int(number)), + ) + except: + return bottle.abort(404, "no such contest problem") + user = Session.get(Session.token == bottle.request.get_cookie("s_id")).user time = datetime.datetime.now() uploaded = bottle.request.files.get("upload").file.read() - expected = questions[number].output + with open(os.path.join(question_dir, number, "output.txt"), "rb") as fl: + expected = fl.read() expected = expected.strip() uploaded = uploaded.strip() ans = uploaded == expected - - with shelve.open(database_path) as submission_record: - submissions = ( - [] if u_name not in submission_record else submission_record[u_name] + try: + Submission.create( + user=user, contestProblem=contestProblem, time=time, is_correct=ans ) - submissions.append( - Submission( - question=number, - time=time, - output=uploaded, - is_correct=ans, - contest=code, - ) - ) - submission_record[u_name] = submissions - + except: + bottle.abort(500, "Error in inserting submission to database.") if not ans: return "Wrong Answer!!" else: @@ -299,6 +352,7 @@ def file_upload(code, number): @app.error(404) def error404(error): - return template("error.html" ,errorcode=error.status_code , errorbody = error.body) + return template("error.html", errorcode=error.status_code, errorbody=error.body) + -bottle.run(app, host="localhost", port=8080) \ No newline at end of file +bottle.run(app, host="localhost", port=8080) diff --git a/views/dashboard.html b/views/dashboard.html index 1349b5c..95e17ee 100644 --- a/views/dashboard.html +++ b/views/dashboard.html @@ -13,9 +13,9 @@

Contests

- % for code, contest in contests.items(): + % for contest in contests: - {{code}} + {{contest.code}} {{contest.start_time}} {{contest.end_time}} @@ -24,6 +24,7 @@

Contests

diff --git a/views/stats.html b/views/stats.html index d4e6489..f7188a1 100644 --- a/views/stats.html +++ b/views/stats.html @@ -4,6 +4,10 @@

User Statistics

+ @@ -14,29 +18,19 @@

User Statistics

- - - - - - + + + + - % for name,attempts in sub_history : - % for records in attempts : + % for sub_history in sub_history : - - - - - - + + + + % end - % end
UsernameQuestion NumberTime submittedCorrect/Not CorrectContestContestQuestion NumberTime submittedCorrect/Not Correct
{{name}}{{records.question}}{{records.time.strftime("%d-%m-%Y %H:%M")}}{{records.is_correct}}{{records.contest}}{{sub_history[0]}}{{sub_history[1]}}{{sub_history[2].strftime("%d-%m-%Y %H:%M")}}{{sub_history[3]}}
@@ -46,15 +40,20 @@

User Statistics

- % for name,incorrect,correct,total in sub_stats : + % for sub_stats_correct in sub_stats_correct : + + % end + % for sub_stats_total in sub_stats_total : - + @@ -63,7 +62,6 @@

User Statistics

Total Submissions : {{total}}Total Submissions : {{sub_stats_total[0]}}
% end - From 58d7b324ad4615616975235dc48e66d10b26899b Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Fri, 24 May 2019 00:35:53 +0530 Subject: [PATCH 3/7] Updated Code Updated Code --- server.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/server.py b/server.py index 40d89eb..120d0a4 100644 --- a/server.py +++ b/server.py @@ -12,7 +12,6 @@ db = SqliteDatabase(DATABASE_NAME) - class User(Model): username = CharField(unique=True) password = CharField() @@ -69,39 +68,6 @@ class Meta: indexes = ((("user", "time"), True),) -db.connect() -db.create_tables([User, Session, Submission, ContestProblems, Contest, Question]) - -======= - -class Question(Model): - q_no = IntegerField(unique=True) - author = ForeignKeyField(User) - - class Meta: - database = db - - -class ContestProblems(Model): - contest = ForeignKeyField(Contest, backref="questions") - question = ForeignKeyField(Question) - - class Meta: - database = db - indexes = ((("contest", "question"), True),) - - -class Submission(Model): - user = ForeignKeyField(User) - time = DateTimeField() - contestProblem = ForeignKeyField(ContestProblems) - is_correct = BooleanField() - - class Meta: - database = db - indexes = ((("user", "time"), True),) - - db.connect() db.create_tables([User, Session, Submission, ContestProblems, Contest, Question]) From b62639182f4ea94558f3e56d0876f84beea3f584 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Fri, 24 May 2019 17:45:26 +0530 Subject: [PATCH 4/7] Updated as per comments Updated to check user session cookie, get count from already read database and directly convert to list --- server.py | 26 ++++---------------------- views/stats.html | 12 +++--------- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/server.py b/server.py index 120d0a4..3469413 100644 --- a/server.py +++ b/server.py @@ -146,34 +146,16 @@ def dashboard(): @app.get("/stats") @login_required def statistics(): - sub_history = [] - sub_stats_correct = [] - sub_stats_total = [] sub_history_temp = Submission.select(Contest.code, ContestProblems.question, Submission.time, Submission.is_correct)\ + .where(Session.token == bottle.request.get_cookie("s_id"))\ .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) \ .join(Session, on=(Submission.user == Session.user))\ .switch() \ .join(Contest, on=(ContestProblems.contest == Contest.id)) \ .order_by(Submission.time.desc()) - for sub in sub_history_temp.tuples(): - sub_history.append(sub) - sub_stats_correct_temp = ( - Submission.select( - fn.count(Submission.is_correct) - ) - .where((Submission.is_correct == True)) - .join(Session, on=(Submission.user == Session.user)) - ) - for sub in sub_stats_correct_temp.tuples(): - sub_stats_correct.append(sub) - sub_stats_total_temp = ( - Submission.select( - fn.count(Submission.is_correct) - ) - .join(Session, on=(Submission.user == Session.user)) - ) - for sub in sub_stats_total_temp.tuples(): - sub_stats_total.append(sub) + sub_history = list(sub_history_temp.tuples()) + sub_stats_total = len(sub_history) + sub_stats_correct = len([sub_history for sub in sub_history if sub[3]==True]) return bottle.template("stats.html", sub_history=sub_history, sub_stats_correct=sub_stats_correct, sub_stats_total=sub_stats_total) @app.get("/contest//") diff --git a/views/stats.html b/views/stats.html index f7188a1..7942b1a 100644 --- a/views/stats.html +++ b/views/stats.html @@ -40,20 +40,15 @@

User Statistics

- % for sub_stats_correct in sub_stats_correct : - % end - % for sub_stats_total in sub_stats_total : - - + @@ -61,7 +56,6 @@

User Statistics

Total Submissions : {{sub_stats_total[0]}}Total Submissions : {{sub_stats_total}}
- % end From a1a1e90106ae22046921da1fcc3923bcebc971b1 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Sat, 25 May 2019 02:25:33 +0530 Subject: [PATCH 5/7] Updated to handle Session changes Updated to handle statsitics even if the session changes --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index 3469413..0f806b1 100644 --- a/server.py +++ b/server.py @@ -147,7 +147,7 @@ def dashboard(): @login_required def statistics(): sub_history_temp = Submission.select(Contest.code, ContestProblems.question, Submission.time, Submission.is_correct)\ - .where(Session.token == bottle.request.get_cookie("s_id"))\ + .where(Submission.user == Session.get(Session.token == bottle.request.get_cookie("s_id")).user)\ .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) \ .join(Session, on=(Submission.user == Session.user))\ .switch() \ From 0aa8b707c64ea75b64f328b8b03fbef0c5a9ce01 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Sat, 25 May 2019 15:43:59 +0530 Subject: [PATCH 6/7] Updated as per @rishabhKalakoti and @ theSage21 comments Updated as per @rishabhKalakoti and @ theSage21 comments --- server.py | 13 +++++++------ views/stats.html | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/server.py b/server.py index 0f806b1..1aff354 100644 --- a/server.py +++ b/server.py @@ -120,6 +120,8 @@ def login_required(function): def login_redirect(*args, **kwargs): if not logggedIn(): return bottle.template("home.html", message="Login required.") + me = Session.get(Session.token == bottle.request.get_cookie('s_id')) + bottle.request.session = me return function(*args, **kwargs) return login_redirect @@ -146,16 +148,15 @@ def dashboard(): @app.get("/stats") @login_required def statistics(): - sub_history_temp = Submission.select(Contest.code, ContestProblems.question, Submission.time, Submission.is_correct)\ - .where(Submission.user == Session.get(Session.token == bottle.request.get_cookie("s_id")).user)\ + sub_history = Submission.select(Contest.code, ContestProblems.question, Submission.time, Submission.is_correct)\ + .where(Submission.user == bottle.request.session.user)\ .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) \ - .join(Session, on=(Submission.user == Session.user))\ .switch() \ .join(Contest, on=(ContestProblems.contest == Contest.id)) \ - .order_by(Submission.time.desc()) - sub_history = list(sub_history_temp.tuples()) + .order_by(Submission.time.desc()) \ + .dicts() sub_stats_total = len(sub_history) - sub_stats_correct = len([sub_history for sub in sub_history if sub[3]==True]) + sub_stats_correct = len([sub_history for sub in sub_history if sub["is_correct"]]) return bottle.template("stats.html", sub_history=sub_history, sub_stats_correct=sub_stats_correct, sub_stats_total=sub_stats_total) @app.get("/contest//") diff --git a/views/stats.html b/views/stats.html index 7942b1a..329262b 100644 --- a/views/stats.html +++ b/views/stats.html @@ -25,10 +25,10 @@

User Statistics

% for sub_history in sub_history : - {{sub_history[0]}} - {{sub_history[1]}} - {{sub_history[2].strftime("%d-%m-%Y %H:%M")}} - {{sub_history[3]}} + {{sub_history["code"]}} + {{sub_history["question"]}} + {{sub_history["time"].strftime("%d-%m-%Y %H:%M")}} + {{sub_history["is_correct"]}} % end From 4c924055ce1b68c613264507d93643b463f8dea3 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Sat, 25 May 2019 17:00:49 +0530 Subject: [PATCH 7/7] Formatted code Formatted code --- server.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/server.py b/server.py index 1aff354..e261920 100644 --- a/server.py +++ b/server.py @@ -12,6 +12,7 @@ db = SqliteDatabase(DATABASE_NAME) + class User(Model): username = CharField(unique=True) password = CharField() @@ -40,6 +41,7 @@ class Contest(Model): class Meta: database = db + class Question(Model): q_no = IntegerField(unique=True) author = ForeignKeyField(User) @@ -120,7 +122,7 @@ def login_required(function): def login_redirect(*args, **kwargs): if not logggedIn(): return bottle.template("home.html", message="Login required.") - me = Session.get(Session.token == bottle.request.get_cookie('s_id')) + me = Session.get(Session.token == bottle.request.get_cookie("s_id")) bottle.request.session = me return function(*args, **kwargs) @@ -145,19 +147,33 @@ def dashboard(): contests = Contest.select().order_by(Contest.start_time) return bottle.template("dashboard.html", contests=contests) + @app.get("/stats") @login_required def statistics(): - sub_history = Submission.select(Contest.code, ContestProblems.question, Submission.time, Submission.is_correct)\ - .where(Submission.user == bottle.request.session.user)\ - .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) \ - .switch() \ - .join(Contest, on=(ContestProblems.contest == Contest.id)) \ - .order_by(Submission.time.desc()) \ + sub_history = ( + Submission.select( + Contest.code, + ContestProblems.question, + Submission.time, + Submission.is_correct, + ) + .where(Submission.user == bottle.request.session.user) + .join(ContestProblems, on=(Submission.contestProblem == ContestProblems.id)) + .switch() + .join(Contest, on=(ContestProblems.contest == Contest.id)) + .order_by(Submission.time.desc()) .dicts() + ) sub_stats_total = len(sub_history) sub_stats_correct = len([sub_history for sub in sub_history if sub["is_correct"]]) - return bottle.template("stats.html", sub_history=sub_history, sub_stats_correct=sub_stats_correct, sub_stats_total=sub_stats_total) + return bottle.template( + "stats.html", + sub_history=sub_history, + sub_stats_correct=sub_stats_correct, + sub_stats_total=sub_stats_total, + ) + @app.get("/contest//") @login_required @@ -244,6 +260,7 @@ def rankings(): ] return bottle.template("rankings.html", people=order) + def logggedIn(): if not bottle.request.get_cookie("s_id"): return False