예제 #1
0
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)
예제 #2
0
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)
예제 #3
0
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)
예제 #4
0
    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)
예제 #5
0
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