Jul 10 - Update facility's area with QR code
This commit is contained in:
@@ -226,6 +226,91 @@ def facility_qr_print_all():
|
||||
facilities=facilities,
|
||||
selected_contract=selected_contract)
|
||||
|
||||
# ── Public Area QR code ───────────────────────────────────────────────────────
|
||||
# Mirrors the facility QR routes above, but scoped to a single area. Customer
|
||||
# scope is enforced via the area's parent facility.
|
||||
|
||||
def _public_area_url(area):
|
||||
"""Absolute URL the area QR encodes — the login-free area summary page."""
|
||||
area.ensure_public_token()
|
||||
if not area.public_token:
|
||||
return None
|
||||
return url_for('public.area_summary',
|
||||
token=area.public_token, _external=True)
|
||||
|
||||
|
||||
def _area_for_qr_or_403(area_id):
|
||||
"""Load an area for a QR action, enforcing customer facility scope."""
|
||||
area = db.session.get(Area, area_id)
|
||||
if area is None:
|
||||
abort(404)
|
||||
if current_user.role == 'customer':
|
||||
cids = get_customer_scope(current_user) or []
|
||||
if area.facility_id not in cids:
|
||||
abort(403)
|
||||
return area
|
||||
|
||||
|
||||
@bp.route('/areas/<int:area_id>/qr.png')
|
||||
@login_required
|
||||
def area_qr_png(area_id):
|
||||
"""Return the area's QR code as a PNG image."""
|
||||
area = _area_for_qr_or_403(area_id)
|
||||
|
||||
created = not area.public_token
|
||||
url = _public_area_url(area)
|
||||
if created:
|
||||
db.session.commit()
|
||||
|
||||
import io
|
||||
import qrcode
|
||||
img = qrcode.make(url, box_size=10, border=2)
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format='PNG')
|
||||
buf.seek(0)
|
||||
|
||||
from flask import Response
|
||||
return Response(buf.getvalue(), mimetype='image/png', headers={
|
||||
'Cache-Control': 'private, max-age=3600',
|
||||
})
|
||||
|
||||
|
||||
@bp.route('/areas/<int:area_id>/qr')
|
||||
@login_required
|
||||
def area_qr_page(area_id):
|
||||
"""Printable page: area name + facility + QR + public URL + instructions."""
|
||||
area = _area_for_qr_or_403(area_id)
|
||||
public_url = _public_area_url(area)
|
||||
db.session.commit() # persist token if it was just generated
|
||||
return render_template('facilities/area_qr.html',
|
||||
area=area, facility=area.facility,
|
||||
public_url=public_url)
|
||||
|
||||
|
||||
@bp.route('/areas/<int:area_id>/qr/regenerate', methods=['POST'])
|
||||
@login_required
|
||||
def area_qr_regenerate(area_id):
|
||||
"""Mint a NEW token for this area, invalidating any printed QR code.
|
||||
|
||||
Allowed for admin/director, and for customers on their own assigned
|
||||
facilities. Project managers and inspectors cannot regenerate.
|
||||
"""
|
||||
area = _area_for_qr_or_403(area_id)
|
||||
if current_user.role not in ('admin', 'director', 'customer'):
|
||||
abort(403)
|
||||
|
||||
area.public_token = Area.generate_public_token()
|
||||
db.session.commit()
|
||||
|
||||
logger.info('FACILITIES | area_qr_regenerate | user=%s | area_id=%s',
|
||||
current_user.username, area.id)
|
||||
log_action(ACTION_UPDATE, 'Area', area.id, area.name,
|
||||
'regenerated public QR token (old code invalidated)')
|
||||
flash('QR code regenerated. Any previously printed codes for this area no '
|
||||
'longer work — reprint and repost.', 'warning')
|
||||
return redirect(url_for('facilities.area_qr_page', area_id=area.id))
|
||||
|
||||
|
||||
@bp.route('/<int:facility_id>/edit', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@supervisor_required
|
||||
@@ -297,7 +382,8 @@ def create_area(facility_id):
|
||||
area_type=form.area_type.data,
|
||||
facility_id=facility.id
|
||||
)
|
||||
|
||||
area.ensure_public_token() # QR landing-page token
|
||||
|
||||
db.session.add(area)
|
||||
db.session.commit()
|
||||
logger.info('FACILITIES | create_area | user=%s | area_id=%s name=%r facility=%r',
|
||||
|
||||
Reference in New Issue
Block a user