Skip to content

Commit 84aeb5d

Browse files
authored
Update app.py
1 parent ad937b6 commit 84aeb5d

File tree

1 file changed

+95
-62
lines changed

1 file changed

+95
-62
lines changed

app.py

Lines changed: 95 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def load_db():
1717
if not os.path.exists(DB_FILE):
1818
default_data = {
1919
"role_db": {"armasupplyguy@gmail.com": "SUPER_ADMIN"},
20-
"usernames": {"armasupplyguy@gmail.com": "ArmaSupplyGuy"}, # Default Username
20+
"usernames": {"armasupplyguy@gmail.com": "ArmaSupplyGuy"},
2121
"passwords": {"armasupplyguy@gmail.com": SYSTEM_PASSWORD},
2222
"mods": [],
2323
"events": [],
@@ -31,7 +31,6 @@ def load_db():
3131
try:
3232
with open(DB_FILE, 'r') as f:
3333
data = json.load(f)
34-
# Migration check: Ensure 'usernames' exists for old databases
3534
if "usernames" not in data:
3635
data["usernames"] = {}
3736
return data
@@ -95,7 +94,6 @@ def save_db(data):
9594

9695
with signup_tab:
9796
with st.container(border=True):
98-
# NEW FIELD: USERNAME
9997
new_user = st.text_input("Username", key="sign_user")
10098
new_email = st.text_input("New Email", key="sign_email")
10199
new_pass = st.text_input("New Password", type="password", key="sign_pwd")
@@ -109,18 +107,17 @@ def save_db(data):
109107
elif new_email and new_pass and new_user:
110108
DB['role_db'][new_email] = "staff"
111109
DB['passwords'][new_email] = new_pass
112-
DB['usernames'][new_email] = new_user # Save Username
110+
DB['usernames'][new_email] = new_user
113111
save_db(DB)
114112
st.success("Account created! Please login.")
115113
else:
116-
st.warning("All fields (including Username) are required.")
114+
st.warning("All fields are required.")
117115
st.stop()
118116

119117
# =========================================================
120118
# MAIN APP
121119
# =========================================================
122120
USER_EMAIL = st.session_state.current_user
123-
# Fallback for legacy users who might not have a username set
124121
USER_NAME = DB['usernames'].get(USER_EMAIL, USER_EMAIL.split('@')[0])
125122
user_role = DB['role_db'].get(USER_EMAIL, "staff")
126123

@@ -134,7 +131,7 @@ def get_mod_status():
134131

135132
# --- SIDEBAR ---
136133
st.sidebar.title("🛠 Staff Portal")
137-
st.sidebar.write(f"User: **{USER_NAME}**") # Show Username, not email
134+
st.sidebar.write(f"User: **{USER_NAME}**")
138135
if st.sidebar.button("🚪 Logout"):
139136
st.session_state.logged_in = False
140137
st.rerun()
@@ -160,15 +157,28 @@ def get_mod_status():
160157
st.sidebar.divider()
161158
st.sidebar.button("🔑 Assign Roles", on_click=navigate_to, args=("roles",))
162159

163-
# --- TOP NAV (HIDDEN FOR STAFF) ---
160+
# --- DYNAMIC TOP NAV ---
161+
# Logic: Staff sees NOTHING. Admins see EVERYTHING. CLP sees LIMITED.
164162
if user_role != "staff":
165-
cols = st.columns(6)
166-
with cols[0]: st.button("Broken Mods", use_container_width=True, on_click=navigate_to, args=("view_broken_mods",))
167-
with cols[1]: st.button("Fixed", use_container_width=True, on_click=navigate_to, args=("view_fixed_mods",))
168-
with cols[2]: st.button("Tutorials", use_container_width=True, on_click=navigate_to, args=("view_tutorials",))
169-
with cols[3]: st.button("Training Schedules", use_container_width=True, on_click=navigate_to, args=("view_events",))
170-
with cols[4]: st.button("Events", use_container_width=True, on_click=navigate_to, args=("view_events",))
171-
with cols[5]: st.button("Users", use_container_width=True, on_click=navigate_to, args=("view_users",))
163+
menu_items = []
164+
165+
# 1. Admin Only Items
166+
if user_role in ["admin", "SUPER_ADMIN"]:
167+
menu_items.append({"label": "Broken Mods", "page": "view_broken_mods"})
168+
menu_items.append({"label": "Fixed", "page": "view_fixed_mods"})
169+
170+
# 2. Common Items (CLP, CLPLEAD, Admin, Super Admin)
171+
menu_items.append({"label": "Tutorials", "page": "view_tutorials"})
172+
menu_items.append({"label": "Training Schedules", "page": "view_events"})
173+
menu_items.append({"label": "Events", "page": "view_events"})
174+
menu_items.append({"label": "Users", "page": "view_users"})
175+
176+
# Render the Menu
177+
cols = st.columns(len(menu_items))
178+
for i, item in enumerate(menu_items):
179+
with cols[i]:
180+
st.button(item["label"], use_container_width=True, on_click=navigate_to, args=(item["page"],))
181+
172182
st.markdown("---")
173183

174184
# --- PAGES ---
@@ -215,26 +225,34 @@ def get_mod_status():
215225
st.rerun()
216226

217227
elif st.session_state.page == "view_broken_mods":
218-
st.title("Active Broken Mods")
219-
active = [m for m in DB['mods'] if not m['complete']]
220-
if not active: st.success("No active issues.")
221-
for m in active:
222-
with st.container(border=True):
223-
c1, c2 = st.columns([5,1])
224-
with c1:
225-
st.subheader(f"⚠️ {m['name']}")
226-
st.caption(f"Severity: {m['severity']} | Assigned: {m['assignment']}")
227-
with c2: st.button("Details", key=f"d_{m['id']}", on_click=navigate_to, args=("mod_detail", m['id']))
228+
# DOUBLE CHECK ACCESS (Security Layer)
229+
if user_role not in ["admin", "SUPER_ADMIN"]:
230+
st.error("Access Denied.")
231+
else:
232+
st.title("Active Broken Mods")
233+
active = [m for m in DB['mods'] if not m['complete']]
234+
if not active: st.success("No active issues.")
235+
for m in active:
236+
with st.container(border=True):
237+
c1, c2 = st.columns([5,1])
238+
with c1:
239+
st.subheader(f"⚠️ {m['name']}")
240+
st.caption(f"Severity: {m['severity']} | Assigned: {m['assignment']}")
241+
with c2: st.button("Details", key=f"d_{m['id']}", on_click=navigate_to, args=("mod_detail", m['id']))
228242

229243
elif st.session_state.page == "view_fixed_mods":
230-
st.title("Fixed Mods Archive")
231-
fixed = [m for m in DB['mods'] if m['complete']]
232-
if not fixed: st.info("Empty archive.")
233-
for m in fixed:
234-
with st.container(border=True):
235-
c1, c2 = st.columns([5,1])
236-
with c1: st.subheader(f"✅ {m['name']}")
237-
with c2: st.button("Archive View", key=f"a_{m['id']}", on_click=navigate_to, args=("mod_detail", m['id']))
244+
# DOUBLE CHECK ACCESS
245+
if user_role not in ["admin", "SUPER_ADMIN"]:
246+
st.error("Access Denied.")
247+
else:
248+
st.title("Fixed Mods Archive")
249+
fixed = [m for m in DB['mods'] if m['complete']]
250+
if not fixed: st.info("Empty archive.")
251+
for m in fixed:
252+
with st.container(border=True):
253+
c1, c2 = st.columns([5,1])
254+
with c1: st.subheader(f"✅ {m['name']}")
255+
with c2: st.button("Archive View", key=f"a_{m['id']}", on_click=navigate_to, args=("mod_detail", m['id']))
238256

239257
elif st.session_state.page == "mod_detail":
240258
m = next((x for x in DB['mods'] if x['id'] == st.session_state.selected_mod_id), None)
@@ -246,19 +264,24 @@ def get_mod_status():
246264
if m.get('json_data'): st.code(m['json_data'], language='json')
247265
st.markdown(m['description'], unsafe_allow_html=True)
248266
st.divider()
249-
if not m['complete']:
250-
if st.button("✅ Mark Resolved", type="primary"):
251-
m['complete'] = True
252-
save_db(DB)
253-
st.success("Resolved!")
254-
st.session_state.page = "view_fixed_mods"
255-
st.rerun()
256-
else:
257-
st.success("Resolved.")
258-
if st.button("Re-open"):
259-
m['complete'] = False
260-
save_db(DB)
261-
st.rerun()
267+
# Only Admins can Resolve
268+
if user_role in ["admin", "SUPER_ADMIN"]:
269+
if not m['complete']:
270+
if st.button("✅ Mark Resolved", type="primary"):
271+
m['complete'] = True
272+
save_db(DB)
273+
st.success("Resolved!")
274+
st.session_state.page = "view_fixed_mods"
275+
st.rerun()
276+
else:
277+
st.success("Resolved.")
278+
if st.button("Re-open"):
279+
m['complete'] = False
280+
save_db(DB)
281+
st.rerun()
282+
elif m['complete']:
283+
st.success("This issue is Resolved.")
284+
262285
with c2:
263286
st.subheader("Discussion")
264287
chat = st.container(height=400, border=True)
@@ -320,37 +343,47 @@ def get_mod_status():
320343
st.subheader(t['title'])
321344
st.markdown(t['content'], unsafe_allow_html=True)
322345

323-
# --- VIEW USERS (UPDATED: USERNAMES & PRIVACY) ---
324346
elif st.session_state.page == "view_users":
325347
st.title("Staff Roster")
326348
for email, role in DB['role_db'].items():
327349
with st.container(border=True):
328350
c1, c2, c3 = st.columns([1,4,2])
329-
330-
# 1. Get Username (Default to 'Unknown' if missing)
331351
u_name = DB.get('usernames', {}).get(email, "Unknown User")
332-
333352
with c1: st.write("👤")
334353
with c2:
335-
# 2. Show Username Main
336354
st.subheader(u_name)
337-
# 3. Restrict Email Visibility
338355
if user_role == "SUPER_ADMIN":
339-
st.caption(f"Email: {email}") # Only Super Admin sees this
356+
st.caption(f"Email: {email}")
340357
st.caption(f"Role: {role}")
341358
with c3:
342359
st.write("🟢 Online" if email == USER_EMAIL else "⚪ Offline")
343360

344361
elif st.session_state.page == "roles":
345362
st.title("Role Management")
346-
u_email = st.text_input("Email to Update")
347-
u_role = st.selectbox("New Role", ["admin", "CLPLEAD", "CLP", "staff"])
348-
if st.button("Update"):
349-
if u_email in DB['role_db']:
350-
DB['role_db'][u_email] = u_role
351-
save_db(DB)
352-
st.success("Updated!")
353-
else:
354-
st.error("User not found.")
363+
364+
with st.container(border=True):
365+
st.subheader("Update User Role")
366+
u_email = st.text_input("User Email to Update")
367+
u_role = st.selectbox("New Role", ["admin", "CLPLEAD", "CLP", "staff"])
368+
if st.button("Update Role"):
369+
if u_email in DB['role_db']:
370+
DB['role_db'][u_email] = u_role
371+
save_db(DB)
372+
st.success("Updated!")
373+
else:
374+
st.error("User not found.")
375+
376+
with st.expander("❌ Delete User (Danger Zone)"):
377+
st.warning("This action cannot be undone.")
378+
del_email = st.text_input("Enter Email to Delete")
379+
if st.button("Permanently Delete User", type="primary"):
380+
if del_email in DB['role_db']:
381+
del DB['role_db'][del_email]
382+
if del_email in DB['passwords']: del DB['passwords'][del_email]
383+
if del_email in DB['usernames']: del DB['usernames'][del_email]
384+
save_db(DB)
385+
st.success(f"User {del_email} deleted.")
386+
else:
387+
st.error("User not found.")
355388

356389
st.table(pd.DataFrame(DB['role_db'].items(), columns=["Email", "Role"]))

0 commit comments

Comments
 (0)