示例#1
0
    def send_confirm_email_singular(self, email, is_new_user=False):
        from sentry import options
        from sentry.utils.email import MessageBuilder

        if not email.hash_is_valid():
            email.set_hash()
            email.save()

        context = {
            'user':
            self,
            'url':
            absolute_uri(
                reverse('sentry-account-confirm-email', args=[self.id, email.validation_hash])
            ),
            'confirm_email':
            email.email,
            'is_new_user':
            is_new_user,
        }
        msg = MessageBuilder(
            subject='%sConfirm Email' % (options.get('mail.subject-prefix'), ),
            template='sentry/emails/confirm_email.txt',
            html_template='sentry/emails/confirm_email.html',
            type='user.confirm_email',
            context=context,
        )
        msg.send_async([email.email])
    def send_sso_unlink_email(self, actor, provider):
        from sentry.utils.email import MessageBuilder
        from sentry.models import LostPasswordHash

        email = self.get_email()

        recover_uri = '{path}?{query}'.format(
            path=reverse('sentry-account-recover'),
            query=urlencode({'email': email}),
        )

        context = {
            'email': email,
            'recover_url': absolute_uri(recover_uri),
            'has_password': self.user.password,
            'organization': self.organization,
            'actor': actor,
            'provider': provider,
        }

        if not self.user.password:
            password_hash = LostPasswordHash.for_user(self.user)
            context['set_password_url'] = password_hash.get_absolute_url(mode='set_password')

        msg = MessageBuilder(
            subject='Action Required for %s' % (self.organization.name, ),
            template='sentry/emails/auth-sso-disabled.txt',
            html_template='sentry/emails/auth-sso-disabled.html',
            type='organization.auth_sso_disabled',
            context=context,
        )
        msg.send_async([email])
示例#3
0
    def send_invite_email(self):
        from sentry.utils.email import MessageBuilder

        context = {
            'email': self.email,
            'organization': self.organization,
            'url': absolute_uri(reverse('sentry-accept-invite', kwargs={
                'member_id': self.id,
                'token': self.token,
            })),
        }

        msg = MessageBuilder(
            subject='Join %s in using Sentry' % self.organization.name,
            template='sentry/emails/member-invite.txt',
            html_template='sentry/emails/member-invite.html',
            type='organization.invite',
            context=context,
        )

        try:
            msg.send_async([self.get_email()])
        except Exception as e:
            logger = get_logger(name='sentry.mail')
            logger.exception(e)
示例#4
0
文件: base.py 项目: alexandrul/sentry
    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()
示例#5
0
文件: auth.py 项目: alexandrul/sentry
def _remove_2fa_non_compliant_member(member, org, actor=None, actor_key=None, ip_address=None):
    user = member.user
    logging_data = {
        'organization_id': org.id,
        'user_id': user.id,
        'member_id': member.id
    }

    try:
        member.email = member.get_email()
        member.user = None
        member.save()
    except (AssertionError, IntegrityError):
        logger.warning(
            'Could not remove 2FA noncompliant user from org',
            extra=logging_data
        )
    else:
        logger.info(
            '2FA noncompliant user removed from org',
            extra=logging_data
        )
        AuditLogEntry.objects.create(
            actor=actor,
            actor_key=actor_key,
            ip_address=ip_address,
            event=AuditLogEntryEvent.MEMBER_PENDING,
            data=member.get_audit_log_data(),
            organization=org,
            target_object=org.id,
            target_user=user,
        )

        # send invite to setup 2fa
        email_context = {
            'url': member.get_invite_link(),
            'organization': org
        }
        subject = u'{} {} Mandatory: Enable Two-Factor Authentication'.format(
            options.get('mail.subject-prefix'),
            org.name.capitalize(),
        )
        message = MessageBuilder(
            subject=subject,
            template='sentry/emails/setup_2fa.txt',
            html_template='sentry/emails/setup_2fa.html',
            type='user.setup_2fa',
            context=email_context,
        )
        message.send_async([member.email])
示例#6
0
文件: activity.py 项目: KinKir/sentry
    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()
示例#7
0
    def send_recover_mail(self):
        from sentry.utils.email import MessageBuilder

        context = {
            'user': self.user,
            'domain': urlparse(settings.SENTRY_URL_PREFIX).hostname,
            'url': absolute_uri(reverse(
                'sentry-account-recover-confirm',
                args=[self.user.id, self.hash]
            )),
        }
        msg = MessageBuilder(
            subject='%sPassword Recovery' % (settings.EMAIL_SUBJECT_PREFIX,),
            template='sentry/emails/recover_account.txt',
            context=context,
        )
        msg.send_async([self.user.email])
    def send_approved_email(self):
        from sentry.utils.email import MessageBuilder

        user = self.member.user
        email = user.email
        organization = self.team.organization

        context = {"email": email, "name": user.get_display_name(), "organization": organization, "team": self.team}

        msg = MessageBuilder(
            subject="Sentry Access Request",
            template="sentry/emails/access-approved.txt",
            html_template="sentry/emails/access-approved.html",
            context=context,
        )

        msg.send_async([email])
示例#9
0
文件: base.py 项目: bsergean/sentry
    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()
示例#10
0
    def send_sso_link_email(self):
        from sentry.utils.email import MessageBuilder

        context = {
            'email': self.email,
            'organization_name': self.organization.name,
            'url': absolute_uri(reverse('sentry-auth-link-identity', kwargs={
                'organization_slug': self.organization.slug,
            })),
        }

        msg = MessageBuilder(
            subject='Action Required for %s' % (self.organization.name,),
            template='sentry/emails/auth-link-identity.txt',
            html_template='sentry/emails/auth-link-identity.html',
            context=context,
        )
        msg.send_async([self.get_email()])
示例#11
0
    def send_recover_mail(self):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            'user': self.user,
            'domain': get_server_hostname(),
            'url': self.get_absolute_url(),
        }
        msg = MessageBuilder(
            subject='%sPassword Recovery' % (options.get('mail.subject-prefix'),),
            template='sentry/emails/recover_account.txt',
            html_template='sentry/emails/recover_account.html',
            type='user.password_recovery',
            context=context,
        )
        msg.send_async([self.user.email])
    def send_request_email(self):
        from sentry.models import OrganizationMember
        from sentry.utils.email import MessageBuilder

        user = self.member.user
        email = user.email
        organization = self.team.organization

        context = {
            'email': email,
            'name': user.get_display_name(),
            'organization': organization,
            'team': self.team,
            'url': absolute_uri(reverse('sentry-organization-members', kwargs={
                'organization_slug': organization.slug,
            }) + '?ref=access-requests'),
        }

        msg = MessageBuilder(
            subject='Sentry Access Request',
            template='sentry/emails/request-team-access.txt',
            html_template='sentry/emails/request-team-access.html',
            type='team.access.request',
            context=context,
        )

        global_roles = [
            r.id for r in roles.with_scope('org:write')
            if r.is_global
        ]
        team_roles = [
            r.id for r in roles.with_scope('team:write')
        ]

        # find members which are either team scoped or have access to all teams
        member_list = OrganizationMember.objects.filter(
            Q(role__in=global_roles) |
            Q(teams=self.team, role__in=team_roles),
            organization=self.team.organization,
            user__isnull=False,
        ).select_related('user')

        msg.send_async([m.user.email for m in member_list])
示例#13
0
    def send_recover_mail(self):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            'user': self.user,
            'domain': get_server_hostname(),
            'url': absolute_uri(reverse(
                'sentry-account-recover-confirm',
                args=[self.user.id, self.hash]
            )),
        }
        msg = MessageBuilder(
            subject='%sPassword Recovery' % (options.get('mail.subject-prefix'),),
            template='sentry/emails/recover_account.txt',
            context=context,
        )
        msg.send_async([self.user.email])
    def send_sso_link_email(self, actor, provider):
        from sentry.utils.email import MessageBuilder

        link_args = {'organization_slug': self.organization.slug}

        context = {
            'organization': self.organization,
            'actor': actor,
            'provider': provider,
            'url': absolute_uri(reverse('sentry-auth-organization', kwargs=link_args)),
        }

        msg = MessageBuilder(
            subject='Action Required for %s' % (self.organization.name, ),
            template='sentry/emails/auth-link-identity.txt',
            html_template='sentry/emails/auth-link-identity.html',
            type='organization.auth_link',
            context=context,
        )
        msg.send_async([self.get_email()])
示例#15
0
    def email_success(self):
        from sentry.utils.email import MessageBuilder

        # The following condition should never be true, but it's a safeguard in case someone manually calls this method
        if self.date_finished is None or self.date_expired is None or self.file is None:
            # TODO(Leander): Implement logging here
            return
        msg = MessageBuilder(
            subject="Your Download is Ready!",
            context={
                "url":
                absolute_uri(
                    reverse("sentry-data-export-details",
                            args=[self.organization.slug, self.id])),
                "expiration":
                self.date_expired_string,
            },
            template="sentry/emails/data-export-success.txt",
            html_template="sentry/emails/data-export-success.html",
        )
        msg.send_async([self.user.email])
示例#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()
示例#17
0
    def send_recover_mail(self, request):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            'user': self.user,
            'domain': get_server_hostname(),
            'url': self.get_absolute_url(),
            'datetime': timezone.now(),
            'ip_address': request.META['REMOTE_ADDR'],
        }

        msg = MessageBuilder(
            subject='%sPassword Recovery' %
            (options.get('mail.subject-prefix'), ),
            template='sentry/emails/recover_account.txt',
            html_template='sentry/emails/recover_account.html',
            type='user.password_recovery',
            context=context,
        )
        msg.send_async([self.user.email])
    def send_invite_email(self):
        from sentry.utils.email import MessageBuilder

        context = {
            'email': self.email,
            'organization': self.organization,
            'url': self.get_invite_link(),
        }

        msg = MessageBuilder(
            subject='Join %s in using Sentry' % self.organization.name,
            template='sentry/emails/member-invite.txt',
            html_template='sentry/emails/member-invite.html',
            type='organization.invite',
            context=context,
        )

        try:
            msg.send_async([self.get_email()])
        except Exception as e:
            logger = get_logger(name='sentry.mail')
            logger.exception(e)
示例#19
0
    def send_recover_mail(self):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            'user':
            self.user,
            'domain':
            get_server_hostname(),
            'url':
            absolute_uri(
                reverse('sentry-account-recover-confirm',
                        args=[self.user.id, self.hash])),
        }
        msg = MessageBuilder(
            subject='%sPassword Recovery' %
            (options.get('mail.subject-prefix'), ),
            template='sentry/emails/recover_account.txt',
            context=context,
        )
        msg.send_async([self.user.email])
    def send_approved_email(self):
        from sentry.utils.email import MessageBuilder

        user = self.member.user
        email = user.email
        organization = self.team.organization

        context = {
            'email': email,
            'name': user.get_display_name(),
            'organization': organization,
            'team': self.team,
        }

        msg = MessageBuilder(
            subject='Sentry Access Request',
            template='sentry/emails/access-approved.txt',
            html_template='sentry/emails/access-approved.html',
            context=context,
        )

        msg.send_async([email])
示例#21
0
    def send_invite_email(self):
        from sentry.utils.email import MessageBuilder

        context = {
            "email": self.email,
            "organization": self.organization,
            "url": self.get_invite_link(),
        }

        msg = MessageBuilder(
            subject="Join %s in using Sentry" % self.organization.name,
            template="sentry/emails/member-invite.txt",
            html_template="sentry/emails/member-invite.html",
            type="organization.invite",
            context=context,
        )

        try:
            msg.send_async([self.get_email()])
        except Exception as e:
            logger = get_logger(name="sentry.mail")
            logger.exception(e)
示例#22
0
    def send_invite_email(self):
        from sentry.utils.email import MessageBuilder

        context = {
            'email': self.email,
            'organization': self.organization,
            'url': self.get_invite_link(),
        }

        msg = MessageBuilder(
            subject='Join %s in using Sentry' % self.organization.name,
            template='sentry/emails/member-invite.txt',
            html_template='sentry/emails/member-invite.html',
            type='organization.invite',
            context=context,
        )

        try:
            msg.send_async([self.get_email()])
        except Exception as e:
            logger = get_logger(name='sentry.mail')
            logger.exception(e)
    def send_approved_email(self):
        from sentry.utils.email import MessageBuilder

        user = self.member.user
        email = user.email
        organization = self.team.organization

        context = {
            'email': email,
            'name': user.get_display_name(),
            'organization': organization,
            'team': self.team,
        }

        msg = MessageBuilder(
            subject='Sentry Access Request',
            template='sentry/emails/access-approved.txt',
            html_template='sentry/emails/access-approved.html',
            context=context,
        )

        msg.send_async([email])
示例#24
0
    def send_email(self, request, mode="recover"):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            "user": self.user,
            "domain": get_server_hostname(),
            "url": self.get_absolute_url(mode),
            "datetime": timezone.now(),
            "ip_address": request.META["REMOTE_ADDR"],
        }

        template = "set_password" if mode == "set_password" else "recover_account"

        msg = MessageBuilder(
            subject="{}Password Recovery".format(options.get("mail.subject-prefix")),
            template="sentry/emails/{name}.txt".format(name=template),
            html_template="sentry/emails/{name}.html".format(name=template),
            type="user.password_recovery",
            context=context,
        )
        msg.send_async([self.user.email])
示例#25
0
    def send_email(self, request, mode='recover'):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            'user': self.user,
            'domain': get_server_hostname(),
            'url': self.get_absolute_url(mode),
            'datetime': timezone.now(),
            'ip_address': request.META['REMOTE_ADDR'],
        }

        template = 'set_password' if mode == 'set_password' else 'recover_account'

        msg = MessageBuilder(
            subject=u'{}Password Recovery'.format(options.get('mail.subject-prefix')),
            template=u'sentry/emails/{name}.txt'.format(name=template),
            html_template=u'sentry/emails/{name}.html'.format(name=template),
            type='user.password_recovery',
            context=context,
        )
        msg.send_async([self.user.email])
示例#26
0
    def send_email(self, request, mode='recover'):
        from sentry import options
        from sentry.http import get_server_hostname
        from sentry.utils.email import MessageBuilder

        context = {
            'user': self.user,
            'domain': get_server_hostname(),
            'url': self.get_absolute_url(mode),
            'datetime': timezone.now(),
            'ip_address': request.META['REMOTE_ADDR'],
        }

        template = 'set_password' if mode == 'set_password' else 'recover_account'

        msg = MessageBuilder(
            subject=u'{}Password Recovery'.format(options.get('mail.subject-prefix')),
            template=u'sentry/emails/{name}.txt'.format(name=template),
            html_template=u'sentry/emails/{name}.html'.format(name=template),
            type='user.password_recovery',
            context=context,
        )
        msg.send_async([self.user.email])
示例#27
0
    def send_sso_link_email(self):
        from sentry.utils.email import MessageBuilder

        context = {
            'email':
            self.email,
            'organization_name':
            self.organization.name,
            'url':
            absolute_uri(
                reverse('sentry-auth-link-identity',
                        kwargs={
                            'organization_slug': self.organization.slug,
                        })),
        }

        msg = MessageBuilder(
            subject='Action Required for %s' % (self.organization.name, ),
            template='sentry/emails/auth-link-identity.txt',
            html_template='sentry/emails/auth-link-identity.html',
            context=context,
        )
        msg.send_async([self.get_email()])
    def send_approved_email(self):
        from sentry.utils.email import MessageBuilder

        user = self.member.user
        email = user.email
        organization = self.team.organization

        context = {
            "email": email,
            "name": user.get_display_name(),
            "organization": organization,
            "team": self.team,
        }

        msg = MessageBuilder(
            subject="Sentry Access Request",
            template="sentry/emails/access-approved.txt",
            html_template="sentry/emails/access-approved.html",
            type="team.access.approved",
            context=context,
        )

        msg.send_async([email])
    def send_sso_unlink_email(self, actor, provider):
        from sentry.utils.email import MessageBuilder
        from sentry.models import LostPasswordHash

        email = self.get_email()

        recover_uri = '{path}?{query}'.format(
            path=reverse('sentry-account-recover'),
            query=urlencode({'email': email}),
        )

        # Nothing to send if this member isn't associated to a user
        if not self.user_id:
            return

        context = {
            'email': email,
            'recover_url': absolute_uri(recover_uri),
            'has_password': self.user.password,
            'organization': self.organization,
            'actor': actor,
            'provider': provider,
        }

        if not self.user.password:
            password_hash = LostPasswordHash.for_user(self.user)
            context['set_password_url'] = password_hash.get_absolute_url(
                mode='set_password')

        msg = MessageBuilder(
            subject='Action Required for %s' % (self.organization.name, ),
            template='sentry/emails/auth-sso-disabled.txt',
            html_template='sentry/emails/auth-sso-disabled.html',
            type='organization.auth_sso_disabled',
            context=context,
        )
        msg.send_async([email])
    def send_request_email(self):
        from sentry.models import OrganizationMember
        from sentry.utils.email import MessageBuilder

        user = self.member.user
        email = user.email
        organization = self.team.organization

        context = {
            "email": email,
            "name": user.get_display_name(),
            "organization": organization,
            "team": self.team,
            "url": absolute_uri(
                reverse("sentry-organization-members", kwargs={"organization_slug": organization.slug})
                + "?ref=access-requests"
            ),
        }

        msg = MessageBuilder(
            subject="Sentry Access Request",
            template="sentry/emails/request-team-access.txt",
            html_template="sentry/emails/request-team-access.html",
            context=context,
        )

        global_roles = [r.id for r in roles.with_scope("org:write") if r.is_global]
        team_roles = [r.id for r in roles.with_scope("team:write")]

        # find members which are either team scoped or have access to all teams
        member_list = OrganizationMember.objects.filter(
            Q(role__in=global_roles) | Q(teams=self.team, role__in=team_roles),
            organization=self.team.organization,
            user__isnull=False,
        ).select_related("user")

        msg.send_async([m.user.email for m in member_list])
示例#31
0
    def send_sso_unlink_email(self, actor, provider):
        from sentry.models import LostPasswordHash
        from sentry.utils.email import MessageBuilder

        email = self.get_email()

        recover_uri = "{path}?{query}".format(
            path=reverse("sentry-account-recover"),
            query=urlencode({"email": email}))

        # Nothing to send if this member isn't associated to a user
        if not self.user_id:
            return

        context = {
            "email": email,
            "recover_url": absolute_uri(recover_uri),
            "has_password": self.user.password,
            "organization": self.organization,
            "actor": actor,
            "provider": provider,
        }

        if not self.user.password:
            password_hash = LostPasswordHash.for_user(self.user)
            context["set_password_url"] = password_hash.get_absolute_url(
                mode="set_password")

        msg = MessageBuilder(
            subject=f"Action Required for {self.organization.name}",
            template="sentry/emails/auth-sso-disabled.txt",
            html_template="sentry/emails/auth-sso-disabled.html",
            type="organization.auth_sso_disabled",
            context=context,
        )
        msg.send_async([email])
示例#32
0
    def send_setup_2fa_emails(self):
        from sentry import options
        from sentry.utils.email import MessageBuilder
        from sentry.models import User

        for user in User.objects.filter(
            is_active=True,
            sentry_orgmember_set__organization=self,
        ):
            if not Authenticator.objects.user_has_2fa(user):
                context = {
                    'user': user,
                    'url': absolute_uri(reverse('sentry-account-settings-2fa')),
                    'organization': self
                }
                message = MessageBuilder(
                    subject='%s %s Mandatory: Enable Two-Factor Authentication' % (
                        options.get('mail.subject-prefix'), self.name),
                    template='sentry/emails/setup_2fa.txt',
                    html_template='sentry/emails/setup_2fa.html',
                    type='user.setup_2fa',
                    context=context,
                )
                message.send_async([user.email])
示例#33
0
    def send_confirm_email_singular(self, email, is_new_user=False):
        from sentry import options
        from sentry.utils.email import MessageBuilder

        if not email.hash_is_valid():
            email.set_hash()
            email.save()

        context = {
            "user": self,
            "url": absolute_uri(
                reverse("sentry-account-confirm-email", args=[self.id, email.validation_hash])
            ),
            "confirm_email": email.email,
            "is_new_user": is_new_user,
        }
        msg = MessageBuilder(
            subject="{}Confirm Email".format(options.get("mail.subject-prefix")),
            template="sentry/emails/confirm_email.txt",
            html_template="sentry/emails/confirm_email.html",
            type="user.confirm_email",
            context=context,
        )
        msg.send_async([email.email])
示例#34
0
    def call_to_action(self, org: Organization, user: User,
                       member: OrganizationMember):
        import django.contrib.auth.models

        if isinstance(user, django.contrib.auth.models.User):
            # TODO(RyanSkonnord): Add test to repro this case (or delete check if unable)
            logger.warning(
                "Could not send verified email compliance notification (non-Sentry User model)"
            )
            return
        elif not isinstance(user, User):
            raise TypeError(user)

        email = UserEmail.objects.get_primary_email(user)
        email_context = {
            "confirm_url":
            absolute_uri(
                reverse("sentry-account-confirm-email",
                        args=[user.id, email.validation_hash])),
            "invite_url":
            member.get_invite_link(),
            "email":
            email.email,
            "organization":
            org,
        }
        subject = "{} {} Mandatory: Verify Email Address".format(
            options.get("mail.subject-prefix"), org.name.capitalize())
        message = MessageBuilder(
            subject=subject,
            template="sentry/emails/setup_email.txt",
            html_template="sentry/emails/setup_email.html",
            type="user.setup_email",
            context=email_context,
        )
        message.send_async([email])
示例#35
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()
示例#36
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('/{}/{}/'.format(
                project.organization.slug,
                project.slug,
            )),
            'issue_link':
            absolute_uri('/{}/{}/issues/{}/'.format(
                project.organization.slug,
                project.slug,
                payload['report']['issue']['id'],
            )),
            # TODO(dcramer): we dont have permalinks to feedback yet
            'link':
            absolute_uri('/{}/{}/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()
示例#37
0
    def handle_user_report(self, payload, project, **kwargs):
        metrics.incr("mail_adapter.handle_user_report")
        group = Group.objects.get(id=payload["report"]["issue"]["id"])

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

        if not participants:
            return

        org = group.organization
        enhanced_privacy = org.flags.enhanced_privacy

        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"],
            "enhanced_privacy":
            enhanced_privacy,
        }

        subject_prefix = self._build_subject_prefix(project)
        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()
    def post(self, request, organization):
        """
        Email the organization owners asking them to install an integration.
        ````````````````````````````````````````````````````````````````````
        When a non-owner user views integrations in the integrations directory,
        they lack the ability to install them themselves. POSTing to this API
        alerts users with permission that there is demand for this integration.

        :param string providerSlug: Unique string that identifies the integration.
        :param string providerType: One of: first_party, plugin, sentry_app.
        :param string message: Optional message from the requester to the owners.
        """

        provider_type = request.data.get("providerType")
        provider_slug = request.data.get("providerSlug")
        message_option = request.data.get("message", "").strip()

        try:
            provider_name = get_provider_name(provider_type, provider_slug)
        except RuntimeError as error:
            return Response({"detail": force_text(error)}, status=400)

        requester = request.user
        owners_list = organization.get_owners()

        # If for some reason the user had permissions all along, silently fail.
        if requester.id in [user.id for user in owners_list]:
            return Response({"detail": "User can install integration"},
                            status=200)

        msg = MessageBuilder(
            subject="Your team member requested the %s integration on Sentry" %
            provider_name,
            template="sentry/emails/requests/organization-integration.txt",
            html_template=
            "sentry/emails/requests/organization-integration.html",
            type="organization.integration.request",
            context={
                "integration_link":
                get_url(organization, provider_type, provider_slug),
                "integration_name":
                provider_name,
                "message":
                message_option,
                "organization_name":
                organization.name,
                "requester_name":
                requester.name or requester.username,
                "requester_link":
                absolute_uri(
                    "/settings/{organization_slug}/members/{user_id}/".format(
                        organization_slug=organization.slug,
                        user_id=requester.id,
                    )),
                "settings_link":
                absolute_uri(
                    reverse("sentry-organization-settings",
                            args=[organization.slug])),
            },
        )
        msg.send_async([user.email for user in owners_list])

        return Response(status=201)
示例#39
0
def send_invite_request_notification_email(member_id):
    try:
        om = OrganizationMember.objects.select_related(
            "inviter", "organization").get(id=member_id)
    except OrganizationMember.DoesNotExist:
        return

    link_args = {"organization_slug": om.organization.slug}

    context = {
        "email":
        om.email,
        "organization_name":
        om.organization.name,
        "pending_requests_link":
        absolute_uri(reverse("sentry-organization-members", kwargs=link_args)),
    }

    if om.requested_to_join:
        email_args = {
            "template": "sentry/emails/organization-join-request.txt",
            "html_template": "sentry/emails/organization-join-request.html",
        }
        context["settings_link"] = absolute_uri(
            reverse("sentry-organization-settings",
                    args=[om.organization.slug]))

    elif om.requested_to_be_invited:
        email_args = {
            "template": "sentry/emails/organization-invite-request.txt",
            "html_template": "sentry/emails/organization-invite-request.html",
        }
        context["inviter_name"] = om.inviter.get_salutation_name
    else:
        raise RuntimeError("This member is not pending invitation")

    recipients = OrganizationMember.objects.select_related("user").filter(
        organization_id=om.organization_id,
        user__isnull=False,
        invite_status=InviteStatus.APPROVED.value,
        role__in=(r.id for r in roles.get_all()
                  if r.has_scope("member:write")),
    )

    msg = MessageBuilder(
        subject=f"Access request to {om.organization.name}",
        type="organization.invite-request",
        context=context,
        **email_args,
    )

    for recipient in recipients:
        try:
            msg.send_async([recipient.get_email()])
        except Exception as e:
            logger = get_logger(name="sentry.mail")
            logger.exception(e)
        analytics.record(
            "invite_request.sent",
            organization_id=om.organization.id,
            user_id=om.inviter.id if om.inviter else None,
            target_user_id=recipient.id,
            providers="email",
        )
示例#40
0
    def send_request_notification_email(self):
        from sentry.utils.email import MessageBuilder

        link_args = {"organization_slug": self.organization.slug}

        context = {
            "email":
            self.email,
            "inviter":
            self.inviter,
            "organization":
            self.organization,
            "organization_link":
            absolute_uri(
                reverse("sentry-organization-index",
                        args=[self.organization.slug])),
            "pending_requests_link":
            absolute_uri(
                reverse("sentry-organization-members-requests",
                        kwargs=link_args)),
            "settings_link":
            absolute_uri(
                reverse("sentry-organization-settings",
                        args=[self.organization.slug])),
        }

        if self.requested_to_join:
            email_args = {
                "template": "sentry/emails/organization-join-request.txt",
                "html_template":
                "sentry/emails/organization-join-request.html",
            }
        elif self.requested_to_be_invited:
            email_args = {
                "template": "sentry/emails/organization-invite-request.txt",
                "html_template":
                "sentry/emails/organization-invite-request.html",
            }
        else:
            raise RuntimeError("This member is not pending invitation")

        recipients = OrganizationMember.objects.select_related("user").filter(
            organization_id=self.organization_id,
            user__isnull=False,
            invite_status=InviteStatus.APPROVED.value,
            role__in=(r.id for r in roles.get_all()
                      if r.has_scope("member:write")),
        )

        msg = MessageBuilder(subject="Access request to %s" %
                             (self.organization.name, ),
                             type="organization.invite-request",
                             context=context,
                             **email_args)

        for recipient in recipients:
            try:
                msg.send_async([recipient.get_email()])
            except Exception as e:
                logger = get_logger(name="sentry.mail")
                logger.exception(e)
示例#41
0
文件: activity.py 项目: Natim/sentry
    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()
示例#42
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()
示例#43
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()
示例#44
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.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()
示例#45
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.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()