def set_username(): """Invoke to set a user's username during welcome and subsequently when they want to change it """ user_id = decode_token(request) user_email = decode_token(request, "email") candidate_username = request.json["username"] if candidate_username is None: make_response(MISSING_USERNAME_ERROR_MSG, 400) session_token = register_username_with_token(user_id, user_email, candidate_username) if session_token is not None: resp = make_response() resp.set_cookie("session_token", session_token, httponly=True, samesite=None, secure=True) return resp return make_response(USERNAME_TAKE_ERROR_MSG, 400)
def game_defaults(): """Returns information to the MakeGame form that contains the defaults and optional values that it needs to render fields correctly """ user_id = decode_token(request) game_mode = request.json.get("game_mode") default_title = make_random_game_title() # TODO: Enforce uniqueness at some point here friend_details = get_friend_details(user_id)["friends"] available_invitees = [x["username"] for x in friend_details] resp = dict( title=default_title, duration=DEFAULT_GAME_DURATION, benchmark=DEFAULT_BENCHMARK, benchmarks=BENCHMARKS, ) if game_mode == "multi_player": resp.update(dict( buy_in=DEFAULT_BUYIN, side_bets_perc=DEFAULT_SIDEBET_PERCENT, side_bets_period=DEFAULT_SIDEBET_PERIOD, sidebet_periods=SIDE_BET_PERIODS, available_invitees=available_invitees, invite_window=DEFAULT_INVITE_OPEN_WINDOW, stakes=DEFAULT_STAKES, stakes_options=STAKES )) return jsonify(resp)
def home(): """Return some basic information about the user's profile, games, and bets in order to populate the landing page""" user_id = decode_token(request) user_info = get_user_information(user_id) user_info["game_info"] = get_game_info_for_user(user_id) return jsonify(user_info)
def get_cash_balances(): game_id = request.json.get("game_id") user_id = decode_token(request) cash_balance = get_current_game_cash_balance(user_id, game_id) outstanding_buy_order_value = get_pending_buy_order_value(user_id, game_id) buying_power = cash_balance - outstanding_buy_order_value return jsonify({"cash_balance": cash_balance, "buying_power": buying_power})
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 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_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 api_game_info(): user_id = decode_token(request) game_id = request.json.get("game_id") game_info = get_game_info(game_id) game_info["is_host"] = game_info["creator_id"] == user_id game_info["user_status"] = get_user_invite_status_for_game(game_id, user_id) if game_info["game_status"] in ["active", "finished"]: game_info["leaderboard"] = s3_cache.unpack_s3_json(f"{game_id}/{LEADERBOARD_PREFIX}")["records"] return jsonify(game_info)
def respond_to_friend_request(): """Note to frontend developers working with this endpoint: the acceptable response options are 'accepted' and 'declined' """ user_id = decode_token(request) requester_username = request.json.get("requester_username") decision = request.json.get("decision") respond_to_friend_invite(requester_username, user_id, decision) return make_response(FRIEND_INVITE_RESPONSE_MSG, 200)
def invite_friend_by_email(): user_id = decode_token(request) emails = request.json.get('friend_emails') for email in emails: try: email_platform_invitation(user_id, email) except InvalidEmailError as e: make_response(f"{email} : {str(e)}", 400) return make_response(EMAIL_SENT_MESSAGE, 200)
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 create_game(): user_id = decode_token(request) game_settings = request.json game_id = add_game( user_id, game_settings["title"], game_settings["game_mode"], game_settings["duration"], game_settings["benchmark"], game_settings.get("stakes"), game_settings.get("buy_in"), game_settings.get("side_bets_perc"), game_settings.get("side_bets_period"), game_settings.get("invitees"), game_settings.get("invite_window"), game_settings.get("email_invitees") ) return jsonify({"game_id": game_id})
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 process_payment(): user_id = decode_token(request) game_id = request.json.get("game_id") amount = request.json["amount"] currency = request.json["currency"] processor = request.json["processor"] payment_type = request.json["type"] payer_email = request.json.get("payer_email") uuid = request.json.get("uuid") winner_table_id = request.json.get("winner_table_id") # get payment profile id profile_id = check_payment_profile(user_id, processor, uuid, payer_email) # register payment add_row("payments", game_id=game_id, user_id=user_id, profile_id=profile_id, winner_table_id=winner_table_id, type=payment_type, amount=amount, currency=currency, direction='inflow', timestamp=time.time()) return make_response("Payment processed", 200)
def api_place_order(): """Placing an order involves several layers of conditional logic: is this is a buy or sell order? Stop, limit, or market? Do we either have the adequate cash on hand, or enough of a position in the stock for this order to be valid? Here an order_ticket from the frontend--along with the user_id tacked on during the API call--gets decoded, checked for validity, and booked. Market orders are fulfilled in the same step. Stop/limit orders are monitored on an ongoing basis by the celery schedule and book as their requirements are satisfies""" user_id = decode_token(request) order_ticket = request.json game_id = order_ticket["game_id"] stop_limit_price = order_ticket.get("stop_limit_price") if stop_limit_price: stop_limit_price = float(stop_limit_price) try: symbol = order_ticket["symbol"].upper() # ensure upper casing market_price, last_updated = fetch_price(symbol) async_cache_price.delay(symbol, market_price, last_updated) cash_balance = get_current_game_cash_balance(user_id, game_id) current_holding = get_current_stock_holding(user_id, game_id, symbol) order_id = place_order( user_id, game_id, symbol, order_ticket["buy_or_sell"], cash_balance, current_holding, order_ticket["order_type"], order_ticket["quantity_type"], market_price, float(order_ticket["amount"]), order_ticket["time_in_force"], stop_limit_price) except Exception as e: return make_response(str(e), 400) serialize_and_pack_pending_orders(game_id, user_id) add_fulfilled_order_entry(game_id, user_id, order_id) serialize_and_pack_portfolio_details(game_id, user_id) return make_response(ORDER_PLACED_MESSAGE, 200)
def decorated(*args, **kwargs): user_email = decode_token(request, "email") if user_email not in ADMIN_USERS: return make_response(ADMIN_BLOCK_MSG, 401) return f(*args, **kwargs)
def get_transactions_table(): game_id = request.json.get("game_id") user_id = decode_token(request) return jsonify(get_downloadable_transactions_table(game_id, user_id))
def get_user_info(): user_id = decode_token(request) return jsonify(get_user_information(user_id))
def api_respond_to_game_invite(): user_id = decode_token(request) game_id = request.json.get("game_id") decision = request.json.get("decision") respond_to_game_invite(game_id, user_id, decision, time.time()) return make_response(GAME_RESPONSE_MSG, 200)
def api_leave_game(): user_id = decode_token(request) game_id = request.json.get("game_id") leave_game(game_id, user_id) return make_response(LEAVE_GAME_MESSAGE, 200)
def api_suggest_symbols(): user_id = decode_token(request) game_id = request.json["game_id"] text = request.json["text"] buy_or_sell = request.json["buy_or_sell"] return jsonify(suggest_symbols(game_id, user_id, text, buy_or_sell))
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 suggest_friend_invites(): user_id = decode_token(request) text = request.json.get("text") return jsonify(suggest_friends(user_id, text))
def get_list_of_friend_invites(): user_id = decode_token(request) return jsonify(get_friend_invites_list(user_id))
def get_list_of_friends(): user_id = decode_token(request) return jsonify(get_friend_details(user_id))