auth.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. from django import forms
  2. from django.contrib.auth import authenticate, get_user_model
  3. from django.contrib.auth.forms import AuthenticationForm as BaseAuthenticationForm
  4. from django.core.exceptions import ValidationError
  5. from django.core.validators import validate_email
  6. from django.utils.translation import gettext_lazy as _
  7. from ..bans import get_user_ban
  8. User = get_user_model()
  9. class MisagoAuthMixin:
  10. error_messages = {
  11. "empty_data": _("Fill out both fields."),
  12. "invalid_login": _("Login or password is incorrect."),
  13. "inactive_user": _(
  14. "You have to activate your account before you will be able to sign in."
  15. ),
  16. "inactive_admin": _(
  17. "Your account has to be activated by site administrator "
  18. "before you will be able to sign in."
  19. ),
  20. }
  21. def confirm_user_active(self, user):
  22. if user.requires_activation_by_admin:
  23. raise ValidationError(
  24. self.error_messages["inactive_admin"], code="inactive_admin"
  25. )
  26. if user.requires_activation_by_user:
  27. raise ValidationError(
  28. self.error_messages["inactive_user"], code="inactive_user"
  29. )
  30. def confirm_user_not_banned(self, user):
  31. if not user.is_staff:
  32. self.user_ban = get_user_ban(user, self.request.cache_versions)
  33. if self.user_ban:
  34. raise ValidationError("", code="banned")
  35. def get_errors_dict(self):
  36. error = self.errors.as_data()["__all__"][0]
  37. if error.code == "banned":
  38. error.message = self.user_ban.ban.get_serialized_message()
  39. else:
  40. error.message = error.messages[0]
  41. return {"detail": error.message, "code": error.code}
  42. class AuthenticationForm(MisagoAuthMixin, BaseAuthenticationForm):
  43. """
  44. Base class for authenticating users, Floppy-forms and
  45. Misago login field compliant
  46. """
  47. username = forms.CharField(
  48. label=_("Username or e-mail"), required=False, max_length=254
  49. )
  50. password = forms.CharField(
  51. label=_("Password"), strip=False, required=False, widget=forms.PasswordInput
  52. )
  53. def __init__(self, *args, request=None, **kwargs):
  54. self.request = request
  55. super().__init__(*args, **kwargs)
  56. def clean(self):
  57. username = self.cleaned_data.get("username")
  58. password = self.cleaned_data.get("password")
  59. if username and password:
  60. self.user_cache = authenticate(username=username, password=password)
  61. if self.user_cache is None or not self.user_cache.is_active:
  62. raise ValidationError(
  63. self.error_messages["invalid_login"], code="invalid_login"
  64. )
  65. else:
  66. self.confirm_login_allowed(self.user_cache)
  67. else:
  68. raise ValidationError(self.error_messages["empty_data"], code="empty_data")
  69. return self.cleaned_data
  70. def confirm_login_allowed(self, user):
  71. self.confirm_user_active(user)
  72. self.confirm_user_not_banned(user)
  73. class AdminAuthenticationForm(AuthenticationForm):
  74. required_css_class = "required"
  75. def __init__(self, *args, **kwargs):
  76. self.error_messages.update(
  77. {"not_staff": _("Your account does not have admin privileges.")}
  78. )
  79. super().__init__(*args, **kwargs)
  80. def confirm_login_allowed(self, user):
  81. if not user.is_staff:
  82. raise forms.ValidationError(
  83. self.error_messages["not_staff"], code="not_staff"
  84. )
  85. class GetUserForm(MisagoAuthMixin, forms.Form):
  86. email = forms.CharField()
  87. def clean(self):
  88. data = super().clean()
  89. email = data.get("email")
  90. if not email or len(email) > 250:
  91. raise forms.ValidationError(_("Enter e-mail address."), code="empty_email")
  92. try:
  93. validate_email(email)
  94. except forms.ValidationError:
  95. raise forms.ValidationError(
  96. _("Entered e-mail is invalid."), code="invalid_email"
  97. )
  98. try:
  99. user = User.objects.get_by_email(data["email"])
  100. if not user.is_active:
  101. raise User.DoesNotExist()
  102. self.user_cache = user
  103. except User.DoesNotExist:
  104. raise forms.ValidationError(
  105. _("No user with this e-mail exists."), code="not_found"
  106. )
  107. self.confirm_allowed(user)
  108. return data
  109. def confirm_allowed(self, user):
  110. """override this method to include additional checks"""
  111. class ResendActivationForm(GetUserForm):
  112. def confirm_allowed(self, user):
  113. username_format = {"user": user.username}
  114. if not user.requires_activation:
  115. message = _("%(user)s, your account is already active.")
  116. raise forms.ValidationError(
  117. message % username_format, code="already_active"
  118. )
  119. if user.requires_activation_by_admin:
  120. message = _("%(user)s, only administrator may activate your account.")
  121. raise forms.ValidationError(
  122. message % username_format, code="inactive_admin"
  123. )
  124. class ResetPasswordForm(GetUserForm):
  125. error_messages = {
  126. "inactive_user": _(
  127. "You have to activate your account before "
  128. "you will be able to request new password."
  129. ),
  130. "inactive_admin": _(
  131. "Administrator has to activate your account before "
  132. "you will be able to request new password."
  133. ),
  134. }
  135. def confirm_allowed(self, user):
  136. self.confirm_user_active(user)