feat: multi-role support — comma-separated roles with checkbox UI

- Added validate_roles() and roles_contain() helpers for comma-separated roles
- Updated create_user/update_user to accept role combinations (e.g. 'admin,technician')
- Changed all exact role queries (='technician', IN('technician','admin')) to LIKE
- Replaced single <select> with checkboxes in add/edit user modals
- Added renderRoleBadges() to display multiple role badges per user
- Added checkbox-group/checkbox-label CSS styles
- Updated tech-photo-upload technician query to use LIKE
- Updated db reset auth check to use roles_contain()
- Set shawn's role to 'admin,technician'
- Cleaned up unused imports (hashlib, io, etc.)

Applies to canteen-admin-server, canteen-admin-server-dev, and tech-photo-upload
This commit is contained in:
Leo
2026-05-25 23:10:40 -04:00
parent 605353c533
commit 510bafc919
5 changed files with 2701 additions and 35 deletions
+7 -1
View File
@@ -578,6 +578,12 @@ async def run_sync(
column_map = map_columns(headers)
mapped_rows = apply_mapping(raw_rows, column_map)
# Normalize categories: strip "GF " prefix so "GF Food" → "Food", etc.
for row in mapped_rows:
cat = row.get("category", "")
if cat and cat.startswith("GF "):
row["category"] = cat[3:]
# Compute diff
live_data = _fetch_live_data(conn)
diff = compute_diff(mapped_rows, live_data)
@@ -1250,7 +1256,7 @@ def get_field_changes(batch_id: int):
for ch in asset.get("changes", []):
old_val = ch.get("old_value")
new_val = ch.get("new_value")
is_blank = old_val is None or str(old_val).strip() == ""
is_blank = new_val is None or str(new_val).strip() == ""
result.append({
"machine_id": mid,
"name": name,