mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-05 05:31:31 +02:00
Floating bug report button submits issues via bambuddy.cool relay (no GitHub token needed locally). Collects 30s debug logs with printer push_all, sanitizes all sensitive data, uploads logs as files to GitHub. Screenshot upload/paste/drag with JPEG compression. Translated into all 7 languages. Includes 21 tests.
96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
"""Bug report endpoint for submitting user bug reports to GitHub."""
|
|
|
|
import asyncio
|
|
import logging
|
|
|
|
from fastapi import APIRouter
|
|
from pydantic import BaseModel
|
|
|
|
from backend.app.api.routes.support import (
|
|
_apply_log_level,
|
|
_collect_support_info,
|
|
_get_debug_setting,
|
|
_get_recent_sanitized_logs,
|
|
_set_debug_setting,
|
|
)
|
|
from backend.app.core.database import async_session
|
|
from backend.app.services.bug_report import submit_report
|
|
from backend.app.services.printer_manager import printer_manager
|
|
|
|
router = APIRouter(prefix="/bug-report", tags=["bug-report"])
|
|
logger = logging.getLogger(__name__)
|
|
|
|
LOG_COLLECTION_SECONDS = 30
|
|
|
|
|
|
class BugReportRequest(BaseModel):
|
|
description: str
|
|
email: str | None = None
|
|
screenshot_base64: str | None = None
|
|
include_support_info: bool = True
|
|
|
|
|
|
class BugReportResponse(BaseModel):
|
|
success: bool
|
|
message: str
|
|
issue_url: str | None = None
|
|
issue_number: int | None = None
|
|
|
|
|
|
async def _collect_debug_logs() -> str:
|
|
"""Enable debug logging, push all printers, wait, then collect logs."""
|
|
# Check if debug was already enabled
|
|
async with async_session() as db:
|
|
was_debug, _ = await _get_debug_setting(db)
|
|
|
|
# Enable debug logging
|
|
if not was_debug:
|
|
async with async_session() as db:
|
|
await _set_debug_setting(db, True)
|
|
_apply_log_level(True)
|
|
logger.info("Bug report: temporarily enabled debug logging")
|
|
|
|
# Send push_all to all connected printers
|
|
for printer_id in list(printer_manager._clients.keys()):
|
|
try:
|
|
printer_manager.request_status_update(printer_id)
|
|
except Exception:
|
|
logger.debug("Failed to push_all for printer %s", printer_id)
|
|
|
|
# Wait for logs to accumulate
|
|
await asyncio.sleep(LOG_COLLECTION_SECONDS)
|
|
|
|
# Collect logs
|
|
logs = await _get_recent_sanitized_logs()
|
|
|
|
# Restore previous log level if it wasn't debug before
|
|
if not was_debug:
|
|
async with async_session() as db:
|
|
await _set_debug_setting(db, False)
|
|
_apply_log_level(False)
|
|
logger.info("Bug report: restored normal logging")
|
|
|
|
return logs
|
|
|
|
|
|
@router.post("/submit", response_model=BugReportResponse)
|
|
async def submit_bug_report(report: BugReportRequest):
|
|
"""Submit a bug report. No auth required — anyone should be able to report bugs."""
|
|
support_info = None
|
|
if report.include_support_info:
|
|
try:
|
|
support_info = await _collect_support_info()
|
|
logs = await _collect_debug_logs()
|
|
if logs:
|
|
support_info["recent_logs"] = logs
|
|
except Exception:
|
|
logger.exception("Failed to collect support info for bug report")
|
|
|
|
result = await submit_report(
|
|
description=report.description,
|
|
reporter_email=report.email,
|
|
screenshot_base64=report.screenshot_base64,
|
|
support_info=support_info,
|
|
)
|
|
return BugReportResponse(**result)
|