Add email alerts for operator issue reports

- Send alert to default alert recipients when operator submits issue report
- Email includes device link, hostname, asset tag, reason, details, and timestamp
- Screenshot link included when available
- Uses existing send_alert() mailer infrastructure
This commit is contained in:
Proudlock
2026-09-09 08:18:44 -04:00
parent deb2bbe9df
commit f5d1b12e3f

View File

@@ -32,6 +32,7 @@ from ..models import (
)
from ..commands import COMMAND_ALLOWLIST, is_allowed_action, ALLOWED_ACTIONS_FOR, row_actions_for, requires_target, action_targetkind, elevated_permission_for, PLACE_POLICY_HOLD, ACTIVE_POLICY_HOLDS, HOLDABLE_ACTIONS_FOR, RELEASE_POLICY_HOLD, ACTIVE_LOCK_FOR, PLACE_ENDPOINT_LOCK, RELEASE_ENDPOINT_LOCK
from ..eventcatalog import CRITICAL_EVENT_IDS, event_severity, event_title
from shopdb.utils.mailer import send_alert
endpoints_bp = Blueprint('endpoints', __name__)
@@ -2935,6 +2936,45 @@ def _purge_expired_operator_reports():
db.session.commit()
def _send_operator_report_alert(report, asset_id, hostname):
"""Send email alert for new operator issue report to default alert recipients."""
from flask import url_for
asset = Asset.query.get(asset_id)
if not asset:
return
device_url = url_for('assets.detail', asset_id=asset_id, _external=True)
reported_at = report.createdat.strftime('%Y-%m-%d %H:%M:%S UTC') if report.createdat else 'Unknown'
screenshot_info = ''
if report.imagefilename:
screenshot_url = url_for('endpoints.serve_operator_report_image',
operatorreportid=report.operatorreportid,
_external=True)
screenshot_info = f'<p><strong>Screenshot:</strong> <a href="{screenshot_url}">View Screenshot</a></p>'
details_html = f'<p style="white-space: pre-wrap;">{report.details or "No additional details provided."}</p>'
html_body = f'''
<div style="padding: 16px; background: #f9f9f9; border-left: 4px solid #d93f3f; margin-bottom: 16px;">
<p style="margin: 0 0 8px; font-weight: bold; color: #d93f3f;">New Issue Report from Shop Floor</p>
<p style="margin: 0;"><strong>Device:</strong> <a href="{device_url}">{asset.computername or hostname}</a> ({hostname})</p>
<p style="margin: 0;"><strong>Asset Tag:</strong> {asset.assettag or 'N/A'}</p>
<p style="margin: 0;"><strong>Reason:</strong> {report.reason}</p>
<p style="margin: 0;"><strong>Reported:</strong> {reported_at}</p>
</div>
<p><strong>Details:</strong></p>
{details_html}
{screenshot_info}
<p><a href="{device_url}" style="display: inline-block; padding: 10px 16px; background: #1a73e8; color: white; text-decoration: none; border-radius: 4px;">View Device in ShopDB</a></p>
'''
subject = f'Operator Issue Report: {asset.computername or hostname}'
send_alert(subject, html_body)
@endpoints_bp.route('/operatorreports', methods=['POST'])
def upload_operator_report():
"""Agent uploads one operator issue report (collector-token auth).
@@ -3031,6 +3071,12 @@ def upload_operator_report():
except Exception:
db.session.rollback()
# Send email alert to default alert recipients
try:
_send_operator_report_alert(report, asset_id, hostname)
except Exception as e:
current_app.logger.warning('Failed to send operator report alert email: %s', e)
return success_response(report.to_dict(),
message='Operator report received', http_code=201)