We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Too many redirects for a account during login of deactivated account
I deactivated my Zulip account and then signed up again and tried to sign in. For wrong password, it showed wrong password, when i entered correct credentials, chrome showed
```
chat.zulip.org redirected you too many times.
Try clearing your cookies.
ERR_TOO_MANY_REDIRECTS
```
Clearing cookies did not work as a solution for it.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `zerver/forms.py`
Content:
```
1 from __future__ import absolute_import
2 
3 from django import forms
4 from django.conf import settings
5 from django.contrib.auth.forms import SetPasswordForm, AuthenticationForm, \
6     PasswordResetForm
7 from django.core.exceptions import ValidationError
8 from django.core.urlresolvers import reverse
9 from django.core.validators import validate_email
10 from django.db.models.query import QuerySet
11 from django.utils.translation import ugettext as _
12 from jinja2 import Markup as mark_safe
13 
14 from zerver.lib.actions import do_change_password, is_inactive, user_email_is_unique
15 from zerver.lib.name_restrictions import is_reserved_subdomain, is_disposable_domain
16 from zerver.lib.request import JsonableError
17 from zerver.lib.send_email import send_email
18 from zerver.lib.users import check_full_name
19 from zerver.lib.utils import get_subdomain, check_subdomain
20 from zerver.models import Realm, get_user_profile_by_email, UserProfile, \
21     get_realm_by_email_domain, get_realm, \
22     get_unique_open_realm, email_to_domain, email_allowed_for_realm
23 from zproject.backends import password_auth_enabled
24 
25 import logging
26 import re
27 import DNS
28 
29 from typing import Any, Callable, List, Optional, Text, Dict
30 
31 MIT_VALIDATION_ERROR = u'That user does not exist at MIT or is a ' + \
32                        u'<a href="https://ist.mit.edu/email-lists">mailing list</a>. ' + \
33                        u'If you want to sign up an alias for Zulip, ' + \
34                        u'<a href="mailto:support@zulipchat.com">contact us</a>.'
35 WRONG_SUBDOMAIN_ERROR = "Your Zulip account is not a member of the " + \
36                         "organization associated with this subdomain.  " + \
37                         "Please contact %s with any questions!" % (settings.ZULIP_ADMINISTRATOR,)
38 
39 def email_is_not_mit_mailing_list(email):
40     # type: (Text) -> None
41     """Prevent MIT mailing lists from signing up for Zulip"""
42     if "@mit.edu" in email:
43         username = email.rsplit("@", 1)[0]
44         # Check whether the user exists and can get mail.
45         try:
46             DNS.dnslookup("%s.pobox.ns.athena.mit.edu" % username, DNS.Type.TXT)
47         except DNS.Base.ServerError as e:
48             if e.rcode == DNS.Status.NXDOMAIN:
49                 raise ValidationError(mark_safe(MIT_VALIDATION_ERROR))
50             else:
51                 raise
52 
53 class RegistrationForm(forms.Form):
54     MAX_PASSWORD_LENGTH = 100
55     full_name = forms.CharField(max_length=100)
56     # The required-ness of the password field gets overridden if it isn't
57     # actually required for a realm
58     password = forms.CharField(widget=forms.PasswordInput, max_length=MAX_PASSWORD_LENGTH,
59                                required=False)
60     realm_subdomain = forms.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH, required=False)
61     realm_org_type = forms.ChoiceField(((Realm.COMMUNITY, 'Community'),
62                                         (Realm.CORPORATE, 'Corporate')),
63                                        initial=Realm.COMMUNITY, required=False)
64 
65     def __init__(self, *args, **kwargs):
66         # type: (*Any, **Any) -> None
67 
68         # Since the superclass doesn't except random extra kwargs, we
69         # remove it from the kwargs dict before initializing.
70         realm_creation = kwargs['realm_creation']
71         del kwargs['realm_creation']
72 
73         super(RegistrationForm, self).__init__(*args, **kwargs)
74         if settings.TERMS_OF_SERVICE:
75             self.fields['terms'] = forms.BooleanField(required=True)
76         self.fields['realm_name'] = forms.CharField(
77             max_length=Realm.MAX_REALM_NAME_LENGTH,
78             required=realm_creation)
79 
80     def clean_full_name(self):
81         # type: () -> Text
82         try:
83             return check_full_name(self.cleaned_data['full_name'])
84         except JsonableError as e:
85             raise ValidationError(e.error)
86 
87     def clean_realm_subdomain(self):
88         # type: () -> str
89         if settings.REALMS_HAVE_SUBDOMAINS:
90             error_strings = {
91                 'too short': _("Subdomain needs to have length 3 or greater."),
92                 'extremal dash': _("Subdomain cannot start or end with a '-'."),
93                 'bad character': _("Subdomain can only have lowercase letters, numbers, and '-'s."),
94                 'unavailable': _("Subdomain unavailable. Please choose a different one.")}
95         else:
96             error_strings = {
97                 'too short': _("Short name needs at least 3 characters."),
98                 'extremal dash': _("Short name cannot start or end with a '-'."),
99                 'bad character': _("Short name can only have lowercase letters, numbers, and '-'s."),
100                 'unavailable': _("Short name unavailable. Please choose a different one.")}
101         subdomain = self.cleaned_data['realm_subdomain']
102         if not subdomain:
103             return ''
104         if len(subdomain) < 3:
105             raise ValidationError(error_strings['too short'])
106         if subdomain[0] == '-' or subdomain[-1] == '-':
107             raise ValidationError(error_strings['extremal dash'])
108         if not re.match('^[a-z0-9-]*$', subdomain):
109             raise ValidationError(error_strings['bad character'])
110         if is_reserved_subdomain(subdomain) or \
111            get_realm(subdomain) is not None:
112             raise ValidationError(error_strings['unavailable'])
113         return subdomain
114 
115 class ToSForm(forms.Form):
116     terms = forms.BooleanField(required=True)
117 
118 class HomepageForm(forms.Form):
119     email = forms.EmailField(validators=[is_inactive])
120 
121     def __init__(self, *args, **kwargs):
122         # type: (*Any, **Any) -> None
123         self.realm = kwargs.pop('realm', None)
124         super(HomepageForm, self).__init__(*args, **kwargs)
125 
126     def clean_email(self):
127         # type: () -> str
128         """Returns the email if and only if the user's email address is
129         allowed to join the realm they are trying to join."""
130         email = self.cleaned_data['email']
131 
132         if get_unique_open_realm():
133             return email
134 
135         # Otherwise, the user is trying to join a specific realm.
136         realm = self.realm
137         if realm is None and not settings.REALMS_HAVE_SUBDOMAINS:
138             realm = get_realm_by_email_domain(email)
139 
140         if realm is None:
141             if settings.REALMS_HAVE_SUBDOMAINS:
142                 raise ValidationError(_("The organization you are trying to "
143                                         "join using {email} does not "
144                                         "exist.").format(email=email))
145             else:
146                 raise ValidationError(_("Your email address, {email}, does not "
147                                         "correspond to any existing "
148                                         "organization.").format(email=email))
149 
150         if realm.invite_required:
151             raise ValidationError(_("Please request an invite for {email} "
152                                     "from the organization "
153                                     "administrator.").format(email=email))
154 
155         if not email_allowed_for_realm(email, realm):
156             raise ValidationError(
157                 _("Your email address, {email}, is not in one of the domains "
158                   "that are allowed to register for accounts in this organization.").format(
159                       string_id=realm.string_id, email=email))
160 
161         if realm.is_zephyr_mirror_realm:
162             email_is_not_mit_mailing_list(email)
163 
164         return email
165 
166 def email_is_not_disposable(email):
167     # type: (Text) -> None
168     if is_disposable_domain(email_to_domain(email)):
169         raise ValidationError(_("Please use your real email address."))
170 
171 class RealmCreationForm(forms.Form):
172     # This form determines whether users can create a new realm.
173     email = forms.EmailField(validators=[user_email_is_unique, email_is_not_disposable])
174 
175 class LoggingSetPasswordForm(SetPasswordForm):
176     def save(self, commit=True):
177         # type: (bool) -> UserProfile
178         do_change_password(self.user, self.cleaned_data['new_password1'],
179                            commit=commit)
180         return self.user
181 
182 class ZulipPasswordResetForm(PasswordResetForm):
183     def get_users(self, email):
184         # type: (str) -> QuerySet
185         """Given an email, return matching user(s) who should receive a reset.
186 
187         This is modified from the original in that it allows non-bot
188         users who don't have a usable password to reset their
189         passwords.
190         """
191         if not password_auth_enabled:
192             logging.info("Password reset attempted for %s even though password auth is disabled." % (email,))
193             return []
194         result = UserProfile.objects.filter(email__iexact=email, is_active=True,
195                                             is_bot=False)
196         if len(result) == 0:
197             logging.info("Password reset attempted for %s; no active account." % (email,))
198         return result
199 
200     def send_mail(self, subject_template_name, email_template_name,
201                   context, from_email, to_email, html_email_template_name=None):
202         # type: (str, str, Dict[str, Any], str, str, str) -> None
203         """
204         Currently we don't support accounts in multiple subdomains using
205         a single email address. We override this function so that we do
206         not send a reset link to an email address if the reset attempt is
207         done on the subdomain which does not match user.realm.subdomain.
208 
209         Once we start supporting accounts with the same email in
210         multiple subdomains, we may be able to refactor this function.
211 
212         A second reason we override this function is so that we can send
213         the mail through the functions in zerver.lib.send_email, to match
214         how we send all other mail in the codebase.
215         """
216         user_realm = get_user_profile_by_email(to_email).realm
217         attempted_subdomain = get_subdomain(getattr(self, 'request'))
218         context['attempted_realm'] = False
219         if not check_subdomain(user_realm.subdomain, attempted_subdomain):
220             context['attempted_realm'] = get_realm(attempted_subdomain)
221 
222         send_email('zerver/emails/password_reset', to_email, from_email=from_email,
223                    context=context)
224 
225     def save(self, *args, **kwargs):
226         # type: (*Any, **Any) -> None
227         """Currently we don't support accounts in multiple subdomains using
228         a single email addresss. We override this function so that we can
229         inject request parameter in context. This parameter will be used
230         by send_mail function.
231 
232         Once we start supporting accounts with the same email in
233         multiple subdomains, we may be able to delete or refactor this
234         function.
235         """
236         setattr(self, 'request', kwargs.get('request'))
237         super(ZulipPasswordResetForm, self).save(*args, **kwargs)
238 
239 class CreateUserForm(forms.Form):
240     full_name = forms.CharField(max_length=100)
241     email = forms.EmailField()
242 
243 class OurAuthenticationForm(AuthenticationForm):
244     def clean_username(self):
245         # type: () -> str
246         email = self.cleaned_data['username']
247         try:
248             user_profile = get_user_profile_by_email(email)
249         except UserProfile.DoesNotExist:
250             return email
251 
252         if user_profile.realm.deactivated:
253             error_msg = u"""Sorry for the trouble, but %s has been deactivated.
254 
255 Please contact %s to reactivate this group.""" % (
256                 user_profile.realm.name,
257                 settings.ZULIP_ADMINISTRATOR)
258             raise ValidationError(mark_safe(error_msg))
259 
260         if not check_subdomain(get_subdomain(self.request), user_profile.realm.subdomain):
261             logging.warning("User %s attempted to password login to wrong subdomain %s" %
262                             (user_profile.email, get_subdomain(self.request)))
263             raise ValidationError(mark_safe(WRONG_SUBDOMAIN_ERROR))
264         return email
265 
266 class MultiEmailField(forms.Field):
267     def to_python(self, emails):
268         # type: (Text) -> List[Text]
269         """Normalize data to a list of strings."""
270         if not emails:
271             return []
272 
273         return [email.strip() for email in emails.split(',')]
274 
275     def validate(self, emails):
276         # type: (List[Text]) -> None
277         """Check if value consists only of valid emails."""
278         super(MultiEmailField, self).validate(emails)
279         for email in emails:
280             validate_email(email)
281 
282 class FindMyTeamForm(forms.Form):
283     emails = MultiEmailField(
284         help_text=_("Add up to 10 comma-separated email addresses."))
285 
286     def clean_emails(self):
287         # type: () -> List[Text]
288         emails = self.cleaned_data['emails']
289         if len(emails) > 10:
290             raise forms.ValidationError(_("Please enter at most 10 emails."))
291 
292         return emails
293
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/zerver/forms.py b/zerver/forms.py
--- a/zerver/forms.py
+++ b/zerver/forms.py
@@ -257,6 +257,12 @@
                 settings.ZULIP_ADMINISTRATOR)
             raise ValidationError(mark_safe(error_msg))
 
+        if not user_profile.is_active:
+            error_msg = (u"Sorry for the trouble, but your account has been "
+                         u"deactivated. Please contact %s to reactivate "
+                         u"it.") % (settings.ZULIP_ADMINISTRATOR,)
+            raise ValidationError(mark_safe(error_msg))
+
         if not check_subdomain(get_subdomain(self.request), user_profile.realm.subdomain):
             logging.warning("User %s attempted to password login to wrong subdomain %s" %
                             (user_profile.email, get_subdomain(self.request)))

{"golden_diff": "diff --git a/zerver/forms.py b/zerver/forms.py\n--- a/zerver/forms.py\n+++ b/zerver/forms.py\n@@ -257,6 +257,12 @@\n                 settings.ZULIP_ADMINISTRATOR)\n             raise ValidationError(mark_safe(error_msg))\n \n+        if not user_profile.is_active:\n+            error_msg = (u\"Sorry for the trouble, but your account has been \"\n+                         u\"deactivated. Please contact %s to reactivate \"\n+                         u\"it.\") % (settings.ZULIP_ADMINISTRATOR,)\n+            raise ValidationError(mark_safe(error_msg))\n+\n         if not check_subdomain(get_subdomain(self.request), user_profile.realm.subdomain):\n             logging.warning(\"User %s attempted to password login to wrong subdomain %s\" %\n                             (user_profile.email, get_subdomain(self.request)))\n", "issue": "Too many redirects for a account during login of deactivated account\nI deactivated my Zulip account and then signed up again and tried to sign in. For wrong password, it showed wrong password, when i entered correct credentials, chrome showed\r\n```\r\nchat.zulip.org redirected you too many times.\r\nTry clearing your cookies.\r\nERR_TOO_MANY_REDIRECTS\r\n```\r\nClearing cookies did not work as a solution for it.\n", "before_files": [{"content": "from __future__ import absolute_import\n\nfrom django import forms\nfrom django.conf import settings\nfrom django.contrib.auth.forms import SetPasswordForm, AuthenticationForm, \\\n    PasswordResetForm\nfrom django.core.exceptions import ValidationError\nfrom django.core.urlresolvers import reverse\nfrom django.core.validators import validate_email\nfrom django.db.models.query import QuerySet\nfrom django.utils.translation import ugettext as _\nfrom jinja2 import Markup as mark_safe\n\nfrom zerver.lib.actions import do_change_password, is_inactive, user_email_is_unique\nfrom zerver.lib.name_restrictions import is_reserved_subdomain, is_disposable_domain\nfrom zerver.lib.request import JsonableError\nfrom zerver.lib.send_email import send_email\nfrom zerver.lib.users import check_full_name\nfrom zerver.lib.utils import get_subdomain, check_subdomain\nfrom zerver.models import Realm, get_user_profile_by_email, UserProfile, \\\n    get_realm_by_email_domain, get_realm, \\\n    get_unique_open_realm, email_to_domain, email_allowed_for_realm\nfrom zproject.backends import password_auth_enabled\n\nimport logging\nimport re\nimport DNS\n\nfrom typing import Any, Callable, List, Optional, Text, Dict\n\nMIT_VALIDATION_ERROR = u'That user does not exist at MIT or is a ' + \\\n                       u'<a href=\"https://ist.mit.edu/email-lists\">mailing list</a>. ' + \\\n                       u'If you want to sign up an alias for Zulip, ' + \\\n                       u'<a href=\"mailto:support@zulipchat.com\">contact us</a>.'\nWRONG_SUBDOMAIN_ERROR = \"Your Zulip account is not a member of the \" + \\\n                        \"organization associated with this subdomain.  \" + \\\n                        \"Please contact %s with any questions!\" % (settings.ZULIP_ADMINISTRATOR,)\n\ndef email_is_not_mit_mailing_list(email):\n    # type: (Text) -> None\n    \"\"\"Prevent MIT mailing lists from signing up for Zulip\"\"\"\n    if \"@mit.edu\" in email:\n        username = email.rsplit(\"@\", 1)[0]\n        # Check whether the user exists and can get mail.\n        try:\n            DNS.dnslookup(\"%s.pobox.ns.athena.mit.edu\" % username, DNS.Type.TXT)\n        except DNS.Base.ServerError as e:\n            if e.rcode == DNS.Status.NXDOMAIN:\n                raise ValidationError(mark_safe(MIT_VALIDATION_ERROR))\n            else:\n                raise\n\nclass RegistrationForm(forms.Form):\n    MAX_PASSWORD_LENGTH = 100\n    full_name = forms.CharField(max_length=100)\n    # The required-ness of the password field gets overridden if it isn't\n    # actually required for a realm\n    password = forms.CharField(widget=forms.PasswordInput, max_length=MAX_PASSWORD_LENGTH,\n                               required=False)\n    realm_subdomain = forms.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH, required=False)\n    realm_org_type = forms.ChoiceField(((Realm.COMMUNITY, 'Community'),\n                                        (Realm.CORPORATE, 'Corporate')),\n                                       initial=Realm.COMMUNITY, required=False)\n\n    def __init__(self, *args, **kwargs):\n        # type: (*Any, **Any) -> None\n\n        # Since the superclass doesn't except random extra kwargs, we\n        # remove it from the kwargs dict before initializing.\n        realm_creation = kwargs['realm_creation']\n        del kwargs['realm_creation']\n\n        super(RegistrationForm, self).__init__(*args, **kwargs)\n        if settings.TERMS_OF_SERVICE:\n            self.fields['terms'] = forms.BooleanField(required=True)\n        self.fields['realm_name'] = forms.CharField(\n            max_length=Realm.MAX_REALM_NAME_LENGTH,\n            required=realm_creation)\n\n    def clean_full_name(self):\n        # type: () -> Text\n        try:\n            return check_full_name(self.cleaned_data['full_name'])\n        except JsonableError as e:\n            raise ValidationError(e.error)\n\n    def clean_realm_subdomain(self):\n        # type: () -> str\n        if settings.REALMS_HAVE_SUBDOMAINS:\n            error_strings = {\n                'too short': _(\"Subdomain needs to have length 3 or greater.\"),\n                'extremal dash': _(\"Subdomain cannot start or end with a '-'.\"),\n                'bad character': _(\"Subdomain can only have lowercase letters, numbers, and '-'s.\"),\n                'unavailable': _(\"Subdomain unavailable. Please choose a different one.\")}\n        else:\n            error_strings = {\n                'too short': _(\"Short name needs at least 3 characters.\"),\n                'extremal dash': _(\"Short name cannot start or end with a '-'.\"),\n                'bad character': _(\"Short name can only have lowercase letters, numbers, and '-'s.\"),\n                'unavailable': _(\"Short name unavailable. Please choose a different one.\")}\n        subdomain = self.cleaned_data['realm_subdomain']\n        if not subdomain:\n            return ''\n        if len(subdomain) < 3:\n            raise ValidationError(error_strings['too short'])\n        if subdomain[0] == '-' or subdomain[-1] == '-':\n            raise ValidationError(error_strings['extremal dash'])\n        if not re.match('^[a-z0-9-]*$', subdomain):\n            raise ValidationError(error_strings['bad character'])\n        if is_reserved_subdomain(subdomain) or \\\n           get_realm(subdomain) is not None:\n            raise ValidationError(error_strings['unavailable'])\n        return subdomain\n\nclass ToSForm(forms.Form):\n    terms = forms.BooleanField(required=True)\n\nclass HomepageForm(forms.Form):\n    email = forms.EmailField(validators=[is_inactive])\n\n    def __init__(self, *args, **kwargs):\n        # type: (*Any, **Any) -> None\n        self.realm = kwargs.pop('realm', None)\n        super(HomepageForm, self).__init__(*args, **kwargs)\n\n    def clean_email(self):\n        # type: () -> str\n        \"\"\"Returns the email if and only if the user's email address is\n        allowed to join the realm they are trying to join.\"\"\"\n        email = self.cleaned_data['email']\n\n        if get_unique_open_realm():\n            return email\n\n        # Otherwise, the user is trying to join a specific realm.\n        realm = self.realm\n        if realm is None and not settings.REALMS_HAVE_SUBDOMAINS:\n            realm = get_realm_by_email_domain(email)\n\n        if realm is None:\n            if settings.REALMS_HAVE_SUBDOMAINS:\n                raise ValidationError(_(\"The organization you are trying to \"\n                                        \"join using {email} does not \"\n                                        \"exist.\").format(email=email))\n            else:\n                raise ValidationError(_(\"Your email address, {email}, does not \"\n                                        \"correspond to any existing \"\n                                        \"organization.\").format(email=email))\n\n        if realm.invite_required:\n            raise ValidationError(_(\"Please request an invite for {email} \"\n                                    \"from the organization \"\n                                    \"administrator.\").format(email=email))\n\n        if not email_allowed_for_realm(email, realm):\n            raise ValidationError(\n                _(\"Your email address, {email}, is not in one of the domains \"\n                  \"that are allowed to register for accounts in this organization.\").format(\n                      string_id=realm.string_id, email=email))\n\n        if realm.is_zephyr_mirror_realm:\n            email_is_not_mit_mailing_list(email)\n\n        return email\n\ndef email_is_not_disposable(email):\n    # type: (Text) -> None\n    if is_disposable_domain(email_to_domain(email)):\n        raise ValidationError(_(\"Please use your real email address.\"))\n\nclass RealmCreationForm(forms.Form):\n    # This form determines whether users can create a new realm.\n    email = forms.EmailField(validators=[user_email_is_unique, email_is_not_disposable])\n\nclass LoggingSetPasswordForm(SetPasswordForm):\n    def save(self, commit=True):\n        # type: (bool) -> UserProfile\n        do_change_password(self.user, self.cleaned_data['new_password1'],\n                           commit=commit)\n        return self.user\n\nclass ZulipPasswordResetForm(PasswordResetForm):\n    def get_users(self, email):\n        # type: (str) -> QuerySet\n        \"\"\"Given an email, return matching user(s) who should receive a reset.\n\n        This is modified from the original in that it allows non-bot\n        users who don't have a usable password to reset their\n        passwords.\n        \"\"\"\n        if not password_auth_enabled:\n            logging.info(\"Password reset attempted for %s even though password auth is disabled.\" % (email,))\n            return []\n        result = UserProfile.objects.filter(email__iexact=email, is_active=True,\n                                            is_bot=False)\n        if len(result) == 0:\n            logging.info(\"Password reset attempted for %s; no active account.\" % (email,))\n        return result\n\n    def send_mail(self, subject_template_name, email_template_name,\n                  context, from_email, to_email, html_email_template_name=None):\n        # type: (str, str, Dict[str, Any], str, str, str) -> None\n        \"\"\"\n        Currently we don't support accounts in multiple subdomains using\n        a single email address. We override this function so that we do\n        not send a reset link to an email address if the reset attempt is\n        done on the subdomain which does not match user.realm.subdomain.\n\n        Once we start supporting accounts with the same email in\n        multiple subdomains, we may be able to refactor this function.\n\n        A second reason we override this function is so that we can send\n        the mail through the functions in zerver.lib.send_email, to match\n        how we send all other mail in the codebase.\n        \"\"\"\n        user_realm = get_user_profile_by_email(to_email).realm\n        attempted_subdomain = get_subdomain(getattr(self, 'request'))\n        context['attempted_realm'] = False\n        if not check_subdomain(user_realm.subdomain, attempted_subdomain):\n            context['attempted_realm'] = get_realm(attempted_subdomain)\n\n        send_email('zerver/emails/password_reset', to_email, from_email=from_email,\n                   context=context)\n\n    def save(self, *args, **kwargs):\n        # type: (*Any, **Any) -> None\n        \"\"\"Currently we don't support accounts in multiple subdomains using\n        a single email addresss. We override this function so that we can\n        inject request parameter in context. This parameter will be used\n        by send_mail function.\n\n        Once we start supporting accounts with the same email in\n        multiple subdomains, we may be able to delete or refactor this\n        function.\n        \"\"\"\n        setattr(self, 'request', kwargs.get('request'))\n        super(ZulipPasswordResetForm, self).save(*args, **kwargs)\n\nclass CreateUserForm(forms.Form):\n    full_name = forms.CharField(max_length=100)\n    email = forms.EmailField()\n\nclass OurAuthenticationForm(AuthenticationForm):\n    def clean_username(self):\n        # type: () -> str\n        email = self.cleaned_data['username']\n        try:\n            user_profile = get_user_profile_by_email(email)\n        except UserProfile.DoesNotExist:\n            return email\n\n        if user_profile.realm.deactivated:\n            error_msg = u\"\"\"Sorry for the trouble, but %s has been deactivated.\n\nPlease contact %s to reactivate this group.\"\"\" % (\n                user_profile.realm.name,\n                settings.ZULIP_ADMINISTRATOR)\n            raise ValidationError(mark_safe(error_msg))\n\n        if not check_subdomain(get_subdomain(self.request), user_profile.realm.subdomain):\n            logging.warning(\"User %s attempted to password login to wrong subdomain %s\" %\n                            (user_profile.email, get_subdomain(self.request)))\n            raise ValidationError(mark_safe(WRONG_SUBDOMAIN_ERROR))\n        return email\n\nclass MultiEmailField(forms.Field):\n    def to_python(self, emails):\n        # type: (Text) -> List[Text]\n        \"\"\"Normalize data to a list of strings.\"\"\"\n        if not emails:\n            return []\n\n        return [email.strip() for email in emails.split(',')]\n\n    def validate(self, emails):\n        # type: (List[Text]) -> None\n        \"\"\"Check if value consists only of valid emails.\"\"\"\n        super(MultiEmailField, self).validate(emails)\n        for email in emails:\n            validate_email(email)\n\nclass FindMyTeamForm(forms.Form):\n    emails = MultiEmailField(\n        help_text=_(\"Add up to 10 comma-separated email addresses.\"))\n\n    def clean_emails(self):\n        # type: () -> List[Text]\n        emails = self.cleaned_data['emails']\n        if len(emails) > 10:\n            raise forms.ValidationError(_(\"Please enter at most 10 emails.\"))\n\n        return emails\n", "path": "zerver/forms.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nfrom django import forms\nfrom django.conf import settings\nfrom django.contrib.auth.forms import SetPasswordForm, AuthenticationForm, \\\n    PasswordResetForm\nfrom django.core.exceptions import ValidationError\nfrom django.core.urlresolvers import reverse\nfrom django.core.validators import validate_email\nfrom django.db.models.query import QuerySet\nfrom django.utils.translation import ugettext as _\nfrom jinja2 import Markup as mark_safe\n\nfrom zerver.lib.actions import do_change_password, is_inactive, user_email_is_unique\nfrom zerver.lib.name_restrictions import is_reserved_subdomain, is_disposable_domain\nfrom zerver.lib.request import JsonableError\nfrom zerver.lib.send_email import send_email\nfrom zerver.lib.users import check_full_name\nfrom zerver.lib.utils import get_subdomain, check_subdomain\nfrom zerver.models import Realm, get_user_profile_by_email, UserProfile, \\\n    get_realm_by_email_domain, get_realm, \\\n    get_unique_open_realm, email_to_domain, email_allowed_for_realm\nfrom zproject.backends import password_auth_enabled\n\nimport logging\nimport re\nimport DNS\n\nfrom typing import Any, Callable, List, Optional, Text, Dict\n\nMIT_VALIDATION_ERROR = u'That user does not exist at MIT or is a ' + \\\n                       u'<a href=\"https://ist.mit.edu/email-lists\">mailing list</a>. ' + \\\n                       u'If you want to sign up an alias for Zulip, ' + \\\n                       u'<a href=\"mailto:support@zulipchat.com\">contact us</a>.'\nWRONG_SUBDOMAIN_ERROR = \"Your Zulip account is not a member of the \" + \\\n                        \"organization associated with this subdomain.  \" + \\\n                        \"Please contact %s with any questions!\" % (settings.ZULIP_ADMINISTRATOR,)\n\ndef email_is_not_mit_mailing_list(email):\n    # type: (Text) -> None\n    \"\"\"Prevent MIT mailing lists from signing up for Zulip\"\"\"\n    if \"@mit.edu\" in email:\n        username = email.rsplit(\"@\", 1)[0]\n        # Check whether the user exists and can get mail.\n        try:\n            DNS.dnslookup(\"%s.pobox.ns.athena.mit.edu\" % username, DNS.Type.TXT)\n        except DNS.Base.ServerError as e:\n            if e.rcode == DNS.Status.NXDOMAIN:\n                raise ValidationError(mark_safe(MIT_VALIDATION_ERROR))\n            else:\n                raise\n\nclass RegistrationForm(forms.Form):\n    MAX_PASSWORD_LENGTH = 100\n    full_name = forms.CharField(max_length=100)\n    # The required-ness of the password field gets overridden if it isn't\n    # actually required for a realm\n    password = forms.CharField(widget=forms.PasswordInput, max_length=MAX_PASSWORD_LENGTH,\n                               required=False)\n    realm_subdomain = forms.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH, required=False)\n    realm_org_type = forms.ChoiceField(((Realm.COMMUNITY, 'Community'),\n                                        (Realm.CORPORATE, 'Corporate')),\n                                       initial=Realm.COMMUNITY, required=False)\n\n    def __init__(self, *args, **kwargs):\n        # type: (*Any, **Any) -> None\n\n        # Since the superclass doesn't except random extra kwargs, we\n        # remove it from the kwargs dict before initializing.\n        realm_creation = kwargs['realm_creation']\n        del kwargs['realm_creation']\n\n        super(RegistrationForm, self).__init__(*args, **kwargs)\n        if settings.TERMS_OF_SERVICE:\n            self.fields['terms'] = forms.BooleanField(required=True)\n        self.fields['realm_name'] = forms.CharField(\n            max_length=Realm.MAX_REALM_NAME_LENGTH,\n            required=realm_creation)\n\n    def clean_full_name(self):\n        # type: () -> Text\n        try:\n            return check_full_name(self.cleaned_data['full_name'])\n        except JsonableError as e:\n            raise ValidationError(e.error)\n\n    def clean_realm_subdomain(self):\n        # type: () -> str\n        if settings.REALMS_HAVE_SUBDOMAINS:\n            error_strings = {\n                'too short': _(\"Subdomain needs to have length 3 or greater.\"),\n                'extremal dash': _(\"Subdomain cannot start or end with a '-'.\"),\n                'bad character': _(\"Subdomain can only have lowercase letters, numbers, and '-'s.\"),\n                'unavailable': _(\"Subdomain unavailable. Please choose a different one.\")}\n        else:\n            error_strings = {\n                'too short': _(\"Short name needs at least 3 characters.\"),\n                'extremal dash': _(\"Short name cannot start or end with a '-'.\"),\n                'bad character': _(\"Short name can only have lowercase letters, numbers, and '-'s.\"),\n                'unavailable': _(\"Short name unavailable. Please choose a different one.\")}\n        subdomain = self.cleaned_data['realm_subdomain']\n        if not subdomain:\n            return ''\n        if len(subdomain) < 3:\n            raise ValidationError(error_strings['too short'])\n        if subdomain[0] == '-' or subdomain[-1] == '-':\n            raise ValidationError(error_strings['extremal dash'])\n        if not re.match('^[a-z0-9-]*$', subdomain):\n            raise ValidationError(error_strings['bad character'])\n        if is_reserved_subdomain(subdomain) or \\\n           get_realm(subdomain) is not None:\n            raise ValidationError(error_strings['unavailable'])\n        return subdomain\n\nclass ToSForm(forms.Form):\n    terms = forms.BooleanField(required=True)\n\nclass HomepageForm(forms.Form):\n    email = forms.EmailField(validators=[is_inactive])\n\n    def __init__(self, *args, **kwargs):\n        # type: (*Any, **Any) -> None\n        self.realm = kwargs.pop('realm', None)\n        super(HomepageForm, self).__init__(*args, **kwargs)\n\n    def clean_email(self):\n        # type: () -> str\n        \"\"\"Returns the email if and only if the user's email address is\n        allowed to join the realm they are trying to join.\"\"\"\n        email = self.cleaned_data['email']\n\n        if get_unique_open_realm():\n            return email\n\n        # Otherwise, the user is trying to join a specific realm.\n        realm = self.realm\n        if realm is None and not settings.REALMS_HAVE_SUBDOMAINS:\n            realm = get_realm_by_email_domain(email)\n\n        if realm is None:\n            if settings.REALMS_HAVE_SUBDOMAINS:\n                raise ValidationError(_(\"The organization you are trying to \"\n                                        \"join using {email} does not \"\n                                        \"exist.\").format(email=email))\n            else:\n                raise ValidationError(_(\"Your email address, {email}, does not \"\n                                        \"correspond to any existing \"\n                                        \"organization.\").format(email=email))\n\n        if realm.invite_required:\n            raise ValidationError(_(\"Please request an invite for {email} \"\n                                    \"from the organization \"\n                                    \"administrator.\").format(email=email))\n\n        if not email_allowed_for_realm(email, realm):\n            raise ValidationError(\n                _(\"Your email address, {email}, is not in one of the domains \"\n                  \"that are allowed to register for accounts in this organization.\").format(\n                      string_id=realm.string_id, email=email))\n\n        if realm.is_zephyr_mirror_realm:\n            email_is_not_mit_mailing_list(email)\n\n        return email\n\ndef email_is_not_disposable(email):\n    # type: (Text) -> None\n    if is_disposable_domain(email_to_domain(email)):\n        raise ValidationError(_(\"Please use your real email address.\"))\n\nclass RealmCreationForm(forms.Form):\n    # This form determines whether users can create a new realm.\n    email = forms.EmailField(validators=[user_email_is_unique, email_is_not_disposable])\n\nclass LoggingSetPasswordForm(SetPasswordForm):\n    def save(self, commit=True):\n        # type: (bool) -> UserProfile\n        do_change_password(self.user, self.cleaned_data['new_password1'],\n                           commit=commit)\n        return self.user\n\nclass ZulipPasswordResetForm(PasswordResetForm):\n    def get_users(self, email):\n        # type: (str) -> QuerySet\n        \"\"\"Given an email, return matching user(s) who should receive a reset.\n\n        This is modified from the original in that it allows non-bot\n        users who don't have a usable password to reset their\n        passwords.\n        \"\"\"\n        if not password_auth_enabled:\n            logging.info(\"Password reset attempted for %s even though password auth is disabled.\" % (email,))\n            return []\n        result = UserProfile.objects.filter(email__iexact=email, is_active=True,\n                                            is_bot=False)\n        if len(result) == 0:\n            logging.info(\"Password reset attempted for %s; no active account.\" % (email,))\n        return result\n\n    def send_mail(self, subject_template_name, email_template_name,\n                  context, from_email, to_email, html_email_template_name=None):\n        # type: (str, str, Dict[str, Any], str, str, str) -> None\n        \"\"\"\n        Currently we don't support accounts in multiple subdomains using\n        a single email address. We override this function so that we do\n        not send a reset link to an email address if the reset attempt is\n        done on the subdomain which does not match user.realm.subdomain.\n\n        Once we start supporting accounts with the same email in\n        multiple subdomains, we may be able to refactor this function.\n\n        A second reason we override this function is so that we can send\n        the mail through the functions in zerver.lib.send_email, to match\n        how we send all other mail in the codebase.\n        \"\"\"\n        user_realm = get_user_profile_by_email(to_email).realm\n        attempted_subdomain = get_subdomain(getattr(self, 'request'))\n        context['attempted_realm'] = False\n        if not check_subdomain(user_realm.subdomain, attempted_subdomain):\n            context['attempted_realm'] = get_realm(attempted_subdomain)\n\n        send_email('zerver/emails/password_reset', to_email, from_email=from_email,\n                   context=context)\n\n    def save(self, *args, **kwargs):\n        # type: (*Any, **Any) -> None\n        \"\"\"Currently we don't support accounts in multiple subdomains using\n        a single email addresss. We override this function so that we can\n        inject request parameter in context. This parameter will be used\n        by send_mail function.\n\n        Once we start supporting accounts with the same email in\n        multiple subdomains, we may be able to delete or refactor this\n        function.\n        \"\"\"\n        setattr(self, 'request', kwargs.get('request'))\n        super(ZulipPasswordResetForm, self).save(*args, **kwargs)\n\nclass CreateUserForm(forms.Form):\n    full_name = forms.CharField(max_length=100)\n    email = forms.EmailField()\n\nclass OurAuthenticationForm(AuthenticationForm):\n    def clean_username(self):\n        # type: () -> str\n        email = self.cleaned_data['username']\n        try:\n            user_profile = get_user_profile_by_email(email)\n        except UserProfile.DoesNotExist:\n            return email\n\n        if user_profile.realm.deactivated:\n            error_msg = u\"\"\"Sorry for the trouble, but %s has been deactivated.\n\nPlease contact %s to reactivate this group.\"\"\" % (\n                user_profile.realm.name,\n                settings.ZULIP_ADMINISTRATOR)\n            raise ValidationError(mark_safe(error_msg))\n\n        if not user_profile.is_active:\n            error_msg = (u\"Sorry for the trouble, but your account has been \"\n                         u\"deactivated. Please contact %s to reactivate \"\n                         u\"it.\") % (settings.ZULIP_ADMINISTRATOR,)\n            raise ValidationError(mark_safe(error_msg))\n\n        if not check_subdomain(get_subdomain(self.request), user_profile.realm.subdomain):\n            logging.warning(\"User %s attempted to password login to wrong subdomain %s\" %\n                            (user_profile.email, get_subdomain(self.request)))\n            raise ValidationError(mark_safe(WRONG_SUBDOMAIN_ERROR))\n        return email\n\nclass MultiEmailField(forms.Field):\n    def to_python(self, emails):\n        # type: (Text) -> List[Text]\n        \"\"\"Normalize data to a list of strings.\"\"\"\n        if not emails:\n            return []\n\n        return [email.strip() for email in emails.split(',')]\n\n    def validate(self, emails):\n        # type: (List[Text]) -> None\n        \"\"\"Check if value consists only of valid emails.\"\"\"\n        super(MultiEmailField, self).validate(emails)\n        for email in emails:\n            validate_email(email)\n\nclass FindMyTeamForm(forms.Form):\n    emails = MultiEmailField(\n        help_text=_(\"Add up to 10 comma-separated email addresses.\"))\n\n    def clean_emails(self):\n        # type: () -> List[Text]\n        emails = self.cleaned_data['emails']\n        if len(emails) > 10:\n            raise forms.ValidationError(_(\"Please enter at most 10 emails.\"))\n\n        return emails\n", "path": "zerver/forms.py"}]}