Пример #1
0
def game_has_round_and_question(session):
    """
    verify that this session has at least one round and question
    """
    game_id = session.get(GAME_ID, None)
    if not game_id:
        return fail(f"Session {session[ID]} does not have a {GAME}_id")

    game = get_game(game_id)  # probably don't need to test validity because setting game_id illegal is prevented
    if not game[SUCCESS]:
        return game

    game = game[OBJECT]

    rounds = game.get(ROUNDS, [])
    if len(rounds) == 0:
        return fail(f"{GAME}_id {game_id} does not have any {ROUNDS}")

    first_round_id = rounds[0]
    round_obj = get_round(first_round_id)
    if not round_obj[SUCCESS]:
        return round_obj
    round_obj = round_obj[OBJECT]

    questions = round_obj.get(QUESTIONS, [])
    if len(questions) == 0:
        return fail(f"{ROUND}_id {first_round_id} does not have any {QUESTIONS}")

    first_question_id = questions[0]

    return succeed({ROUND_ID: first_round_id, QUESTION_ID: first_question_id, ROUNDS: rounds})
Пример #2
0
def get_players(session_id, player_id=None):
    """
    args: session_id
    returns:
        [
            {player_name: name, player_id: uuid4},
            {player_name: name, player_id: uuid4},
            ...
        ]
    """
    session = get_session(session_id)
    if session[SUCCESS]:
        session = session[OBJECT]
        players = session.get(PLAYERS, [])

        ret = []
        for player_id in players:
            player = get_player(player_id)
            if player[SUCCESS]:
                player = player[OBJECT]
                ret.append(player)
            else:
                return fail(f"Failed to get player {player_id}")

        resp = succeed(ret)
        resp[MODERATOR] = session[MODERATOR]
        return resp

    return fail("Failed to get session")
Пример #3
0
def update_game(game_id, data, game={}):

    round_names = data.get(ROUND_NAMES, {})
    rounds = data.get(ROUNDS, [])

    if len(round_names) != len(rounds):
        return fail(
            f"{ROUND_NAMES} is different length ({len(round_names)}) than {ROUNDS} ({len(rounds)})"
        )

    for round_id in rounds:
        if round_names.get(round_id, None) is None:
            return fail(f"missing round name for round with id {round_id})")

    prev_rounds = game.get(ROUNDS, [])
    target_rounds = data.get(ROUNDS, [])
    for round_id in prev_rounds:
        if round_id not in target_rounds:
            set_round_and_game_id(round_id, game_id,
                                  False)  # remove game_id from round

    for round_id in target_rounds:
        if round_id not in prev_rounds:
            set_round_and_game_id(round_id, game_id,
                                  True)  # add game_id to round

    if len(round_names) == 0 or len(rounds) == 0:
        data[ROUND_NAMES] = {}
        data[ROUNDS] = {}

    success = mongo.update("game", game_id, data)
    if success:
        game.update(data)
        return succeed(game)
    return fail(f"Failed to update game with data {data}")
Пример #4
0
def create_game(data):

    round_names = data[ROUND_NAMES]
    rounds = data[ROUNDS]

    if len(round_names) != len(rounds):
        return fail(
            f"{ROUND_NAMES} is different length ({len(round_names)}) than {ROUNDS} ({len(rounds)})"
        )

    for round_id in rounds:
        if round_names.get(round_id, None) is None:
            return fail(f"missing round name for round with id {round_id})")

    created = mongo.create("game", data)
    if not created:
        return fail("Failed to create game")

    # add game_id to all rounds, and return error if this fails
    game_id = created[ID]
    rupdate = rounds_have_game_id(rounds, game_id)
    if not rupdate:
        return rupdate

    return succeed(created)
Пример #5
0
def set_round_and_game_id(round_id, game_id, present=True):
    """
    set round so that it has or does not have game_id in its games list

    args:
        round_id: ID of target round
        game_id: ID of target game
        present: true if round X is marked as in game Y, false if not
    """
    round = get_round(round_id)
    if not round:
        return fail(
            f"Can't set game_id {game_id} in nonexistent round_id {round_id}")
    round = round[OBJECT]

    games = round.get(GAMES, [])
    if present and game_id not in games:
        if not mongo.push("round", round_id, GAMES, game_id):
            return fail(
                f"Failed to add game_id {game_id} to round_id {round_id}")

    if not present and game_id in games:
        if not mongo.pull("round", round_id, GAMES, game_id):
            return fail(
                f"Failed to remove game_id {game_id} to round_id {round_id}")

    return succeed(round)
Пример #6
0
def get_answer_status(session_id):
    player_id = request.args.get(PLAYER_ID, None)
    round_id = request.args.get(ROUND_ID, None)
    question_id = request.args.get(QUESTION_ID, None)

    try:
        round_id = int(round_id)
        question_id = int(question_id)
    except:
        return _resp(fail("Bad question/round ID"))

    session = get_session(session_id)[OBJECT]

    question = session[ROUNDS][round_id][QUESTIONS][question_id]
    answers = question.get(ANSWERS, None)
    if answers is None:
        return _resp(fail("Question is not open"))

    mod = session[MODERATOR]
    players = get_players2(session)
    if player_id != mod:
        # scored questions will provide answers and wagers
        if question.get(SCORED, False):
            return _resp(get_answers_scored(players, answers, player_id))
        else:
            # unscored questions will provide only answered:true/false
            return _resp(get_answers_unscored(players, answers, player_id))

    else:
        # mod always gets complete player_id/answer/wager
        return _resp(get_answers_as_mod(players, answers))
Пример #7
0
def score_question(session_id, data, session={}):
    """
    data = {
        question_id: x
        round_id: y
        players:
            team1: {correct: true}
            team2: {correct: false}
            ...
    }

    """
    question_id = data[QUESTION_ID]
    round_id = data[ROUND_ID]

    question = session.get(ROUNDS)[round_id][QUESTIONS][question_id]
    rescore = question.get(SCORED, False)

    answers = question.get(ANSWERS, None)
    if answers is None:
        return fail(f"{QUESTION}_id {question_id} is not open")

    session_players = session.get(PLAYERS, [])
    given_players = data[PLAYERS]

    for player_id in session_players:
        if player_id not in given_players:
            return fail(f"{PLAYER_ID} {player_id} was not scored.")
        is_correct = given_players[player_id].get(CORRECT, None)
        if is_correct is None:
            return fail(f"Did not set correct True/False for {PLAYER_ID} {player_id}")

    players = get_players2(session)
    answers = get_answers_as_mod(players, answers)[OBJECT]
    for answer in answers:
        print(answer)
        if answer['answered'] is False:
            return fail(f"{PLAYER_ID} {answer[PLAYER_ID]} has not answered question {question_id}")

        last_answer = answer[ANSWERS][-1]

        player_id = answer[PLAYER_ID]
        score_override = given_players[player_id].get(SCORE_OVERRIDE, None)
        wager = last_answer[WAGER] if score_override is None else score_override  # hack here to override

        is_correct = given_players[player_id].get(CORRECT, None)
        points_awarded = wager if is_correct else 0

        mongo.update("answer", last_answer['answer_id'], {CORRECT: is_correct, POINTS_AWARDED: points_awarded})

        award_points(session_id, player_id, points_awarded, rescore)

    score_flag = f"{ROUNDS}.{round_id}.{QUESTIONS}.{question_id}.{SCORED}"
    answ = f"{ROUNDS}.{round_id}.{QUESTIONS}.{question_id}.{ANSWER}"
    real_answer = get_real_question(session, round_id, question_id)[ANSWER]

    mongo.update("session", session_id, {score_flag: True, answ: real_answer})

    mongo.incr_state(session_id)
    return succeed(data)
Пример #8
0
def create_session(data):
    """
    POST /session
    """
    mod = create_player({TEAM_NAME: "mod", REAL_NAME: "mod", ICON: ""})
    if not mod[SUCCESS]:
        return mod

    mod_id = str(mod[OBJECT][ID])

    # create session with this moderator ID
    data[STARTED] = False
    data[MODERATOR] = mod_id
    created = mongo.create("session", data)
    if not created:
        return fail("Failed to create session")

    success = mongo.create("answer", data)
    if not success:
        return fail("Failed to create session")
    # created = created

    # resp = update_player(mod_id, {SESSION_ID: created[ID]})
    # if not resp[SUCCESS]:
    #     return fail(errors=resp[ERRORS])
    mongo.incr_state(created[ID])

    return succeed(created)
Пример #9
0
def validate_wagers(data):
    qlen = len(data.get(QUESTIONS, []))
    wlen = len(data.get(WAGERS, []))
    if qlen != wlen:
        error = f"{WAGERS} length ({wlen}) does not equal {QUESTIONS} length ({qlen}) (data: {data}))"
        return fail(error)

    for wager in data.get(WAGERS, []):
        if wager <= 0:
            return fail(f"Wager '{wager}' is not positive int")
    return succeed(data)
Пример #10
0
def _set_current_question(session_id, data, session={}):
    """
    validate that question ID in round
    set question.open = True
    set session.current_question = question_id
    return new question_id
    """
    qindex = data[QUESTION_ID]
    rindex = data[ROUND_ID]

    prev = get_question_in_round(session, rindex, qindex)
    if prev[SUCCESS]:
        prev = prev[OBJECT].get(ANSWERS, {})
    else:
        prev = {}

    r = get_current_round(session_id)
    if r[SUCCESS]:
        r = r[OBJECT]
        round_id = r[ROUND_ID]
        round_obj = get_round(round_id)
        if round_obj[SUCCESS]:
            round_obj = round_obj[OBJECT]

        question_ids = round_obj.get(QUESTIONS, [])

        if qindex > len(question_ids):
            return fail(f"{QUESTION} with index {qindex} is not in current round {r}.")

        question_id = question_ids[qindex]

        question = get_question(question_id)
        if not question[SUCCESS]:
            return question
        question = question[OBJECT]

        spot = f"{ROUNDS}.{rindex}.{QUESTIONS}.{qindex}"
        data_to_update = {
            CURRENT_QUESTION: qindex,
            f"{spot}.{QUESTION}": question[QUESTION],
            f"{spot}.{ANSWERS}": prev
        }
        mongo.update("session", session_id, data_to_update)
        # if not success:
        #     return fail(f"Failed to set question for question_id {question_id}")

        mongo.incr_state(session_id)

        return succeed({CURRENT_QUESTION: qindex})

    return fail(f"Failed to get round with ID {session.get(ROUND_ID)}")
Пример #11
0
def _set_current_round(session_id, data, session={}):
    round_index = data[ROUND_ID]

    # round must be in game.rounds
    game = get_game(session[GAME_ID])
    if game[SUCCESS]:
        game = game[OBJECT]
        round_ids = game.get(ROUNDS)
        if round_index > len(round_ids):
            return fail(f"{ROUND} with index '{round_index}' is not in {GAME} '{game}'")

        round_id = round_ids[round_index]

        # get round from DB and set in session obj
        r = get_round(round_id)
        if r[SUCCESS]:
            r = r[OBJECT]

            data_to_update = {
                f"{ROUNDS}.{round_index}.{WAGERS}":  r[WAGERS],
                ROUND_ID: round_id,
                CURRENT_ROUND: round_index,
            }

            success = mongo.update("session", session_id, data_to_update)
            if not success:
                fail(f"Failed to add update round with index {i} in session")
            if session[ROUNDS][round_index].get(QUESTIONS, None) is None:
                spot = f"{ROUNDS}.{round_index}.{QUESTIONS}"
                questions = r[QUESTIONS]
                for i, question_id in enumerate(questions):
                    question = get_question(question_id)
                    if not question[SUCCESS]:
                        return question
                    category = question[OBJECT][CATEGORY]

                    success = mongo.push("session", session_id, spot, {CATEGORY: category})
                    if not success:
                        fail(f"Failed to add question with index {i} to round")

            set_first_q = set_current_question(session_id, round_index, 0)
            if not set_first_q[SUCCESS]:
                return set_first_q

            mongo.incr_state(session_id)

            return succeed(r)

            fail(f"Failed to update {SESSION}")

        return fail(f"Failed to get {ROUND} with id {round_id}")

    return fail(f"Failed to get game with id '{session[GAME_ID]}'")
Пример #12
0
def get_question_in_round(session, round_index, question_index):
    """
    get question at index X in round with index Y
    """
    rounds = session[ROUNDS]
    if round_index >= len(rounds):
        return fail(f"{ROUND} index {round_index} not found in {SESSION} {session}")

    r = rounds[round_index]
    questions = r[QUESTIONS]
    if question_index >= len(questions):
        return fail(f"{QUESTION} index {question_index} not found in round {r}")

    question = questions[question_index]
    question[ID] = question_index
    return succeed(question)
Пример #13
0
def update_session(session_id, data, session={}):
    success = mongo.update("session", session_id, data)
    if success:
        session.update(data)
        return succeed(session)

    mongo.incr_state(session_id)
    return fail(f"Failed to update session with data {data}")
Пример #14
0
def update_question(question_id, data, question={}):
    """
    returns
         True/false if update successful
    """
    success = mongo.update("question", question_id, data)
    if success:
        question.update(data)
        return succeed(question)
    return fail(f"Failed to update {QUESTION} with data {data}")
Пример #15
0
def remove_question_from_all_rounds(question):
    rounds_used = question.get(ROUNDS_USED, [])
    question_id = question.get(ID)
    for round_id in rounds_used:
        modified_count = mongo.pull("round", round_id, QUESTIONS, question_id)
        if modified_count == 0:
            return fail(
                f"Failed to remove {QUESTION} {question_id} from {ROUND} {round_id}"
            )

    return succeed(question)
Пример #16
0
def legal_wagers_for_player(session_id):
    player_id = request.args.get(PLAYER_ID, None)
    round_id = request.args.get(ROUND_ID, None)
    session = get_session(session_id)[OBJECT]

    try:
        round_id = int(round_id)
    except:
        return _resp(fail("Bad round ID"))

    return _resp(succeed(get_legal_wagers(session, round_id, player_id)))
Пример #17
0
def create_round(data):
    validate = validate_wagers(data)
    if not validate[SUCCESS]:
        return validate

    created = mongo.create("round", data)
    if not created:
        return fail("Failed to create round")

    set_round_in_questions(created, [])  # no original questions, new round
    return succeed(created)
Пример #18
0
def verify_mod(session_id, player_id):
    # get session to make sure you are the mod
    # TODO: refactor this somehow into helper method to avoid double get
    session = get_session(session_id)
    if not session[SUCCESS]:
        return session

    mod = session[OBJECT][MODERATOR]
    if player_id != mod:
        return fail(f"only mod can start session")
    return succeed({})
Пример #19
0
def update_player(player_id, data, player={}):
    success = mongo.update("player", player_id, data)
    if success:
        player.update(data)

        # dirty the session state, so other clients will see this update
        session_id = player.get(SESSION_ID, None)
        if session_id:
            mongo.incr_state(session_id)

        return succeed(player)
    return fail(f"Failed to update player with data {data}")
Пример #20
0
def _start_session(session_id, data, session={}):
    if session[STARTED]:
        return fail(f"Session {session_id} is already started.")

    start = data[STARTED]
    if start:
        startable = game_has_round_and_question(session)
        if not startable[SUCCESS]:
            return startable

        rounds = startable[OBJECT][ROUNDS]
        for i, round_id in enumerate(rounds):
            success = mongo.push("session", session_id, ROUNDS, {ROUND_ID: round_id})
            if not success:
                fail(f"Failed to add round with index {i} to session")

        success = mongo.update("session", session_id, {STARTED: True})
        if not success:
            return fail("Failed tto start session")
        # set current round to 0th round ID in game
        # this will also set first question to 0th question in round
        set_round = set_current_round(session_id, 0)
        if not set_round[SUCCESS]:
            return set_round

        mongo.incr_state(session_id)
        return succeed(session)

    else:
        fail("Cannot start session with data {data}")
Пример #21
0
def update_round(round_id, data, round_obj={}, set_questions=True):
    validate = validate_wagers(data)
    if not validate[SUCCESS]:
        return validate

    orig_questions = round_obj.get(QUESTIONS, [])
    success = mongo.update("round", round_id, data)
    if success:
        if set_questions:
            round_obj[QUESTIONS] = data.get(QUESTIONS, orig_questions)
            set_round_in_questions(round_obj, orig_questions)
        return succeed(round_obj)
    return fail(f"Failed to update round")
Пример #22
0
def remove_round_from_question(question_id, data, question={}):
    round_id = data[ROUND_ID]
    rounds_used = question.get(ROUNDS_USED, [])
    if round_id not in rounds_used:
        raise RuntimeError(
            f"Round {round_id} is not added to question {question_id}")

    success = mongo.pull("question", question_id, ROUNDS_USED, round_id)
    if not success:
        return fail(f"Failed to remove {ROUND} from {QUESTION}")

    rounds_used.remove(round_id)
    question[ROUNDS_USED] = rounds_used
    return succeed(question)
Пример #23
0
def remove_from_session(session_id, data, session={}):
    """
    POST /session/:id/remove
    """
    admin_id = data[ADMIN_ID]
    player_id = data[PLAYER_ID]

    if player_id not in session.get(PLAYERS, []):
        return fail(f"Player id {player_id} is not in session")

    mod = session[MODERATOR]
    if admin_id != mod:
        return fail("Given admin ID does not match session")

    success = mongo.pull("session", session_id, PLAYERS, player_id)
    if not success:
        return fail("Failed to remove player from session")

    # delete player?
    data[SESSION_ID] = session_id
    mongo.incr_state(session_id)

    return succeed(data)
Пример #24
0
def add_to_session(session_id, data, session={}):
    """
    POST /session/:id/join
    """
    if session[STARTED]:
        return fail("Cannot add player to already-started session")

    if data[PLAYER_ID] in session.get(PLAYERS, []):
        return fail(f"Player id {data[PLAYER_ID]} is already in session")

    player_id = data[PLAYER_ID]
    success = mongo.push("session", session_id, PLAYERS, player_id)
    if not success:
        return fail("Failed to add player to session")

    data[SESSION_ID] = session_id

    mongo.incr_state(session_id)
    update = update_player(player_id, {"session_id": session_id})
    if not update:
        return update

    return succeed(data)
Пример #25
0
def add_round_to_question(question_id, data, question={}):
    round_id = data[ROUND_ID]
    rounds_used = question.get(ROUNDS_USED, [])
    if round_id in rounds_used:
        raise RuntimeError(
            f"Round {round_id} is already added to question {question_id}")

    success = mongo.push("question", question_id, ROUNDS_USED, round_id)
    if not success:
        return fail(f"Failed to add {ROUND} to {QUESTION}")

    rounds_used.append(round_id)
    question[ROUNDS_USED] = rounds_used
    return succeed(question)
Пример #26
0
def answer_question(session_id, data, session={}):
    """
    validate wager is legal
    validate question is answerable
    create answer record
    push answer ID to
        session.question_id.player_id.answers
    return success: true
    """
    player_id = data[PLAYER_ID]
    rindex = data[ROUND_ID]
    qindex = data[QUESTION_ID]

    legal_wagers = get_legal_wagers(session, rindex, player_id)
    wager = data[WAGER]
    if wager not in legal_wagers:
        return fail(f"Wager {wager} is illegal")

    answers = session[ROUNDS][rindex][QUESTIONS][qindex].get(ANSWERS, None)
    if answers is None:
        return fail(f"{QUESTION}_id {qindex} is not open")

    answer = create_answer(data)
    if not answer[SUCCESS]:
        return answer
    answer = answer[OBJECT]

    answer_id = answer[ID]
    array = f"{ROUNDS}.{rindex}.{QUESTIONS}.{qindex}.{ANSWERS}.{player_id}"
    success = mongo.push("session", session_id, array, answer_id)
    if not success:
        return fail(f"Failed to add add {answer_id} for player {player_id}")

    mongo.incr_state(session_id)

    return succeed(answer)
Пример #27
0
def create_question(data):
    created = mongo.create("question", data)
    if not created:
        return fail("Failed to create question")
    return succeed(created)
Пример #28
0
def create_answer(data):
    success = mongo.create("answer", data)
    if not success:
        return fail("Failed to create answer")
    return succeed(success)