From 257f12aa06503fa581ad30365e1c75b9ba220337 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Thu, 23 May 2019 19:49:59 +0530 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 04/12] 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 05/12] 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 06/12] 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 07/12] 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 From c4ef33640a9e16a1d3d9f5bb1b8bab209ac41571 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Sun, 26 May 2019 16:52:08 +0530 Subject: [PATCH 08/12] Included enchancement to submit questions through the web interface Included enchancement to submit questions through the web interface --- server.py | 70 ++++++++++++++++++++++++++++++++++++++++- views/addQuestion.html | 20 ++++++++++++ views/dashboard.html | 1 + views/questionBank.html | 38 ++++++++++++++++++++++ 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 views/addQuestion.html create mode 100644 views/questionBank.html diff --git a/server.py b/server.py index e261920..e49974a 100644 --- a/server.py +++ b/server.py @@ -50,6 +50,17 @@ class Meta: database = db +class UploadedQuestion(Model): + question_text = TextField() + answer_text = TextField() + statement_text = CharField() + author = ForeignKeyField(User) + created_date_time = DateTimeField() + + class Meta: + database = db + + class ContestProblems(Model): contest = ForeignKeyField(Contest, backref="questions") question = ForeignKeyField(Question) @@ -71,7 +82,9 @@ class Meta: db.connect() -db.create_tables([User, Session, Submission, ContestProblems, Contest, Question]) +db.create_tables( + [User, Session, Submission, ContestProblems, Contest, Question, UploadedQuestion] +) # dummy contest data practiceContest = Contest.get_or_create( @@ -175,6 +188,61 @@ def statistics(): ) +@app.get("/addQuestion") +@login_required +def addQuestion(): + return bottle.template("addQuestion.html") + + +@app.post("/questionInput") +@login_required +def questionInput(): + userid = Session.get(Session.token == bottle.request.get_cookie("s_id")).user + time = datetime.datetime.now() + uploaded_question = bottle.request.files.get("question").file.read() + uploaded_answer = bottle.request.files.get("answer").file.read() + uploaded_statement = bottle.request.forms.get("statement") + try: + UploadedQuestion.create( + question_text=uploaded_question, + answer_text=uploaded_answer, + statement_text=uploaded_statement, + author=userid, + created_date_time=time, + ) + except: + bottle.abort(500, "Error in inserting submission to database.") + question_bank = ( + UploadedQuestion.select( + UploadedQuestion.id, + UploadedQuestion.question_text, + UploadedQuestion.statement_text, + User.username, + UploadedQuestion.created_date_time, + ) + .join(User, on=(UploadedQuestion.author == User.id)) + .order_by(UploadedQuestion.created_date_time.desc()) + .dicts() + ) + return bottle.template("questionBank.html", question_bank=question_bank) + + +@app.get("/display/") +@app.post("/display/") +@login_required +def displayQuestion(id): + try: + question_result = ( + UploadedQuestion.select(UploadedQuestion.question_text) + .where(UploadedQuestion.id == id) + .dicts() + .get() + ) + return question_result["question_text"] + except: + bottle.abort(404, "No such question") + + @app.get("/contest//") @login_required def question(code, number): diff --git a/views/addQuestion.html b/views/addQuestion.html new file mode 100644 index 0000000..7f2557f --- /dev/null +++ b/views/addQuestion.html @@ -0,0 +1,20 @@ +% include('base.html', title="Add Question") + +
+

Question Upload Page

+
+
+
+
+
Question Upload :
+

+ Answer Upload :
+

+ Statement :
+ +
+
+ +
+
+ \ No newline at end of file diff --git a/views/dashboard.html b/views/dashboard.html index 95e17ee..5a551bf 100644 --- a/views/dashboard.html +++ b/views/dashboard.html @@ -24,6 +24,7 @@

Contests

diff --git a/views/questionBank.html b/views/questionBank.html new file mode 100644 index 0000000..7e0e4aa --- /dev/null +++ b/views/questionBank.html @@ -0,0 +1,38 @@ +% include('base.html', title="Question Bank") + +
+ + + + + + + +
List Of Questions
+ + + + + + + + + % for question in question_bank : + + + + + + + % end + +
Question Question StatementAuthorTime submitted
+ + Download Question + + {{question["statement_text"]}}{{question["username"]}}{{question["created_date_time"].strftime("%d-%m-%Y %H:%M")}}
+
+ \ No newline at end of file From 34a7c42fb0c857ec88ea79093f927faf87180ae6 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Sun, 26 May 2019 19:12:51 +0530 Subject: [PATCH 09/12] Updated to remove the existing table and replace it with the new table Updated to remove the existing table and replace it with the new table --- server.py | 109 +++++++++++++++++++--------------------- views/question.html | 4 +- views/questionBank.html | 4 +- 3 files changed, 56 insertions(+), 61 deletions(-) diff --git a/server.py b/server.py index e49974a..cfb0692 100644 --- a/server.py +++ b/server.py @@ -2,6 +2,7 @@ import os, sys, datetime import string, random from peewee import * +import logging path = os.path.abspath(__file__) dir_path = os.path.dirname(path) @@ -43,17 +44,9 @@ class Meta: class Question(Model): - q_no = IntegerField(unique=True) - author = ForeignKeyField(User) - - class Meta: - database = db - - -class UploadedQuestion(Model): - question_text = TextField() - answer_text = TextField() - statement_text = CharField() + test_case_input = TextField() + test_case_output = TextField() + question_statement = CharField() author = ForeignKeyField(User) created_date_time = DateTimeField() @@ -83,7 +76,7 @@ class Meta: db.connect() db.create_tables( - [User, Session, Submission, ContestProblems, Contest, Question, UploadedQuestion] + [User, Session, Submission, ContestProblems, Contest, Question] ) # dummy contest data @@ -114,13 +107,13 @@ class Meta: 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]) - +q1 = Question.get_or_create(test_case_input="1", test_case_output="1", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) +q2 = Question.get_or_create(test_case_input="2", test_case_output="2", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) +q3 = Question.get_or_create(test_case_input="3", test_case_output="3", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) +q4 = Question.get_or_create(test_case_input="4", test_case_output="4", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) +q5 = Question.get_or_create(test_case_input="5", test_case_output="5", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) +q6 = Question.get_or_create(test_case_input="6", test_case_output="6", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) +logging.getLogger().setLevel(logging.INFO) 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]) @@ -203,62 +196,50 @@ def questionInput(): uploaded_answer = bottle.request.files.get("answer").file.read() uploaded_statement = bottle.request.forms.get("statement") try: - UploadedQuestion.create( - question_text=uploaded_question, - answer_text=uploaded_answer, - statement_text=uploaded_statement, + Question.create( + test_case_input=uploaded_question, + test_case_output=uploaded_answer, + question_statement=uploaded_statement, author=userid, created_date_time=time, ) except: bottle.abort(500, "Error in inserting submission to database.") question_bank = ( - UploadedQuestion.select( - UploadedQuestion.id, - UploadedQuestion.question_text, - UploadedQuestion.statement_text, + Question.select( + Question.id, + Question.test_case_input, + Question.question_statement, User.username, - UploadedQuestion.created_date_time, + Question.created_date_time, ) - .join(User, on=(UploadedQuestion.author == User.id)) - .order_by(UploadedQuestion.created_date_time.desc()) + .join(User, on=(Question.author == User.id)) + .order_by(Question.created_date_time.desc()) .dicts() ) return bottle.template("questionBank.html", question_bank=question_bank) -@app.get("/display/") -@app.post("/display/") -@login_required -def displayQuestion(id): - try: - question_result = ( - UploadedQuestion.select(UploadedQuestion.question_text) - .where(UploadedQuestion.id == id) - .dicts() - .get() - ) - return question_result["question_text"] - except: - bottle.abort(404, "No such question") - - @app.get("/contest//") @login_required def question(code, number): if ( not ContestProblems.select() - .where((Contest.code == code) & (Question.q_no == int(number))) + .where((Contest.code == code) & (Question.id == int(number))) .join(Contest, on=(ContestProblems.contest == Contest.id)) - .join(Question, on=(ContestProblems.question == Question.q_no)) + .join(Question, on=(ContestProblems.question == Question.id)) .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." - with open(os.path.join(question_dir, number, "statement.txt"), "rb") as fl: - statement = fl.read() + statement = ( + Question.select(Question.question_statement) + .where(Question.id == number) + .dicts() + .get() + ) return bottle.template( "question.html", question_number=number, contest=code, question=statement ) @@ -273,12 +254,22 @@ def contest(code): return bottle.abort(404, "no such contest") if contest.start_time > datetime.datetime.now(): return "The contest had not started yet." + logging.info(contest.questions.get()) return bottle.template("contest.html", contest=contest, questions=contest.questions) -@app.get("/question/") -def download(path): - return bottle.static_file(path, root=question_dir) +@app.get("/question/") +def download(id): + try: + question_result = ( + Question.select(Question.test_case_input) + .where(Question.id == id) + .dicts() + .get() + ) + return question_result["test_case_input"] + except: + bottle.abort(404, "No such question") @app.get("/static/") @@ -391,16 +382,20 @@ def file_upload(code, number): try: contestProblem = ContestProblems.get( ContestProblems.contest == Contest.get(Contest.code == code), - ContestProblems.question == Question.get(Question.q_no == int(number)), + ContestProblems.question == Question.get(Question.id == 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() - with open(os.path.join(question_dir, number, "output.txt"), "rb") as fl: - expected = fl.read() - expected = expected.strip() + expected = ( + Question.select(Question.test_case_output) + .where(Question.id == number) + .dicts() + .get() + ) + expected = expected["test_case_output"] uploaded = uploaded.strip() ans = uploaded == expected try: diff --git a/views/question.html b/views/question.html index 9b76a1a..de10aaa 100644 --- a/views/question.html +++ b/views/question.html @@ -5,8 +5,8 @@

Submission Page

diff --git a/views/questionBank.html b/views/questionBank.html index 7e0e4aa..865d108 100644 --- a/views/questionBank.html +++ b/views/questionBank.html @@ -23,11 +23,11 @@ % for question in question_bank : - + Download Question - {{question["statement_text"]}} + {{question["question_statement"]}} {{question["username"]}} {{question["created_date_time"].strftime("%d-%m-%Y %H:%M")}} From 4684659d75b60e08d0bc1047be1654bdee4aa1af Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Sun, 26 May 2019 22:21:01 +0530 Subject: [PATCH 10/12] Updated as per changes Updated to move the dummy code to another file Updated to add proper exceptions Upudated to adddeafult date/time Updated to refer session variable directly --- insert_dummy.py | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ server.py | 86 +++++++-------------------------- 2 files changed, 144 insertions(+), 68 deletions(-) create mode 100644 insert_dummy.py diff --git a/insert_dummy.py b/insert_dummy.py new file mode 100644 index 0000000..0cd2bee --- /dev/null +++ b/insert_dummy.py @@ -0,0 +1,126 @@ +import datetime +from peewee import * + +DATABASE_NAME = "data.db" +db = SqliteDatabase(DATABASE_NAME) + + +class User(Model): + username = CharField(unique=True) + password = CharField() + + class Meta: + database = db + + +class Contest(Model): + code = CharField(unique=True) + description = CharField() + start_time = DateTimeField() + end_time = DateTimeField() + + class Meta: + database = db + + +class Question(Model): + test_case_input = TextField() + test_case_output = TextField() + question_statement = CharField() + author = ForeignKeyField(User) + created_date_time = DateTimeField(default=datetime.datetime.now) + + class Meta: + database = db + + +class ContestProblems(Model): + contest = ForeignKeyField(Contest, backref="questions") + question = ForeignKeyField(Question) + + class Meta: + database = db + indexes = ((("contest", "question"), True),) + + +db.connect() + +# dummy contest data +practiceContest = Contest.get_or_create( + code="PRACTICE", + description="practice questions", + start_time=datetime.datetime(day=1, month=1, year=1), + end_time=datetime.datetime(day=1, month=1, year=9999), +) +pastContest = Contest.get_or_create( + code="PASTCONTEST", + description="somewhere in the past", + start_time=datetime.datetime(day=1, month=11, year=2018), + end_time=datetime.datetime(day=1, month=12, year=2018), +) +ongoingContest = Contest.get_or_create( + code="ONGOINGCONTEST", + description="somewhere in the present", + start_time=datetime.datetime(day=1, month=4, year=2019), + end_time=datetime.datetime(day=1, month=6, year=2019), +) +futureContest = Contest.get_or_create( + code="FUTURECONTEST", + description="somewhere in the future", + start_time=datetime.datetime(day=1, month=1, year=2020), + end_time=datetime.datetime(day=1, month=10, year=2020), +) + +test = User.get_or_create(username="test", password="test") + +q1 = Question.get_or_create( + test_case_input="1", + test_case_output="1", + question_statement="1", + author=test[0], + created_date_time=datetime.datetime.now(), +) +q2 = Question.get_or_create( + test_case_input="2", + test_case_output="2", + question_statement="1", + author=test[0], + created_date_time=datetime.datetime.now(), +) +q3 = Question.get_or_create( + test_case_input="3", + test_case_output="3", + question_statement="1", + author=test[0], + created_date_time=datetime.datetime.now(), +) +q4 = Question.get_or_create( + test_case_input="4", + test_case_output="4", + question_statement="1", + author=test[0], + created_date_time=datetime.datetime.now(), +) +q5 = Question.get_or_create( + test_case_input="5", + test_case_output="5", + question_statement="1", + author=test[0], + created_date_time=datetime.datetime.now(), +) +q6 = Question.get_or_create( + test_case_input="6", + test_case_output="6", + question_statement="1", + author=test[0], + created_date_time=datetime.datetime.now(), +) + +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]) diff --git a/server.py b/server.py index cfb0692..161e8f5 100644 --- a/server.py +++ b/server.py @@ -2,7 +2,6 @@ import os, sys, datetime import string, random from peewee import * -import logging path = os.path.abspath(__file__) dir_path = os.path.dirname(path) @@ -48,7 +47,7 @@ class Question(Model): test_case_output = TextField() question_statement = CharField() author = ForeignKeyField(User) - created_date_time = DateTimeField() + created_date_time = DateTimeField(default=datetime.datetime.now) class Meta: database = db @@ -75,53 +74,7 @@ class Meta: db.connect() -db.create_tables( - [User, Session, Submission, ContestProblems, Contest, Question] -) - -# dummy contest data -practiceContest = Contest.get_or_create( - code="PRACTICE", - description="practice questions", - start_time=datetime.datetime(day=1, month=1, year=1), - end_time=datetime.datetime(day=1, month=1, year=9999), -) -pastContest = Contest.get_or_create( - code="PASTCONTEST", - description="somewhere in the past", - start_time=datetime.datetime(day=1, month=11, year=2018), - end_time=datetime.datetime(day=1, month=12, year=2018), -) -ongoingContest = Contest.get_or_create( - code="ONGOINGCONTEST", - description="somewhere in the present", - start_time=datetime.datetime(day=1, month=4, year=2019), - end_time=datetime.datetime(day=1, month=6, year=2019), -) -futureContest = Contest.get_or_create( - code="FUTURECONTEST", - description="somewhere in the future", - start_time=datetime.datetime(day=1, month=1, year=2020), - end_time=datetime.datetime(day=1, month=10, year=2020), -) - -test = User.get_or_create(username="test", password="test") - -q1 = Question.get_or_create(test_case_input="1", test_case_output="1", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) -q2 = Question.get_or_create(test_case_input="2", test_case_output="2", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) -q3 = Question.get_or_create(test_case_input="3", test_case_output="3", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) -q4 = Question.get_or_create(test_case_input="4", test_case_output="4", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) -q5 = Question.get_or_create(test_case_input="5", test_case_output="5", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) -q6 = Question.get_or_create(test_case_input="6", test_case_output="6", question_statement="1", author=test[0], created_date_time=datetime.datetime.now()) -logging.getLogger().setLevel(logging.INFO) -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]) +db.create_tables([User, Session, Submission, ContestProblems, Contest, Question]) def login_required(function): @@ -190,8 +143,7 @@ def addQuestion(): @app.post("/questionInput") @login_required def questionInput(): - userid = Session.get(Session.token == bottle.request.get_cookie("s_id")).user - time = datetime.datetime.now() + userid = bottle.request.session.user uploaded_question = bottle.request.files.get("question").file.read() uploaded_answer = bottle.request.files.get("answer").file.read() uploaded_statement = bottle.request.forms.get("statement") @@ -201,10 +153,9 @@ def questionInput(): test_case_output=uploaded_answer, question_statement=uploaded_statement, author=userid, - created_date_time=time, ) - except: - bottle.abort(500, "Error in inserting submission to database.") + except Exception as e: + bottle.abort(500, str(e)) question_bank = ( Question.select( Question.id, @@ -235,11 +186,11 @@ def question(code, number): if contest.start_time > datetime.datetime.now(): return "The contest had not started yet." statement = ( - Question.select(Question.question_statement) - .where(Question.id == number) - .dicts() - .get() - ) + Question.select(Question.question_statement) + .where(Question.id == number) + .dicts() + .get() + ) return bottle.template( "question.html", question_number=number, contest=code, question=statement ) @@ -254,7 +205,6 @@ def contest(code): return bottle.abort(404, "no such contest") if contest.start_time > datetime.datetime.now(): return "The contest had not started yet." - logging.info(contest.questions.get()) return bottle.template("contest.html", contest=contest, questions=contest.questions) @@ -267,9 +217,9 @@ def download(id): .dicts() .get() ) - return question_result["test_case_input"] except: bottle.abort(404, "No such question") + return question_result["test_case_input"] @app.get("/static/") @@ -390,11 +340,11 @@ def file_upload(code, number): time = datetime.datetime.now() uploaded = bottle.request.files.get("upload").file.read() expected = ( - Question.select(Question.test_case_output) - .where(Question.id == number) - .dicts() - .get() - ) + Question.select(Question.test_case_output) + .where(Question.id == number) + .dicts() + .get() + ) expected = expected["test_case_output"] uploaded = uploaded.strip() ans = uploaded == expected @@ -402,8 +352,8 @@ def file_upload(code, number): Submission.create( user=user, contestProblem=contestProblem, time=time, is_correct=ans ) - except: - bottle.abort(500, "Error in inserting submission to database.") + except Exception as e: + bottle.abort(500, str(e)) if not ans: return "Wrong Answer!!" else: From 7c7bb721ebe8d6adbcb5e7b7d5297bc3b3befbfa Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Mon, 27 May 2019 22:03:24 +0530 Subject: [PATCH 11/12] Updated to add support for adding Contests Updated to add support for adding Contests --- server.py | 45 ++++++++++++++++++++++++++++++++ views/addContest.html | 58 +++++++++++++++++++++++++++++++++++++++++ views/base.html | 7 +++++ views/dashboard.html | 1 + views/questionBank.html | 2 +- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 views/addContest.html diff --git a/server.py b/server.py index 161e8f5..65a3cc6 100644 --- a/server.py +++ b/server.py @@ -37,6 +37,8 @@ class Contest(Model): description = CharField() start_time = DateTimeField() end_time = DateTimeField() + creator = ForeignKeyField(User) + created_date_time = DateTimeField(default=datetime.datetime.now) class Meta: database = db @@ -171,6 +173,49 @@ def questionInput(): return bottle.template("questionBank.html", question_bank=question_bank) +@app.get("/addContest") +@login_required +def addContest(): + question_bank = ( + Question.select( + Question.id, + Question.test_case_input, + Question.question_statement, + User.username, + Question.created_date_time, + ) + .join(User, on=(Question.author == User.id)) + .order_by(Question.created_date_time.desc()) + .dicts() + ) + return bottle.template("addContest.html", question_bank=question_bank) + + +@app.post("/contestInput") +@login_required +def contestInput(): + userid = bottle.request.session.user + code = bottle.request.forms.get("code") + description = bottle.request.forms.get("description") + start_time = bottle.request.forms.get("start_time") + end_time = bottle.request.forms.get("end_time") + selection = bottle.request.forms.getall("selection") + try: + contest = Contest.get_or_create( + code=code, + description=description, + start_time=start_time, + end_time=end_time, + creator=userid, + ) + except Exception as e: + bottle.abort(500, str(e)) + for questions in selection: + ContestProblems.create(contest=contest[0], question=questions) + contests = Contest.select().order_by(Contest.start_time) + return bottle.template("dashboard.html", contests=contests) + + @app.get("/contest//") @login_required def question(code, number): diff --git a/views/addContest.html b/views/addContest.html new file mode 100644 index 0000000..efe32fd --- /dev/null +++ b/views/addContest.html @@ -0,0 +1,58 @@ +% include('base.html', title="Add Contest") + +
+

Contest Creation Page

+
+
+
+
+
+ Contest Code :
+

+ Contest Description :
+ +

+ Start Time :
+

+ End Time :
+ +
+
+
+
+ + + + + + +
List Of Questions
+ + + + + + + + + + % for question in question_bank : + + + + + + + + % end + +
QuestionQuestion StatementAuthorTime submittedSelection
+ + Download Question + + {{question["question_statement"]}}{{question["username"]}}{{question["created_date_time"].strftime("%d-%m-%Y %H:%M")}}
+ + +
+ + diff --git a/views/base.html b/views/base.html index c10f517..e497a56 100644 --- a/views/base.html +++ b/views/base.html @@ -6,4 +6,11 @@ + + + + + + + diff --git a/views/dashboard.html b/views/dashboard.html index 5a551bf..e7992d9 100644 --- a/views/dashboard.html +++ b/views/dashboard.html @@ -25,6 +25,7 @@

Contests

diff --git a/views/questionBank.html b/views/questionBank.html index 865d108..4f5dd8a 100644 --- a/views/questionBank.html +++ b/views/questionBank.html @@ -8,7 +8,7 @@ - +

List Of QuestionsList Of Questions
From 97cfcad2f165eb61cf19dd9357bfbe158bc81931 Mon Sep 17 00:00:00 2001 From: Raul9595 Date: Tue, 28 May 2019 21:39:07 +0530 Subject: [PATCH 12/12] Updated insert_dummy.py file Updated file to populate test data without database call and directly through POST method --- insert_dummy.py | 194 +++++++++++++++++------------------------------- 1 file changed, 69 insertions(+), 125 deletions(-) diff --git a/insert_dummy.py b/insert_dummy.py index 0cd2bee..a36b19d 100644 --- a/insert_dummy.py +++ b/insert_dummy.py @@ -1,126 +1,70 @@ +import requests import datetime -from peewee import * - -DATABASE_NAME = "data.db" -db = SqliteDatabase(DATABASE_NAME) - - -class User(Model): - username = CharField(unique=True) - password = CharField() - - class Meta: - database = db - - -class Contest(Model): - code = CharField(unique=True) - description = CharField() - start_time = DateTimeField() - end_time = DateTimeField() - - class Meta: - database = db - - -class Question(Model): - test_case_input = TextField() - test_case_output = TextField() - question_statement = CharField() - author = ForeignKeyField(User) - created_date_time = DateTimeField(default=datetime.datetime.now) - - class Meta: - database = db - - -class ContestProblems(Model): - contest = ForeignKeyField(Contest, backref="questions") - question = ForeignKeyField(Question) - - class Meta: - database = db - indexes = ((("contest", "question"), True),) - - -db.connect() - -# dummy contest data -practiceContest = Contest.get_or_create( - code="PRACTICE", - description="practice questions", - start_time=datetime.datetime(day=1, month=1, year=1), - end_time=datetime.datetime(day=1, month=1, year=9999), -) -pastContest = Contest.get_or_create( - code="PASTCONTEST", - description="somewhere in the past", - start_time=datetime.datetime(day=1, month=11, year=2018), - end_time=datetime.datetime(day=1, month=12, year=2018), -) -ongoingContest = Contest.get_or_create( - code="ONGOINGCONTEST", - description="somewhere in the present", - start_time=datetime.datetime(day=1, month=4, year=2019), - end_time=datetime.datetime(day=1, month=6, year=2019), -) -futureContest = Contest.get_or_create( - code="FUTURECONTEST", - description="somewhere in the future", - start_time=datetime.datetime(day=1, month=1, year=2020), - end_time=datetime.datetime(day=1, month=10, year=2020), -) - -test = User.get_or_create(username="test", password="test") - -q1 = Question.get_or_create( - test_case_input="1", - test_case_output="1", - question_statement="1", - author=test[0], - created_date_time=datetime.datetime.now(), -) -q2 = Question.get_or_create( - test_case_input="2", - test_case_output="2", - question_statement="1", - author=test[0], - created_date_time=datetime.datetime.now(), -) -q3 = Question.get_or_create( - test_case_input="3", - test_case_output="3", - question_statement="1", - author=test[0], - created_date_time=datetime.datetime.now(), -) -q4 = Question.get_or_create( - test_case_input="4", - test_case_output="4", - question_statement="1", - author=test[0], - created_date_time=datetime.datetime.now(), -) -q5 = Question.get_or_create( - test_case_input="5", - test_case_output="5", - question_statement="1", - author=test[0], - created_date_time=datetime.datetime.now(), -) -q6 = Question.get_or_create( - test_case_input="6", - test_case_output="6", - question_statement="1", - author=test[0], - created_date_time=datetime.datetime.now(), -) - -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]) +import os + + +path = os.path.abspath(__file__) +dir_path = os.path.dirname(path) +question_dir = "files/questions" + +with requests.Session() as session: + register = session.post( + "http://localhost:8080/register", data={"username": "test", "password": "test"} + ) + + login = session.post( + "http://localhost:8080/login", data={"username": "test", "password": "test"} + ) + + for i in range(1, 7, 1): + Question1 = session.post( + "http://localhost:8080/questionInput", + files={ + "question": open( + os.path.join(question_dir, str(i), "inputs.txt"), "rb" + ), + "answer": open(os.path.join(question_dir, str(i), "output.txt"), "rb"), + }, + data={"statement": str(i)}, + ) + + Contest1 = session.post( + "http://localhost:8080/contestInput", + data={ + "code": "PRACTICE", + "description": "practice questions", + "start_time": datetime.datetime(day=1, month=1, year=1), + "end_time": datetime.datetime(day=1, month=1, year=9999), + "selection": [1, 2], + }, + ) + Contest2 = session.post( + "http://localhost:8080/contestInput", + data={ + "code": "PASTCONTEST", + "description": "somewhere in the past", + "start_time": datetime.datetime(day=1, month=11, year=2018), + "end_time": datetime.datetime(day=1, month=12, year=2018), + "selection": [1, 2], + }, + ) + Contest3 = session.post( + "http://localhost:8080/contestInput", + data={ + "code": "ONGOINGCONTEST", + "description": "somewhere in the present", + "start_time": datetime.datetime(day=1, month=4, year=2019), + "end_time": datetime.datetime(day=1, month=6, year=2019), + "selection": [3, 4], + }, + ) + Contest4 = session.post( + "http://localhost:8080/contestInput", + data={ + "code": "FUTURECONTEST", + "description": "somewhere in the future", + "start_time": datetime.datetime(day=1, month=1, year=2020), + "end_time": datetime.datetime(day=1, month=10, year=2020), + "selection": [5, 6], + }, + )