Refactor day: Move RoleViewSet from taiga.projects to taiga.users

remotes/origin/enhancement/email-actions
David Barragán Merino 2015-02-10 15:24:08 +01:00
parent 589490d7a5
commit 5196f1c25d
10 changed files with 213 additions and 134 deletions

View File

@ -17,15 +17,13 @@ import operator
from functools import reduce
import logging
from django.apps import apps
from django.db.models import Q
from django.db.models.sql.where import ExtraWhere, OR, AND
from rest_framework import filters
from taiga.base import tags
from taiga.base import exceptions as exc
from taiga.projects.models import Membership
logger = logging.getLogger(__name__)
@ -101,7 +99,8 @@ class PermissionBasedFilterBackend(FilterBackend):
try:
project_id = int(request.QUERY_PARAMS["project"])
except:
logger.error("Filtering project diferent value than an integer: {}".format(request.QUERY_PARAMS["project"]))
logger.error("Filtering project diferent value than an integer: {}".format(
request.QUERY_PARAMS["project"]))
raise exc.BadRequest("'project' must be an integer value.")
qs = queryset
@ -109,7 +108,8 @@ class PermissionBasedFilterBackend(FilterBackend):
if request.user.is_authenticated() and request.user.is_superuser:
qs = qs
elif request.user.is_authenticated():
memberships_qs = Membership.objects.filter(user=request.user)
membership_model = apps.get_model('projects', 'Membership')
memberships_qs = membership_model.objects.filter(user=request.user)
if project_id:
memberships_qs = memberships_qs.filter(project_id=project_id)
memberships_qs = memberships_qs.filter(Q(role__permissions__contains=[self.permission]) |
@ -187,7 +187,8 @@ class CanViewProjectObjFilterBackend(FilterBackend):
try:
project_id = int(request.QUERY_PARAMS["project"])
except:
logger.error("Filtering project diferent value than an integer: {}".format(request.QUERY_PARAMS["project"]))
logger.error("Filtering project diferent value than an integer: {}".format(
request.QUERY_PARAMS["project"]))
raise exc.BadRequest("'project' must be an integer value.")
qs = queryset
@ -195,7 +196,8 @@ class CanViewProjectObjFilterBackend(FilterBackend):
if request.user.is_authenticated() and request.user.is_superuser:
qs = qs
elif request.user.is_authenticated():
memberships_qs = Membership.objects.filter(user=request.user)
membership_model = apps.get_model("projects", "Membership")
memberships_qs = membership_model.objects.filter(user=request.user)
if project_id:
memberships_qs = memberships_qs.filter(project_id=project_id)
memberships_qs = memberships_qs.filter(Q(role__permissions__contains=['view_project']) |
@ -203,7 +205,8 @@ class CanViewProjectObjFilterBackend(FilterBackend):
projects_list = [membership.project_id for membership in memberships_qs]
qs = qs.filter(Q(id__in=projects_list) | Q(public_permissions__contains=["view_project"]))
qs = qs.filter((Q(id__in=projects_list) |
Q(public_permissions__contains=["view_project"])))
else:
qs = qs.filter(public_permissions__contains=["view_project"])
@ -221,6 +224,25 @@ class IsProjectMemberFilterBackend(FilterBackend):
return super().filter_queryset(request, queryset.distinct(), view)
class MembersFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
project_id = request.QUERY_PARAMS.get('project', None)
if project_id:
project_model = apps.get_model('projects', 'Project')
project = get_object_or_404(project_model, pk=project_id)
if (request.user.is_authenticated() and
project.memberships.filter(user=request.user).exists()):
return queryset.filter(memberships__project=project).distinct()
else:
raise exc.PermissionDenied(_("You don't have permisions to see this project users."))
if request.user.is_superuser:
return queryset
return []
class BaseIsProjectAdminFilterBackend(object):
def get_project_ids(self, request, view):
project_id = None
@ -233,7 +255,8 @@ class BaseIsProjectAdminFilterBackend(object):
if not request.user.is_authenticated():
return []
memberships_qs = Membership.objects.filter(user=request.user, is_owner=True)
membership_model = apps.get_model('projects', 'Membership')
memberships_qs = membership_model.objects.filter(user=request.user, is_owner=True)
if project_id:
memberships_qs = memberships_qs.filter(project_id=project_id)

View File

@ -20,7 +20,8 @@ from django.db.models import signals
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from taiga.base import filters, response
from taiga.base import filters
from taiga.base import response
from taiga.base import exceptions as exc
from taiga.base.decorators import list_route
from taiga.base.decorators import detail_route
@ -32,7 +33,6 @@ from taiga.base.utils.slug import slugify_uniquely
from taiga.projects.mixins.ordering import BulkUpdateOrderMixin
from taiga.projects.mixins.on_destroy import MoveOnDestroyMixin
from taiga.users.models import Role
from taiga.projects.userstories.models import UserStory
from taiga.projects.tasks.models import Task
from taiga.projects.issues.models import Issue
@ -325,7 +325,7 @@ class ProjectTemplateViewSet(ModelCrudViewSet):
######################################################
## Members Invitations and Roles
## Members & Invitations
######################################################
class MembershipViewSet(ModelCrudViewSet):
@ -403,20 +403,3 @@ class InvitationViewSet(ModelListViewSet):
def list(self, *args, **kwargs):
raise exc.PermissionDenied(_("You don't have permisions to see that."))
class RolesViewSet(ModelCrudViewSet):
model = Role
serializer_class = serializers.RoleSerializer
permission_classes = (permissions.RolesPermission, )
filter_backends = (filters.CanViewProjectFilterBackend,)
filter_fields = ('project',)
def pre_delete(self, obj):
move_to = self.request.QUERY_PARAMS.get('moveTo', None)
if move_to:
role_dest = get_object_or_404(self.model, project=obj.project, id=move_to)
qs = models.Membership.objects.filter(project_id=obj.project.pk, role=obj)
qs.update(role=role_dest)
super().pre_delete(obj)

View File

@ -16,9 +16,13 @@
from django.utils.translation import ugettext_lazy as _
from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm,
IsAuthenticated, IsProjectOwner,
AllowAny, IsSuperUser, PermissionComponent)
from taiga.base.api.permissions import TaigaResourcePermission
from taiga.base.api.permissions import HasProjectPerm
from taiga.base.api.permissions import IsAuthenticated
from taiga.base.api.permissions import IsProjectOwner
from taiga.base.api.permissions import AllowAny
from taiga.base.api.permissions import IsSuperUser
from taiga.base.api.permissions import PermissionComponent
from taiga.base import exceptions as exc
from taiga.projects.models import Membership
@ -32,8 +36,8 @@ class CanLeaveProject(PermissionComponent):
try:
if not services.can_user_leave_project(request.user, obj):
raise exc.PermissionDenied(_("You can't leave the project if there are no more owners"))
raise exc.PermissionDenied(_("You can't leave the project if there are no "
"more owners"))
return True
except Membership.DoesNotExist:
return False
@ -140,14 +144,6 @@ class IssueTypePermission(TaigaResourcePermission):
bulk_update_order_perms = IsProjectOwner()
class RolesPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
create_perms = IsProjectOwner()
update_perms = IsProjectOwner()
destroy_perms = IsProjectOwner()
list_perms = AllowAny()
# Project Templates
class ProjectTemplatePermission(TaigaResourcePermission):

View File

@ -14,27 +14,32 @@
# 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 os import path
from django.utils.translation import ugettext_lazy as _
from django.db.models import Q
from rest_framework import serializers
from taiga.base.serializers import JsonField, PgArrayField, ModelSerializer, TagsColorsField
from taiga.users.models import Role, User
from taiga.base.serializers import JsonField
from taiga.base.serializers import PgArrayField
from taiga.base.serializers import ModelSerializer
from taiga.base.serializers import TagsColorsField
from taiga.users.services import get_photo_or_gravatar_url
from taiga.users.serializers import UserSerializer
from taiga.users.serializers import ProjectRoleSerializer
from taiga.users.validators import RoleExistsValidator
from taiga.permissions.service import get_user_project_permissions, is_project_owner
from taiga.permissions.service import get_user_project_permissions
from taiga.permissions.service import is_project_owner
from . import models
from . import services
from . validators import ProjectExistsValidator
# User Stories common serializers
######################################################
## Custom values for selectors
######################################################
class PointsSerializer(ModelSerializer):
class Meta:
@ -69,10 +74,12 @@ class UserStoryStatusSerializer(ModelSerializer):
qs = None
# If the user story status exists:
if self.object and attrs.get("name", None):
qs = models.UserStoryStatus.objects.filter(project=self.object.project, name=attrs[source])
qs = models.UserStoryStatus.objects.filter(project=self.object.project,
name=attrs[source])
if not self.object and attrs.get("project", None) and attrs.get("name", None):
qs = models.UserStoryStatus.objects.filter(project=attrs["project"], name=attrs[source])
qs = models.UserStoryStatus.objects.filter(project=attrs["project"],
name=attrs[source])
if qs and qs.exists():
raise serializers.ValidationError("Name duplicated for the project")
@ -80,8 +87,6 @@ class UserStoryStatusSerializer(ModelSerializer):
return attrs
# Task common serializers
class TaskStatusSerializer(ModelSerializer):
class Meta:
model = models.TaskStatus
@ -103,7 +108,6 @@ class TaskStatusSerializer(ModelSerializer):
return attrs
# Issues common serializers
class SeveritySerializer(ModelSerializer):
class Meta:
@ -142,13 +146,16 @@ class IssueTypeSerializer(ModelSerializer):
model = models.IssueType
# Projects
######################################################
## Members
######################################################
class MembershipSerializer(ModelSerializer):
role_name = serializers.CharField(source='role.name', required=False, read_only=True)
full_name = serializers.CharField(source='user.get_full_name', required=False, read_only=True)
user_email = serializers.EmailField(source='user.email', required=False, read_only=True)
is_user_active = serializers.BooleanField(source='user.is_active', required=False, read_only=True)
is_user_active = serializers.BooleanField(source='user.is_active', required=False,
read_only=True)
email = serializers.EmailField(required=True)
color = serializers.CharField(source='user.color', required=False, read_only=True)
photo = serializers.SerializerMethodField("get_photo")
@ -210,7 +217,8 @@ class MembershipSerializer(ModelSerializer):
if project is None:
project = self.object.project
if self.object and not services.project_has_valid_owners(project, exclude_user=self.object.user):
if (self.object and
not services.project_has_valid_owners(project, exclude_user=self.object.user)):
raise serializers.ValidationError(_("At least one of the user must be an active admin"))
return attrs
@ -229,6 +237,21 @@ class ProjectMembershipSerializer(ModelSerializer):
return get_photo_or_gravatar_url(project.user)
class MemberBulkSerializer(RoleExistsValidator, serializers.Serializer):
email = serializers.EmailField()
role_id = serializers.IntegerField()
class MembersBulkSerializer(ProjectExistsValidator, serializers.Serializer):
project_id = serializers.IntegerField()
bulk_memberships = MemberBulkSerializer(many=True)
invitation_extra_text = serializers.CharField(required=False, max_length=255)
######################################################
## Projects
######################################################
class ProjectSerializer(ModelSerializer):
tags = PgArrayField(required=False)
anon_permissions = PgArrayField(required=False)
@ -300,23 +323,20 @@ class ProjectDetailSerializer(ProjectSerializer):
return serializer.data
class ProjectRoleSerializer(ModelSerializer):
######################################################
## Starred
######################################################
class StarredSerializer(ModelSerializer):
class Meta:
model = Role
fields = ('id', 'name', 'slug', 'order', 'computable')
model = models.Project
fields = ['id', 'name', 'slug']
class RoleSerializer(ModelSerializer):
members_count = serializers.SerializerMethodField("get_members_count")
permissions = PgArrayField(required=False)
class Meta:
model = Role
fields = ('id', 'name', 'permissions', 'computable', 'project', 'order', 'members_count')
def get_members_count(self, obj):
return obj.memberships.count()
######################################################
## Project Templates
######################################################
class ProjectTemplateSerializer(ModelSerializer):
default_options = JsonField(required=False, label=_("Default options"))
@ -332,20 +352,3 @@ class ProjectTemplateSerializer(ModelSerializer):
class Meta:
model = models.ProjectTemplate
read_only_fields = ("created_date", "modified_date")
class StarredSerializer(ModelSerializer):
class Meta:
model = models.Project
fields = ['id', 'name', 'slug']
class MemberBulkSerializer(RoleExistsValidator, serializers.Serializer):
email = serializers.EmailField()
role_id = serializers.IntegerField()
class MembersBulkSerializer(ProjectExistsValidator, serializers.Serializer):
project_id = serializers.IntegerField()
bulk_memberships = MemberBulkSerializer(many=True)
invitation_extra_text = serializers.CharField(required=False, max_length=255)

View File

@ -18,15 +18,18 @@ from taiga.base import routers
router = routers.DefaultRouter(trailing_slash=False)
# taiga.users
from taiga.users.api import UsersViewSet
# Users & Roles
from taiga.auth.api import AuthViewSet
from taiga.users.api import UsersViewSet
from taiga.users.api import RolesViewSet
router.register(r"users", UsersViewSet, base_name="users")
router.register(r"auth", AuthViewSet, base_name="auth")
router.register(r"users", UsersViewSet, base_name="users")
router.register(r"roles", RolesViewSet, base_name="roles")
#taiga.userstorage
# User Storage
from taiga.userstorage.api import StorageEntriesViewSet
router.register(r"user-storage", StorageEntriesViewSet, base_name="user-storage")
@ -51,8 +54,7 @@ router.register(r"importer", ProjectImporterViewSet, base_name="importer")
router.register(r"exporter", ProjectExporterViewSet, base_name="exporter")
# Projects & Types
from taiga.projects.api import RolesViewSet
# Projects & Selectors
from taiga.projects.api import ProjectViewSet
from taiga.projects.api import MembershipViewSet
from taiga.projects.api import InvitationViewSet
@ -65,8 +67,6 @@ from taiga.projects.api import PriorityViewSet
from taiga.projects.api import SeverityViewSet
from taiga.projects.api import ProjectTemplateViewSet
router.register(r"roles", RolesViewSet, base_name="roles")
router.register(r"projects", ProjectViewSet, base_name="projects")
router.register(r"project-templates", ProjectTemplateViewSet, base_name="project-templates")
router.register(r"memberships", MembershipViewSet, base_name="memberships")
@ -79,22 +79,27 @@ router.register(r"issue-types", IssueTypeViewSet, base_name="issue-types")
router.register(r"priorities", PriorityViewSet, base_name="priorities")
router.register(r"severities",SeverityViewSet , base_name="severities")
# Attachments
from taiga.projects.attachments.api import UserStoryAttachmentViewSet
from taiga.projects.attachments.api import IssueAttachmentViewSet
from taiga.projects.attachments.api import TaskAttachmentViewSet
from taiga.projects.attachments.api import WikiAttachmentViewSet
router.register(r"userstories/attachments", UserStoryAttachmentViewSet, base_name="userstory-attachments")
router.register(r"userstories/attachments", UserStoryAttachmentViewSet,
base_name="userstory-attachments")
router.register(r"tasks/attachments", TaskAttachmentViewSet, base_name="task-attachments")
router.register(r"issues/attachments", IssueAttachmentViewSet, base_name="issue-attachments")
router.register(r"wiki/attachments", WikiAttachmentViewSet, base_name="wiki-attachments")
# Webhooks
from taiga.webhooks.api import WebhookViewSet, WebhookLogViewSet
router.register(r"webhooks", WebhookViewSet, base_name="webhooks")
router.register(r"webhooklogs", WebhookLogViewSet, base_name="webhooklogs")
# History & Components
from taiga.projects.history.api import UserStoryHistory
from taiga.projects.history.api import TaskHistory
@ -131,22 +136,30 @@ router.register(r"issues/(?P<issue_id>\d+)/voters", VotersViewSet, base_name="is
router.register(r"wiki", WikiViewSet, base_name="wiki")
router.register(r"wiki-links", WikiLinkViewSet, base_name="wiki-links")
# Notify policies
from taiga.projects.notifications.api import NotifyPolicyViewSet
router.register(r"notify-policies", NotifyPolicyViewSet, base_name="notifications")
# GitHub webhooks
from taiga.hooks.github.api import GitHubViewSet
router.register(r"github-hook", GitHubViewSet, base_name="github-hook")
# Gitlab webhooks
from taiga.hooks.gitlab.api import GitLabViewSet
router.register(r"gitlab-hook", GitLabViewSet, base_name="gitlab-hook")
# Bitbucket webhooks
from taiga.hooks.bitbucket.api import BitBucketViewSet
router.register(r"bitbucket-hook", BitBucketViewSet, base_name="bitbucket-hook")
# feedback
# - see taiga.feedback.routers and taiga.feedback.apps

View File

@ -26,20 +26,21 @@ from django.conf import settings
from easy_thumbnails.source_generators import pil_image
from rest_framework.response import Response
from rest_framework.filters import BaseFilterBackend
from rest_framework import status
from djmail.template_mail import MagicMailBuilder, InlineCSSTemplateMail
from djmail.template_mail import MagicMailBuilder
from djmail.template_mail import InlineCSSTemplateMail
from taiga.auth.tokens import get_user_for_token
from taiga.base.decorators import list_route, detail_route
from taiga.base.decorators import list_route
from taiga.base.decorators import detail_route
from taiga.base import exceptions as exc
from taiga.base import filters
from taiga.base.api import ModelCrudViewSet
from taiga.base.api.utils import get_object_or_404
from taiga.base.utils.slug import slugify_uniquely
from taiga.base.filters import MembersFilterBackend
from taiga.projects.votes import services as votes_service
from taiga.projects.serializers import StarredSerializer
from taiga.permissions.service import is_project_owner
from . import models
from . import serializers
@ -47,22 +48,9 @@ from . import permissions
from .signals import user_cancel_account as user_cancel_account_signal
class MembersFilterBackend(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
project_id = request.QUERY_PARAMS.get('project', None)
if project_id:
Project = apps.get_model('projects', 'Project')
project = get_object_or_404(Project, pk=project_id)
if request.user.is_authenticated() and project.memberships.filter(user=request.user).exists():
return queryset.filter(memberships__project=project).distinct()
else:
raise exc.PermissionDenied(_("You don't have permisions to see this project users."))
if request.user.is_superuser:
return queryset
return []
######################################################
## User
######################################################
class UsersViewSet(ModelCrudViewSet):
permission_classes = (permissions.UserPermission,)
@ -73,7 +61,9 @@ class UsersViewSet(ModelCrudViewSet):
raise exc.NotSupported()
def list(self, request, *args, **kwargs):
self.object_list = MembersFilterBackend().filter_queryset(request, self.get_queryset(), self)
self.object_list = MembersFilterBackend().filter_queryset(request,
self.get_queryset(),
self)
page = self.paginate_queryset(self.object_list)
if page is not None:
@ -249,12 +239,14 @@ class UsersViewSet(ModelCrudViewSet):
"""
serializer = serializers.ChangeEmailSerializer(data=request.DATA, many=False)
if not serializer.is_valid():
raise exc.WrongArguments(_("Invalid, are you sure the token is correct and you didn't use it before?"))
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"])
except models.User.DoesNotExist:
raise exc.WrongArguments(_("Invalid, are you sure the token is correct and you didn't use it before?"))
raise exc.WrongArguments(_("Invalid, are you sure the token is correct and you "
"didn't use it before?"))
self.check_permissions(request, "change_email", user)
user.email = user.new_email
@ -304,3 +296,25 @@ class UsersViewSet(ModelCrudViewSet):
user_cancel_account_signal.send(sender=user.__class__, user=user, request_data=request_data)
user.cancel()
return Response(status=status.HTTP_204_NO_CONTENT)
######################################################
## Role
######################################################
class RolesViewSet(ModelCrudViewSet):
model = models.Role
serializer_class = serializers.RoleSerializer
permission_classes = (permissions.RolesPermission, )
filter_backends = (filters.CanViewProjectFilterBackend,)
filter_fields = ('project',)
def pre_delete(self, obj):
move_to = self.request.QUERY_PARAMS.get('moveTo', None)
if move_to:
membership_model = apps.get_model("projects", "Membership")
role_dest = get_object_or_404(self.model, project=obj.project, id=move_to)
qs = membership_model.objects.filter(project_id=obj.project.pk, role=obj)
qs.update(role=role_dest)
super().pre_delete(obj)

View File

@ -174,6 +174,7 @@ class User(AbstractBaseUser, PermissionsMixin):
self.save()
self.auth_data.all().delete()
class Role(models.Model):
name = models.CharField(max_length=200, null=False, blank=False,
verbose_name=_("name"))

View File

@ -14,9 +14,13 @@
# 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 taiga.base.api.permissions import (TaigaResourcePermission, IsSuperUser,
AllowAny, PermissionComponent,
IsAuthenticated)
from taiga.base.api.permissions import TaigaResourcePermission
from taiga.base.api.permissions import IsSuperUser
from taiga.base.api.permissions import AllowAny
from taiga.base.api.permissions import IsAuthenticated
from taiga.base.api.permissions import HasProjectPerm
from taiga.base.api.permissions import IsProjectOwner
from taiga.base.api.permissions import PermissionComponent
class IsTheSameUser(PermissionComponent):
@ -39,3 +43,11 @@ class UserPermission(TaigaResourcePermission):
remove_avatar_perms = IsAuthenticated()
starred_perms = AllowAny()
change_email_perms = IsTheSameUser()
class RolesPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
create_perms = IsProjectOwner()
update_perms = IsProjectOwner()
destroy_perms = IsProjectOwner()
list_perms = AllowAny()

View File

@ -16,16 +16,24 @@
from django.core import validators
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from taiga.base.serializers import Serializer
from taiga.base.serializers import ModelSerializer
from taiga.base.serializers import PgArrayField
from .models import User
from .models import User, Role
from .services import get_photo_or_gravatar_url, get_big_photo_or_gravatar_url
import re
class UserSerializer(serializers.ModelSerializer):
######################################################
## User
######################################################
class UserSerializer(ModelSerializer):
full_name_display = serializers.SerializerMethodField("get_full_name_display")
photo = serializers.SerializerMethodField("get_photo")
big_photo = serializers.SerializerMethodField("get_big_photo")
@ -39,16 +47,19 @@ class UserSerializer(serializers.ModelSerializer):
def validate_username(self, attrs, source):
value = attrs[source]
validator = validators.RegexValidator(re.compile('^[\w.-]+$'), "invalid username", "invalid")
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'")
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.")
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
@ -62,14 +73,36 @@ class UserSerializer(serializers.ModelSerializer):
return get_big_photo_or_gravatar_url(user)
class RecoverySerializer(serializers.Serializer):
class RecoverySerializer(Serializer):
token = serializers.CharField(max_length=200)
password = serializers.CharField(min_length=6)
class ChangeEmailSerializer(serializers.Serializer):
class ChangeEmailSerializer(Serializer):
email_token = serializers.CharField(max_length=200)
class CancelAccountSerializer(serializers.Serializer):
class CancelAccountSerializer(Serializer):
cancel_token = serializers.CharField(max_length=200)
######################################################
## Role
######################################################
class RoleSerializer(ModelSerializer):
members_count = serializers.SerializerMethodField("get_members_count")
permissions = PgArrayField(required=False)
class Meta:
model = Role
fields = ('id', 'name', 'permissions', 'computable', 'project', 'order', 'members_count')
def get_members_count(self, obj):
return obj.memberships.count()
class ProjectRoleSerializer(ModelSerializer):
class Meta:
model = Role
fields = ('id', 'name', 'slug', 'order', 'computable')

View File

@ -2,6 +2,7 @@ from django.core.urlresolvers import reverse
from taiga.base.utils import json
from taiga.projects import serializers
from taiga.users.serializers import RoleSerializer
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
from tests import factories as f
@ -140,19 +141,19 @@ def test_roles_update(client, data):
data.project_owner
]
role_data = serializers.RoleSerializer(data.public_project.roles.all()[0]).data
role_data = RoleSerializer(data.public_project.roles.all()[0]).data
role_data["name"] = "test"
role_data = json.dumps(role_data)
results = helper_test_http_method(client, 'put', public_url, role_data, users)
assert results == [401, 403, 403, 403, 200]
role_data = serializers.RoleSerializer(data.private_project1.roles.all()[0]).data
role_data = RoleSerializer(data.private_project1.roles.all()[0]).data
role_data["name"] = "test"
role_data = json.dumps(role_data)
results = helper_test_http_method(client, 'put', private1_url, role_data, users)
assert results == [401, 403, 403, 403, 200]
role_data = serializers.RoleSerializer(data.private_project2.roles.all()[0]).data
role_data = RoleSerializer(data.private_project2.roles.all()[0]).data
role_data["name"] = "test"
role_data = json.dumps(role_data)
results = helper_test_http_method(client, 'put', private2_url, role_data, users)