<commit_before># Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.

"""
Forms and validation code for user registration and updating.

"""

import datetime
import re

from django import forms

from django.contrib.auth import get_user_model
from django.contrib.auth.forms import PasswordChangeForm, SetPasswordForm
from django.contrib.sites.models import get_current_site
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe

from registration.models import RegistrationProfile

from urlparse import urlsplit, urlunsplit

from .models import Country
from .models import Organisation
from .models import ProjectUpdate
from .models import ProjectUpdateLocation

from akvo import settings

PASSWORD_MINIMUM_LENGTH = settings.PASSWORD_MINIMUM_LENGTH


def check_password_minimum_length(password):
    if len(password) < PASSWORD_MINIMUM_LENGTH:
        raise forms.ValidationError(
            _(u'Passwords must be at least {} characters long.'.format(
                PASSWORD_MINIMUM_LENGTH))
        )


def check_password_has_number(password):
    if not re.findall('\d', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one digit, 0-9.')
        )


def check_password_has_upper(password):
    if not re.findall('[A-Z]', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one uppercase letter, A-Z.')
        )


def check_password_has_lower(password):
    if not re.findall('[a-z]', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one lowercase letter, a-z.')
        )


def check_password_has_symbol(password):
    if not re.findall('[()[\]{}|\\`~!@#$%^&*_\-+=;:\'",<>./?]', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one symbol: '
              u'()[]{}|\`~!@#$%^&*_-+=;:\'",<>./?')
        )


class PasswordValidationMixin():

    def clean(self):
        def check_passwords_identical(password1, password2):
            if password1 != password2:
                raise forms.ValidationError(
                    _(u'Passwords do not match. Please enter the same password in both fields.')
                )

        if 'password1' in self.cleaned_data:
            password1 = self.cleaned_data['password1']
            password2 = self.cleaned_data['password2']
        elif 'new_password1' in self.cleaned_data:
            password1 = self.cleaned_data['new_password1']
            password2 = self.cleaned_data['new_password2']
        else:
            raise forms.ValidationError(
                _(u"Couldn't find the password fields in the form")
            )

        check_passwords_identical(password1, password2)

        check_password_minimum_length(password1)
        check_password_has_number(password1)
        check_password_has_upper(password1)
        check_password_has_lower(password1)
        check_password_has_symbol(password1)

        return self.cleaned_data


class RegisterForm(PasswordValidationMixin, forms.Form):
    email = forms.EmailField(
        label=_(u'Email'),
        max_length=254,
        widget=forms.TextInput(
            attrs={'placeholder': _(u'Email')}
        ),
    )
    first_name = forms.CharField(
        label=_(u'First name'),
        max_length=30,
        widget=forms.TextInput(
            attrs={'placeholder': _(u'First name')}
        ),
    )
    last_name = forms.CharField(
        label=_(u'Last name'),
        max_length=30,
        widget=forms.TextInput(
            attrs={'placeholder': _(u'Last name')}
        ),
    )
    password1 = forms.CharField(
        label=_(u'Password'),
        widget=forms.PasswordInput(
            attrs={'placeholder': _(u'Password')},
            render_value=False
        )
    )
    password2 = forms.CharField(
        label=_(u'Repeat password'),
        widget=forms.PasswordInput(
            attrs={'placeholder': _(u'Repeat password')},
            render_value=False
        )
    )

    def clean_email(self):
        """
        Verify that the email entered does not exist as an email or username.
        """
        email = self.cleaned_data['email']
        if get_user_model().objects.filter(email__iexact=email).exists() \
                or get_user_model().objects.filter(username__iexact=email).exists():
            raise forms.ValidationError(_(u'A user with this email address already exists.'))
        return email

    def save(self, request):
        """
        Create the new User and RegistrationProfile, and returns the User.

        This is essentially a light wrapper around
        RegistrationProfile.objects.create_inactive_user(), feeding it the form data and
        a profile callback (see the documentation on create_inactive_user() for details)
        if supplied. Modified to set user.is_active = False and add User object creation.
        """
        site = get_current_site(request)
        new_user = RegistrationProfile.objects.create_inactive_user(
            username=self.cleaned_data['email'],
            email=self.cleaned_data['email'],
            password=self.cleaned_data['<PASSWORD>'],
            site=site,
        )
        new_user.first_name = self.cleaned_data['first_name']
        new_user.last_name = self.cleaned_data['last_name']
        new_user.is_active = False<commit_msg>[#3357] Fix validation errors when passwords didn't match<commit_after># Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.

"""
Forms and validation code for user registration and updating.

"""

import datetime
import re

from django import forms

from django.contrib.auth import get_user_model
from django.contrib.auth.forms import PasswordChangeForm, SetPasswordForm
from django.contrib.sites.models import get_current_site
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe

from registration.models import RegistrationProfile

from urlparse import urlsplit, urlunsplit

from .models import Country
from .models import Organisation
from .models import ProjectUpdate
from .models import ProjectUpdateLocation

from akvo import settings

PASSWORD_MINIMUM_LENGTH = settings.PASSWORD_MINIMUM_LENGTH


def check_password_minimum_length(password):
    if len(password) < PASSWORD_MINIMUM_LENGTH:
        raise forms.ValidationError(
            _(u'Passwords must be at least {} characters long.'.format(
                PASSWORD_MINIMUM_LENGTH))
        )


def check_password_has_number(password):
    if not re.findall('\d', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one digit, 0-9.')
        )


def check_password_has_upper(password):
    if not re.findall('[A-Z]', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one uppercase letter, A-Z.')
        )


def check_password_has_lower(password):
    if not re.findall('[a-z]', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one lowercase letter, a-z.')
        )


def check_password_has_symbol(password):
    if not re.findall('[()[\]{}|\\`~!@#$%^&*_\-+=;:\'",<>./?]', password):
        raise forms.ValidationError(
            _(u'The password must contain at least one symbol: '
              u'()[]{}|\`~!@#$%^&*_-+=;:\'",<>./?')
        )


class PasswordValidationMixin():

    def clean(self):
        if self.errors:
            raise forms.ValidationError(
                self.errors[self.errors.keys()[0]]
            )

        if 'password1' in self.cleaned_data:
            password = self.cleaned_data['password1']
        elif 'new_password1' in self.cleaned_data:
            password = self.cleaned_data['<PASSWORD>password1']
        else:
            raise forms.ValidationError(
                _(u"Couldn't find the password fields in the form")
            )

        check_password_minimum_length(password)
        check_password_has_number(password)
        check_password_has_upper(password)
        check_password_has_lower(password)
        check_password_has_symbol(password)

        return self.cleaned_data


class RegisterForm(PasswordValidationMixin, forms.Form):
    email = forms.EmailField(
        label=_(u'Email'),
        max_length=254,
        widget=forms.TextInput(
            attrs={'placeholder': _(u'Email')}
        ),
    )
    first_name = forms.CharField(
        label=_(u'First name'),
        max_length=30,
        widget=forms.TextInput(
            attrs={'placeholder': _(u'First name')}
        ),
    )
    last_name = forms.CharField(
        label=_(u'Last name'),
        max_length=30,
        widget=forms.TextInput(
            attrs={'placeholder': _(u'Last name')}
        ),
    )
    password1 = forms.CharField(
        label=_(u'Password'),
        widget=forms.PasswordInput(
            attrs={'placeholder': _(u'Password')},
            render_value=False
        )
    )
    password2 = forms.CharField(
        label=_(u'Repeat password'),
        widget=forms.PasswordInput(
            attrs={'placeholder': _(u'Repeat password')},
            render_value=False
        )
    )

    def clean_email(self):
        """
        Verify that the email entered does not exist as an email or username.
        """
        email = self.cleaned_data['email']
        if get_user_model().objects.filter(email__iexact=email).exists() \
                or get_user_model().objects.filter(username__iexact=email).exists():
            raise forms.ValidationError(_(u'A user with this email address already exists.'))
        return email

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2:
            if password1 != password2:
                raise forms.ValidationError(
                    _(u'Passwords do not match. Please enter the same password in both fields.')
                )
        return password2

    def save(self, request):
        """
        Create the new User and RegistrationProfile, and returns the User.

        This is essentially a light wrapper around
        RegistrationProfile.objects.create_inactive_user(), feeding it the form data and
        a profile callback (see the documentation on create_inactive_user() for details)
        if supplied. Modified to set user.is_active = False and add User object creation.
        """
        site = get_current_site(request)
        new_user = RegistrationProfile.objects.create_inactive_user(
            username=self.cleaned_data['email'],
            email=self.cleaned_data['email'],
            password=<PASSWORD>_data['<PASSWORD>'],
            site=site,
        )
        new_user.first_name = self.cleaned_data['first_name']
        new_user.last_name = self.cleaned_data['last_name']
        new_user.is_active = False
{'fraction_non_alphanumeric': 0.09977204979835175, 'fraction_numerical': 0.005435735577766088, 'mean_word_length': 2.659608598010908, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '183892', 'n_tokens_mistral': 3208, 'n_tokens_neox': 3141, 'n_words': 800}