auth.py 5.4 KB

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