MENG21 commited on
Commit
d43e69b
·
1 Parent(s): 5488dda

Refactor data loading to use MySQL database connection; removed CSV decryption function and implemented student grade retrieval from the database.

Browse files
Files changed (3) hide show
  1. .gitignore +1 -0
  2. app copy.py +214 -0
  3. app.py +96 -70
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .streamlit/secrets.toml
app copy.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
18
+ # Load environment variables from .env file
19
+ load_dotenv()
20
+
21
+
22
+ # Set up logging
23
+ logging.basicConfig(level=logging.DEBUG)
24
+
25
+ # Set page configuration
26
+ st.set_page_config(page_title="Midterm Grade for 2nd Sem 2024-2025", page_icon="📚", layout="centered")
27
+ #ADDD
28
+ # Custom CSS to improve the app's appearance
29
+ st.markdown("""
30
+ <style>
31
+ .reportview-container {
32
+ background: #f0f2f6
33
+ }
34
+ .big-font {
35
+ font-size:20px !important;
36
+ font-weight: bold;
37
+ }
38
+ .welcome-message {
39
+ font-size:24px !important;
40
+ font-weight: bold;
41
+ margin-bottom: 20px;
42
+ }
43
+ .stAlert > div {
44
+ padding-top: 15px;
45
+ padding-bottom: 15px;
46
+ }
47
+ .message {
48
+ font-size: 18px;
49
+ font-style: italic;
50
+ margin-top: 20px;
51
+ }
52
+ .warning-message {
53
+ font-size: 18px;
54
+ font-weight: bold;
55
+ color: #ff9800;
56
+ margin-top: 20px;
57
+ }
58
+ </style>
59
+ """, unsafe_allow_html=True)
60
+
61
+ # Google OAuth configuration
62
+ CLIENT_CONFIG = {
63
+ "web": {
64
+ "client_id": os.getenv("GOOGLE_CLIENT_ID"),
65
+ "client_secret": os.getenv("GOOGLE_CLIENT_SECRET"),
66
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
67
+ "token_uri": "https://oauth2.googleapis.com/token",
68
+ }
69
+ }
70
+
71
+ SCOPES = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'openid']
72
+
73
+ # Function to create OAuth flow
74
+ def create_flow():
75
+ redirect_uri = "https://meng21-gradeview.hf.space/" # Update this with your Streamlit app's URL
76
+ # redirect_uri = "http://192.168.1.18:8501" # local dev
77
+ logging.debug(f"Creating flow with redirect URI: {redirect_uri}")
78
+ flow = Flow.from_client_config(
79
+ client_config=CLIENT_CONFIG,
80
+ scopes=SCOPES,
81
+ redirect_uri=redirect_uri
82
+ )
83
+ return flow
84
+
85
+ # Function to check if the user is logged in
86
+ def is_logged_in():
87
+ return 'credentials' in st.session_state
88
+
89
+ # Function to get user info
90
+ def get_user_info(credentials):
91
+ service = build('oauth2', 'v2', credentials=credentials)
92
+ user_info = service.userinfo().get().execute()
93
+ return user_info
94
+
95
+ # Load and decrypt the CSV file
96
+ @st.cache_data
97
+ def load_data():
98
+ encryption_key = os.getenv('ENCRYPTION_KEY')
99
+ if not encryption_key:
100
+ st.error("Encryption key not found in environment variables.")
101
+ return pd.DataFrame()
102
+
103
+ f = Fernet(encryption_key.encode())
104
+ try:
105
+ with open('encrypted_grades.csv', 'rb') as file:
106
+ encrypted_data = file.read()
107
+ decrypted_data = f.decrypt(encrypted_data)
108
+ return pd.read_csv(io.StringIO(decrypted_data.decode()))
109
+ except Exception as e:
110
+ st.error(f"Error decrypting file: {str(e)}")
111
+ return pd.DataFrame()
112
+
113
+ # Main function to run the Streamlit app
114
+ def main():
115
+ st.title('📚 Midterm Grade for 2nd Sem 2024-2025')
116
+ st.markdown("---")
117
+
118
+ if not is_logged_in():
119
+ st.write("Please log in with your CSPC Google account to access your grade.")
120
+
121
+ if st.button("Login with Google"):
122
+ flow = create_flow()
123
+ authorization_url, _ = flow.authorization_url(prompt="consent")
124
+ st.markdown(f'<meta http-equiv="refresh" content="0;url={authorization_url}">', unsafe_allow_html=True)
125
+ else:
126
+ credentials = Credentials.from_authorized_user_info(json.loads(st.session_state['credentials']))
127
+ user_info = get_user_info(credentials)
128
+ st.markdown(f"<p class='welcome-message'>Welcome, {user_info['name']}!</p>", unsafe_allow_html=True)
129
+
130
+ # Load the data
131
+ df = load_data()
132
+
133
+ # Look up the student's information using their email
134
+ student_records = df[df['EMAIL'].str.lower() == user_info['email'].lower()]
135
+
136
+ if not student_records.empty:
137
+ st.markdown("---")
138
+ st.subheader('Your Grade Information:')
139
+
140
+ for index, record in student_records.iterrows():
141
+ st.markdown(f"### Course: {record['COURSE']}")
142
+
143
+ col1, col2, col3 = st.columns(3)
144
+
145
+ with col1:
146
+ st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
147
+ st.write(f"{record['ID']}")
148
+
149
+ with col2:
150
+ st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
151
+ grade = record['GRADE']
152
+ if pd.isna(grade):
153
+ grade_display = "N/A"
154
+ else:
155
+ grade_display = f"{grade:.2f}"
156
+ st.write(grade_display)
157
+
158
+ with col3:
159
+ st.markdown("<p class='big-font'>Remarks</p>", unsafe_allow_html=True)
160
+ remarks = record['REMARKS']
161
+ if remarks == "Passed":
162
+ st.success(remarks)
163
+ elif remarks == "Conditional":
164
+ st.warning(remarks)
165
+ else:
166
+ st.write(remarks)
167
+
168
+ if not pd.isna(grade):
169
+ if grade >= 1.9 and grade <= 3.0:
170
+ message = f"Keep up the good work! Your grade of {grade:.2f} shows dedication. Consider seeking additional support to further improve your performance."
171
+ st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
172
+
173
+ elif grade > 3.00:
174
+ 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."
175
+ st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
176
+ else:
177
+ message = f"Congratulations! Your outstanding grade of {grade:.2f} demonstrates exceptional performance. Keep up the excellent work!"
178
+ st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
179
+
180
+ if remarks == "Conditional":
181
+ 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."
182
+ st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
183
+
184
+ st.markdown("---")
185
+ else:
186
+ st.error('Your email is not found in our records. Please contact the administrator.')
187
+
188
+ if st.button("Logout"):
189
+ for key in list(st.session_state.keys()):
190
+ del st.session_state[key]
191
+ st.rerun()
192
+
193
+ # Function to handle OAuth callback
194
+ def handle_callback():
195
+ flow = create_flow()
196
+ try:
197
+ flow.fetch_token(code=st.query_params["code"])
198
+ credentials = flow.credentials
199
+ st.session_state['credentials'] = credentials.to_json()
200
+ logging.debug("Token fetch successful")
201
+ st.success("Authentication successful!")
202
+ time.sleep(2) # Give user time to see the success message
203
+ st.rerun() # Rerun the app to clear the URL parameters
204
+ except Exception as e:
205
+ pass
206
+ # logging.error(f"Error during authentication: {str(e)}")
207
+ # st.error(f"Authentication failed: {str(e)}")
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
+ main()
app.py CHANGED
@@ -14,6 +14,7 @@ import logging
14
  from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
15
  import secrets
16
  import time
 
17
 
18
  # Load environment variables from .env file
19
  load_dotenv()
@@ -92,23 +93,15 @@ def get_user_info(credentials):
92
  user_info = service.userinfo().get().execute()
93
  return user_info
94
 
95
- # Load and decrypt the CSV file
96
- @st.cache_data
97
- def load_data():
98
- encryption_key = os.getenv('ENCRYPTION_KEY')
99
- if not encryption_key:
100
- st.error("Encryption key not found in environment variables.")
101
- return pd.DataFrame()
102
-
103
- f = Fernet(encryption_key.encode())
104
- try:
105
- with open('encrypted_grades.csv', 'rb') as file:
106
- encrypted_data = file.read()
107
- decrypted_data = f.decrypt(encrypted_data)
108
- return pd.read_csv(io.StringIO(decrypted_data.decode()))
109
- except Exception as e:
110
- st.error(f"Error decrypting file: {str(e)}")
111
- return pd.DataFrame()
112
 
113
  # Main function to run the Streamlit app
114
  def main():
@@ -126,64 +119,88 @@ def main():
126
  credentials = Credentials.from_authorized_user_info(json.loads(st.session_state['credentials']))
127
  user_info = get_user_info(credentials)
128
  st.markdown(f"<p class='welcome-message'>Welcome, {user_info['name']}!</p>", unsafe_allow_html=True)
129
-
130
- # Load the data
131
- df = load_data()
132
 
133
- # Look up the student's information using their email
134
- student_records = df[df['EMAIL'].str.lower() == user_info['email'].lower()]
 
135
 
136
- if not student_records.empty:
137
- st.markdown("---")
138
- st.subheader('Your Grade Information:')
 
 
 
139
 
140
- for index, record in student_records.iterrows():
141
- st.markdown(f"### Course: {record['COURSE']}")
142
-
143
- col1, col2, col3 = st.columns(3)
144
-
145
- with col1:
146
- st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
147
- st.write(f"{record['ID']}")
148
-
149
- with col2:
150
- st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
151
- grade = record['GRADE']
152
- if pd.isna(grade):
153
- grade_display = "N/A"
154
- else:
155
- grade_display = f"{grade:.2f}"
156
- st.write(grade_display)
157
-
158
- with col3:
159
- st.markdown("<p class='big-font'>Remarks</p>", unsafe_allow_html=True)
160
- remarks = record['REMARKS']
161
- if remarks == "Passed":
162
- st.success(remarks)
163
- elif remarks == "Conditional":
164
- st.warning(remarks)
165
- else:
166
- st.write(remarks)
167
 
168
- if not pd.isna(grade):
169
- if grade >= 1.9 and grade <= 3.0:
170
- message = f"Keep up the good work! Your grade of {grade:.2f} shows dedication. Consider seeking additional support to further improve your performance."
171
- st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
 
 
 
172
 
173
- elif grade > 3.00:
174
- 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."
175
- st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
176
- else:
177
- message = f"Congratulations! Your outstanding grade of {grade:.2f} demonstrates exceptional performance. Keep up the excellent work!"
178
- st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
179
-
180
- if remarks == "Conditional":
181
- 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."
182
- st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
183
-
184
- st.markdown("---")
185
- else:
186
- st.error('Your email is not found in our records. Please contact the administrator.')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  if st.button("Logout"):
189
  for key in list(st.session_state.keys()):
@@ -206,6 +223,15 @@ def handle_callback():
206
  # logging.error(f"Error during authentication: {str(e)}")
207
  # st.error(f"Authentication failed: {str(e)}")
208
 
 
 
 
 
 
 
 
 
 
209
  if __name__ == '__main__':
210
  logging.debug("Starting the application")
211
  if 'code' in st.query_params:
 
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()
 
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.db.host,
100
+ port=int(st.secrets.db.port),
101
+ user=st.secrets.db.user,
102
+ password=st.secrets.db.password,
103
+ database=st.secrets.db.database
104
+ )
 
 
 
 
 
 
 
 
105
 
106
  # Main function to run the Streamlit app
107
  def main():
 
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"{record['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
  if st.button("Logout"):
206
  for key in list(st.session_state.keys()):
 
223
  # logging.error(f"Error during authentication: {str(e)}")
224
  # st.error(f"Authentication failed: {str(e)}")
225
 
226
+ # Database configuration
227
+ DB_CONFIG = {
228
+ 'host': st.secrets.db.host,
229
+ 'port': int(st.secrets.db.port),
230
+ 'user': st.secrets.db.user,
231
+ 'password': st.secrets.db.password,
232
+ 'database': st.secrets.db.database
233
+ }
234
+
235
  if __name__ == '__main__':
236
  logging.debug("Starting the application")
237
  if 'code' in st.query_params: