From 1a956be2f227ceb37d478bb5b581b7245d6a42d8 Mon Sep 17 00:00:00 2001
From: Eraldo Energy <eraldo@eraldo.org>
Date: Tue, 28 Jun 2016 13:55:09 +0200
Subject: [PATCH] Added file handling to support custom user add/edit forms.

---
 CHANGELOG.txt                                 |  1 +
 CONTRIBUTORS.rst                              |  1 +
 docs/releases/1.6.rst                         |  1 +
 .../migrations/0002_added_file_field.py       | 19 +++++++++++++++++++
 wagtail/tests/customuser/models.py            |  1 +
 wagtail/tests/settings.py                     |  2 +-
 .../templates/wagtailusers/users/create.html  |  2 +-
 .../templates/wagtailusers/users/edit.html    |  2 +-
 wagtail/wagtailusers/tests.py                 |  9 ++++++++-
 wagtail/wagtailusers/views/users.py           |  4 ++--
 10 files changed, 36 insertions(+), 6 deletions(-)
 create mode 100644 wagtail/tests/customuser/migrations/0002_added_file_field.py

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 7c26a33e66..7b81d7e102 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -40,6 +40,7 @@ Changelog
  * Fix: Saving a page by pressing enter key no longer triggers a "Changes may not be saved message" (Sean Muck, Matt Westcott)
  * Fix: RoutablePageMixin no longer breaks in the presence of instance-only attributes such as those generated by FileFields (Fábio Macêdo Mendes)
  * Fix: The `--schema-only` flag on update_index no longer expects an argument (Karl Hobley)
+ * Fix: Added file handling to support custom user add/edit forms with images/files (Eraldo Energy)
 
 
 1.5.3 (18.07.2016)
diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst
index 0682d4062d..46a67ed49f 100644
--- a/CONTRIBUTORS.rst
+++ b/CONTRIBUTORS.rst
@@ -159,6 +159,7 @@ Contributors
 * sebworks
 * Sean Muck
 * Fábio Macêdo Mendes
+* Eraldo Energy
 
 Translators
 ===========
diff --git a/docs/releases/1.6.rst b/docs/releases/1.6.rst
index 5d3db944ea..6a7846f1c9 100644
--- a/docs/releases/1.6.rst
+++ b/docs/releases/1.6.rst
@@ -70,6 +70,7 @@ Bug fixes
  * Saving a page by pressing enter key no longer triggers a "Changes may not be saved message" (Sean Muck, Matt Westcott)
  * RoutablePageMixin no longer breaks in the presence of instance-only attributes such as those generated by FileFields (Fábio Macêdo Mendes)
  * The ``--schema-only`` flag on update_index no longer expects an argument (Karl Hobley)
+ * Added file handling to support custom user add/edit forms with images/files (Eraldo Energy)
 
 
 Upgrade considerations
diff --git a/wagtail/tests/customuser/migrations/0002_added_file_field.py b/wagtail/tests/customuser/migrations/0002_added_file_field.py
new file mode 100644
index 0000000000..1a6a27faae
--- /dev/null
+++ b/wagtail/tests/customuser/migrations/0002_added_file_field.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('customuser', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='CustomUser',
+            name='attachment',
+            field=models.FileField(blank=True),
+        ),
+    ]
diff --git a/wagtail/tests/customuser/models.py b/wagtail/tests/customuser/models.py
index fc2ef95779..93c79edcfc 100644
--- a/wagtail/tests/customuser/models.py
+++ b/wagtail/tests/customuser/models.py
@@ -41,6 +41,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
     first_name = models.CharField(max_length=50, blank=True)
     last_name = models.CharField(max_length=50, blank=True)
     country = models.CharField(max_length=100, blank=True)
+    attachment = models.FileField(blank=True)
 
     USERNAME_FIELD = 'username'
     REQUIRED_FIELDS = ['email']
diff --git a/wagtail/tests/settings.py b/wagtail/tests/settings.py
index 2defe9cc15..5a3a51436f 100644
--- a/wagtail/tests/settings.py
+++ b/wagtail/tests/settings.py
@@ -168,7 +168,7 @@ WAGTAIL_SITE_NAME = "Test Site"
 # needs to here because it is used at the module level of wagtailusers.forms
 # when the module gets loaded. The decorator 'override_settings' does not work
 # in this scenario.
-WAGTAIL_USER_CUSTOM_FIELDS = ['country']
+WAGTAIL_USER_CUSTOM_FIELDS = ['country', 'attachment']
 
 WAGTAILADMIN_RICH_TEXT_EDITORS = {
     'default': {
diff --git a/wagtail/wagtailusers/templates/wagtailusers/users/create.html b/wagtail/wagtailusers/templates/wagtailusers/users/create.html
index 898553f17a..bbd3f0e252 100644
--- a/wagtail/wagtailusers/templates/wagtailusers/users/create.html
+++ b/wagtail/wagtailusers/templates/wagtailusers/users/create.html
@@ -12,7 +12,7 @@
         <li><a href="#roles">{% trans "Roles" %}</a></li>
     </ul>
 
-    <form action="{% url 'wagtailusers_users:add' %}" method="POST">
+    <form action="{% url 'wagtailusers_users:add' %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
         <div class="tab-content">
             {% csrf_token %}
             <section id="account" class="active nice-padding">
diff --git a/wagtail/wagtailusers/templates/wagtailusers/users/edit.html b/wagtail/wagtailusers/templates/wagtailusers/users/edit.html
index f89be03b16..a2d61673e2 100644
--- a/wagtail/wagtailusers/templates/wagtailusers/users/edit.html
+++ b/wagtail/wagtailusers/templates/wagtailusers/users/edit.html
@@ -12,7 +12,7 @@
         <li><a href="#roles">{% trans "Roles" %}</a></li>
     </ul>
 
-    <form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST">
+    <form action="{% url 'wagtailusers_users:edit' user.pk %}" method="POST"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
         <div class="tab-content">
             {% csrf_token %}
 
diff --git a/wagtail/wagtailusers/tests.py b/wagtail/wagtailusers/tests.py
index aa9727791c..e31b456d32 100644
--- a/wagtail/wagtailusers/tests.py
+++ b/wagtail/wagtailusers/tests.py
@@ -4,6 +4,7 @@ from django import forms
 from django.contrib.auth import get_user_model
 from django.contrib.auth.models import Group, Permission
 from django.core.exceptions import ImproperlyConfigured
+from django.core.files.uploadedfile import SimpleUploadedFile
 from django.core.urlresolvers import reverse
 from django.test import TestCase, override_settings
 from django.utils import six
@@ -23,10 +24,12 @@ delete_user_perm_codename = "delete_{0}".format(AUTH_USER_MODEL_NAME.lower())
 
 class CustomUserCreationForm(UserCreationForm):
     country = forms.CharField(required=True, label="Country")
+    attachment = forms.FileField(required=True, label="Attachment")
 
 
 class CustomUserEditForm(UserEditForm):
     country = forms.CharField(required=True, label="Country")
+    attachment = forms.FileField(required=True, label="Attachment")
 
 
 class TestUserFormHelpers(TestCase):
@@ -140,7 +143,7 @@ class TestUserCreateView(TestCase, WagtailTestUtils):
 
     @override_settings(
         WAGTAIL_USER_CREATION_FORM='wagtail.wagtailusers.tests.CustomUserCreationForm',
-        WAGTAIL_USER_CUSTOM_FIELDS=['country'],
+        WAGTAIL_USER_CUSTOM_FIELDS=['country', 'document'],
     )
     def test_create_with_custom_form(self):
         response = self.post({
@@ -151,6 +154,7 @@ class TestUserCreateView(TestCase, WagtailTestUtils):
             'password1': "password",
             'password2': "password",
             'country': "testcountry",
+            'attachment': SimpleUploadedFile('test.txt', b"Uploaded file"),
         })
 
         # Should redirect back to index
@@ -161,6 +165,7 @@ class TestUserCreateView(TestCase, WagtailTestUtils):
         self.assertEqual(users.count(), 1)
         self.assertEqual(users.first().email, 'test@user.com')
         self.assertEqual(users.first().country, 'testcountry')
+        self.assertEqual(users.first().attachment.read(), b"Uploaded file")
 
     def test_create_with_password_mismatch(self):
         response = self.post({
@@ -354,6 +359,7 @@ class TestUserEditView(TestCase, WagtailTestUtils):
             'password1': "password",
             'password2': "password",
             'country': "testcountry",
+            'attachment': SimpleUploadedFile('test.txt', b"Uploaded file"),
         })
 
         # Should redirect back to index
@@ -363,6 +369,7 @@ class TestUserEditView(TestCase, WagtailTestUtils):
         user = get_user_model().objects.get(pk=self.test_user.pk)
         self.assertEqual(user.first_name, 'Edited')
         self.assertEqual(user.country, 'testcountry')
+        self.assertEqual(user.attachment.read(), b"Uploaded file")
 
     def test_edit_validation_error(self):
         # Leave "username" field blank. This should give a validation error
diff --git a/wagtail/wagtailusers/views/users.py b/wagtail/wagtailusers/views/users.py
index ed8029041b..fcf359b8ac 100644
--- a/wagtail/wagtailusers/views/users.py
+++ b/wagtail/wagtailusers/views/users.py
@@ -122,7 +122,7 @@ def index(request):
 @permission_required(add_user_perm)
 def create(request):
     if request.method == 'POST':
-        form = get_user_creation_form()(request.POST)
+        form = get_user_creation_form()(request.POST, request.FILES)
         if form.is_valid():
             user = form.save()
             messages.success(request, _("User '{0}' created.").format(user), buttons=[
@@ -145,7 +145,7 @@ def edit(request, user_id):
     can_delete = user_can_delete_user(request.user, user)
 
     if request.method == 'POST':
-        form = get_user_edit_form()(request.POST, instance=user)
+        form = get_user_edit_form()(request.POST, request.FILES, instance=user)
         if form.is_valid():
             user = form.save()
             messages.success(request, _("User '{0}' updated.").format(user), buttons=[