GRADEVIEW / app.py
MENG21's picture
modified: app.py
72fe06e
raw
history blame
7.78 kB
import streamlit as st
import pandas as pd
import numpy as np
from cryptography.fernet import Fernet
import os
import io
from dotenv import load_dotenv
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
import json
import logging
from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
import secrets
import time
# Load environment variables from .env file
load_dotenv()
# Set up logging
logging.basicConfig(level=logging.DEBUG)
# Set page configuration
st.set_page_config(page_title="Student Grade Lookup", page_icon="πŸ“š", layout="centered")
#ADDD
# Custom CSS to improve the app's appearance
st.markdown("""
<style>
.reportview-container {
background: #f0f2f6
}
.big-font {
font-size:20px !important;
font-weight: bold;
}
.welcome-message {
font-size:24px !important;
font-weight: bold;
margin-bottom: 20px;
}
.stAlert > div {
padding-top: 15px;
padding-bottom: 15px;
}
.message {
font-size: 18px;
font-style: italic;
margin-top: 20px;
}
.warning-message {
font-size: 18px;
font-weight: bold;
color: #ff9800;
margin-top: 20px;
}
</style>
""", unsafe_allow_html=True)
# Google OAuth configuration
CLIENT_CONFIG = {
"web": {
"client_id": os.getenv("GOOGLE_CLIENT_ID"),
"client_secret": os.getenv("GOOGLE_CLIENT_SECRET"),
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
}
}
SCOPES = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', 'openid']
# Function to create OAuth flow
def create_flow():
redirect_uri = "https://meng21-gradeview.hf.space/" # Update this with your Streamlit app's URL
logging.debug(f"Creating flow with redirect URI: {redirect_uri}")
flow = Flow.from_client_config(
client_config=CLIENT_CONFIG,
scopes=SCOPES,
redirect_uri=redirect_uri
)
return flow
# Function to check if the user is logged in
def is_logged_in():
return 'credentials' in st.session_state
# Function to get user info
def get_user_info(credentials):
service = build('oauth2', 'v2', credentials=credentials)
user_info = service.userinfo().get().execute()
return user_info
# Load and decrypt the CSV file
@st.cache_data
def load_data():
encryption_key = os.getenv('ENCRYPTION_KEY')
if not encryption_key:
st.error("Encryption key not found in environment variables.")
return pd.DataFrame()
f = Fernet(encryption_key.encode())
try:
with open('encrypted_grades.csv', 'rb') as file:
encrypted_data = file.read()
decrypted_data = f.decrypt(encrypted_data)
return pd.read_csv(io.StringIO(decrypted_data.decode()))
except Exception as e:
st.error(f"Error decrypting file: {str(e)}")
return pd.DataFrame()
# Main function to run the Streamlit app
def main():
st.title('πŸ“š Student Grade Lookup')
st.markdown("---")
if not is_logged_in():
st.write("Please log in with your CSPC Google account to access your grade.")
if st.button("Login with Google"):
flow = create_flow()
authorization_url, _ = flow.authorization_url(prompt="consent")
st.markdown(f'<meta http-equiv="refresh" content="0;url={authorization_url}">', unsafe_allow_html=True)
else:
credentials = Credentials.from_authorized_user_info(json.loads(st.session_state['credentials']))
user_info = get_user_info(credentials)
st.markdown(f"<p class='welcome-message'>Welcome, {user_info['name']}!</p>", unsafe_allow_html=True)
# Load the data
df = load_data()
# Look up the student's information using their email
student_records = df[df['EMAIL'].str.lower() == user_info['email'].lower()]
if not student_records.empty:
st.markdown("---")
st.subheader('Your Grade Information:')
for index, record in student_records.iterrows():
st.markdown(f"### Course: {record['COURSE']}")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
st.write(f"{record['ID']}")
with col2:
st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
grade = record['GRADE']
if pd.isna(grade):
grade_display = "N/A"
else:
grade_display = f"{grade:.2f}"
st.write(grade_display)
with col3:
st.markdown("<p class='big-font'>Remarks</p>", unsafe_allow_html=True)
remarks = record['REMARKS']
if remarks == "Passed":
st.success(remarks)
elif remarks == "Conditional":
st.warning(remarks)
else:
st.write(remarks)
if not pd.isna(grade):
if grade > 1.9:
message = f"Keep up the good work! Your grade of {grade:.2f} shows dedication. Consider seeking additional support to further improve your performance."
st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
else:
message = f"Congratulations! Your outstanding grade of {grade:.2f} demonstrates exceptional performance. Keep up the excellent work!"
st.markdown(f"<p class='message'>{message}</p>", unsafe_allow_html=True)
if remarks == "Conditional":
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."
st.markdown(f"<p class='warning-message'>{warning_message}</p>", unsafe_allow_html=True)
st.markdown("---")
else:
st.error('Your email is not found in our records. Please contact the administrator.')
if st.button("Logout"):
for key in list(st.session_state.keys()):
del st.session_state[key]
st.rerun()
# Function to handle OAuth callback
def handle_callback():
flow = create_flow()
try:
flow.fetch_token(code=st.query_params["code"])
credentials = flow.credentials
st.session_state['credentials'] = credentials.to_json()
logging.debug("Token fetch successful")
st.success("Authentication successful!")
time.sleep(2) # Give user time to see the success message
st.rerun() # Rerun the app to clear the URL parameters
except Exception as e:
pass
# logging.error(f"Error during authentication: {str(e)}")
# st.error(f"Authentication failed: {str(e)}")
if __name__ == '__main__':
logging.debug("Starting the application")
if 'code' in st.query_params:
logging.debug("Authorization code found in query parameters")
handle_callback()
main()