prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Passwords complexity
  We must ensure passwords respect a minimum complexity.
  
  See https://github.com/modoboa/modoboa-admin/issues/27
  
  
  </issue>
  <code>
  [start of modoboa/core/forms.py]
  1 # coding: utf-8
  2 
  3 """Core forms."""
  4 
  5 from django import forms
  6 from django.utils.translation import ugettext as _, ugettext_lazy
  7 
  8 from modoboa.core.models import User
  9 from modoboa.lib import parameters
  10 
  11 
  12 class LoginForm(forms.Form):
  13     username = forms.CharField(
  14         label=ugettext_lazy("Username"),
  15         widget=forms.TextInput(attrs={"class": "form-control"})
  16     )
  17     password = forms.CharField(
  18         label=ugettext_lazy("Password"),
  19         widget=forms.PasswordInput(attrs={"class": "form-control"})
  20     )
  21     rememberme = forms.BooleanField(
  22         initial=False,
  23         required=False
  24     )
  25 
  26 
  27 class ProfileForm(forms.ModelForm):
  28     oldpassword = forms.CharField(
  29         label=ugettext_lazy("Old password"), required=False,
  30         widget=forms.PasswordInput(attrs={"class": "form-control"})
  31     )
  32     newpassword = forms.CharField(
  33         label=ugettext_lazy("New password"), required=False,
  34         widget=forms.PasswordInput(attrs={"class": "form-control"})
  35     )
  36     confirmation = forms.CharField(
  37         label=ugettext_lazy("Confirmation"), required=False,
  38         widget=forms.PasswordInput(attrs={"class": "form-control"})
  39     )
  40 
  41     class Meta:
  42         model = User
  43         fields = ("first_name", "last_name")
  44         widgets = {
  45             'first_name': forms.TextInput(attrs={'class': 'form-control'}),
  46             'last_name': forms.TextInput(attrs={'class': 'form-control'})
  47         }
  48 
  49     def __init__(self, update_password, *args, **kwargs):
  50         super(ProfileForm, self).__init__(*args, **kwargs)
  51         if not update_password:
  52             del self.fields["oldpassword"]
  53             del self.fields["newpassword"]
  54             del self.fields["confirmation"]
  55 
  56     def clean_oldpassword(self):
  57         if self.cleaned_data["oldpassword"] == "":
  58             return self.cleaned_data["oldpassword"]
  59 
  60         if parameters.get_admin("AUTHENTICATION_TYPE") != "local":
  61             return self.cleaned_data["oldpassword"]
  62 
  63         if not self.instance.check_password(self.cleaned_data["oldpassword"]):
  64             raise forms.ValidationError(_("Old password mismatchs"))
  65         return self.cleaned_data["oldpassword"]
  66 
  67     def clean_confirmation(self):
  68         newpassword = self.cleaned_data["newpassword"]
  69         confirmation = self.cleaned_data["confirmation"]
  70         if newpassword != confirmation:
  71             raise forms.ValidationError(_("Passwords mismatch"))
  72         return self.cleaned_data["confirmation"]
  73 
  74     def save(self, commit=True):
  75         user = super(ProfileForm, self).save(commit=False)
  76         if commit:
  77             if self.cleaned_data.get("confirmation", "") != "":
  78                 user.set_password(
  79                     self.cleaned_data["confirmation"],
  80                     self.cleaned_data["oldpassword"]
  81                 )
  82             user.save()
  83         return user
  84
  [end of modoboa/core/forms.py]
  [start of modoboa/core/dev_settings.py]
  1 # Development settings
  2 import os
  3 
  4 BOWER_COMPONENTS_ROOT = os.path.join(
  5     os.path.dirname(__file__), ".."
  6 )
  7 
  8 BOWER_INSTALLED_APPS = (
  9     "jquery#1.9",
  10     "jquery-ui#1.11",
  11     "bootstrap#3.3.1",
  12     "bootstrap-select#1.6",
  13     "d3#3.5.0",
  14     "eonasdan-bootstrap-datetimepicker#3.1.3",
  15     "font-awesome#4.2.0",
  16     "c3#0.4.10",
  17 )
  18
  [end of modoboa/core/dev_settings.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/modoboa/core/dev_settings.py b/modoboa/core/dev_settings.py
  --- a/modoboa/core/dev_settings.py
  +++ b/modoboa/core/dev_settings.py
  @@ -8,7 +8,7 @@
   BOWER_INSTALLED_APPS = (
       "jquery#1.9",
       "jquery-ui#1.11",
  -    "bootstrap#3.3.1",
  +    "bootstrap#3.3.5",
       "bootstrap-select#1.6",
       "d3#3.5.0",
       "eonasdan-bootstrap-datetimepicker#3.1.3",
  diff --git a/modoboa/core/forms.py b/modoboa/core/forms.py
  --- a/modoboa/core/forms.py
  +++ b/modoboa/core/forms.py
  @@ -5,6 +5,8 @@
   from django import forms
   from django.utils.translation import ugettext as _, ugettext_lazy
   
  +from passwords.fields import PasswordField
  +
   from modoboa.core.models import User
   from modoboa.lib import parameters
   
  @@ -29,11 +31,11 @@
           label=ugettext_lazy("Old password"), required=False,
           widget=forms.PasswordInput(attrs={"class": "form-control"})
       )
  -    newpassword = forms.CharField(
  +    newpassword = PasswordField(
           label=ugettext_lazy("New password"), required=False,
           widget=forms.PasswordInput(attrs={"class": "form-control"})
       )
  -    confirmation = forms.CharField(
  +    confirmation = PasswordField(
           label=ugettext_lazy("Confirmation"), required=False,
           widget=forms.PasswordInput(attrs={"class": "form-control"})
       )
  
verification_info: {"golden_diff": "diff --git a/modoboa/core/dev_settings.py b/modoboa/core/dev_settings.py\n--- a/modoboa/core/dev_settings.py\n+++ b/modoboa/core/dev_settings.py\n@@ -8,7 +8,7 @@\n BOWER_INSTALLED_APPS = (\n     \"jquery#1.9\",\n     \"jquery-ui#1.11\",\n-    \"bootstrap#3.3.1\",\n+    \"bootstrap#3.3.5\",\n     \"bootstrap-select#1.6\",\n     \"d3#3.5.0\",\n     \"eonasdan-bootstrap-datetimepicker#3.1.3\",\ndiff --git a/modoboa/core/forms.py b/modoboa/core/forms.py\n--- a/modoboa/core/forms.py\n+++ b/modoboa/core/forms.py\n@@ -5,6 +5,8 @@\n from django import forms\n from django.utils.translation import ugettext as _, ugettext_lazy\n \n+from passwords.fields import PasswordField\n+\n from modoboa.core.models import User\n from modoboa.lib import parameters\n \n@@ -29,11 +31,11 @@\n         label=ugettext_lazy(\"Old password\"), required=False,\n         widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n     )\n-    newpassword = forms.CharField(\n+    newpassword = PasswordField(\n         label=ugettext_lazy(\"New password\"), required=False,\n         widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n     )\n-    confirmation = forms.CharField(\n+    confirmation = PasswordField(\n         label=ugettext_lazy(\"Confirmation\"), required=False,\n         widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n     )\n", "issue": "Passwords complexity\nWe must ensure passwords respect a minimum complexity.\n\nSee https://github.com/modoboa/modoboa-admin/issues/27\n\n", "before_files": [{"content": "# coding: utf-8\n\n\"\"\"Core forms.\"\"\"\n\nfrom django import forms\nfrom django.utils.translation import ugettext as _, ugettext_lazy\n\nfrom modoboa.core.models import User\nfrom modoboa.lib import parameters\n\n\nclass LoginForm(forms.Form):\n    username = forms.CharField(\n        label=ugettext_lazy(\"Username\"),\n        widget=forms.TextInput(attrs={\"class\": \"form-control\"})\n    )\n    password = forms.CharField(\n        label=ugettext_lazy(\"Password\"),\n        widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n    )\n    rememberme = forms.BooleanField(\n        initial=False,\n        required=False\n    )\n\n\nclass ProfileForm(forms.ModelForm):\n    oldpassword = forms.CharField(\n        label=ugettext_lazy(\"Old password\"), required=False,\n        widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n    )\n    newpassword = forms.CharField(\n        label=ugettext_lazy(\"New password\"), required=False,\n        widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n    )\n    confirmation = forms.CharField(\n        label=ugettext_lazy(\"Confirmation\"), required=False,\n        widget=forms.PasswordInput(attrs={\"class\": \"form-control\"})\n    )\n\n    class Meta:\n        model = User\n        fields = (\"first_name\", \"last_name\")\n        widgets = {\n            'first_name': forms.TextInput(attrs={'class': 'form-control'}),\n            'last_name': forms.TextInput(attrs={'class': 'form-control'})\n        }\n\n    def __init__(self, update_password, *args, **kwargs):\n        super(ProfileForm, self).__init__(*args, **kwargs)\n        if not update_password:\n            del self.fields[\"oldpassword\"]\n            del self.fields[\"newpassword\"]\n            del self.fields[\"confirmation\"]\n\n    def clean_oldpassword(self):\n        if self.cleaned_data[\"oldpassword\"] == \"\":\n            return self.cleaned_data[\"oldpassword\"]\n\n        if parameters.get_admin(\"AUTHENTICATION_TYPE\") != \"local\":\n            return self.cleaned_data[\"oldpassword\"]\n\n        if not self.instance.check_password(self.cleaned_data[\"oldpassword\"]):\n            raise forms.ValidationError(_(\"Old password mismatchs\"))\n        return self.cleaned_data[\"oldpassword\"]\n\n    def clean_confirmation(self):\n        newpassword = self.cleaned_data[\"newpassword\"]\n        confirmation = self.cleaned_data[\"confirmation\"]\n        if newpassword != confirmation:\n            raise forms.ValidationError(_(\"Passwords mismatch\"))\n        return self.cleaned_data[\"confirmation\"]\n\n    def save(self, commit=True):\n        user = super(ProfileForm, self).save(commit=False)\n        if commit:\n            if self.cleaned_data.get(\"confirmation\", \"\") != \"\":\n                user.set_password(\n                    self.cleaned_data[\"confirmation\"],\n                    self.cleaned_data[\"oldpassword\"]\n                )\n            user.save()\n        return user\n", "path": "modoboa/core/forms.py"}, {"content": "# Development settings\nimport os\n\nBOWER_COMPONENTS_ROOT = os.path.join(\n    os.path.dirname(__file__), \"..\"\n)\n\nBOWER_INSTALLED_APPS = (\n    \"jquery#1.9\",\n    \"jquery-ui#1.11\",\n    \"bootstrap#3.3.1\",\n    \"bootstrap-select#1.6\",\n    \"d3#3.5.0\",\n    \"eonasdan-bootstrap-datetimepicker#3.1.3\",\n    \"font-awesome#4.2.0\",\n    \"c3#0.4.10\",\n)\n", "path": "modoboa/core/dev_settings.py"}]}