def set_answer(data): """socketio event listener that receives an answer from a particular client""" # get data user_id = data["user_id"] user = store.get_user_by_id(user_id) answer_id = data["answer_id"] answer = store.get_answer_by_id(answer_id) quiz = store.get_quiz_by_user_id(user_id) # check if it is time to go to the next question, if needed quiz.next_question() # get the question question_id = quiz.get_current_question_id() question = store.get_question_by_id(question_id) # check if enough data to answer the question if user_id and answer: # get the users answers for this question (user is still scoped to quiz, so user == quiz) user_answers = store.get_user_answers_by_user_and_question_id( user_id, answer.question_id) # if correct and no previous answer found and the question is still active if not len(user_answers) and answer.question_id == question_id: # create a new answer new_user_answer = UserAnswer(answer.question_id, answer_id, user_id) # store new answer and increment the store store.set_user_answer(new_user_answer) if answer.is_correct: user.score += question.score question = store.get_question_by_id(answer.question_id)
def scoreboard(): """route that shows the scoreboard""" # get data for scoreboard user_id = session["user_id"] user = store.get_user_by_id(user_id) quiz = store.get_quiz_by_id(user.quiz) questions = store.get_questions_by_id(quiz.questions) # collect and format data for scoreboard scoreboard_questions = [] for question in questions: # Get answers answers = store.get_answers_by_id(question.answers) # Get the users answers for the question user_answers = store.get_user_answers_by_user_and_question_id( user_id, question.question_id) # set user answer id (empty list would evaluate true) # TODO: weird that this returns a list of 1, while it should never be more than one answered_answer_id = user_answers[0].answer_id if len( user_answers) else False # format the question # make a shallow serializable clone (plain assignment would simply hand over the object pointer) scoreboard_question = {**vars(question)} scoreboard_question["answers"] = [] for answer in answers: # check if the user actually chose this answer is_chosen = True if str( answer.answer_id) == str(answered_answer_id) else False # append the answers by cloning them and adding a boolean is_chosen scoreboard_question["answers"].append({ **vars(answer), "is_chosen": is_chosen }) # TODO: is the question["is_correct"] still used on the client? if is_chosen and answer.is_correct: scoreboard_question["is_correct"] = True scoreboard_questions.append(scoreboard_question) # sort users by score users = store.get_users_by_id(quiz.users) users = sorted(users, key=lambda user: user.score, reverse=True) return render_template("scoreboard.html", users=users, questions=scoreboard_questions, quiz=quiz)
def game(): """route that renders questions and receives answers""" # get information user_id = session["user_id"] user = store.get_user_by_id(user_id) quiz = store.get_quiz_by_id(user.quiz) # check if it is time to go to the next question, if needed quiz.next_question() # emit finish command so client can reroute if quiz.is_finished: socketio.emit("finish_game", room=quiz.quiz_id) # render template with vue component return render_template("quiz.html", user=user, quiz=quiz)
def decorated_function(*args, **kwargs): # get quiz data user = store.get_user_by_id(session["user_id"]) quiz = store.get_quiz_by_id(user.quiz) # game mode = preparation if not quiz.is_started and str(request.url_rule) != "/lobby": return redirect(url_for("lobby")) # game mode = active if quiz.is_started and not quiz.is_finished and str(request.url_rule) != "/game": return redirect(url_for("game")) # game mode = finished if quiz.is_finished and str(request.url_rule) != "/scoreboard": return redirect(url_for("scoreboard")) # if on correct route, return the route function return f(*args, **kwargs)
def lobby(): """route that shows the lobby and receives start game actions""" user = store.get_user_by_id(session["user_id"]) quiz = store.get_quiz_by_id(user.quiz) # render the lobby view if request.method == "GET": # get name of current category if quiz.category: category = [ category["name"] for category in CATEGORIES if int(category["id"]) == int(quiz.category) ][0] else: category = "Random" # render the lobby template (with a vue element for the users included) return render_template("lobby.html", user=user, quiz=quiz, category=category) # submit the game start signal elif request.method == "POST": action = request.form["action"] # allow the starting of the quiz if owner if action == "start" and user.is_owner: # start te quiz store.get_quiz_by_id(user.quiz).start() # emit to all clients that the game starts (forces a refresh) socketio.emit("start_game", room=quiz.quiz_id) # redirect the current client return redirect(url_for("game")) else: return "starting quiz only allowed by owner", 400