views.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import json
  2. from django.db import IntegrityError
  3. from django.conf import settings
  4. from django.template.loader import render_to_string
  5. from django.utils.safestring import mark_safe
  6. from rest_framework import views, viewsets, exceptions, permissions, renderers
  7. from rest_framework.response import Response
  8. from projects.models import ProjectKey
  9. from events.models import Event
  10. from issues.permissions import EventPermission
  11. from .models import UserReport
  12. from .forms import UserReportForm
  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