The SW was served from /static/sw.js with default scope /static/, so it only intercepted static asset requests. Page navigations to /capture, /queue, /browser were not handled by the SW at all — Safari showed its native offline error. Fix: serve SW from /sw.js route with Service-Worker-Allowed: / header and register with scope: /. Now the SW intercepts all navigations and serves the offline fallback page when the network is unavailable. Also remove auth-protected page routes from precache (they would cache the login redirect). Pages are cached via network-first on visit instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
2.8 KiB
Python
97 lines
2.8 KiB
Python
from flask import Blueprint, render_template, redirect, url_for, session, jsonify, send_from_directory, current_app
|
|
|
|
bp = Blueprint('views', __name__)
|
|
|
|
|
|
@bp.route('/sw.js')
|
|
def service_worker():
|
|
"""Serve service worker from root scope."""
|
|
response = send_from_directory(
|
|
current_app.static_folder, 'sw.js',
|
|
mimetype='application/javascript'
|
|
)
|
|
response.headers['Service-Worker-Allowed'] = '/'
|
|
response.headers['Cache-Control'] = 'no-cache'
|
|
return response
|
|
|
|
@bp.route('/')
|
|
def index():
|
|
"""Root route - redirect to capture if logged in, otherwise show login."""
|
|
if 'username' in session:
|
|
return redirect(url_for('views.capture'))
|
|
return render_template('login.html')
|
|
|
|
@bp.route('/login')
|
|
def login_page():
|
|
"""Render login page."""
|
|
if 'username' in session:
|
|
return redirect(url_for('views.capture'))
|
|
return render_template('login.html')
|
|
|
|
@bp.route('/capture')
|
|
def capture():
|
|
"""Render capture page (requires authentication)."""
|
|
if 'username' not in session:
|
|
return redirect(url_for('views.login_page'))
|
|
return render_template(
|
|
'capture.html',
|
|
username=session['username'],
|
|
show_nav=True,
|
|
is_admin=session.get('is_admin', False)
|
|
)
|
|
|
|
@bp.route('/queue')
|
|
def queue():
|
|
"""Render queue page (requires authentication)."""
|
|
if 'username' not in session:
|
|
return redirect(url_for('views.login_page'))
|
|
return render_template(
|
|
'queue.html',
|
|
username=session['username'],
|
|
show_nav=True,
|
|
is_admin=session.get('is_admin', False)
|
|
)
|
|
|
|
@bp.route('/browser')
|
|
def browser():
|
|
"""Render file browser page (requires authentication)."""
|
|
if 'username' not in session:
|
|
return redirect(url_for('views.login_page'))
|
|
return render_template(
|
|
'browser.html',
|
|
username=session['username'],
|
|
show_nav=True,
|
|
is_admin=session.get('is_admin', False)
|
|
)
|
|
|
|
@bp.route('/reviewer')
|
|
def reviewer():
|
|
"""Render photo reviewer page (requires authentication)."""
|
|
if 'username' not in session:
|
|
return redirect(url_for('views.login_page'))
|
|
return render_template(
|
|
'reviewer.html',
|
|
username=session['username'],
|
|
show_nav=False,
|
|
is_admin=session.get('is_admin', False)
|
|
)
|
|
|
|
@bp.route('/admin')
|
|
def admin():
|
|
"""Render admin page (requires admin privileges)."""
|
|
if 'username' not in session:
|
|
return redirect(url_for('views.login_page'))
|
|
if not session.get('is_admin', False):
|
|
return "Access denied: Admin privileges required", 403
|
|
return render_template(
|
|
'admin.html',
|
|
username=session['username'],
|
|
show_nav=True,
|
|
is_admin=True
|
|
)
|
|
|
|
@bp.route('/test')
|
|
def test():
|
|
"""Test page for camera functionality."""
|
|
return render_template('test.html')
|