Jul 9 - Update to allow customer to manage their facilities' QR codes
This commit is contained in:
+36
-22
@@ -97,7 +97,9 @@ def view_facility(facility_id):
|
||||
return render_template('facilities/view.html', facility=facility, areas=areas)
|
||||
|
||||
|
||||
# ── Public QR code (staff-only generation) ────────────────────────────────────
|
||||
# ── Public QR code ────────────────────────────────────────────────────────────
|
||||
# Staff (admin/director/pm/inspector) may access QR for any facility; customers
|
||||
# may access QR only for facilities in their assigned scope.
|
||||
|
||||
def _public_facility_url(facility):
|
||||
"""Absolute URL the QR encodes — the login-free occupant summary page."""
|
||||
@@ -108,15 +110,27 @@ def _public_facility_url(facility):
|
||||
token=facility.public_token, _external=True)
|
||||
|
||||
|
||||
@bp.route('/<int:facility_id>/qr.png')
|
||||
@login_required
|
||||
def facility_qr_png(facility_id):
|
||||
"""Return the facility's QR code as a PNG image (staff only)."""
|
||||
if current_user.role == 'customer':
|
||||
abort(403)
|
||||
def _facility_for_qr_or_403(facility_id):
|
||||
"""Load a facility for a QR action, enforcing customer facility scope.
|
||||
|
||||
Customers may only touch QR codes for facilities they are assigned to; all
|
||||
other (staff) roles have unrestricted QR access.
|
||||
"""
|
||||
facility = db.session.get(Facility, facility_id)
|
||||
if facility is None:
|
||||
abort(404)
|
||||
if current_user.role == 'customer':
|
||||
cids = get_customer_scope(current_user) or []
|
||||
if facility.id not in cids:
|
||||
abort(403)
|
||||
return facility
|
||||
|
||||
|
||||
@bp.route('/<int:facility_id>/qr.png')
|
||||
@login_required
|
||||
def facility_qr_png(facility_id):
|
||||
"""Return the facility's QR code as a PNG image."""
|
||||
facility = _facility_for_qr_or_403(facility_id)
|
||||
|
||||
# Token may not exist for pre-phase34 rows viewed before any commit.
|
||||
created = not facility.public_token
|
||||
@@ -141,11 +155,7 @@ def facility_qr_png(facility_id):
|
||||
@login_required
|
||||
def facility_qr_page(facility_id):
|
||||
"""Printable page: facility name + QR + public URL + posting instructions."""
|
||||
if current_user.role == 'customer':
|
||||
abort(403)
|
||||
facility = db.session.get(Facility, facility_id)
|
||||
if facility is None:
|
||||
abort(404)
|
||||
facility = _facility_for_qr_or_403(facility_id)
|
||||
public_url = _public_facility_url(facility)
|
||||
db.session.commit() # persist token if it was just generated
|
||||
return render_template('facilities/qr.html',
|
||||
@@ -154,12 +164,15 @@ def facility_qr_page(facility_id):
|
||||
|
||||
@bp.route('/<int:facility_id>/qr/regenerate', methods=['POST'])
|
||||
@login_required
|
||||
@supervisor_required
|
||||
def facility_qr_regenerate(facility_id):
|
||||
"""Mint a NEW public token, invalidating any previously printed QR code."""
|
||||
facility = db.session.get(Facility, facility_id)
|
||||
if facility is None:
|
||||
abort(404)
|
||||
"""Mint a NEW public token, invalidating any previously printed QR code.
|
||||
|
||||
Allowed for admin/director, and for customers on their own assigned
|
||||
facilities. Project managers and inspectors cannot regenerate.
|
||||
"""
|
||||
facility = _facility_for_qr_or_403(facility_id)
|
||||
if current_user.role not in ('admin', 'director', 'customer'):
|
||||
abort(403)
|
||||
|
||||
facility.public_token = Facility.generate_public_token()
|
||||
db.session.commit()
|
||||
@@ -178,17 +191,18 @@ def facility_qr_regenerate(facility_id):
|
||||
def facility_qr_print_all():
|
||||
"""Printable sheet of QR codes for all facilities the user can see.
|
||||
|
||||
Optional ?contract_id=<id> limits the sheet to one contract. Customers have
|
||||
no QR access (403); inspectors are scoped to their contracted facilities.
|
||||
Optional ?contract_id=<id> limits the sheet to one contract. Inspectors are
|
||||
scoped to their contracted facilities; customers to their assigned
|
||||
facilities; managers see all active facilities.
|
||||
"""
|
||||
if current_user.role == 'customer':
|
||||
abort(403)
|
||||
|
||||
contract_id = request.args.get('contract_id', type=int)
|
||||
|
||||
if current_user.role == 'inspector':
|
||||
fids = get_inspector_scope(current_user) or []
|
||||
query = Facility.query.filter(Facility.id.in_(fids), Facility.active == True)
|
||||
elif current_user.role == 'customer':
|
||||
fids = get_customer_scope(current_user) or []
|
||||
query = Facility.query.filter(Facility.id.in_(fids), Facility.active == True)
|
||||
else:
|
||||
query = Facility.query.filter(Facility.active == True)
|
||||
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
<h2><i class="bi bi-building"></i> Facilities</h2>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
{% if current_user.role != 'customer' %}
|
||||
<a href="{{ url_for('facilities.facility_qr_print_all') }}"
|
||||
class="btn btn-outline-dark" title="Printable sheet of every facility's QR code">
|
||||
class="btn btn-outline-dark" title="Printable sheet of your facilities' QR codes">
|
||||
<i class="bi bi-qr-code"></i> Print All QR Codes
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if current_user.role in ['admin', 'director'] %}
|
||||
<a href="{{ url_for('facilities.create_facility') }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle"></i> Add Facility
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<i class="bi bi-arrow-left"></i> Back to Facility
|
||||
</a>
|
||||
<div class="d-flex gap-2">
|
||||
{% if current_user.role in ['admin', 'director'] %}
|
||||
{% if current_user.role in ['admin', 'director', 'customer'] %}
|
||||
<form method="POST"
|
||||
action="{{ url_for('facilities.facility_qr_regenerate', facility_id=facility.id) }}"
|
||||
onsubmit="return confirm('Regenerate this QR code? Any codes already printed and posted for {{ facility.name }} will STOP working and must be reprinted.');">
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<i class="bi bi-graph-up-arrow"></i> Scorecard
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if current_user.role in ['admin', 'director', 'project_manager'] %}
|
||||
{% if current_user.role in ['admin', 'director', 'project_manager', 'customer'] %}
|
||||
<a href="{{ url_for('facilities.facility_qr_page', facility_id=facility.id) }}"
|
||||
class="btn btn-outline-dark" title="Printable QR code for this facility">
|
||||
<i class="bi bi-qr-code"></i> QR Code
|
||||
|
||||
Reference in New Issue
Block a user