from rest_framework import serializers from django.contrib.auth import get_user_model from django.contrib.auth.password_validation import validate_password from django.core.exceptions import ValidationError from django.urls import reverse from django.utils.translation import ugettext_lazy, ugettext as _ from misago.acl import serialize_acl from misago.users.authmixin import AuthMixin from misago.users.tokens import is_password_change_token_valid from .user import UserSerializer UserModel = get_user_model() class AuthenticatedUserSerializer(UserSerializer): email = serializers.SerializerMethodField() class Meta: model = UserModel fields = UserSerializer.Meta.fields + [ 'is_hiding_presence', 'limits_private_thread_invites_to', 'unread_private_threads', 'subscribe_to_started_threads', 'subscribe_to_replied_threads', ] def get_email(self, obj): return obj.email AuthenticatedUserSerializer = AuthenticatedUserSerializer.exclude_fields( 'is_avatar_locked', 'is_blocked', 'is_followed', 'is_signature_locked', 'meta', 'signature', 'status', ) class AnonymousUserSerializer(serializers.Serializer): id = serializers.ReadOnlyField() class LoginSerializer(serializers.Serializer, AuthMixin): username = serializers.CharField(max_length=255) password = serializers.CharField(max_length=255, trim_whitespace=False) def validate(self, data): user = self.authenticate(data.get('username'), data.get('password')) self.confirm_login_allowed(user) return {'user': user} class GetUserSerializer(serializers.Serializer, AuthMixin): email = serializers.EmailField(max_length=255) def validate(self, data): user = self.get_user_by_email(data.get('email')) self.confirm_allowed(user) return {'user': user} def confirm_allowed(self, user): """override this method to include additional checks""" pass class ResendActivationSerializer(GetUserSerializer): def confirm_allowed(self, user): username_format = {'user': user.username} if not user.requires_activation: message = _("%(user)s, your account is already active.") raise ValidationError(message % username_format) if user.requires_activation_by_admin: message = _("%(user)s, only administrator may activate your account.") raise ValidationError(message % username_format) class SendPasswordFormSerializer(GetUserSerializer): auth_messages = { 'inactive_user': ugettext_lazy( "You have to activate your account before " "you will be able to request new password." ), 'inactive_admin': ugettext_lazy( "Administrator has to activate your account before " "you will be able to request new password." ), } def confirm_allowed(self, user): self.confirm_user_active(user) class ChangeForgottenPasswordSerializer(serializers.Serializer, AuthMixin): password = serializers.CharField( max_length=255, trim_whitespace=False, ) token = serializers.CharField(max_length=255) auth_messages = { 'inactive_user': ugettext_lazy( "You have to activate your account before " "you will be able to change your password." ), 'inactive_admin': ugettext_lazy( "Administrator has to activate your account before " "you will be able to change your password." ), } def confirm_allowed(self): self.confirm_user_active(self.instance) self.confirm_user_not_banned(self.instance) def validate_password(self, value): validate_password(value, user=self.instance) return value def validate_token(self, value): if not is_password_change_token_valid(self.instance, value): raise ValidationError(_("Form link is invalid or expired. Please try again.")) return value def validate(self, data): self.confirm_allowed() return data def save(self): self.instance.set_password(self.validated_data['password']) self.instance.save()