Example #1
0
    def test_with_users(self):
        project = self.project

        user_a = User.objects.create(email='*****@*****.**')
        user_b = User.objects.create(email='*****@*****.**')
        user_c = User.objects.create(email='*****@*****.**')

        UserOption.objects.create(
            user=user_b,
            key='alert_email',
            value='*****@*****.**',
        )
        UserOption.objects.create(
            user=user_c,
            project=project,
            key='mail:email',
            value='*****@*****.**',
        )

        msg = MessageBuilder(
            subject='Test',
            body='hello world',
            html_body='<!DOCTYPE html>\n<b>hello world</b>',
        )
        msg.add_users([user_a.id, user_b.id, user_c.id], project=project)
        msg.send()

        assert len(mail.outbox) == 3

        assert sorted([out.to[0] for out in mail.outbox]) == [
            '*****@*****.**',
            '*****@*****.**',
            '*****@*****.**',
        ]
Example #2
0
    def test_fake_dont_send(self):
        project = self.project

        user_a = User.objects.create(email=create_fake_email('foo', 'fake'))
        user_b = User.objects.create(email=create_fake_email('bar', 'fake'))
        user_c = User.objects.create(email=create_fake_email('baz', 'fake'))

        UserOption.objects.create(
            user=user_b,
            key='alert_email',
            value=create_fake_email('fizzle', 'fake'),
        )
        UserOption.objects.create(
            user=user_c,
            project=project,
            key='mail:email',
            value=create_fake_email('bazzer', 'fake'),
        )

        msg = MessageBuilder(
            subject='Test',
            body='hello world',
            html_body='<!DOCTYPE html>\n<b>hello world</b>',
        )
        msg.add_users([user_a.id, user_b.id, user_c.id], project=project)
        msg.send()

        assert len(mail.outbox) == 0
def handle_project(plugin, project, stream):
    stream.write('# Project: %s\n' % project)
    from sentry.utils.email import MessageBuilder
    msg = MessageBuilder('test')
    msg.add_users(plugin.get_sendable_users(project), project)
    for email in msg._send_to:
        stream.write(email + '\n')
Example #4
0
    def _build_message(self, project, subject, template=None, html_template=None,
                   body=None, reference=None, reply_reference=None, headers=None,
                   context=None, send_to=None, type=None):
        if send_to is None:
            send_to = self.get_send_to(project)
        if not send_to:
            logger.debug('Skipping message rendering, no users to send to.')
            return

        subject_prefix = self.get_option('subject_prefix', project) or self._subject_prefix()
        subject_prefix = force_text(subject_prefix)
        subject = force_text(subject)

        msg = MessageBuilder(
            subject='%s%s' % (subject_prefix, subject),
            template=template,
            html_template=html_template,
            body=body,
            headers=headers,
            type=type,
            context=context,
            reference=reference,
            reply_reference=reply_reference,
        )
        msg.add_users(send_to, project=project)
        return msg
Example #5
0
def send_notification_as_email(
    notification: BaseNotification,
    recipients: Iterable[Team | User],
    shared_context: Mapping[str, Any],
    extra_context_by_actor_id: Mapping[int, Mapping[str, Any]] | None,
) -> None:
    for recipient in recipients:
        with sentry_sdk.start_span(op="notification.send_email",
                                   description="one_recipient"):
            if isinstance(recipient, Team):
                # TODO(mgaeta): MessageBuilder only works with Users so filter out Teams for now.
                continue
            log_message(notification, recipient)

            with sentry_sdk.start_span(op="notification.send_email",
                                       description="build_message"):
                msg = MessageBuilder(
                    **get_builder_args(notification, recipient, shared_context,
                                       extra_context_by_actor_id))

            with sentry_sdk.start_span(op="notification.send_email",
                                       description="send_message"):
                # TODO: find better way of handling this
                add_users_kwargs = {}
                if isinstance(notification, ProjectNotification):
                    add_users_kwargs["project"] = notification.project
                msg.add_users([recipient.id], **add_users_kwargs)
                msg.send_async()
            notification.record_notification_sent(recipient,
                                                  ExternalProviders.EMAIL)
def send_notification_as_email(
    notification: BaseNotification,
    recipients: Iterable[Union["Team", "User"]],
    shared_context: Mapping[str, Any],
    extra_context_by_user_id: Optional[Mapping[int, Mapping[str, Any]]],
) -> None:
    headers = get_headers(notification)

    for recipient in recipients:
        if isinstance(recipient, Team):
            # TODO(mgaeta): MessageBuilder only works with Users so filter out Teams for now.
            continue
        extra_context = (extra_context_by_user_id or {}).get(recipient.id, {})
        log_message(notification, recipient)
        context = get_context(notification, recipient, shared_context,
                              extra_context)
        subject = get_subject_with_prefix(notification, context=context)
        msg = MessageBuilder(
            subject=subject,
            context=context,
            template=notification.get_template(),
            html_template=notification.get_html_template(),
            headers=headers,
            reference=notification.get_reference(),
            reply_reference=notification.get_reply_reference(),
            type=notification.get_type(),
        )
        msg.add_users([recipient.id], project=notification.project)
        msg.send_async()
Example #7
0
def build_message(timestamp, duration, organization, user, report):
    start, stop = interval = _to_interval(timestamp, duration)

    duration_spec = durations[duration]
    message = MessageBuilder(
        subject=u'{} Report for {}: {} - {}'.format(
            duration_spec.adjective.title(),
            organization.name,
            date_format(start),
            date_format(stop),
        ),
        template='sentry/emails/reports/body.txt',
        html_template='sentry/emails/reports/body.html',
        type='report.organization',
        context={
            'duration': duration_spec,
            'interval': {
                'start': date_format(start),
                'stop': date_format(stop),
            },
            'organization': organization,
            'personal': fetch_personal_statistics(
                interval,
                organization,
                user,
            ),
            'report': to_context(report),
            'user': user,
        },
    )

    message.add_users((user.id,))

    return message
Example #8
0
    def _send_mail(self, subject, template=None, html_template=None, body=None,
                   project=None, group=None, headers=None, context=None,
                   fail_silently=False):
        send_to = self.get_send_to(project)
        if not send_to:
            return

        subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix

        try:
            subject_prefix = subject_prefix.encode("utf-8")
            subject = subject.encode("utf-8")
        except UnicodeDecodeError:
            subject_prefix = unicode(subject_prefix, "utf-8")
            subject = unicode(subject, "utf-8")

        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(send_to, project=project)
        return msg.send(fail_silently=fail_silently)
Example #9
0
def send_notification_as_email(
    notification: BaseNotification,
    users: Set[User],
    shared_context: Mapping[str, Any],
    extra_context_by_user_id: Optional[Mapping[int, Mapping[str, Any]]],
) -> None:
    headers = get_headers(notification)
    subject = get_subject_with_prefix(notification)
    type = get_email_type(notification)

    for user in users:
        extra_context = (extra_context_by_user_id or {}).get(user.id, {})
        log_message(notification, user)
        msg = MessageBuilder(
            subject=subject,
            context=get_context(notification, user, shared_context,
                                extra_context),
            template=notification.get_template(),
            html_template=notification.get_html_template(),
            headers=headers,
            reference=notification.get_reference(),
            reply_reference=notification.get_reply_reference(),
            type=type,
        )
        msg.add_users([user.id], project=notification.project)
        msg.send_async()
Example #10
0
    def send(self):
        if not self.should_email():
            return

        participants = self.get_participants()
        if not participants:
            return

        activity = self.activity
        project = self.project
        group = self.group

        context = self.get_base_context()
        context.update(self.get_context())

        template = self.get_template()
        html_template = self.get_html_template()
        email_type = self.get_email_type()
        headers = self.get_headers()

        for user, reason in participants.items():
            if group:
                context.update(
                    {
                        'reason':
                        GroupSubscriptionReason.descriptions.get(
                            reason,
                            "are subscribed to this issue",
                        ),
                        'unsubscribe_link':
                        generate_signed_link(
                            user.id,
                            'sentry-account-email-unsubscribe-issue',
                            kwargs={'issue_id': group.id},
                        ),
                    }
                )
            user_context = self.get_user_context(user)
            if user_context:
                user_context.update(context)
            else:
                user_context = context

            msg = MessageBuilder(
                subject=self.get_subject_with_prefix(),
                template=template,
                html_template=html_template,
                headers=headers,
                type=email_type,
                context=user_context,
                reference=activity,
                reply_reference=group,
            )
            msg.add_users([user.id], project=project)
            msg.send_async()
Example #11
0
def send_notification_as_email(
    notification: ActivityNotification, user: User, context: Mapping[str, Any]
) -> None:
    msg = MessageBuilder(
        subject=notification.get_subject_with_prefix(),
        template=notification.get_template(),
        html_template=notification.get_html_template(),
        headers=notification.get_headers(),
        type=notification.get_email_type(),
        context=context,
        reference=notification.activity,
        reply_reference=notification.group,
    )
    msg.add_users([user.id], project=notification.project)
    msg.send_async()
Example #12
0
    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()
Example #13
0
    def send(self):
        if not self.should_email():
            return

        users = self.get_participants()
        if not users:
            return

        activity = self.activity
        project = self.project
        group = self.group

        context = self.get_base_context()
        context.update(self.get_context())

        subject_prefix = self._get_subject_prefix()

        subject = (u'{}{}'.format(
            subject_prefix,
            self.get_subject(),
        )).encode('utf-8')
        template = self.get_template()
        html_template = self.get_html_template()
        email_type = self.get_email_type()
        headers = self.get_headers()

        for user in users:
            if group:
                context['unsubscribe_link'] = generate_signed_link(
                    user.id,
                    'sentry-account-email-unsubscribe-issue',
                    kwargs={'issue_id': group.id},
                )

            msg = MessageBuilder(
                subject=subject,
                template=template,
                html_template=html_template,
                headers=headers,
                type=email_type,
                context=context,
                reference=activity,
                reply_reference=group,
            )
            msg.add_users([user.id], project=project)
            msg.send_async()
Example #14
0
    def _send_mail(self, subject, template=None, html_template=None, body=None,
                   project=None, headers=None, context=None, fail_silently=False):
        send_to = self.get_send_to(project)
        if not send_to:
            return

        subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix

        msg = MessageBuilder(
            subject='%s%s' % (subject_prefix, subject),
            template=template,
            html_template=html_template,
            body=body,
            headers=headers,
            context=context,
        )
        msg.add_users(send_to, project=project)
        return msg.send(fail_silently=fail_silently)
Example #15
0
    def _send_mail(self, subject, template=None, html_template=None, body=None,
                   project=None, group=None, headers=None, context=None):
        send_to = self.get_send_to(project)
        if not send_to:
            return

        subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix
        subject_prefix = force_text(subject_prefix)
        subject = force_text(subject)

        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(send_to, project=project)
        return msg.send()
Example #16
0
def send_notification_as_email(
    notification: ActivityNotification,
    users: Mapping[User, int],
    shared_context: Mapping[str, Any],
) -> None:
    headers = get_headers(notification)
    subject = get_subject_with_prefix(notification)
    type = get_email_type(notification)

    for user, reason in users.items():
        msg = MessageBuilder(
            subject=subject,
            template=notification.get_template(),
            html_template=notification.get_html_template(),
            headers=headers,
            type=type,
            context=get_context(notification, user, reason, shared_context),
            reference=notification.activity,
            reply_reference=notification.group,
        )
        msg.add_users([user.id], project=notification.project)
        msg.send_async()
Example #17
0
    def _build_message(self, project, subject, template=None, html_template=None,
                   body=None, reference=None, reply_reference=None, headers=None,
                   context=None, send_to=None, type=None):
        if send_to is None:
            send_to = self.get_send_to(project)
        if not send_to:
            logger.debug('Skipping message rendering, no users to send to.')
            return

        tags = {}
        if 'event' in context:
            tags = dict(context['event'].get_tags())

        subject_prefix = self.get_option('subject_prefix', project) or self._subject_prefix()
        
        try:
            subject_prefix = subject_prefix.format(tags=tags)
        except Exception:
            pass
        
        subject_prefix = force_text(subject_prefix)
        subject = force_text(subject)

        msg = MessageBuilder(
            subject='%s%s' % (subject_prefix, subject),
            template=template,
            html_template=html_template,
            body=body,
            headers=headers,
            type=type,
            context=context,
            reference=reference,
            reply_reference=reply_reference,
        )
        msg.add_users(send_to, project=project)
        return msg
Example #18
0
    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)
Example #19
0
    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()
Example #20
0
    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)
Example #21
0
    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()
Example #22
0
    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)
Example #23
0
    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()
Example #24
0
    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('/{}/{}/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()

        # 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()
Example #25
0
    def handle_user_report(self, payload, project, **kwargs):
        from sentry.models import Group, GroupSubscription, GroupSubscriptionReason

        group = Group.objects.get(id=payload['report']['issue']['id'])

        participants = GroupSubscription.objects.get_participants(group=group)

        if not participants:
            return

        context = {
            'project': project,
            'project_link': absolute_uri(u'/{}/{}/'.format(
                project.organization.slug,
                project.slug,
            )),
            'issue_link': absolute_uri(u'/{}/{}/issues/{}/'.format(
                project.organization.slug,
                project.slug,
                payload['report']['issue']['id'],
            )),
            # TODO(dcramer): we dont have permalinks to feedback yet
            'link': absolute_uri(u'/{}/{}/issues/{}/feedback/'.format(
                project.organization.slug,
                project.slug,
                payload['report']['issue']['id'],
            )),
            'group': group,
            'report': payload['report'],
        }

        subject_prefix = self.get_option('subject_prefix', project) or self._subject_prefix()
        subject_prefix = force_text(subject_prefix)
        subject = force_text(u'{}{} - New Feedback from {}'.format(
            subject_prefix,
            group.qualified_short_id,
            payload['report']['name'],
        ))

        headers = {
            'X-Sentry-Project': project.slug,
        }

        # TODO(dcramer): this is copypasta'd from activity notifications
        # and while it'd be nice to re-use all of that, they are currently
        # coupled to <Activity> instances which makes this tough
        for user, reason in participants.items():
            context.update({
                'reason': GroupSubscriptionReason.descriptions.get(
                    reason,
                    "are subscribed to this issue",
                ),
                'unsubscribe_link': generate_signed_link(
                    user.id,
                    'sentry-account-email-unsubscribe-issue',
                    kwargs={'issue_id': group.id},
                ),
            })

            msg = MessageBuilder(
                subject=subject,
                template='sentry/emails/activity/new-user-feedback.txt',
                html_template='sentry/emails/activity/new-user-feedback.html',
                headers=headers,
                type='notify.user-report',
                context=context,
                reference=group,
            )
            msg.add_users([user.id], project=project)
            msg.send_async()