We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
User object not retrieved.
### Description

When I try running the project locally and I try registering a user, It shows an error.




### What should have happened?

I expect the registration to work successfully.

### What browser(s) are you seeing the problem on?

_No response_

### Further details

![image](https://user-images.githubusercontent.com/67182544/133763364-70ea311b-bf73-4699-88be-04f031defece.png)
![image](https://user-images.githubusercontent.com/67182544/133763487-61446088-b524-40de-b07f-89301dbc4b11.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `project/accounts/forms.py`
Content:
```
1 import re
2 from django.core.files.images import get_image_dimensions
3 from django import forms
4 from django.contrib.auth.forms import (
5     SetPasswordForm,
6     PasswordResetForm as AuthRecoverUserForm,
7 )
8 from django.forms.models import ModelForm
9 from django.contrib.auth import get_user_model
10 from django.contrib.auth.tokens import default_token_generator
11 from django.contrib.sites.shortcuts import get_current_site
12 from django.utils.encoding import force_bytes
13 from django.utils.http import urlsafe_base64_encode
14 from django.template.loader import render_to_string
15 from django.utils.translation import ugettext_lazy as _
16 from django.conf import settings
17 
18 from accounts.utils import send_email
19 from .reserved_usernames import RESERVED_USERNAMES
20 from accounts.models import Profile
21 
22 
23 class UserRegistrationForm(ModelForm):
24     """
25     This class is used to register a new user in Civiwiki
26 
27     Components:
28         - Email     - from registration form
29         - Username  - from registration form
30         - Password  - from registration form
31         - Error_Message
32             - Invalid_Username - Usernames may only use lowercase characters or numbers
33             - Email_Exists - An account exists for this email address
34             - Invalid_Password - Password can not be entirely numeric
35             - Invalid_Password_Length - Password must be at least 4 characters
36     """
37 
38     email = forms.EmailField(required=True)
39     username = forms.CharField(required=True)
40     password = forms.CharField(required=True, widget=forms.PasswordInput())
41 
42     error_message = {
43         "invalid_username": _(
44             "Usernames may only use lowercase characters or numbers."
45         ),
46         "email_exists": _("An account exists for this email address."),
47         "username_exists": _("Sorry, this username already exists."),
48         "invalid_password": _("Password can not be entirely numeric."),
49         "invalid_password_length": _("Password must be at least 4 characters."),
50     }
51 
52     class Meta:
53         model = get_user_model()
54         fields = ("username", "email", "password")
55 
56     def clean_email(self):
57         """
58         Used to make sure user entered email address is a valid email address
59 
60         Returns email
61         """
62 
63         email = self.cleaned_data.get("email")
64 
65         if User.objects.filter(email=email).exists():
66             raise forms.ValidationError(self.error_message["email_exists"])
67 
68         return email
69 
70     def clean_username(self):
71         """
72         Used to make sure that usernames meet the Civiwiki standards
73 
74         Requirements:
75             - Username can only be made of lower case alphanumeric values
76             - Username cannot match entries from RESERVED_USERNAMES
77 
78         Returns username
79         """
80 
81         username = self.cleaned_data.get("username")
82 
83         if not re.match(r"^[0-9a-z]*$", username):
84             raise forms.ValidationError(self.error_message["invalid_username"])
85 
86         if (
87             User.objects.filter(username=username).exists()
88             or username in RESERVED_USERNAMES
89         ):
90             raise forms.ValidationError(self.error_message["username_exists"])
91 
92         return username
93 
94     def clean_password(self):
95         """
96         Used to make sure that passwords meet the Civiwiki standards
97 
98         Requirements:
99             - At least 4 characters in length
100             - Cannot be all numbers
101 
102         Returns password
103         """
104 
105         password = self.cleaned_data.get("password")
106 
107         if len(password) < 4:
108             raise forms.ValidationError(self.error_message["invalid_password_length"])
109 
110         if password.isdigit():
111             raise forms.ValidationError(self.error_message["invalid_password"])
112 
113         return password
114 
115 
116 class PasswordResetForm(SetPasswordForm):
117     """
118     A form that lets a user reset their password
119     """
120 
121     error_messages = dict(
122         SetPasswordForm.error_messages,
123         **{
124             "invalid_password": _("Password can not be entirely numeric."),
125             "invalid_password_length": _("Password must be at least 4 characters."),
126         }
127     )
128 
129     def clean_new_password1(self):
130         """
131         Used to make sure that new passwords meet the Civiwiki standards
132 
133         Must be:
134             - At least 4 characters in length
135             - Cannot be all numbers
136 
137         Returns new password
138         """
139 
140         password = self.cleaned_data.get("new_password1")
141 
142         if len(password) < 4:
143             raise forms.ValidationError(self.error_messages["invalid_password_length"])
144 
145         if password.isdigit():
146             raise forms.ValidationError(self.error_messages["invalid_password"])
147 
148         return password
149 
150 
151 class RecoverUserForm(AuthRecoverUserForm):
152     """
153     Send custom recovery mail with a task runner mostly taken from PasswordResetForm in auth
154     """
155 
156     def save(
157         self,
158         domain_override=None,
159         subject_template_name=None,
160         email_template_name=None,
161         use_https=False,
162         token_generator=default_token_generator,
163         from_email=None,
164         request=None,
165         html_email_template_name=None,
166         extra_email_context=None,
167     ):
168         """
169         Generates a one-use only link for resetting password and sends to the
170         user.
171         """
172         email = self.cleaned_data["email"]
173 
174         for user in self.get_users(email):
175             uid = urlsafe_base64_encode(force_bytes(user.pk))
176             token = token_generator.make_token(user)
177             domain = get_current_site(request).domain
178             base_url = "http://{domain}/auth/password_reset/{uid}/{token}/"
179             url_with_code = base_url.format(domain=domain, uid=uid, token=token)
180             body_txt = """You're receiving this email because you requested an account recovery
181                           email for your user account at {domain}. Your username for this email
182                           is: {username}. If you also need to reset your password, please go to
183                           the following page and choose a new password."""
184 
185             email_body = body_txt.format(domain=domain, username=user.username)
186 
187             context = {
188                 "title": "Profile Recovery for CiviWiki",
189                 "greeting": "Recover your account on CiviWiki",
190                 "body": email_body,
191                 "link": url_with_code,
192             }
193 
194             text_message_template = "email/base_text_template.txt"
195             html_message_template = "email/base_email_template.html"
196 
197             message = render_to_string(text_message_template, context)
198             html_message = render_to_string(html_message_template, context)
199             sender = settings.EMAIL_HOST_USER
200             send_email(
201                 subject="Profile Recovery for CiviWiki",
202                 message=message,
203                 sender=settings.EMAIL_HOST_USER,
204                 recipient_list=[email],
205                 html_message=html_message,
206             )
207 
208 
209 class UpdateProfile(forms.ModelForm):
210     """
211     Form for updating Profile data
212     """
213 
214     def __init__(self, *args, **kwargs):
215         readonly = kwargs.pop("readonly", False)
216         super(UpdateProfile, self).__init__(*args, **kwargs)
217         if readonly:
218             self.disable_fields()
219 
220     def disable_fields(self):
221         for _, field in self.fields.items():
222             field.disabled = True
223 
224     class Meta:
225         model = Profile
226         fields = [
227             "first_name",
228             "last_name",
229             "about_me",
230             "profile_image",
231             "username",
232             "email",
233         ]
234 
235     first_name = forms.CharField(label="First Name", max_length=63, required=False)
236     last_name = forms.CharField(label="Last Name", max_length=63, required=False)
237     about_me = forms.CharField(label="About Me", max_length=511, required=False)
238     email = forms.EmailField(label="Email", disabled=True)
239     username = forms.CharField(label="Username", disabled=True)
240     profile_image = forms.ImageField(required=False)
241 
242 
243 class UpdatePassword(forms.ModelForm):
244     """
245     Form for updating User Password
246     """
247 
248     class Meta:
249         model = get_user_model()
250         fields = ["password", "verify"]
251 
252     password = forms.CharField(
253         label="Password",
254         widget=forms.PasswordInput(
255             attrs={
256                 "class": "form-control",
257                 "placeholder": "Password",
258                 "required": "True",
259             }
260         ),
261     )
262     verify = forms.CharField(
263         label="Password Verify",
264         widget=forms.PasswordInput(
265             attrs={
266                 "class": "form-control",
267                 "placeholder": "Password Verify",
268                 "required": "True",
269             }
270         ),
271         help_text="Please retype your password.",
272     )
273 
274     def clean(self):
275         """
276         Verifies that the passwords match
277         """
278         clean_data = super(UpdatePassword, self).clean()
279         if "password" in clean_data and "verify" in clean_data:
280             if clean_data["password"] != clean_data["verify"]:
281                 raise forms.ValidationError("Passwords don't match.")
282         else:
283             raise forms.ValidationError("Both password fields need to be filled out.")
284         return clean_data
285 
286 
287 class UpdateProfileImage(forms.ModelForm):
288     """
289     Form for updating profile image
290     """
291 
292     class Meta:
293         model = Profile
294         fields = ["profile_image"]
295 
296     profile_image = forms.ImageField()
297 
298     def clean_profile_image(self):
299         """
300         This function is used to make sure that profile images follow Civiwiki standards.
301 
302         Requirements:
303             - Height cannot exceed 960px
304             - Width cannot exceed 1280px
305             - Image must be (jpg, jpeg, pjeg, png)
306             - File size cannot exceed 2MB
307         """
308         profile_image = self.cleaned_data["profile_image"]
309 
310         try:
311             w, h = get_image_dimensions(profile_image)
312 
313             # validate dimensions
314             max_height = 960
315             max_width = 1280
316             if w > max_width or h > max_height:
317                 raise forms.ValidationError(
318                     u"Please use an image that is {w} x {h} pixels or smaller.".format(
319                         w=max_width, h=max_height
320                     )
321                 )
322 
323             # validate content type
324             main, sub = profile_image.content_type.split("/")
325             if not (main == "image" and sub in ["jpg", "jpeg", "pjpeg", "png"]):
326                 raise forms.ValidationError(u"Please use a JPEG or PNG image.")
327 
328             # validate file size
329             if len(profile_image) > (2000 * 1024):
330                 raise forms.ValidationError(
331                     "Profile image file size may not exceed 2MB."
332                 )
333 
334         except AttributeError:
335             pass
336 
337         return profile_image
338
```
--- 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/project/accounts/forms.py b/project/accounts/forms.py
--- a/project/accounts/forms.py
+++ b/project/accounts/forms.py
@@ -62,7 +62,7 @@
 
         email = self.cleaned_data.get("email")
 
-        if User.objects.filter(email=email).exists():
+        if get_user_model().objects.filter(email=email).exists():
             raise forms.ValidationError(self.error_message["email_exists"])
 
         return email
@@ -84,7 +84,7 @@
             raise forms.ValidationError(self.error_message["invalid_username"])
 
         if (
-            User.objects.filter(username=username).exists()
+            get_user_model().objects.filter(username=username).exists()
             or username in RESERVED_USERNAMES
         ):
             raise forms.ValidationError(self.error_message["username_exists"])
@@ -200,7 +200,7 @@
             send_email(
                 subject="Profile Recovery for CiviWiki",
                 message=message,
-                sender=settings.EMAIL_HOST_USER,
+                sender=sender,
                 recipient_list=[email],
                 html_message=html_message,
             )

{"golden_diff": "diff --git a/project/accounts/forms.py b/project/accounts/forms.py\n--- a/project/accounts/forms.py\n+++ b/project/accounts/forms.py\n@@ -62,7 +62,7 @@\n \n         email = self.cleaned_data.get(\"email\")\n \n-        if User.objects.filter(email=email).exists():\n+        if get_user_model().objects.filter(email=email).exists():\n             raise forms.ValidationError(self.error_message[\"email_exists\"])\n \n         return email\n@@ -84,7 +84,7 @@\n             raise forms.ValidationError(self.error_message[\"invalid_username\"])\n \n         if (\n-            User.objects.filter(username=username).exists()\n+            get_user_model().objects.filter(username=username).exists()\n             or username in RESERVED_USERNAMES\n         ):\n             raise forms.ValidationError(self.error_message[\"username_exists\"])\n@@ -200,7 +200,7 @@\n             send_email(\n                 subject=\"Profile Recovery for CiviWiki\",\n                 message=message,\n-                sender=settings.EMAIL_HOST_USER,\n+                sender=sender,\n                 recipient_list=[email],\n                 html_message=html_message,\n             )\n", "issue": "User object not retrieved.\n### Description\r\n\r\nWhen I try running the project locally and I try registering a user, It shows an error.\r\n\r\n\r\n\r\n\r\n### What should have happened?\r\n\r\nI expect the registration to work successfully.\r\n\r\n### What browser(s) are you seeing the problem on?\r\n\r\n_No response_\r\n\r\n### Further details\r\n\r\n![image](https://user-images.githubusercontent.com/67182544/133763364-70ea311b-bf73-4699-88be-04f031defece.png)\r\n![image](https://user-images.githubusercontent.com/67182544/133763487-61446088-b524-40de-b07f-89301dbc4b11.png)\r\n\n", "before_files": [{"content": "import re\nfrom django.core.files.images import get_image_dimensions\nfrom django import forms\nfrom django.contrib.auth.forms import (\n    SetPasswordForm,\n    PasswordResetForm as AuthRecoverUserForm,\n)\nfrom django.forms.models import ModelForm\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.tokens import default_token_generator\nfrom django.contrib.sites.shortcuts import get_current_site\nfrom django.utils.encoding import force_bytes\nfrom django.utils.http import urlsafe_base64_encode\nfrom django.template.loader import render_to_string\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.conf import settings\n\nfrom accounts.utils import send_email\nfrom .reserved_usernames import RESERVED_USERNAMES\nfrom accounts.models import Profile\n\n\nclass UserRegistrationForm(ModelForm):\n    \"\"\"\n    This class is used to register a new user in Civiwiki\n\n    Components:\n        - Email     - from registration form\n        - Username  - from registration form\n        - Password  - from registration form\n        - Error_Message\n            - Invalid_Username - Usernames may only use lowercase characters or numbers\n            - Email_Exists - An account exists for this email address\n            - Invalid_Password - Password can not be entirely numeric\n            - Invalid_Password_Length - Password must be at least 4 characters\n    \"\"\"\n\n    email = forms.EmailField(required=True)\n    username = forms.CharField(required=True)\n    password = forms.CharField(required=True, widget=forms.PasswordInput())\n\n    error_message = {\n        \"invalid_username\": _(\n            \"Usernames may only use lowercase characters or numbers.\"\n        ),\n        \"email_exists\": _(\"An account exists for this email address.\"),\n        \"username_exists\": _(\"Sorry, this username already exists.\"),\n        \"invalid_password\": _(\"Password can not be entirely numeric.\"),\n        \"invalid_password_length\": _(\"Password must be at least 4 characters.\"),\n    }\n\n    class Meta:\n        model = get_user_model()\n        fields = (\"username\", \"email\", \"password\")\n\n    def clean_email(self):\n        \"\"\"\n        Used to make sure user entered email address is a valid email address\n\n        Returns email\n        \"\"\"\n\n        email = self.cleaned_data.get(\"email\")\n\n        if User.objects.filter(email=email).exists():\n            raise forms.ValidationError(self.error_message[\"email_exists\"])\n\n        return email\n\n    def clean_username(self):\n        \"\"\"\n        Used to make sure that usernames meet the Civiwiki standards\n\n        Requirements:\n            - Username can only be made of lower case alphanumeric values\n            - Username cannot match entries from RESERVED_USERNAMES\n\n        Returns username\n        \"\"\"\n\n        username = self.cleaned_data.get(\"username\")\n\n        if not re.match(r\"^[0-9a-z]*$\", username):\n            raise forms.ValidationError(self.error_message[\"invalid_username\"])\n\n        if (\n            User.objects.filter(username=username).exists()\n            or username in RESERVED_USERNAMES\n        ):\n            raise forms.ValidationError(self.error_message[\"username_exists\"])\n\n        return username\n\n    def clean_password(self):\n        \"\"\"\n        Used to make sure that passwords meet the Civiwiki standards\n\n        Requirements:\n            - At least 4 characters in length\n            - Cannot be all numbers\n\n        Returns password\n        \"\"\"\n\n        password = self.cleaned_data.get(\"password\")\n\n        if len(password) < 4:\n            raise forms.ValidationError(self.error_message[\"invalid_password_length\"])\n\n        if password.isdigit():\n            raise forms.ValidationError(self.error_message[\"invalid_password\"])\n\n        return password\n\n\nclass PasswordResetForm(SetPasswordForm):\n    \"\"\"\n    A form that lets a user reset their password\n    \"\"\"\n\n    error_messages = dict(\n        SetPasswordForm.error_messages,\n        **{\n            \"invalid_password\": _(\"Password can not be entirely numeric.\"),\n            \"invalid_password_length\": _(\"Password must be at least 4 characters.\"),\n        }\n    )\n\n    def clean_new_password1(self):\n        \"\"\"\n        Used to make sure that new passwords meet the Civiwiki standards\n\n        Must be:\n            - At least 4 characters in length\n            - Cannot be all numbers\n\n        Returns new password\n        \"\"\"\n\n        password = self.cleaned_data.get(\"new_password1\")\n\n        if len(password) < 4:\n            raise forms.ValidationError(self.error_messages[\"invalid_password_length\"])\n\n        if password.isdigit():\n            raise forms.ValidationError(self.error_messages[\"invalid_password\"])\n\n        return password\n\n\nclass RecoverUserForm(AuthRecoverUserForm):\n    \"\"\"\n    Send custom recovery mail with a task runner mostly taken from PasswordResetForm in auth\n    \"\"\"\n\n    def save(\n        self,\n        domain_override=None,\n        subject_template_name=None,\n        email_template_name=None,\n        use_https=False,\n        token_generator=default_token_generator,\n        from_email=None,\n        request=None,\n        html_email_template_name=None,\n        extra_email_context=None,\n    ):\n        \"\"\"\n        Generates a one-use only link for resetting password and sends to the\n        user.\n        \"\"\"\n        email = self.cleaned_data[\"email\"]\n\n        for user in self.get_users(email):\n            uid = urlsafe_base64_encode(force_bytes(user.pk))\n            token = token_generator.make_token(user)\n            domain = get_current_site(request).domain\n            base_url = \"http://{domain}/auth/password_reset/{uid}/{token}/\"\n            url_with_code = base_url.format(domain=domain, uid=uid, token=token)\n            body_txt = \"\"\"You're receiving this email because you requested an account recovery\n                          email for your user account at {domain}. Your username for this email\n                          is: {username}. If you also need to reset your password, please go to\n                          the following page and choose a new password.\"\"\"\n\n            email_body = body_txt.format(domain=domain, username=user.username)\n\n            context = {\n                \"title\": \"Profile Recovery for CiviWiki\",\n                \"greeting\": \"Recover your account on CiviWiki\",\n                \"body\": email_body,\n                \"link\": url_with_code,\n            }\n\n            text_message_template = \"email/base_text_template.txt\"\n            html_message_template = \"email/base_email_template.html\"\n\n            message = render_to_string(text_message_template, context)\n            html_message = render_to_string(html_message_template, context)\n            sender = settings.EMAIL_HOST_USER\n            send_email(\n                subject=\"Profile Recovery for CiviWiki\",\n                message=message,\n                sender=settings.EMAIL_HOST_USER,\n                recipient_list=[email],\n                html_message=html_message,\n            )\n\n\nclass UpdateProfile(forms.ModelForm):\n    \"\"\"\n    Form for updating Profile data\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        readonly = kwargs.pop(\"readonly\", False)\n        super(UpdateProfile, self).__init__(*args, **kwargs)\n        if readonly:\n            self.disable_fields()\n\n    def disable_fields(self):\n        for _, field in self.fields.items():\n            field.disabled = True\n\n    class Meta:\n        model = Profile\n        fields = [\n            \"first_name\",\n            \"last_name\",\n            \"about_me\",\n            \"profile_image\",\n            \"username\",\n            \"email\",\n        ]\n\n    first_name = forms.CharField(label=\"First Name\", max_length=63, required=False)\n    last_name = forms.CharField(label=\"Last Name\", max_length=63, required=False)\n    about_me = forms.CharField(label=\"About Me\", max_length=511, required=False)\n    email = forms.EmailField(label=\"Email\", disabled=True)\n    username = forms.CharField(label=\"Username\", disabled=True)\n    profile_image = forms.ImageField(required=False)\n\n\nclass UpdatePassword(forms.ModelForm):\n    \"\"\"\n    Form for updating User Password\n    \"\"\"\n\n    class Meta:\n        model = get_user_model()\n        fields = [\"password\", \"verify\"]\n\n    password = forms.CharField(\n        label=\"Password\",\n        widget=forms.PasswordInput(\n            attrs={\n                \"class\": \"form-control\",\n                \"placeholder\": \"Password\",\n                \"required\": \"True\",\n            }\n        ),\n    )\n    verify = forms.CharField(\n        label=\"Password Verify\",\n        widget=forms.PasswordInput(\n            attrs={\n                \"class\": \"form-control\",\n                \"placeholder\": \"Password Verify\",\n                \"required\": \"True\",\n            }\n        ),\n        help_text=\"Please retype your password.\",\n    )\n\n    def clean(self):\n        \"\"\"\n        Verifies that the passwords match\n        \"\"\"\n        clean_data = super(UpdatePassword, self).clean()\n        if \"password\" in clean_data and \"verify\" in clean_data:\n            if clean_data[\"password\"] != clean_data[\"verify\"]:\n                raise forms.ValidationError(\"Passwords don't match.\")\n        else:\n            raise forms.ValidationError(\"Both password fields need to be filled out.\")\n        return clean_data\n\n\nclass UpdateProfileImage(forms.ModelForm):\n    \"\"\"\n    Form for updating profile image\n    \"\"\"\n\n    class Meta:\n        model = Profile\n        fields = [\"profile_image\"]\n\n    profile_image = forms.ImageField()\n\n    def clean_profile_image(self):\n        \"\"\"\n        This function is used to make sure that profile images follow Civiwiki standards.\n\n        Requirements:\n            - Height cannot exceed 960px\n            - Width cannot exceed 1280px\n            - Image must be (jpg, jpeg, pjeg, png)\n            - File size cannot exceed 2MB\n        \"\"\"\n        profile_image = self.cleaned_data[\"profile_image\"]\n\n        try:\n            w, h = get_image_dimensions(profile_image)\n\n            # validate dimensions\n            max_height = 960\n            max_width = 1280\n            if w > max_width or h > max_height:\n                raise forms.ValidationError(\n                    u\"Please use an image that is {w} x {h} pixels or smaller.\".format(\n                        w=max_width, h=max_height\n                    )\n                )\n\n            # validate content type\n            main, sub = profile_image.content_type.split(\"/\")\n            if not (main == \"image\" and sub in [\"jpg\", \"jpeg\", \"pjpeg\", \"png\"]):\n                raise forms.ValidationError(u\"Please use a JPEG or PNG image.\")\n\n            # validate file size\n            if len(profile_image) > (2000 * 1024):\n                raise forms.ValidationError(\n                    \"Profile image file size may not exceed 2MB.\"\n                )\n\n        except AttributeError:\n            pass\n\n        return profile_image\n", "path": "project/accounts/forms.py"}], "after_files": [{"content": "import re\nfrom django.core.files.images import get_image_dimensions\nfrom django import forms\nfrom django.contrib.auth.forms import (\n    SetPasswordForm,\n    PasswordResetForm as AuthRecoverUserForm,\n)\nfrom django.forms.models import ModelForm\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.tokens import default_token_generator\nfrom django.contrib.sites.shortcuts import get_current_site\nfrom django.utils.encoding import force_bytes\nfrom django.utils.http import urlsafe_base64_encode\nfrom django.template.loader import render_to_string\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.conf import settings\n\nfrom accounts.utils import send_email\nfrom .reserved_usernames import RESERVED_USERNAMES\nfrom accounts.models import Profile\n\n\nclass UserRegistrationForm(ModelForm):\n    \"\"\"\n    This class is used to register a new user in Civiwiki\n\n    Components:\n        - Email     - from registration form\n        - Username  - from registration form\n        - Password  - from registration form\n        - Error_Message\n            - Invalid_Username - Usernames may only use lowercase characters or numbers\n            - Email_Exists - An account exists for this email address\n            - Invalid_Password - Password can not be entirely numeric\n            - Invalid_Password_Length - Password must be at least 4 characters\n    \"\"\"\n\n    email = forms.EmailField(required=True)\n    username = forms.CharField(required=True)\n    password = forms.CharField(required=True, widget=forms.PasswordInput())\n\n    error_message = {\n        \"invalid_username\": _(\n            \"Usernames may only use lowercase characters or numbers.\"\n        ),\n        \"email_exists\": _(\"An account exists for this email address.\"),\n        \"username_exists\": _(\"Sorry, this username already exists.\"),\n        \"invalid_password\": _(\"Password can not be entirely numeric.\"),\n        \"invalid_password_length\": _(\"Password must be at least 4 characters.\"),\n    }\n\n    class Meta:\n        model = get_user_model()\n        fields = (\"username\", \"email\", \"password\")\n\n    def clean_email(self):\n        \"\"\"\n        Used to make sure user entered email address is a valid email address\n\n        Returns email\n        \"\"\"\n\n        email = self.cleaned_data.get(\"email\")\n\n        if get_user_model().objects.filter(email=email).exists():\n            raise forms.ValidationError(self.error_message[\"email_exists\"])\n\n        return email\n\n    def clean_username(self):\n        \"\"\"\n        Used to make sure that usernames meet the Civiwiki standards\n\n        Requirements:\n            - Username can only be made of lower case alphanumeric values\n            - Username cannot match entries from RESERVED_USERNAMES\n\n        Returns username\n        \"\"\"\n\n        username = self.cleaned_data.get(\"username\")\n\n        if not re.match(r\"^[0-9a-z]*$\", username):\n            raise forms.ValidationError(self.error_message[\"invalid_username\"])\n\n        if (\n            get_user_model().objects.filter(username=username).exists()\n            or username in RESERVED_USERNAMES\n        ):\n            raise forms.ValidationError(self.error_message[\"username_exists\"])\n\n        return username\n\n    def clean_password(self):\n        \"\"\"\n        Used to make sure that passwords meet the Civiwiki standards\n\n        Requirements:\n            - At least 4 characters in length\n            - Cannot be all numbers\n\n        Returns password\n        \"\"\"\n\n        password = self.cleaned_data.get(\"password\")\n\n        if len(password) < 4:\n            raise forms.ValidationError(self.error_message[\"invalid_password_length\"])\n\n        if password.isdigit():\n            raise forms.ValidationError(self.error_message[\"invalid_password\"])\n\n        return password\n\n\nclass PasswordResetForm(SetPasswordForm):\n    \"\"\"\n    A form that lets a user reset their password\n    \"\"\"\n\n    error_messages = dict(\n        SetPasswordForm.error_messages,\n        **{\n            \"invalid_password\": _(\"Password can not be entirely numeric.\"),\n            \"invalid_password_length\": _(\"Password must be at least 4 characters.\"),\n        }\n    )\n\n    def clean_new_password1(self):\n        \"\"\"\n        Used to make sure that new passwords meet the Civiwiki standards\n\n        Must be:\n            - At least 4 characters in length\n            - Cannot be all numbers\n\n        Returns new password\n        \"\"\"\n\n        password = self.cleaned_data.get(\"new_password1\")\n\n        if len(password) < 4:\n            raise forms.ValidationError(self.error_messages[\"invalid_password_length\"])\n\n        if password.isdigit():\n            raise forms.ValidationError(self.error_messages[\"invalid_password\"])\n\n        return password\n\n\nclass RecoverUserForm(AuthRecoverUserForm):\n    \"\"\"\n    Send custom recovery mail with a task runner mostly taken from PasswordResetForm in auth\n    \"\"\"\n\n    def save(\n        self,\n        domain_override=None,\n        subject_template_name=None,\n        email_template_name=None,\n        use_https=False,\n        token_generator=default_token_generator,\n        from_email=None,\n        request=None,\n        html_email_template_name=None,\n        extra_email_context=None,\n    ):\n        \"\"\"\n        Generates a one-use only link for resetting password and sends to the\n        user.\n        \"\"\"\n        email = self.cleaned_data[\"email\"]\n\n        for user in self.get_users(email):\n            uid = urlsafe_base64_encode(force_bytes(user.pk))\n            token = token_generator.make_token(user)\n            domain = get_current_site(request).domain\n            base_url = \"http://{domain}/auth/password_reset/{uid}/{token}/\"\n            url_with_code = base_url.format(domain=domain, uid=uid, token=token)\n            body_txt = \"\"\"You're receiving this email because you requested an account recovery\n                          email for your user account at {domain}. Your username for this email\n                          is: {username}. If you also need to reset your password, please go to\n                          the following page and choose a new password.\"\"\"\n\n            email_body = body_txt.format(domain=domain, username=user.username)\n\n            context = {\n                \"title\": \"Profile Recovery for CiviWiki\",\n                \"greeting\": \"Recover your account on CiviWiki\",\n                \"body\": email_body,\n                \"link\": url_with_code,\n            }\n\n            text_message_template = \"email/base_text_template.txt\"\n            html_message_template = \"email/base_email_template.html\"\n\n            message = render_to_string(text_message_template, context)\n            html_message = render_to_string(html_message_template, context)\n            sender = settings.EMAIL_HOST_USER\n            send_email(\n                subject=\"Profile Recovery for CiviWiki\",\n                message=message,\n                sender=sender,\n                recipient_list=[email],\n                html_message=html_message,\n            )\n\n\nclass UpdateProfile(forms.ModelForm):\n    \"\"\"\n    Form for updating Profile data\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        readonly = kwargs.pop(\"readonly\", False)\n        super(UpdateProfile, self).__init__(*args, **kwargs)\n        if readonly:\n            self.disable_fields()\n\n    def disable_fields(self):\n        for _, field in self.fields.items():\n            field.disabled = True\n\n    class Meta:\n        model = Profile\n        fields = [\n            \"first_name\",\n            \"last_name\",\n            \"about_me\",\n            \"profile_image\",\n            \"username\",\n            \"email\",\n        ]\n\n    first_name = forms.CharField(label=\"First Name\", max_length=63, required=False)\n    last_name = forms.CharField(label=\"Last Name\", max_length=63, required=False)\n    about_me = forms.CharField(label=\"About Me\", max_length=511, required=False)\n    email = forms.EmailField(label=\"Email\", disabled=True)\n    username = forms.CharField(label=\"Username\", disabled=True)\n    profile_image = forms.ImageField(required=False)\n\n\nclass UpdatePassword(forms.ModelForm):\n    \"\"\"\n    Form for updating User Password\n    \"\"\"\n\n    class Meta:\n        model = get_user_model()\n        fields = [\"password\", \"verify\"]\n\n    password = forms.CharField(\n        label=\"Password\",\n        widget=forms.PasswordInput(\n            attrs={\n                \"class\": \"form-control\",\n                \"placeholder\": \"Password\",\n                \"required\": \"True\",\n            }\n        ),\n    )\n    verify = forms.CharField(\n        label=\"Password Verify\",\n        widget=forms.PasswordInput(\n            attrs={\n                \"class\": \"form-control\",\n                \"placeholder\": \"Password Verify\",\n                \"required\": \"True\",\n            }\n        ),\n        help_text=\"Please retype your password.\",\n    )\n\n    def clean(self):\n        \"\"\"\n        Verifies that the passwords match\n        \"\"\"\n        clean_data = super(UpdatePassword, self).clean()\n        if \"password\" in clean_data and \"verify\" in clean_data:\n            if clean_data[\"password\"] != clean_data[\"verify\"]:\n                raise forms.ValidationError(\"Passwords don't match.\")\n        else:\n            raise forms.ValidationError(\"Both password fields need to be filled out.\")\n        return clean_data\n\n\nclass UpdateProfileImage(forms.ModelForm):\n    \"\"\"\n    Form for updating profile image\n    \"\"\"\n\n    class Meta:\n        model = Profile\n        fields = [\"profile_image\"]\n\n    profile_image = forms.ImageField()\n\n    def clean_profile_image(self):\n        \"\"\"\n        This function is used to make sure that profile images follow Civiwiki standards.\n\n        Requirements:\n            - Height cannot exceed 960px\n            - Width cannot exceed 1280px\n            - Image must be (jpg, jpeg, pjeg, png)\n            - File size cannot exceed 2MB\n        \"\"\"\n        profile_image = self.cleaned_data[\"profile_image\"]\n\n        try:\n            w, h = get_image_dimensions(profile_image)\n\n            # validate dimensions\n            max_height = 960\n            max_width = 1280\n            if w > max_width or h > max_height:\n                raise forms.ValidationError(\n                    u\"Please use an image that is {w} x {h} pixels or smaller.\".format(\n                        w=max_width, h=max_height\n                    )\n                )\n\n            # validate content type\n            main, sub = profile_image.content_type.split(\"/\")\n            if not (main == \"image\" and sub in [\"jpg\", \"jpeg\", \"pjpeg\", \"png\"]):\n                raise forms.ValidationError(u\"Please use a JPEG or PNG image.\")\n\n            # validate file size\n            if len(profile_image) > (2000 * 1024):\n                raise forms.ValidationError(\n                    \"Profile image file size may not exceed 2MB.\"\n                )\n\n        except AttributeError:\n            pass\n\n        return profile_image\n", "path": "project/accounts/forms.py"}]}