Jacksonnavigator7 commited on
Commit
cb6c1f9
Β·
verified Β·
1 Parent(s): b219018

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +326 -58
app.py CHANGED
@@ -6,47 +6,125 @@ from database import (
6
  get_open_session, has_marked_attendance, mark_attendance, get_attendance_summary
7
  )
8
 
 
9
  init_db()
10
 
 
11
  current_user = {"email": None, "role": None, "device_id": None, "class_id": None}
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  # --- Login Logic ---
14
  def login(email, password):
 
 
 
15
  device_id = get_device_id()
16
  success, message = authenticate_user(email, password, device_id)
 
17
  if success:
18
  current_user["email"] = email
19
  current_user["role"] = get_user_role(email)
20
  current_user["device_id"] = device_id
21
 
22
- # Get class_id
23
  conn = sqlite3.connect("attendance.db")
24
  cursor = conn.cursor()
25
- cursor.execute("SELECT class_id FROM users WHERE email=?", (email,))
26
  row = cursor.fetchone()
27
  current_user["class_id"] = row[0] if row else None
 
28
  conn.close()
29
 
30
- return f"Welcome, {email}! You are logged in as {current_user['role']}.", gr.update(visible=True), gr.update(visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  else:
32
- return message, gr.update(visible=False), gr.update(visible=True)
 
 
 
 
 
 
 
 
 
 
33
 
34
  # --- Teacher Dashboard Functions ---
35
  def teacher_dashboard_view():
36
  if current_user["role"] != "teacher":
37
  return "Access denied. You are not a teacher."
 
38
  sessions = get_sessions(current_user["class_id"])
39
- session_text = "\n".join([f"ID: {s[0]}, Date: {s[1]}, Open: {bool(s[2])}" for s in sessions])
40
- return session_text if session_text else "No sessions found."
 
 
 
 
 
 
 
 
 
41
 
42
  def handle_open_session():
43
- return toggle_session(current_user["class_id"], True)
 
 
 
 
44
 
45
  def handle_close_session():
46
- return toggle_session(current_user["class_id"], False)
 
 
 
 
47
 
48
  def handle_add_student(name, email, password):
49
- return add_student(name, email, password, current_user["class_id"])
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  # --- Student Dashboard Functions ---
52
  def handle_mark_attendance():
@@ -54,59 +132,249 @@ def handle_mark_attendance():
54
  return "Access denied. You are not a student."
55
 
56
  session_id = get_open_session(current_user["class_id"])
 
57
  if not session_id:
58
- return "No open attendance session right now."
59
 
60
  if has_marked_attendance(current_user["email"], session_id):
61
- return "You have already marked attendance for this session."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- return mark_attendance(current_user["email"], session_id)
 
 
 
64
 
65
- def handle_summary():
66
- return get_attendance_summary(current_user["email"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  # --- UI Layout ---
69
- with gr.Blocks() as demo:
70
- gr.Markdown("# πŸ“² Mobile Attendance System")
71
-
72
- login_msg = gr.Textbox(label="Login Status", interactive=False)
73
- email = gr.Textbox(label="Email")
74
- password = gr.Textbox(label="Password", type="password")
75
- login_btn = gr.Button("Login")
76
-
77
- dashboard_box = gr.Column(visible=False)
78
-
79
- with dashboard_box:
80
- gr.Markdown("## πŸ§‘β€πŸ« Teacher Dashboard")
81
- refresh_btn = gr.Button("πŸ“‹ View All Sessions")
82
- session_output = gr.Textbox(label="Session Logs", lines=6)
83
-
84
- open_btn = gr.Button("βœ… Open New Attendance Session")
85
- close_btn = gr.Button("❌ Close Attendance Session")
86
- session_status = gr.Textbox(label="Session Status")
87
-
88
- gr.Markdown("### βž• Add Student")
89
- student_name = gr.Textbox(label="Name")
90
- student_email = gr.Textbox(label="Email")
91
- student_pass = gr.Textbox(label="Password")
92
- add_btn = gr.Button("Add Student")
93
- add_status = gr.Textbox(label="Add Student Status")
94
-
95
- gr.Markdown("## πŸ‘¨β€πŸŽ“ Student Dashboard")
96
- mark_btn = gr.Button("πŸ“ Mark Attendance")
97
- mark_status = gr.Textbox(label="Marking Result")
98
- view_summary_btn = gr.Button("πŸ“† View Attendance Summary")
99
- summary_output = gr.Textbox(label="Attendance Summary", lines=5)
100
-
101
- # --- Event Bindings ---
102
- login_btn.click(fn=login, inputs=[email, password], outputs=[login_msg, dashboard_box, dashboard_box])
103
- refresh_btn.click(fn=teacher_dashboard_view, outputs=session_output)
104
- open_btn.click(fn=handle_open_session, outputs=session_status)
105
- close_btn.click(fn=handle_close_session, outputs=session_status)
106
- add_btn.click(fn=handle_add_student, inputs=[student_name, student_email, student_pass], outputs=add_status)
107
- mark_btn.click(fn=handle_mark_attendance, outputs=mark_status)
108
- view_summary_btn.click(fn=handle_summary, outputs=summary_output)
109
-
110
- gr.Markdown("Made for Hugging Face Spaces")
111
-
112
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  get_open_session, has_marked_attendance, mark_attendance, get_attendance_summary
7
  )
8
 
9
+ # Initialize the database
10
  init_db()
11
 
12
+ # Global user state
13
  current_user = {"email": None, "role": None, "device_id": None, "class_id": None}
14
 
15
+ # Custom theme for the app
16
+ theme = gr.themes.Soft(
17
+ primary_hue="indigo",
18
+ secondary_hue="blue",
19
+ neutral_hue="slate",
20
+ radius_size=gr.themes.sizes.radius_md,
21
+ ).set(
22
+ button_primary_background_fill="*primary_500",
23
+ button_primary_background_fill_hover="*primary_600",
24
+ button_primary_text_color="white",
25
+ button_secondary_background_fill="*neutral_100",
26
+ button_secondary_background_fill_hover="*neutral_200",
27
+ button_secondary_text_color="*neutral_800",
28
+ block_label_background_fill="*neutral_50",
29
+ block_title_text_weight="600",
30
+ )
31
+
32
  # --- Login Logic ---
33
  def login(email, password):
34
+ if not email or not password:
35
+ return "Please fill in all fields.", gr.update(visible=False), gr.update(visible=True)
36
+
37
  device_id = get_device_id()
38
  success, message = authenticate_user(email, password, device_id)
39
+
40
  if success:
41
  current_user["email"] = email
42
  current_user["role"] = get_user_role(email)
43
  current_user["device_id"] = device_id
44
 
45
+ # Get class_id and name
46
  conn = sqlite3.connect("attendance.db")
47
  cursor = conn.cursor()
48
+ cursor.execute("SELECT class_id, name FROM users WHERE email=?", (email,))
49
  row = cursor.fetchone()
50
  current_user["class_id"] = row[0] if row else None
51
+ user_name = row[1] if row else email
52
  conn.close()
53
 
54
+ # Set visibility based on user role
55
+ if current_user["role"] == "teacher":
56
+ return (
57
+ f"πŸ‘‹ Welcome, {user_name}!",
58
+ gr.update(visible=False),
59
+ gr.update(visible=True),
60
+ gr.update(selected="teacher_tab" if current_user["role"] == "teacher" else "student_tab")
61
+ )
62
+ else:
63
+ return (
64
+ f"πŸ‘‹ Welcome, {user_name}!",
65
+ gr.update(visible=False),
66
+ gr.update(visible=True),
67
+ gr.update(selected="student_tab")
68
+ )
69
  else:
70
+ return message, gr.update(visible=True), gr.update(visible=False), gr.update()
71
+
72
+ def logout():
73
+ # Reset user data
74
+ current_user["email"] = None
75
+ current_user["role"] = None
76
+ current_user["class_id"] = None
77
+ current_user["device_id"] = None
78
+
79
+ # Show login form, hide dashboard
80
+ return gr.update(visible=True), gr.update(visible=False)
81
 
82
  # --- Teacher Dashboard Functions ---
83
  def teacher_dashboard_view():
84
  if current_user["role"] != "teacher":
85
  return "Access denied. You are not a teacher."
86
+
87
  sessions = get_sessions(current_user["class_id"])
88
+
89
+ # Format sessions as a list of dictionaries for the DataFrame
90
+ session_data = [
91
+ {"ID": s[0], "Date & Time": s[1], "Status": "🟒 Open" if bool(s[2]) else "πŸ”΄ Closed"}
92
+ for s in sessions
93
+ ]
94
+
95
+ if not session_data:
96
+ session_data = [{"ID": "-", "Date & Time": "-", "Status": "-"}]
97
+
98
+ return session_data
99
 
100
  def handle_open_session():
101
+ if current_user["role"] != "teacher":
102
+ return "Access denied.", teacher_dashboard_view()
103
+
104
+ result = toggle_session(current_user["class_id"], True)
105
+ return f"βœ… {result}", teacher_dashboard_view()
106
 
107
  def handle_close_session():
108
+ if current_user["role"] != "teacher":
109
+ return "Access denied.", teacher_dashboard_view()
110
+
111
+ result = toggle_session(current_user["class_id"], False)
112
+ return f"❌ {result}", teacher_dashboard_view()
113
 
114
  def handle_add_student(name, email, password):
115
+ if not name or not email or not password:
116
+ return "Please fill in all fields."
117
+
118
+ if current_user["role"] != "teacher":
119
+ return "Access denied. You are not authorized to add students."
120
+
121
+ result = add_student(name, email, password, current_user["class_id"])
122
+
123
+ # Clear the form on success
124
+ if "successfully" in result:
125
+ return f"βœ… {result}", "", "", ""
126
+ else:
127
+ return f"❌ {result}", gr.update(), gr.update(), gr.update()
128
 
129
  # --- Student Dashboard Functions ---
130
  def handle_mark_attendance():
 
132
  return "Access denied. You are not a student."
133
 
134
  session_id = get_open_session(current_user["class_id"])
135
+
136
  if not session_id:
137
+ return "❌ No open attendance session right now.", get_student_attendance_data()
138
 
139
  if has_marked_attendance(current_user["email"], session_id):
140
+ return "ℹ️ You have already marked attendance for this session.", get_student_attendance_data()
141
+
142
+ result = mark_attendance(current_user["email"], session_id)
143
+ return f"βœ… {result}", get_student_attendance_data()
144
+
145
+ def get_student_attendance_data():
146
+ if current_user["role"] != "student":
147
+ return [{"Date": "-", "Class": "-"}]
148
+
149
+ conn = sqlite3.connect("attendance.db")
150
+ cursor = conn.cursor()
151
+ cursor.execute("""
152
+ SELECT s.date, s.class_id
153
+ FROM attendance_logs a
154
+ JOIN sessions s ON a.session_id = s.id
155
+ WHERE a.student_email=?
156
+ ORDER BY s.date DESC
157
+ LIMIT 10
158
+ """, (current_user["email"],))
159
+ records = cursor.fetchall()
160
+ conn.close()
161
 
162
+ if not records:
163
+ return [{"Date": "-", "Class": "-"}]
164
+
165
+ return [{"Date": row[0], "Class": row[1]} for row in records]
166
 
167
+ def get_student_stats():
168
+ if current_user["role"] != "student" or not current_user["email"]:
169
+ return "0", "0%"
170
+
171
+ conn = sqlite3.connect("attendance.db")
172
+ cursor = conn.cursor()
173
+
174
+ # Get total sessions for the student's class
175
+ cursor.execute("SELECT COUNT(*) FROM sessions WHERE class_id=?", (current_user["class_id"],))
176
+ total_sessions = cursor.fetchone()[0]
177
+
178
+ # Get student's attendance count
179
+ cursor.execute("""
180
+ SELECT COUNT(*) FROM attendance_logs a
181
+ JOIN sessions s ON a.session_id = s.id
182
+ WHERE a.student_email=? AND s.class_id=?
183
+ """, (current_user["email"], current_user["class_id"]))
184
+ attended_sessions = cursor.fetchone()[0]
185
+ conn.close()
186
+
187
+ attendance_percentage = "0%"
188
+ if total_sessions > 0:
189
+ attendance_percentage = f"{(attended_sessions / total_sessions) * 100:.1f}%"
190
+
191
+ return str(attended_sessions), attendance_percentage
192
 
193
  # --- UI Layout ---
194
+ with gr.Blocks(theme=theme, title="Smart Attendance System") as demo:
195
+ gr.Markdown(
196
+ """
197
+ # πŸ“± Smart Attendance System
198
+ ### Modern attendance tracking for educational institutions
199
+ """
200
+ )
201
+
202
+ # Login Section
203
+ login_container = gr.Column(visible=True)
204
+ with login_container:
205
+ with gr.Group():
206
+ gr.Markdown("### Log in to your account")
207
+ with gr.Row():
208
+ with gr.Column(scale=2):
209
+ email = gr.Textbox(
210
+ label="Email Address",
211
+ placeholder="Enter your email",
212
+ scale=2
213
+ )
214
+ password = gr.Textbox(
215
+ label="Password",
216
+ placeholder="Enter your password",
217
+ type="password",
218
+ scale=2
219
+ )
220
+ login_msg = gr.Textbox(
221
+ label="",
222
+ interactive=False,
223
+ visible=True
224
+ )
225
+
226
+ with gr.Column(scale=1):
227
+ gr.Markdown("### Welcome!")
228
+ gr.Markdown("Sign in to access the attendance system. Teachers can manage sessions and students, while students can mark their attendance.")
229
+
230
+ with gr.Row():
231
+ login_btn = gr.Button(
232
+ "πŸ” Login",
233
+ variant="primary",
234
+ scale=1
235
+ )
236
+
237
+ # Dashboard Section
238
+ dashboard_container = gr.Column(visible=False)
239
+ with dashboard_container:
240
+ with gr.Row():
241
+ user_greeting = gr.Textbox(
242
+ value="Welcome!",
243
+ label="",
244
+ interactive=False
245
+ )
246
+ logout_btn = gr.Button(
247
+ "πŸšͺ Logout",
248
+ variant="secondary",
249
+ scale=0
250
+ )
251
+
252
+ # Tabs for different interfaces
253
+ with gr.Tabs(selected=0) as dashboard_tabs:
254
+ # Teacher Dashboard Tab
255
+ with gr.TabItem("πŸ‘¨β€πŸ« Teacher Dashboard", id="teacher_tab"):
256
+ with gr.Row():
257
+ with gr.Column(scale=2):
258
+ gr.Markdown("### Class Sessions")
259
+ with gr.Row():
260
+ open_btn = gr.Button("βœ… Open Session", variant="primary")
261
+ close_btn = gr.Button("❌ Close Session", variant="secondary")
262
+
263
+ session_status = gr.Textbox(label="", interactive=False)
264
+
265
+ gr.Markdown("### Session History")
266
+ refresh_btn = gr.Button("πŸ”„ Refresh Sessions", variant="secondary")
267
+ session_output = gr.DataFrame(
268
+ headers=["ID", "Date & Time", "Status"],
269
+ datatype=["number", "str", "str"],
270
+ label="All Sessions"
271
+ )
272
+
273
+ with gr.Column(scale=1):
274
+ gr.Markdown("### Add New Student")
275
+ with gr.Group():
276
+ student_name = gr.Textbox(
277
+ label="Student Name",
278
+ placeholder="Full name"
279
+ )
280
+ student_email = gr.Textbox(
281
+ label="Student Email",
282
+ placeholder="student@example.com"
283
+ )
284
+ student_pass = gr.Textbox(
285
+ label="Password",
286
+ placeholder="Create password",
287
+ type="password"
288
+ )
289
+ add_btn = gr.Button("βž• Add Student", variant="primary")
290
+ add_status = gr.Textbox(label="", interactive=False)
291
+
292
+ # Student Dashboard Tab
293
+ with gr.TabItem("πŸ‘¨β€πŸŽ“ Student Dashboard", id="student_tab"):
294
+ with gr.Row():
295
+ with gr.Column(scale=1):
296
+ gr.Markdown("### Quick Actions")
297
+ mark_btn = gr.Button("πŸ“ Mark Attendance", size="lg", variant="primary")
298
+ mark_status = gr.Textbox(label="Status", interactive=False)
299
+
300
+ gr.Markdown("### Your Statistics")
301
+ with gr.Row():
302
+ with gr.Column():
303
+ total_attended = gr.Textbox(label="Sessions Attended", interactive=False)
304
+ with gr.Column():
305
+ attendance_rate = gr.Textbox(label="Attendance Rate", interactive=False)
306
+
307
+ with gr.Column(scale=2):
308
+ gr.Markdown("### Attendance History")
309
+ attendance_table = gr.DataFrame(
310
+ headers=["Date", "Class"],
311
+ datatype=["str", "str"],
312
+ label="Your Recent Attendance",
313
+ interactive=False
314
+ )
315
+
316
+ # Event Bindings
317
+ login_btn.click(
318
+ fn=login,
319
+ inputs=[email, password],
320
+ outputs=[user_greeting, login_container, dashboard_container, dashboard_tabs]
321
+ )
322
+
323
+ logout_btn.click(
324
+ fn=logout,
325
+ outputs=[login_container, dashboard_container]
326
+ )
327
+
328
+ # Teacher functions
329
+ refresh_btn.click(
330
+ fn=teacher_dashboard_view,
331
+ outputs=session_output
332
+ )
333
+
334
+ open_btn.click(
335
+ fn=handle_open_session,
336
+ outputs=[session_status, session_output]
337
+ )
338
+
339
+ close_btn.click(
340
+ fn=handle_close_session,
341
+ outputs=[session_status, session_output]
342
+ )
343
+
344
+ add_btn.click(
345
+ fn=handle_add_student,
346
+ inputs=[student_name, student_email, student_pass],
347
+ outputs=[add_status, student_name, student_email, student_pass]
348
+ )
349
+
350
+ # Student functions
351
+ mark_btn.click(
352
+ fn=handle_mark_attendance,
353
+ outputs=[mark_status, attendance_table]
354
+ )
355
+
356
+ # Dynamic loading handlers
357
+ dashboard_tabs.select(
358
+ fn=lambda tab: teacher_dashboard_view() if tab == "teacher_tab" else get_student_attendance_data(),
359
+ inputs=dashboard_tabs,
360
+ outputs=session_output if dashboard_tabs.selected == "teacher_tab" else attendance_table
361
+ )
362
+
363
+ dashboard_tabs.select(
364
+ fn=lambda tab: get_student_stats() if tab == "student_tab" else (None, None),
365
+ inputs=dashboard_tabs,
366
+ outputs=[total_attended, attendance_rate]
367
+ )
368
+
369
+ # Footer
370
+ gr.Markdown(
371
+ """
372
+ ---
373
+ ### Smart Attendance - A modern attendance tracking solution
374
+ Version 2.0 | Β© 2025
375
+ """
376
+ )
377
+
378
+ # Launch the app
379
+ if __name__ == "__main__":
380
+ demo.launch(share=True)