v0.12.0 - Add modular system architecture with user-based module access

- Add Modules and UserModules database tables
- Create home page with module selection grid
- Implement per-user module assignment in user management
- Add route guards for module access control
- Refactor navigation: login -> home -> modules, admin console via button
- Add Font Awesome icons
This commit is contained in:
Javier
2026-01-26 11:35:29 -06:00
parent cbd7e535e6
commit 21671d6bee
17 changed files with 365 additions and 47 deletions

View File

@@ -10,6 +10,32 @@ def get_active_session(session_id):
return None
return sess
@counting_bp.route('/counts')
@login_required
def index():
"""Counts module landing - show active sessions"""
# Check if user has access to this module
user_id = session.get('user_id')
has_access = query_db('''
SELECT 1 FROM UserModules um
JOIN Modules m ON um.module_id = m.module_id
WHERE um.user_id = ? AND m.module_key = 'counting' AND m.is_active = 1
''', [user_id], one=True)
if not has_access:
flash('You do not have access to this module', 'danger')
return redirect(url_for('home'))
active_sessions = query_db('''
SELECT session_id, session_name, session_type, created_timestamp
FROM CountSessions
WHERE status = 'active'
ORDER BY created_timestamp DESC
''')
return render_template('staff_dashboard.html', sessions=active_sessions)
@counting_bp.route('/count/<int:session_id>')
@login_required
def count_session(session_id):
@@ -19,7 +45,7 @@ def count_session(session_id):
if not sess:
flash('Session not found or not active', 'danger')
return redirect(url_for('dashboard'))
return redirect(url_for('counting.index'))
# Redirect to my_counts page (staff can manage multiple bins)
return redirect(url_for('counting.my_counts', session_id=session_id))
@@ -33,11 +59,11 @@ def my_counts(session_id):
if not sess:
flash('Session not found', 'danger')
return redirect(url_for('dashboard'))
return redirect(url_for('counting.index'))
if sess['status'] == 'archived':
flash('This session has been archived', 'warning')
return redirect(url_for('dashboard'))
return redirect(url_for('counting.index'))
# Get this user's active bins
active_bins = query_db('''
@@ -78,7 +104,7 @@ def start_bin_count(session_id):
sess = get_active_session(session_id)
if not sess:
flash('Session not found or archived', 'warning')
return redirect(url_for('dashboard'))
return redirect(url_for('counting.index'))
if not sess['master_baseline_timestamp']:
flash('Master File not uploaded. Please upload it before starting bins.', 'warning')
return redirect(url_for('counting.my_counts', session_id=session_id))
@@ -146,7 +172,7 @@ def count_location(session_id, location_count_id):
sess = get_active_session(session_id)
if not sess:
flash('Session not found or archived', 'warning')
return redirect(url_for('dashboard'))
return redirect(url_for('counting.index'))
if not sess['master_baseline_timestamp']:
flash('Master File not uploaded. Please upload it before starting bins.', 'warning')
return redirect(url_for('counting.my_counts', session_id=session_id))