diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 62fed60e3..edd9b396b 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -22,7 +22,7 @@ from ..serializers import UserSerializer, UserRetrieveSerializer, MiniUserSerial from .mixins import UserQuerysetMixin from ..models import User from ..signals import post_user_create -from ..filters import OrgRoleUserFilterBackend +from ..filters import OrgRoleUserFilterBackend, UserFilter logger = get_logger(__name__) __all__ = [ @@ -32,8 +32,8 @@ __all__ = [ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): - filterset_fields = ('username', 'email', 'name', 'id', 'source', 'role') - search_fields = filterset_fields + filterset_class = UserFilter + search_fields = ('username', 'email', 'name', 'id', 'source', 'role') permission_classes = (IsOrgAdmin, CanUpdateDeleteUser) serializer_classes = { 'default': UserSerializer, diff --git a/apps/users/const.py b/apps/users/const.py new file mode 100644 index 000000000..41f350a28 --- /dev/null +++ b/apps/users/const.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# +from django.db.models import TextChoices +from django.utils.translation import ugettext_lazy as _ + +TICKET_DETAIL_URL = '/ui/#/tickets/tickets/{id}' + + +class SystemOrOrgRole(TextChoices): + SYSTEM_ADMIN = 'system_admin', _('System administrator') + SYSTEM_AUDITOR = 'system_auditor', _('System auditor') + ORG_ADMIN = 'org_admin', _('Organization administrator') + ORG_AUDITOR = 'org_auditor', _("Organization auditor") + USER = 'user', _('User') + + +class PasswordStrategy(TextChoices): + email = 'email', _('Reset link will be generated and sent to the user') + custom = 'custom', _('Set password') diff --git a/apps/users/filters.py b/apps/users/filters.py index faf5959c8..5b3d86759 100644 --- a/apps/users/filters.py +++ b/apps/users/filters.py @@ -1,11 +1,15 @@ +from django_filters import rest_framework as filters +from django.db.models import Q from rest_framework.compat import coreapi, coreschema -from rest_framework import filters +from rest_framework.filters import BaseFilterBackend +from common.drf.filters import BaseFilterSet from users.models.user import User +from users.const import SystemOrOrgRole from orgs.utils import current_org -class OrgRoleUserFilterBackend(filters.BaseFilterBackend): +class OrgRoleUserFilterBackend(BaseFilterBackend): def filter_queryset(self, request, queryset, view): org_role = request.query_params.get('org_role') if not org_role: @@ -30,3 +34,30 @@ class OrgRoleUserFilterBackend(filters.BaseFilterBackend): ) ) ] + + +class UserFilter(BaseFilterSet): + system_or_org_role = filters.ChoiceFilter(choices=SystemOrOrgRole.choices, method='filter_system_or_org_role') + + class Meta: + model = User + fields = ( + 'id', 'username', 'email', 'name', 'source', 'system_or_org_role' + ) + + def filter_system_or_org_role(self, queryset, name, value): + value = value.split('_') + if len(value) == 1: + role_type, value = None, value[0] + else: + role_type, value = value + value = value.title() + system_queries = Q(role=value) + org_queries = Q(m2m_org_members__role=value, m2m_org_members__org_id=current_org.id) + if not role_type: + queries = system_queries | org_queries + elif role_type == 'system': + queries = system_queries + elif role_type == 'org': + queries = org_queries + return queryset.filter(queries) diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index e9010e1af..4323dc658 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -2,14 +2,13 @@ # from django.core.cache import cache from django.utils.translation import ugettext_lazy as _ -from django.db.models import TextChoices from rest_framework import serializers from common.mixins import CommonBulkSerializerMixin from common.permissions import CanUpdateDeleteUser from orgs.models import ROLE as ORG_ROLE from ..models import User - +from ..const import SystemOrOrgRole, PasswordStrategy __all__ = [ 'UserSerializer', 'UserRetrieveSerializer', 'MiniUserSerializer', @@ -18,10 +17,6 @@ __all__ = [ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): - class PasswordStrategy(TextChoices): - email = 'email', _('Reset link will be generated and sent to the user') - custom = 'custom', _('Set password') - password_strategy = serializers.ChoiceField( choices=PasswordStrategy.choices, default=PasswordStrategy.email, required=False, write_only=True, label=_('Password strategy') @@ -38,6 +33,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): label=_('Organization role name'), allow_null=True, required=False, child=serializers.ChoiceField(choices=ORG_ROLE.choices), default=["User"] ) + system_or_org_role = serializers.ChoiceField(read_only=True, choices=SystemOrOrgRole.choices, label=_('Role')) class Meta: model = User @@ -60,7 +56,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): fields_verbose = fields_small + [ 'total_role_display', 'org_role_display', 'mfa_level_display', 'mfa_force_enabled', 'is_first_login', - 'date_password_last_updated', 'avatar_url', + 'date_password_last_updated', 'avatar_url', 'system_or_org_role' ] # 外键的字段 fields_fk = ['role', 'role_display'] @@ -184,7 +180,6 @@ class InviteSerializer(serializers.Serializer): class ServiceAccountSerializer(serializers.ModelSerializer): - class Meta: model = User fields = ['id', 'name', 'access_key']