From 67730ed88a8c14fc1e4381f0bde6ee55f81aef12 Mon Sep 17 00:00:00 2001 From: rahulVarma Date: Mon, 3 Jun 2019 19:58:55 +0530 Subject: [PATCH] Question interface (#134) * User Submission History and User Stats User Submission History and User Stats * Updated to include new db changes and user specific data Updated to include new db changes and user specific data * Updated Code Updated Code * Updated as per comments Updated to check user session cookie, get count from already read database and directly convert to list * Updated to handle Session changes Updated to handle statsitics even if the session changes * Updated as per @rishabhKalakoti and @ theSage21 comments Updated as per @rishabhKalakoti and @ theSage21 comments * Formatted code Formatted code * Included enchancement to submit questions through the web interface Included enchancement to submit questions through the web interface * 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 * 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 * Updated to add support for adding Contests Updated to add support for adding Contests * Updated insert_dummy.py file Updated file to populate test data without database call and directly through POST method --- insert_dummy.py | 70 ++++++++++++++++ server.py | 174 ++++++++++++++++++++++++++-------------- views/addContest.html | 58 ++++++++++++++ views/addQuestion.html | 20 +++++ views/base.html | 7 ++ views/dashboard.html | 2 + views/question.html | 4 +- views/questionBank.html | 38 +++++++++ 8 files changed, 313 insertions(+), 60 deletions(-) create mode 100644 insert_dummy.py create mode 100644 views/addContest.html create mode 100644 views/addQuestion.html create mode 100644 views/questionBank.html diff --git a/insert_dummy.py b/insert_dummy.py new file mode 100644 index 0000000..a36b19d --- /dev/null +++ b/insert_dummy.py @@ -0,0 +1,70 @@ +import requests +import datetime +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], + }, + ) diff --git a/server.py b/server.py index 624feef..3bf333b 100644 --- a/server.py +++ b/server.py @@ -37,14 +37,19 @@ 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 class Question(Model): - q_no = IntegerField(unique=True) + 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 @@ -73,50 +78,6 @@ 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(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): def login_redirect(*args, **kwargs): @@ -175,22 +136,106 @@ def statistics(): ) +@app.get("/addQuestion") +@login_required +def addQuestion(): + return bottle.template("addQuestion.html") + + +@app.post("/questionInput") +@login_required +def questionInput(): + 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") + try: + Question.create( + test_case_input=uploaded_question, + test_case_output=uploaded_answer, + question_statement=uploaded_statement, + author=userid, + ) + except Exception as e: + bottle.abort(500, str(e)) + 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("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): 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 ) @@ -208,9 +253,18 @@ def contest(code): 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() + ) + except: + bottle.abort(404, "No such question") + return question_result["test_case_input"] @app.get("/static/") @@ -323,24 +377,28 @@ 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: 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: 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/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/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 95e17ee..e7992d9 100644 --- a/views/dashboard.html +++ b/views/dashboard.html @@ -24,6 +24,8 @@

Contests

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 new file mode 100644 index 0000000..4f5dd8a --- /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["question_statement"]}}{{question["username"]}}{{question["created_date_time"].strftime("%d-%m-%Y %H:%M")}}
+
+ \ No newline at end of file