Migrating users serializers and validators
parent
39075288ac
commit
7d2b6c34ce
|
@ -25,3 +25,7 @@ def dict_sum(*args):
|
|||
assert isinstance(arg, dict)
|
||||
result += collections.Counter(arg)
|
||||
return result
|
||||
|
||||
|
||||
def into_namedtuple(dictionary):
|
||||
return collections.namedtuple('GenericDict', dictionary.keys())(**dictionary)
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import uuid
|
||||
|
||||
from django.apps import apps
|
||||
from django.db.models import Q, F
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.validators import validate_email
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -28,21 +27,21 @@ from django.conf import settings
|
|||
from taiga.base import exceptions as exc
|
||||
from taiga.base import filters
|
||||
from taiga.base import response
|
||||
from taiga.base.utils.dicts import into_namedtuple
|
||||
from taiga.auth.tokens import get_user_for_token
|
||||
from taiga.base.decorators import list_route
|
||||
from taiga.base.decorators import detail_route
|
||||
from taiga.base.api import ModelCrudViewSet
|
||||
from taiga.base.api.mixins import BlockedByProjectMixin
|
||||
from taiga.base.filters import PermissionBasedFilterBackend
|
||||
from taiga.base.api.utils import get_object_or_404
|
||||
from taiga.base.filters import MembersFilterBackend
|
||||
from taiga.base.mails import mail_builder
|
||||
from taiga.projects.votes import services as votes_service
|
||||
from taiga.users.services import get_user_by_username_or_email
|
||||
from easy_thumbnails.source_generators import pil_image
|
||||
|
||||
from . import models
|
||||
from . import serializers
|
||||
from . import validators
|
||||
from . import permissions
|
||||
from . import filters as user_filters
|
||||
from . import services
|
||||
|
@ -53,6 +52,8 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
permission_classes = (permissions.UserPermission,)
|
||||
admin_serializer_class = serializers.UserAdminSerializer
|
||||
serializer_class = serializers.UserSerializer
|
||||
admin_validator_class = validators.UserAdminValidator
|
||||
validator_class = validators.UserValidator
|
||||
queryset = models.User.objects.all().prefetch_related("memberships")
|
||||
filter_backends = (MembersFilterBackend,)
|
||||
|
||||
|
@ -64,6 +65,14 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
|
||||
return self.serializer_class
|
||||
|
||||
def get_validator_class(self):
|
||||
if self.action in ["partial_update", "update", "retrieve", "by_username"]:
|
||||
user = self.object
|
||||
if self.request.user == user or self.request.user.is_superuser:
|
||||
return self.admin_validator_class
|
||||
|
||||
return self.validator_class
|
||||
|
||||
def create(self, *args, **kwargs):
|
||||
raise exc.NotSupported()
|
||||
|
||||
|
@ -96,8 +105,6 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
user = self.get_object()
|
||||
self.check_permissions(request, "update", user)
|
||||
|
||||
ret = super().partial_update(request, *args, **kwargs)
|
||||
|
||||
new_email = request.DATA.get('email', None)
|
||||
if new_email is not None:
|
||||
valid_new_email = True
|
||||
|
@ -119,10 +126,17 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
request.user.email_token = str(uuid.uuid1())
|
||||
request.user.new_email = new_email
|
||||
request.user.save(update_fields=["email_token", "new_email"])
|
||||
email = mail_builder.change_email(request.user.new_email, {"user": request.user,
|
||||
"lang": request.user.lang})
|
||||
email = mail_builder.change_email(
|
||||
request.user.new_email,
|
||||
{
|
||||
"user": request.user,
|
||||
"lang": request.user.lang
|
||||
}
|
||||
)
|
||||
email.send()
|
||||
|
||||
ret = super().partial_update(request, *args, **kwargs)
|
||||
|
||||
return ret
|
||||
|
||||
def destroy(self, request, pk=None):
|
||||
|
@ -165,16 +179,16 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
|
||||
self.check_permissions(request, "change_password_from_recovery", None)
|
||||
|
||||
serializer = serializers.RecoverySerializer(data=request.DATA, many=False)
|
||||
if not serializer.is_valid():
|
||||
validator = validators.RecoveryValidator(data=request.DATA, many=False)
|
||||
if not validator.is_valid():
|
||||
raise exc.WrongArguments(_("Token is invalid"))
|
||||
|
||||
try:
|
||||
user = models.User.objects.get(token=serializer.data["token"])
|
||||
user = models.User.objects.get(token=validator.data["token"])
|
||||
except models.User.DoesNotExist:
|
||||
raise exc.WrongArguments(_("Token is invalid"))
|
||||
|
||||
user.set_password(serializer.data["password"])
|
||||
user.set_password(validator.data["password"])
|
||||
user.token = None
|
||||
user.save(update_fields=["password", "token"])
|
||||
|
||||
|
@ -247,13 +261,13 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
"""
|
||||
Verify the email change to current logged user.
|
||||
"""
|
||||
serializer = serializers.ChangeEmailSerializer(data=request.DATA, many=False)
|
||||
if not serializer.is_valid():
|
||||
validator = validators.ChangeEmailValidator(data=request.DATA, many=False)
|
||||
if not validator.is_valid():
|
||||
raise exc.WrongArguments(_("Invalid, are you sure the token is correct and you "
|
||||
"didn't use it before?"))
|
||||
|
||||
try:
|
||||
user = models.User.objects.get(email_token=serializer.data["email_token"])
|
||||
user = models.User.objects.get(email_token=validator.data["email_token"])
|
||||
except models.User.DoesNotExist:
|
||||
raise exc.WrongArguments(_("Invalid, are you sure the token is correct and you "
|
||||
"didn't use it before?"))
|
||||
|
@ -280,13 +294,13 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
"""
|
||||
Cancel an account via token
|
||||
"""
|
||||
serializer = serializers.CancelAccountSerializer(data=request.DATA, many=False)
|
||||
if not serializer.is_valid():
|
||||
validator = validators.CancelAccountValidator(data=request.DATA, many=False)
|
||||
if not validator.is_valid():
|
||||
raise exc.WrongArguments(_("Invalid, are you sure the token is correct?"))
|
||||
|
||||
try:
|
||||
max_age_cancel_account = getattr(settings, "MAX_AGE_CANCEL_ACCOUNT", None)
|
||||
user = get_user_for_token(serializer.data["cancel_token"], "cancel_account",
|
||||
user = get_user_for_token(validator.data["cancel_token"], "cancel_account",
|
||||
max_age=max_age_cancel_account)
|
||||
|
||||
except exc.NotAuthenticated:
|
||||
|
@ -349,10 +363,10 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
for elem in elements:
|
||||
if elem["type"] == "project":
|
||||
# projects are liked objects
|
||||
response_data.append(serializers.LikedObjectSerializer(elem, **extra_args_liked).data )
|
||||
response_data.append(serializers.LikedObjectSerializer(into_namedtuple(elem), **extra_args_liked).data)
|
||||
else:
|
||||
# stories, tasks and issues are voted objects
|
||||
response_data.append(serializers.VotedObjectSerializer(elem, **extra_args_voted).data )
|
||||
response_data.append(serializers.VotedObjectSerializer(into_namedtuple(elem), **extra_args_voted).data)
|
||||
|
||||
return response.Ok(response_data)
|
||||
|
||||
|
@ -374,7 +388,7 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
"user_likes": services.get_liked_content_for_user(request.user),
|
||||
}
|
||||
|
||||
response_data = [serializers.LikedObjectSerializer(elem, **extra_args).data for elem in elements]
|
||||
response_data = [serializers.LikedObjectSerializer(into_namedtuple(elem), **extra_args).data for elem in elements]
|
||||
|
||||
return response.Ok(response_data)
|
||||
|
||||
|
@ -397,17 +411,18 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
"user_votes": services.get_voted_content_for_user(request.user),
|
||||
}
|
||||
|
||||
response_data = [serializers.VotedObjectSerializer(elem, **extra_args).data for elem in elements]
|
||||
response_data = [serializers.VotedObjectSerializer(into_namedtuple(elem), **extra_args).data for elem in elements]
|
||||
|
||||
return response.Ok(response_data)
|
||||
|
||||
######################################################
|
||||
## Role
|
||||
######################################################
|
||||
|
||||
######################################################
|
||||
# Role
|
||||
######################################################
|
||||
class RolesViewSet(BlockedByProjectMixin, ModelCrudViewSet):
|
||||
model = models.Role
|
||||
serializer_class = serializers.RoleSerializer
|
||||
validator_class = validators.RoleValidator
|
||||
permission_classes = (permissions.RolesPermission, )
|
||||
filter_backends = (filters.CanViewProjectFilterBackend,)
|
||||
filter_fields = ('project',)
|
||||
|
|
|
@ -22,7 +22,7 @@ from django.core.exceptions import ValidationError
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.base.api import serializers
|
||||
from taiga.base.fields import PgArrayField, Field, MethodField
|
||||
from taiga.base.fields import PgArrayField, Field, MethodField, I18NField
|
||||
|
||||
from taiga.base.utils.thumbnails import get_thumbnail_url
|
||||
|
||||
|
@ -40,47 +40,28 @@ import re
|
|||
# User
|
||||
######################################################
|
||||
|
||||
class ContactProjectDetailSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Project
|
||||
fields = ("id", "slug", "name")
|
||||
class ContactProjectDetailSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
slug = Field()
|
||||
name = Field()
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
full_name_display = serializers.SerializerMethodField("get_full_name_display")
|
||||
photo = serializers.SerializerMethodField("get_photo")
|
||||
big_photo = serializers.SerializerMethodField("get_big_photo")
|
||||
gravatar_url = serializers.SerializerMethodField("get_gravatar_url")
|
||||
roles = serializers.SerializerMethodField("get_roles")
|
||||
projects_with_me = serializers.SerializerMethodField("get_projects_with_me")
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
# IMPORTANT: Maintain the UserAdminSerializer Meta up to date
|
||||
# with this info (including there the email)
|
||||
fields = ("id", "username", "full_name", "full_name_display",
|
||||
"color", "bio", "lang", "theme", "timezone", "is_active",
|
||||
"photo", "big_photo", "roles", "projects_with_me",
|
||||
"gravatar_url")
|
||||
read_only_fields = ("id",)
|
||||
|
||||
def validate_username(self, attrs, source):
|
||||
value = attrs[source]
|
||||
validator = validators.RegexValidator(re.compile('^[\w.-]+$'), _("invalid username"),
|
||||
_("invalid"))
|
||||
|
||||
try:
|
||||
validator(value)
|
||||
except ValidationError:
|
||||
raise serializers.ValidationError(_("Required. 255 characters or fewer. Letters, "
|
||||
"numbers and /./-/_ characters'"))
|
||||
|
||||
if (self.object and
|
||||
self.object.username != value and
|
||||
User.objects.filter(username=value).exists()):
|
||||
raise serializers.ValidationError(_("Invalid username. Try with a different one."))
|
||||
|
||||
return attrs
|
||||
class UserSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
username = Field()
|
||||
full_name = Field()
|
||||
full_name_display = MethodField()
|
||||
color = Field()
|
||||
bio = Field()
|
||||
lang = Field()
|
||||
theme = Field()
|
||||
timezone = Field()
|
||||
is_active = Field()
|
||||
photo = MethodField()
|
||||
big_photo = MethodField()
|
||||
gravatar_url = MethodField()
|
||||
roles = MethodField()
|
||||
projects_with_me = MethodField()
|
||||
|
||||
def get_full_name_display(self, obj):
|
||||
return obj.get_full_name() if obj else ""
|
||||
|
@ -113,24 +94,13 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class UserAdminSerializer(UserSerializer):
|
||||
total_private_projects = serializers.SerializerMethodField("get_total_private_projects")
|
||||
total_public_projects = serializers.SerializerMethodField("get_total_public_projects")
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
# IMPORTANT: Maintain the UserSerializer Meta up to date
|
||||
# with this info (including here the email)
|
||||
fields = ("id", "username", "full_name", "full_name_display", "email",
|
||||
"color", "bio", "lang", "theme", "timezone", "is_active", "photo",
|
||||
"big_photo", "gravatar_url",
|
||||
"max_private_projects", "max_public_projects",
|
||||
"max_memberships_private_projects", "max_memberships_public_projects",
|
||||
"total_private_projects", "total_public_projects")
|
||||
|
||||
read_only_fields = ("id", "email",
|
||||
"max_private_projects", "max_public_projects",
|
||||
"max_memberships_private_projects",
|
||||
"max_memberships_public_projects")
|
||||
total_private_projects = MethodField()
|
||||
total_public_projects = MethodField()
|
||||
email = Field()
|
||||
max_private_projects = Field()
|
||||
max_public_projects = Field()
|
||||
max_memberships_private_projects = Field()
|
||||
max_memberships_public_projects = Field()
|
||||
|
||||
def get_total_private_projects(self, user):
|
||||
return user.owned_projects.filter(is_private=True).count()
|
||||
|
@ -163,75 +133,63 @@ class UserBasicInfoSerializer(serializers.LightSerializer):
|
|||
return super().to_value(instance)
|
||||
|
||||
|
||||
class RecoverySerializer(serializers.Serializer):
|
||||
token = serializers.CharField(max_length=200)
|
||||
password = serializers.CharField(min_length=6)
|
||||
|
||||
|
||||
class ChangeEmailSerializer(serializers.Serializer):
|
||||
email_token = serializers.CharField(max_length=200)
|
||||
|
||||
|
||||
class CancelAccountSerializer(serializers.Serializer):
|
||||
cancel_token = serializers.CharField(max_length=200)
|
||||
|
||||
|
||||
######################################################
|
||||
# Role
|
||||
######################################################
|
||||
|
||||
class RoleSerializer(serializers.ModelSerializer):
|
||||
members_count = serializers.SerializerMethodField("get_members_count")
|
||||
class RoleSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = Field()
|
||||
computable = Field()
|
||||
project = Field(attr="project_id")
|
||||
order = Field()
|
||||
members_count = MethodField()
|
||||
permissions = PgArrayField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
fields = ('id', 'name', 'permissions', 'computable', 'project', 'order', 'members_count')
|
||||
i18n_fields = ("name",)
|
||||
|
||||
def get_members_count(self, obj):
|
||||
return obj.memberships.count()
|
||||
|
||||
|
||||
class ProjectRoleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Role
|
||||
fields = ('id', 'name', 'slug', 'order', 'computable')
|
||||
i18n_fields = ("name",)
|
||||
class ProjectRoleSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = I18NField()
|
||||
slug = Field()
|
||||
order = Field()
|
||||
computable = Field()
|
||||
|
||||
|
||||
######################################################
|
||||
# Like
|
||||
######################################################
|
||||
|
||||
class HighLightedContentSerializer(serializers.Serializer):
|
||||
type = serializers.CharField()
|
||||
id = serializers.IntegerField()
|
||||
ref = serializers.IntegerField()
|
||||
slug = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
subject = serializers.CharField()
|
||||
description = serializers.SerializerMethodField("get_description")
|
||||
assigned_to = serializers.IntegerField()
|
||||
status = serializers.CharField()
|
||||
status_color = serializers.CharField()
|
||||
tags_colors = serializers.SerializerMethodField("get_tags_color")
|
||||
created_date = serializers.DateTimeField()
|
||||
is_private = serializers.SerializerMethodField("get_is_private")
|
||||
logo_small_url = serializers.SerializerMethodField("get_logo_small_url")
|
||||
class HighLightedContentSerializer(serializers.LightSerializer):
|
||||
type = Field()
|
||||
id = Field()
|
||||
ref = Field()
|
||||
slug = Field()
|
||||
name = Field()
|
||||
subject = Field()
|
||||
description = MethodField()
|
||||
assigned_to = Field()
|
||||
status = Field()
|
||||
status_color = Field()
|
||||
tags_colors = MethodField()
|
||||
created_date = Field()
|
||||
is_private = MethodField()
|
||||
logo_small_url = MethodField()
|
||||
|
||||
project = serializers.SerializerMethodField("get_project")
|
||||
project_name = serializers.SerializerMethodField("get_project_name")
|
||||
project_slug = serializers.SerializerMethodField("get_project_slug")
|
||||
project_is_private = serializers.SerializerMethodField("get_project_is_private")
|
||||
project_blocked_code = serializers.CharField()
|
||||
project = MethodField()
|
||||
project_name = MethodField()
|
||||
project_slug = MethodField()
|
||||
project_is_private = MethodField()
|
||||
project_blocked_code = Field()
|
||||
|
||||
assigned_to_username = serializers.CharField()
|
||||
assigned_to_full_name = serializers.CharField()
|
||||
assigned_to_photo = serializers.SerializerMethodField("get_photo")
|
||||
assigned_to_username = Field()
|
||||
assigned_to_full_name = Field()
|
||||
assigned_to_photo = MethodField()
|
||||
|
||||
is_watcher = serializers.SerializerMethodField("get_is_watcher")
|
||||
total_watchers = serializers.IntegerField()
|
||||
is_watcher = MethodField()
|
||||
total_watchers = Field()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Don't pass the extra ids args up to the superclass
|
||||
|
@ -241,18 +199,18 @@ class HighLightedContentSerializer(serializers.Serializer):
|
|||
super().__init__(*args, **kwargs)
|
||||
|
||||
def _none_if_project(self, obj, property):
|
||||
type = obj.get("type", "")
|
||||
type = getattr(obj, "type", "")
|
||||
if type == "project":
|
||||
return None
|
||||
|
||||
return obj.get(property)
|
||||
return getattr(obj, property)
|
||||
|
||||
def _none_if_not_project(self, obj, property):
|
||||
type = obj.get("type", "")
|
||||
type = getattr(obj, "type", "")
|
||||
if type != "project":
|
||||
return None
|
||||
|
||||
return obj.get(property)
|
||||
return getattr(obj, property)
|
||||
|
||||
def get_project(self, obj):
|
||||
return self._none_if_project(obj, "project")
|
||||
|
@ -278,29 +236,29 @@ class HighLightedContentSerializer(serializers.Serializer):
|
|||
return get_thumbnail_url(logo, settings.THN_LOGO_SMALL)
|
||||
return None
|
||||
|
||||
def get_photo(self, obj):
|
||||
type = obj.get("type", "")
|
||||
def get_assigned_to_photo(self, obj):
|
||||
type = getattr(obj, "type", "")
|
||||
if type == "project":
|
||||
return None
|
||||
|
||||
UserData = namedtuple("UserData", ["photo", "email"])
|
||||
user_data = UserData(photo=obj["assigned_to_photo"], email=obj.get("assigned_to_email") or "")
|
||||
user_data = UserData(photo=obj.assigned_to_photo, email=obj.assigned_to_email or "")
|
||||
return get_photo_or_gravatar_url(user_data)
|
||||
|
||||
def get_tags_color(self, obj):
|
||||
tags = obj.get("tags", [])
|
||||
def get_tags_colors(self, obj):
|
||||
tags = getattr(obj, "tags", [])
|
||||
tags = tags if tags is not None else []
|
||||
tags_colors = obj.get("tags_colors", [])
|
||||
tags_colors = getattr(obj, "tags_colors", [])
|
||||
tags_colors = tags_colors if tags_colors is not None else []
|
||||
return [{"name": tc[0], "color": tc[1]} for tc in tags_colors if tc[0] in tags]
|
||||
|
||||
def get_is_watcher(self, obj):
|
||||
return obj["id"] in self.user_watching.get(obj["type"], [])
|
||||
return obj.id in self.user_watching.get(obj.type, [])
|
||||
|
||||
|
||||
class LikedObjectSerializer(HighLightedContentSerializer):
|
||||
is_fan = serializers.SerializerMethodField("get_is_fan")
|
||||
total_fans = serializers.IntegerField()
|
||||
is_fan = MethodField()
|
||||
total_fans = Field()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Don't pass the extra ids args up to the superclass
|
||||
|
@ -310,12 +268,12 @@ class LikedObjectSerializer(HighLightedContentSerializer):
|
|||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_is_fan(self, obj):
|
||||
return obj["id"] in self.user_likes.get(obj["type"], [])
|
||||
return obj.id in self.user_likes.get(obj.type, [])
|
||||
|
||||
|
||||
class VotedObjectSerializer(HighLightedContentSerializer):
|
||||
is_voter = serializers.SerializerMethodField("get_is_voter")
|
||||
total_voters = serializers.IntegerField()
|
||||
is_voter = MethodField()
|
||||
total_voters = Field()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Don't pass the extra ids args up to the superclass
|
||||
|
@ -325,4 +283,4 @@ class VotedObjectSerializer(HighLightedContentSerializer):
|
|||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_is_voter(self, obj):
|
||||
return obj["id"] in self.user_votes.get(obj["type"], [])
|
||||
return obj.id in self.user_votes.get(obj.type, [])
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
||||
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
|
@ -17,17 +16,92 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core import validators as core_validators
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.base.api import serializers
|
||||
from taiga.base.api import validators
|
||||
from taiga.base.fields import PgArrayField, Field
|
||||
|
||||
from . import models
|
||||
from .models import User, Role
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class RoleExistsValidator:
|
||||
def validate_role_id(self, attrs, source):
|
||||
value = attrs[source]
|
||||
if not models.Role.objects.filter(pk=value).exists():
|
||||
if not Role.objects.filter(pk=value).exists():
|
||||
msg = _("There's no role with that id")
|
||||
raise serializers.ValidationError(msg)
|
||||
return attrs
|
||||
|
||||
|
||||
######################################################
|
||||
# User
|
||||
######################################################
|
||||
class UserValidator(validators.ModelValidator):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ("username", "full_name", "color", "bio", "lang",
|
||||
"theme", "timezone", "is_active")
|
||||
|
||||
def validate_username(self, attrs, source):
|
||||
value = attrs[source]
|
||||
validator = core_validators.RegexValidator(re.compile('^[\w.-]+$'), _("invalid username"),
|
||||
_("invalid"))
|
||||
|
||||
try:
|
||||
validator(value)
|
||||
except ValidationError:
|
||||
raise validators.ValidationError(_("Required. 255 characters or fewer. Letters, "
|
||||
"numbers and /./-/_ characters'"))
|
||||
|
||||
if (self.object and
|
||||
self.object.username != value and
|
||||
User.objects.filter(username=value).exists()):
|
||||
raise validators.ValidationError(_("Invalid username. Try with a different one."))
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class UserAdminValidator(UserValidator):
|
||||
class Meta:
|
||||
model = User
|
||||
# IMPORTANT: Maintain the UserSerializer Meta up to date
|
||||
# with this info (including here the email)
|
||||
fields = ("username", "full_name", "color", "bio", "lang",
|
||||
"theme", "timezone", "is_active", "email")
|
||||
|
||||
|
||||
class RecoveryValidator(validators.Validator):
|
||||
token = serializers.CharField(max_length=200)
|
||||
password = serializers.CharField(min_length=6)
|
||||
|
||||
|
||||
class ChangeEmailValidator(validators.Validator):
|
||||
email_token = serializers.CharField(max_length=200)
|
||||
|
||||
|
||||
class CancelAccountValidator(validators.Validator):
|
||||
cancel_token = serializers.CharField(max_length=200)
|
||||
|
||||
|
||||
######################################################
|
||||
# Role
|
||||
######################################################
|
||||
|
||||
class RoleValidator(validators.ModelValidator):
|
||||
permissions = PgArrayField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
fields = ('id', 'name', 'permissions', 'computable', 'project', 'order')
|
||||
i18n_fields = ("name",)
|
||||
|
||||
|
||||
class ProjectRoleValidator(validators.ModelValidator):
|
||||
class Meta:
|
||||
model = Role
|
||||
fields = ('id', 'name', 'slug', 'order', 'computable')
|
||||
|
|
|
@ -30,6 +30,7 @@ from ..utils import DUMMY_BMP_DATA
|
|||
|
||||
from taiga.base.utils import json
|
||||
from taiga.base.utils.thumbnails import get_thumbnail_url
|
||||
from taiga.base.utils.dicts import into_namedtuple
|
||||
from taiga.users import models
|
||||
from taiga.users.serializers import LikedObjectSerializer, VotedObjectSerializer
|
||||
from taiga.auth.tokens import get_token_for_user
|
||||
|
@ -505,7 +506,7 @@ def test_get_watched_list_valid_info_for_project():
|
|||
|
||||
raw_project_watch_info = get_watched_list(fav_user, viewer_user)[0]
|
||||
|
||||
project_watch_info = LikedObjectSerializer(raw_project_watch_info).data
|
||||
project_watch_info = LikedObjectSerializer(into_namedtuple(raw_project_watch_info)).data
|
||||
|
||||
assert project_watch_info["type"] == "project"
|
||||
assert project_watch_info["id"] == project.id
|
||||
|
@ -559,7 +560,7 @@ def test_get_liked_list_valid_info():
|
|||
project.refresh_totals()
|
||||
|
||||
raw_project_like_info = get_liked_list(fan_user, viewer_user)[0]
|
||||
project_like_info = LikedObjectSerializer(raw_project_like_info).data
|
||||
project_like_info = LikedObjectSerializer(into_namedtuple(raw_project_like_info)).data
|
||||
|
||||
assert project_like_info["type"] == "project"
|
||||
assert project_like_info["id"] == project.id
|
||||
|
@ -609,7 +610,7 @@ def test_get_watched_list_valid_info_for_not_project_types():
|
|||
|
||||
instance.add_watcher(fav_user)
|
||||
raw_instance_watch_info = get_watched_list(fav_user, viewer_user, type=object_type)[0]
|
||||
instance_watch_info = VotedObjectSerializer(raw_instance_watch_info).data
|
||||
instance_watch_info = VotedObjectSerializer(into_namedtuple(raw_instance_watch_info)).data
|
||||
|
||||
assert instance_watch_info["type"] == object_type
|
||||
assert instance_watch_info["id"] == instance.id
|
||||
|
@ -666,7 +667,7 @@ def test_get_voted_list_valid_info():
|
|||
f.VotesFactory(content_type=content_type, object_id=instance.id, count=3)
|
||||
|
||||
raw_instance_vote_info = get_voted_list(fav_user, viewer_user, type=object_type)[0]
|
||||
instance_vote_info = VotedObjectSerializer(raw_instance_vote_info).data
|
||||
instance_vote_info = VotedObjectSerializer(into_namedtuple(raw_instance_vote_info)).data
|
||||
|
||||
assert instance_vote_info["type"] == object_type
|
||||
assert instance_vote_info["id"] == instance.id
|
||||
|
|
Loading…
Reference in New Issue