Skip to content
This repository was archived by the owner on Dec 8, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 51 additions & 13 deletions CodeChallenge/api/vote.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from flask_jwt_extended import get_current_user, jwt_optional
from flask_mail import Message
from itsdangerous import URLSafeSerializer
from sqlalchemy import or_

from .. import core
from ..auth import Users
Expand Down Expand Up @@ -49,25 +50,14 @@ def get_contestants():
contestants = []
for ans in p.items: # type: Answer

display = None
if ans.user.studentfirstname \
and ans.user.studentlastname:
display = f"{ans.user.studentfirstname} " \
f"{ans.user.studentlastname[0]}."

confirmed_votes = []
for v in ans.votes:
if v.confirmed:
confirmed_votes.append(v)

contestants.append(dict(
id=ans.id,
text=ans.text,
numVotes=len(confirmed_votes),
numVotes=ans.confirmed_votes(),
firstName=ans.user.studentfirstname,
lastName=ans.user.studentlastname,
username=ans.user.username,
display=display
display=ans.user.display()
))

return jsonify(
Expand Down Expand Up @@ -188,3 +178,51 @@ def vote_confirm():

return jsonify(status="success",
reason="vote confirmed")


@bp.route("/search", methods=["GET"])
def search():
keyword = request.args.get("q")
try:
page = int(request.args.get("page", 1))
per = int(request.args.get("per", 20))
except ValueError:
return jsonify(status="error",
reason="invalid 'page' or 'per' parameter"), 400

if keyword is None:
return jsonify(status="error", reason="missing 'q' parameter"), 400

keyword = f"%{keyword}%"

p = Answer.query \
.join(Answer.question) \
.join(Answer.user) \
.filter(Question.rank == core.max_rank(),
Answer.correct, or_(Users.username.ilike(keyword), Users.studentlastname.ilike(keyword),
Users.studentlastname.ilike(keyword))) \
.paginate(page=page, per_page=per)

results = []

for ans in p.items: # type: Answer
results.append(dict(
id=ans.id,
text=ans.text,
numVotes=ans.confirmed_votes(),
firstName=ans.user.studentfirstname,
lastName=ans.user.studentlastname,
username=ans.user.username,
display=ans.user.display()
))

return jsonify(
items=results,
totalItems=p.total,
page=p.page,
totalPages=p.pages,
hasNext=p.has_next,
nextNum=p.next_num,
hasPrev=p.has_prev,
prevNum=p.prev_num
)
7 changes: 7 additions & 0 deletions CodeChallenge/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ def votes(self):
.all()
return v

def display(self):
if self.studentfirstname is not None \
and self.studentlastname is not None \
and len(self.studentlastname):
return f"{self.studentfirstname} " \
f"{self.studentlastname[0]}."


def hash_password(plaintext):
ph = argon2.PasswordHasher()
Expand Down
8 changes: 8 additions & 0 deletions CodeChallenge/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ class Answer(db.Model):
votes = db.relationship("Vote", cascade="all,delete",
lazy=True, uselist=True)

def confirmed_votes(self) -> int:
confirmed = 0
for vote in self.votes:
if vote.confirmed:
confirmed += 1

return confirmed


class Vote(db.Model):
id = db.Column(db.Integer, primary_key=True)
Expand Down
18 changes: 18 additions & 0 deletions tests/test_question.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,24 @@ def test_cast_vote(client_challenge_lastq):
assert rv.json["status"] == "success"


@pytest.mark.skipif(not os.getenv("SANDBOX_API_URL"), reason="no final question")
def test_vote_search(client_challenge_lastq):
rv = client_challenge_lastq.get("/api/v1/vote/search?q=sam")
assert rv.status_code == 200

results = rv.json["items"]
assert len(results) == 1
assert results[0]["username"] == "cwhqsam"
assert results[0]["numVotes"] == 1

rv2 = client_challenge_lastq.get("/api/v1/vote/search?q=hOffMan")
assert rv2.status_code == 200

results2 = rv.json["items"]
assert len(results2) == 1
assert results2[0]["username"] == "cwhqsam"


@pytest.mark.skipif(not os.getenv("SANDBOX_API_URL"), reason="no final question")
def test_cast_notregistered(client_challenge_lastq):
client_challenge_lastq.cookie_jar.clear() # logout
Expand Down