PraneshJs commited on
Commit
f343b19
Β·
verified Β·
1 Parent(s): cfb4845

added Admin Reload Feature

Browse files
Files changed (1) hide show
  1. app.py +184 -14
app.py CHANGED
@@ -6,6 +6,7 @@ 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
11
  from pytz import timezone
@@ -152,7 +153,7 @@ def load_reward_points_data():
152
  print(f"❌ Error loading Reward Points data: {str(e)}")
153
  return None
154
 
155
- # MODIFIED FUNCTION: Get activity details from cached data
156
  def get_activity_details(roll_no, reward_points_df):
157
  """Get activity details for a specific roll number from cached reward points data in breakdown format"""
158
  try:
@@ -225,6 +226,10 @@ def get_activity_details(roll_no, reward_points_df):
225
 
226
  # Format output in breakdown style
227
  output = []
 
 
 
 
228
  # Define all possible activity categories in order
229
  activity_categories = [
230
  "INITIAL POINTS / CARRY-OVER",
@@ -278,12 +283,22 @@ def get_activity_details(roll_no, reward_points_df):
278
  count = final_count.get(category, 0)
279
  points = final_summary.get(category, 0.0)
280
 
 
 
281
 
282
  # Add any categories not in the standard list
283
  for category, points in final_summary.items():
284
  if category not in activity_categories:
285
  count = final_count.get(category, 0)
 
 
286
 
 
 
 
 
 
 
287
 
288
  # Add detailed activity list if needed
289
  if len(student_rows) <= 20: # Only show detailed list for reasonable number of activities
@@ -303,10 +318,9 @@ def get_activity_details(roll_no, reward_points_df):
303
  points_val = 0
304
 
305
  # Truncate long names for display
306
- display_name = activity_name[:50] + "..." if len(activity_name) > 63 else activity_name
307
  output.append(f"{idx:2d}. {activity_type}: {display_name} - {points_val:.2f} pts")
308
 
309
-
310
  output.append("=" * 80)
311
 
312
  return "\n".join(output)
@@ -821,14 +835,6 @@ def get_system_info():
821
  output.append("-" * 40)
822
  output.append(details_info['last_updated'])
823
 
824
- # NEW: Add reward points data info
825
- if reward_points_df is not None:
826
- output.append(f"\nREWARD POINTS DATA:")
827
- output.append("-" * 40)
828
- output.append(f"Total activity records: {len(reward_points_df)}")
829
- unique_students = reward_points_df.iloc[:, 0].nunique() if not reward_points_df.empty else 0
830
- output.append(f"Students with activities: {unique_students}")
831
-
832
  # Cache info
833
  if data_cache["last_update"]:
834
  cache_age = datetime.now() - data_cache["last_update"]
@@ -844,12 +850,87 @@ def get_system_info():
844
 
845
  return "\n".join(output)
846
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
847
  # Create Gradio interface
848
  with gr.Blocks(title="Student Reward Points Check", theme=gr.themes.Soft()) as app:
849
  gr.Markdown("# πŸŽ“ Student Reward Points Check")
850
  gr.Markdown("### Search for student details including reward points and redemption dates")
851
  gr.Markdown("πŸ•’ **Auto-Updates**: Data automatically refreshes every 12 hours")
852
 
 
 
 
853
  with gr.Tabs():
854
  with gr.TabItem("πŸ” Student Search"):
855
  with gr.Row():
@@ -881,15 +962,87 @@ with gr.Blocks(title="Student Reward Points Check", theme=gr.themes.Soft()) as a
881
  interactive=False,
882
  show_label=True
883
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
884
 
885
  # Event handlers
886
  search_btn.click(fn=search_student, inputs=roll_input, outputs=result_output)
887
  roll_input.submit(fn=search_student, inputs=roll_input, outputs=result_output)
888
  system_btn.click(fn=get_system_info, outputs=system_output)
889
 
890
- # Load system info on startup
891
- app.load(fn=get_system_info, outputs=system_output)
892
-
893
  # 🌟 FOOTER SECTION
894
  gr.Markdown("---")
895
  with gr.Row():
@@ -919,6 +1072,23 @@ with gr.Blocks(title="Student Reward Points Check", theme=gr.themes.Soft()) as a
919
  elem_id="footer"
920
  )
921
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
922
 
923
  # Launch the app
924
  if __name__ == "__main__":
 
6
  from google_auth_oauthlib.flow import InstalledAppFlow
7
  import json
8
  import gradio as gr
9
+ import urllib.parse
10
  import time
11
  from datetime import datetime
12
  from pytz import timezone
 
153
  print(f"❌ Error loading Reward Points data: {str(e)}")
154
  return None
155
 
156
+ # MODIFIED FUNCTION: Get activity details from cached data in breakdown format
157
  def get_activity_details(roll_no, reward_points_df):
158
  """Get activity details for a specific roll number from cached reward points data in breakdown format"""
159
  try:
 
226
 
227
  # Format output in breakdown style
228
  output = []
229
+ output.append("\n" + "=" * 80)
230
+ output.append("πŸ† INDIVIDUAL ACTIVITY BREAKDOWN")
231
+ output.append("=" * 80)
232
+
233
  # Define all possible activity categories in order
234
  activity_categories = [
235
  "INITIAL POINTS / CARRY-OVER",
 
283
  count = final_count.get(category, 0)
284
  points = final_summary.get(category, 0.0)
285
 
286
+ output.append(f"πŸ“‹ **{category}**")
287
+ output.append(f" Count: {count} | Points: {points:.2f}")
288
 
289
  # Add any categories not in the standard list
290
  for category, points in final_summary.items():
291
  if category not in activity_categories:
292
  count = final_count.get(category, 0)
293
+ output.append(f"πŸ“‹ **{category}**")
294
+ output.append(f" Count: {count} | Points: {points:.2f}")
295
 
296
+ # Add summary totals
297
+ output.append("")
298
+ output.append("=" * 80)
299
+ output.append(f"πŸ“ˆ Total Individual Activities: {len(student_rows)}")
300
+ output.append(f"πŸ† Total Activity Types: {len(final_summary)}")
301
+ output.append(f"πŸ’° Total Activity Points: {total_points:.2f}")
302
 
303
  # Add detailed activity list if needed
304
  if len(student_rows) <= 20: # Only show detailed list for reasonable number of activities
 
318
  points_val = 0
319
 
320
  # Truncate long names for display
321
+ display_name = activity_name[:50] + "..." if len(activity_name) > 53 else activity_name
322
  output.append(f"{idx:2d}. {activity_type}: {display_name} - {points_val:.2f} pts")
323
 
 
324
  output.append("=" * 80)
325
 
326
  return "\n".join(output)
 
835
  output.append("-" * 40)
836
  output.append(details_info['last_updated'])
837
 
 
 
 
 
 
 
 
 
838
  # Cache info
839
  if data_cache["last_update"]:
840
  cache_age = datetime.now() - data_cache["last_update"]
 
850
 
851
  return "\n".join(output)
852
 
853
+ # Admin UI Controls
854
+ def build_admin_section():
855
+ """Build admin controls section"""
856
+ with gr.Accordion("πŸ”§ Admin Controls", open=False, visible=True) as admin_accordion:
857
+ admin_key = gr.Textbox(
858
+ label="Enter Admin Key",
859
+ type="password",
860
+ placeholder="Admin Only",
861
+ value=""
862
+ )
863
+ load_button = gr.Button("πŸ” Reload All Data", visible=False, variant="primary")
864
+ admin_status = gr.Markdown("ℹ️ Enter admin key to access controls", visible=True)
865
+
866
+ def verify_admin_key(key):
867
+ """Verify admin key and show/hide controls"""
868
+ if key.strip() == os.getenv("ADMIN_KEY", ""):
869
+ return (
870
+ gr.update(visible=True), # Show reload button
871
+ "βœ… Access granted. You can reload data now."
872
+ )
873
+ elif key.strip() == "":
874
+ return (
875
+ gr.update(visible=False), # Hide reload button
876
+ "ℹ️ Enter admin key to access controls"
877
+ )
878
+ else:
879
+ return (
880
+ gr.update(visible=False), # Hide reload button
881
+ "❌ Invalid admin key."
882
+ )
883
+
884
+ def admin_reload():
885
+ """Admin function to reload all data"""
886
+ try:
887
+ print("πŸ”§ Admin reload triggered...")
888
+ combined_df, studentwise_data, details_info, reward_points_df = load_all_data()
889
+
890
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
891
+ return f"βœ… Data reloaded successfully at {timestamp}\nπŸ“Š Total records: {len(combined_df) if not combined_df.empty else 0}"
892
+ except Exception as e:
893
+ return f"❌ Error reloading data: {str(e)}"
894
+
895
+ # Event handlers
896
+ admin_key.change(
897
+ fn=verify_admin_key,
898
+ inputs=admin_key,
899
+ outputs=[load_button, admin_status]
900
+ )
901
+
902
+ load_button.click(
903
+ fn=admin_reload,
904
+ outputs=admin_status
905
+ )
906
+
907
+ return admin_accordion, admin_key, load_button, admin_status
908
+
909
+ # Function to determine if admin mode is enabled via URL parameter
910
+ def check_admin_mode(request: gr.Request) -> bool:
911
+ """Check if admin mode is enabled via URL parameter"""
912
+ try:
913
+ query_params = urllib.parse.parse_qs(str(request.url).split('?')[1] if '?' in str(request.url) else "")
914
+ admin_param = query_params.get("admin", [""])[0]
915
+ admin_mode_key = os.getenv("ADMIN_MODE_KEY", "")
916
+
917
+ is_admin = admin_param == admin_mode_key and admin_mode_key != ""
918
+ if is_admin:
919
+ print(f"πŸ”§ Admin mode activated via URL parameter")
920
+ return is_admin
921
+ except Exception as e:
922
+ print(f"⚠️ Error checking admin mode: {str(e)}")
923
+ return False
924
+
925
  # Create Gradio interface
926
  with gr.Blocks(title="Student Reward Points Check", theme=gr.themes.Soft()) as app:
927
  gr.Markdown("# πŸŽ“ Student Reward Points Check")
928
  gr.Markdown("### Search for student details including reward points and redemption dates")
929
  gr.Markdown("πŸ•’ **Auto-Updates**: Data automatically refreshes every 12 hours")
930
 
931
+ # Store admin components for conditional visibility
932
+ admin_components = gr.State(None)
933
+
934
  with gr.Tabs():
935
  with gr.TabItem("πŸ” Student Search"):
936
  with gr.Row():
 
962
  interactive=False,
963
  show_label=True
964
  )
965
+
966
+ # NEW: Admin Controls as a separate tab
967
+ with gr.TabItem("πŸ”§ Admin Controls") as admin_tab:
968
+ gr.Markdown("### πŸ” Administrative Functions")
969
+ gr.Markdown("⚠️ **Access restricted to authorized personnel only**")
970
+
971
+ with gr.Row():
972
+ with gr.Column(scale=1):
973
+ admin_key = gr.Textbox(
974
+ label="Enter Admin Key",
975
+ type="password",
976
+ placeholder="Enter admin password",
977
+ value=""
978
+ )
979
+
980
+ with gr.Column(scale=1):
981
+ load_button = gr.Button("πŸ” Reload All Data", visible=False, variant="primary", size="lg")
982
+
983
+ admin_status = gr.Markdown("ℹ️ Enter admin key to access controls", visible=True)
984
+
985
+ # Admin functions
986
+ def verify_admin_key(key):
987
+ """Verify admin key and show/hide controls"""
988
+ if key.strip() == os.getenv("ADMIN_KEY", ""):
989
+ return (
990
+ gr.update(visible=True), # Show reload button
991
+ "βœ… **Access Granted!** You can now reload data."
992
+ )
993
+ elif key.strip() == "":
994
+ return (
995
+ gr.update(visible=False), # Hide reload button
996
+ "ℹ️ Enter admin key to access controls"
997
+ )
998
+ else:
999
+ return (
1000
+ gr.update(visible=False), # Hide reload button
1001
+ "❌ **Access Denied!** Invalid admin key."
1002
+ )
1003
+
1004
+ def admin_reload():
1005
+ """Admin function to reload all data"""
1006
+ try:
1007
+ print("πŸ”§ Admin reload triggered...")
1008
+ combined_df, studentwise_data, details_info, reward_points_df = load_all_data()
1009
+
1010
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1011
+ total_records = len(combined_df) if not combined_df.empty else 0
1012
+
1013
+ return f"""βœ… **Data Reload Successful!**
1014
+
1015
+ πŸ“… **Timestamp:** {timestamp}
1016
+ πŸ“Š **Total Records:** {total_records:,}
1017
+ πŸ”„ **Status:** All data sources refreshed
1018
+ ⏰ **Next Auto-refresh:** 12 hours from now
1019
+
1020
+ 🎯 **Data Sources Updated:**
1021
+ β€’ Main spreadsheet ({len(sheet_configs)} sheets)
1022
+ β€’ Studentwise reward points data
1023
+ β€’ Activity breakdown data
1024
+ β€’ System information"""
1025
+
1026
+ except Exception as e:
1027
+ return f"❌ **Error reloading data:** {str(e)}"
1028
+
1029
+ # Event handlers for admin tab
1030
+ admin_key.change(
1031
+ fn=verify_admin_key,
1032
+ inputs=admin_key,
1033
+ outputs=[load_button, admin_status]
1034
+ )
1035
+
1036
+ load_button.click(
1037
+ fn=admin_reload,
1038
+ outputs=admin_status
1039
+ )
1040
 
1041
  # Event handlers
1042
  search_btn.click(fn=search_student, inputs=roll_input, outputs=result_output)
1043
  roll_input.submit(fn=search_student, inputs=roll_input, outputs=result_output)
1044
  system_btn.click(fn=get_system_info, outputs=system_output)
1045
 
 
 
 
1046
  # 🌟 FOOTER SECTION
1047
  gr.Markdown("---")
1048
  with gr.Row():
 
1072
  elem_id="footer"
1073
  )
1074
 
1075
+ # Admin mode handler on app load (for tab visibility)
1076
+ def setup_admin_mode(request: gr.Request):
1077
+ """Setup admin mode based on URL parameters"""
1078
+ is_admin = check_admin_mode(request)
1079
+ if is_admin:
1080
+ return gr.update(visible=True) # Show admin tab
1081
+ else:
1082
+ return gr.update(visible=False) # Hide admin tab
1083
+
1084
+ # Apply admin mode check on load
1085
+ app.load(
1086
+ fn=setup_admin_mode,
1087
+ outputs=admin_tab
1088
+ )
1089
+
1090
+ # Load system info on startup
1091
+ app.load(fn=get_system_info, outputs=system_output)
1092
 
1093
  # Launch the app
1094
  if __name__ == "__main__":