Пример #1
0
    def consume(self, data: Mapping[str, Any]) -> None:
        if "email" in data:
            # When upgrading from a version up through 1.7.1, there may be
            # existing items in the queue with `email` instead of `prereg_id`.
            invitee = PreregistrationUser.objects.filter(
                email__iexact=data["email"].strip()).latest("invited_at")
        else:
            invitee = PreregistrationUser.objects.filter(id=data["prereg_id"]).first()
            if invitee is None:
                # The invitation could have been revoked
                return

        referrer = get_user_profile_by_id(data["referrer_id"])
        logger.info("Sending invitation for realm %s to %s" % (referrer.realm.string_id, invitee.email))
        do_send_confirmation_email(invitee, referrer)

        # queue invitation reminder for two days from now.
        link = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION)
        context = common_context(referrer)
        context.update({
            'activate_url': link,
            'referrer_name': referrer.full_name,
            'referrer_email': referrer.email,
            'referrer_realm_name': referrer.realm.name,
        })
        send_future_email(
            "zerver/emails/invitation_reminder",
            referrer.realm,
            to_emails=[invitee.email],
            from_address=FromAddress.tokenized_no_reply_address(),
            language=referrer.realm.default_language,
            context=context,
            delay=datetime.timedelta(days=2))
Пример #2
0
    def consume(self, data: Mapping[str, Any]) -> None:
        if "email" in data:
            # When upgrading from a version up through 1.7.1, there may be
            # existing items in the queue with `email` instead of `prereg_id`.
            invitee = PreregistrationUser.objects.filter(
                email__iexact=data["email"].strip()).latest("invited_at")
        else:
            invitee = PreregistrationUser.objects.filter(
                id=data["prereg_id"]).first()
            if invitee is None:
                # The invitation could have been revoked
                return

        referrer = get_user_profile_by_id(data["referrer_id"])
        logger.info("Sending invitation for realm %s to %s" %
                    (referrer.realm.string_id, invitee.email))
        do_send_confirmation_email(invitee, referrer)

        # queue invitation reminder for two days from now.
        link = create_confirmation_link(invitee, referrer.realm.host,
                                        Confirmation.INVITATION)
        context = common_context(referrer)
        context.update({
            'activate_url': link,
            'referrer_name': referrer.full_name,
            'referrer_email': referrer.email,
            'referrer_realm_name': referrer.realm.name,
        })
        send_future_email(
            "zerver/emails/invitation_reminder",
            referrer.realm,
            to_emails=[invitee.email],
            from_address=FromAddress.tokenized_no_reply_address(),
            context=context,
            delay=datetime.timedelta(days=2))
Пример #3
0
def do_send_confirmation_email(
    invitee: PreregistrationUser,
    referrer: UserProfile,
    email_language: str,
    invite_expires_in_minutes: Union[Optional[int],
                                     UnspecifiedValue] = UnspecifiedValue(),
) -> str:
    """
    Send the confirmation/welcome e-mail to an invited user.
    """
    activation_url = create_confirmation_link(
        invitee,
        Confirmation.INVITATION,
        validity_in_minutes=invite_expires_in_minutes)
    context = {
        "referrer_full_name": referrer.full_name,
        "referrer_email": referrer.delivery_email,
        "activate_url": activation_url,
        "referrer_realm_name": referrer.realm.name,
    }
    send_email(
        "zerver/emails/invitation",
        to_emails=[invitee.email],
        from_address=FromAddress.tokenized_no_reply_address(),
        language=email_language,
        context=context,
        realm=referrer.realm,
    )
    return activation_url
Пример #4
0
def downgrade_small_realms_behind_on_payments_as_needed() -> None:
    customers = Customer.objects.all().exclude(stripe_customer_id=None)
    for customer in customers:
        realm = customer.realm

        # For larger realms, we generally want to talk to the customer
        # before downgrading or cancelling invoices; so this logic only applies with 5.
        if get_latest_seat_count(realm) >= 5:
            continue

        if get_current_plan_by_customer(customer) is not None:
            # Only customers with last 2 invoices open should be downgraded.
            if not customer_has_last_n_invoices_open(customer, 2):
                continue

            # We've now decided to downgrade this customer and void all invoices, and the below will execute this.

            downgrade_now_without_creating_additional_invoices(realm)
            void_all_open_invoices(realm)
            context: Dict[str, Union[str, Realm]] = {
                "upgrade_url": f"{realm.uri}{reverse('initial_upgrade')}",
                "realm": realm,
            }
            send_email_to_billing_admins_and_realm_owners(
                "zerver/emails/realm_auto_downgraded",
                realm,
                from_name=FromAddress.security_email_from_name(language=realm.default_language),
                from_address=FromAddress.tokenized_no_reply_address(),
                language=realm.default_language,
                context=context,
            )
        else:
            if customer_has_last_n_invoices_open(customer, 1):
                void_all_open_invoices(realm)
Пример #5
0
def send_confirm_registration_email(email: str, activation_url: str,
                                    language: str) -> None:
    send_email('zerver/emails/confirm_registration',
               to_emails=[email],
               from_address=FromAddress.tokenized_no_reply_address(),
               language=language,
               context={'activate_url': activation_url})
Пример #6
0
def do_start_email_change_process(user_profile: UserProfile,
                                  new_email: str) -> None:
    old_email = user_profile.delivery_email
    obj = EmailChangeStatus.objects.create(
        new_email=new_email,
        old_email=old_email,
        user_profile=user_profile,
        realm=user_profile.realm,
    )

    activation_url = create_confirmation_link(obj, Confirmation.EMAIL_CHANGE)
    from zerver.context_processors import common_context

    context = common_context(user_profile)
    context.update(
        old_email=old_email,
        new_email=new_email,
        activate_url=activation_url,
    )
    language = user_profile.default_language
    send_email(
        "zerver/emails/confirm_new_email",
        to_emails=[new_email],
        from_name=FromAddress.security_email_from_name(language=language),
        from_address=FromAddress.tokenized_no_reply_address(),
        language=language,
        context=context,
        realm=user_profile.realm,
    )
Пример #7
0
    def handle(self, *args: Any, **kwargs: str) -> None:
        if settings.WARN_NO_EMAIL:
            raise CommandError(
                "Outgoing email not yet configured, see\n  "
                "https://zulip.readthedocs.io/en/latest/production/email.html")
        if len(kwargs["email"]) == 0:
            raise CommandError(
                "Usage: /home/zulip/deployments/current/manage.py "
                "send_test_email [email protected]")

        print("If you run into any trouble, read:")
        print()
        print(
            "  https://zulip.readthedocs.io/en/latest/production/email.html#troubleshooting"
        )
        print()
        print(
            "The most common error is not setting `ADD_TOKENS_TO_NOREPLY_ADDRESS=False` when"
        )
        print("using an email provider that doesn't support that feature.")
        print()
        print("Sending 2 test emails from:")

        message = (
            "Success!  If you receive this message (and a second with a different subject), "
            "you've successfully configured sending emails from your Zulip server.  "
            "Remember that you need to restart "
            "the Zulip server with /home/zulip/deployments/current/scripts/restart-server "
            "after changing the settings in /etc/zulip before your changes will take effect."
        )
        with redirect_stderr(io.StringIO()) as f:
            smtplib.SMTP.debuglevel = 1
            try:
                sender = FromAddress.SUPPORT
                print(f"  * {sender}")
                send_mail("Zulip email test", message, sender, kwargs["email"])

                noreply_sender = FromAddress.tokenized_no_reply_address()
                print(f"  * {noreply_sender}")
                send_mail("Zulip noreply email test", message, noreply_sender,
                          kwargs["email"])
            except smtplib.SMTPException as e:
                print(f"Failed to send mails: {e}")
                print()
                print("Full SMTP log follows:")
                print(f.getvalue())
                raise CommandError("Email sending failed!")
        print()
        print("Successfully sent 2 emails to {}!".format(", ".join(
            kwargs["email"])))

        if kwargs["managers"]:
            mail_managers("Zulip manager email test",
                          "This email was sent to the site managers.")

        if kwargs["admins"]:
            mail_admins("Zulip admins email test",
                        "This email was sent to the site admins.")
Пример #8
0
def send_confirm_registration_email(
    email: str, activation_url: str, language: str, realm: Optional[Realm] = None
) -> None:
    send_email(
        "zerver/emails/confirm_registration",
        to_emails=[email],
        from_address=FromAddress.tokenized_no_reply_address(),
        language=language,
        context={"activate_url": activation_url},
        realm=realm,
    )
Пример #9
0
    def send(self, users: List[UserProfile]) -> None:
        """Sends one-use only links for resetting password to target users

        """
        for user_profile in users:
            context = {
                'email': user_profile.email,
                'reset_url': generate_password_reset_url(user_profile, default_token_generator),
                'realm_uri': user_profile.realm.uri,
                'active_account_in_realm': True,
            }
            send_email('zerver/emails/password_reset', to_user_id=user_profile.id,
                       from_address=FromAddress.tokenized_no_reply_address(),
                       from_name="Zulip Account Security", context=context)
Пример #10
0
    def send(self, users: List[UserProfile]) -> None:
        """Sends one-use only links for resetting password to target users

        """
        for user_profile in users:
            context = {
                'email': user_profile.email,
                'reset_url': generate_password_reset_url(user_profile, default_token_generator),
                'realm_uri': user_profile.realm.uri,
                'active_account_in_realm': True,
            }
            send_email('zerver/emails/password_reset', to_user_ids=[user_profile.id],
                       from_address=FromAddress.tokenized_no_reply_address(),
                       from_name="Zulip Account Security", context=context)
Пример #11
0
    def handle(self, *args: Any, **kwargs: str) -> None:
        if settings.WARN_NO_EMAIL:
            raise CommandError(
                "Outgoing email not yet configured, see\n  "
                "https://zulip.readthedocs.io/en/latest/production/email.html")
        if len(kwargs['email']) == 0:
            raise CommandError(
                "Usage: /home/zulip/deployments/current/manage.py "
                "send_test_email [email protected]")

        print("If you run into any trouble, read:")
        print()
        print(
            "  https://zulip.readthedocs.io/en/latest/production/email.html#troubleshooting"
        )
        print()
        print(
            "The most common error is not setting `ADD_TOKENS_TO_NOREPLY_ADDRESS=False` when"
        )
        print("using an email provider that doesn't support that feature.")
        print()
        print("Sending 2 test emails from:")

        message = (
            "Success!  If you receive this message (and a second with a different subject), "
            "you've successfully configured sending emails from your Zulip server.  "
            "Remember that you need to restart "
            "the Zulip server with /home/zulip/deployments/current/scripts/restart-server "
            "after changing the settings in /etc/zulip before your changes will take effect."
        )
        sender = FromAddress.SUPPORT
        print("  * %s" % (sender, ))
        send_mail("Zulip email test", message, sender, kwargs['email'])
        noreply_sender = FromAddress.tokenized_no_reply_address()
        print("  * %s" % (noreply_sender, ))
        send_mail("Zulip noreply email test", message, noreply_sender,
                  kwargs['email'])
        print()
        print("Successfully sent 2 emails to %s!" %
              (", ".join(kwargs['email'])))

        if kwargs['managers']:
            mail_managers("Zulip manager email test",
                          "This email was sent to the site managers.")

        if kwargs['admins']:
            mail_admins("Zulip admins email test",
                        "This email was sent to the site admins.")
Пример #12
0
def sponsorship(
    request: HttpRequest,
    user: UserProfile,
    organization_type: str = REQ("organization-type", validator=check_string),
    website: str = REQ("website", validator=check_string),
    description: str = REQ("description", validator=check_string)
) -> HttpResponse:
    realm = user.realm

    requested_by = user.full_name

    role_id_to_name_map = {
        UserProfile.ROLE_REALM_OWNER: "Realm owner",
        UserProfile.ROLE_REALM_ADMINISTRATOR: "Realm adminstrator",
        UserProfile.ROLE_MEMBER: "Member",
        UserProfile.ROLE_GUEST: "Guest"
    }
    user_role = role_id_to_name_map[user.role]

    support_realm_uri = get_realm(settings.STAFF_SUBDOMAIN).uri
    support_url = urljoin(
        support_realm_uri,
        urlunsplit(("", "", reverse('analytics.views.support'),
                    urlencode({"q": realm.string_id}), "")))

    context = {
        "requested_by": requested_by,
        "user_role": user_role,
        "string_id": realm.string_id,
        "support_url": support_url,
        "organization_type": organization_type,
        "website": website,
        "description": description,
    }
    send_email(
        "zerver/emails/sponsorship_request",
        to_emails=[FromAddress.SUPPORT],
        from_name="Zulip sponsorship",
        from_address=FromAddress.tokenized_no_reply_address(),
        reply_to_email=user.delivery_email,
        context=context,
    )

    update_sponsorship_status(realm, True)
    user.is_billing_admin = True
    user.save(update_fields=["is_billing_admin"])

    return json_success()
 def send(self, users: List[UserProfile]) -> None:
     """Sends one-use only links for resetting password to target users"""
     for user_profile in users:
         context = {
             "email": user_profile.delivery_email,
             "reset_url": generate_password_reset_url(user_profile, default_token_generator),
             "realm_uri": user_profile.realm.uri,
             "realm_name": user_profile.realm.name,
             "active_account_in_realm": True,
         }
         send_email(
             "zerver/emails/password_reset",
             to_user_ids=[user_profile.id],
             from_address=FromAddress.tokenized_no_reply_address(),
             from_name=FromAddress.security_email_from_name(user_profile=user_profile),
             context=context,
         )
Пример #14
0
    def handle(self, *args: Any, **kwargs: str) -> None:
        if settings.WARN_NO_EMAIL:
            raise CommandError("Outgoing email not yet configured, see\n  "
                               "https://zulip.readthedocs.io/en/latest/production/email.html")
        message = ("Success!  If you receive this message, you've "
                   "successfully configured sending email from your "
                   "Zulip server.  Remember that you need to restart "
                   "the Zulip server with /home/zulip/deployments/current/scripts/restart-server "
                   "after changing the settings in /etc/zulip before your changes will take effect.")
        send_mail("Zulip email test", message, FromAddress.SUPPORT, kwargs['email'])
        send_mail("Zulip noreply email test", message, FromAddress.tokenized_no_reply_address(), kwargs['email'])

        if kwargs['managers']:
            mail_managers("Zulip manager email test", "This email was sent to the site managers.")

        if kwargs['admins']:
            mail_admins("Zulip admins email test", "This email was sent to the site admins.")
Пример #15
0
def sponsorship(
    request: HttpRequest,
    user: UserProfile,
    organization_type: str = REQ("organization-type",
                                 json_validator=check_string),
    website: str = REQ("website", json_validator=check_string),
    description: str = REQ("description", json_validator=check_string),
) -> HttpResponse:
    realm = user.realm

    requested_by = user.full_name
    user_role = user.get_role_name()

    support_realm_uri = get_realm(settings.STAFF_SUBDOMAIN).uri
    support_url = urljoin(
        support_realm_uri,
        urlunsplit(
            ("", "", reverse("support"), urlencode({"q":
                                                    realm.string_id}), "")),
    )

    context = {
        "requested_by": requested_by,
        "user_role": user_role,
        "string_id": realm.string_id,
        "support_url": support_url,
        "organization_type": organization_type,
        "website": website,
        "description": description,
    }
    send_email(
        "zerver/emails/sponsorship_request",
        to_emails=[FromAddress.SUPPORT],
        from_name="Zulip sponsorship",
        from_address=FromAddress.tokenized_no_reply_address(),
        reply_to_email=user.delivery_email,
        context=context,
    )

    update_sponsorship_status(realm, True, acting_user=user)
    user.is_billing_admin = True
    user.save(update_fields=["is_billing_admin"])

    return json_success()
Пример #16
0
def send_confirm_registration_email(
    email: str,
    activation_url: str,
    *,
    realm: Optional[Realm] = None,
    request: Optional[HttpRequest] = None,
) -> None:
    send_email(
        "zerver/emails/confirm_registration",
        to_emails=[email],
        from_address=FromAddress.tokenized_no_reply_address(),
        language=request.LANGUAGE_CODE if request is not None else None,
        context={
            "create_realm": (realm is None),
            "activate_url": activation_url,
        },
        realm=realm,
        request=request,
    )
Пример #17
0
def downgrade_small_realms_behind_on_payments_as_needed() -> None:
    customers = Customer.objects.all()
    for customer in customers:
        realm = customer.realm

        # For larger realms, we generally want to talk to the customer
        # before downgrading; so this logic only applies with 5.
        if get_latest_seat_count(realm) >= 5:
            continue

        if get_current_plan_by_customer(customer) is None:
            continue

        due_invoice_count = 0
        for invoice in stripe.Invoice.list(
                customer=customer.stripe_customer_id, limit=2):
            if invoice.status == "open":
                due_invoice_count += 1

        # Customers with only 1 overdue invoice are ignored.
        if due_invoice_count < 2:
            continue

        # We've now decided to downgrade this customer and void all invoices, and the below will execute this.

        downgrade_now_without_creating_additional_invoices(realm)
        void_all_open_invoices(realm)
        context: Dict[str, str] = {
            "upgrade_url": f"{realm.uri}{reverse('initial_upgrade')}",
            "realm": realm,
        }
        send_email_to_billing_admins_and_realm_owners(
            "zerver/emails/realm_auto_downgraded",
            realm,
            from_name=FromAddress.security_email_from_name(
                language=realm.default_language),
            from_address=FromAddress.tokenized_no_reply_address(),
            language=realm.default_language,
            context=context,
        )
Пример #18
0
def support_request(request: HttpRequest) -> HttpResponse:
    user = request.user
    assert user.is_authenticated

    context = {
        "email": user.delivery_email,
        "realm_name": user.realm.name,
        "MAX_SUBJECT_LENGTH": SupportRequestForm.MAX_SUBJECT_LENGTH,
    }

    if request.POST:
        post_data = request.POST.copy()
        form = SupportRequestForm(post_data)

        if form.is_valid():
            email_context = {
                "requested_by": user.full_name,
                "realm_string_id": user.realm.string_id,
                "request_subject": form.cleaned_data["request_subject"],
                "request_message": form.cleaned_data["request_message"],
                "support_url": get_support_url(user.realm),
                "user_role": user.get_role_name(),
            }

            send_email(
                "zerver/emails/support_request",
                to_emails=[FromAddress.SUPPORT],
                from_name="Zulip Support",
                from_address=FromAddress.tokenized_no_reply_address(),
                reply_to_email=user.delivery_email,
                context=email_context,
            )

            response = render(request, "corporate/support_request_thanks.html", context=context)
            return response

    response = render(request, "corporate/support_request.html", context=context)
    return response
Пример #19
0
def do_send_realm_reactivation_email(
        realm: Realm, *, acting_user: Optional[UserProfile]) -> None:
    url = create_confirmation_link(realm, Confirmation.REALM_REACTIVATION)
    RealmAuditLog.objects.create(
        realm=realm,
        acting_user=acting_user,
        event_type=RealmAuditLog.REALM_REACTIVATION_EMAIL_SENT,
        event_time=timezone_now(),
    )
    context = {
        "confirmation_url": url,
        "realm_uri": realm.uri,
        "realm_name": realm.name
    }
    language = realm.default_language
    send_email_to_admins(
        "zerver/emails/realm_reactivation",
        realm,
        from_address=FromAddress.tokenized_no_reply_address(),
        from_name=FromAddress.security_email_from_name(language=language),
        language=language,
        context=context,
    )
Пример #20
0
    def save(
            self,
            domain_override: Optional[bool] = None,
            subject_template_name:
        str = 'registration/password_reset_subject.txt',
            email_template_name: str = 'registration/password_reset_email.html',
            use_https: bool = False,
            token_generator:
        PasswordResetTokenGenerator = default_token_generator,
            from_email: Optional[str] = None,
            request: HttpRequest = None,
            html_email_template_name: Optional[str] = None,
            extra_email_context: Optional[Dict[str, Any]] = None) -> None:
        """
        If the email address has an account in the target realm,
        generates a one-use only link for resetting password and sends
        to the user.

        We send a different email if an associated account does not exist in the
        database, or an account does exist, but not in the realm.

        Note: We ignore protocol and the various email template arguments (those
        are an artifact of using Django's password reset framework).
        """
        email = self.cleaned_data["email"]

        realm = get_realm(get_subdomain(request))

        if not email_auth_enabled(realm):
            logging.info(
                "Password reset attempted for %s even though password auth is disabled."
                % (email, ))
            return
        if email_belongs_to_ldap(realm, email):
            # TODO: Ideally, we'd provide a user-facing error here
            # about the fact that they aren't allowed to have a
            # password in the Zulip server and should change it in LDAP.
            logging.info("Password reset not allowed for user in LDAP domain")
            return
        if realm.deactivated:
            logging.info("Realm is deactivated")
            return

        user = None  # type: Optional[UserProfile]
        try:
            user = get_active_user(email, realm)
        except UserProfile.DoesNotExist:
            pass

        context = {
            'email': email,
            'realm_uri': realm.uri,
        }

        if user is not None:
            token = token_generator.make_token(user)
            uid = urlsafe_base64_encode(force_bytes(user.id)).decode('ascii')
            endpoint = reverse(
                'django.contrib.auth.views.password_reset_confirm',
                kwargs=dict(uidb64=uid, token=token))

            context['no_account_in_realm'] = False
            context['reset_url'] = "{}{}".format(user.realm.uri, endpoint)
            send_email('zerver/emails/password_reset',
                       to_user_id=user.id,
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       context=context)
        else:
            context['no_account_in_realm'] = True
            active_accounts = UserProfile.objects.filter(email__iexact=email,
                                                         is_active=True)
            if active_accounts:
                context['active_accounts'] = active_accounts
                context['multiple_active_accounts'] = active_accounts.count(
                ) != 1
            send_email('zerver/emails/password_reset',
                       to_email=email,
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       context=context)
Пример #21
0
    def save(self,
             domain_override: Optional[bool]=None,
             subject_template_name: str='registration/password_reset_subject.txt',
             email_template_name: str='registration/password_reset_email.html',
             use_https: bool=False,
             token_generator: PasswordResetTokenGenerator=default_token_generator,
             from_email: Optional[str]=None,
             request: HttpRequest=None,
             html_email_template_name: Optional[str]=None,
             extra_email_context: Optional[Dict[str, Any]]=None
             ) -> None:
        """
        If the email address has an account in the target realm,
        generates a one-use only link for resetting password and sends
        to the user.

        We send a different email if an associated account does not exist in the
        database, or an account does exist, but not in the realm.

        Note: We ignore protocol and the various email template arguments (those
        are an artifact of using Django's password reset framework).
        """
        email = self.cleaned_data["email"]

        realm = get_realm(get_subdomain(request))

        if not email_auth_enabled(realm):
            logging.info("Password reset attempted for %s even though password auth is disabled." % (email,))
            return
        if email_belongs_to_ldap(realm, email):
            # TODO: Ideally, we'd provide a user-facing error here
            # about the fact that they aren't allowed to have a
            # password in the Zulip server and should change it in LDAP.
            logging.info("Password reset not allowed for user in LDAP domain")
            return
        if realm.deactivated:
            logging.info("Realm is deactivated")
            return

        user = None  # type: Optional[UserProfile]
        try:
            user = get_user_by_delivery_email(email, realm)
        except UserProfile.DoesNotExist:
            pass

        context = {
            'email': email,
            'realm_uri': realm.uri,
            'realm_name': realm.name,
        }

        if user is not None and not user.is_active:
            context['user_deactivated'] = True
            user = None

        if user is not None:
            context['active_account_in_realm'] = True
            context['reset_url'] = generate_password_reset_url(user, token_generator)
            send_email('zerver/emails/password_reset', to_user_ids=[user.id],
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       context=context)
        else:
            context['active_account_in_realm'] = False
            active_accounts_in_other_realms = UserProfile.objects.filter(
                delivery_email__iexact=email, is_active=True)
            if active_accounts_in_other_realms:
                context['active_accounts_in_other_realms'] = active_accounts_in_other_realms
            send_email('zerver/emails/password_reset', to_emails=[email],
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       language=request.LANGUAGE_CODE,
                       context=context)
Пример #22
0
    def save(
        self,
        domain_override: Optional[str] = None,
        subject_template_name: str = "registration/password_reset_subject.txt",
        email_template_name: str = "registration/password_reset_email.html",
        use_https: bool = False,
        token_generator: PasswordResetTokenGenerator = default_token_generator,
        from_email: Optional[str] = None,
        request: Optional[HttpRequest] = None,
        html_email_template_name: Optional[str] = None,
        extra_email_context: Optional[Dict[str, Any]] = None,
    ) -> None:
        """
        If the email address has an account in the target realm,
        generates a one-use only link for resetting password and sends
        to the user.

        We send a different email if an associated account does not exist in the
        database, or an account does exist, but not in the realm.

        Note: We ignore protocol and the various email template arguments (those
        are an artifact of using Django's password reset framework).
        """
        email = self.cleaned_data["email"]
        # The form is only used in zerver.views.auth.password_rest, we know that
        # the request must not be None
        assert request is not None

        realm = get_realm(get_subdomain(request))

        if not email_auth_enabled(realm):
            logging.info(
                "Password reset attempted for %s even though password auth is disabled.",
                email)
            return
        if email_belongs_to_ldap(realm, email):
            # TODO: Ideally, we'd provide a user-facing error here
            # about the fact that they aren't allowed to have a
            # password in the Zulip server and should change it in LDAP.
            logging.info("Password reset not allowed for user in LDAP domain")
            return
        if realm.deactivated:
            logging.info("Realm is deactivated")
            return

        if settings.RATE_LIMITING:
            try:
                rate_limit_password_reset_form_by_email(email)
                rate_limit_request_by_ip(request, domain="sends_email_by_ip")
            except RateLimited:
                logging.info(
                    "Too many password reset attempts for email %s from %s",
                    email,
                    request.META["REMOTE_ADDR"],
                )
                # The view will handle the RateLimit exception and render an appropriate page
                raise

        user: Optional[UserProfile] = None
        try:
            user = get_user_by_delivery_email(email, realm)
        except UserProfile.DoesNotExist:
            pass

        context = {
            "email": email,
            "realm_uri": realm.uri,
            "realm_name": realm.name,
        }

        if user is not None and not user.is_active:
            context["user_deactivated"] = True
            user = None

        if user is not None:
            context["active_account_in_realm"] = True
            context["reset_url"] = generate_password_reset_url(
                user, token_generator)
            queue_soft_reactivation(user.id)
            send_email(
                "zerver/emails/password_reset",
                to_user_ids=[user.id],
                from_name=FromAddress.security_email_from_name(
                    user_profile=user),
                from_address=FromAddress.tokenized_no_reply_address(),
                context=context,
                realm=realm,
                request=request,
            )
        else:
            context["active_account_in_realm"] = False
            active_accounts_in_other_realms = UserProfile.objects.filter(
                delivery_email__iexact=email, is_active=True)
            if active_accounts_in_other_realms:
                context[
                    "active_accounts_in_other_realms"] = active_accounts_in_other_realms
            language = get_language()

            send_email(
                "zerver/emails/password_reset",
                to_emails=[email],
                from_name=FromAddress.security_email_from_name(
                    language=language),
                from_address=FromAddress.tokenized_no_reply_address(),
                language=language,
                context=context,
                realm=realm,
                request=request,
            )
Пример #23
0
    def save(self,
             domain_override: Optional[bool]=None,
             subject_template_name: str='registration/password_reset_subject.txt',
             email_template_name: str='registration/password_reset_email.html',
             use_https: bool=False,
             token_generator: PasswordResetTokenGenerator=default_token_generator,
             from_email: Optional[str]=None,
             request: HttpRequest=None,
             html_email_template_name: Optional[str]=None,
             extra_email_context: Optional[Dict[str, Any]]=None
             ) -> None:
        """
        If the email address has an account in the target realm,
        generates a one-use only link for resetting password and sends
        to the user.

        We send a different email if an associated account does not exist in the
        database, or an account does exist, but not in the realm.

        Note: We ignore protocol and the various email template arguments (those
        are an artifact of using Django's password reset framework).
        """
        email = self.cleaned_data["email"]

        realm = get_realm(get_subdomain(request))

        if not email_auth_enabled(realm):
            logging.info("Password reset attempted for %s even though password auth is disabled." % (email,))
            return
        if email_belongs_to_ldap(realm, email):
            # TODO: Ideally, we'd provide a user-facing error here
            # about the fact that they aren't allowed to have a
            # password in the Zulip server and should change it in LDAP.
            logging.info("Password reset not allowed for user in LDAP domain")
            return
        if realm.deactivated:
            logging.info("Realm is deactivated")
            return

        user = None  # type: Optional[UserProfile]
        try:
            user = get_user_by_delivery_email(email, realm)
        except UserProfile.DoesNotExist:
            pass

        context = {
            'email': email,
            'realm_uri': realm.uri,
            'realm_name': realm.name,
        }

        if user is not None and not user.is_active:
            context['user_deactivated'] = True
            user = None

        if user is not None:
            context['active_account_in_realm'] = True
            context['reset_url'] = generate_password_reset_url(user, token_generator)
            send_email('zerver/emails/password_reset', to_user_ids=[user.id],
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       context=context)
        else:
            context['active_account_in_realm'] = False
            active_accounts_in_other_realms = UserProfile.objects.filter(
                delivery_email__iexact=email, is_active=True)
            if active_accounts_in_other_realms:
                context['active_accounts_in_other_realms'] = active_accounts_in_other_realms
            send_email('zerver/emails/password_reset', to_emails=[email],
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       language=request.LANGUAGE_CODE,
                       context=context)
Пример #24
0
    def save(self,
             domain_override: Optional[bool]=None,
             subject_template_name: str='registration/password_reset_subject.txt',
             email_template_name: str='registration/password_reset_email.html',
             use_https: bool=False,
             token_generator: PasswordResetTokenGenerator=default_token_generator,
             from_email: Optional[str]=None,
             request: HttpRequest=None,
             html_email_template_name: Optional[str]=None,
             extra_email_context: Optional[Dict[str, Any]]=None
             ) -> None:
        """
        If the email address has an account in the target realm,
        generates a one-use only link for resetting password and sends
        to the user.

        We send a different email if an associated account does not exist in the
        database, or an account does exist, but not in the realm.

        Note: We ignore protocol and the various email template arguments (those
        are an artifact of using Django's password reset framework).
        """
        email = self.cleaned_data["email"]

        realm = get_realm(get_subdomain(request))

        if not email_auth_enabled(realm):
            logging.info("Password reset attempted for %s even though password auth is disabled." % (email,))
            return
        if email_belongs_to_ldap(realm, email):
            # TODO: Ideally, we'd provide a user-facing error here
            # about the fact that they aren't allowed to have a
            # password in the Zulip server and should change it in LDAP.
            logging.info("Password reset not allowed for user in LDAP domain")
            return
        if realm.deactivated:
            logging.info("Realm is deactivated")
            return

        user = None  # type: Optional[UserProfile]
        try:
            user = get_active_user(email, realm)
        except UserProfile.DoesNotExist:
            pass

        context = {
            'email': email,
            'realm_uri': realm.uri,
        }

        if user is not None:
            token = token_generator.make_token(user)
            uid = urlsafe_base64_encode(force_bytes(user.id)).decode('ascii')
            endpoint = reverse('django.contrib.auth.views.password_reset_confirm',
                               kwargs=dict(uidb64=uid, token=token))

            context['no_account_in_realm'] = False
            context['reset_url'] = "{}{}".format(user.realm.uri, endpoint)
            send_email('zerver/emails/password_reset', to_user_id=user.id,
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       context=context)
        else:
            context['no_account_in_realm'] = True
            accounts = UserProfile.objects.filter(email__iexact=email)
            if accounts:
                context['accounts'] = accounts
                context['multiple_accounts'] = accounts.count() != 1
            send_email('zerver/emails/password_reset', to_email=email,
                       from_name="Zulip Account Security",
                       from_address=FromAddress.tokenized_no_reply_address(),
                       context=context)
Пример #25
0
def sponsorship(
        request: HttpRequest,
        user: UserProfile,
        organization_type: str = REQ("organization-type"),
        website: str = REQ(),
        description: str = REQ(),
) -> HttpResponse:
    realm = user.realm

    requested_by = user.full_name
    user_role = user.get_role_name()
    support_url = get_support_url(realm)

    post_data = request.POST.copy()
    # We need to do this because the field name in the template
    # for organization type contains a hyphen and the form expects
    # an underscore.
    post_data.update(organization_type=organization_type)
    form = SponsorshipRequestForm(post_data)

    if form.is_valid():
        with transaction.atomic():
            sponsorship_request = ZulipSponsorshipRequest(
                realm=realm,
                requested_by=user,
                org_website=form.cleaned_data["website"],
                org_description=form.cleaned_data["description"],
                org_type=form.cleaned_data["organization_type"],
            )
            sponsorship_request.save()

            org_type = form.cleaned_data["organization_type"]
            if realm.org_type != org_type:
                realm.org_type = org_type
                realm.save(update_fields=["org_type"])

            update_sponsorship_status(realm, True, acting_user=user)
            do_make_user_billing_admin(user)

            org_type_display_name = get_org_type_display_name(org_type)

        context = {
            "requested_by": requested_by,
            "user_role": user_role,
            "string_id": realm.string_id,
            "support_url": support_url,
            "organization_type": org_type_display_name,
            "website": website,
            "description": description,
        }
        send_email(
            "zerver/emails/sponsorship_request",
            to_emails=[FromAddress.SUPPORT],
            from_name="Zulip sponsorship",
            from_address=FromAddress.tokenized_no_reply_address(),
            reply_to_email=user.delivery_email,
            context=context,
        )

        return json_success(request)
    else:
        messages = []
        for error_list in form.errors.get_json_data().values():
            for error in error_list:
                messages.append(error["message"])
        message = " ".join(messages)
        raise BillingError("Form validation error", message=message)
Пример #26
0
def sponsorship(
    request: HttpRequest,
    user: UserProfile,
    organization_type: str = REQ("organization-type"),
    website: str = REQ(),
    description: str = REQ(),
) -> HttpResponse:
    realm = user.realm

    requested_by = user.full_name
    user_role = user.get_role_name()

    support_realm_uri = get_realm(settings.STAFF_SUBDOMAIN).uri
    support_url = urljoin(
        support_realm_uri,
        urlunsplit(("", "", reverse("support"), urlencode({"q": realm.string_id}), "")),
    )

    post_data = request.POST.copy()
    # We need to do this because the field name in the template
    # for organization type contains a hyphen and the form expects
    # an underscore.
    post_data.update(organization_type=organization_type)
    form = SponsorshipRequestForm(post_data)

    with transaction.atomic():
        if form.is_valid():
            sponsorship_request = ZulipSponsorshipRequest(
                realm=realm,
                requested_by=user,
                org_website=form.cleaned_data["website"],
                org_description=form.cleaned_data["description"],
                org_type=form.cleaned_data["organization_type"],
            )
            sponsorship_request.save()

            org_type = form.cleaned_data["organization_type"]
            if realm.org_type != org_type:
                realm.org_type = org_type
                realm.save(update_fields=["org_type"])

        update_sponsorship_status(realm, True, acting_user=user)
        do_make_user_billing_admin(user)

    org_type_display_name = get_org_type_display_name(org_type)

    context = {
        "requested_by": requested_by,
        "user_role": user_role,
        "string_id": realm.string_id,
        "support_url": support_url,
        "organization_type": org_type_display_name,
        "website": website,
        "description": description,
    }
    send_email(
        "zerver/emails/sponsorship_request",
        to_emails=[FromAddress.SUPPORT],
        from_name="Zulip sponsorship",
        from_address=FromAddress.tokenized_no_reply_address(),
        reply_to_email=user.delivery_email,
        context=context,
    )

    return json_success()
Пример #27
0
def send_confirm_registration_email(email: str, activation_url: str) -> None:
    send_email('zerver/emails/confirm_registration', to_email=email,
               from_address=FromAddress.tokenized_no_reply_address(),
               context={'activate_url': activation_url})