def build(self, to): if self.headers is None: headers = {} else: headers = self.headers.copy() if ENABLE_EMAIL_REPLIES and "X-Sentry-Reply-To" in headers: reply_to = headers["X-Sentry-Reply-To"] else: reply_to = ", ".join(to) headers.setdefault("Reply-To", reply_to) if self.template: txt_body = render_to_string(self.template, self.context) else: txt_body = self.body if self.html_template: html_body = render_to_string(self.html_template, self.context) else: html_body = self.html_body msg = EmailMultiAlternatives(self.subject, txt_body, settings.SERVER_EMAIL, to, headers=headers) if html_body: msg.attach_alternative(UnicodeSafePynliner().from_string(html_body).run(), "text/html") return msg
def build(self, to): if self.headers is None: headers = {} else: headers = self.headers.copy() headers.setdefault('Reply-To', ', '.join(to)) if self.template: txt_body = render_to_string(self.template, self.context) else: txt_body = self.body if self.html_template: html_body = render_to_string(self.html_template, self.context) else: html_body = self.html_body msg = EmailMultiAlternatives( self.subject, txt_body, settings.SERVER_EMAIL, to, headers=headers ) if html_body: msg.attach_alternative( UnicodeSafePynliner().from_string(html_body).run(), "text/html") return msg
def to_html(self, event, **kwargs): if not self.values: return '' if len(self.values) == 1 and not self.values[0].stacktrace: exception = self.values[0] context = exception.get_context(event=event, **kwargs) return render_to_string('sentry/partial/interfaces/exception.html', context) context = self.get_context(event=event, **kwargs) return render_to_string('sentry/partial/interfaces/chained_exception.html', context)
def to_html(self, event): frames = [] for frame in self.frames: if 'context_line' in frame: context = get_context(frame['lineno'], frame['context_line'], frame.get('pre_context'), frame.get('post_context')) start_lineno = context[0][0] else: context = [] start_lineno = None context_vars = [] if 'vars' in frame: context_vars = self._shorten(frame['vars']) else: context_vars = [] frames.append({ 'abs_path': frame.get('abs_path'), 'filename': frame['filename'], 'function': frame.get('function'), 'start_lineno': start_lineno, 'lineno': frame.get('lineno'), 'context': context, 'vars': context_vars, }) return render_to_string('sentry/partial/interfaces/stacktrace.html', { 'event': event, 'frames': frames, 'stacktrace': self.get_traceback(event), })
def to_html(self, event): return render_to_string('sentry/partial/interfaces/exception.html', { 'event': event, 'exception_value': self.value, 'exception_type': self.type, 'exception_module': self.module, })
def to_html(self, event): data = self.data data_is_dict = False if self.headers.get('Content-Type') == 'application/x-www-form-urlencoded': try: data = QueryDict(data) except: pass else: data_is_dict = True # It's kind of silly we store this twice cookies = self.cookies or self.headers.pop('Cookie', {}) cookies_is_dict = isinstance(cookies, dict) if not cookies_is_dict: try: cookies = QueryDict(cookies) except: pass else: cookies_is_dict = True return render_to_string('sentry/partial/interfaces/http.html', { 'event': event, 'full_url': '?'.join(filter(None, [self.url, self.query_string])), 'url': self.url, 'method': self.method, 'data': data, 'data_is_dict': data_is_dict, 'query_string': self.query_string, 'cookies': cookies, 'cookies_is_dict': cookies_is_dict, 'headers': self.headers, 'env': self.env, })
def to_html(self, event, is_public=False, **kwargs): data = self.data headers_is_dict, headers = self._to_dict(self.headers) # educated guess as to whether the body is normal POST data if headers_is_dict and headers.get("Content-Type") == "application/x-www-form-urlencoded" and "=" in data: _, data = self._to_dict(data) context = { "is_public": is_public, "event": event, "full_url": "?".join(filter(bool, [self.url, self.query_string])), "url": self.url, "method": self.method, "data": data, "query_string": self.query_string, "headers": self.headers, } if not is_public: # It's kind of silly we store this twice _, cookies = self._to_dict(self.cookies) context.update({"cookies": cookies, "env": self.env}) return render_to_string("sentry/partial/interfaces/http.html", context)
def to_html(self, event, is_public=False, **kwargs): if not self.frames: return "" system_frames = 0 frames = [] for frame in self.frames: frames.append(frame.get_context(event=event, is_public=is_public)) if not frame.in_app: system_frames += 1 if len(frames) == system_frames: system_frames = 0 newest_first = self.is_newest_frame_first(event) if newest_first: frames = frames[::-1] return render_to_string( "sentry/partial/interfaces/stacktrace.html", { "is_public": is_public, "newest_first": newest_first, "system_frames": system_frames, "event": event, "frames": frames, "stacktrace": self.get_traceback(event, newest_first=newest_first), }, )
def to_html(self, event): data = self.data data_is_dict = False headers_is_dict, headers = self._to_dict(self.headers) if headers_is_dict and headers.get("Content-Type") == "application/x-www-form-urlencoded": data_is_dict, data = self._to_dict(data) # It's kind of silly we store this twice cookies_is_dict, cookies = self._to_dict(self.cookies or headers.pop("Cookie", {})) return render_to_string( "sentry/partial/interfaces/http.html", { "event": event, "full_url": "?".join(filter(bool, [self.url, self.query_string])), "url": self.url, "method": self.method, "data": data, "data_is_dict": data_is_dict, "query_string": self.query_string, "cookies": cookies, "cookies_is_dict": cookies_is_dict, "headers": self.headers, "headers_is_dict": headers_is_dict, "env": self.env, }, )
def notify_users(self, group, event, fail_silently=False): project = event.project interface_list = [] for interface in event.interfaces.itervalues(): body = interface.to_string(event) if not body: # Skip continue interface_list.append((interface.get_title(), mark_safe(body))) title = ('[%s] %s' % ( project.name.encode(API_CHARSET), unicode(group.get_level_display().upper().encode(API_CHARSET)))) link = group.get_absolute_url() message = render_to_string(message_template, ({ 'group': group, 'event': event, 'tags': event.get_tags(), 'link': link, 'interfaces': interface_list })) if len(message) > self.BASE_MAXIMUM_MESSAGE_LENGTH: message = message[:self.BASE_MAXIMUM_MESSAGE_LENGTH - 4] + ' ...' message = message.encode(API_CHARSET) else: message = message.encode(API_CHARSET) self.send_notification(title, message, link, project)
def resolve(request, project): gid = request.REQUEST.get("gid") if not gid: return HttpResponseForbidden() try: group = Group.objects.get(pk=gid) except Group.DoesNotExist: return HttpResponseForbidden() Group.objects.filter(pk=group.pk).update(status=1) group.status = 1 data = [ ( m.pk, { "html": render_to_string("sentry/partial/_group.html", {"group": m, "request": request}).strip(), "count": m.times_seen, }, ) for m in [group] ] response = HttpResponse(json.dumps(data)) response["Content-Type"] = "application/json" return response
def html_body(self): try: return inline_css(render_to_string(self.email.get_html_template(), self.get_context())) except Exception: import traceback traceback.print_exc() raise
def to_html(self, event): frames = [] for frame in self.frames: if frame.get("context_line"): context = get_context( frame["lineno"], frame["context_line"], frame.get("pre_context"), frame.get("post_context") ) start_lineno = context[0][0] else: context = [] start_lineno = None context_vars = [] if frame.get("vars"): context_vars = self._shorten(frame["vars"]) else: context_vars = [] frames.append( { "abs_path": frame.get("abs_path"), "filename": frame["filename"], "function": frame.get("function"), "start_lineno": start_lineno, "lineno": frame.get("lineno"), "context": context, "vars": context_vars, } ) return render_to_string( "sentry/partial/interfaces/stacktrace.html", {"event": event, "frames": frames, "stacktrace": self.get_traceback(event)}, )
def send_recover_mail(self): from django.core.mail import send_mail from sentry.web.helpers import render_to_string context = { 'user': self.user, 'domain': urlparse.urlparse(settings.SENTRY_URL_PREFIX).hostname, 'url': absolute_uri( reverse( 'sentry-account-recover-confirm', args=[self.user.id, self.hash])), } body = render_to_string('sentry/emails/recover_account.txt', context) try: send_mail( '%sPassword Recovery' % (settings.EMAIL_SUBJECT_PREFIX, ), body, settings.SERVER_EMAIL, [self.user.email], fail_silently=False) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def post_process(self, group, event, is_new, is_sample, **kwargs): if not is_new: return project = group.project token = self.get_option('token', project) subject = '[%s] %s: %s' % ( project.name.encode('utf-8'), unicode(event.get_level_display()).upper().encode('utf-8'), event.error().encode('utf-8').splitlines()[0]) interface_list = [] for interface in event.interfaces.itervalues(): body = interface.to_email_html(event) if not body: continue interface_list.append((interface.get_title(), mark_safe(body))) message = render_to_string('sentry_flowdock/event.html', { 'group': group, 'event': event, 'link': 'http://example.com/link', 'interfaces': interface_list, 'tags': event.get_tags(), }) self.send_payload( token=token, subject=subject, message=message, link=group.get_absolute_url(), )
def send_invite_email(self): from django.core.mail import send_mail from sentry.web.helpers import render_to_string context = { 'email': self.email, 'team': self.team, 'url': absolute_uri( reverse( 'sentry-accept-invite', kwargs={ 'member_id': self.id, 'token': self.token, })), } body = render_to_string('sentry/emails/member_invite.txt', context) try: send_mail( '%sInvite to join team: %s' % (settings.EMAIL_SUBJECT_PREFIX, self.team.name), body, settings.SERVER_EMAIL, [self.email], fail_silently=False) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def client_guide(request, project, platform): if platform not in PLATFORM_LIST: return HttpResponseRedirect(reverse('sentry')) key = ProjectKey.objects.get(user=request.user, project=project) dsn = key.get_dsn() dsn_public = key.get_dsn(public=True) template = 'sentry/partial/client_config/%s.html' % (platform,) context = { 'platform': platform, 'platform_title': platform.title(), 'project': project, 'dsn': dsn, 'dsn_public': dsn_public, 'page': 'client_help' } if request.is_ajax(): return render_to_response(template, context, request) context['template'] = render_to_string(template, context, request) return render_to_response('sentry/projects/docs/client_config.html', context, request)
def to_html(self, event, is_public=False, **kwargs): data = self.data headers_is_dict, headers = self._to_dict(self.headers) # educated guess as to whether the body is normal POST data if headers_is_dict and headers.get('Content-Type') == 'application/x-www-form-urlencoded' and '=' in data: _, data = self._to_dict(data) context = { 'is_public': is_public, 'event': event, 'url': self.url, 'short_url': self.short_url, 'method': self.method, 'query_string': self.query_string, 'fragment': self.fragment, 'headers': self.headers, } if not is_public: # It's kind of silly we store this twice _, cookies = self._to_dict(self.cookies) context.update({ 'cookies': cookies, 'env': self.env, 'data': data, }) return render_to_string('sentry/partial/interfaces/http.html', context)
def to_html(self, event, is_public=False, **kwargs): if not self.frames: return '' system_frames = 0 frames = [] for frame in self.frames: frames.append(frame.get_context(event=event, is_public=is_public)) if not frame.in_app: system_frames += 1 if len(frames) == system_frames: system_frames = 0 newest_first = self.is_newest_frame_first(event) if newest_first: frames = frames[::-1] return render_to_string('sentry/partial/interfaces/stacktrace.html', { 'is_public': is_public, 'newest_first': newest_first, 'system_frames': system_frames, 'event': event, 'frames': frames, 'stacktrace': self.get_traceback(event, newest_first=newest_first), })
def to_html(self, event, is_public=False, **kwargs): data = self.data data_is_dict = False headers_is_dict, headers = self._to_dict(self.headers) if headers_is_dict and headers.get('Content-Type') == 'application/x-www-form-urlencoded': data_is_dict, data = self._to_dict(data) cookies = self.cookies or headers.pop('Cookie', {}) context = { 'is_public': is_public, 'event': event, 'full_url': '?'.join(filter(bool, [self.url, self.query_string])), 'url': self.url, 'method': self.method, 'data': data, 'data_is_dict': data_is_dict, 'query_string': self.query_string, 'headers': self.headers, 'headers_is_dict': headers_is_dict, } if not is_public: # It's kind of silly we store this twice cookies_is_dict, cookies = self._to_dict(cookies) context.update({ 'cookies': cookies, 'cookies_is_dict': cookies_is_dict, 'env': self.env, }) return render_to_string('sentry/partial/interfaces/http.html', context)
def resolve(request, project): gid = request.REQUEST.get('gid') if not gid: return HttpResponseForbidden() try: group = Group.objects.get(pk=gid) except Group.DoesNotExist: return HttpResponseForbidden() if group.project and group.project.pk not in get_project_list(request.user): return HttpResponseForbidden() Group.objects.filter(pk=group.pk).update(status=1) group.status = 1 data = [ (m.pk, { 'html': render_to_string('sentry/partial/_group.html', { 'group': m, 'request': request, }).strip(), 'count': m.times_seen, }) for m in [group]] response = HttpResponse(json.dumps(data)) response['Content-Type'] = 'application/json' return response
def to_string(self, event, is_public = False, **kwargs): return render_to_string('sentry_uploads/uploads.txt', { 'files': [{ 'filename': file['filename'], 'deleted': file.get('deleted', False), 'size': file['size'], } for file in self.files], })
def to_html(self, event): return render_to_string('sentry/partial/interfaces/user.html', { 'event': event, 'user_id': self.id, 'user_username': self.username, 'user_email': self.email, 'user_data': self.data, })
def to_email_html(self, event, **kwargs): return render_to_string('sentry/partial/interfaces/http_email.html', { 'event': event, 'url': self.full_url, 'short_url': self.url, 'method': self.method, 'query_string': self.query_string, })
def to_html(self, event): return render_to_string('sentry/partial/interfaces/user.html', { 'event': event, 'user_authenticated': self.is_authenticated, 'user_id': self.id, 'user_username': self.username, 'user_email': self.email })
def to_string(self, event, is_public=False, **kwargs): return render_to_string('sentry_cfml/partial/interfaces/cfmlhttp.txt', { 'event': event, 'full_url': '?'.join(filter(bool, [self.url_path, self.query_string])), 'url_path': self.url_path, 'method': self.method, 'query_string': self.query_string, })
def to_string(self, event): return render_to_string('sentry/partial/interfaces/http.txt', { 'event': event, 'full_url': '?'.join(filter(bool, [self.url, self.query_string])), 'url': self.url, 'method': self.method, 'query_string': self.query_string, })
def to_email_html(self, event, **kwargs): return render_to_string('sentry/partial/interfaces/http_email.html', { 'event': event, 'full_url': '?'.join(filter(bool, [self.url, self.query_string])), 'url': self.url, 'method': self.method, 'query_string': self.query_string, })
def to_email_html(self, event, **kwargs): context = { "user_id": self.id, "user_email": self.email, "user_username": self.username, "user_ip_address": self.ip_address, "user_data": self.data, } return render_to_string("sentry/partial/interfaces/user_email.html", context)
def render(self, request, context=None): from sentry.web.helpers import render_to_string if not context: context = {} if self.context: context.update(self.context) return render_to_string(self.template, context, request)
def html_body(self): return render_to_string(self.html_template, self.context)
def to_html(self, event): if not self.frames: return '' system_frames = 0 frames = [] for frame in self.frames: if frame.get('context_line') and frame.get('lineno') is not None: context = get_context( lineno=frame['lineno'], context_line=frame['context_line'], pre_context=frame.get('pre_context'), post_context=frame.get('post_context'), filename=frame.get('abs_path', frame.get('filename')), format=True, ) start_lineno = context[0][0] else: context = [] start_lineno = None context_vars = [] if frame.get('vars'): context_vars = frame['vars'] else: context_vars = [] if frame.get('lineno') is not None: lineno = int(frame['lineno']) else: lineno = None in_app = bool(frame.get('in_app', True)) frame_data = { 'abs_path': frame.get('abs_path'), 'filename': frame['filename'], 'function': frame.get('function'), 'start_lineno': start_lineno, 'lineno': lineno, 'context': context, 'vars': context_vars, 'in_app': in_app, } if event.platform == 'javascript' and frame.get('data'): data = frame['data'] frame_data.update({ 'sourcemap': data['sourcemap'].rsplit('/', 1)[-1], 'orig_filename': data['orig_filename'], 'orig_lineno': data['orig_lineno'], 'orig_colno': data['orig_colno'], }) frames.append(frame_data) if not in_app: system_frames += 1 if len(frames) == system_frames: system_frames = 0 newest_first = self.is_newest_frame_first(event) if newest_first: frames = frames[::-1] return render_to_string( 'sentry/partial/interfaces/stacktrace.html', { 'newest_first': newest_first, 'system_frames': system_frames, 'event': event, 'frames': frames, 'stacktrace': self.get_traceback(event, newest_first=newest_first), })
def text_body(self): return render_to_string(self.text_template, self.context)
def html_body(self): return inline_css(render_to_string(self.html_template, self.context))
def txt_body(self): if self.template: return render_to_string(self.template, self.context) return self._txt_body
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 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_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": 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 html_body(self): try: return inline_css(render_to_string(self.html_template, self.context)) except Exception: traceback.print_exc() raise
def default_plugin_config(plugin, project, request): if plugin.can_enable_for_projects( ) and not plugin.can_configure_for_project(project): raise Http404() plugin_key = plugin.get_conf_key() form_class = plugin.get_conf_form(project) template = plugin.get_conf_template(project) if form_class is None: return HttpResponseRedirect( reverse("sentry-manage-project", args=[project.organization.slug, project.slug])) test_results = None form = form_class( request.POST if request.POST.get("plugin") == plugin.slug else None, initial=plugin.get_conf_options(project), prefix=plugin_key, ) if form.is_valid(): if "action_test" in request.POST and plugin.is_testable(): try: test_results = plugin.test_configuration(project) except Exception as exc: if isinstance(exc, HTTPError): test_results = "%s\n%s" % (exc, exc.response.text[:256]) elif hasattr(exc, "read") and callable(exc.read): test_results = "%s\n%s" % (exc, exc.read()[:256]) else: logging.exception("Plugin(%s) raised an error during test", plugin_key) test_results = "There was an internal error with the Plugin" if not test_results: test_results = "No errors returned" else: for field, value in six.iteritems(form.cleaned_data): key = "%s:%s" % (plugin_key, field) if project: ProjectOption.objects.set_value(project, key, value) else: options.set(key, value) messages.add_message(request, messages.SUCCESS, _("Your settings were saved successfully.")) return HttpResponseRedirect(request.path) # TODO(mattrobenolt): Reliably determine if a plugin is configured # if hasattr(plugin, 'is_configured'): # is_configured = plugin.is_configured(project) # else: # is_configured = True is_configured = True return mark_safe( render_to_string( template=template, context={ "form": form, "plugin": plugin, "plugin_description": plugin.get_description() or "", "plugin_test_results": test_results, "plugin_is_configured": is_configured, }, request=request, ))
def to_html(self, event, **kwargs): context = self.get_context(event=event, **kwargs) return render_to_string('sentry/partial/interfaces/stacktrace.html', context)
def to_email_html(self, event, **kwargs): context = self.get_context() return render_to_string('sentry/partial/interfaces/user_email.html', context)
def to_email_html(self, event, **kwargs): return render_to_string( 'sentry/partial/interfaces/csp_email.html', {'data': self.get_api_context()} )
def text_body(self): return render_to_string(self.email.get_template(), self.get_context())
def __render_text_body(self) -> str: if self.template: body: str = render_to_string(self.template, self.context) return body return self._txt_body