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())
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}"))
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}"))
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}"))
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
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}"))
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}"))
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)
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)
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)