Exemple #1
0
    def test_user_feedback(self):
        user_feedback_received.send(project=self.project,
                                    sender=type(self.project))

        feature_complete = FeatureAdoption.objects.get_by_slug(
            organization=self.organization, slug="user_feedback")
        assert feature_complete
Exemple #2
0
    def test_user_feedback(self):
        user_feedback_received.send(project=self.project, sender=type(self.project))

        feature_complete = FeatureAdoption.objects.get_by_slug(
            organization=self.organization, slug="user_feedback"
        )
        assert feature_complete
    def post(self, request, project):
        """
        Submit User Feedback
        ````````````````````

        Submit and associate user feedback with an issue.

        :pparam string organization_slug: the slug of the organization.
        :pparam string project_slug: the slug of the project.
        :auth: required
        :param string event_id: the event ID
        :param string name: user's name
        :param string email: user's email address
        :param string comments: comments supplied by user
        """
        serializer = UserReportSerializer(data=request.DATA)
        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        report = serializer.object
        report.project = project

        # TODO(dcramer): we should probably create the user if they dont
        # exist, and ideally we'd also associate that with the event
        euser = self.find_event_user(report)
        if euser and not euser.name and report.name:
            euser.update(name=report.name)
        if euser:
            report.event_user_id = euser.id

        try:
            report.group = Group.objects.from_event_id(project,
                                                       report.event_id)
        except Group.DoesNotExist:
            pass

        try:
            with transaction.atomic():
                report.save()
        except IntegrityError:
            # There was a duplicate, so just overwrite the existing
            # row with the new one. The only way this ever happens is
            # if someone is messing around with the API, or doing
            # something wrong with the SDK, but this behavior is
            # more reasonable than just hard erroring and is more
            # expected.
            existing_report = UserReport.objects.get(
                project=report.project,
                event_id=report.event_id,
            )

            existing_report.update(
                name=report.name,
                email=report.email,
                comments=report.comments,
                date_added=timezone.now(),
                event_user_id=euser.id if euser else None,
            )
            report = existing_report

        if report.group_id is None:
            backfill_group.apply_async(
                kwargs={
                    'report_id': report.id,
                },
                countdown=30,
            )

        user_feedback_received.send(project=report.project,
                                    group=report.group,
                                    sender=self)

        return Response(
            serialize(report, request.user, ProjectUserReportSerializer()))
Exemple #4
0
    def dispatch(self, request):
        try:
            event_id = request.GET['eventId']
        except KeyError:
            return self._smart_response(
                request, {'eventId': 'Missing or invalid parameter.'},
                status=400)

        if event_id and not is_event_id(event_id):
            return self._smart_response(
                request, {'eventId': 'Missing or invalid parameter.'},
                status=400)

        # XXX(dcramer): enforce case insensitivty by coercing this to a lowercase string
        event_id = event_id.lower()

        key = self._get_project_key(request)
        if not key:
            return self._smart_response(
                request, {'dsn': 'Missing or invalid parameter.'}, status=404)

        origin = self._get_origin(request)
        if not is_valid_origin(origin, key.project):
            return self._smart_response(request, status=403)

        if request.method == 'OPTIONS':
            return self._smart_response(request)

        # customization options
        options = DEFAULT_OPTIONS.copy()
        for name in six.iterkeys(options):
            if name in request.GET:
                options[name] = six.text_type(request.GET[name])

        # TODO(dcramer): since we cant use a csrf cookie we should at the very
        # least sign the request / add some kind of nonce
        initial = {
            'name': request.GET.get('name'),
            'email': request.GET.get('email'),
        }

        form = UserReportForm(
            request.POST if request.method == 'POST' else None,
            initial=initial)
        if form.is_valid():
            # TODO(dcramer): move this to post to the internal API
            report = form.save(commit=False)
            report.project = key.project
            report.event_id = event_id

            try:
                event = Event.objects.filter(project_id=report.project.id,
                                             event_id=report.event_id)[0]
            except IndexError:
                try:
                    report.group = Group.objects.from_event_id(
                        report.project, report.event_id)
                except Group.DoesNotExist:
                    pass
            else:
                Event.objects.bind_nodes([event])
                report.environment = event.get_environment()
                report.group = event.group

            try:
                with transaction.atomic():
                    report.save()
            except IntegrityError:
                # There was a duplicate, so just overwrite the existing
                # row with the new one. The only way this ever happens is
                # if someone is messing around with the API, or doing
                # something wrong with the SDK, but this behavior is
                # more reasonable than just hard erroring and is more
                # expected.
                UserReport.objects.filter(
                    project=report.project,
                    event_id=report.event_id,
                ).update(
                    name=report.name,
                    email=report.email,
                    comments=report.comments,
                    date_added=timezone.now(),
                )

            else:
                if report.group:
                    report.notify()

            user_feedback_received.send(project=report.project,
                                        group=report.group,
                                        sender=self)

            return self._smart_response(request)
        elif request.method == 'POST':
            return self._smart_response(request, {
                "errors": dict(form.errors),
            },
                                        status=400)

        show_branding = ProjectOption.objects.get_value(
            project=key.project, key='feedback:branding', default='1') == '1'

        template = render_to_string(
            'sentry/error-page-embed.html', {
                'form': form,
                'show_branding': show_branding,
                'title': options['title'],
                'subtitle': options['subtitle'],
                'subtitle2': options['subtitle2'],
                'name_label': options['labelName'],
                'email_label': options['labelEmail'],
                'comments_label': options['labelComments'],
                'submit_label': options['labelSubmit'],
                'close_label': options['labelClose'],
            })

        context = {
            'endpoint':
            mark_safe('*/' + json.dumps(request.build_absolute_uri()) + ';/*'),
            'template':
            mark_safe('*/' + json.dumps(template) + ';/*'),
            'strings':
            json.dumps_htmlsafe({
                'generic_error':
                six.text_type(options['errorGeneric']),
                'form_error':
                six.text_type(options['errorFormEntry']),
                'sent_message':
                six.text_type(options['successMessage']),
            }),
        }

        return render_to_response('sentry/error-page-embed.js',
                                  context,
                                  request,
                                  content_type='text/javascript')
    def dispatch(self, request):
        try:
            event_id = request.GET["eventId"]
        except KeyError:
            return self._smart_response(
                request, {"eventId": "Missing or invalid parameter."},
                status=400)

        normalized_event_id = normalize_event_id(event_id)
        if normalized_event_id:
            event_id = normalized_event_id
        elif event_id:
            return self._smart_response(
                request, {"eventId": "Missing or invalid parameter."},
                status=400)

        key = self._get_project_key(request)
        if not key:
            return self._smart_response(
                request, {"dsn": "Missing or invalid parameter."}, status=404)

        origin = self._get_origin(request)
        if not is_valid_origin(origin, key.project):
            return self._smart_response(request, status=403)

        if request.method == "OPTIONS":
            return self._smart_response(request)

        # customization options
        options = DEFAULT_OPTIONS.copy()
        for name in options.keys():
            if name in request.GET:
                options[name] = str(request.GET[name])

        # TODO(dcramer): since we cant use a csrf cookie we should at the very
        # least sign the request / add some kind of nonce
        initial = {
            "name": request.GET.get("name"),
            "email": request.GET.get("email")
        }

        form = UserReportForm(
            request.POST if request.method == "POST" else None,
            initial=initial)
        if form.is_valid():
            # TODO(dcramer): move this to post to the internal API
            report = form.save(commit=False)
            report.project_id = key.project_id
            report.event_id = event_id

            event = eventstore.get_event_by_id(report.project_id,
                                               report.event_id)

            if event is not None:
                report.environment_id = event.get_environment().id
                report.group_id = event.group_id

            try:
                with transaction.atomic():
                    report.save()
            except IntegrityError:
                # There was a duplicate, so just overwrite the existing
                # row with the new one. The only way this ever happens is
                # if someone is messing around with the API, or doing
                # something wrong with the SDK, but this behavior is
                # more reasonable than just hard erroring and is more
                # expected.
                UserReport.objects.filter(project_id=report.project_id,
                                          event_id=report.event_id).update(
                                              name=report.name,
                                              email=report.email,
                                              comments=report.comments,
                                              date_added=timezone.now(),
                                          )

            else:
                if report.group_id:
                    report.notify()

            user_feedback_received.send(
                project=Project.objects.get(id=report.project_id),
                sender=self,
            )

            return self._smart_response(request)
        elif request.method == "POST":
            return self._smart_response(request, {"errors": dict(form.errors)},
                                        status=400)

        show_branding = (ProjectOption.objects.get_value(
            project=key.project, key="feedback:branding", default="1") == "1")

        template = render_to_string(
            "sentry/error-page-embed.html",
            context={
                "form": form,
                "show_branding": show_branding,
                "title": options["title"],
                "subtitle": options["subtitle"],
                "subtitle2": options["subtitle2"],
                "name_label": options["labelName"],
                "email_label": options["labelEmail"],
                "comments_label": options["labelComments"],
                "submit_label": options["labelSubmit"],
                "close_label": options["labelClose"],
            },
        )

        context = {
            "endpoint":
            mark_safe("*/" +
                      json.dumps(absolute_uri(request.get_full_path())) +
                      ";/*"),
            "template":
            mark_safe("*/" + json.dumps(template) + ";/*"),
            "strings":
            mark_safe("*/" + json.dumps_htmlsafe(
                {
                    "generic_error": str(options["errorGeneric"]),
                    "form_error": str(options["errorFormEntry"]),
                    "sent_message": str(options["successMessage"]),
                }) + ";/*"),
        }

        return render_to_response("sentry/error-page-embed.js",
                                  context,
                                  request,
                                  content_type="text/javascript")
    def post(self, request, project):
        """
        Submit User Feedback
        ````````````````````

        Submit and associate user feedback with an issue.

        Feedback must be received by the server no more than 30 minutes after the event was saved.

        Additionally, within 5 minutes of submitting feedback it may also be overwritten. This is useful
        in situations where you may need to retry sending a request due to network failures.

        If feedback is rejected due to a mutability threshold, a 409 status code will be returned.

        :pparam string organization_slug: the slug of the organization.
        :pparam string project_slug: the slug of the project.
        :auth: required
        :param string event_id: the event ID
        :param string name: user's name
        :param string email: user's email address
        :param string comments: comments supplied by user
        """
        serializer = UserReportSerializer(data=request.DATA)
        if not serializer.is_valid():
            return self.respond(serializer.errors, status=400)

        report = serializer.object
        report.project = project

        # TODO(dcramer): we should probably create the user if they dont
        # exist, and ideally we'd also associate that with the event
        euser = self.find_event_user(report)
        if euser and not euser.name and report.name:
            euser.update(name=report.name)
        if euser:
            report.event_user_id = euser.id

        event = Event.objects.filter(
            project_id=project.id,
            event_id=report.event_id,
        ).first()
        if not event:
            try:
                report.group = Group.objects.from_event_id(
                    project, report.event_id)
            except Group.DoesNotExist:
                pass
        else:
            # if the event is more than 30 minutes old, we dont allow updates
            # as it might be abusive
            if event.datetime < timezone.now() - timedelta(minutes=30):
                return self.respond(
                    {'detail': 'Feedback for this event cannot be modified.'},
                    status=409)

            report.environment = event.get_environment()
            report.group = event.group

        try:
            with transaction.atomic():
                report.save()
        except IntegrityError:
            # There was a duplicate, so just overwrite the existing
            # row with the new one. The only way this ever happens is
            # if someone is messing around with the API, or doing
            # something wrong with the SDK, but this behavior is
            # more reasonable than just hard erroring and is more
            # expected.
            existing_report = UserReport.objects.get(
                project=report.project,
                event_id=report.event_id,
            )

            # if the existing report was submitted more than 5 minutes ago, we dont
            # allow updates as it might be abusive (replay attacks)
            if existing_report.date_added < timezone.now() - timedelta(
                    minutes=5):
                return self.respond(
                    {'detail': 'Feedback for this event cannot be modified.'},
                    status=409)

            existing_report.update(
                name=report.name,
                email=report.email,
                comments=report.comments,
                date_added=timezone.now(),
                event_user_id=euser.id if euser else None,
            )
            report = existing_report

        else:
            if report.group:
                report.notify()

        user_feedback_received.send(project=report.project,
                                    group=report.group,
                                    sender=self)

        return self.respond(
            serialize(
                report, request.user,
                ProjectUserReportSerializer(
                    environment_func=self._get_environment_func(
                        request, project.organization_id))))
    def dispatch(self, request):
        try:
            event_id = request.GET['eventId']
        except KeyError:
            return self._json_response(request, status=400)

        if not is_event_id(event_id):
            return self._json_response(request, status=400)

        key = self._get_project_key(request)
        if not key:
            return self._json_response(request, status=404)

        origin = self._get_origin(request)
        if not origin:
            return self._json_response(request, status=403)

        if not is_valid_origin(origin, key.project):
            return HttpResponse(status=403)

        if request.method == 'OPTIONS':
            return self._json_response(request)

        # TODO(dcramer): since we cant use a csrf cookie we should at the very
        # least sign the request / add some kind of nonce
        initial = {
            'name': request.GET.get('name'),
            'email': request.GET.get('email'),
        }

        form = UserReportForm(
            request.POST if request.method == 'POST' else None,
            initial=initial)
        if form.is_valid():
            # TODO(dcramer): move this to post to the internal API
            report = form.save(commit=False)
            report.project = key.project
            report.event_id = event_id
            try:
                mapping = EventMapping.objects.get(
                    event_id=report.event_id,
                    project_id=key.project_id,
                )
            except EventMapping.DoesNotExist:
                # XXX(dcramer): the system should fill this in later
                pass
            else:
                report.group = Group.objects.get(id=mapping.group_id)

            try:
                with transaction.atomic():
                    report.save()
            except IntegrityError:
                # There was a duplicate, so just overwrite the existing
                # row with the new one. The only way this ever happens is
                # if someone is messing around with the API, or doing
                # something wrong with the SDK, but this behavior is
                # more reasonable than just hard erroring and is more
                # expected.
                UserReport.objects.filter(
                    project=report.project,
                    event_id=report.event_id,
                ).update(
                    name=report.name,
                    email=report.email,
                    comments=report.comments,
                    date_added=timezone.now(),
                )

            user_feedback_received.send(project=report.project,
                                        group=report.group,
                                        sender=self)

            return self._json_response(request)
        elif request.method == 'POST':
            return self._json_response(request, {
                "errors": dict(form.errors),
            },
                                       status=400)

        show_branding = ProjectOption.objects.get_value(
            project=key.project, key='feedback:branding', default='1') == '1'

        template = render_to_string('sentry/error-page-embed.html', {
            'form': form,
            'show_branding': show_branding,
        })

        context = {
            'endpoint':
            mark_safe('*/' + json.dumps(request.build_absolute_uri()) + ';/*'),
            'template':
            mark_safe('*/' + json.dumps(template) + ';/*'),
            'strings':
            json.dumps_htmlsafe({
                'generic_error': six.text_type(GENERIC_ERROR),
                'form_error': six.text_type(FORM_ERROR),
                'sent_message': six.text_type(SENT_MESSAGE),
            }),
        }

        return render_to_response('sentry/error-page-embed.js',
                                  context,
                                  request,
                                  content_type='text/javascript')
    def post(self, request, project):
        """
        Submit User Feedback
        ````````````````````

        Submit and associate user feedback with an issue.

        Feedback must be received by the server no more than 30 minutes after the event was saved.

        Additionally, within 5 minutes of submitting feedback it may also be overwritten. This is useful
        in situations where you may need to retry sending a request due to network failures.

        If feedback is rejected due to a mutability threshold, a 409 status code will be returned.

        Note: Feedback may be submitted with DSN authentication (see auth documentation).

        :pparam string organization_slug: the slug of the organization.
        :pparam string project_slug: the slug of the project.
        :auth: required
        :param string event_id: the event ID
        :param string name: user's name
        :param string email: user's email address
        :param string comments: comments supplied by user
        """
        if hasattr(request.auth, 'project_id') and project.id != request.auth.project_id:
            return self.respond(status=400)

        serializer = UserReportSerializer(data=request.DATA)
        if not serializer.is_valid():
            return self.respond(serializer.errors, status=400)

        report = serializer.object
        # XXX(dcramer): enforce case insensitivty by coercing this to a lowercase string
        report.event_id = report.event_id.lower()
        report.project = project

        # TODO(dcramer): we should probably create the user if they dont
        # exist, and ideally we'd also associate that with the event
        euser = self.find_event_user(report)
        if euser and not euser.name and report.name:
            euser.update(name=report.name)
        if euser:
            report.event_user_id = euser.id

        event = Event.objects.from_event_id(report.event_id, project.id)
        if not event:
            try:
                report.group = Group.objects.from_event_id(project, report.event_id)
            except Group.DoesNotExist:
                pass
        else:
            # if the event is more than 30 minutes old, we dont allow updates
            # as it might be abusive
            if event.datetime < timezone.now() - timedelta(minutes=30):
                return self.respond(
                    {'detail': 'Feedback for this event cannot be modified.'}, status=409)

            report.environment = event.get_environment()
            report.group = event.group

        try:
            with transaction.atomic():
                report.save()
        except IntegrityError:
            # There was a duplicate, so just overwrite the existing
            # row with the new one. The only way this ever happens is
            # if someone is messing around with the API, or doing
            # something wrong with the SDK, but this behavior is
            # more reasonable than just hard erroring and is more
            # expected.
            existing_report = UserReport.objects.get(
                project=report.project,
                event_id=report.event_id,
            )

            # if the existing report was submitted more than 5 minutes ago, we dont
            # allow updates as it might be abusive (replay attacks)
            if existing_report.date_added < timezone.now() - timedelta(minutes=5):
                return self.respond(
                    {'detail': 'Feedback for this event cannot be modified.'}, status=409)

            existing_report.update(
                name=report.name,
                email=report.email,
                comments=report.comments,
                date_added=timezone.now(),
                event_user_id=euser.id if euser else None,
            )
            report = existing_report

        else:
            if report.group:
                report.notify()

        user_feedback_received.send(project=report.project, group=report.group, sender=self)

        return self.respond(serialize(report, request.user, UserReportWithGroupSerializer(
            environment_func=self._get_environment_func(
                request, project.organization_id)
        )))
Exemple #9
0
def save_userreport(project, report, start_time=None):
    if start_time is None:
        start_time = timezone.now()

    # XXX(dcramer): enforce case insensitivity by coercing this to a lowercase string
    report["event_id"] = report["event_id"].lower()
    report["project_id"] = project.id

    event = eventstore.get_event_by_id(project.id, report["event_id"])

    # TODO(dcramer): we should probably create the user if they dont
    # exist, and ideally we'd also associate that with the event
    euser = find_event_user(report, event)

    if euser and not euser.name and report.get("name"):
        euser.update(name=report["name"])
    if euser:
        report["event_user_id"] = euser.id

    if event:
        # if the event is more than 30 minutes old, we dont allow updates
        # as it might be abusive
        if event.datetime < start_time - timedelta(minutes=30):
            raise Conflict("Feedback for this event cannot be modified.")

        report["environment_id"] = event.get_environment().id
        report["group_id"] = event.group_id

    try:
        with transaction.atomic():
            report_instance = UserReport.objects.create(**report)

    except IntegrityError:
        # There was a duplicate, so just overwrite the existing
        # row with the new one. The only way this ever happens is
        # if someone is messing around with the API, or doing
        # something wrong with the SDK, but this behavior is
        # more reasonable than just hard erroring and is more
        # expected.

        existing_report = UserReport.objects.get(
            project_id=report["project_id"], event_id=report["event_id"])

        # if the existing report was submitted more than 5 minutes ago, we dont
        # allow updates as it might be abusive (replay attacks)
        if existing_report.date_added < timezone.now() - timedelta(minutes=5):
            raise Conflict("Feedback for this event cannot be modified.")

        existing_report.update(
            name=report.get("name", ""),
            email=report["email"],
            comments=report["comments"],
            date_added=timezone.now(),
            event_user_id=euser.id if euser else None,
        )
        report_instance = existing_report

    else:
        if report_instance.group_id:
            report_instance.notify()

    user_feedback_received.send(project=project, sender=save_userreport)

    return report_instance
Exemple #10
0
    def post(self, request, project):
        """
        Submit User Feedback
        ````````````````````

        Submit and associate user feedback with an issue.

        Feedback must be received by the server no more than 30 minutes after the event was saved.

        Additionally, within 5 minutes of submitting feedback it may also be overwritten. This is useful
        in situations where you may need to retry sending a request due to network failures.

        If feedback is rejected due to a mutability threshold, a 409 status code will be returned.

        Note: Feedback may be submitted with DSN authentication (see auth documentation).

        :pparam string organization_slug: the slug of the organization.
        :pparam string project_slug: the slug of the project.
        :auth: required
        :param string event_id: the event ID
        :param string name: user's name
        :param string email: user's email address
        :param string comments: comments supplied by user
        """
        if hasattr(request.auth,
                   'project_id') and project.id != request.auth.project_id:
            return self.respond(status=400)

        serializer = UserReportSerializer(data=request.data)
        if not serializer.is_valid():
            return self.respond(serializer.errors, status=400)

        report = serializer.validated_data

        # XXX(dcramer): enforce case insensitivty by coercing this to a lowercase string
        report['event_id'] = report['event_id'].lower()
        report['project'] = project

        event = eventstore.get_event_by_id(project.id, report['event_id'])

        # TODO(dcramer): we should probably create the user if they dont
        # exist, and ideally we'd also associate that with the event
        euser = self.find_event_user(report, event)
        if euser and not euser.name and report['name']:
            euser.update(name=report['name'])
        if euser:
            report['event_user_id'] = euser.id

        if event:
            # if the event is more than 30 minutes old, we dont allow updates
            # as it might be abusive
            if event.datetime < timezone.now() - timedelta(minutes=30):
                return self.respond(
                    {'detail': 'Feedback for this event cannot be modified.'},
                    status=409)

            report['environment'] = event.get_environment()
            report['group'] = event.group

        try:
            with transaction.atomic():
                report_instance = UserReport.objects.create(**report)
        except IntegrityError:
            # There was a duplicate, so just overwrite the existing
            # row with the new one. The only way this ever happens is
            # if someone is messing around with the API, or doing
            # something wrong with the SDK, but this behavior is
            # more reasonable than just hard erroring and is more
            # expected.
            existing_report = UserReport.objects.get(
                project=report['project'],
                event_id=report['event_id'],
            )

            # if the existing report was submitted more than 5 minutes ago, we dont
            # allow updates as it might be abusive (replay attacks)
            if existing_report.date_added < timezone.now() - timedelta(
                    minutes=5):
                return self.respond(
                    {'detail': 'Feedback for this event cannot be modified.'},
                    status=409)

            existing_report.update(
                name=report['name'],
                email=report['email'],
                comments=report['comments'],
                date_added=timezone.now(),
                event_user_id=euser.id if euser else None,
            )
            report_instance = existing_report

        else:
            if report_instance.group:
                report_instance.notify()

        user_feedback_received.send(project=report_instance.project,
                                    group=report_instance.group,
                                    sender=self)

        return self.respond(
            serialize(
                report_instance, request.user,
                UserReportWithGroupSerializer(
                    environment_func=self._get_environment_func(
                        request, project.organization_id))))
    def post(self, request, project):
        """
        Submit User Feedback
        ````````````````````

        Submit and associate user feedback with an issue.

        :pparam string organization_slug: the slug of the organization.
        :pparam string project_slug: the slug of the project.
        :auth: required
        :param string event_id: the event ID
        :param string name: user's name
        :param string email: user's email address
        :param string comments: comments supplied by user
        """
        serializer = UserReportSerializer(data=request.DATA)
        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        report = serializer.object
        report.project = project

        # TODO(dcramer): we should probably create the user if they dont
        # exist, and ideally we'd also associate that with the event
        euser = self.find_event_user(report)
        if euser and not euser.name and report.name:
            euser.update(name=report.name)
        if euser:
            report.event_user_id = euser.id

        try:
            event = Event.objects.filter(project_id=project.id,
                                         event_id=report.event_id)[0]
        except IndexError:
            try:
                report.group = Group.objects.from_event_id(project, report.event_id)
            except Group.DoesNotExist:
                pass
        else:
            report.environment = event.get_environment()
            report.group = event.group

        try:
            with transaction.atomic():
                report.save()
        except IntegrityError:
            # There was a duplicate, so just overwrite the existing
            # row with the new one. The only way this ever happens is
            # if someone is messing around with the API, or doing
            # something wrong with the SDK, but this behavior is
            # more reasonable than just hard erroring and is more
            # expected.
            existing_report = UserReport.objects.get(
                project=report.project,
                event_id=report.event_id,
            )

            existing_report.update(
                name=report.name,
                email=report.email,
                comments=report.comments,
                date_added=timezone.now(),
                event_user_id=euser.id if euser else None,
            )
            report = existing_report

        else:
            if report.group:
                report.notify()

        user_feedback_received.send(project=report.project, group=report.group, sender=self)

        return Response(serialize(report, request.user, ProjectUserReportSerializer(
            environment_func=self._get_environment_func(
                request, project.organization_id)
        )))
Exemple #12
0
    def dispatch(self, request):
        try:
            event_id = request.GET['eventId']
        except KeyError:
            return self._smart_response(
                request, {'eventId': 'Missing or invalid parameter.'}, status=400)

        if event_id and not is_event_id(event_id):
            return self._smart_response(
                request, {'eventId': 'Missing or invalid parameter.'}, status=400)

        key = self._get_project_key(request)
        if not key:
            return self._smart_response(
                request, {'dsn': 'Missing or invalid parameter.'}, status=404)

        origin = self._get_origin(request)
        if not is_valid_origin(origin, key.project):
            return self._smart_response(request, status=403)

        if request.method == 'OPTIONS':
            return self._smart_response(request)

        # customization options
        options = DEFAULT_OPTIONS.copy()
        for name in six.iterkeys(options):
            if name in request.GET:
                options[name] = six.text_type(request.GET[name])

        # TODO(dcramer): since we cant use a csrf cookie we should at the very
        # least sign the request / add some kind of nonce
        initial = {
            'name': request.GET.get('name'),
            'email': request.GET.get('email'),
        }

        form = UserReportForm(request.POST if request.method == 'POST' else None, initial=initial)
        if form.is_valid():
            # TODO(dcramer): move this to post to the internal API
            report = form.save(commit=False)
            report.project = key.project
            report.event_id = event_id

            try:
                event = Event.objects.filter(project_id=report.project.id,
                                             event_id=report.event_id)[0]
            except IndexError:
                try:
                    report.group = Group.objects.from_event_id(report.project, report.event_id)
                except Group.DoesNotExist:
                    pass
            else:
                report.environment = event.get_environment()
                report.group = event.group

            try:
                with transaction.atomic():
                    report.save()
            except IntegrityError:
                # There was a duplicate, so just overwrite the existing
                # row with the new one. The only way this ever happens is
                # if someone is messing around with the API, or doing
                # something wrong with the SDK, but this behavior is
                # more reasonable than just hard erroring and is more
                # expected.
                UserReport.objects.filter(
                    project=report.project,
                    event_id=report.event_id,
                ).update(
                    name=report.name,
                    email=report.email,
                    comments=report.comments,
                    date_added=timezone.now(),
                )

            else:
                if report.group:
                    report.notify()

            user_feedback_received.send(project=report.project, group=report.group, sender=self)

            return self._smart_response(request)
        elif request.method == 'POST':
            return self._smart_response(
                request, {
                    "errors": dict(form.errors),
                }, status=400
            )

        show_branding = ProjectOption.objects.get_value(
            project=key.project, key='feedback:branding', default='1'
        ) == '1'

        template = render_to_string(
            'sentry/error-page-embed.html', {
                'form': form,
                'show_branding': show_branding,
                'title': options['title'],
                'subtitle': options['subtitle'],
                'subtitle2': options['subtitle2'],
                'name_label': options['labelName'],
                'email_label': options['labelEmail'],
                'comments_label': options['labelComments'],
                'submit_label': options['labelSubmit'],
                'close_label': options['labelClose'],
            }
        )

        context = {
            'endpoint': mark_safe('*/' + json.dumps(request.build_absolute_uri()) + ';/*'),
            'template': mark_safe('*/' + json.dumps(template) + ';/*'),
            'strings': json.dumps_htmlsafe({
                'generic_error': six.text_type(options['errorGeneric']),
                'form_error': six.text_type(options['errorFormEntry']),
                'sent_message': six.text_type(options['successMessage']),
            }),
        }

        return render_to_response(
            'sentry/error-page-embed.js', context, request, content_type='text/javascript'
        )
    def dispatch(self, request):
        try:
            event_id = request.GET['eventId']
        except KeyError:
            return self._json_response(request, status=400)

        if not is_event_id(event_id):
            return self._json_response(request, status=400)

        key = self._get_project_key(request)
        if not key:
            return self._json_response(request, status=404)

        origin = self._get_origin(request)
        if not origin:
            return self._json_response(request, status=403)

        if not is_valid_origin(origin, key.project):
            return HttpResponse(status=403)

        if request.method == 'OPTIONS':
            return self._json_response(request)

        # TODO(dcramer): since we cant use a csrf cookie we should at the very
        # least sign the request / add some kind of nonce
        initial = {
            'name': request.GET.get('name'),
            'email': request.GET.get('email'),
        }

        form = UserReportForm(request.POST if request.method == 'POST' else None,
                              initial=initial)
        if form.is_valid():
            # TODO(dcramer): move this to post to the internal API
            report = form.save(commit=False)
            report.project = key.project
            report.event_id = event_id
            try:
                mapping = EventMapping.objects.get(
                    event_id=report.event_id,
                    project_id=key.project_id,
                )
            except EventMapping.DoesNotExist:
                # XXX(dcramer): the system should fill this in later
                pass
            else:
                report.group = Group.objects.get(id=mapping.group_id)

            try:
                with transaction.atomic():
                    report.save()
            except IntegrityError:
                # There was a duplicate, so just overwrite the existing
                # row with the new one. The only way this ever happens is
                # if someone is messing around with the API, or doing
                # something wrong with the SDK, but this behavior is
                # more reasonable than just hard erroring and is more
                # expected.
                UserReport.objects.filter(
                    project=report.project,
                    event_id=report.event_id,
                ).update(
                    name=report.name,
                    email=report.email,
                    comments=report.comments,
                    date_added=timezone.now(),
                )

            user_feedback_received.send(project=report.project, group=report.group, sender=self)

            return self._json_response(request)
        elif request.method == 'POST':
            return self._json_response(request, {
                "errors": dict(form.errors),
            }, status=400)

        show_branding = ProjectOption.objects.get_value(
            project=key.project,
            key='feedback:branding',
            default='1'
        ) == '1'

        template = render_to_string('sentry/error-page-embed.html', {
            'form': form,
            'show_branding': show_branding,
        })

        context = {
            'endpoint': mark_safe('*/' + json.dumps(request.build_absolute_uri()) + ';/*'),
            'template': mark_safe('*/' + json.dumps(template) + ';/*'),
            'strings': json.dumps_htmlsafe({
                'generic_error': six.text_type(GENERIC_ERROR),
                'form_error': six.text_type(FORM_ERROR),
                'sent_message': six.text_type(SENT_MESSAGE),
            }),
        }

        return render_to_response('sentry/error-page-embed.js', context, request,
                                  content_type='text/javascript')