File size: 6,193 Bytes
5a94297
0cd2128
 
 
 
f128fe5
5a94297
 
 
 
40fa5b9
d657219
0cd2128
f128fe5
40fa5b9
 
f128fe5
5a94297
f128fe5
 
 
40fa5b9
f128fe5
 
 
 
 
 
 
0cd2128
 
 
d657219
 
 
0cd2128
 
 
 
 
 
d657219
0cd2128
 
 
 
 
 
 
 
 
 
 
 
f128fe5
 
 
 
 
d657219
 
 
 
 
 
 
 
 
f128fe5
 
 
 
 
 
 
0cd2128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01b734e
0cd2128
 
01b734e
0cd2128
 
 
 
01b734e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6efe11e
 
01b734e
 
 
 
f128fe5
 
01b734e
f128fe5
 
01b734e
f128fe5
 
 
 
 
 
 
 
 
01b734e
 
 
 
 
 
 
 
f128fe5
 
 
 
 
079a08e
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import streamlit as st
# Do not load st-gsheets-connection
# from streamlit_gsheets import GSheetsConnection
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import hmac

# Standard imports
import pandas as pd

# Custom and other imports
import project_config
# from utils import add_logo
from menu import menu

# Insert logo
# add_logo(project_config.MEDIA_DIR / 'gravity_logo.png')

# Initialize st.session_state.role to None
if "role" not in st.session_state:
    st.session_state.role = None

# # Retrieve the role from Session State to initialize the widget
# st.session_state._role = st.session_state.role

# def set_role():
#     # Callback function to save the role selection to Session State
#     st.session_state.role = st.session_state._role


# From https://stackoverflow.com/questions/55961295/serviceaccountcredentials-from-json-keyfile-name-equivalent-for-remote-json
# See also https://www.slingacademy.com/article/pandas-how-to-read-and-update-google-sheet-files/
# See also https://docs.streamlit.io/develop/tutorials/databases/private-gsheet
# Note that the secrets cannot be passed in a group in HuggingFace Spaces, 
#   which is required for the native Streamlit implementation
def create_keyfile_dict():
    variables_keys = {
        # "spreadsheet": st.secrets['spreadsheet'], # spreadsheet
        "type": st.secrets['type'], # type
        "project_id": st.secrets['project_id'], # project_id
        "private_key_id": st.secrets['private_key_id'], # private_key_id
        # Have to replace \n with new lines (^l in Word) by hand
        "private_key": st.secrets['private_key'], # private_key
        "client_email": st.secrets['client_email'], # client_email
        "client_id": st.secrets['client_id'], # client_id
        "auth_uri": st.secrets['auth_uri'], # auth_uri
        "token_uri": st.secrets['token_uri'], # token_uri
        "auth_provider_x509_cert_url": st.secrets['auth_provider_x509_cert_url'], # auth_provider_x509_cert_url
        "client_x509_cert_url": st.secrets['client_x509_cert_url'], # client_x509_cert_url
        "universe_domain": st.secrets['universe_domain'] # universe_domain
    }
    return variables_keys


def check_password():
    """Returns `True` if the user had a correct password."""

    def login_form():
        """Form with widgets to collect user information"""
        # Header
        col1, col2, col3 = st.columns(3)
        with col2:
            st.image(str(project_config.MEDIA_DIR / 'gravity_logo.svg'), width=300)

        # col1, col2, col3 = st.columns(3)
        # with col1:
        #     st.header("Log In")

        with st.form("Credentials"):
            st.text_input("Username", key="username")
            st.text_input("Password", type="password", key="password")
            st.form_submit_button("Log In", on_click=password_entered)

    def password_entered():
        """Checks whether a password entered by the user is correct."""

        # Define the scope
        scope = [
            'https://spreadsheets.google.com/feeds',
            'https://www.googleapis.com/auth/drive'
        ]

        # Add credentials to the account
        creds = ServiceAccountCredentials.from_json_keyfile_dict(create_keyfile_dict(), scope)

        # Authenticate and create the client
        client = gspread.authorize(creds)

        # Open the spreadsheet
        sheet = client.open_by_url(st.secrets['spreadsheet']).worksheet("user_db")
        data = sheet.get_all_records()
        user_db = pd.DataFrame(data)
        
        # # Create a connection object to Google Sheets
        # conn = st.connection("gsheets", type=GSheetsConnection)

        # # Read the user database
        # user_db = conn.read()
        # user_db.dropna(axis=0, how="all", inplace=True)
        # user_db.dropna(axis=1, how="all", inplace=True)

        # Check if the username is in the database
        if st.session_state["username"] in user_db.username.values:

            st.session_state["username_correct"] = True

            # Check if the password is correct
            if hmac.compare_digest(
                st.session_state["password"],
                user_db.loc[user_db.username == st.session_state["username"], "password"].values[0],
            ):
                
                st.session_state["password_correct"] = True
                
                # Check if the username is an admin
                if st.session_state["username"] in user_db[user_db.role == "admin"].username.values:
                    st.session_state["role"] = "admin"
                else:
                    st.session_state["role"] = "user"

                # Retrieve and store user name and team
                st.session_state["name"] = user_db.loc[user_db.username == st.session_state["username"], "name"].values[0]
                st.session_state["team"] = user_db.loc[user_db.username == st.session_state["username"], "team"].values[0]
                # st.session_state["profile_pic"] = user_db.loc[user_db.username == st.session_state["username"], "profile_pic"].values[0]
                st.session_state["profile_pic"] = st.session_state["username"]

                # Don't store the username or password
                del st.session_state["password"]
                # del st.session_state["username"]

            else:
                st.session_state["password_correct"] = False

        else:
            st.session_state["username_correct"] = False
            st.session_state["password_correct"] = False

    # Return True if the username + password is validated
    if st.session_state.get("password_correct", False):
        return True

    # Show inputs for username + password
    login_form()
    if "password_correct" in st.session_state:

        if not st.session_state["username_correct"]:
            st.error("User not found.")
        elif not st.session_state["password_correct"]:
            st.error("The password you entered is incorrect.")
        else:
            st.error("An unexpected error occurred.")

    return False

menu() # Render the dynamic menu!

if not check_password():
    st.stop()

st.switch_page("pages/about.py")