Spaces:
Running
Running
added admin mode for data reloading and keeps logs safe
Browse files
app.py
CHANGED
|
@@ -5,6 +5,7 @@ from google.auth.transport.requests import Request
|
|
| 5 |
from google.oauth2.credentials import Credentials
|
| 6 |
from google_auth_oauthlib.flow import InstalledAppFlow
|
| 7 |
import json
|
|
|
|
| 8 |
import gradio as gr
|
| 9 |
import time
|
| 10 |
from datetime import datetime
|
|
@@ -1290,6 +1291,81 @@ def get_system_info():
|
|
| 1290 |
|
| 1291 |
return "\n".join(output)
|
| 1292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1293 |
# Create Gradio interface
|
| 1294 |
with gr.Blocks(
|
| 1295 |
title="Student Reward Points Check",
|
|
@@ -1386,6 +1462,80 @@ with gr.Blocks(
|
|
| 1386 |
show_copy_button=True,
|
| 1387 |
autoscroll=False
|
| 1388 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1389 |
|
| 1390 |
# Event handlers - FIXED: Proper input/output mapping
|
| 1391 |
|
|
@@ -1453,6 +1603,21 @@ with gr.Blocks(
|
|
| 1453 |
elem_id="footer"
|
| 1454 |
)
|
| 1455 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1456 |
# System info initialization function - Fixed to handle errors gracefully
|
| 1457 |
def initialize_system_info():
|
| 1458 |
"""Initialize system information display with error handling"""
|
|
@@ -1463,6 +1628,11 @@ with gr.Blocks(
|
|
| 1463 |
print(error_msg)
|
| 1464 |
return "β οΈ System information will be available after data loads completely. Please click 'Get System Information' button to retry."
|
| 1465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1466 |
# Load system info on startup
|
| 1467 |
app.load(
|
| 1468 |
fn=initialize_system_info,
|
|
|
|
| 5 |
from google.oauth2.credentials import Credentials
|
| 6 |
from google_auth_oauthlib.flow import InstalledAppFlow
|
| 7 |
import json
|
| 8 |
+
import urllib
|
| 9 |
import gradio as gr
|
| 10 |
import time
|
| 11 |
from datetime import datetime
|
|
|
|
| 1291 |
|
| 1292 |
return "\n".join(output)
|
| 1293 |
|
| 1294 |
+
# Admin UI Controls
|
| 1295 |
+
def build_admin_section():
|
| 1296 |
+
"""Build admin controls section"""
|
| 1297 |
+
with gr.Accordion("π§ Admin Controls", open=False, visible=True) as admin_accordion:
|
| 1298 |
+
admin_key = gr.Textbox(
|
| 1299 |
+
label="Enter Admin Key",
|
| 1300 |
+
type="password",
|
| 1301 |
+
placeholder="Admin Only",
|
| 1302 |
+
value=""
|
| 1303 |
+
)
|
| 1304 |
+
load_button = gr.Button("π Reload All Data", visible=False, variant="primary")
|
| 1305 |
+
admin_status = gr.Markdown("βΉοΈ Enter admin key to access controls", visible=True)
|
| 1306 |
+
|
| 1307 |
+
def verify_admin_key(key):
|
| 1308 |
+
"""Verify admin key and show/hide controls"""
|
| 1309 |
+
if key.strip() == os.getenv("ADMIN_KEY", ""):
|
| 1310 |
+
return (
|
| 1311 |
+
gr.update(visible=True), # Show reload button
|
| 1312 |
+
"β
Access granted. You can reload data now."
|
| 1313 |
+
)
|
| 1314 |
+
elif key.strip() == "":
|
| 1315 |
+
return (
|
| 1316 |
+
gr.update(visible=False), # Hide reload button
|
| 1317 |
+
"βΉοΈ Enter admin key to access controls"
|
| 1318 |
+
)
|
| 1319 |
+
else:
|
| 1320 |
+
return (
|
| 1321 |
+
gr.update(visible=False), # Hide reload button
|
| 1322 |
+
"β Invalid admin key."
|
| 1323 |
+
)
|
| 1324 |
+
|
| 1325 |
+
def admin_reload():
|
| 1326 |
+
"""Admin function to reload all data"""
|
| 1327 |
+
try:
|
| 1328 |
+
print("π§ Admin reload triggered...")
|
| 1329 |
+
combined_df, studentwise_data, details_info, reward_points_df = load_all_data()
|
| 1330 |
+
|
| 1331 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 1332 |
+
return f"β
Data reloaded successfully at {timestamp}\nπ Total records: {len(combined_df) if not combined_df.empty else 0}"
|
| 1333 |
+
except Exception as e:
|
| 1334 |
+
return f"β Error reloading data: {str(e)}"
|
| 1335 |
+
|
| 1336 |
+
# Event handlers
|
| 1337 |
+
admin_key.change(
|
| 1338 |
+
fn=verify_admin_key,
|
| 1339 |
+
inputs=admin_key,
|
| 1340 |
+
outputs=[load_button, admin_status]
|
| 1341 |
+
)
|
| 1342 |
+
|
| 1343 |
+
load_button.click(
|
| 1344 |
+
fn=admin_reload,
|
| 1345 |
+
outputs=admin_status
|
| 1346 |
+
)
|
| 1347 |
+
|
| 1348 |
+
return admin_accordion, admin_key, load_button, admin_status
|
| 1349 |
+
|
| 1350 |
+
# Function to determine if admin mode is enabled via URL parameter
|
| 1351 |
+
def check_admin_mode(request: gr.Request) -> bool:
|
| 1352 |
+
"""Check if admin mode is enabled via URL parameter"""
|
| 1353 |
+
try:
|
| 1354 |
+
query_params = urllib.parse.parse_qs(str(request.url).split('?')[1] if '?' in str(request.url) else "")
|
| 1355 |
+
admin_param = query_params.get(os.getenv("ADMIN_MODE_URL"), [""])[0]
|
| 1356 |
+
admin_mode_key = os.getenv("ADMIN_MODE_KEY", "")
|
| 1357 |
+
|
| 1358 |
+
is_admin = admin_param == admin_mode_key and admin_mode_key != ""
|
| 1359 |
+
if is_admin:
|
| 1360 |
+
print(f"π§ Admin mode activated via URL parameter")
|
| 1361 |
+
return is_admin
|
| 1362 |
+
except Exception as e:
|
| 1363 |
+
print(f"β οΈ Error checking admin mode: {str(e)}")
|
| 1364 |
+
return False
|
| 1365 |
+
|
| 1366 |
+
|
| 1367 |
+
|
| 1368 |
+
|
| 1369 |
# Create Gradio interface
|
| 1370 |
with gr.Blocks(
|
| 1371 |
title="Student Reward Points Check",
|
|
|
|
| 1462 |
show_copy_button=True,
|
| 1463 |
autoscroll=False
|
| 1464 |
)
|
| 1465 |
+
|
| 1466 |
+
with gr.TabItem("π§ Admin Controls", visible=False) as admin_tab: # Start hidden by default
|
| 1467 |
+
gr.Markdown("### π Administrative Functions")
|
| 1468 |
+
gr.Markdown("β οΈ **Access restricted to authorized personnel only**")
|
| 1469 |
+
|
| 1470 |
+
with gr.Row():
|
| 1471 |
+
with gr.Column(scale=1):
|
| 1472 |
+
admin_key = gr.Textbox(
|
| 1473 |
+
label="Enter Admin Key",
|
| 1474 |
+
type="password",
|
| 1475 |
+
placeholder="Enter admin password",
|
| 1476 |
+
value=""
|
| 1477 |
+
)
|
| 1478 |
+
|
| 1479 |
+
with gr.Column(scale=1):
|
| 1480 |
+
load_button = gr.Button("π Reload All Data", visible=False, variant="primary", size="lg")
|
| 1481 |
+
|
| 1482 |
+
admin_status = gr.Markdown("βΉοΈ Enter admin key to access controls", visible=True)
|
| 1483 |
+
|
| 1484 |
+
# Admin functions
|
| 1485 |
+
def verify_admin_key(key):
|
| 1486 |
+
"""Verify admin key and show/hide controls"""
|
| 1487 |
+
if key.strip() == os.getenv("ADMIN_KEY", ""):
|
| 1488 |
+
return (
|
| 1489 |
+
gr.update(visible=True), # Show reload button
|
| 1490 |
+
"β
**Access Granted!** You can now reload data."
|
| 1491 |
+
)
|
| 1492 |
+
elif key.strip() == "":
|
| 1493 |
+
return (
|
| 1494 |
+
gr.update(visible=False), # Hide reload button
|
| 1495 |
+
"βΉοΈ Enter admin key to access controls"
|
| 1496 |
+
)
|
| 1497 |
+
else:
|
| 1498 |
+
return (
|
| 1499 |
+
gr.update(visible=False), # Hide reload button
|
| 1500 |
+
"β **Access Denied!** Invalid admin key."
|
| 1501 |
+
)
|
| 1502 |
+
|
| 1503 |
+
def admin_reload():
|
| 1504 |
+
"""Admin function to reload all data"""
|
| 1505 |
+
try:
|
| 1506 |
+
print("π§ Admin reload triggered...")
|
| 1507 |
+
combined_df, studentwise_data, details_info, reward_points_df = load_all_data()
|
| 1508 |
+
|
| 1509 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 1510 |
+
total_records = len(combined_df) if not combined_df.empty else 0
|
| 1511 |
+
|
| 1512 |
+
return f"""β
**Data Reload Successful!**
|
| 1513 |
+
|
| 1514 |
+
π
**Timestamp:** {timestamp}\n
|
| 1515 |
+
π **Total Records:** {total_records:,}\n
|
| 1516 |
+
π **Status:** All data sources refreshed\n
|
| 1517 |
+
β° **Next Auto-refresh:** 12 hours from now\n
|
| 1518 |
+
π― **Data Sources Updated:**\n
|
| 1519 |
+
β’ Main spreadsheet ({len(sheet_configs)} sheets)\n
|
| 1520 |
+
β’ Studentwise reward points data\n
|
| 1521 |
+
β’ Activity breakdown data\n
|
| 1522 |
+
β’ System information"""
|
| 1523 |
+
|
| 1524 |
+
except Exception as e:
|
| 1525 |
+
return f"β **Error reloading data:** {str(e)}"
|
| 1526 |
+
|
| 1527 |
+
# Event handlers for admin tab
|
| 1528 |
+
admin_key.change(
|
| 1529 |
+
fn=verify_admin_key,
|
| 1530 |
+
inputs=admin_key,
|
| 1531 |
+
outputs=[load_button, admin_status]
|
| 1532 |
+
)
|
| 1533 |
+
|
| 1534 |
+
load_button.click(
|
| 1535 |
+
fn=admin_reload,
|
| 1536 |
+
outputs=admin_status
|
| 1537 |
+
)
|
| 1538 |
+
|
| 1539 |
|
| 1540 |
# Event handlers - FIXED: Proper input/output mapping
|
| 1541 |
|
|
|
|
| 1603 |
elem_id="footer"
|
| 1604 |
)
|
| 1605 |
|
| 1606 |
+
def setup_admin_mode(request: gr.Request):
|
| 1607 |
+
"""Setup admin mode based on URL parameters"""
|
| 1608 |
+
try:
|
| 1609 |
+
is_admin = check_admin_mode(request)
|
| 1610 |
+
if is_admin:
|
| 1611 |
+
print("π§ Admin tab will be visible")
|
| 1612 |
+
return gr.update(visible=True) # Show admin tab
|
| 1613 |
+
else:
|
| 1614 |
+
return gr.update(visible=False) # Hide admin tab
|
| 1615 |
+
except Exception as e:
|
| 1616 |
+
print(f"β οΈ Error in setup_admin_mode: {str(e)}")
|
| 1617 |
+
return gr.update(visible=False) # Hide admin tab on error
|
| 1618 |
+
|
| 1619 |
+
|
| 1620 |
+
|
| 1621 |
# System info initialization function - Fixed to handle errors gracefully
|
| 1622 |
def initialize_system_info():
|
| 1623 |
"""Initialize system information display with error handling"""
|
|
|
|
| 1628 |
print(error_msg)
|
| 1629 |
return "β οΈ System information will be available after data loads completely. Please click 'Get System Information' button to retry."
|
| 1630 |
|
| 1631 |
+
app.load(
|
| 1632 |
+
fn=setup_admin_mode,
|
| 1633 |
+
outputs=admin_tab
|
| 1634 |
+
)
|
| 1635 |
+
|
| 1636 |
# Load system info on startup
|
| 1637 |
app.load(
|
| 1638 |
fn=initialize_system_info,
|