Example #1
0
def on_join(data):
    """socketio event listener that joins a user and emits to all users if someone joins"""
    quiz = store.get_quiz_by_user_id(data['user_id'])
    room = quiz.quiz_id

    # get and clean the users (no score)
    users = store.get_users_by_id(store.get_quiz_by_id(room).users)
    users_cleaned = [user.name for user in users]

    # emit the new users the to the room
    if room is not None:
        join_room(room)
        emit("current_players", {"users": users_cleaned}, room=room)
Example #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)
Example #3
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
Example #4
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)
Example #5
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)
Example #6
0
def index():
    """route that shows the entry page"""
    if request.method == "GET":
        return render_template("index.html", CATEGORIES=CATEGORIES)

    elif request.method == "POST":
        username = request.form.get("username", False)
        gamecode = request.form.get("gamecode", False)
        action = request.form.get("action", False)
        difficulty = request.form.get("difficulty", None)
        category = request.form.get("category", None)
        max_questions = request.form.get("amount", None)

        # give feedback to user
        if username == "":
            return render_template("index.html",
                                   error="Username should not be empty!",
                                   CATEGORIES=CATEGORIES), 400

        # join the game
        if action == "joingame" and gamecode:

            # check if gamecode can be case to int
            try:
                gamecode = int(gamecode)
            except ValueError:
                return render_template("index.html",
                                       error="Invalid Game Code!",
                                       CATEGORIES=CATEGORIES), 400

            # test if game is already started, if so return an error
            if store.get_quiz_by_code(gamecode) and store.get_quiz_by_code(
                    gamecode).is_started:
                return render_template("index.html",
                                       error="Game has already started!",
                                       CATEGORIES=CATEGORIES), 400
            # if game is not started, join game
            elif store.get_quiz_by_code(gamecode):
                quiz = store.get_quiz_by_code(gamecode)
                user_id = store.create_user(quiz_id=quiz.quiz_id,
                                            name=username,
                                            is_owner=False)
                session["user_id"] = user_id
                return redirect(url_for("lobby"))

            # if game does not exists return a 404
            else:
                return render_template("index.html",
                                       error="Game does not exist!",
                                       CATEGORIES=CATEGORIES), 400

        # create a new quiz
        elif action == "creategame":

            # if difficulty and category are random, set it to none
            if difficulty == "random":
                difficulty = None

            if category == "random":
                category = None

            # check if max questions can be cast to int
            if max_questions:
                try:
                    max_questions = int(max_questions)
                except TypeError:
                    return render_template(
                        "index.html",
                        error="Choose a number between 1 and 50",
                        CATEGORIES=CATEGORIES), 400

                if int(max_questions) < 1 or int(max_questions) > 50:
                    return render_template(
                        "index.html",
                        error="Choose a number between 1 and 50",
                        CATEGORIES=CATEGORIES), 400

            # try to make a game (connects to API by instantiating a Datasource)
            quiz_id = store.create_quiz(OpenTDB, difficulty, category,
                                        max_questions)
            quiz = store.get_quiz_by_id(quiz_id)

            # create the questions from the Quiz and the Datasource buffer (could connect to API
            # when buffer is empty)
            for _ in range(quiz.max_questions):
                store.create_question_from_source(quiz_id)

            # create a user
            user_id = store.create_user(quiz_id=quiz_id,
                                        name=username,
                                        is_owner=True)
            session["user_id"] = user_id

            return redirect(url_for("lobby"))

        elif action == "joingame" and not gamecode:
            return render_template("index.html",
                                   error="Game Code should not be empty!",
                                   CATEGORIES=CATEGORIES), 400
        # invalid request
        else:
            # TODO: JOIN GAME WITHOUT CODE EVALUATES TO THIS
            return "Invalid request", 400