def after(self, event, state): mail_plugin = plugins.get('mail') if not mail_plugin.is_enabled(event.project): return username = self.get_option('username') try: user = User.objects.get(username=username) except: return project = event.project group = event.group subject_prefix = mail_plugin.get_option('subject_prefix', project) or settings.EMAIL_SUBJECT_PREFIX 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))) subject = group.get_email_subject() link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' context = { 'group': group, 'event': event, 'tags': event.get_tags(), 'link': link, 'interfaces': interface_list, 'rule': None, 'rule_link': None, } headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Project': project.name, 'X-Sentry-Reply-To': group_id_to_email(group.id), } msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, reference=group, ) msg.add_users([user.id], project=project) return msg.send()
def notify(self, notification): event = notification.event group = event.group project = group.project org = group.organization subject = group.get_email_subject() link = group.get_absolute_url() template = "sentry/emails/error.txt" html_template = "sentry/emails/error.html" rules = [] for rule in notification.rules: rule_link = reverse("sentry-edit-project-rule", args=[org.slug, project.slug, rule.id]) rules.append((rule.label, rule_link)) enhanced_privacy = org.flags.enhanced_privacy context = { "project_label": project.get_full_name(), "group": group, "event": event, "link": link, "rules": rules, "enhanced_privacy": enhanced_privacy, } # if the organization has enabled enhanced privacy controls we dont send # data which may show PII or source code if not enhanced_privacy: interface_list = [] for interface in event.interfaces.itervalues(): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append((interface.get_title(), mark_safe(body), text_body)) context.update({"tags": event.get_tags(), "interfaces": interface_list}) headers = { "X-Sentry-Logger": group.logger, "X-Sentry-Logger-Level": group.get_level_display(), "X-Sentry-Team": project.team.name, "X-Sentry-Project": project.name, "X-Sentry-Reply-To": group_id_to_email(group.id), } self._send_mail( subject=subject, template=template, html_template=html_template, project=project, reference=group, headers=headers, context=context, )
def notify(self, notification): event = notification.event group = event.group project = group.project interface_list = [] for interface in event.interfaces.itervalues(): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append( (interface.get_title(), mark_safe(body), text_body) ) subject = group.get_email_subject() link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' rules = [] for rule in notification.rules: rule_link = reverse('sentry-edit-project-rule', args=[ group.organization.slug, project.slug, rule.id ]) rules.append((rule.label, rule_link)) context = { 'project_label': project.get_full_name(), 'group': group, 'event': event, 'tags': event.get_tags(), 'link': link, 'interfaces': interface_list, 'rules': rules, } headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Team': project.team.name, 'X-Sentry-Project': project.name, 'X-Sentry-Reply-To': group_id_to_email(group.id), } self._send_mail( subject=subject, template=template, html_template=html_template, project=project, group=group, headers=headers, context=context, )
def notify_users(self, group, event, fail_silently=False): project = group.project 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))) 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]) url_prefix = settings.URL_PREFIX parsed = urlparse.urlparse(url_prefix) url_prefix = "%s://%s" % (parsed.scheme, parsed.netloc) link = '%s%s' % (url_prefix, reverse('sentry-group', args=[group.team.slug, group.project.slug, group.id])) template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' context = { 'group': group, 'event': event, 'link': link, 'interfaces': interface_list, 'settings_link': self.get_notification_settings_url(), } headers = { 'X-Sentry-Logger': event.logger, 'X-Sentry-Logger-Level': event.get_level_display(), 'X-Sentry-Project': project.name, 'X-Sentry-Server': event.server_name, 'X-Sentry-Reply-To': group_id_to_email(group.pk), } self._send_mail( subject=subject, template=template, html_template=html_template, project=project, fail_silently=fail_silently, headers=headers, context=context, )
def get_headers(self): project = self.project group = self.group headers = {"X-Sentry-Project": project.slug} if group: headers.update({ "X-Sentry-Logger": group.logger, "X-Sentry-Logger-Level": group.get_level_display(), "X-Sentry-Reply-To": group_id_to_email(group.id), "category": self.get_category(), }) return headers
def get_headers(notification: BaseNotification) -> Mapping[str, Any]: headers = { "X-Sentry-Project": notification.project.slug, "X-SMTPAPI": json.dumps({"category": notification.get_category()}), } group = getattr(notification, "group", None) if group: headers.update({ "X-Sentry-Logger": group.logger, "X-Sentry-Logger-Level": group.get_level_display(), "X-Sentry-Reply-To": group_id_to_email(group.id), }) return headers
def send_notification(self): from sentry.utils.email import MessageBuilder, group_id_to_email if not self.group_id: return if self.type not in (Activity.NOTE, Activity.ASSIGNED): return send_to = self.get_recipients() if not send_to: return author = self.user.first_name or self.user.username subject_prefix = self.project.get_option('subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' subject = '%s%s' % (subject_prefix, self.group.get_email_subject()) context = { 'data': self.data, 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.id), } template_name = self.get_type_display() msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format( template_name), headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) msg.send_async()
def get_headers(self): project = self.project group = self.group headers = { 'X-Sentry-Project': project.slug, } if group: headers.update({ 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Reply-To': group_id_to_email(group.id), }) return headers
def send_notification(self): from sentry.utils.email import MessageBuilder, group_id_to_email if not self.group_id: return if self.type not in (Activity.NOTE, Activity.ASSIGNED): return send_to = self.get_recipients() if not send_to: return author = self.user.first_name or self.user.username subject_prefix = self.project.get_option( 'subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' subject = '%s%s' % (subject_prefix, self.group.get_email_subject()) context = { 'data': self.data, 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.id), } template_name = self.get_type_display() msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format(template_name), headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) msg.send_async()
def get_headers(self): project = self.project group = self.group headers = { 'X-Sentry-Team': project.team.slug, 'X-Sentry-Project': project.slug, } if group: headers.update({ 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Reply-To': group_id_to_email(group.id), }) return headers
def get_headers(self) -> Mapping[str, Any]: project = self.project group = self.group headers = { "X-Sentry-Project": project.slug, "X-SMTPAPI": json.dumps({"category": self.get_category()}), } if group: headers.update({ "X-Sentry-Logger": group.logger, "X-Sentry-Logger-Level": group.get_level_display(), "X-Sentry-Reply-To": group_id_to_email(group.id), }) return headers
def notify_users(self, group, event, fail_silently=False): project = group.project 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))) 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]) link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' context = { 'group': group, 'event': event, 'tags': event.get_tags(), 'link': link, 'interfaces': interface_list, } headers = { 'X-Sentry-Logger': event.logger, 'X-Sentry-Logger-Level': event.get_level_display(), 'X-Sentry-Project': project.name, 'X-Sentry-Server': event.server_name, 'X-Sentry-Reply-To': group_id_to_email(group.pk), } self._send_mail( subject=subject, template=template, html_template=html_template, project=project, fail_silently=fail_silently, headers=headers, context=context, )
def notify(self, notification): event = notification.event group = event.group project = group.project org = group.organization subject = group.get_email_subject() link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' rules = [] for rule in notification.rules: rule_link = reverse('sentry-edit-project-rule', args=[ org.slug, project.slug, rule.id ]) rules.append((rule.label, rule_link)) enhanced_privacy = org.flags.enhanced_privacy context = { 'project_label': project.get_full_name(), 'group': group, 'event': event, 'link': link, 'rules': rules, 'enhanced_privacy': enhanced_privacy, } # if the organization has enabled enhanced privacy controls we dont send # data which may show PII or source code if not enhanced_privacy: interface_list = [] for interface in event.interfaces.itervalues(): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append( (interface.get_title(), mark_safe(body), text_body) ) context.update({ 'tags': event.get_tags(), 'interfaces': interface_list, }) headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Team': project.team.name, 'X-Sentry-Project': project.name, 'X-Sentry-Reply-To': group_id_to_email(group.id), } for user_id in self.get_send_to(project): self.add_unsubscribe_link(context, user_id, project) self._send_mail( subject=subject, template=template, html_template=html_template, project=project, reference=group, headers=headers, context=context, send_to=[user_id], )
def notify_about_activity(self, activity): if activity.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return candidate_ids = set(self.get_send_to(activity.project)) # Never send a notification to the user that performed the action. candidate_ids.discard(activity.user_id) if activity.type == Activity.ASSIGNED: # Only notify the assignee, and only if they are in the candidate set. recipient_ids = candidate_ids & set(map(int, (activity.data['assignee'],))) elif activity.type == Activity.NOTE: recipient_ids = candidate_ids - set( UserOption.objects.filter( user__in=candidate_ids, key='subscribe_notes', value=u'0', ).values_list('user', flat=True) ) else: recipient_ids = candidate_ids if not recipient_ids: return project = activity.project org = project.organization group = activity.group headers = {} context = { 'data': activity.data, 'author': activity.user, 'project': project, 'project_link': absolute_uri(reverse('sentry-stream', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, })), } if group: group_link = absolute_uri('/{}/{}/issues/{}/'.format( org.slug, project.slug, group.id )) activity_link = '{}activity/'.format(group_link) headers.update({ 'X-Sentry-Reply-To': group_id_to_email(group.id), }) context.update({ 'group': group, 'link': group_link, 'activity_link': activity_link, }) # TODO(dcramer): abstract each activity email into its own helper class if activity.type == Activity.RELEASE: context.update({ 'release': Release.objects.get( version=activity.data['version'], project=project, ), 'release_link': absolute_uri('/{}/{}/releases/{}/'.format( org.slug, project.slug, activity.data['version'], )), }) template_name = activity.get_type_display() if group: subject = group.get_email_subject() elif activity.type == Activity.RELEASE: subject = 'Release %s' % activity.data['version'] else: raise NotImplementedError self._send_mail( project=project, send_to=recipient_ids, subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format(template_name), headers=headers, reference=activity, reply_reference=group, )
def send_notification(self): from sentry.models import Release from sentry.utils.email import MessageBuilder, group_id_to_email if self.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return send_to = self.get_recipients() if not send_to: return project = self.project org = self.project.organization group = self.group if self.user: author = self.user.first_name or self.user.username else: author = None subject_prefix = self.project.get_option( 'subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' if self.group: subject = '%s%s' % (subject_prefix, self.group.get_email_subject()) elif self.type == Activity.RELEASE: subject = '%sRelease %s' % (subject_prefix, self.data['version']) else: raise NotImplementedError headers = {} context = { 'data': self.data, 'author': author, 'project': project, 'project_link': absolute_uri(reverse('sentry-stream', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, })), } if group: group_link = absolute_uri('/{}/{}/group/{}/'.format(org.slug, project.slug, group.id)) activity_link = '{}activity/'.format(group_link) headers.update({ 'X-Sentry-Reply-To': group_id_to_email(group.id), }) context.update({ 'group': group, 'link': group_link, 'activity_link': activity_link, }) # TODO(dcramer): abstract each activity email into its own helper class if self.type == Activity.RELEASE: context.update({ 'release': Release.objects.get( version=self.data['version'], project=project, ), 'release_link': absolute_uri(reverse('sentry-release-details', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, 'version': self.data['version'], })), }) template_name = self.get_type_display() msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format(template_name), headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) msg.send_async()
def setUp(self): self.address = ('0.0.0.0', 0) self.server = SentrySMTPServer(*self.address) self.mailto = group_id_to_email(self.group.pk)
def send_notification(self): from sentry.models import Release from sentry.utils.email import MessageBuilder, group_id_to_email if self.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return send_to = self.get_recipients() if not send_to: return project = self.project org = self.project.organization if self.user: author = self.user.first_name or self.user.username else: author = None subject_prefix = self.project.get_option("subject_prefix", settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + " " if self.group: subject = "%s%s" % (subject_prefix, self.group.get_email_subject()) elif self.type == Activity.RELEASE: subject = "%sRelease %s" % (subject_prefix, self.data["version"]) else: raise NotImplementedError headers = {} context = { "data": self.data, "author": author, "project": self.project, "project_link": absolute_uri( reverse("sentry-stream", kwargs={"organization_slug": org.slug, "project_id": project.slug}) ), } if self.group: headers.update({"X-Sentry-Reply-To": group_id_to_email(self.group.id)}) context.update({"group": self.group, "link": self.group.get_absolute_url()}) # TODO(dcramer): abstract each activity email into its own helper class if self.type == Activity.RELEASE: context.update( { "release": Release.objects.get(version=self.data["version"], project=project), "release_link": absolute_uri( reverse( "sentry-release-details", kwargs={ "organization_slug": org.slug, "project_id": project.slug, "version": self.data["version"], }, ) ), } ) template_name = self.get_type_display() msg = MessageBuilder( subject=subject, context=context, template="sentry/emails/activity/{}.txt".format(template_name), html_template="sentry/emails/activity/{}.html".format(template_name), headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) msg.send_async()
def send_notification(self): from sentry.models import User, UserOption from sentry.utils.email import MessageBuilder, group_id_to_email if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_id_list = set( User.objects.filter(accessgroup__projects=self.project, is_active=True).exclude( id=self.user_id, ).values_list('id', flat=True)) if self.project.team: # fetch team members user_id_list |= set( u_id for u_id in self.project.team.member_set.filter( user__is_active=True, ).exclude(user__id=self.user_id, ). values_list('user', flat=True)) if not user_id_list: return disabled = set( UserOption.objects.filter( user__in=user_id_list, key='subscribe_comments', value='0', ).values_list('user', flat=True)) send_to = [u_id for u_id in user_id_list if u_id not in disabled] if not send_to: return author = self.user.first_name or self.user.username subject = '[%s] %s: %s' % (self.project.name, author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.pk), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', headers=headers, ) msg.add_users(send_to, project=self.project) try: msg.send() except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_notification(self): from sentry.models import User, UserOption, ProjectOption from sentry.utils.email import MessageBuilder, group_id_to_email if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_id_list = set( User.objects.filter(accessgroup__projects=self.project, is_active=True).exclude( id=self.user_id, ).values_list('id', flat=True)) if self.project.team: # fetch team members user_id_list |= set( u_id for u_id in self.project.team.member_set.filter( user__is_active=True, ).exclude(user__id=self.user_id, ). values_list('user', flat=True)) if not user_id_list: return disabled = set( UserOption.objects.filter( user__in=user_id_list, key='subscribe_notes', value=u'0', ).values_list('user', flat=True)) send_to = filter(lambda u_id: u_id not in disabled, user_id_list) if not send_to: return author = self.user.first_name or self.user.username subject_prefix = ProjectOption.objects.get_value( self.project, 'subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' subject = '%s%s' % (subject_prefix, self.group.get_email_subject()) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.pk), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) msg.send_async()
def notify_about_activity(self, activity): if activity.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return candidate_ids = set(self.get_send_to(activity.project)) # Never send a notification to the user that performed the action. candidate_ids.discard(activity.user_id) if activity.type == Activity.ASSIGNED: # Only notify the assignee, and only if they are in the candidate set. recipient_ids = candidate_ids & set((activity.data['assignee'],)) elif activity.type == Activity.NOTE: recipient_ids = candidate_ids - set( UserOption.objects.filter( user__in=candidate_ids, key='subscribe_notes', value=u'0', ).values_list('user', flat=True) ) else: recipient_ids = candidate_ids if not recipient_ids: return project = activity.project org = project.organization group = activity.group headers = {} context = { 'data': activity.data, 'author': activity.user, 'project': project, 'project_link': absolute_uri(reverse('sentry-stream', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, })), } if group: group_link = absolute_uri('/{}/{}/group/{}/'.format(org.slug, project.slug, group.id)) activity_link = '{}activity/'.format(group_link) headers.update({ 'X-Sentry-Reply-To': group_id_to_email(group.id), }) context.update({ 'group': group, 'link': group_link, 'activity_link': activity_link, }) # TODO(dcramer): abstract each activity email into its own helper class if activity.type == Activity.RELEASE: context.update({ 'release': Release.objects.get( version=activity.data['version'], project=project, ), 'release_link': absolute_uri(reverse('sentry-release-details', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, 'version': activity.data['version'], })), }) template_name = activity.get_type_display() # TODO: Everything below should instead use `_send_mail` for consistency. subject_prefix = project.get_option('subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' if group: subject = '%s%s' % (subject_prefix, group.get_email_subject()) elif activity.type == Activity.RELEASE: subject = '%sRelease %s' % (subject_prefix, activity.data['version']) else: raise NotImplementedError msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format(template_name), headers=headers, reference=activity, reply_reference=group, ) msg.add_users(recipient_ids, project=project) msg.send()
def setUp(self): self.address = ('0.0.0.0', 0) self.server = SentrySMTPServer(*self.address) self.mailto = group_id_to_email(self.group.pk) self.event # side effect of generating an event
def notify_about_activity(self, activity): if activity.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return candidate_ids = set(self.get_send_to(activity.project)) # Never send a notification to the user that performed the action. candidate_ids.discard(activity.user_id) if activity.type == Activity.ASSIGNED: # Only notify the assignee, and only if they are in the candidate set. recipient_ids = candidate_ids & set(map(int, (activity.data["assignee"],))) elif activity.type == Activity.NOTE: recipient_ids = candidate_ids - set( UserOption.objects.filter(user__in=candidate_ids, key="subscribe_notes", value=u"0").values_list( "user", flat=True ) ) else: recipient_ids = candidate_ids if not recipient_ids: return project = activity.project org = project.organization group = activity.group headers = {} context = { "data": activity.data, "author": activity.user, "project": project, "project_link": absolute_uri( reverse("sentry-stream", kwargs={"organization_slug": org.slug, "project_id": project.slug}) ), } if group: group_link = absolute_uri("/{}/{}/issues/{}/".format(org.slug, project.slug, group.id)) activity_link = "{}activity/".format(group_link) headers.update({"X-Sentry-Reply-To": group_id_to_email(group.id)}) context.update({"group": group, "link": group_link, "activity_link": activity_link}) # TODO(dcramer): abstract each activity email into its own helper class if activity.type == Activity.RELEASE: context.update( { "release": Release.objects.get(version=activity.data["version"], project=project), "release_link": absolute_uri( "/{}/{}/releases/{}/".format(org.slug, project.slug, activity.data["version"]) ), } ) template_name = activity.get_type_display() if group: subject = group.get_email_subject() elif activity.type == Activity.RELEASE: subject = "Release %s" % activity.data["version"] else: raise NotImplementedError self._send_mail( project=project, send_to=recipient_ids, subject=subject, context=context, template="sentry/emails/activity/{}.txt".format(template_name), html_template="sentry/emails/activity/{}.html".format(template_name), headers=headers, reference=activity, reply_reference=group, )
def notify(self, notification): from sentry.models import Commit, Release event = notification.event group = event.group project = group.project org = group.organization subject = event.get_email_subject() link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' rules = [] for rule in notification.rules: rule_link = '/%s/%s/settings/alerts/rules/%s/' % ( org.slug, project.slug, rule.id) rules.append((rule.label, rule_link)) enhanced_privacy = org.flags.enhanced_privacy # lets identify possibly suspect commits and owners commits = {} if features.has('organizations:suggested-commits', org): try: committers = get_event_file_committers(project, event) except (Commit.DoesNotExist, Release.DoesNotExist): pass except Exception as exc: logging.exception(six.text_type(exc)) else: for committer in committers: for commit in committer['commits']: if commit['id'] not in commits: commit_data = commit.copy() commit_data['shortId'] = commit_data['id'][:7] commit_data['author'] = committer['author'] commit_data['subject'] = commit_data[ 'message'].split('\n', 1)[0] commits[commit['id']] = commit_data context = { 'project_label': project.get_full_name(), 'group': group, 'event': event, 'link': link, 'rules': rules, 'enhanced_privacy': enhanced_privacy, 'commits': sorted(commits.values(), key=lambda x: x['score'], reverse=True), } # if the organization has enabled enhanced privacy controls we dont send # data which may show PII or source code if not enhanced_privacy: interface_list = [] for interface in six.itervalues(event.interfaces): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append( (interface.get_title(), mark_safe(body), text_body)) context.update({ 'tags': event.get_tags(), 'interfaces': interface_list, }) headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Project': project.slug, 'X-Sentry-Reply-To': group_id_to_email(group.id), } for user_id in self.get_send_to(project=project, event=event): self.add_unsubscribe_link(context, user_id, project) self._send_mail( subject=subject, template=template, html_template=html_template, project=project, reference=group, headers=headers, type='notify.error', context=context, send_to=[user_id], )
def notify(self, notification, target_type, target_identifier=None, **kwargs): metrics.incr("mail_adapter.notify") event = notification.event environment = event.get_tag("environment") group = event.group project = group.project org = group.organization logger.info( "mail.adapter.notify", extra={ "target_type": target_type.value, "target_identifier": target_identifier, "group": group.id, "project_id": project.id, }, ) subject = event.get_email_subject() query_params = {"referrer": "alert_email"} if environment: query_params["environment"] = environment link = group.get_absolute_url(params=query_params) template = "sentry/emails/error.txt" html_template = "sentry/emails/error.html" rules = [] for rule in notification.rules: rule_link = "/settings/%s/projects/%s/alerts/rules/%s/" % ( org.slug, project.slug, rule.id, ) rules.append((rule.label, rule_link)) enhanced_privacy = org.flags.enhanced_privacy # lets identify possibly suspect commits and owners commits = {} try: committers = get_serialized_event_file_committers(project, event) except (Commit.DoesNotExist, Release.DoesNotExist): pass except Exception as exc: logging.exception(six.text_type(exc)) else: for committer in committers: for commit in committer["commits"]: if commit["id"] not in commits: commit_data = commit.copy() commit_data["shortId"] = commit_data["id"][:7] commit_data["author"] = committer["author"] commit_data["subject"] = commit_data["message"].split( "\n", 1)[0] commits[commit["id"]] = commit_data project_plugins = plugins.for_project(project, version=1) organization_integrations = Integration.objects.filter( organizations=org).first() has_integrations = bool(project_plugins or organization_integrations) context = { "project_label": project.get_full_name(), "group": group, "event": event, "link": link, "rules": rules, "has_integrations": has_integrations, "enhanced_privacy": enhanced_privacy, "commits": sorted(commits.values(), key=lambda x: x["score"], reverse=True), "environment": environment, } # if the organization has enabled enhanced privacy controls we dont send # data which may show PII or source code if not enhanced_privacy: interface_list = [] for interface in six.itervalues(event.interfaces): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append( (interface.get_title(), mark_safe(body), text_body)) context.update({"tags": event.tags, "interfaces": interface_list}) headers = { "X-Sentry-Logger": group.logger, "X-Sentry-Logger-Level": group.get_level_display(), "X-Sentry-Project": project.slug, "X-Sentry-Reply-To": group_id_to_email(group.id), } for user_id in self.get_send_to( project=project, target_type=target_type, target_identifier=target_identifier, event=event, ): logger.info( "mail.adapter.notify.mail_user", extra={ "target_type": target_type, "target_identifier": target_identifier, "group": group.id, "project_id": project.id, "user_id": user_id, }, ) self.add_unsubscribe_link(context, user_id, project, "alert_email") self._send_mail( subject=subject, template=template, html_template=html_template, project=project, reference=group, headers=headers, type="notify.error", context=context, send_to=[user_id], )
def setUp(self): super(TestMailgunInboundWebhookView, self).setUp() self.event = self.create_event(event_id='a' * 32) self.mailto = group_id_to_email(self.group.pk)
def setUp(self): super().setUp() self.event = self.store_event(data={"event_id": "a" * 32}, project_id=self.project.id) self.mailto = group_id_to_email(self.group.pk)
def notify(self, notification): from sentry.models import Commit, Release event = notification.event environment = event.get_tag('environment') group = event.group project = group.project org = group.organization subject = event.get_email_subject() link = group.get_absolute_url() if environment: link = link + '?' + urlencode({'environment': environment}) template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' rules = [] for rule in notification.rules: rule_link = '/%s/%s/settings/alerts/rules/%s/' % (org.slug, project.slug, rule.id) rules.append((rule.label, rule_link)) enhanced_privacy = org.flags.enhanced_privacy # lets identify possibly suspect commits and owners commits = {} if features.has('organizations:suggested-commits', org): try: committers = get_event_file_committers(project, event) except (Commit.DoesNotExist, Release.DoesNotExist): pass except Exception as exc: logging.exception(six.text_type(exc)) else: for committer in committers: for commit in committer['commits']: if commit['id'] not in commits: commit_data = commit.copy() commit_data['shortId'] = commit_data['id'][:7] commit_data['author'] = committer['author'] commit_data['subject'] = commit_data['message'].split('\n', 1)[0] commits[commit['id']] = commit_data context = { 'project_label': project.get_full_name(), 'group': group, 'event': event, 'link': link, 'rules': rules, 'enhanced_privacy': enhanced_privacy, 'commits': sorted(commits.values(), key=lambda x: x['score'], reverse=True), 'environment': environment } # if the organization has enabled enhanced privacy controls we dont send # data which may show PII or source code if not enhanced_privacy: interface_list = [] for interface in six.itervalues(event.interfaces): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append((interface.get_title(), mark_safe(body), text_body)) context.update({ 'tags': event.get_tags(), 'interfaces': interface_list, }) headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Project': project.slug, 'X-Sentry-Reply-To': group_id_to_email(group.id), } for user_id in self.get_send_to(project=project, event=event): self.add_unsubscribe_link(context, user_id, project) self._send_mail( subject=subject, template=template, html_template=html_template, project=project, reference=group, headers=headers, type='notify.error', context=context, send_to=[user_id], )
def send_notification(self): from sentry.models import User, UserOption from sentry.utils.email import MessageBuilder, group_id_to_email if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_id_list = set( User.objects.filter( accessgroup__projects=self.project, is_active=True ).exclude( id=self.user_id, ).values_list('id', flat=True) ) if self.project.team: # fetch team members user_id_list |= set( u_id for u_id in self.project.team.member_set.filter( user__is_active=True, ).exclude( user__id=self.user_id, ).values_list('user', flat=True) ) if not user_id_list: return disabled = set(UserOption.objects.filter( user__in=user_id_list, key='subscribe_comments', value='0', ).values_list('user', flat=True)) send_to = [ u_id for u_id in user_id_list if u_id not in disabled ] if not send_to: return author = self.user.first_name or self.user.username subject = '[%s] %s: %s' % ( self.project.name, author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.pk), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', headers=headers, ) msg.add_users(send_to, project=self.project) try: msg.send() except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_notification(self): from sentry.models import User, UserOption, ProjectOption from sentry.utils.email import MessageBuilder, group_id_to_email if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_id_list = set( User.objects.filter( accessgroup__projects=self.project, is_active=True ).exclude( id=self.user_id, ).values_list('id', flat=True) ) if self.project.team: # fetch team members user_id_list |= set( u_id for u_id in self.project.team.member_set.filter( user__is_active=True, ).exclude( user__id=self.user_id, ).values_list('user', flat=True) ) if not user_id_list: return disabled = set(UserOption.objects.filter( user__in=user_id_list, key='subscribe_notes', value=u'0', ).values_list('user', flat=True)) send_to = filter(lambda u_id: u_id not in disabled, user_id_list) if not send_to: return author = self.user.first_name or self.user.username subject_prefix = ProjectOption.objects.get_value( self.project, 'subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' subject = '%s%s' % (subject_prefix, self.event.get_email_subject()) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.pk), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) try: msg.send() except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_notification(self): from sentry.models import Release from sentry.utils.email import MessageBuilder, group_id_to_email if self.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return send_to = self.get_recipients() if not send_to: return project = self.project org = self.project.organization if self.user: author = self.user.first_name or self.user.username else: author = None subject_prefix = self.project.get_option( 'subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' if self.group: subject = '%s%s' % (subject_prefix, self.group.get_email_subject()) elif self.type == Activity.RELEASE: subject = '%sRelease %s' % (subject_prefix, self.data['version']) else: raise NotImplementedError headers = {} context = { 'data': self.data, 'author': author, 'project': self.project, 'project_link': absolute_uri(reverse('sentry-stream', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, })), } if self.group: headers.update({ 'X-Sentry-Reply-To': group_id_to_email(self.group.id), }) context.update({ 'group': self.group, 'link': self.group.get_absolute_url(), }) # TODO(dcramer): abstract each activity email into its own helper class if self.type == Activity.RELEASE: context.update({ 'release': Release.objects.get( version=self.data['version'], project=project, ), 'release_link': absolute_uri(reverse('sentry-release-details', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, 'version': self.data['version'], })), }) template_name = self.get_type_display() msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format(template_name), headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) msg.send_async()
def notify(self, notification): event = notification.event group = event.group project = group.project org = group.organization subject = event.get_email_subject() link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' rules = [] for rule in notification.rules: rule_link = reverse('sentry-edit-project-rule', args=[ org.slug, project.slug, rule.id ]) rules.append((rule.label, rule_link)) enhanced_privacy = org.flags.enhanced_privacy context = { 'project_label': project.get_full_name(), 'group': group, 'event': event, 'link': link, 'rules': rules, 'enhanced_privacy': enhanced_privacy, } # if the organization has enabled enhanced privacy controls we dont send # data which may show PII or source code if not enhanced_privacy: interface_list = [] for interface in six.itervalues(event.interfaces): body = interface.to_email_html(event) if not body: continue text_body = interface.to_string(event) interface_list.append( (interface.get_title(), mark_safe(body), text_body) ) context.update({ 'tags': event.get_tags(), 'interfaces': interface_list, }) headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Team': project.team.name, 'X-Sentry-Project': project.name, 'X-Sentry-Reply-To': group_id_to_email(group.id), } for user_id in self.get_send_to(project): self.add_unsubscribe_link(context, user_id, project) self._send_mail( subject=subject, template=template, html_template=html_template, project=project, reference=group, headers=headers, type='notify.error', context=context, send_to=[user_id], )
def setUp(self): super(TestMailgunInboundWebhookView, self).setUp() self.event = self.store_event(data={"event_id": "a" * 32}, project_id=self.project.id) self.mailto = group_id_to_email(self.group.pk)