Example #1
0
def respond_to_friend_invite(requester_username, invited_id, decision):
    requester_id = get_user_ids([requester_username])[0]
    add_row("friends",
            requester_id=requester_id,
            invited_id=invited_id,
            status=decision,
            timestamp=time.time())
Example #2
0
def get_fulfilled_orders_table():
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}"))
Example #3
0
def get_pending_orders_table():
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}"))
Example #4
0
def get_current_balances_table():
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{CURRENT_BALANCES_PREFIX}"))
Example #5
0
def add_game(creator_id: int,
             title: str,
             game_mode: str,
             duration: int,
             benchmark: str,
             stakes: str = None,
             buy_in: float = None,
             side_bets_perc=None,
             side_bets_period: str = None,
             invitees: List[str] = None,
             invite_window: int = None,
             email_invitees: List[str] = None):
    if invitees is None:
        invitees = []

    if email_invitees is None:
        email_invitees = []

    opened_at = time.time()
    invite_window_posix = None
    if invite_window is not None:
        invite_window_posix = opened_at + int(invite_window) * SECONDS_IN_A_DAY

    game_id = add_row("games",
                      creator_id=creator_id,
                      title=title,
                      game_mode=game_mode,
                      duration=duration,
                      benchmark=benchmark,
                      buy_in=buy_in,
                      side_bets_perc=side_bets_perc,
                      side_bets_period=side_bets_period,
                      invite_window=invite_window_posix,
                      stakes=stakes)

    user_ids = [creator_id]
    if invitees:
        user_ids += get_user_ids(invitees)

    matched_ids = []
    if email_invitees:
        matched_ids = get_user_ids_from_passed_emails(email_invitees)
    user_ids = list(set(user_ids).union(set(matched_ids)))
    create_game_invites_entries(game_id, creator_id, user_ids, opened_at)

    if game_mode in ["public", "multi_player"]:
        add_row("game_status",
                game_id=game_id,
                status="pending",
                timestamp=opened_at,
                users=user_ids)
        for email in email_invitees:
            email_game_invitation(creator_id, email, game_id)
    else:
        kick_off_game(game_id, user_ids, opened_at)

    return game_id
Example #6
0
def order_performance_chart():
    """This endpoints works exactly the same as balances_chart. See above for details
    """
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}"))
Example #7
0
def balances_chart():
    """Be default, the frontend will load with username = null for the chart selector dropdown, and we'll show them
    their own chart. When the user proactively picks a username to checkout, this will be sent in the POST request to
    this endpoint and used to pull up the appropriate chart
    """
    game_id = request.json.get("game_id")
    username = request.json.get("username")
    if username:
        user_id = get_user_ids([username])[0]
    else:
        user_id = decode_token(request)
    return jsonify(s3_cache.unpack_s3_json(f"{game_id}/{user_id}/{BALANCES_CHART_PREFIX}"))
Example #8
0
def invite_users_to_pending_game():
    user_id = decode_token(request)
    game_id = request.json.get("game_id")
    invitee_emails = request.json.get("email_invitees")
    invitees = request.json.get("invitees")

    if invitees is not None:
        invited_ids = get_user_ids(invitees)
        for invited_id in invited_ids:
            add_user_via_platform(game_id, invited_id)

    if invitee_emails is not None:
        try:
            for email in invitee_emails:
                add_user_via_email(game_id, user_id, email)
        except InvalidEmailError as e:
            make_response(f"{email} : {str(e)}", 400)

    return make_response(INVITED_MORE_USERS_MESSAGE, 200)
Example #9
0
def send_friend_request():
    user_id = decode_token(request)
    invited_username = request.json.get("friend_invitee")
    invited_id = get_user_ids([invited_username])[0]
    invite_friend(user_id, invited_id)
    return make_response(FRIEND_INVITE_SENT_MSG, 200)
Example #10
0
    def _start_game_runner(self, start_time, game_id):
        s3_cache.flushall()
        user_statuses = get_user_invite_statuses_for_pending_game(game_id)
        pending_user_usernames = [
            x["username"] for x in user_statuses if x["status"] == "invited"
        ]
        pending_user_ids = get_user_ids(pending_user_usernames)

        # get all user IDs for the game. For this test case everyone is going or accept
        with self.engine.connect() as conn:
            result = conn.execute(
                "SELECT DISTINCT user_id FROM game_invites WHERE game_id = %s",
                game_id).fetchall()
        all_ids = [x[0] for x in result]
        self.user_id = all_ids[0]

        # all users accept their game invite
        with patch("backend.logic.games.time") as game_time_mock, patch(
                "backend.logic.base.time") as base_time_mock:
            game_time_mock.time.return_value = start_time
            time = Mock()
            time.time.return_value = base_time_mock.time.return_value = start_time
            for user_id in pending_user_ids:
                respond_to_game_invite(game_id, user_id, "joined", time.time())

        # check that we have the balances that we expect
        sql = "SELECT balance, user_id from game_balances WHERE game_id = %s;"
        with self.engine.connect() as conn:
            df = pd.read_sql(sql, conn, params=[game_id])
        self.assertTrue(df.shape, (0, 2))

        sql = "SELECT balance, user_id from game_balances WHERE game_id = %s;"
        with self.engine.connect() as conn:
            df = pd.read_sql(sql, conn, params=[game_id])
        self.assertTrue(df.shape, (4, 2))

        # a couple things should have just happened here. We expect to have the following assets available to us
        # now in our redis cache: (1) an empty open orders table for each user, (2) an empty current balances table for
        # each user, (3) an empty field chart for each user, (4) an empty field chart, and (5) an initial game stats
        # list
        cache_keys = s3_cache.keys()
        self.assertIn(f"{game_id}/{LEADERBOARD_PREFIX}", cache_keys)
        self.assertIn(f"{game_id}/{FIELD_CHART_PREFIX}", cache_keys)
        for user_id in all_ids:
            self.assertIn(f"{game_id}/{user_id}/{CURRENT_BALANCES_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{PENDING_ORDERS_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{FULFILLED_ORDER_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{BALANCES_CHART_PREFIX}",
                          cache_keys)
            self.assertIn(f"{game_id}/{user_id}/{ORDER_PERF_CHART_PREFIX}",
                          cache_keys)

        # quickly verify the structure of the chart assets. They should be blank, with transparent colors
        field_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{FIELD_CHART_PREFIX}")
        self.assertEqual(len(field_chart["datasets"]), len(all_ids))
        chart_colors = [x["backgroundColor"] for x in field_chart["datasets"]]
        self.assertTrue(all([x == NULL_RGBA for x in chart_colors]))

        leaderboard = s3_cache.unpack_s3_json(
            f"{game_id}/{LEADERBOARD_PREFIX}")
        self.assertEqual(len(leaderboard["records"]), len(all_ids))
        self.assertTrue(
            all([
                x["cash_balance"] == STARTING_VIRTUAL_CASH
                for x in leaderboard["records"]
            ]))

        a_current_balance_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{CURRENT_BALANCES_PREFIX}")
        self.assertEqual(a_current_balance_table["data"], [])

        an_open_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{PENDING_ORDERS_PREFIX}")
        self.assertEqual(an_open_orders_table["data"], [])
        a_fulfilled_orders_table = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{FULFILLED_ORDER_PREFIX}")
        self.assertEqual(a_fulfilled_orders_table["data"], [])

        a_balances_chart = s3_cache.unpack_s3_json(
            f"{game_id}/{self.user_id}/{BALANCES_CHART_PREFIX}")
        self.assertEqual(len(a_balances_chart["datasets"]), 1)
        self.assertEqual(a_balances_chart["datasets"][0]["label"], "Cash")
        self.assertEqual(a_balances_chart["datasets"][0]["backgroundColor"],
                         NULL_RGBA)

        # now have a user put an order. It should go straight to the queue and be reflected in the open orders table,
        # but they should not have any impact on the user's balances if the order is placed outside of trading day
        self.stock_pick = "TSLA"
        self.market_price = 1_000
        with patch("backend.logic.games.time") as game_time_mock, patch(
                "backend.logic.base.time") as base_time_mock:
            game_time_mock.time.side_effect = [start_time + 1] * 2
            base_time_mock.time.return_value = start_time + 1
            stock_pick = self.stock_pick
            cash_balance = get_current_game_cash_balance(self.user_id, game_id)
            current_holding = get_current_stock_holding(
                self.user_id, game_id, stock_pick)
            order_id = place_order(user_id=self.user_id,
                                   game_id=game_id,
                                   symbol=self.stock_pick,
                                   buy_or_sell="buy",
                                   cash_balance=cash_balance,
                                   current_holding=current_holding,
                                   order_type="market",
                                   quantity_type="Shares",
                                   market_price=self.market_price,
                                   amount=1,
                                   time_in_force="day")
            serialize_and_pack_pending_orders(game_id, self.user_id)
            add_fulfilled_order_entry(game_id, self.user_id, order_id)
            serialize_and_pack_portfolio_details(game_id, self.user_id)