bug_report.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. """Bug report endpoint for submitting user bug reports to GitHub."""
  2. import logging
  3. from fastapi import APIRouter, Query
  4. from pydantic import BaseModel
  5. from backend.app.api.routes.support import (
  6. _apply_log_level,
  7. _collect_support_info,
  8. _get_debug_setting,
  9. _get_recent_sanitized_logs,
  10. _set_debug_setting,
  11. )
  12. from backend.app.core.database import async_session
  13. from backend.app.services.bug_report import submit_report
  14. from backend.app.services.printer_manager import printer_manager
  15. router = APIRouter(prefix="/bug-report", tags=["bug-report"])
  16. logger = logging.getLogger(__name__)
  17. class BugReportRequest(BaseModel):
  18. description: str
  19. email: str | None = None
  20. screenshot_base64: str | None = None
  21. include_support_info: bool = True
  22. debug_logs: str | None = None
  23. class BugReportResponse(BaseModel):
  24. success: bool
  25. message: str
  26. issue_url: str | None = None
  27. issue_number: int | None = None
  28. class StartLoggingResponse(BaseModel):
  29. started: bool
  30. was_debug: bool
  31. class StopLoggingResponse(BaseModel):
  32. logs: str
  33. @router.post("/start-logging", response_model=StartLoggingResponse)
  34. async def start_logging():
  35. """Enable debug logging and push all printers for fresh data."""
  36. async with async_session() as db:
  37. was_debug, _ = await _get_debug_setting(db)
  38. if not was_debug:
  39. async with async_session() as db:
  40. await _set_debug_setting(db, True)
  41. _apply_log_level(True)
  42. logger.info("Bug report: enabled debug logging")
  43. for printer_id in list(printer_manager._clients.keys()):
  44. try:
  45. printer_manager.request_status_update(printer_id)
  46. except Exception:
  47. logger.debug("Failed to push_all for printer %s", printer_id)
  48. return StartLoggingResponse(started=True, was_debug=was_debug)
  49. @router.post("/stop-logging", response_model=StopLoggingResponse)
  50. async def stop_logging(was_debug: bool = Query(default=False)):
  51. """Collect logs and restore previous log level."""
  52. logs = await _get_recent_sanitized_logs()
  53. if not was_debug:
  54. async with async_session() as db:
  55. await _set_debug_setting(db, False)
  56. _apply_log_level(False)
  57. logger.info("Bug report: restored normal logging")
  58. return StopLoggingResponse(logs=logs)
  59. @router.post("/submit", response_model=BugReportResponse)
  60. async def submit_bug_report(report: BugReportRequest):
  61. """Submit a bug report. No auth required — anyone should be able to report bugs."""
  62. support_info = None
  63. if report.include_support_info:
  64. try:
  65. support_info = await _collect_support_info()
  66. if report.debug_logs:
  67. support_info["recent_logs"] = report.debug_logs
  68. except Exception:
  69. logger.exception("Failed to collect support info for bug report")
  70. result = await submit_report(
  71. description=report.description,
  72. reporter_email=report.email,
  73. screenshot_base64=report.screenshot_base64,
  74. support_info=support_info,
  75. )
  76. return BugReportResponse(**result)