""" ScanLook - Inventory Management System Flask Application Production-Ready Release """ from flask import Flask, render_template, request, redirect, url_for, session, flash, jsonify, send_from_directory from werkzeug.security import check_password_hash import os from datetime import timedelta # Initialize App FIRST to prevent circular import errors app = Flask(__name__) # Now import your custom modules from db import query_db, execute_db, get_db from blueprints.data_imports import data_imports_bp from blueprints.users import users_bp from blueprints.sessions import sessions_bp from blueprints.admin_locations import admin_locations_bp from blueprints.counting import counting_bp from utils import login_required # Register Blueprints app.register_blueprint(data_imports_bp) app.register_blueprint(users_bp) app.register_blueprint(sessions_bp) app.register_blueprint(admin_locations_bp) app.register_blueprint(counting_bp) # V1.0: Use environment variable for production, fallback to demo key for development app.secret_key = os.environ.get('SCANLOOK_SECRET_KEY', 'scanlook-demo-key-replace-for-production') app.config['DATABASE'] = os.path.join(os.path.dirname(__file__), 'database', 'scanlook.db') # Session timeout: 1 hour (auto-logout after idle period) app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1) # 1. Define the version APP_VERSION = '0.11.0' # 2. Inject it into all templates automatically @app.context_processor def inject_version(): return dict(version=APP_VERSION) # ==================== ROUTES: AUTHENTICATION ==================== @app.route('/') def index(): """Landing page - redirect based on login status""" if 'user_id' in session: return redirect(url_for('dashboard')) return redirect(url_for('login')) @app.route('/login', methods=['GET', 'POST']) def login(): """Login page""" if request.method == 'POST': username = request.form.get('username', '').strip() password = request.form.get('password', '') user = query_db('SELECT * FROM Users WHERE username = ? AND is_active = 1', [username], one=True) if user and check_password_hash(user['password'], password): session.permanent = True # Enable session timeout session['user_id'] = user['user_id'] session['username'] = user['username'] session['full_name'] = user['full_name'] session['role'] = user['role'] flash(f'Welcome back, {user["full_name"]}!', 'success') return redirect(url_for('dashboard')) else: flash('Invalid username or password', 'danger') return render_template('login.html') @app.route('/logout') def logout(): """Logout""" session.clear() flash('You have been logged out', 'info') return redirect(url_for('login')) # ==================== ROUTES: DASHBOARD ==================== @app.route('/dashboard') @login_required def dashboard(): """Main dashboard - different views for admin vs staff""" role = session.get('role') if role in ['owner', 'admin']: # Admin dashboard show_archived = request.args.get('show_archived', '0') == '1' if show_archived: # Show all sessions (active and archived) sessions_list = query_db(''' SELECT s.*, u.full_name as created_by_name, COUNT(DISTINCT lc.location_count_id) as total_locations, SUM(CASE WHEN lc.status = 'completed' THEN 1 ELSE 0 END) as completed_locations, SUM(CASE WHEN lc.status = 'in_progress' THEN 1 ELSE 0 END) as in_progress_locations FROM CountSessions s LEFT JOIN Users u ON s.created_by = u.user_id LEFT JOIN LocationCounts lc ON s.session_id = lc.session_id WHERE s.status IN ('active', 'archived') GROUP BY s.session_id ORDER BY s.status ASC, s.created_timestamp DESC ''') else: # Show only active sessions sessions_list = query_db(''' SELECT s.*, u.full_name as created_by_name, COUNT(DISTINCT lc.location_count_id) as total_locations, SUM(CASE WHEN lc.status = 'completed' THEN 1 ELSE 0 END) as completed_locations, SUM(CASE WHEN lc.status = 'in_progress' THEN 1 ELSE 0 END) as in_progress_locations FROM CountSessions s LEFT JOIN Users u ON s.created_by = u.user_id LEFT JOIN LocationCounts lc ON s.session_id = lc.session_id WHERE s.status = 'active' GROUP BY s.session_id ORDER BY s.created_timestamp DESC ''') return render_template('admin_dashboard.html', sessions=sessions_list, show_archived=show_archived) else: # Staff dashboard 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) @app.route('/staff-mode') @login_required def staff_mode(): """Allow admin/owner to switch to staff view for scanning""" # Show staff dashboard view regardless of role 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, is_admin_mode=True) # ==================== PWA SUPPORT ROUTES ==================== @app.route('/manifest.json') def serve_manifest(): """Serve the PWA manifest file from the static directory""" return send_from_directory('static', 'manifest.json') @app.route('/sw.js') def serve_sw(): """Serve the Service Worker file from the static directory""" return send_from_directory('static', 'sw.js') # ==================== Temp delete me later ==================== @app.route('/whatami') def whatami(): """Temporary route to identify device user-agent""" ua = request.headers.get('User-Agent', 'Unknown') return f"""

Device Info

User-Agent:

{ua}

Screen Size:

Loading...

Viewport Size:

Loading...

""" # ==================== RUN APPLICATION ==================== if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)