Jon Solow
commited on
Commit
·
050fd9f
1
Parent(s):
f66425a
Get a client per session to help with expiry
Browse files- src/data_storage.py +15 -25
- src/login.py +7 -7
- src/pages/10_Set_Your_Lineup.py +2 -2
- src/pages/11_Scoreboard.py +2 -2
- src/pages/99_Admin.py +5 -3
- src/queries/supabase_db/client.py +3 -1
- src/shared_page.py +9 -1
src/data_storage.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
| 1 |
-
from postgrest.exceptions import APIError
|
| 2 |
from secrets import token_urlsafe
|
| 3 |
import streamlit as st
|
| 4 |
-
import time
|
| 5 |
|
| 6 |
-
from
|
| 7 |
|
| 8 |
|
| 9 |
USERS_TABLE = "npcs_users"
|
|
@@ -11,15 +9,7 @@ USER_ROSTERS_TABLE = "npcs_user_rosters"
|
|
| 11 |
TOKENS_TABLE = "npcs_tokens"
|
| 12 |
|
| 13 |
|
| 14 |
-
|
| 15 |
-
user_count = supabase_client.table(USERS_TABLE).select("*", count="exact").execute().count
|
| 16 |
-
except APIError:
|
| 17 |
-
# automatic retry
|
| 18 |
-
time.sleep(0.5)
|
| 19 |
-
user_count = supabase_client.table(USERS_TABLE).select("*", count="exact").execute().count
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def update_selection(user_id: str | int, position_id: str, player_id: str):
|
| 23 |
existing_record = (
|
| 24 |
supabase_client.table(USER_ROSTERS_TABLE)
|
| 25 |
.select("*")
|
|
@@ -42,7 +32,7 @@ def update_selection(user_id: str | int, position_id: str, player_id: str):
|
|
| 42 |
)
|
| 43 |
|
| 44 |
|
| 45 |
-
def get_user_team(user_id):
|
| 46 |
team = (
|
| 47 |
supabase_client.table(USER_ROSTERS_TABLE)
|
| 48 |
.select("position_id", "player_id")
|
|
@@ -56,11 +46,11 @@ def get_user_team(user_id):
|
|
| 56 |
return {}
|
| 57 |
|
| 58 |
|
| 59 |
-
def add_new_user(email: str, name: str):
|
| 60 |
(supabase_client.table(USERS_TABLE).insert({"email": email.lower(), "name": name}).execute())
|
| 61 |
|
| 62 |
|
| 63 |
-
def get_user(user_id: int):
|
| 64 |
user_data = (
|
| 65 |
supabase_client.table("npcs_users").select("user_id", "email", "name").eq("user_id", user_id).execute().data
|
| 66 |
)
|
|
@@ -69,7 +59,7 @@ def get_user(user_id: int):
|
|
| 69 |
return user_data[0]
|
| 70 |
|
| 71 |
|
| 72 |
-
def get_user_id_if_email_exists(email: str) -> int | None:
|
| 73 |
query_result = supabase_client.table(USERS_TABLE).select("user_id").eq("email", email.lower()).execute().data
|
| 74 |
if query_result:
|
| 75 |
user_id = query_result[0]["user_id"]
|
|
@@ -78,7 +68,7 @@ def get_user_id_if_email_exists(email: str) -> int | None:
|
|
| 78 |
return user_id
|
| 79 |
|
| 80 |
|
| 81 |
-
def is_admin(user_id: int | None):
|
| 82 |
if user_id is None:
|
| 83 |
return False
|
| 84 |
query_result = supabase_client.table(USERS_TABLE).select("admin").eq("user_id", user_id).execute().data
|
|
@@ -87,7 +77,7 @@ def is_admin(user_id: int | None):
|
|
| 87 |
return False
|
| 88 |
|
| 89 |
|
| 90 |
-
def login_by_token(token: str):
|
| 91 |
# returns true if logged in successfully
|
| 92 |
query_result = supabase_client.table(TOKENS_TABLE).select("user_id").eq("token", token).execute().data
|
| 93 |
if query_result:
|
|
@@ -98,24 +88,24 @@ def login_by_token(token: str):
|
|
| 98 |
return user_id
|
| 99 |
|
| 100 |
|
| 101 |
-
def create_new_token_for_user(user_id: int, existing_user: bool = False):
|
| 102 |
# returns true if logged in successfully
|
| 103 |
token = token_urlsafe(32)
|
| 104 |
supabase_client.table(TOKENS_TABLE).upsert({"user_id": user_id, "token": token}).execute()
|
| 105 |
return token
|
| 106 |
|
| 107 |
|
| 108 |
-
def get_all_users(columns_included: list[str] = ["user_id", "name", "email"]):
|
| 109 |
all_users = supabase_client.table(USERS_TABLE).select(*columns_included).execute().data
|
| 110 |
return all_users
|
| 111 |
|
| 112 |
|
| 113 |
-
def get_all_rosters() -> list[dict[str, int | str]]:
|
| 114 |
all_rosters = supabase_client.table(USER_ROSTERS_TABLE).select("user_id", "position_id", "player_id").execute().data
|
| 115 |
return all_rosters
|
| 116 |
|
| 117 |
|
| 118 |
-
def get_all_rosters_week(week: int) -> list[dict[str, int | str]]:
|
| 119 |
week_rosters = (
|
| 120 |
supabase_client.table(USER_ROSTERS_TABLE)
|
| 121 |
.select("user_id", "position_id", "player_id")
|
|
@@ -126,14 +116,14 @@ def get_all_rosters_week(week: int) -> list[dict[str, int | str]]:
|
|
| 126 |
return week_rosters
|
| 127 |
|
| 128 |
|
| 129 |
-
def migrate_players_from_week(migrate_from_week: int):
|
| 130 |
"""
|
| 131 |
Migrate players from the week = migrate_from_week to the week = migrate_from_week + 1
|
| 132 |
"""
|
| 133 |
-
rosters = get_all_rosters_week(migrate_from_week)
|
| 134 |
for roster_slot_map in rosters:
|
| 135 |
position_id = str(roster_slot_map["position_id"])
|
| 136 |
player_id = str(roster_slot_map["player_id"])
|
| 137 |
user_id = int(roster_slot_map["user_id"])
|
| 138 |
new_position_id = f"""{migrate_from_week + 1}-{position_id.split("-", 1)[1]}"""
|
| 139 |
-
update_selection(user_id, new_position_id, player_id)
|
|
|
|
|
|
|
| 1 |
from secrets import token_urlsafe
|
| 2 |
import streamlit as st
|
|
|
|
| 3 |
|
| 4 |
+
from supabase import Client
|
| 5 |
|
| 6 |
|
| 7 |
USERS_TABLE = "npcs_users"
|
|
|
|
| 9 |
TOKENS_TABLE = "npcs_tokens"
|
| 10 |
|
| 11 |
|
| 12 |
+
def update_selection(user_id: str | int, position_id: str, player_id: str, supabase_client: Client):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
existing_record = (
|
| 14 |
supabase_client.table(USER_ROSTERS_TABLE)
|
| 15 |
.select("*")
|
|
|
|
| 32 |
)
|
| 33 |
|
| 34 |
|
| 35 |
+
def get_user_team(user_id, supabase_client: Client):
|
| 36 |
team = (
|
| 37 |
supabase_client.table(USER_ROSTERS_TABLE)
|
| 38 |
.select("position_id", "player_id")
|
|
|
|
| 46 |
return {}
|
| 47 |
|
| 48 |
|
| 49 |
+
def add_new_user(email: str, name: str, supabase_client: Client):
|
| 50 |
(supabase_client.table(USERS_TABLE).insert({"email": email.lower(), "name": name}).execute())
|
| 51 |
|
| 52 |
|
| 53 |
+
def get_user(user_id: int, supabase_client: Client):
|
| 54 |
user_data = (
|
| 55 |
supabase_client.table("npcs_users").select("user_id", "email", "name").eq("user_id", user_id).execute().data
|
| 56 |
)
|
|
|
|
| 59 |
return user_data[0]
|
| 60 |
|
| 61 |
|
| 62 |
+
def get_user_id_if_email_exists(email: str, supabase_client: Client) -> int | None:
|
| 63 |
query_result = supabase_client.table(USERS_TABLE).select("user_id").eq("email", email.lower()).execute().data
|
| 64 |
if query_result:
|
| 65 |
user_id = query_result[0]["user_id"]
|
|
|
|
| 68 |
return user_id
|
| 69 |
|
| 70 |
|
| 71 |
+
def is_admin(user_id: int | None, supabase_client: Client):
|
| 72 |
if user_id is None:
|
| 73 |
return False
|
| 74 |
query_result = supabase_client.table(USERS_TABLE).select("admin").eq("user_id", user_id).execute().data
|
|
|
|
| 77 |
return False
|
| 78 |
|
| 79 |
|
| 80 |
+
def login_by_token(token: str, supabase_client: Client):
|
| 81 |
# returns true if logged in successfully
|
| 82 |
query_result = supabase_client.table(TOKENS_TABLE).select("user_id").eq("token", token).execute().data
|
| 83 |
if query_result:
|
|
|
|
| 88 |
return user_id
|
| 89 |
|
| 90 |
|
| 91 |
+
def create_new_token_for_user(user_id: int, supabase_client: Client, existing_user: bool = False):
|
| 92 |
# returns true if logged in successfully
|
| 93 |
token = token_urlsafe(32)
|
| 94 |
supabase_client.table(TOKENS_TABLE).upsert({"user_id": user_id, "token": token}).execute()
|
| 95 |
return token
|
| 96 |
|
| 97 |
|
| 98 |
+
def get_all_users(supabase_client: Client, columns_included: list[str] = ["user_id", "name", "email"]):
|
| 99 |
all_users = supabase_client.table(USERS_TABLE).select(*columns_included).execute().data
|
| 100 |
return all_users
|
| 101 |
|
| 102 |
|
| 103 |
+
def get_all_rosters(supabase_client: Client) -> list[dict[str, int | str]]:
|
| 104 |
all_rosters = supabase_client.table(USER_ROSTERS_TABLE).select("user_id", "position_id", "player_id").execute().data
|
| 105 |
return all_rosters
|
| 106 |
|
| 107 |
|
| 108 |
+
def get_all_rosters_week(week: int, supabase_client: Client) -> list[dict[str, int | str]]:
|
| 109 |
week_rosters = (
|
| 110 |
supabase_client.table(USER_ROSTERS_TABLE)
|
| 111 |
.select("user_id", "position_id", "player_id")
|
|
|
|
| 116 |
return week_rosters
|
| 117 |
|
| 118 |
|
| 119 |
+
def migrate_players_from_week(migrate_from_week: int, supabase_client: Client):
|
| 120 |
"""
|
| 121 |
Migrate players from the week = migrate_from_week to the week = migrate_from_week + 1
|
| 122 |
"""
|
| 123 |
+
rosters = get_all_rosters_week(migrate_from_week, supabase_client)
|
| 124 |
for roster_slot_map in rosters:
|
| 125 |
position_id = str(roster_slot_map["position_id"])
|
| 126 |
player_id = str(roster_slot_map["player_id"])
|
| 127 |
user_id = int(roster_slot_map["user_id"])
|
| 128 |
new_position_id = f"""{migrate_from_week + 1}-{position_id.split("-", 1)[1]}"""
|
| 129 |
+
update_selection(user_id, new_position_id, player_id, supabase_client)
|
src/login.py
CHANGED
|
@@ -82,10 +82,10 @@ def generate_new_token_request():
|
|
| 82 |
if not check_email(email := st.session_state["reset_token_user_email"]):
|
| 83 |
st.warning("Sorry email is invalid. Please try a valid email address.")
|
| 84 |
return
|
| 85 |
-
user_id = get_user_id_if_email_exists(email)
|
| 86 |
if not user_id:
|
| 87 |
return
|
| 88 |
-
token = create_new_token_for_user(user_id, existing_user=True)
|
| 89 |
insert_new_token_to_sheet(email, token)
|
| 90 |
|
| 91 |
st.info("Request submitted. Please check your email for a login url with a few minutes.")
|
|
@@ -106,10 +106,10 @@ def insert_new_token_to_sheet(email: str, token: str):
|
|
| 106 |
|
| 107 |
|
| 108 |
def create_new_user_request(email: str, name: str):
|
| 109 |
-
add_new_user(email, name)
|
| 110 |
-
user_id = get_user_id_if_email_exists(email)
|
| 111 |
assert user_id
|
| 112 |
-
token = create_new_token_for_user(user_id)
|
| 113 |
insert_new_token_to_sheet(email, token)
|
| 114 |
st.info("New user request submitted. Please check your email for a login url with a few minutes.")
|
| 115 |
|
|
@@ -123,7 +123,7 @@ def new_user_submitted():
|
|
| 123 |
st.warning("No name entered. Please enter your name for display.")
|
| 124 |
return
|
| 125 |
|
| 126 |
-
if get_user_id_if_email_exists(email):
|
| 127 |
st.warning(
|
| 128 |
"User with that email already exists. If you would like a new login url, please click the New Login URL button."
|
| 129 |
)
|
|
@@ -149,7 +149,7 @@ def get_logged_in_user_name_email() -> tuple[str | None, str | None]:
|
|
| 149 |
# if not logged
|
| 150 |
return (None, None)
|
| 151 |
|
| 152 |
-
user_info_map = get_user(user_id)
|
| 153 |
email = user_info_map.get("email")
|
| 154 |
name = user_info_map.get("name")
|
| 155 |
return email, name
|
|
|
|
| 82 |
if not check_email(email := st.session_state["reset_token_user_email"]):
|
| 83 |
st.warning("Sorry email is invalid. Please try a valid email address.")
|
| 84 |
return
|
| 85 |
+
user_id = get_user_id_if_email_exists(email, st.session_state["db_client"])
|
| 86 |
if not user_id:
|
| 87 |
return
|
| 88 |
+
token = create_new_token_for_user(user_id, st.session_state["db_client"], existing_user=True)
|
| 89 |
insert_new_token_to_sheet(email, token)
|
| 90 |
|
| 91 |
st.info("Request submitted. Please check your email for a login url with a few minutes.")
|
|
|
|
| 106 |
|
| 107 |
|
| 108 |
def create_new_user_request(email: str, name: str):
|
| 109 |
+
add_new_user(email, name, st.session_state["db_client"])
|
| 110 |
+
user_id = get_user_id_if_email_exists(email, st.session_state["db_client"])
|
| 111 |
assert user_id
|
| 112 |
+
token = create_new_token_for_user(user_id, st.session_state["db_client"])
|
| 113 |
insert_new_token_to_sheet(email, token)
|
| 114 |
st.info("New user request submitted. Please check your email for a login url with a few minutes.")
|
| 115 |
|
|
|
|
| 123 |
st.warning("No name entered. Please enter your name for display.")
|
| 124 |
return
|
| 125 |
|
| 126 |
+
if get_user_id_if_email_exists(email, st.session_state["db_client"]):
|
| 127 |
st.warning(
|
| 128 |
"User with that email already exists. If you would like a new login url, please click the New Login URL button."
|
| 129 |
)
|
|
|
|
| 149 |
# if not logged
|
| 150 |
return (None, None)
|
| 151 |
|
| 152 |
+
user_info_map = get_user(user_id, st.session_state["db_client"])
|
| 153 |
email = user_info_map.get("email")
|
| 154 |
name = user_info_map.get("name")
|
| 155 |
return email, name
|
src/pages/10_Set_Your_Lineup.py
CHANGED
|
@@ -96,7 +96,7 @@ def position_cell(
|
|
| 96 |
|
| 97 |
|
| 98 |
def update_and_save_selection(pos_label: str, selection_id: str):
|
| 99 |
-
update_selection(st.session_state["logged_in_user"], pos_label, selection_id)
|
| 100 |
st.rerun()
|
| 101 |
|
| 102 |
|
|
@@ -140,7 +140,7 @@ def get_page():
|
|
| 140 |
if st.button("Refresh Data"):
|
| 141 |
st.rerun()
|
| 142 |
try:
|
| 143 |
-
existing_selections = get_user_team(st.session_state["logged_in_user"])
|
| 144 |
except Exception:
|
| 145 |
st.write("Sorry error occurred loading team. Please try refreshing page.")
|
| 146 |
st.stop()
|
|
|
|
| 96 |
|
| 97 |
|
| 98 |
def update_and_save_selection(pos_label: str, selection_id: str):
|
| 99 |
+
update_selection(st.session_state["logged_in_user"], pos_label, selection_id, st.session_state["db_client"])
|
| 100 |
st.rerun()
|
| 101 |
|
| 102 |
|
|
|
|
| 140 |
if st.button("Refresh Data"):
|
| 141 |
st.rerun()
|
| 142 |
try:
|
| 143 |
+
existing_selections = get_user_team(st.session_state["logged_in_user"], st.session_state["db_client"])
|
| 144 |
except Exception:
|
| 145 |
st.write("Sorry error occurred loading team. Please try refreshing page.")
|
| 146 |
st.stop()
|
src/pages/11_Scoreboard.py
CHANGED
|
@@ -16,7 +16,7 @@ from stats import get_scores_map
|
|
| 16 |
|
| 17 |
def get_users_df():
|
| 18 |
columns = ["user_id", "name"]
|
| 19 |
-
all_users = pd.DataFrame(get_all_users(columns_included=columns), columns=columns)
|
| 20 |
return all_users
|
| 21 |
|
| 22 |
|
|
@@ -24,7 +24,7 @@ def get_users_df():
|
|
| 24 |
def load_masked_rosters() -> dict[int, dict[str, PlayerOption]]:
|
| 25 |
options_map = get_map_week_player_id_option()
|
| 26 |
roster_user_position_map: dict[int, dict[str, PlayerOption]] = {}
|
| 27 |
-
for roster_slot_map in get_all_rosters():
|
| 28 |
position_id = str(roster_slot_map["position_id"])
|
| 29 |
player_id = str(roster_slot_map["player_id"])
|
| 30 |
user_id = int(roster_slot_map["user_id"])
|
|
|
|
| 16 |
|
| 17 |
def get_users_df():
|
| 18 |
columns = ["user_id", "name"]
|
| 19 |
+
all_users = pd.DataFrame(get_all_users(st.session_state["db_client"], columns_included=columns), columns=columns)
|
| 20 |
return all_users
|
| 21 |
|
| 22 |
|
|
|
|
| 24 |
def load_masked_rosters() -> dict[int, dict[str, PlayerOption]]:
|
| 25 |
options_map = get_map_week_player_id_option()
|
| 26 |
roster_user_position_map: dict[int, dict[str, PlayerOption]] = {}
|
| 27 |
+
for roster_slot_map in get_all_rosters(st.session_state["db_client"]):
|
| 28 |
position_id = str(roster_slot_map["position_id"])
|
| 29 |
player_id = str(roster_slot_map["player_id"])
|
| 30 |
user_id = int(roster_slot_map["user_id"])
|
src/pages/99_Admin.py
CHANGED
|
@@ -7,7 +7,9 @@ from data_storage import add_new_user, is_admin, migrate_players_from_week
|
|
| 7 |
|
| 8 |
|
| 9 |
def admin_add_new_user():
|
| 10 |
-
add_new_user(
|
|
|
|
|
|
|
| 11 |
|
| 12 |
|
| 13 |
def admin_add_new_user_form():
|
|
@@ -27,7 +29,7 @@ def migrate_players_week():
|
|
| 27 |
st.text_input("Enter week to confirm", key="week_migrate_from")
|
| 28 |
if st.button("Migrate Week"):
|
| 29 |
if st.session_state.get("week_migrate_from") == str(week_migrate_from):
|
| 30 |
-
migrate_players_from_week(week_migrate_from)
|
| 31 |
st.warning("Week migrated")
|
| 32 |
else:
|
| 33 |
st.warning("Must confirm migration by entering matching week")
|
|
@@ -37,7 +39,7 @@ def get_page():
|
|
| 37 |
page_title = "Admin"
|
| 38 |
st.set_page_config(page_title=page_title, page_icon=DEFAULT_ICON, layout="wide")
|
| 39 |
common_page_config()
|
| 40 |
-
if not is_admin(st.session_state.get("logged_in_user")):
|
| 41 |
st.write("Not authorized")
|
| 42 |
st.stop()
|
| 43 |
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
def admin_add_new_user():
|
| 10 |
+
add_new_user(
|
| 11 |
+
st.session_state["admin_new_user_email"], st.session_state["admin_new_user_name"], st.session_state["db_client"]
|
| 12 |
+
)
|
| 13 |
|
| 14 |
|
| 15 |
def admin_add_new_user_form():
|
|
|
|
| 29 |
st.text_input("Enter week to confirm", key="week_migrate_from")
|
| 30 |
if st.button("Migrate Week"):
|
| 31 |
if st.session_state.get("week_migrate_from") == str(week_migrate_from):
|
| 32 |
+
migrate_players_from_week(week_migrate_from, st.session_state["db_client"])
|
| 33 |
st.warning("Week migrated")
|
| 34 |
else:
|
| 35 |
st.warning("Must confirm migration by entering matching week")
|
|
|
|
| 39 |
page_title = "Admin"
|
| 40 |
st.set_page_config(page_title=page_title, page_icon=DEFAULT_ICON, layout="wide")
|
| 41 |
common_page_config()
|
| 42 |
+
if not is_admin(st.session_state.get("logged_in_user"), st.session_state["db_client"]):
|
| 43 |
st.write("Not authorized")
|
| 44 |
st.stop()
|
| 45 |
|
src/queries/supabase_db/client.py
CHANGED
|
@@ -5,4 +5,6 @@ from supabase import create_client, Client
|
|
| 5 |
url: str = str(os.environ.get("SUPABASE_URL"))
|
| 6 |
key: str = str(os.environ.get("SUPABASE_KEY"))
|
| 7 |
|
| 8 |
-
|
|
|
|
|
|
|
|
|
| 5 |
url: str = str(os.environ.get("SUPABASE_URL"))
|
| 6 |
key: str = str(os.environ.get("SUPABASE_KEY"))
|
| 7 |
|
| 8 |
+
|
| 9 |
+
def get_new_supabase_client() -> Client:
|
| 10 |
+
return create_client(url, key)
|
src/shared_page.py
CHANGED
|
@@ -2,6 +2,7 @@ import os
|
|
| 2 |
import streamlit as st
|
| 3 |
|
| 4 |
from queries.nflverse.github_data import load_assets
|
|
|
|
| 5 |
from data_storage import login_by_token
|
| 6 |
|
| 7 |
|
|
@@ -24,13 +25,20 @@ def login_token_arg_if_exists():
|
|
| 24 |
url_params = st.query_params
|
| 25 |
if arg_token := url_params.get("token"):
|
| 26 |
try:
|
| 27 |
-
login_by_token(arg_token)
|
| 28 |
except Exception:
|
| 29 |
st.write("Sorry, error logging in. Please refresh to try again.")
|
| 30 |
st.stop()
|
| 31 |
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
def common_page_config():
|
| 34 |
local_css()
|
| 35 |
load_assets()
|
|
|
|
| 36 |
login_token_arg_if_exists()
|
|
|
|
| 2 |
import streamlit as st
|
| 3 |
|
| 4 |
from queries.nflverse.github_data import load_assets
|
| 5 |
+
from queries.supabase_db.client import get_new_supabase_client
|
| 6 |
from data_storage import login_by_token
|
| 7 |
|
| 8 |
|
|
|
|
| 25 |
url_params = st.query_params
|
| 26 |
if arg_token := url_params.get("token"):
|
| 27 |
try:
|
| 28 |
+
login_by_token(arg_token, st.session_state["db_client"])
|
| 29 |
except Exception:
|
| 30 |
st.write("Sorry, error logging in. Please refresh to try again.")
|
| 31 |
st.stop()
|
| 32 |
|
| 33 |
|
| 34 |
+
def set_session_db_client():
|
| 35 |
+
session_db_key = "db_client"
|
| 36 |
+
if not st.session_state.get(session_db_key):
|
| 37 |
+
st.session_state[session_db_key] = get_new_supabase_client()
|
| 38 |
+
|
| 39 |
+
|
| 40 |
def common_page_config():
|
| 41 |
local_css()
|
| 42 |
load_assets()
|
| 43 |
+
set_session_db_client()
|
| 44 |
login_token_arg_if_exists()
|