Skip to content

Commit

Permalink
Fix/translation functions fixes (#8) (#9)
Browse files Browse the repository at this point in the history
* fix: proper use translation functions (#8)

* fix: translation interpolation fixes (#8)

* fix: more translation fixes (#8)

* feat: add special_characters to ContainsSpecialCharactersValidator msg (#8)

* feat: add special_characters to translation message, have consistent order (#8)

* chore: reformat with black

* chore: reformat with black
  • Loading branch information
bmihelac committed Jul 12, 2023
1 parent 1f050af commit b715fa6
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 63 deletions.
131 changes: 73 additions & 58 deletions django_advanced_password_validation/advanced_password_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"""

from django.core.exceptions import ValidationError
from django.utils.translation import ngettext as _
from django.utils.translation import gettext
from django.utils.translation import ngettext_lazy
from django.utils.translation import gettext_lazy as _


class ContainsDigitsValidator:
Expand Down Expand Up @@ -34,22 +34,22 @@ def validate(self, password, user=None):
"""
if sum(c.isdigit() for c in password) < self.min_digits:
raise ValidationError(
_(
f"Password must contain at least {self.min_digits} number.",
f"Password must contain at least {self.min_digits} numbers.",
ngettext_lazy(
"Password must contain at least %(min_digits)s number.",
"Password must contain at least %(min_digits)s numbers.",
self.min_digits,
),
)
% {"min_digits": self.min_digits},
code="password_too_weak",
params={"min_digits": self.min_digits},
)

def get_help_text(self):
"""
Get the help text for the validator.
"""
return _(
f"Your password must contain at least {self.min_digits} number.",
f"Your password must contain at least {self.min_digits} numbers.",
return ngettext_lazy(
"Your password must contain at least %(min_digits)s number.",
"Your password must contain at least %(min_digits)s numbers.",
self.min_digits,
) % {"min_digits": self.min_digits}

Expand Down Expand Up @@ -82,22 +82,26 @@ def validate(self, password, user=None):
"""
if sum(c.isupper() for c in password) < self.min_uppercase:
raise ValidationError(
_(
f"Password must contain at least {self.min_uppercase} uppercase character.",
f"Password must contain at least {self.min_uppercase} uppercase characters.",
ngettext_lazy(
"Password must contain at least %(min_uppercase)s uppercase"
" character.",
"Password must contain at least %(min_uppercase)s uppercase"
" characters.",
self.min_uppercase,
),
)
% {"min_uppercase": self.min_uppercase},
code="password_too_weak",
params={"min_uppercase": self.min_uppercase},
)

def get_help_text(self):
"""
Get the help text for the validator.
"""
return _(
f"Your password must contain at least {self.min_uppercase} uppercase character.",
f"Your password must contain at least {self.min_uppercase} uppercase characters.",
return ngettext_lazy(
"Your password must contain at least %(min_uppercase)s uppercase"
" character.",
"Your password must contain at least %(min_uppercase)s uppercase"
" characters.",
self.min_uppercase,
) % {"min_uppercase": self.min_uppercase}

Expand Down Expand Up @@ -130,22 +134,26 @@ def validate(self, password, user=None):
"""
if sum(c.islower() for c in password) < self.min_lowercase:
raise ValidationError(
_(
f"Password must contain at least {self.min_lowercase} lowercase character.",
f"Password must contain at least {self.min_lowercase} lowercase characters.",
ngettext_lazy(
"Password must contain at least %(min_lowercase)s lowercase"
" character.",
"Password must contain at least %(min_lowercase)s lowercase"
" characters.",
self.min_lowercase,
),
)
% {"min_lowercase": self.min_lowercase},
code="password_too_weak",
params={"min_lowercase": self.min_lowercase},
)

def get_help_text(self):
"""
Get the help text for the validator.
"""
return _(
f"Your password must contain at least {self.min_lowercase} lowercase character.",
f"Your password must contain at least {self.min_lowercase} lowercase characters.",
return ngettext_lazy(
"Your password must contain at least %(min_lowercase)s lowercase"
" character.",
"Your password must contain at least %(min_lowercase)s lowercase"
" characters.",
self.min_lowercase,
) % {"min_lowercase": self.min_lowercase}

Expand All @@ -163,7 +171,7 @@ def __init__(self, min_characters=1):
validate password against. Defaults to 1.
"""
self.min_characters = min_characters
self.characters = set(" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
self.characters = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"

def validate(self, password, user=None):
"""
Expand All @@ -177,26 +185,36 @@ def validate(self, password, user=None):
ValidationError: Password must contain at least {self.min_characters} special
character(s).
"""
if sum(c in self.characters for c in password) < self.min_characters:
if sum(c in set(self.characters) for c in password) < self.min_characters:
raise ValidationError(
_(
f"Password must contain at least {self.min_characters} special character.",
f"Password must contain at least {self.min_characters} special characters.",
ngettext_lazy(
"Password must contain at least %(min_characters)s special"
" character (%(special_characters)s).",
"Password must contain at least %(min_characters)s special"
" characters (%(special_characters)s).",
self.min_characters,
),
)
% {
"min_characters": self.min_characters,
"special_characters": "".join(self.characters),
},
code="password_too_weak",
params={"min_characters": self.min_characters},
)

def get_help_text(self):
"""
Get the help text for the validator.
"""
return _(
f"Your password must contain at least {self.min_characters} special character.",
f"Your password must contain at least {self.min_characters} special characters.",
return ngettext_lazy(
"Your password must contain at least %(min_characters)s special character"
" (%(special_characters)s).",
"Your password must contain at least %(min_characters)s special characters"
" (%(special_characters)s).",
self.min_characters,
) % {"min_characters": self.min_characters}
) % {
"min_characters": self.min_characters,
"special_characters": "".join(self.characters),
}


class MaximumLengthValidator:
Expand Down Expand Up @@ -227,9 +245,9 @@ def validate(self, password, user=None):
"""
if len(password) > self.max_length:
raise ValidationError(
_(
f"Password must contain at maximum {self.max_length} character.",
f"Password must contain at maximum {self.max_length} characters.",
ngettext_lazy(
"Password must contain at maximum %(max_length)s character.",
"Password must contain at maximum %(max_length)s characters.",
self.max_length,
)
% {"max_length": self.max_length}
Expand All @@ -239,9 +257,9 @@ def get_help_text(self):
"""
Get the help text for the validator.
"""
return _(
f"Password must contain at maximum {self.max_length} character.",
f"Password must contain at maximum {self.max_length} characters.",
return ngettext_lazy(
"Password must contain at maximum %(max_length)s character.",
"Password must contain at maximum %(max_length)s characters.",
self.max_length,
) % {"max_length": self.max_length}

Expand Down Expand Up @@ -277,7 +295,7 @@ def validate(self, password, user=None):
check = c * (self.max_consecutive + 1)
if check in password:
raise ValidationError(
gettext(
_(
"Password contains consecutively repeating characters. "
"e.g 'aaa' or '111'"
)
Expand All @@ -287,8 +305,9 @@ def get_help_text(self):
"""
Get the help text for the validator.
"""
return gettext(
"Password cannot contain consecutively repeating characters. e.g 'aaa' or '111'"
return _(
"Password cannot contain consecutively repeating characters. e.g 'aaa' or"
" '111'"
)


Expand Down Expand Up @@ -332,9 +351,9 @@ def validate(self, password, user=None):

while count >= self.max_consecutive:
raise ValidationError(
gettext(
"Password contains consecutively increasing digits. "
"e.g '12345'"
_(
"Password contains consecutively increasing"
" digits. e.g '12345'"
)
)
except IndexError:
Expand All @@ -344,9 +363,7 @@ def get_help_text(self):
"""
Get the help text for the validator.
"""
return gettext(
"Password cannot contain consecutively increasing digits. e.g '12345'"
)
return _("Password cannot contain consecutively increasing digits. e.g '12345'")


class ConsecutivelyDecreasingDigitValidator:
Expand Down Expand Up @@ -389,9 +406,9 @@ def validate(self, password, user=None):

while count >= self.max_consecutive:
raise ValidationError(
gettext(
"Password contains consecutively decreasing digits. "
"e.g '54321'"
_(
"Password contains consecutively decreasing"
" digits. e.g '54321'"
)
)
except IndexError:
Expand All @@ -401,6 +418,4 @@ def get_help_text(self):
"""
Get the help text for the validator.
"""
return gettext(
"Password cannot contain consecutively decreasing digits. e.g '54321'"
)
return _("Password cannot contain consecutively decreasing digits. e.g '54321'")
20 changes: 15 additions & 5 deletions django_advanced_password_validation/tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ def test_contains_special_characters_validator():
with pytest.raises(ValidationError) as exc:
validator.validate("abcdefghij")
assert exc.value.code == "password_too_weak"
assert exc.value.message == "Password must contain at least 1 special character."
assert (
exc.value.message
== "Password must contain at least 1 special character ("
" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)."
)


def test_contains_special_characters_get_help_text():
Expand All @@ -120,12 +124,14 @@ def test_contains_special_characters_get_help_text():
validator = ContainsSpecialCharactersValidator(min_characters=1)
assert (
validator.get_help_text()
== "Your password must contain at least 1 special character."
== "Your password must contain at least 1 special character ("
" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)."
)
validator = ContainsSpecialCharactersValidator(min_characters=2)
assert (
validator.get_help_text()
== "Your password must contain at least 2 special characters."
== "Your password must contain at least 2 special characters ("
" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)."
)


Expand Down Expand Up @@ -175,7 +181,8 @@ def test_max_consecutive_characters_get_help_text():
validator = MaxConsecutiveCharactersValidator()
assert (
validator.get_help_text()
== "Password cannot contain consecutively repeating characters. e.g 'aaa' or '111'"
== "Password cannot contain consecutively repeating characters. e.g 'aaa' or"
" '111'"
)


Expand Down Expand Up @@ -255,5 +262,8 @@ def test_invalid_password():
"Password must contain at least 1 number.",
"Password must contain at least 1 uppercase character.",
"Password must contain at least 1 lowercase character.",
"Password must contain at least 1 special character.",
(
"Password must contain at least 1 special character ("
" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)."
),
]

0 comments on commit b715fa6

Please sign in to comment.