diff --git a/plugins/endpoints/api/routes.py b/plugins/endpoints/api/routes.py index 470fbf54..9f9fff9d 100644 --- a/plugins/endpoints/api/routes.py +++ b/plugins/endpoints/api/routes.py @@ -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'

Screenshot: View Screenshot

' + + details_html = f'

{report.details or "No additional details provided."}

' + + html_body = f''' +
+

New Issue Report from Shop Floor

+

Device: {asset.computername or hostname} ({hostname})

+

Asset Tag: {asset.assettag or 'N/A'}

+

Reason: {report.reason}

+

Reported: {reported_at}

+
+

Details:

+{details_html} +{screenshot_info} +

View Device in ShopDB

+''' + + 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)