MENG21 commited on
Commit
cfc6187
ยท
1 Parent(s): 90b4d93

Update .gitattributes and .gitignore; modify README.md for formatting; enhance app_new.py with database connection and user authentication; update encrypted_grades.csv with new encrypted data.

Browse files
Files changed (5) hide show
  1. .gitattributes +35 -35
  2. .gitignore +1 -1
  3. README.md +14 -14
  4. app_new.py +248 -248
  5. encrypted_grades.csv +1 -1
.gitattributes CHANGED
@@ -1,35 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore CHANGED
@@ -1 +1 @@
1
- .streamlit/secrets.toml
 
1
+ .streamlit/secrets.toml
README.md CHANGED
@@ -1,14 +1,14 @@
1
- ---
2
- title: GRADEVIEW
3
- emoji: ๐Ÿ“ˆ
4
- colorFrom: pink
5
- colorTo: red
6
- sdk: streamlit
7
- sdk_version: 1.39.0
8
- app_file: app.py
9
- pinned: false
10
- license: apache-2.0
11
- short_description: GRADEVIEWING
12
- ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: GRADEVIEW
3
+ emoji: ๐Ÿ“ˆ
4
+ colorFrom: pink
5
+ colorTo: red
6
+ sdk: streamlit
7
+ sdk_version: 1.39.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: apache-2.0
11
+ short_description: GRADEVIEWING
12
+ ---
13
+
14
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app_new.py CHANGED
@@ -1,248 +1,248 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import numpy as np
4
- from cryptography.fernet import Fernet
5
- import os
6
- import io
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
- from googleapiclient.discovery import build
12
- import json
13
- import logging
14
- from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
15
- import secrets
16
- import time
17
- import mysql.connector # Add new import
18
-
19
- # Load environment variables from .env file
20
- load_dotenv()
21
-
22
-
23
- # Set up logging
24
- logging.basicConfig(level=logging.DEBUG)
25
-
26
- # Set page configuration
27
- st.set_page_config(page_title="Midterm Grade for 2nd Sem 2024-2025", page_icon="๐Ÿ“š", layout="centered")
28
- #ADDD
29
- # Custom CSS to improve the app's appearance
30
- st.markdown("""
31
- <style>
32
- .reportview-container {
33
- background: #f0f2f6
34
- }
35
- .big-font {
36
- font-size:20px !important;
37
- font-weight: bold;
38
- }
39
- .welcome-message {
40
- font-size:24px !important;
41
- font-weight: bold;
42
- margin-bottom: 20px;
43
- }
44
- .stAlert > div {
45
- padding-top: 15px;
46
- padding-bottom: 15px;
47
- }
48
- .message {
49
- font-size: 18px;
50
- font-style: italic;
51
- margin-top: 20px;
52
- }
53
- .warning-message {
54
- font-size: 18px;
55
- font-weight: bold;
56
- color: #ff9800;
57
- margin-top: 20px;
58
- }
59
- </style>
60
- """, unsafe_allow_html=True)
61
-
62
- # Google OAuth configuration
63
- CLIENT_CONFIG = {
64
- "web": {
65
- "client_id": os.getenv("GOOGLE_CLIENT_ID"),
66
- "client_secret": os.getenv("GOOGLE_CLIENT_SECRET"),
67
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
68
- "token_uri": "https://oauth2.googleapis.com/token",
69
- }
70
- }
71
-
72
- SCOPES = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'openid']
73
-
74
- # Function to create OAuth flow
75
- def create_flow():
76
- redirect_uri = "https://meng21-gradeview.hf.space/" # Update this with your Streamlit app's URL
77
- # redirect_uri = "http://192.168.1.18:8501" # local dev
78
- logging.debug(f"Creating flow with redirect URI: {redirect_uri}")
79
- flow = Flow.from_client_config(
80
- client_config=CLIENT_CONFIG,
81
- scopes=SCOPES,
82
- redirect_uri=redirect_uri
83
- )
84
- return flow
85
-
86
- # Function to check if the user is logged in
87
- def is_logged_in():
88
- return 'credentials' in st.session_state
89
-
90
- # Function to get user info
91
- def get_user_info(credentials):
92
- service = build('oauth2', 'v2', credentials=credentials)
93
- user_info = service.userinfo().get().execute()
94
- return user_info
95
-
96
- # Remove the load_data function and replace with database connection
97
- def get_db_connection():
98
- return mysql.connector.connect(
99
- host=st.secrets.host,
100
- port=int(st.secrets.port),
101
- user=st.secrets.user,
102
- password=st.secrets.password,
103
- database=st.secrets.database
104
- )
105
-
106
- # Main function to run the Streamlit app
107
- def main():
108
- st.title('๐Ÿ“š Midterm Grade for 2nd Sem 2024-2025')
109
- st.markdown("---")
110
-
111
- if not is_logged_in():
112
- st.write("Please log in with your CSPC Google account to access your grade.")
113
-
114
- if st.button("Login with Google"):
115
- flow = create_flow()
116
- authorization_url, _ = flow.authorization_url(prompt="consent")
117
- st.markdown(f'<meta http-equiv="refresh" content="0;url={authorization_url}">', unsafe_allow_html=True)
118
- else:
119
- credentials = Credentials.from_authorized_user_info(json.loads(st.session_state['credentials']))
120
- user_info = get_user_info(credentials)
121
- st.markdown(f"<p class='welcome-message'>Welcome, {user_info['name']}!</p>", unsafe_allow_html=True)
122
-
123
- try:
124
- conn = get_db_connection()
125
- cursor = conn.cursor(dictionary=True)
126
-
127
- # Get student ID from email
128
- cursor.execute("""
129
- SELECT s.student_id, s.name
130
- FROM students s
131
- WHERE s.email = %s
132
- """, (user_info['email'],))
133
-
134
- student = cursor.fetchone()
135
-
136
- if student:
137
- # Get student's courses and grades
138
- cursor.execute("""
139
- SELECT c.course_name AS COURSE, e.grade AS GRADE, e.remarks AS REMARKS
140
- FROM enrollments e
141
- JOIN courses c ON e.course_code = c.course_code
142
- WHERE e.student_id = %s
143
- """, (student['student_id'],))
144
-
145
- student_records = cursor.fetchall()
146
-
147
- if not student_records:
148
- st.error('Your email is not found in our records. Please contact the administrator.')
149
- else:
150
- st.markdown("---")
151
- st.subheader('Your Grade Information:')
152
-
153
- for record in student_records:
154
- st.markdown(f"### Course: {record['COURSE']}")
155
-
156
- col1, col2, col3 = st.columns(3)
157
-
158
- with col1:
159
- st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
160
- st.write(f"{student['student_id']}")
161
-
162
- with col2:
163
- st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
164
- grade = record['GRADE']
165
- if pd.isna(grade):
166
- grade_display = "N/A"
167
- else:
168
- grade_display = f"{grade:.2f}"
169
- st.write(grade_display)
170
-
171
- with col3:
172
- st.markdown("<p class='big-font'>Remarks</p>", unsafe_allow_html=True)
173
- remarks = record['REMARKS']
174
- if remarks == "Passed":
175
- st.success(remarks)
176
- elif remarks == "Conditional":
177
- st.warning(remarks)
178
- else:
179
- st.write(remarks)
180
-
181
- if not pd.isna(grade):
182
- if grade >= 1.9 and grade <= 3.0:
183
- message = f"Keep up the good work! Your grade of {grade:.2f} shows dedication. Consider seeking additional support to further improve your performance."
184
- st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
185
-
186
- elif grade > 3.00:
187
- message = f"Your grade of {grade:.2f} indicates that you did not meet the passing requirements. Please consult with your instructor to discuss options for improvement and potential remediation."
188
- st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
189
- else:
190
- message = f"Congratulations! Your outstanding grade of {grade:.2f} demonstrates exceptional performance. Keep up the excellent work!"
191
- st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
192
-
193
- if remarks == "Conditional":
194
- 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."
195
- st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
196
-
197
- st.markdown("---")
198
- else:
199
- st.error('Your email is not found in our records. Please contact the administrator.')
200
-
201
- conn.close()
202
- except mysql.connector.Error as err:
203
- st.error(f"Database error: {err}")
204
-
205
- # Add refresh button above logout
206
- col1, col2 = st.columns(2)
207
- with col1:
208
- if st.button("๐Ÿ”„ Refresh Grades"):
209
- st.success("Grades refreshed!")
210
- time.sleep(0.5)
211
- st.rerun()
212
- with col2:
213
- if st.button("๐Ÿšช Logout"):
214
- for key in list(st.session_state.keys()):
215
- del st.session_state[key]
216
- st.rerun()
217
-
218
- # Function to handle OAuth callback
219
- def handle_callback():
220
- flow = create_flow()
221
- try:
222
- flow.fetch_token(code=st.query_params["code"])
223
- credentials = flow.credentials
224
- st.session_state['credentials'] = credentials.to_json()
225
- logging.debug("Token fetch successful")
226
- st.success("Authentication successful!")
227
- time.sleep(2) # Give user time to see the success message
228
- st.rerun() # Rerun the app to clear the URL parameters
229
- except Exception as e:
230
- pass
231
- # logging.error(f"Error during authentication: {str(e)}")
232
- # st.error(f"Authentication failed: {str(e)}")
233
-
234
- # Database configuration
235
- DB_CONFIG = {
236
- 'host': st.secrets.host,
237
- 'port': int(st.secrets.port),
238
- 'user': st.secrets.user,
239
- 'password': st.secrets.password,
240
- 'database': st.secrets.database
241
- }
242
-
243
- if __name__ == '__main__':
244
- logging.debug("Starting the application")
245
- if 'code' in st.query_params:
246
- logging.debug("Authorization code found in query parameters")
247
- handle_callback()
248
- main()
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ from cryptography.fernet import Fernet
5
+ import os
6
+ import io
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
+ from googleapiclient.discovery import build
12
+ import json
13
+ import logging
14
+ from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
15
+ import secrets
16
+ import time
17
+ import mysql.connector # Add new import
18
+
19
+ # Load environment variables from .env file
20
+ load_dotenv()
21
+
22
+
23
+ # Set up logging
24
+ logging.basicConfig(level=logging.DEBUG)
25
+
26
+ # Set page configuration
27
+ st.set_page_config(page_title="Midterm Grade for 2nd Sem 2024-2025", page_icon="๐Ÿ“š", layout="centered")
28
+ #ADDD
29
+ # Custom CSS to improve the app's appearance
30
+ st.markdown("""
31
+ <style>
32
+ .reportview-container {
33
+ background: #f0f2f6
34
+ }
35
+ .big-font {
36
+ font-size:20px !important;
37
+ font-weight: bold;
38
+ }
39
+ .welcome-message {
40
+ font-size:24px !important;
41
+ font-weight: bold;
42
+ margin-bottom: 20px;
43
+ }
44
+ .stAlert > div {
45
+ padding-top: 15px;
46
+ padding-bottom: 15px;
47
+ }
48
+ .message {
49
+ font-size: 18px;
50
+ font-style: italic;
51
+ margin-top: 20px;
52
+ }
53
+ .warning-message {
54
+ font-size: 18px;
55
+ font-weight: bold;
56
+ color: #ff9800;
57
+ margin-top: 20px;
58
+ }
59
+ </style>
60
+ """, unsafe_allow_html=True)
61
+
62
+ # Google OAuth configuration
63
+ CLIENT_CONFIG = {
64
+ "web": {
65
+ "client_id": os.getenv("GOOGLE_CLIENT_ID"),
66
+ "client_secret": os.getenv("GOOGLE_CLIENT_SECRET"),
67
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
68
+ "token_uri": "https://oauth2.googleapis.com/token",
69
+ }
70
+ }
71
+
72
+ SCOPES = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'openid']
73
+
74
+ # Function to create OAuth flow
75
+ def create_flow():
76
+ redirect_uri = "https://meng21-gradeview.hf.space/" # Update this with your Streamlit app's URL
77
+ # redirect_uri = "http://192.168.1.18:8501" # local dev
78
+ logging.debug(f"Creating flow with redirect URI: {redirect_uri}")
79
+ flow = Flow.from_client_config(
80
+ client_config=CLIENT_CONFIG,
81
+ scopes=SCOPES,
82
+ redirect_uri=redirect_uri
83
+ )
84
+ return flow
85
+
86
+ # Function to check if the user is logged in
87
+ def is_logged_in():
88
+ return 'credentials' in st.session_state
89
+
90
+ # Function to get user info
91
+ def get_user_info(credentials):
92
+ service = build('oauth2', 'v2', credentials=credentials)
93
+ user_info = service.userinfo().get().execute()
94
+ return user_info
95
+
96
+ # Remove the load_data function and replace with database connection
97
+ def get_db_connection():
98
+ return mysql.connector.connect(
99
+ host=st.secrets.host,
100
+ port=int(st.secrets.port),
101
+ user=st.secrets.user,
102
+ password=st.secrets.password,
103
+ database=st.secrets.database
104
+ )
105
+
106
+ # Main function to run the Streamlit app
107
+ def main():
108
+ st.title('๐Ÿ“š Midterm Grade for 2nd Sem 2024-2025')
109
+ st.markdown("---")
110
+
111
+ if not is_logged_in():
112
+ st.write("Please log in with your CSPC Google account to access your grade.")
113
+
114
+ if st.button("Login with Google"):
115
+ flow = create_flow()
116
+ authorization_url, _ = flow.authorization_url(prompt="consent")
117
+ st.markdown(f'<meta http-equiv="refresh" content="0;url={authorization_url}">', unsafe_allow_html=True)
118
+ else:
119
+ credentials = Credentials.from_authorized_user_info(json.loads(st.session_state['credentials']))
120
+ user_info = get_user_info(credentials)
121
+ st.markdown(f"<p class='welcome-message'>Welcome, {user_info['name']}!</p>", unsafe_allow_html=True)
122
+
123
+ try:
124
+ conn = get_db_connection()
125
+ cursor = conn.cursor(dictionary=True)
126
+
127
+ # Get student ID from email
128
+ cursor.execute("""
129
+ SELECT s.student_id, s.name
130
+ FROM students s
131
+ WHERE s.email = %s
132
+ """, (user_info['email'],))
133
+
134
+ student = cursor.fetchone()
135
+
136
+ if student:
137
+ # Get student's courses and grades
138
+ cursor.execute("""
139
+ SELECT c.course_name AS COURSE, e.grade AS GRADE, e.remarks AS REMARKS
140
+ FROM enrollments e
141
+ JOIN courses c ON e.course_code = c.course_code
142
+ WHERE e.student_id = %s
143
+ """, (student['student_id'],))
144
+
145
+ student_records = cursor.fetchall()
146
+
147
+ if not student_records:
148
+ st.error('Your email is not found in our records. Please contact the administrator.')
149
+ else:
150
+ st.markdown("---")
151
+ st.subheader('Your Grade Information:')
152
+
153
+ for record in student_records:
154
+ st.markdown(f"### Course: {record['COURSE']}")
155
+
156
+ col1, col2, col3 = st.columns(3)
157
+
158
+ with col1:
159
+ st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
160
+ st.write(f"{student['student_id']}")
161
+
162
+ with col2:
163
+ st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
164
+ grade = record['GRADE']
165
+ if pd.isna(grade):
166
+ grade_display = "N/A"
167
+ else:
168
+ grade_display = f"{grade:.2f}"
169
+ st.write(grade_display)
170
+
171
+ with col3:
172
+ st.markdown("<p class='big-font'>Remarks</p>", unsafe_allow_html=True)
173
+ remarks = record['REMARKS']
174
+ if remarks == "Passed":
175
+ st.success(remarks)
176
+ elif remarks == "Conditional":
177
+ st.warning(remarks)
178
+ else:
179
+ st.write(remarks)
180
+
181
+ if not pd.isna(grade):
182
+ if grade >= 1.9 and grade <= 3.0:
183
+ message = f"Keep up the good work! Your grade of {grade:.2f} shows dedication. Consider seeking additional support to further improve your performance."
184
+ st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
185
+
186
+ elif grade > 3.00:
187
+ message = f"Your grade of {grade:.2f} indicates that you did not meet the passing requirements. Please consult with your instructor to discuss options for improvement and potential remediation."
188
+ st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
189
+ else:
190
+ message = f"Congratulations! Your outstanding grade of {grade:.2f} demonstrates exceptional performance. Keep up the excellent work!"
191
+ st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
192
+
193
+ if remarks == "Conditional":
194
+ 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."
195
+ st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
196
+
197
+ st.markdown("---")
198
+ else:
199
+ st.error('Your email is not found in our records. Please contact the administrator.')
200
+
201
+ conn.close()
202
+ except mysql.connector.Error as err:
203
+ st.error(f"Database error: {err}")
204
+
205
+ # Add refresh button above logout
206
+ col1, col2 = st.columns(2)
207
+ with col1:
208
+ if st.button("๐Ÿ”„ Refresh Grades"):
209
+ st.success("Grades refreshed!")
210
+ time.sleep(0.5)
211
+ st.rerun()
212
+ with col2:
213
+ if st.button("๐Ÿšช Logout"):
214
+ for key in list(st.session_state.keys()):
215
+ del st.session_state[key]
216
+ st.rerun()
217
+
218
+ # Function to handle OAuth callback
219
+ def handle_callback():
220
+ flow = create_flow()
221
+ try:
222
+ flow.fetch_token(code=st.query_params["code"])
223
+ credentials = flow.credentials
224
+ st.session_state['credentials'] = credentials.to_json()
225
+ logging.debug("Token fetch successful")
226
+ st.success("Authentication successful!")
227
+ time.sleep(2) # Give user time to see the success message
228
+ st.rerun() # Rerun the app to clear the URL parameters
229
+ except Exception as e:
230
+ pass
231
+ # logging.error(f"Error during authentication: {str(e)}")
232
+ # st.error(f"Authentication failed: {str(e)}")
233
+
234
+ # Database configuration
235
+ DB_CONFIG = {
236
+ 'host': st.secrets.host,
237
+ 'port': int(st.secrets.port),
238
+ 'user': st.secrets.user,
239
+ 'password': st.secrets.password,
240
+ 'database': st.secrets.database
241
+ }
242
+
243
+ if __name__ == '__main__':
244
+ logging.debug("Starting the application")
245
+ if 'code' in st.query_params:
246
+ logging.debug("Authorization code found in query parameters")
247
+ handle_callback()
248
+ main()
encrypted_grades.csv CHANGED
@@ -1 +1 @@
1
- gAAAAABog4JYu4t0h0cmyIYgO1q_4cucoZ0ilFBs7p3fEwGWpfTrL9tv4mG1bE_T329iZaC7h0ZMmSk_1H4dTs4vRnCJ682Nnv4e7i8_mauPnyjAdIBuSKQl4pf78PffjjiezkYLpiJi3WrvGAuZzaVriFdfsAz79iCUaX1S93W3FFQCBveIexFj2UPX6KUxFy_hyt42cJ4DbdTlNnTRRd_nM1W5cb1eNbqUxCD1H5wLgU9nRroQbbGuZc5ZRwBQjeE4LOAR_Tx-9517uoJtw4x7XAzmXrVjEyoXpdHRgfO3Cw6pJTwDxuu_bcp77ZahPTvRJg4bFuRX-EGDd6GILGaI0Nwx4YJo5uDFiJxmN8KOXc2ybGW8kh9pz59zBL4ZLttB1AS0DYeC6GLrryNshetB9hw4kjrOky8CEfW4rNIZybmlblhZGaxPZRhJDQcS0KSZifVrh_YnlYe9vcYgEOM8YPYjNG_oqPHSd7vyueZIvoYzgNXJZP0m7DH1fqlUi5GN25nfm5GnTO3j17YRBIhqHzxIp4mHW0-xUGM-7yCJPNATfaNW0GkktOStWFnd6LU4GJuOgVZjdexW70UFVnvI7M7npas79CL2NwHzTvHRbFzb-VR26WsREsoZ-z2UaAFal-pVoMaGO8u-1KZFWO9kItvkBolUibEKatEEmc7LXgOVg2v4EM4aYDUsvnkYlbovGPd9Uoz9ydFCkQxBVPii_-P-olvPQDudXNDkU5LhR_qAoGgfcJi8pqfN8sFxusaSm9_NH1-hInOqdrjh1i-JOnizEFZ4T5cYNtiLu9x8Sl4H6wIq1Bddh6mhL9TsfX0jq0u5q--NFfVKHxwyzuCVVUVtvfJMP4o-YZxL5H812cH49t8cBekhcTnmKk4QlI_R6ObIBKi6tSk8gnsT8N-UZNLDkvW1iXMuO2-MwObqqyJykyrJLouED1v_UKxpJXWVP0XRwt92QFl3izQKoUcXdfpDxbjSffYkn4wD_DjtkVfd4GbKYTGudgz1z2DEv4rirxjqD51Y91k0Ej2eqqWR06ug0DOHsAIT_AxjTKT1IzXNs7MHAb4HBOQufg2E2F0blBsOK8rDu8nOwI0O4WeE6NKbgfK2Yhq3VZUpRzAv7ivDzOaEW-DgDFIm2pcGMaLbspE_g4hvf2m1iVzzrXgPKPM018RBGwQKAytyDd10f-rbCFYWxSUZXA5e8MDpPc2eF5mC_LGjM1eWJZkeQmJtxbJKV5hCJXAgZ8QzhqX5p9FA50D8QUVUPxqs1kb6is1Qm5P8cqTSKshYp5d-a7zS9rX7UF3f7oIYHyWA2UnSxIZfz7u2wVyMjPHxCsipv_Xai9PcaHQOBC1lj6JCQaGqgtrU-C1ggHw_J-qHk-Gqq-hFeCoyOsQ3QsDbl57C8w-YEujyCgl98pVQUesin_lyolPJPZa_nUm0_CL3qDZ4PoJZThJIZMqSniB6rPVemRaOtcWiZr7H4zIwUg9L3HYUPqgP6842srHOyryjEaP0EVb9Odgi1RmqPsrq2P1_3FlSKJOInpCRwDl3CIteuvD88toyP_VxNidVJ5OHTMLcRudMdrW9E7JeJW42kXM3Z0KCxo8O7pU3q0OI8MTxX8VkHiVegPMkB9gn9Sz8PcHLMEllV5StHS1YAVRnP3FQlSdQ9ahukECy_6hvFHthkTy8PPqMs0iPvDrMacpm32DHdA3SVVvUM4me85ZskaglFK0j9ck-4SvYnOH_5bV12tJoyF5KxSOmpJ3DR64pO9dyzKPpWHEhRaaW_zHsYwXZYgp_WF-ydk2HIQw8uLKc1np6CIayOFnWvz_Fjwq-fd4layiQbYLFQkTaHlGkNw7nlbYU-ive_XGTy6-OqVBh_89q7IgDY8KOmrkG3lsaSE90b_o_KfZYyH35oub_0KA9CcEnAk9ieU6NqpPZ1DdXqjd_Tcm_1BKTGCtGWLlqgWmiUmaLglXhP-zrKI-m_ugDlm9Oa-4_M6MKjNgedOcvUWO__rtvdhjv5M9Pl53KlByyfNgc_2bkQHLr8p33c7VwJ0k2D1bRTdJKUNuFyru-FGMBfifib5blK3h5sFsik-ct6ATOaRFbB8bddpYt73s8WNZCiCByJyvA8RsehMcdKpWlnK2WwYTLUyu-TLE4ghP4ycGM9WUxlJvaeB97JYCoElsJp-h4FrAHxbIfOQ0pvlPQR1SaGGqfW7Iw2r4xPgg-TxwM0gUXSQbOPHD9hpfod1w0cyy3d1_n12oI0IVnygt0LqnKanyEUVcb5og--3Byky0W6f71joueQdIfQ2AYbkBo0cRygLxVSESKJR012BO8DH-BWjBo50jLFB7wDMXmP9GxjWVZPf6zUHqjVl_QtEabrJlko-B4DvJRSj72GTddxG7trd336nyycPhplbR_qwVqrmx5q7upF-TgQTiOCbEXqb708P1GtyJIIzxxcrDnbwwS5R6sKl0AeGnRo0nvIBMe7Wg7QFOEGqGADgdzE2MMyb0IWx3WE_YSvq_7oFxNCZxr6TPMEwWQXbZip91L5-zFzpfb0aC2Q9RUFbhy5JL-TLgxt--ujy2eekvw1_-J6Q1cl7MUEwJT25MpVD_oE_7jaVf9CDB9qDZSOAo7tJZLTQ9OTEsulkwuWcco8AWbr7TIzEUgV4QBkSbrg9AP-hD7bQHE2llbKku1Q1HdZVKm0a5XTLwp2S9TeoWLj2FGthwIHrzcr_gzhS7kt6S9IZ-U54UdaAisA0q1C0iYNhtWHwxXlelhFn7KznV2-qbhT4NA6Z8U7H8q_PYaR4RghpdX3-yFD61f8XByonGRCrPHd_l14VlSu3GUGc97677n1UR1MvZG-R9QXzlHQG7ApBXb16VpNSl5nW3U6jjq5BYYSifuH_BTvjCj6rm6WyJ_ml0-xOuqgDrFrpEmRaJ7xtiymF84K6s8WVsdZQY0jZJZgI7hhv1ux4LDst6D6vNVg7AsyVPrhf_g88uoFFj8ey1EBKogkszCsl45LGO6iZTqRd2IC64iEpZ3GpRf9v01vHKuf5Rk8OCjpCLRKM9uhkB6asD89n9POX9txPuvaTJKipQhr8H5iyksHGcFJ3V08Oa0PoIPyg==
 
1
+ gAAAAABo5y_BCTV_fnnDYy2MnSK3bLP-WoT4M8B4qbjiolP1ZLVw-rtyOlwnKWzHfxB1T0vzoq84sU0McZt8YdC5qvjOaeBydzY5mEgAbpw0zyqDUKg-kF9y1K9lQnK-K4st7d_5S4q-AGdJi4N4V3uXRReFmtxGle-YJ2gfiUtleUJ_uO19ZhJYPYopnoU6XR3HU4_PlABWZPzxpiUjzL203G3Pp2mqYjpvbI5oU4Qh3qd94gTa_O03vihHywtbiB6EwKjMkFL-xJzPFi76SEoLNIsxQHHr8-HeW4KqM4cRPjucO-NrkmF6wcDN5SUpCJH-BL1GnkT7gZqy_YQ-Btzwupt5TSvYuvVM4cYkiiQGXmydmyyIudRvdnUoqDmUNj9B9ew5Peu1phJKdJrWu0lIo8a5FC5YVa4Ks0vyhl7RH_027ccIA-rTmwegxQMpSNO8YQy5zVuu6zUiz7giv76RRI_gh1bwcJW6KwoLvTuPXjzPU7fFdX52--d-Xy37Gdizoe1fJlPMh4xlXnwrPLOOtZfNAX5zqNedqilOf_Bchub-9ULMnWT6mRMHjiGtf3RAyDzUFWunmGg5I8L1Sy2qAD2iKNqQjHLEI_XFQiUv_bLnMJaxpyyM4P_fcRs58KRTn9DleWWHqj6Ze6zqe0-87IPVHxuxOV2mETu6gQNwL-pzixUwrega57xcKV_Uz_H1Gnyx5GeiGw0Ov5Cp11pqcGrd47aElctZwzP6SSSp9zcD2pmjQMmUp71M_ZxcRioC82Qnqu7G3YiA8PV36iOoZOcETb7W31pSmlr2vTqHFlOZmkVHdCLHbdFqrKTVYTnYvT9fbRpKJt4yMCVml8ohUXV-S-6c_SbgpMv7LdUDvKHe7Tz1h0Aq9fk9W4er-z_x7PVjfGFk3EVGuYlZHh8YwclQkihmMvADcJe4EvLImm6wiF2pzz2NqMdgQjRCvU8l6hSXU61-qJB4Rvx0GXMi4tNiSf-C8bYo-mj_-3dPtCaT8fS1eZyOt3UC2aNlQkglpz3vh1NYXJNWKlO-0evd1W8Lqo-5SPjLvP6YTV2h13m6XUaVAz1EB1T7wy6R1iM-vjIuHetKNTuQfFbWd_jSIBySSZsBO68OVyL1r5ZsbHxLZ8t99AZwSYPUJWjQ_vTDyG3X2hXh17-ZcrxgT0yI3O4t2HDjaegE6xhCe1-DrZg_cKF31m7D437-lVQvBshi6AzCfJHI3yVnq0qyFBjnFRGkQduIbIOaMOc1PjokIHRZuQZVPnGdpfH3xUhk6GagN6L_0zgiiwnvid_a0c_aDut1_DF7Fsu31dC2IPHn2esc2iifDJx4lkctSn9ooGyE8cYZGCuDs0E4LrH6NjHi5j1mS50RI5v_B7CTG8IDWI15H-kXfASjv3wAy76k75Ux4VW34Dv_5cNugwhcLdIrnfejodZ0WXG2X1LBozU4qFwNoQrelRXnapppUU0fZ_xZOPOqdohg0IUMZ_o2jRNSdmXS-6xKKUvjxnYa2SDiRL55G91anRo0GTEB6WddI9V5KzUz-ac182e9eFXYPnWJjLPMV1yca5sEkTK9b9gQXnchTFdCmpJLwR0sCepZACKmKPEDY5jVML5dVPPEwpDCJ-7DkaIZctSMo4tJCBzH_mdV0vzi0n-lX5x8zaN0OWlfpRORTeBhlCA-6NX6BhqdzcmIu9GIItb_mQC_G2DHWgvASbpzt-j1LmtT1UefqR98qxfRlotxsKoUBZIugdYwVybNYOCB6YcpZoVPY_seAOfabbOsoA-wCO0IwEYn7Ni2l55JIz7sbx-sLY9pDBsg0P9UB5_Zt_L0sokbkUFNiHJav0mHATI2IQZpWhWDeHYH0Cqtw0L7a93bYsGMRvzB7A_z-48ZYaWZ9pHplctzL6mAI6mUpouGk3EGaCb2sMBhWSCihk_LQnishRrbVp8Du9Vt7dUyk3XcvXzD8BtDc7XqDJaLaLSphe4g_nVp2JflH69C9nv4zzeTz8YBEzQMPfZsryI8zWZExhNoRgokuexk2sSzGCYIBnbCXhEyl_jMHqGAxNC2Iik0dkE3Up1uGuVXPs5FiSQTb0NBV_g4dLxNgwDNh-ZEzQqNvC2TIo8qkYFkoYocSkEoWChq7M8Ou6vmJwklEHVbWqFM10AxvJZ1k0LZY0eLMNAcp26hJOGoDtCLihqupLOAN-tk62_x3bWtJ_jNSmNVvT3IYaLMYC78xDpwv_X6jUuUdHbR69gG1wkX8Fkwp2JBCv_fyPMK_-zeLiMiBmuyy9MOVMnCp2hq7uHKFt7cDSsj0SazffS9n1a8O9Vk_eHRqcM1ZgfP9dL4heMP-nE_-SKwEPTM67CUeu2CmlhREoQExVJ9kefyMDjdBIgyTU4_23tk64VkKLKy7KJ7mtmhuBnzDyb08qgl_ZYvFiwljcGlBChXGCrB695g7_zcda96IL0QmRcxwbDyQ-Khb7K8n_iSBqbgZU7ZSl11DLzLANGAriiTrNEIUn2o2x03WS3c7fcP4wDV_15LDLb4yj4a4-1BaypZ9GRATuvkFT34Y8tplLvi9R6gc5f132fzD262ZbawGzKqaiChMCER3urhUdPtUAGgjuuL2Rm7M43T0M14vjnGrrTxp8pT82zeoTQruDDdnhbqKL-tCycWvbr-1l9sMzSOgqiXm6SPfsg-aIXzQ8QduZxPnCLBsXqVEg0P2-y83avhKgaCk09dXLJo57Qr-v-T_XQ6DJeBJ3rv-WFUArzzU6T3uaroIIEDumOpASeDwSiOQz6stxtPirPhJE4nTPdHio3oFghRrVW_255JKCOLynT_lIxtZ9VdvubormsR7foHDvkQ7n8APxuSYbaLAB4sQOFywPmLIHXaAFwPnybSc6x193lC43f94BugUC8MzgZIFnoKN2zAjkBIzSg3bjSRgzufGDjuuHk_Wbs7g9FFqK3hhlMuvgsdpmdU8gLGyKXTBSQeARUeW2KRAQYFmZRit0n_9Pu9AdTsRij2TrN-HsgP3o5dV3wAJx81vVEDpmPv5HeV0LhdmYyke2hFORnGrOTUGgYiT0zhTU_oCMcY9hwAq-Y_3nDvfGXaIBOQvZGVXVL1Z5bolF4JV73inR97GpNDoP_NabhAXGhtVl5KztrPxE1h72WxTaXcJaMgtT2YTVyCbrtr8oS3pTdVkNzdLBSaEDa5nSdZSnu3maW9e51GZ3hW2HBufOyY6FfgJVC9Rea4REIuHhUHIkL7i_HUwvjpWySXHBo45UffRUgcoHFYSnFq4IF6jou4kXRH-J6DQrMDRGq7i7PJsJe7u7PnXQXSGVqM-82_W044F7PicTUUexJe-DYze9Lh8ee-jI3Y5peeVMJW1dG4bECySE3AYgEC8xRUMTKsY4_DG2w0xZ9TPTdICC1QucH1Y84uvMmTP0dawdlfCDlQMWFwG18zaUAQxp2KR_i7EHH-I0Li0JhAYPgWycfMP2xyCrGwTvHAWZMqfEHtzPIbuF-kNxT5zHgkAtVpUFJY5SRGgaHTEteQhNEazHEsobH4BzRve_iSDUvm6_3bFL3xx2EZmexiWiwQ71KFBC9lWnXcmY0u24BDX3PzN-N5NVCrR_okRSolGE0Dvp6YYFsbvBP6SKJsZ_ZY304-Vt7wOz-osdb0Csq3G_wEzYN8paJmkpZ0Gq_LpRoTpulimhjtbvHd2wGgxaj7b-bBpAmmahLX1m4rbYJsJvWlSLtarz7AV0zTsdZWyRXSOlNszGN3KR3ww2VlEShFomvXubyQeDpCspwvaYyWGOU5DPD2b2kQrO4FrFAFDPKY-VytT8PySRgFUnbbU2zUFTrSECVKKi8OLYoajxeV7nwn50Ra1V-OsqIiFoz2U2iTZKFRn5lqlJZ2faObmz4QXgNvnd9Yz-zapTej5mpzT-5Zw_eTN3wEv_Z7LscsoB1tcJBbyLfPwD4ZZAlhTpCCEAbBNNp9roY2rVWJc0E082p4NYg7C5mqsfKnoNHOjTDn-rZQQkPClKNA4wTPZtSJpCtBDa-DHi75c2U1qeoyc06BMuyi--8NHwQU5S4V0EZ0n72es_hwq3cKjZOgu0F-p5h1yp7-LYsu03ii9yCSSpWwfCqa-FJRI1UuL9zusH_vXAglh3rXPRfWfUbnZzt69chXk0Q2cE6Q6gjQnMgbpbySiBSbcMXskvYsGE9_9Q5b7vK8afkXefmW2vLMI3_XncAEMYjsF69kIlmCuXfePksFBykC59CASW9Y21lD0atwGtJw4lW5alHXrP6RdzT8kbeUP48b4N5sKTagV1blFZZtQt8NRL2M0pN4CxqMV8G2e3k3OHho_LwHTsaRvWjlEpl6oL2rxpFxBoCzLX7JCr9Wh-Mj7datF46uzjvl90wUxgg3FB-fLkjX79VfY8aLwTpD1j78qVoShGS33d6ot97toLSMR6NDDbkL0WmcTq3bh-Ky1Mool2pdKNvwLfg08tj_lllN5GMLoUs30InST7nNnbW4BzAAlBe0HMvFTpHElJQvvteJUxo2oyr5yIfme2ZDmi7LMN6O4NbjVxodKLK5StATy0fl0Xi55phTY_CK-ZPjuFUfnyZI3FGBGZ7-OWobzdGZK8w0ZVTc7mxdKgxXZUiM-8xZvv6KEYwuq6S30noSboBGGoDX0OCjdF2oSriDCHYfE90Y2iFYmlns7CTiDpoDp1ZsZv73_m1OSg4uvK9FvcW92G4hhB9EyM2mv5g_V6yrJTxSHbDmhGkdfpd_k5GAJhPKbxRD1Rk7cc2718pZsLUaIAbxZGuk_P4pAeaw_nJ5xxoruVwkbYFa36i9E7x6tbOD2zBhVJxaWaZtVAq69ihsYefiANHvEMhikJBPW4TT4yuEbAf278Tti1ZxUi6iY_AIG3-HcrbMGK5SETE9KXBZMjB581IHMIIQBOmWabSyCpgXZmfQqpoY8BInJd1eL7s2Kn8yfLkypth-vzPDTukNVfmq4tHX3cSzFFdoHCZtVvjG4R1kZE8ttiuYLRgBUb_grpfUYpQpm80lQT8bU1g4LTpDoi1lzjyneYIL0I1wCkvcuy8IMpszkkH6SI1U3I08mNvx5iLR0IO_t8gS7R5Hn2j9uayA6S-C_C9VxW98Gj-DQiFZdJxX3EZ0CHAJPDaVmysewl6YlP8sxcz_prxgndZmMc4MSrZFFZ4t7HUtoAyw50ew7MACdXiOQYeM_-5m9xt5zZ2HentX-7xWT127gAd4YEQ4z08Q_n0TET-ZH1YPWfQLnWa4Nyw-ltbqFxdWVY_QVgeuL9UH41Iw9Y7AMUglVgpBuYHmeLbZSEXSkUG9evdPzbYjEGqqJWaIxPtkX9aNT13N-B5G1AmuSQ==