04/28 Updated sprint 3

This commit is contained in:
2026-04-28 17:13:24 -04:00
parent bfc2f58fe2
commit 84c7f9d045
5 changed files with 48 additions and 51 deletions
+25 -31
View File
@@ -42,24 +42,6 @@ import openpyxl
bp = Blueprint('qr_codes', __name__)
def _get_qr_base_url():
"""
Return the authoritative base URL for QR code destination links.
Prefers the explicit QR_BASE_URL config value (set via .env / config.py).
Falls back gracefully to request.url_root if not configured.
Using an explicit QR_BASE_URL is required when the app runs behind a
reverse proxy (e.g. nginx) that can cause request.url_root to produce
a doubled hostname such as:
https://qr.govservicesinc.com,qr.govservicesinc.com/
"""
configured = current_app.config.get('QR_BASE_URL', '').rstrip('/')
if configured:
return configured + '/'
# Fallback: normalise request.url_root to avoid any trailing-slash issues
return request.url_root.rstrip('/') + '/'
# --- ADDED: helper — returns distinct (location, location_address) pairs from
# all standard QR codes, used to auto-populate the dynamic QR location list ---
def get_unique_qr_locations():
@@ -211,7 +193,7 @@ def create_qr_code():
qr_url = generate_qr_url(name, new_qr_code.id)
# Generate QR code data with the destination URL and custom styling
qr_data = f"{_get_qr_base_url()}qr/{qr_url}"
qr_data = f"{request.url_root}qr/{qr_url}"
qr_image = generate_qr_code(
data=qr_data,
fill_color=fill_color,
@@ -339,7 +321,7 @@ def import_bulk_qr_codes():
created_by=session['user_id'],
generate_qr_code_func=generate_qr_code,
generate_qr_url_func=generate_qr_url,
request_url_root=_get_qr_base_url(),
request_url_root=request.url_root,
project_lookup=project_lookup,
QRCode=QRCode,
Project=Project,
@@ -472,11 +454,9 @@ def edit_qr_code(qr_id):
'back_color': getattr(qr_code, 'back_color', '#FFFFFF')
}
# QR code name is immutable after creation — always retain the existing value.
# The name field in the edit form is rendered read-only; this guard ensures
# the constraint is enforced even if the form is submitted programmatically.
new_name = qr_code.name # do not accept name changes from the form
# qr_code.name is intentionally NOT reassigned here
# Update QR code fields
new_name = request.form['name']
qr_code.name = new_name
# --- ADDED: for dynamic QR codes, location/address are auto-managed ---
new_qr_type = request.form.get('qr_type', 'standard')
@@ -561,7 +541,7 @@ def edit_qr_code(qr_id):
# Regenerate QR code if name or styling changed
if name_changed or styling_changed:
qr_data = f"{_get_qr_base_url()}qr/{qr_code.qr_url}"
qr_data = f"{request.url_root}qr/{qr_code.qr_url}"
# Use new styling if available, otherwise use defaults
styling = get_qr_styling(qr_code)
@@ -918,8 +898,22 @@ def qr_checkin(qr_url):
if verification_photo_data:
logger_handler.logger.debug(f"Verification photo provided (size: {len(verification_photo_data)} chars)")
# Validate photo data (basic validation)
# Server-side size enforcement — mirrors client-side MAX_SIZE check
# but cannot be bypassed by a malicious client.
max_photo_bytes = current_app.config.get('VERIFICATION_PHOTO_MAX_SIZE', 5 * 1024 * 1024)
if len(verification_photo_data.encode('utf-8')) > max_photo_bytes:
logger_handler.logger.warning(
f"Verification photo rejected — size {len(verification_photo_data)} chars "
f"exceeds limit of {max_photo_bytes} bytes for employee {employee_id}"
)
return jsonify({
'success': False,
'message': 'Photo is too large. Please use a smaller image and try again.',
'requires_verification': True
}), 413
# Validate photo data format (basic validation)
if verification_photo_data.startswith('data:image/'):
attendance.verification_photo = verification_photo_data
attendance.verification_required = True
@@ -1135,7 +1129,7 @@ def copy_qr_url(qr_id):
return jsonify({
'success': True,
'message': f'QR code URL copied to clipboard!',
'url': f"{_get_qr_base_url()}qr/{qr_code.qr_url}"
'url': f"{request.url_root}qr/{qr_code.qr_url}"
})
except Exception as e:
@@ -1158,7 +1152,7 @@ def open_qr_link(qr_id):
return jsonify({
'success': True,
'message': f'Opening QR code link...',
'url': f"{_get_qr_base_url()}qr/{qr_code.qr_url}"
'url': f"{request.url_root}qr/{qr_code.qr_url}"
})
except Exception as e:
@@ -1216,4 +1210,4 @@ def deactivate_qr_code(qr_id):
return jsonify({
'success': False,
'message': 'Error deactivating QR code. Please try again.'
}), 500
}), 500