Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation of Server File Source Code #133

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
169 changes: 166 additions & 3 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

db = SqliteDatabase(DATABASE_NAME)


class User(Model):
username = CharField(unique=True)
password = CharField()
Expand All @@ -22,6 +21,11 @@ class Meta:


class Session(Model):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see, this comment does not tell me anything new. What it says I can read in the code. A good docstring would let me know WHY the string being random is necessary.

For every new user ,random token is generated,so that the
token is unique for every user
"""

def random_token():
return "".join([random.choice(string.ascii_letters) for _ in range(20)])

Expand All @@ -45,9 +49,14 @@ class Meta:


class Question(Model):
<<<<<<< HEAD
q_no = IntegerField(unique=True)
=======

test_case_input = TextField()
test_case_output = TextField()
question_statement = CharField()
>>>>>>> main3
author = ForeignKeyField(User)
created_date_time = DateTimeField(default=datetime.datetime.now)

Expand All @@ -56,6 +65,11 @@ class Meta:


class ContestProblems(Model):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new. Perhaps this docstring can explain WHY this model is necessary and what all features exist in PyJudge because of this model

All contest problems belong to a Contest and are itself a question.
contest defines the instance of Contest Class it belongs
question defines the questions that belongs to that contest.
"""
contest = ForeignKeyField(Contest, backref="questions")
question = ForeignKeyField(Question)

Expand All @@ -65,19 +79,79 @@ class Meta:


class Submission(Model):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new

Submoission classdefines the submission of solution of a Question
Stores the information about:
User that submits the Solution
Time of Submission
Contest to whish The question belongs
Whether the soolution is correct
"""
user = ForeignKeyField(User)
time = DateTimeField()
contestProblem = ForeignKeyField(ContestProblems)
is_correct = BooleanField()

class Meta:
database = db
#define the database in the main class
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new

indexes = ((("user", "time"), True),)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line does not explain itself completely. A comment pointing to the right section of the peewee docs would be VERY helpful here.



#Establish a Connection with Database
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noise

db.connect()

"""Create Tables with specied fields in Databse"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't leave strings lying around in the code. Either use a comment or a docstring.

db.create_tables([User, Session, Submission, ContestProblems, Contest, Question])

<<<<<<< HEAD
# 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])


=======
>>>>>>> main3

def login_required(function):
def login_redirect(*args, **kwargs):
Expand All @@ -90,6 +164,7 @@ def login_redirect(*args, **kwargs):
return login_redirect



@app.route("/")
def changePath():
return bottle.redirect("/home")
Expand All @@ -105,6 +180,9 @@ def home():
@app.get("/dashboard")
@login_required
def dashboard():
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noise

Return the dashboard template to the user
"""
contests = Contest.select().order_by(Contest.start_time)
return bottle.template("dashboard.html", contests=contests)

Expand Down Expand Up @@ -219,6 +297,20 @@ def contestInput():
@app.get("/contest/<code>/<number>")
@login_required
def question(code, number):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new

Checks if the question and Contest it belongs does exists.
If exists : it checks the current status of the contest
And then returns the question state ment along with question numbers
and contest code to the Template

: paran code : Contest code
: type code: int
: paran Question : Question no
: type Question: int
: return : Html template for Individual Question

"""

if (
not ContestProblems.select()
.where((Contest.code == code) & (Question.id == int(number)))
Expand All @@ -241,9 +333,19 @@ def question(code, number):
)



@app.get("/contest/<code>")
@login_required
def contest(code):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new

Checks if contest exists by validating the contest id.
Checks the the current staus of code

: param code : Contest code
: return : Html template for Contest

"""

try:
contest = Contest.get(Contest.code == code)
except Contest.DoesNotExist:
Expand All @@ -253,6 +355,7 @@ def contest(code):
return bottle.template("contest.html", contest=contest, questions=contest.questions)



@app.get("/question/<id>")
def download(id):
try:
Expand All @@ -267,13 +370,32 @@ def download(id):
return question_result["test_case_input"]



@app.get("/static/<filepath:path>")
def server_static(filepath):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new

Static files for server

: param path : path to download from
:return : Static Files
"""
return bottle.static_file(filepath, root=os.path.join(dir_path, "static"))


@app.get("/ranking/<code>")
def contest_ranking(code):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing new. Perhaps if we had multiple rankings then it would have made sense to add a docstring here. IDK. Right now this docstring repeats what the code does.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here i am explaing how contest ranking are created , i thin it would the reader to understand it more.

Generates rankinks of users in a Contest i.e the Contest results
Validates the Sumbission And Contest.
Checks the number of correct submissions for each user and Added to
list with tuples of Username Along with thier Scores . The tuples
are added to list in descending order of the score .Then rankings are
given to each Username in the list.


:param code : Contest Code
:return : Html Template For Displaying Rankings
"""
order = (
Submission.select(
User.username, fn.count(Submission.contestProblem.distinct()).alias("score")
Expand All @@ -295,8 +417,15 @@ def contest_ranking(code):
return bottle.template("rankings.html", people=order)



@app.get("/ranking")
def rankings():
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a better thing to do would have been to rename the function something like user_rank since the last one was contest_rank

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right now this docstring is noise

Overall Ranking of the user over all the Contest.

:param None
:return : Ranking Template with Overall Ranking
"""
order = (
Submission.select(
User.username, fn.count(Submission.contestProblem.distinct()).alias("score")
Expand All @@ -316,6 +445,7 @@ def rankings():


def logggedIn():

if not bottle.request.get_cookie("s_id"):
return False
return (
Expand All @@ -325,7 +455,9 @@ def logggedIn():
)



def createSession(username):

try:
session = Session.create(user=User.get(User.username == username))
except IntegrityError:
Expand All @@ -340,6 +472,7 @@ def createSession(username):

@app.post("/login")
def login():

username = bottle.request.forms.get("username")
password = bottle.request.forms.get("password")
if (
Expand All @@ -351,8 +484,10 @@ def login():
return createSession(username)



@app.post("/register")
def register():

username = bottle.request.forms.get("username")
password = bottle.request.forms.get("password")
try:
Expand All @@ -364,16 +499,20 @@ def register():
return createSession(username)



@app.get("/logout")
def logout():

Session.delete().where(Session.token == bottle.request.get_cookie("s_id")).execute()
bottle.response.delete_cookie("s_id")
return bottle.redirect("/home")



@app.post("/check/<code>/<number>")
@login_required
@login_required
def file_upload(code, number):

try:
contestProblem = ContestProblems.get(
ContestProblems.contest == Contest.get(Contest.code == code),
Expand All @@ -393,20 +532,44 @@ def file_upload(code, number):
expected = expected["test_case_output"]
uploaded = uploaded.strip()
ans = uploaded == expected

try:
Submission.create(
user=user, contestProblem=contestProblem, time=time, is_correct=ans
<<<<<<< HEAD
)
except:
bottle.abort(500, "Error in inserting submission to database.")

if not ans:
=======
<<<<<<< HEAD
)# Add Submission For User
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noise

except:
bottle.abort(500, "Error in inserting submission to database.")

if not ans: # if Answer is Wrong
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noise

=======
)
except Exception as e:
bottle.abort(500, str(e))
if not ans:
>>>>>>> 67730ed88a8c14fc1e4381f0bde6ee55f81aef12
>>>>>>> main3
return "Wrong Answer!!"
else:
return "Solved! Great Job! "



@app.error(404)
def error404(error):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noise

Handles Error

:param error : Error returned the App
:return : Redirects to Template which Display Error
"""
return template("error.html", errorcode=error.status_code, errorbody=error.body)


Expand Down