auth.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. from rest_framework import serializers
  2. from django.contrib.auth import get_user_model
  3. from django.contrib.auth.password_validation import validate_password
  4. from django.core.exceptions import ValidationError
  5. from django.urls import reverse
  6. from django.utils.translation import ugettext_lazy, ugettext as _
  7. from misago.acl import serialize_acl
  8. from misago.users.authmixin import AuthMixin
  9. from misago.users.tokens import is_password_change_token_valid
  10. from .user import UserSerializer
  11. UserModel = get_user_model()
  12. __all__ = [
  13. 'AuthenticatedUserSerializer',
  14. 'AnonymousUserSerializer',
  15. 'LoginSerializer',
  16. 'ResendActivationSerializer',
  17. 'SendPasswordFormSerializer',
  18. 'ChangePasswordSerializer',
  19. ]
  20. class AuthFlags(object):
  21. def get_is_authenticated(self, obj):
  22. return bool(obj.is_authenticated)
  23. def get_is_anonymous(self, obj):
  24. return bool(obj.is_anonymous)
  25. class AuthenticatedUserSerializer(UserSerializer, AuthFlags):
  26. email = serializers.SerializerMethodField()
  27. is_authenticated = serializers.SerializerMethodField()
  28. is_anonymous = serializers.SerializerMethodField()
  29. class Meta:
  30. model = UserModel
  31. fields = UserSerializer.Meta.fields + [
  32. 'is_hiding_presence',
  33. 'limits_private_thread_invites_to',
  34. 'unread_private_threads',
  35. 'subscribe_to_started_threads',
  36. 'subscribe_to_replied_threads',
  37. 'is_authenticated',
  38. 'is_anonymous',
  39. ]
  40. def get_acl(self, obj):
  41. return serialize_acl(obj)
  42. def get_email(self, obj):
  43. return obj.email
  44. def get_api(self, obj):
  45. return {
  46. 'avatar': reverse('misago:api:user-avatar', kwargs={'pk': obj.pk}),
  47. 'details': reverse('misago:api:user-details', kwargs={'pk': obj.pk}),
  48. 'change_email': reverse('misago:api:user-change-email', kwargs={'pk': obj.pk}),
  49. 'change_password': reverse('misago:api:user-change-password', kwargs={'pk': obj.pk}),
  50. 'edit_details': reverse('misago:api:user-edit-details', kwargs={'pk': obj.pk}),
  51. 'options': reverse('misago:api:user-forum-options', kwargs={'pk': obj.pk}),
  52. 'username': reverse('misago:api:user-username', kwargs={'pk': obj.pk}),
  53. }
  54. AuthenticatedUserSerializer = AuthenticatedUserSerializer.exclude_fields(
  55. 'is_avatar_locked',
  56. 'is_blocked',
  57. 'is_followed',
  58. 'is_signature_locked',
  59. 'meta',
  60. 'signature',
  61. 'status',
  62. )
  63. class AnonymousUserSerializer(serializers.Serializer, AuthFlags):
  64. id = serializers.ReadOnlyField()
  65. acl = serializers.SerializerMethodField()
  66. is_authenticated = serializers.SerializerMethodField()
  67. is_anonymous = serializers.SerializerMethodField()
  68. def get_acl(self, obj):
  69. if hasattr(obj, 'acl_cache'):
  70. return serialize_acl(obj)
  71. else:
  72. return {}
  73. class LoginSerializer(serializers.Serializer, AuthMixin):
  74. username = serializers.CharField(max_length=254)
  75. password = serializers.CharField(max_length=255, trim_whitespace=False)
  76. def validate(self, data):
  77. user = self.authenticate(data.get('username'), data.get('password'))
  78. self.confirm_login_allowed(user)
  79. return {'user': user}
  80. class GetUserSerializer(serializers.Serializer, AuthMixin):
  81. email = serializers.EmailField(max_length=255)
  82. def validate(self, data):
  83. user = self.get_user_by_email(data.get('email'))
  84. self.confirm_allowed(user)
  85. return {'user': user}
  86. def confirm_allowed(self, user):
  87. """override this method to include additional checks"""
  88. pass
  89. class ResendActivationSerializer(GetUserSerializer):
  90. def confirm_allowed(self, user):
  91. username_format = {'user': user.username}
  92. if not user.requires_activation:
  93. message = _("%(user)s, your account is already active.")
  94. raise ValidationError(message % username_format)
  95. if user.requires_activation_by_admin:
  96. message = _("%(user)s, only administrator may activate your account.")
  97. raise ValidationError(message % username_format)
  98. class SendPasswordFormSerializer(GetUserSerializer):
  99. auth_messages = {
  100. 'inactive_user': ugettext_lazy(
  101. "You have to activate your account before "
  102. "you will be able to request new password."
  103. ),
  104. 'inactive_admin': ugettext_lazy(
  105. "Administrator has to activate your account before "
  106. "you will be able to request new password."
  107. ),
  108. }
  109. def confirm_allowed(self, user):
  110. self.confirm_user_active(user)
  111. class ChangePasswordSerializer(serializers.Serializer, AuthMixin):
  112. password = serializers.CharField(
  113. max_length=255,
  114. trim_whitespace=False,
  115. )
  116. token = serializers.CharField(max_length=255)
  117. auth_messages = {
  118. 'inactive_user': ugettext_lazy(
  119. "You have to activate your account before "
  120. "you will be able to change your password."
  121. ),
  122. 'inactive_admin': ugettext_lazy(
  123. "Administrator has to activate your account before "
  124. "you will be able to change your password."
  125. ),
  126. }
  127. def confirm_allowed(self):
  128. self.confirm_user_active(self.instance)
  129. self.confirm_user_not_banned(self.instance)
  130. def validate_password(self, value):
  131. validate_password(value, user=self.instance)
  132. return value
  133. def validate_token(self, value):
  134. if not is_password_change_token_valid(self.instance, value):
  135. raise ValidationError(_("Form link is invalid or expired. Please try again."))
  136. return value
  137. def validate(self, data):
  138. self.confirm_allowed()
  139. return data
  140. def save(self):
  141. self.instance.set_password(self.validated_data['password'])
  142. self.instance.save()
  143. class CreateUserSerializer(serializers.ModelSerializer):
  144. class Meta:
  145. model = UserModel