Attendance / app.py
Jacksonnavigator7's picture
Update app.py
cb6c1f9 verified
import gradio as gr
import sqlite3
from utils import get_device_id, authenticate_user, get_user_role
from database import (
init_db, add_student, get_sessions, toggle_session,
get_open_session, has_marked_attendance, mark_attendance, get_attendance_summary
)
# Initialize the database
init_db()
# Global user state
current_user = {"email": None, "role": None, "device_id": None, "class_id": None}
# Custom theme for the app
theme = gr.themes.Soft(
primary_hue="indigo",
secondary_hue="blue",
neutral_hue="slate",
radius_size=gr.themes.sizes.radius_md,
).set(
button_primary_background_fill="*primary_500",
button_primary_background_fill_hover="*primary_600",
button_primary_text_color="white",
button_secondary_background_fill="*neutral_100",
button_secondary_background_fill_hover="*neutral_200",
button_secondary_text_color="*neutral_800",
block_label_background_fill="*neutral_50",
block_title_text_weight="600",
)
# --- Login Logic ---
def login(email, password):
if not email or not password:
return "Please fill in all fields.", gr.update(visible=False), gr.update(visible=True)
device_id = get_device_id()
success, message = authenticate_user(email, password, device_id)
if success:
current_user["email"] = email
current_user["role"] = get_user_role(email)
current_user["device_id"] = device_id
# Get class_id and name
conn = sqlite3.connect("attendance.db")
cursor = conn.cursor()
cursor.execute("SELECT class_id, name FROM users WHERE email=?", (email,))
row = cursor.fetchone()
current_user["class_id"] = row[0] if row else None
user_name = row[1] if row else email
conn.close()
# Set visibility based on user role
if current_user["role"] == "teacher":
return (
f"πŸ‘‹ Welcome, {user_name}!",
gr.update(visible=False),
gr.update(visible=True),
gr.update(selected="teacher_tab" if current_user["role"] == "teacher" else "student_tab")
)
else:
return (
f"πŸ‘‹ Welcome, {user_name}!",
gr.update(visible=False),
gr.update(visible=True),
gr.update(selected="student_tab")
)
else:
return message, gr.update(visible=True), gr.update(visible=False), gr.update()
def logout():
# Reset user data
current_user["email"] = None
current_user["role"] = None
current_user["class_id"] = None
current_user["device_id"] = None
# Show login form, hide dashboard
return gr.update(visible=True), gr.update(visible=False)
# --- Teacher Dashboard Functions ---
def teacher_dashboard_view():
if current_user["role"] != "teacher":
return "Access denied. You are not a teacher."
sessions = get_sessions(current_user["class_id"])
# Format sessions as a list of dictionaries for the DataFrame
session_data = [
{"ID": s[0], "Date & Time": s[1], "Status": "🟒 Open" if bool(s[2]) else "πŸ”΄ Closed"}
for s in sessions
]
if not session_data:
session_data = [{"ID": "-", "Date & Time": "-", "Status": "-"}]
return session_data
def handle_open_session():
if current_user["role"] != "teacher":
return "Access denied.", teacher_dashboard_view()
result = toggle_session(current_user["class_id"], True)
return f"βœ… {result}", teacher_dashboard_view()
def handle_close_session():
if current_user["role"] != "teacher":
return "Access denied.", teacher_dashboard_view()
result = toggle_session(current_user["class_id"], False)
return f"❌ {result}", teacher_dashboard_view()
def handle_add_student(name, email, password):
if not name or not email or not password:
return "Please fill in all fields."
if current_user["role"] != "teacher":
return "Access denied. You are not authorized to add students."
result = add_student(name, email, password, current_user["class_id"])
# Clear the form on success
if "successfully" in result:
return f"βœ… {result}", "", "", ""
else:
return f"❌ {result}", gr.update(), gr.update(), gr.update()
# --- Student Dashboard Functions ---
def handle_mark_attendance():
if current_user["role"] != "student":
return "Access denied. You are not a student."
session_id = get_open_session(current_user["class_id"])
if not session_id:
return "❌ No open attendance session right now.", get_student_attendance_data()
if has_marked_attendance(current_user["email"], session_id):
return "ℹ️ You have already marked attendance for this session.", get_student_attendance_data()
result = mark_attendance(current_user["email"], session_id)
return f"βœ… {result}", get_student_attendance_data()
def get_student_attendance_data():
if current_user["role"] != "student":
return [{"Date": "-", "Class": "-"}]
conn = sqlite3.connect("attendance.db")
cursor = conn.cursor()
cursor.execute("""
SELECT s.date, s.class_id
FROM attendance_logs a
JOIN sessions s ON a.session_id = s.id
WHERE a.student_email=?
ORDER BY s.date DESC
LIMIT 10
""", (current_user["email"],))
records = cursor.fetchall()
conn.close()
if not records:
return [{"Date": "-", "Class": "-"}]
return [{"Date": row[0], "Class": row[1]} for row in records]
def get_student_stats():
if current_user["role"] != "student" or not current_user["email"]:
return "0", "0%"
conn = sqlite3.connect("attendance.db")
cursor = conn.cursor()
# Get total sessions for the student's class
cursor.execute("SELECT COUNT(*) FROM sessions WHERE class_id=?", (current_user["class_id"],))
total_sessions = cursor.fetchone()[0]
# Get student's attendance count
cursor.execute("""
SELECT COUNT(*) FROM attendance_logs a
JOIN sessions s ON a.session_id = s.id
WHERE a.student_email=? AND s.class_id=?
""", (current_user["email"], current_user["class_id"]))
attended_sessions = cursor.fetchone()[0]
conn.close()
attendance_percentage = "0%"
if total_sessions > 0:
attendance_percentage = f"{(attended_sessions / total_sessions) * 100:.1f}%"
return str(attended_sessions), attendance_percentage
# --- UI Layout ---
with gr.Blocks(theme=theme, title="Smart Attendance System") as demo:
gr.Markdown(
"""
# πŸ“± Smart Attendance System
### Modern attendance tracking for educational institutions
"""
)
# Login Section
login_container = gr.Column(visible=True)
with login_container:
with gr.Group():
gr.Markdown("### Log in to your account")
with gr.Row():
with gr.Column(scale=2):
email = gr.Textbox(
label="Email Address",
placeholder="Enter your email",
scale=2
)
password = gr.Textbox(
label="Password",
placeholder="Enter your password",
type="password",
scale=2
)
login_msg = gr.Textbox(
label="",
interactive=False,
visible=True
)
with gr.Column(scale=1):
gr.Markdown("### Welcome!")
gr.Markdown("Sign in to access the attendance system. Teachers can manage sessions and students, while students can mark their attendance.")
with gr.Row():
login_btn = gr.Button(
"πŸ” Login",
variant="primary",
scale=1
)
# Dashboard Section
dashboard_container = gr.Column(visible=False)
with dashboard_container:
with gr.Row():
user_greeting = gr.Textbox(
value="Welcome!",
label="",
interactive=False
)
logout_btn = gr.Button(
"πŸšͺ Logout",
variant="secondary",
scale=0
)
# Tabs for different interfaces
with gr.Tabs(selected=0) as dashboard_tabs:
# Teacher Dashboard Tab
with gr.TabItem("πŸ‘¨β€πŸ« Teacher Dashboard", id="teacher_tab"):
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### Class Sessions")
with gr.Row():
open_btn = gr.Button("βœ… Open Session", variant="primary")
close_btn = gr.Button("❌ Close Session", variant="secondary")
session_status = gr.Textbox(label="", interactive=False)
gr.Markdown("### Session History")
refresh_btn = gr.Button("πŸ”„ Refresh Sessions", variant="secondary")
session_output = gr.DataFrame(
headers=["ID", "Date & Time", "Status"],
datatype=["number", "str", "str"],
label="All Sessions"
)
with gr.Column(scale=1):
gr.Markdown("### Add New Student")
with gr.Group():
student_name = gr.Textbox(
label="Student Name",
placeholder="Full name"
)
student_email = gr.Textbox(
label="Student Email",
placeholder="student@example.com"
)
student_pass = gr.Textbox(
label="Password",
placeholder="Create password",
type="password"
)
add_btn = gr.Button("βž• Add Student", variant="primary")
add_status = gr.Textbox(label="", interactive=False)
# Student Dashboard Tab
with gr.TabItem("πŸ‘¨β€πŸŽ“ Student Dashboard", id="student_tab"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Quick Actions")
mark_btn = gr.Button("πŸ“ Mark Attendance", size="lg", variant="primary")
mark_status = gr.Textbox(label="Status", interactive=False)
gr.Markdown("### Your Statistics")
with gr.Row():
with gr.Column():
total_attended = gr.Textbox(label="Sessions Attended", interactive=False)
with gr.Column():
attendance_rate = gr.Textbox(label="Attendance Rate", interactive=False)
with gr.Column(scale=2):
gr.Markdown("### Attendance History")
attendance_table = gr.DataFrame(
headers=["Date", "Class"],
datatype=["str", "str"],
label="Your Recent Attendance",
interactive=False
)
# Event Bindings
login_btn.click(
fn=login,
inputs=[email, password],
outputs=[user_greeting, login_container, dashboard_container, dashboard_tabs]
)
logout_btn.click(
fn=logout,
outputs=[login_container, dashboard_container]
)
# Teacher functions
refresh_btn.click(
fn=teacher_dashboard_view,
outputs=session_output
)
open_btn.click(
fn=handle_open_session,
outputs=[session_status, session_output]
)
close_btn.click(
fn=handle_close_session,
outputs=[session_status, session_output]
)
add_btn.click(
fn=handle_add_student,
inputs=[student_name, student_email, student_pass],
outputs=[add_status, student_name, student_email, student_pass]
)
# Student functions
mark_btn.click(
fn=handle_mark_attendance,
outputs=[mark_status, attendance_table]
)
# Dynamic loading handlers
dashboard_tabs.select(
fn=lambda tab: teacher_dashboard_view() if tab == "teacher_tab" else get_student_attendance_data(),
inputs=dashboard_tabs,
outputs=session_output if dashboard_tabs.selected == "teacher_tab" else attendance_table
)
dashboard_tabs.select(
fn=lambda tab: get_student_stats() if tab == "student_tab" else (None, None),
inputs=dashboard_tabs,
outputs=[total_attended, attendance_rate]
)
# Footer
gr.Markdown(
"""
---
### Smart Attendance - A modern attendance tracking solution
Version 2.0 | Β© 2025
"""
)
# Launch the app
if __name__ == "__main__":
demo.launch(share=True)