views.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import json
  2. from django.conf import settings
  3. from django.db import IntegrityError
  4. from django.template.loader import render_to_string
  5. from django.utils.safestring import mark_safe
  6. from rest_framework import exceptions, permissions, renderers, views, viewsets
  7. from rest_framework.response import Response
  8. from events.models import Event
  9. from issues.permissions import EventPermission
  10. from projects.models import ProjectKey
  11. from .forms import UserReportForm
  12. from .models import UserReport
  13. from .serializers import ErrorPageEmbedSerializer, UserReportSerializer
  14. class JavaScriptSuccessRenderer(renderers.JSONRenderer):
  15. """
  16. Render as JavaScript when status code is 200.
  17. On failure status codes, render as JSON instead.
  18. """
  19. media_type = "application/javascript"
  20. format = "js"
  21. def render(self, data, media_type=None, renderer_context=None):
  22. if renderer_context["response"].status_code == 200:
  23. charset = "utf-8"
  24. return data.encode(charset)
  25. return super().render(data, "application/json", renderer_context)
  26. class ErrorPageEmbedView(views.APIView):
  27. """
  28. Ideas taken from OSS Sentry sentry/web/error_page_embed.py
  29. Modified for DRF
  30. """
  31. permission_classes = [permissions.AllowAny]
  32. renderer_classes = [
  33. renderers.JSONRenderer,
  34. renderers.BrowsableAPIRenderer,
  35. JavaScriptSuccessRenderer,
  36. ]
  37. def get_format_suffix(self, **kwargs):
  38. if self.request.method == "GET":
  39. return "js"
  40. return super().get_format_suffix(**kwargs)
  41. def process_get_params(self, params):
  42. serializer = ErrorPageEmbedSerializer(data=params)
  43. serializer.is_valid(raise_exception=True)
  44. return serializer.validated_data
  45. def get_project_key(self, validated_data):
  46. dsn = validated_data["dsn"]
  47. try:
  48. return ProjectKey.from_dsn(dsn)
  49. except ProjectKey.DoesNotExist:
  50. raise exceptions.NotFound("Invalid dsn parameter")
  51. def get(self, request):
  52. data = self.process_get_params(request.GET)
  53. self.get_project_key(data)
  54. initial = {"name": request.GET.get("name"), "email": request.GET.get("email")}
  55. # Stubbed, should be configurable
  56. show_branding = True
  57. form = UserReportForm(initial=initial)
  58. template = render_to_string(
  59. "user_reports/error-page-embed.html",
  60. {
  61. "form": form,
  62. "show_branding": show_branding,
  63. "title": data["title"],
  64. "subtitle": data["subtitle"],
  65. "subtitle2": data["subtitle2"],
  66. "name_label": data["labelName"],
  67. "email_label": data["labelEmail"],
  68. "comments_label": data["labelComments"],
  69. "submit_label": data["labelSubmit"],
  70. "close_label": data["labelClose"],
  71. },
  72. )
  73. url = settings.GLITCHTIP_URL.geturl() + request.get_full_path()
  74. context = {
  75. "endpoint": mark_safe("*/" + json.dumps(url) + ";/*"),
  76. "template": mark_safe("*/" + json.dumps(template) + ";/*"),
  77. "strings": mark_safe(
  78. json.dumps(
  79. {
  80. "generic_error": str(data["errorGeneric"]),
  81. "form_error": str(data["errorFormEntry"]),
  82. "sent_message": str(data["successMessage"]),
  83. }
  84. )
  85. ),
  86. }
  87. return Response(
  88. render_to_string("user_reports/error-page-embed.js", context, request),
  89. content_type="application/javascript",
  90. )
  91. def post(self, request):
  92. data = self.process_get_params(request.GET)
  93. project_key = self.get_project_key(data)
  94. event_id = data["eventId"]
  95. initial = {"name": request.GET.get("name"), "email": request.GET.get("email")}
  96. form = UserReportForm(request.POST, initial=initial)
  97. if form.is_valid():
  98. report = form.save(commit=False)
  99. report.project = project_key.project
  100. report.event_id = event_id
  101. event = Event.objects.filter(event_id=event_id).first()
  102. if event:
  103. report.issue = event.issue
  104. try:
  105. report.save()
  106. except IntegrityError:
  107. pass # Duplicate, ignore
  108. return Response()
  109. return Response({"errors": form.errors}, status=400)
  110. class UserReportViewSet(viewsets.ReadOnlyModelViewSet):
  111. queryset = UserReport.objects.all()
  112. serializer_class = UserReportSerializer
  113. permission_classes = [EventPermission]
  114. def get_queryset(self):
  115. if not self.request.user.is_authenticated:
  116. return self.queryset.none()
  117. queryset = super().get_queryset()
  118. queryset = queryset.filter(project__team__members__user=self.request.user)
  119. issue_id = self.kwargs.get("issue_pk")
  120. if issue_id:
  121. queryset = queryset.filter(issue_id=issue_id)
  122. return queryset