Spaces:
Sleeping
Sleeping
- app.py +38 -27
- encrypted_grades.csv +1 -1
- requirements.txt +2 -1
app.py
CHANGED
|
@@ -8,6 +8,7 @@ from dotenv import load_dotenv
|
|
| 8 |
from google.oauth2.credentials import Credentials
|
| 9 |
from google_auth_oauthlib.flow import Flow
|
| 10 |
from google.auth.transport.requests import Request
|
|
|
|
| 11 |
import json
|
| 12 |
import logging
|
| 13 |
from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
|
|
@@ -96,42 +97,45 @@ def load_data():
|
|
| 96 |
st.error(f"Error decrypting file: {str(e)}")
|
| 97 |
return pd.DataFrame()
|
| 98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
# Main function to run the Streamlit app
|
| 100 |
def main():
|
| 101 |
st.title('📚 Student Grade Lookup')
|
| 102 |
st.markdown("---")
|
| 103 |
|
| 104 |
if not is_logged_in():
|
| 105 |
-
st.write("Please log in with your CSPC Google account to access
|
| 106 |
|
| 107 |
if st.button("Login with Google"):
|
| 108 |
flow = create_flow()
|
| 109 |
authorization_url, _ = flow.authorization_url(prompt="consent")
|
| 110 |
st.markdown(f"[Login with Google]({authorization_url})")
|
| 111 |
else:
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
with col2:
|
| 124 |
-
st.write("")
|
| 125 |
-
st.write("")
|
| 126 |
-
search_button = st.button('Search', use_container_width=True)
|
| 127 |
-
|
| 128 |
-
if student_id and search_button:
|
| 129 |
# Search for the student in the dataframe
|
| 130 |
-
student = df[df['
|
| 131 |
|
| 132 |
if not student.empty:
|
| 133 |
st.markdown("---")
|
| 134 |
-
st.subheader('
|
| 135 |
|
| 136 |
# Display student information in a more structured way
|
| 137 |
col1, col2 = st.columns(2)
|
|
@@ -141,7 +145,7 @@ def main():
|
|
| 141 |
st.write(f"{student['NAME'].values[0]}")
|
| 142 |
|
| 143 |
st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
|
| 144 |
-
st.write(f"{
|
| 145 |
|
| 146 |
with col2:
|
| 147 |
st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
|
|
@@ -176,10 +180,11 @@ def main():
|
|
| 176 |
warning_message = "Warning: Your current status is Conditional. You need to pass or achieve a higher grade in the final term to improve your standing."
|
| 177 |
st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
|
| 178 |
else:
|
| 179 |
-
st.error('
|
| 180 |
|
| 181 |
if st.button("Logout"):
|
| 182 |
-
|
|
|
|
| 183 |
st.rerun()
|
| 184 |
|
| 185 |
# Function to handle OAuth callback
|
|
@@ -189,17 +194,23 @@ def handle_callback():
|
|
| 189 |
flow.fetch_token(code=st.query_params["code"])
|
| 190 |
credentials = flow.credentials
|
| 191 |
st.session_state['credentials'] = credentials.to_json()
|
|
|
|
| 192 |
logging.debug("Token fetch successful")
|
| 193 |
st.success("Authentication successful!")
|
| 194 |
-
|
|
|
|
| 195 |
except Exception as e:
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
|
|
|
|
|
|
| 199 |
|
| 200 |
if __name__ == '__main__':
|
| 201 |
logging.debug("Starting the application")
|
| 202 |
if 'code' in st.query_params:
|
| 203 |
logging.debug("Authorization code found in query parameters")
|
| 204 |
handle_callback()
|
|
|
|
|
|
|
| 205 |
main()
|
|
|
|
| 8 |
from google.oauth2.credentials import Credentials
|
| 9 |
from google_auth_oauthlib.flow import Flow
|
| 10 |
from google.auth.transport.requests import Request
|
| 11 |
+
from googleapiclient.discovery import build
|
| 12 |
import json
|
| 13 |
import logging
|
| 14 |
from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
|
|
|
|
| 97 |
st.error(f"Error decrypting file: {str(e)}")
|
| 98 |
return pd.DataFrame()
|
| 99 |
|
| 100 |
+
# Function to get user info
|
| 101 |
+
def get_user_info(credentials):
|
| 102 |
+
try:
|
| 103 |
+
service = build('oauth2', 'v2', credentials=credentials)
|
| 104 |
+
user_info = service.userinfo().get().execute()
|
| 105 |
+
return user_info
|
| 106 |
+
except Exception as e:
|
| 107 |
+
logging.error(f"Error getting user info: {str(e)}")
|
| 108 |
+
return None
|
| 109 |
+
|
| 110 |
# Main function to run the Streamlit app
|
| 111 |
def main():
|
| 112 |
st.title('📚 Student Grade Lookup')
|
| 113 |
st.markdown("---")
|
| 114 |
|
| 115 |
if not is_logged_in():
|
| 116 |
+
st.write("Please log in with your CSPC Google account to access your grade.")
|
| 117 |
|
| 118 |
if st.button("Login with Google"):
|
| 119 |
flow = create_flow()
|
| 120 |
authorization_url, _ = flow.authorization_url(prompt="consent")
|
| 121 |
st.markdown(f"[Login with Google]({authorization_url})")
|
| 122 |
else:
|
| 123 |
+
credentials = Credentials.from_authorized_user_info(json.loads(st.session_state['credentials']))
|
| 124 |
+
user_info = get_user_info(credentials)
|
| 125 |
+
|
| 126 |
+
if user_info:
|
| 127 |
+
st.write(f"Welcome, {user_info['name']}!")
|
| 128 |
+
user_email = user_info['email']
|
| 129 |
+
|
| 130 |
+
# Load the data
|
| 131 |
+
df = load_data()
|
| 132 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
# Search for the student in the dataframe
|
| 134 |
+
student = df[df['EMAIL'].str.lower() == user_email.lower()]
|
| 135 |
|
| 136 |
if not student.empty:
|
| 137 |
st.markdown("---")
|
| 138 |
+
st.subheader('Your Grade Information:')
|
| 139 |
|
| 140 |
# Display student information in a more structured way
|
| 141 |
col1, col2 = st.columns(2)
|
|
|
|
| 145 |
st.write(f"{student['NAME'].values[0]}")
|
| 146 |
|
| 147 |
st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
|
| 148 |
+
st.write(f"{student['ID'].values[0]}")
|
| 149 |
|
| 150 |
with col2:
|
| 151 |
st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
|
|
|
|
| 180 |
warning_message = "Warning: Your current status is Conditional. You need to pass or achieve a higher grade in the final term to improve your standing."
|
| 181 |
st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
|
| 182 |
else:
|
| 183 |
+
st.error('Your email is not found in our records. Please contact the administrator.')
|
| 184 |
|
| 185 |
if st.button("Logout"):
|
| 186 |
+
for key in list(st.session_state.keys()):
|
| 187 |
+
del st.session_state[key]
|
| 188 |
st.rerun()
|
| 189 |
|
| 190 |
# Function to handle OAuth callback
|
|
|
|
| 194 |
flow.fetch_token(code=st.query_params["code"])
|
| 195 |
credentials = flow.credentials
|
| 196 |
st.session_state['credentials'] = credentials.to_json()
|
| 197 |
+
st.session_state['authenticated'] = True
|
| 198 |
logging.debug("Token fetch successful")
|
| 199 |
st.success("Authentication successful!")
|
| 200 |
+
time.sleep(2) # Give user time to see the success message
|
| 201 |
+
st.rerun() # Rerun the app to clear the URL parameters
|
| 202 |
except Exception as e:
|
| 203 |
+
logging.error(f"Error during authentication: {str(e)}")
|
| 204 |
+
st.error(f"Authentication failed: {str(e)}")
|
| 205 |
+
st.session_state['authenticated'] = False
|
| 206 |
+
if 'credentials' in st.session_state:
|
| 207 |
+
del st.session_state['credentials']
|
| 208 |
|
| 209 |
if __name__ == '__main__':
|
| 210 |
logging.debug("Starting the application")
|
| 211 |
if 'code' in st.query_params:
|
| 212 |
logging.debug("Authorization code found in query parameters")
|
| 213 |
handle_callback()
|
| 214 |
+
elif st.session_state.get('authenticated', False):
|
| 215 |
+
st.success("You are already authenticated.")
|
| 216 |
main()
|
encrypted_grades.csv
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
gAAAAABnC1i2yFabbB-OM79Oj1t0FtsrKYI3bVog_tXt4BlspouWua6MmzCNM5mcyJ-Ww0nUy0Q4LLdzgA0RZ8P90l1ff3JaNG7jI_BcmSApOdWIRl-f0UU99qzZsa2nW6l6T6rYR_uhVQ6eYG6wg1nF0QP6ogzbD7tELtOHfYwUh7wZKzpz8FrBMll7MNjZOXaM9rUsMDJc-jc3QlEgPbQwEW58AupiYltQw5t6rczU1xHUeVMIfnEjD_nwKFsQGDEoBVclsbdKicSVKTC0xODrZascD4JiKG2moXB_4iDEvb9RI9brfcts616mjLE-6Bp4qV6732aHzKobzGvjFMkCBXdm3ly9mbEyoDoRQZ9woNJB-vJ_dF2wczf291ujZvm-ug-Z0YqU9QcC8rETUfvqz-HV4mUfSeCIbsrOgxL9iJd9AtcCS6cMvucPF1IT3_DbMEa9-IIrszxm2XQiJoUYHBINFEjoVy_odhTU1l-qn-qOOLX6hU_uEqHcPBn2CmLOVH2To2zTGHzU5Uni8SeCIdHkLcBMIypbfOOTkvcHly6ZkQllHwPAEUpydXKD2efQpCZJVG2n9f8kNdeoqPmu5RBdC3B8z9ZASGaPH7hyIwzwM93F5HofDrhaSJY8gM8Hj7GXSN9iTA1RekRV0lrQ2EuPYZVWvCbkd9LhjOfyqKt_ntPXih1U8qMQ4kxjYVKHJyflPpCzaIbw8JTzo_U_W93kJozSEAxSOpM8-avjdlF-JrZXOcP-FgxwavyYFxFTu1tJH3vG8torI2hMDksY5Gz4YxzAPOJKx86k97NpQU4pqYJtZiXRtuPrUqzR_WlJtopAlZlVQjLu5uM6VsxKSg9j6wGkyy4XKBxUJPeo4tdrpxEO3ZHIoIQ4UfvZ6qCMRYvJj4njlcfT9rlFvT49_hO7FKYnP3NAJLRdrP81S3UCVMJnOKURw24JJpiG5R-rfkrssIhCH248N4deZhpG8HciIedyAa2GyV68QUqF8HY2UUdDK5HIXRwf60Zoys-4z7zFTsJUweihJieG0q-RuRW0A_1CE2n_EmJAgo7YCFRLykukqaerSN5-LAd6o1kkuKitAJcFVnWA_JNlwhWD-990-3xzaj-zkEYtztI-0x3vtXIxesd0jxRynR3uyx3q9nIbkz7lT1ltorKbGgVrvcFyI6GS0a3-PXMsHrDUfQhP2yN449uuXLmiNzqUcRv83MFfH_6XkJV9RIsWAjS-Ao1NtT-QzPOxXx77Olq7sVz0JLe52YMD-yJXIBeHgMErAgg-88yq8Sii_6qGbgBtA3qD2IEV-BVi_9-tOM379RBu2zfT-T3jzOIknEUhHaPPUz3DACCbmGZcZZn87TfKZ-j3IOaJWCHxS0O2qyiWD8xNSqT9-acVvTGMSBw7gkVyzirr4_n38xHSl9yw3PyKwE5b4cTh5AUA_FgChywmdpyPmVjcho-LVT7HaAv6YgDZX3mnNCZ1AkljqBqSCgLbwtAqw_jHvzvQVyysOtauEwrgGTqVShs7IagB_F-vhYbo--FgukPNEMXDT8tikG-GYvZaHppiSfcdcWnZ6yi8YlKD4zdYz7ykCHpHgma0575DhzeQokakz4MGYMhhJ7xa1Tb3M9lPU6yCkRMLTQuv6UG7FSUAPzJO90SkUgWVCkZrtBSCzqGrEpxmyPolGof4I1MDuyFuYP5njNQbymX8jPzz3Q8zWrIBDLa0HZnQAOlfYrfi673Ovd0YJPBYuwCkU8ZgOGrqqROE1iQsttz30SOzJWBasuuu4v5vOezSk3N4Z6i_5XHuxaSoaaZ7mDa9wqDFAPkSZjteouiC6qI_PfilDuiBcE2YyypTnEEiClKh_bAOjL_hhSE_pcNAUG3f2CJn3XWPbvXqk58XJIJXNpimKZfoHmW9Li_JLJO-hHYNngBwaL7qITcWd8TLHw_LACORL0OPH4TO--0gBWPaH4L-dlphyHZ3MYC5xn4roxotDeXOpIWKKTsOVaFSWDR-v1N2kB5IDYQy5G_pnw3II3AZT-XsVAvsCuoD9gfstJTjxXMVQCnh7Z4cK6maGbxawDdv2hBeEyVBPg4rc8Bg2vMO3Qat46b7IYo7BHh99L94Y1AvNzRCVIA1PBIAXrpLO7AikbhJoi4ZVdaH96G0adxwAsdUVIeu_kd0p-cIn8jao8Tue-RpURZLJdzkMUFGzRnuoeW9iVx8iS5VBOdBDIK31-63hPrqbMcrwojZ3KdP2ni74tgBfhKwP9KChd9stXA5Ka1quq8WcoA7GFJt7o9ilCe6odqFIbtkhTANYBSegddq6_DJ5IBwqu81h3H-XzmkL4remUbmZgwGjwDkfKO88LEBhSgf3e2Szo_nIM063Gttk1xjk9va_HtKahL-FdNQdnhAtaYJina5OtXspjk0gX4oavVF9lI9SkN-tP_dOALUMqoK4wakL0pxBsfyEc9jOFWoNnD214T7dPg1-CsrbclmXz3UVuVdB4xW_hGKsbuXsj-JjxjRkWaiz9sm5LHFCrDwzg1C-ieMUM0l3baK_NkDZz3Bn3nR1ESaacUW-TS3jRshCFJVVhSVkpOlRabE52gkUTZ4uyufZVMzv11wPaO4pRd8U3uiV4aXT4wlX2AWYmy5cpiTLidhyTrU0EjWKnsjKQNZAD6fACpudBpm_HaTWrI-4WPx1xCOegi4IX_5sVCaziUl0BU77fCp7owvcX-Ojx6R5BYzxWbDBbKrqHYbfjXxv8f8_zga0elotZmQRMxUbUy1QmXYaTL0zDBMD6qJYGiad-sJqWoDkyyOOTGXlRVd1xqjXA7NVE95UNelnNjz9anSW-0HUbgt6w6NHkB0RY83cND9R_np7Hmf8YyGgrHXQYUqhvOTEkuDJqQJ11t9cUqK22HyrLSeqpAItWLwTdCYZAieI8lOD0BXiiI9WlifafTW1xvo7KFb0NR7orr8NSVaDx5IVm2DwtJ0aSOBp2mv3MbyjxvAhggKw6TB9x6oZUxzwaYzdQkIEYbmjvcWUOkSFeClQVMd2lnPL5Jzx7J37hHR0GBJ0xOQh3YHmN-4p6c-diOJsXrnFLRcleZ_u2XUpJeRNkpugLAnW58BmwYslKh3h6oaBYH9eXgYniKtYcjtGy4FVvGJO-u-Q715vDrEvoWimdBYthlRMs5h73cK81zWPFF7BizmFbzJvRnZd3k0TCH18_Fg1bX238jYcO9d8uZGiDKsIR1_5Hy3ZfpCXLzA1ID5qGRs3YRHzEW5w_YTQNGviEyYPyPI45XdYZWKY0sGq9EKWZGdiZKfikIh-JpL6uZgDRkeZaXmL8l7zIlPcQVw-1ehPYX7U7jeA5XRr2s0biEFxv_Lu7__fkx3PjXDJ9egtsiKRqX-yAXWcsD2C1TIPaDQJ8F31jOBizXDoRc-nmaz_VFVyc84el24RZqpfI94Yv1CgSQ4Np2jdO0BWbbt2WCcyp3ZfZShK5cf3w1_7nUo3zuT1Mx5dZp-wLttvBRXlIZyG3cox2MMaEePgZ-i0o3ElX0H1VuS-vhb1DneF0a51PoR8MwnNJdi9aZx9GToUdcXiS3Mkuz1Ll1HDP3L8-jV93otcntBzPJtwAZjZ3mCfVyKDL5yTmN6ureT5JilWEX_oMZ37as1OecicJIOlglnqAMNqhYsg2yMddofYvTx1p4CypbaxDV1M3gC0eo0zn9-njggdz6hTIdsDHAA2F7K3Ccf0eBtxNRyHGIxfKl-wEcYzNW9iBB1SjbOZ97rofCU7FNjynswJ-MqXaBomIpFkFy2NMOO_9zjh7vb3Ru4_xE7O5JWsPt0qw3Qbig67jFLWTnUYM0-wMWxqzKoAucEjO3qIO4l7SY8TTQ4ch2r8m3M4FlfuyXfV9dYfKvCdkgKXOeZXOM_A3ba_Mhuk9NyDhLTvESNU769O9WmJJLtMdILnU8vKzXt4e0u5yKyoFXMTiqPzo6ELZLxsjWtkYpbkIC1glNSUQUKuIYnadWImy7Vsa9OTvhqp3p6_uz_VThZvxubd6Gq5U9Hr3MSxa76MdrZh1r3y02oY-WNyCl04tWT9nvmxMCAmfq3m3YgzGSw6rzq_bllSYeFVPiB2L0TuJGONzDuCKIGJNs6M05pFyHPgSt_1UfnG5DFZ6cheqL2HKNjXw_pjflBQvI8abwIsdBx_hPCR13ugaHltW9IDOjRCLN75mnwvVaOl2I0iNno8-Zkk44q1SvGuNrsAnqxs2TbQORICwsj0Ns6gtScqvwNYQGrnCbT_p5fSC_ex0gMEaN_HOgHeXWogorxVCLGMzJn3B20JbCYyDYGMydY59jbNW100kBuTAxF28NM72C3T_dqEUhBGSY-DyWgDWigM4FpLXcx6gB_kaN13OscXiiBUfytq3FFB3tYB7GBLzDSgyJZDu7wtsf7fR8j1FUgbBKZF8X6orsFYu3e2Tx9Ldi8wZL06D7fBE9CxhvXLZRir1__aH33OA4U1i_7Vqlvq6lgbdxsRAxPwDIOUhUuS225_ODL0VKT2x_VEEIjo2DWtFXQzqvZoFnRNJMI5DVnV7pz3xzMGQluidUz2PebjpQiL9xfPzGbLF20JM1Ik6qh1eEOB9pROgg5eMuYGABc-fNqQ2G4mYoSkhofoV2RIzrPHgrHG3wIC3He8toecMsk48sqWRj4Wgyo4lUEjcSDRVrARsyncKOzxMgIIav3Um_bASN1pSzu2pmy9-wk-b5brDatPla1RfWdF-irYDYdBrNqBM6zqtKstMZjTCiws_k0x35t899_mC8bTsx8mwAUUdJJ11N0Z1eWKHH6omvhsYeIzeJlHI75LgHlgCPP93zMfBXfp6B0PIBZz0tSCL5awLul7OC0RsDN9dzTPCIxxvQ6aaKlQ__ZRkJaRBbyg2s80Ues9Fb8GCkWfPlyaFtjjKO0fz0C5xjac7kEViqzzNZANC0krLsCwffXINeu5vgKY_fcT2Nq9yDyez6WrxX1GcW1Ih0fzirPEEah7niQRCTqb0bcfcXER60w4fFiYcC3pWD_Bj7WICtFe0OrTszplx87_cFIlVjrCAn3JL4koofBfP1AVn-1QxeKc8uDQmZILrdHuYRQnCEH-xEzgbqleDM3MKwoxZcHcBGwUFRW8J5jIRm006x9Or68wKu4tUhUvRr8HbfaCjjsjLqS2czgbPy2DWFoZcQJgk_iTc6VSFz6QJRwbXJJJkgU98PX9vFoC3-4b4tXhWx2kvrymi_LOuMA7DTK21Sy0tjDNxc53-7JK3GbweN9dylwT6a2pao1iZhLUF5BEud1wIORtCJM_y7vAFVhyThwzgJ5lrGjMnWqw7EqSZcthdC7i3EJjRXsuGCelD9lMeUwpdFSte1Ww6RdVLYo5s214aLiFPey5eeLZGVmppgxKJvlxBdVKak_H6SZAO0KaogPKeKB5GVypTOBGg6RZCAU5frZFm0dM7-YPz3q3cWz8rTwTL8MVdmYTJkdMtkEM_TaOHndnmSO0_Hu8ZBipUn-1D4hTuNrLJy9MayKcs-rwbWypcxYHX76WMZ_4WkTLk4V5CanM7_-6q1f2Radx32WLEz-YWsDaVqPmrv_UDfDXveUY4FTEpxa1LRzAXT50Iq9amM6fqA2JndwHuzaSPHtvfEz-PukuTVF0UoOvurXxHrROmMmkWM3TQ5u5g==
|
requirements.txt
CHANGED
|
@@ -5,4 +5,5 @@ cryptography==40.0.2
|
|
| 5 |
python-dotenv==1.0.0
|
| 6 |
google-auth==2.22.0
|
| 7 |
google-auth-oauthlib==1.0.0
|
| 8 |
-
google-auth-httplib2==0.1.0
|
|
|
|
|
|
| 5 |
python-dotenv==1.0.0
|
| 6 |
google-auth==2.22.0
|
| 7 |
google-auth-oauthlib==1.0.0
|
| 8 |
+
google-auth-httplib2==0.1.0
|
| 9 |
+
google-api-python-client==2.105.0
|