We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Accessibility Issues with User Feedback Widget
<!-- Requirements: please go through this checklist before opening a new issue -->

- [x] Review the documentation: https://docs.sentry.io/
- [x] Search for existing issues: https://github.com/getsentry/sentry-javascript/issues
- [x] Use the latest release: https://github.com/getsentry/sentry-javascript/releases
- [x] Provide a link to the affected event from your Sentry account <- Not applicable

## Package + Version

- [x] `@sentry/browser`
- [ ] `@sentry/node`
- [ ] `raven-js`
- [ ] `raven-node` _(raven for node)_
- [ ] other:

### Version:

```
5.29.2
```

## Description

The dialog opened by Sentry.showReportDialog is not accessible. See the [WAI-ARIA Authoring Practices guidance on accessible modals](https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal).

Some specific issues which need to be fixed:

- `Tab` and `Shift` + `Tab` should not move focus to elements outside the modal (they currently can)
- When the modal loads, the first input of the form should receive focus (currently nothing in the modal is focused when the modal loads)
- The "Close" button is rendered using an anchor tag without an `href` attribute. As a result it is not in the tab sequence and keyboard users are not able to use it. To fix this, a `button` element should be used instead. Since the element does not cause navigation, the `button` element will also have the proper semantics and will improve the experience for users of assistive technology.
- The outermost div of the dialog needs `role` set to `dialog`
- The outermost div of the dialog needs `aria-modal` set to `true`
- The outermost div of the dialog needs `aria-labelledby` set to the `id` of the modal's h2


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/sentry/web/frontend/error_page_embed.py`
Content:
```
1 from django import forms
2 from django.db import IntegrityError, transaction
3 from django.http import HttpResponse
4 from django.views.generic import View
5 from django.utils import timezone
6 from django.utils.safestring import mark_safe
7 from django.utils.translation import ugettext_lazy as _
8 from django.views.decorators.csrf import csrf_exempt
9 
10 from sentry import eventstore
11 from sentry.models import Project, ProjectKey, ProjectOption, UserReport
12 from sentry.web.helpers import render_to_response, render_to_string
13 from sentry.signals import user_feedback_received
14 from sentry.utils import json
15 from sentry.utils.http import absolute_uri, is_valid_origin, origin_from_request
16 from sentry.utils.validators import normalize_event_id
17 
18 GENERIC_ERROR = _("An unknown error occurred while submitting your report. Please try again.")
19 FORM_ERROR = _("Some fields were invalid. Please correct the errors and try again.")
20 SENT_MESSAGE = _("Your feedback has been sent. Thank you!")
21 
22 DEFAULT_TITLE = _("It looks like we're having issues.")
23 DEFAULT_SUBTITLE = _("Our team has been notified.")
24 DEFAULT_SUBTITLE2 = _("If you'd like to help, tell us what happened below.")
25 
26 DEFAULT_NAME_LABEL = _("Name")
27 DEFAULT_EMAIL_LABEL = _("Email")
28 DEFAULT_COMMENTS_LABEL = _("What happened?")
29 
30 DEFAULT_CLOSE_LABEL = _("Close")
31 DEFAULT_SUBMIT_LABEL = _("Submit Crash Report")
32 
33 DEFAULT_OPTIONS = {
34     "title": DEFAULT_TITLE,
35     "subtitle": DEFAULT_SUBTITLE,
36     "subtitle2": DEFAULT_SUBTITLE2,
37     "labelName": DEFAULT_NAME_LABEL,
38     "labelEmail": DEFAULT_EMAIL_LABEL,
39     "labelComments": DEFAULT_COMMENTS_LABEL,
40     "labelClose": DEFAULT_CLOSE_LABEL,
41     "labelSubmit": DEFAULT_SUBMIT_LABEL,
42     "errorGeneric": GENERIC_ERROR,
43     "errorFormEntry": FORM_ERROR,
44     "successMessage": SENT_MESSAGE,
45 }
46 
47 
48 class UserReportForm(forms.ModelForm):
49     name = forms.CharField(
50         max_length=128, widget=forms.TextInput(attrs={"placeholder": _("Jane Bloggs")})
51     )
52     email = forms.EmailField(
53         max_length=75,
54         widget=forms.TextInput(attrs={"placeholder": _("jane@example.com"), "type": "email"}),
55     )
56     comments = forms.CharField(
57         widget=forms.Textarea(attrs={"placeholder": _("I clicked on 'X' and then hit 'Confirm'")})
58     )
59 
60     class Meta:
61         model = UserReport
62         fields = ("name", "email", "comments")
63 
64 
65 class ErrorPageEmbedView(View):
66     def _get_project_key(self, request):
67         try:
68             dsn = request.GET["dsn"]
69         except KeyError:
70             return
71 
72         try:
73             key = ProjectKey.from_dsn(dsn)
74         except ProjectKey.DoesNotExist:
75             return
76 
77         return key
78 
79     def _get_origin(self, request):
80         return origin_from_request(request)
81 
82     def _smart_response(self, request, context=None, status=200):
83         json_context = json.dumps(context or {})
84         accept = request.META.get("HTTP_ACCEPT") or ""
85         if "text/javascript" in accept:
86             content_type = "text/javascript"
87             content = ""
88         else:
89             content_type = "application/json"
90             content = json_context
91         response = HttpResponse(content, status=status, content_type=content_type)
92         response["Access-Control-Allow-Origin"] = request.META.get("HTTP_ORIGIN", "")
93         response["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
94         response["Access-Control-Max-Age"] = "1000"
95         response["Access-Control-Allow-Headers"] = "Content-Type, Authorization, X-Requested-With"
96         response["Vary"] = "Accept"
97         if content == "" and context:
98             response["X-Sentry-Context"] = json_context
99         return response
100 
101     @csrf_exempt
102     def dispatch(self, request):
103         try:
104             event_id = request.GET["eventId"]
105         except KeyError:
106             return self._smart_response(
107                 request, {"eventId": "Missing or invalid parameter."}, status=400
108             )
109 
110         normalized_event_id = normalize_event_id(event_id)
111         if normalized_event_id:
112             event_id = normalized_event_id
113         elif event_id:
114             return self._smart_response(
115                 request, {"eventId": "Missing or invalid parameter."}, status=400
116             )
117 
118         key = self._get_project_key(request)
119         if not key:
120             return self._smart_response(
121                 request, {"dsn": "Missing or invalid parameter."}, status=404
122             )
123 
124         origin = self._get_origin(request)
125         if not is_valid_origin(origin, key.project):
126             return self._smart_response(request, status=403)
127 
128         if request.method == "OPTIONS":
129             return self._smart_response(request)
130 
131         # customization options
132         options = DEFAULT_OPTIONS.copy()
133         for name in options.keys():
134             if name in request.GET:
135                 options[name] = str(request.GET[name])
136 
137         # TODO(dcramer): since we cant use a csrf cookie we should at the very
138         # least sign the request / add some kind of nonce
139         initial = {"name": request.GET.get("name"), "email": request.GET.get("email")}
140 
141         form = UserReportForm(request.POST if request.method == "POST" else None, initial=initial)
142         if form.is_valid():
143             # TODO(dcramer): move this to post to the internal API
144             report = form.save(commit=False)
145             report.project_id = key.project_id
146             report.event_id = event_id
147 
148             event = eventstore.get_event_by_id(report.project_id, report.event_id)
149 
150             if event is not None:
151                 report.environment_id = event.get_environment().id
152                 report.group_id = event.group_id
153 
154             try:
155                 with transaction.atomic():
156                     report.save()
157             except IntegrityError:
158                 # There was a duplicate, so just overwrite the existing
159                 # row with the new one. The only way this ever happens is
160                 # if someone is messing around with the API, or doing
161                 # something wrong with the SDK, but this behavior is
162                 # more reasonable than just hard erroring and is more
163                 # expected.
164                 UserReport.objects.filter(
165                     project_id=report.project_id, event_id=report.event_id
166                 ).update(
167                     name=report.name,
168                     email=report.email,
169                     comments=report.comments,
170                     date_added=timezone.now(),
171                 )
172 
173             else:
174                 if report.group_id:
175                     report.notify()
176 
177             user_feedback_received.send(
178                 project=Project.objects.get(id=report.project_id),
179                 sender=self,
180             )
181 
182             return self._smart_response(request)
183         elif request.method == "POST":
184             return self._smart_response(request, {"errors": dict(form.errors)}, status=400)
185 
186         show_branding = (
187             ProjectOption.objects.get_value(
188                 project=key.project, key="feedback:branding", default="1"
189             )
190             == "1"
191         )
192 
193         template = render_to_string(
194             "sentry/error-page-embed.html",
195             context={
196                 "form": form,
197                 "show_branding": show_branding,
198                 "title": options["title"],
199                 "subtitle": options["subtitle"],
200                 "subtitle2": options["subtitle2"],
201                 "name_label": options["labelName"],
202                 "email_label": options["labelEmail"],
203                 "comments_label": options["labelComments"],
204                 "submit_label": options["labelSubmit"],
205                 "close_label": options["labelClose"],
206             },
207         )
208 
209         context = {
210             "endpoint": mark_safe("*/" + json.dumps(absolute_uri(request.get_full_path())) + ";/*"),
211             "template": mark_safe("*/" + json.dumps(template) + ";/*"),
212             "strings": json.dumps_htmlsafe(
213                 {
214                     "generic_error": str(options["errorGeneric"]),
215                     "form_error": str(options["errorFormEntry"]),
216                     "sent_message": str(options["successMessage"]),
217                 }
218             ),
219         }
220 
221         return render_to_response(
222             "sentry/error-page-embed.js", context, request, content_type="text/javascript"
223         )
224
```

Path: `src/sentry/web/frontend/debug/debug_error_embed.py`
Content:
```
1 from django.conf import settings
2 from django.views.generic import View
3 from urllib.parse import urlencode
4 
5 from sentry.models import ProjectKey
6 from sentry.web.helpers import render_to_response
7 
8 
9 class DebugErrorPageEmbedView(View):
10     def _get_project_key(self):
11         return ProjectKey.objects.filter(project=settings.SENTRY_PROJECT)[0]
12 
13     def get(self, request):
14         context = {
15             "query_params": urlencode(
16                 {
17                     "dsn": self._get_project_key().dsn_public,
18                     "event_id": "342a3d7f690a49f8bd7c4cf0e61a9ded",
19                     "options": dict(**request.GET),
20                 }
21             )
22         }
23 
24         return render_to_response("sentry/debug/error-page-embed.html", context, request)
25
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/sentry/web/frontend/debug/debug_error_embed.py b/src/sentry/web/frontend/debug/debug_error_embed.py
--- a/src/sentry/web/frontend/debug/debug_error_embed.py
+++ b/src/sentry/web/frontend/debug/debug_error_embed.py
@@ -15,8 +15,8 @@
             "query_params": urlencode(
                 {
                     "dsn": self._get_project_key().dsn_public,
-                    "event_id": "342a3d7f690a49f8bd7c4cf0e61a9ded",
-                    "options": dict(**request.GET),
+                    "eventId": "342a3d7f690a49f8bd7c4cf0e61a9ded",
+                    **request.GET,
                 }
             )
         }
diff --git a/src/sentry/web/frontend/error_page_embed.py b/src/sentry/web/frontend/error_page_embed.py
--- a/src/sentry/web/frontend/error_page_embed.py
+++ b/src/sentry/web/frontend/error_page_embed.py
@@ -209,12 +209,16 @@
         context = {
             "endpoint": mark_safe("*/" + json.dumps(absolute_uri(request.get_full_path())) + ";/*"),
             "template": mark_safe("*/" + json.dumps(template) + ";/*"),
-            "strings": json.dumps_htmlsafe(
-                {
-                    "generic_error": str(options["errorGeneric"]),
-                    "form_error": str(options["errorFormEntry"]),
-                    "sent_message": str(options["successMessage"]),
-                }
+            "strings": mark_safe(
+                "*/"
+                + json.dumps_htmlsafe(
+                    {
+                        "generic_error": str(options["errorGeneric"]),
+                        "form_error": str(options["errorFormEntry"]),
+                        "sent_message": str(options["successMessage"]),
+                    }
+                )
+                + ";/*"
             ),
         }

{"golden_diff": "diff --git a/src/sentry/web/frontend/debug/debug_error_embed.py b/src/sentry/web/frontend/debug/debug_error_embed.py\n--- a/src/sentry/web/frontend/debug/debug_error_embed.py\n+++ b/src/sentry/web/frontend/debug/debug_error_embed.py\n@@ -15,8 +15,8 @@\n             \"query_params\": urlencode(\n                 {\n                     \"dsn\": self._get_project_key().dsn_public,\n-                    \"event_id\": \"342a3d7f690a49f8bd7c4cf0e61a9ded\",\n-                    \"options\": dict(**request.GET),\n+                    \"eventId\": \"342a3d7f690a49f8bd7c4cf0e61a9ded\",\n+                    **request.GET,\n                 }\n             )\n         }\ndiff --git a/src/sentry/web/frontend/error_page_embed.py b/src/sentry/web/frontend/error_page_embed.py\n--- a/src/sentry/web/frontend/error_page_embed.py\n+++ b/src/sentry/web/frontend/error_page_embed.py\n@@ -209,12 +209,16 @@\n         context = {\n             \"endpoint\": mark_safe(\"*/\" + json.dumps(absolute_uri(request.get_full_path())) + \";/*\"),\n             \"template\": mark_safe(\"*/\" + json.dumps(template) + \";/*\"),\n-            \"strings\": json.dumps_htmlsafe(\n-                {\n-                    \"generic_error\": str(options[\"errorGeneric\"]),\n-                    \"form_error\": str(options[\"errorFormEntry\"]),\n-                    \"sent_message\": str(options[\"successMessage\"]),\n-                }\n+            \"strings\": mark_safe(\n+                \"*/\"\n+                + json.dumps_htmlsafe(\n+                    {\n+                        \"generic_error\": str(options[\"errorGeneric\"]),\n+                        \"form_error\": str(options[\"errorFormEntry\"]),\n+                        \"sent_message\": str(options[\"successMessage\"]),\n+                    }\n+                )\n+                + \";/*\"\n             ),\n         }\n", "issue": "Accessibility Issues with User Feedback Widget\n<!-- Requirements: please go through this checklist before opening a new issue -->\r\n\r\n- [x] Review the documentation: https://docs.sentry.io/\r\n- [x] Search for existing issues: https://github.com/getsentry/sentry-javascript/issues\r\n- [x] Use the latest release: https://github.com/getsentry/sentry-javascript/releases\r\n- [x] Provide a link to the affected event from your Sentry account <- Not applicable\r\n\r\n## Package + Version\r\n\r\n- [x] `@sentry/browser`\r\n- [ ] `@sentry/node`\r\n- [ ] `raven-js`\r\n- [ ] `raven-node` _(raven for node)_\r\n- [ ] other:\r\n\r\n### Version:\r\n\r\n```\r\n5.29.2\r\n```\r\n\r\n## Description\r\n\r\nThe dialog opened by Sentry.showReportDialog is not accessible. See the [WAI-ARIA Authoring Practices guidance on accessible modals](https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal).\r\n\r\nSome specific issues which need to be fixed:\r\n\r\n- `Tab` and `Shift` + `Tab` should not move focus to elements outside the modal (they currently can)\r\n- When the modal loads, the first input of the form should receive focus (currently nothing in the modal is focused when the modal loads)\r\n- The \"Close\" button is rendered using an anchor tag without an `href` attribute. As a result it is not in the tab sequence and keyboard users are not able to use it. To fix this, a `button` element should be used instead. Since the element does not cause navigation, the `button` element will also have the proper semantics and will improve the experience for users of assistive technology.\r\n- The outermost div of the dialog needs `role` set to `dialog`\r\n- The outermost div of the dialog needs `aria-modal` set to `true`\r\n- The outermost div of the dialog needs `aria-labelledby` set to the `id` of the modal's h2\r\n\n", "before_files": [{"content": "from django import forms\nfrom django.db import IntegrityError, transaction\nfrom django.http import HttpResponse\nfrom django.views.generic import View\nfrom django.utils import timezone\nfrom django.utils.safestring import mark_safe\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.views.decorators.csrf import csrf_exempt\n\nfrom sentry import eventstore\nfrom sentry.models import Project, ProjectKey, ProjectOption, UserReport\nfrom sentry.web.helpers import render_to_response, render_to_string\nfrom sentry.signals import user_feedback_received\nfrom sentry.utils import json\nfrom sentry.utils.http import absolute_uri, is_valid_origin, origin_from_request\nfrom sentry.utils.validators import normalize_event_id\n\nGENERIC_ERROR = _(\"An unknown error occurred while submitting your report. Please try again.\")\nFORM_ERROR = _(\"Some fields were invalid. Please correct the errors and try again.\")\nSENT_MESSAGE = _(\"Your feedback has been sent. Thank you!\")\n\nDEFAULT_TITLE = _(\"It looks like we're having issues.\")\nDEFAULT_SUBTITLE = _(\"Our team has been notified.\")\nDEFAULT_SUBTITLE2 = _(\"If you'd like to help, tell us what happened below.\")\n\nDEFAULT_NAME_LABEL = _(\"Name\")\nDEFAULT_EMAIL_LABEL = _(\"Email\")\nDEFAULT_COMMENTS_LABEL = _(\"What happened?\")\n\nDEFAULT_CLOSE_LABEL = _(\"Close\")\nDEFAULT_SUBMIT_LABEL = _(\"Submit Crash Report\")\n\nDEFAULT_OPTIONS = {\n    \"title\": DEFAULT_TITLE,\n    \"subtitle\": DEFAULT_SUBTITLE,\n    \"subtitle2\": DEFAULT_SUBTITLE2,\n    \"labelName\": DEFAULT_NAME_LABEL,\n    \"labelEmail\": DEFAULT_EMAIL_LABEL,\n    \"labelComments\": DEFAULT_COMMENTS_LABEL,\n    \"labelClose\": DEFAULT_CLOSE_LABEL,\n    \"labelSubmit\": DEFAULT_SUBMIT_LABEL,\n    \"errorGeneric\": GENERIC_ERROR,\n    \"errorFormEntry\": FORM_ERROR,\n    \"successMessage\": SENT_MESSAGE,\n}\n\n\nclass UserReportForm(forms.ModelForm):\n    name = forms.CharField(\n        max_length=128, widget=forms.TextInput(attrs={\"placeholder\": _(\"Jane Bloggs\")})\n    )\n    email = forms.EmailField(\n        max_length=75,\n        widget=forms.TextInput(attrs={\"placeholder\": _(\"jane@example.com\"), \"type\": \"email\"}),\n    )\n    comments = forms.CharField(\n        widget=forms.Textarea(attrs={\"placeholder\": _(\"I clicked on 'X' and then hit 'Confirm'\")})\n    )\n\n    class Meta:\n        model = UserReport\n        fields = (\"name\", \"email\", \"comments\")\n\n\nclass ErrorPageEmbedView(View):\n    def _get_project_key(self, request):\n        try:\n            dsn = request.GET[\"dsn\"]\n        except KeyError:\n            return\n\n        try:\n            key = ProjectKey.from_dsn(dsn)\n        except ProjectKey.DoesNotExist:\n            return\n\n        return key\n\n    def _get_origin(self, request):\n        return origin_from_request(request)\n\n    def _smart_response(self, request, context=None, status=200):\n        json_context = json.dumps(context or {})\n        accept = request.META.get(\"HTTP_ACCEPT\") or \"\"\n        if \"text/javascript\" in accept:\n            content_type = \"text/javascript\"\n            content = \"\"\n        else:\n            content_type = \"application/json\"\n            content = json_context\n        response = HttpResponse(content, status=status, content_type=content_type)\n        response[\"Access-Control-Allow-Origin\"] = request.META.get(\"HTTP_ORIGIN\", \"\")\n        response[\"Access-Control-Allow-Methods\"] = \"GET, POST, OPTIONS\"\n        response[\"Access-Control-Max-Age\"] = \"1000\"\n        response[\"Access-Control-Allow-Headers\"] = \"Content-Type, Authorization, X-Requested-With\"\n        response[\"Vary\"] = \"Accept\"\n        if content == \"\" and context:\n            response[\"X-Sentry-Context\"] = json_context\n        return response\n\n    @csrf_exempt\n    def dispatch(self, request):\n        try:\n            event_id = request.GET[\"eventId\"]\n        except KeyError:\n            return self._smart_response(\n                request, {\"eventId\": \"Missing or invalid parameter.\"}, status=400\n            )\n\n        normalized_event_id = normalize_event_id(event_id)\n        if normalized_event_id:\n            event_id = normalized_event_id\n        elif event_id:\n            return self._smart_response(\n                request, {\"eventId\": \"Missing or invalid parameter.\"}, status=400\n            )\n\n        key = self._get_project_key(request)\n        if not key:\n            return self._smart_response(\n                request, {\"dsn\": \"Missing or invalid parameter.\"}, status=404\n            )\n\n        origin = self._get_origin(request)\n        if not is_valid_origin(origin, key.project):\n            return self._smart_response(request, status=403)\n\n        if request.method == \"OPTIONS\":\n            return self._smart_response(request)\n\n        # customization options\n        options = DEFAULT_OPTIONS.copy()\n        for name in options.keys():\n            if name in request.GET:\n                options[name] = str(request.GET[name])\n\n        # TODO(dcramer): since we cant use a csrf cookie we should at the very\n        # least sign the request / add some kind of nonce\n        initial = {\"name\": request.GET.get(\"name\"), \"email\": request.GET.get(\"email\")}\n\n        form = UserReportForm(request.POST if request.method == \"POST\" else None, initial=initial)\n        if form.is_valid():\n            # TODO(dcramer): move this to post to the internal API\n            report = form.save(commit=False)\n            report.project_id = key.project_id\n            report.event_id = event_id\n\n            event = eventstore.get_event_by_id(report.project_id, report.event_id)\n\n            if event is not None:\n                report.environment_id = event.get_environment().id\n                report.group_id = event.group_id\n\n            try:\n                with transaction.atomic():\n                    report.save()\n            except IntegrityError:\n                # There was a duplicate, so just overwrite the existing\n                # row with the new one. The only way this ever happens is\n                # if someone is messing around with the API, or doing\n                # something wrong with the SDK, but this behavior is\n                # more reasonable than just hard erroring and is more\n                # expected.\n                UserReport.objects.filter(\n                    project_id=report.project_id, event_id=report.event_id\n                ).update(\n                    name=report.name,\n                    email=report.email,\n                    comments=report.comments,\n                    date_added=timezone.now(),\n                )\n\n            else:\n                if report.group_id:\n                    report.notify()\n\n            user_feedback_received.send(\n                project=Project.objects.get(id=report.project_id),\n                sender=self,\n            )\n\n            return self._smart_response(request)\n        elif request.method == \"POST\":\n            return self._smart_response(request, {\"errors\": dict(form.errors)}, status=400)\n\n        show_branding = (\n            ProjectOption.objects.get_value(\n                project=key.project, key=\"feedback:branding\", default=\"1\"\n            )\n            == \"1\"\n        )\n\n        template = render_to_string(\n            \"sentry/error-page-embed.html\",\n            context={\n                \"form\": form,\n                \"show_branding\": show_branding,\n                \"title\": options[\"title\"],\n                \"subtitle\": options[\"subtitle\"],\n                \"subtitle2\": options[\"subtitle2\"],\n                \"name_label\": options[\"labelName\"],\n                \"email_label\": options[\"labelEmail\"],\n                \"comments_label\": options[\"labelComments\"],\n                \"submit_label\": options[\"labelSubmit\"],\n                \"close_label\": options[\"labelClose\"],\n            },\n        )\n\n        context = {\n            \"endpoint\": mark_safe(\"*/\" + json.dumps(absolute_uri(request.get_full_path())) + \";/*\"),\n            \"template\": mark_safe(\"*/\" + json.dumps(template) + \";/*\"),\n            \"strings\": json.dumps_htmlsafe(\n                {\n                    \"generic_error\": str(options[\"errorGeneric\"]),\n                    \"form_error\": str(options[\"errorFormEntry\"]),\n                    \"sent_message\": str(options[\"successMessage\"]),\n                }\n            ),\n        }\n\n        return render_to_response(\n            \"sentry/error-page-embed.js\", context, request, content_type=\"text/javascript\"\n        )\n", "path": "src/sentry/web/frontend/error_page_embed.py"}, {"content": "from django.conf import settings\nfrom django.views.generic import View\nfrom urllib.parse import urlencode\n\nfrom sentry.models import ProjectKey\nfrom sentry.web.helpers import render_to_response\n\n\nclass DebugErrorPageEmbedView(View):\n    def _get_project_key(self):\n        return ProjectKey.objects.filter(project=settings.SENTRY_PROJECT)[0]\n\n    def get(self, request):\n        context = {\n            \"query_params\": urlencode(\n                {\n                    \"dsn\": self._get_project_key().dsn_public,\n                    \"event_id\": \"342a3d7f690a49f8bd7c4cf0e61a9ded\",\n                    \"options\": dict(**request.GET),\n                }\n            )\n        }\n\n        return render_to_response(\"sentry/debug/error-page-embed.html\", context, request)\n", "path": "src/sentry/web/frontend/debug/debug_error_embed.py"}], "after_files": [{"content": "from django import forms\nfrom django.db import IntegrityError, transaction\nfrom django.http import HttpResponse\nfrom django.views.generic import View\nfrom django.utils import timezone\nfrom django.utils.safestring import mark_safe\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.views.decorators.csrf import csrf_exempt\n\nfrom sentry import eventstore\nfrom sentry.models import Project, ProjectKey, ProjectOption, UserReport\nfrom sentry.web.helpers import render_to_response, render_to_string\nfrom sentry.signals import user_feedback_received\nfrom sentry.utils import json\nfrom sentry.utils.http import absolute_uri, is_valid_origin, origin_from_request\nfrom sentry.utils.validators import normalize_event_id\n\nGENERIC_ERROR = _(\"An unknown error occurred while submitting your report. Please try again.\")\nFORM_ERROR = _(\"Some fields were invalid. Please correct the errors and try again.\")\nSENT_MESSAGE = _(\"Your feedback has been sent. Thank you!\")\n\nDEFAULT_TITLE = _(\"It looks like we're having issues.\")\nDEFAULT_SUBTITLE = _(\"Our team has been notified.\")\nDEFAULT_SUBTITLE2 = _(\"If you'd like to help, tell us what happened below.\")\n\nDEFAULT_NAME_LABEL = _(\"Name\")\nDEFAULT_EMAIL_LABEL = _(\"Email\")\nDEFAULT_COMMENTS_LABEL = _(\"What happened?\")\n\nDEFAULT_CLOSE_LABEL = _(\"Close\")\nDEFAULT_SUBMIT_LABEL = _(\"Submit Crash Report\")\n\nDEFAULT_OPTIONS = {\n    \"title\": DEFAULT_TITLE,\n    \"subtitle\": DEFAULT_SUBTITLE,\n    \"subtitle2\": DEFAULT_SUBTITLE2,\n    \"labelName\": DEFAULT_NAME_LABEL,\n    \"labelEmail\": DEFAULT_EMAIL_LABEL,\n    \"labelComments\": DEFAULT_COMMENTS_LABEL,\n    \"labelClose\": DEFAULT_CLOSE_LABEL,\n    \"labelSubmit\": DEFAULT_SUBMIT_LABEL,\n    \"errorGeneric\": GENERIC_ERROR,\n    \"errorFormEntry\": FORM_ERROR,\n    \"successMessage\": SENT_MESSAGE,\n}\n\n\nclass UserReportForm(forms.ModelForm):\n    name = forms.CharField(\n        max_length=128, widget=forms.TextInput(attrs={\"placeholder\": _(\"Jane Bloggs\")})\n    )\n    email = forms.EmailField(\n        max_length=75,\n        widget=forms.TextInput(attrs={\"placeholder\": _(\"jane@example.com\"), \"type\": \"email\"}),\n    )\n    comments = forms.CharField(\n        widget=forms.Textarea(attrs={\"placeholder\": _(\"I clicked on 'X' and then hit 'Confirm'\")})\n    )\n\n    class Meta:\n        model = UserReport\n        fields = (\"name\", \"email\", \"comments\")\n\n\nclass ErrorPageEmbedView(View):\n    def _get_project_key(self, request):\n        try:\n            dsn = request.GET[\"dsn\"]\n        except KeyError:\n            return\n\n        try:\n            key = ProjectKey.from_dsn(dsn)\n        except ProjectKey.DoesNotExist:\n            return\n\n        return key\n\n    def _get_origin(self, request):\n        return origin_from_request(request)\n\n    def _smart_response(self, request, context=None, status=200):\n        json_context = json.dumps(context or {})\n        accept = request.META.get(\"HTTP_ACCEPT\") or \"\"\n        if \"text/javascript\" in accept:\n            content_type = \"text/javascript\"\n            content = \"\"\n        else:\n            content_type = \"application/json\"\n            content = json_context\n        response = HttpResponse(content, status=status, content_type=content_type)\n        response[\"Access-Control-Allow-Origin\"] = request.META.get(\"HTTP_ORIGIN\", \"\")\n        response[\"Access-Control-Allow-Methods\"] = \"GET, POST, OPTIONS\"\n        response[\"Access-Control-Max-Age\"] = \"1000\"\n        response[\"Access-Control-Allow-Headers\"] = \"Content-Type, Authorization, X-Requested-With\"\n        response[\"Vary\"] = \"Accept\"\n        if content == \"\" and context:\n            response[\"X-Sentry-Context\"] = json_context\n        return response\n\n    @csrf_exempt\n    def dispatch(self, request):\n        try:\n            event_id = request.GET[\"eventId\"]\n        except KeyError:\n            return self._smart_response(\n                request, {\"eventId\": \"Missing or invalid parameter.\"}, status=400\n            )\n\n        normalized_event_id = normalize_event_id(event_id)\n        if normalized_event_id:\n            event_id = normalized_event_id\n        elif event_id:\n            return self._smart_response(\n                request, {\"eventId\": \"Missing or invalid parameter.\"}, status=400\n            )\n\n        key = self._get_project_key(request)\n        if not key:\n            return self._smart_response(\n                request, {\"dsn\": \"Missing or invalid parameter.\"}, status=404\n            )\n\n        origin = self._get_origin(request)\n        if not is_valid_origin(origin, key.project):\n            return self._smart_response(request, status=403)\n\n        if request.method == \"OPTIONS\":\n            return self._smart_response(request)\n\n        # customization options\n        options = DEFAULT_OPTIONS.copy()\n        for name in options.keys():\n            if name in request.GET:\n                options[name] = str(request.GET[name])\n\n        # TODO(dcramer): since we cant use a csrf cookie we should at the very\n        # least sign the request / add some kind of nonce\n        initial = {\"name\": request.GET.get(\"name\"), \"email\": request.GET.get(\"email\")}\n\n        form = UserReportForm(request.POST if request.method == \"POST\" else None, initial=initial)\n        if form.is_valid():\n            # TODO(dcramer): move this to post to the internal API\n            report = form.save(commit=False)\n            report.project_id = key.project_id\n            report.event_id = event_id\n\n            event = eventstore.get_event_by_id(report.project_id, report.event_id)\n\n            if event is not None:\n                report.environment_id = event.get_environment().id\n                report.group_id = event.group_id\n\n            try:\n                with transaction.atomic():\n                    report.save()\n            except IntegrityError:\n                # There was a duplicate, so just overwrite the existing\n                # row with the new one. The only way this ever happens is\n                # if someone is messing around with the API, or doing\n                # something wrong with the SDK, but this behavior is\n                # more reasonable than just hard erroring and is more\n                # expected.\n                UserReport.objects.filter(\n                    project_id=report.project_id, event_id=report.event_id\n                ).update(\n                    name=report.name,\n                    email=report.email,\n                    comments=report.comments,\n                    date_added=timezone.now(),\n                )\n\n            else:\n                if report.group_id:\n                    report.notify()\n\n            user_feedback_received.send(\n                project=Project.objects.get(id=report.project_id),\n                sender=self,\n            )\n\n            return self._smart_response(request)\n        elif request.method == \"POST\":\n            return self._smart_response(request, {\"errors\": dict(form.errors)}, status=400)\n\n        show_branding = (\n            ProjectOption.objects.get_value(\n                project=key.project, key=\"feedback:branding\", default=\"1\"\n            )\n            == \"1\"\n        )\n\n        template = render_to_string(\n            \"sentry/error-page-embed.html\",\n            context={\n                \"form\": form,\n                \"show_branding\": show_branding,\n                \"title\": options[\"title\"],\n                \"subtitle\": options[\"subtitle\"],\n                \"subtitle2\": options[\"subtitle2\"],\n                \"name_label\": options[\"labelName\"],\n                \"email_label\": options[\"labelEmail\"],\n                \"comments_label\": options[\"labelComments\"],\n                \"submit_label\": options[\"labelSubmit\"],\n                \"close_label\": options[\"labelClose\"],\n            },\n        )\n\n        context = {\n            \"endpoint\": mark_safe(\"*/\" + json.dumps(absolute_uri(request.get_full_path())) + \";/*\"),\n            \"template\": mark_safe(\"*/\" + json.dumps(template) + \";/*\"),\n            \"strings\": mark_safe(\n                \"*/\"\n                + json.dumps_htmlsafe(\n                    {\n                        \"generic_error\": str(options[\"errorGeneric\"]),\n                        \"form_error\": str(options[\"errorFormEntry\"]),\n                        \"sent_message\": str(options[\"successMessage\"]),\n                    }\n                )\n                + \";/*\"\n            ),\n        }\n\n        return render_to_response(\n            \"sentry/error-page-embed.js\", context, request, content_type=\"text/javascript\"\n        )\n", "path": "src/sentry/web/frontend/error_page_embed.py"}, {"content": "from django.conf import settings\nfrom django.views.generic import View\nfrom urllib.parse import urlencode\n\nfrom sentry.models import ProjectKey\nfrom sentry.web.helpers import render_to_response\n\n\nclass DebugErrorPageEmbedView(View):\n    def _get_project_key(self):\n        return ProjectKey.objects.filter(project=settings.SENTRY_PROJECT)[0]\n\n    def get(self, request):\n        context = {\n            \"query_params\": urlencode(\n                {\n                    \"dsn\": self._get_project_key().dsn_public,\n                    \"eventId\": \"342a3d7f690a49f8bd7c4cf0e61a9ded\",\n                    **request.GET,\n                }\n            )\n        }\n\n        return render_to_response(\"sentry/debug/error-page-embed.html\", context, request)\n", "path": "src/sentry/web/frontend/debug/debug_error_embed.py"}]}