Beispiel #1
0
class OverrideDingAPIView(generics.RetrieveUpdateAPIView):
    '''
    回写覆盖钉钉数据
    '''

    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_account_sync'))
    ]
Beispiel #2
0
class LogListAPIView(generics.ListAPIView):
    '''
    get log list [GET]
    '''

    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_log_read'))
    ]

    serializer_class = LogLiteSerializer
    pagination_class = DefaultListPaginator

    def get_queryset(self):
        '''
        filter queryset
        '''
        kwargs = {}

        subject = self.request.query_params.get('subject', '')
        if subject:
            kwargs['subject__in'] = subject.split('|')

        summary = self.request.query_params.get('summary', '')
        if summary:
            kwargs['summary__icontains'] = summary

        days = self.request.query_params.get('days', None)
        if days is not None:
            if not days.isdigit():
                raise ValidationError(
                    {'days': ['this field must be interger']})
            days = int(days)

            now = timezone.now()
            if days == 0:
                local_now = timezone.localtime(now)
                kwargs['created__gte'] = local_now.replace(hour=0,
                                                           minute=0,
                                                           second=0,
                                                           microsecond=0)
            else:
                kwargs['created__gte'] = now - datetime.timedelta(days=days)

        queryset = Log.objects.filter(**kwargs)

        user = self.request.query_params.get('user', '')
        if user:
            queryset = queryset.filter(
                Q(user__username__icontains=user)
                | Q(user__name__icontains=user))

        return queryset.order_by('-created')
Beispiel #3
0
class ImportDingAPIView(generics.RetrieveUpdateAPIView):
    '''
    拉取钉钉数据
    '''
    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_account_sync'))
    ]

    serializer_class = UserListSerializer

    def get(self, request, *args, **kwargs):
        task = import_ding.delay()
        return Response({'task_id': task.task_id, 'task_msg': 'import ding'})
Beispiel #4
0
class StorageConfigAPIView(generics.RetrieveUpdateAPIView):
    '''
    文件存储方式
    '''
    serializer_class = StorageConfigSerializer
    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_config_write'))
    ]

    def get_object(self):
        """
        get storage site
        """
        site = Site.objects.get_current()
        return site
Beispiel #5
0
class ContactsConfigAPIView(generics.RetrieveUpdateAPIView):
    '''
    通讯录配置
    '''
    serializer_class = ContactsConfigSerializer
    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_config_write'))
    ]

    def get_object(self):
        """
        get contacts config
        """
        contactsconfig = ContactsConfig.valid_objects.first()
        return contactsconfig
Beispiel #6
0
class OverrideDingAPIView(generics.RetrieveUpdateAPIView):
    '''
    回写覆盖钉钉数据
    '''

    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_account_sync'))
    ]

    serializer_class = UserListSerializer

    def get(self, request, *args, **kwargs):
        ding_config = DingConfig.get_current()
        ding_config.sync_state = 'push'
        ding_config.save()

        task = override_ding.delay()
        return Response({'task_id': task.task_id, 'task_msg': 'override ding'})
Beispiel #7
0
class ConfigAPIView(generics.RetrieveUpdateAPIView):
    """
    基本配置 [GET], [PATCH]
    管理员可见
    """

    serializer_class = ConfigSerializer

    permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_config_write'))
    ]

    def get_object(self):
        """
        get current site
        """
        site = Site.objects.get_current()
        site.refresh_from_db()
        return site

    def perform_update(self, serializer):
        super().perform_update(serializer)  # pylint: disable=no-member
        LOG_CLI().update_config()
Beispiel #8
0
class UserListCreateAPIView(generics.ListCreateAPIView):
    '''
    用户列表 [GET],[POST]
    '''
    serializer_class = EmployeeSerializer
    pagination_class = DefaultListPaginator

    read_permission_classes = [IsAuthenticated & IsAdminUser]
    write_permission_classes = [IsAuthenticated & (IsAdminUser | CustomPerm('system_user_create'))]

    def get_permissions(self):
        '''
        读写权限
        '''
        if self.request.method in SAFE_METHODS:
            return [perm() for perm in self.read_permission_classes]
        return [perm() for perm in self.write_permission_classes]

    def get_queryset(self):
        '''
        return queryset for list [GET]
        '''
        keyword = self.request.query_params.get('keyword', '')
        if keyword != '':
            queryset = User.valid_objects.filter(Q(username__icontains=keyword)|Q(email__icontains=keyword)|\
                Q(private_email__icontains=keyword)|Q(mobile__icontains=keyword)|Q(name__icontains=keyword)).\
                    exclude(is_boss=True).exclude(username='******').order_by('id')
        else:
            queryset = User.valid_objects.exclude(is_boss=True).exclude(username='******').order_by('id')

        return queryset

    @transaction.atomic()
    def create(self, request, *args, **kwargs):    # pylint: disable=unused-argument
        '''
        create user [POST]
        '''
        data = request.data
        user_info = data.get('user', '')

        group_uids = []
        dept_uids = []

        node_uids = data.get('node_uids', [])
        if node_uids:
            for node_uid in node_uids:
                if node_uid.startswith(Dept.NODE_PREFIX):
                    dept_uids.append(node_uid.replace(Dept.NODE_PREFIX, '', 1))
                elif node_uid.startswith(Group.NODE_PREFIX):
                    group_uids.append(node_uid.replace(
                        Group.NODE_PREFIX,
                        '',
                    ))
        else:
            group_uids = data.get('group_uids', [])
            dept_uids = data.get('dept_uids', [])

        cli = CLI()
        password = user_info.pop('password', None)
        user = cli.create_user(user_info)
        if password:
            cli.set_user_password(user, password)
        user.origin = 1    # 管理员添加
        user.save()

        self.assign_user(user, dept_uids=dept_uids, group_uids=group_uids)

        user_serializer = EmployeeSerializer(user)
        return Response(user_serializer.data,
                        status=status.HTTP_201_CREATED,
                        headers=self.get_success_headers(user_serializer.data))

    @staticmethod
    def assign_user(user, dept_uids, group_uids):
        '''
        - add_user_to_depts
        - add_user_to_groups
        :param User user:
        :param list dept_uids: list of uid
        :param list group_uids: list of uid
        '''
        depts = []
        for dept_uid in dept_uids:
            try:
                dept = Dept.valid_objects.get(uid=dept_uid)
            except ObjectDoesNotExist:
                raise ValidationError({'dept_uids': ['dept:{} does not exist'.format(dept_uid)]})
            depts.append(dept)

        groups = []
        for group_uid in group_uids:
            try:
                group = Group.valid_objects.get(uid=group_uid)
            except ObjectDoesNotExist:
                raise ValidationError({'group_uids': ['group:{} does not exist'.format(group_uid)]})
            groups.append(group)

        cli = CLI()
        cli.add_user_to_depts(user, depts)
        cli.add_user_to_groups(user, groups)
Beispiel #9
0
class APPListCreateAPIView(generics.ListCreateAPIView):
    '''
    管理页面-应用列表 [GET], [POST]
    子管理员管理范围内的应用列表
    '''
    pagination_class = DefaultListPaginator

    read_permission_classes = [IsAuthenticated & (IsAdminUser | IsManagerUser)]
    write_permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_app_create'))
    ]

    def get_permissions(self):
        '''
        读写权限
        '''
        if self.request.method in SAFE_METHODS:
            return [perm() for perm in self.read_permission_classes]
        return [perm() for perm in self.write_permission_classes]

    def get_serializer_class(self):
        if self.request.method == 'GET':
            return APPWithAccessOwnerSerializer
        return APPSerializer

    def get_queryset(self):  # pylint: disable=too-many-locals
        '''
        get app list
        '''
        kwargs = {}
        name = self.request.query_params.get('name', '')
        if name:
            kwargs = {'name__icontains': name}

        # 可管理范围
        manager_app_uids = set()
        for manager_group in self.request.user.manager_groups:
            manager_app_uids.update(set(manager_group.apps))
        kwargs['uid__in'] = manager_app_uids
        if self.request.user.is_admin:
            kwargs.pop('uid__in')
            manager_app_uids = None
        # 筛选-对owner可访问
        owner = None
        access_app_uids = None
        node_uid = self.request.query_params.get('node_uid', None)
        if node_uid:
            node, _ = Dept.retrieve_node(node_uid)
            if not node:
                raise ValidationError({'node_uid': ['not found']})
            owner = node
        user_uid = self.request.query_params.get('user_uid', None)
        if user_uid:
            user = User.valid_objects.filter(username=user_uid).first()
            if not user:
                raise ValidationError({'user_uid': ['not found']})
            owner = user
        if owner:
            owner_access = self.request.query_params.get('owner_access', None)
            if owner_access is not None:
                # 一些基础的access判断
                if owner_access in (True, 'true', 'True'):
                    value = True
                elif owner_access in (False, 'false', 'False'):
                    value = False
                else:
                    raise ValidationError(
                        {'owner_access': ['must be a boolean']})
                scope_kwargs = {} if manager_app_uids is None else {
                    'perm__scope__in': manager_app_uids
                }
                if value is True and not user_uid is None:
                    # 获取的是用户指定应用的权限
                    uids = [
                        item['perm__scope']
                        for item in UserPerm.valid_objects.filter(
                            owner=owner,
                            value=True,
                            perm__subject='app',
                            perm__action__startswith='access',
                        ).values('perm__scope')
                    ]
                    # 获取的是指定应用部门的权限
                    data = []
                    dms = DeptMember.valid_objects.filter(user=owner)
                    result = APP.valid_objects.filter(
                        **kwargs).order_by('-created')
                    for item in result:
                        uid = item.uid
                        if item.allow_any_user is True:
                            if item.uuid not in data:
                                data.append(item.uuid)
                        else:
                            if uid in uids:
                                if item.uuid not in data:
                                    data.append(item.uuid)
                            else:
                                # 取的当前分组的所拥有的部门和当前用户的部门进行比对
                                perms = Perm.valid_objects.filter(
                                    scope=uid,
                                    subject='app',
                                    action__startswith='access').order_by('id')
                                for perm in perms:
                                    deps = DeptPerm.valid_objects.filter(
                                        status=1, perm=perm)
                                    for dep in deps:
                                        owner = dep.owner
                                        # 用户的部门是否属于指定的部门
                                        for dm in dms:
                                            dm_owner = dm.owner
                                            if dm_owner == owner:
                                                if item.uuid not in data:
                                                    data.append(item.uuid)
                                            else:
                                                if dm_owner.if_belong_to_dept(
                                                        owner, True) is True:
                                                    if item.uuid not in data:
                                                        data.append(item.uuid)
                    return APP.valid_objects.filter(
                        uuid__in=data).order_by('-created')
                else:
                    access_app_uids = [
                        item['perm__scope']
                        for item in owner.owner_perm_cls.valid_objects.filter(
                            owner=owner,
                            perm__subject='app',
                            perm__action='access',
                            value=value,
                            **scope_kwargs,
                        ).values('perm__scope')
                    ]
                    kwargs['uid__in'] = access_app_uids
        apps = APP.valid_objects.filter(**kwargs).exclude(
            uid='oneid').order_by('-created')
        return apps

    @transaction.atomic()
    def create(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        '''
        create app [POST]
        '''
        data = request.data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        app = serializer.instance
        self._auto_create_access_perm(app)
        self._auto_create_manager_group(request, app)
        if data.get("secret_required", False):
            create_secret_for_app(app)
        return Response(serializer.data,
                        status=status.HTTP_201_CREATED,
                        headers=self.get_success_headers(serializer.data))

    def perform_create(self, serializer):
        super().perform_create(serializer)  # pylint: disable=no-member
        cli = LOG_CLI()
        cli.create_app(serializer.validated_data)

    @staticmethod
    def _auto_create_manager_group(request, app):
        '''
        当创建应用时,自动创建子管理员组
        成员只有创建者一人,节点管理范围为空,人员管理范围仅自己,应用管理范围仅此一个应用
        '''
        cli = CLI()
        data = {
            'uid': gen_uid(name=uuid_utils.uuid4().hex[:6], cls=Group),
            'name': f'管理应用{app.name}',
            'manager_group': {
                'apps': [app.uid],
                'users': [request.user.username],
                'scope_subject': 2,
            }
        }
        manager_group = cli.create_group(data)
        parent, _ = Group.valid_objects.get_or_create(uid='manager')
        cli.add_group_to_group(manager_group, parent)
        cli.add_users_to_group([request.user], manager_group)

    @staticmethod
    def _auto_create_access_perm(app):
        '''
        当创建应用时,自动创建访问权限
        '''
        Perm.valid_objects.create(name=f'访问{app.name}',
                                  subject='app',
                                  scope=app.uid,
                                  action='access')
Beispiel #10
0
class UserListCreateAPIView(generics.ListCreateAPIView):
    '''
    用户列表 [GET],[POST]
    :GET
    - 主管理员可见全部
    - 子管理员可见管理范围内的指定人、指定节点及其子孙节点内的所有人
    :POST
    - 主管理员可以创建用户
    - 拥有 system_user_create 权限的子管理员
    '''
    serializer_class = EmployeeSerializer
    pagination_class = DefaultListPaginator

    read_permission_classes = [IsAuthenticated & (IsAdminUser | IsManagerUser)]
    write_permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_user_create'))
    ]

    def get_permissions(self):
        '''
        读写权限
        '''
        if self.request.method in SAFE_METHODS:
            return [perm() for perm in self.read_permission_classes]
        return [perm() for perm in self.write_permission_classes]

    def get_queryset(self):
        '''
        return queryset for list [GET]
        '''
        queryset = User.valid_objects.all()

        keyword = self.request.query_params.get('keyword', '')
        if keyword != '':
            queryset = queryset.filter(Q(username__icontains=keyword)|Q(email__icontains=keyword)|\
                Q(private_email__icontains=keyword)|Q(mobile__icontains=keyword)|Q(name__icontains=keyword)).\
                    exclude(is_boss=True).exclude(username='******').order_by('id')
        else:
            queryset = queryset.exclude(is_boss=True).exclude(
                username='******').order_by('id')

        filter_params = (
            'wechat_unionid',
            'name',
            'name__icontains',
            'username',
            'username__icontains',
            'email',
            'email__icontains',
            'private_email',
            'private_email__icontains',
            'mobile',
            'mobile__icontains',
            'gender',
            'remark',
            'remark__icontains',
            'created__lte',
            'created__gte',
            'last_active_time__lte',
            'last_active_time__gte',
        )
        mapper = {
            'wechat_unionid': 'wechat_user__unionid',
        }

        for param in filter_params:
            value = self.request.query_params.get(param, None)
            if value is not None:
                param = mapper.get(param, param)
                queryset = queryset.filter(**{param: value})

        user = self.request.user
        if user.is_admin:
            return queryset.select_related('wechat_user', 'custom_user',
                                           'ding_user')

        under_manage_user_ids = set()

        for item in queryset:  # 这种遍历不能接受
            if item.is_visible_to_manager(user):
                under_manage_user_ids.add(item.username)

        under_manage_user_query_set = queryset.filter(
            username__in=under_manage_user_ids)
        return under_manage_user_query_set

    @transaction.atomic()
    def create(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        '''
        create user [POST]
        '''
        data = request.data
        user_info = data.get('user', '')

        group_uids = []
        dept_uids = []

        node_uids = data.get('node_uids', [])
        if node_uids:
            for node_uid in node_uids:
                if node_uid.startswith(Dept.NODE_PREFIX):
                    dept_uids.append(node_uid.replace(Dept.NODE_PREFIX, '', 1))
                elif node_uid.startswith(Group.NODE_PREFIX):
                    group_uids.append(node_uid.replace(
                        Group.NODE_PREFIX,
                        '',
                    ))
        else:
            group_uids = data.get('group_uids', [])
            dept_uids = data.get('dept_uids', [])

        cli = CLI()
        password = user_info.pop('password', None)
        user = cli.create_user(user_info)
        if password:
            cli.set_user_password(user, password)
        user.origin = 1  # 管理员添加
        user.save()

        self.assign_user(user, dept_uids=dept_uids, group_uids=group_uids)

        user_serializer = EmployeeSerializer(user)
        return Response(user_serializer.data,
                        status=status.HTTP_201_CREATED,
                        headers=self.get_success_headers(user_serializer.data))

    @staticmethod
    def assign_user(user, dept_uids, group_uids):
        '''
        - add_user_to_depts
        - add_user_to_groups
        :param User user:
        :param list dept_uids: list of uid
        :param list group_uids: list of uid
        '''
        depts = []
        for dept_uid in dept_uids:
            try:
                dept = Dept.valid_objects.get(uid=dept_uid)
            except ObjectDoesNotExist:
                raise ValidationError(
                    {'dept_uids': ['dept:{} does not exist'.format(dept_uid)]})
            depts.append(dept)

        groups = []
        for group_uid in group_uids:
            try:
                group = Group.valid_objects.get(uid=group_uid)
            except ObjectDoesNotExist:
                raise ValidationError({
                    'group_uids':
                    ['group:{} does not exist'.format(group_uid)]
                })
            groups.append(group)

        cli = CLI()
        cli.add_user_to_depts(user, depts)
        cli.add_user_to_groups(user, groups)
Beispiel #11
0
class GroupChildGroupAPIView(
        mixins.UpdateModelMixin,
        mixins.RetrieveModelMixin,
        generics.ListCreateAPIView,
):
    '''
    组下属子组信息 [GET], [POST], [PATCH]

    管理员可见
    TODO: 权限校验需深入
    '''

    serializer_class = GroupListSerializer

    read_permission_classes = [
        IsAuthenticated &
        (NodeEmployeeReadable | IsAdminUser | NodeManagerReadable)
    ]
    write_permission_classes = [
        IsAuthenticated & (IsAdminUser | IsNodeManager)
    ]
    create_category_permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_category_create'))
    ]

    def dispatch(self, request, *args, **kwargs):
        '''
        管理员组下的子管理员组用专用View
        '''
        if kwargs['uid'] == 'manager' and request.method == 'GET':
            return ManagerGroupListAPIView().dispatch(request, *args, **kwargs)
        return super().dispatch(request, *args, **kwargs)

    def get_permissions(self):
        '''
        读写权限
        '''
        if self.request.method in SAFE_METHODS:
            permissions = self.read_permission_classes
        elif self.kwargs[
                'uid'] == 'intra' and self.request.method == 'POST':  # 新建大类
            permissions = self.create_category_permission_classes
        else:
            permissions = self.write_permission_classes

        return [perm() for perm in permissions]

    def get_object(self):
        '''
        find group
        '''
        group = Group.valid_objects.filter(uid=self.kwargs['uid']).first()
        if not group:
            raise NotFound
        self.check_object_permissions(self.request, group)
        return group

    def get(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        '''
        获取组下属子组信息 [GET]
        '''
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    @transaction.atomic()
    def create(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        '''
        添加子组,从无到有 [POST]
        '''
        parent_group = self.get_object()
        group_data = request.data
        uid = group_data.get('uid', '')
        if 'manager_group' in group_data:
            if parent_group.uid == 'manager':
                if not group_data.get('name', ''):
                    name = "".join(
                        random.choice(string.ascii_lowercase)
                        for _ in range(8))
                    group_data.update(name=name)
            else:
                group_data.pop('manager_group')
        if not uid:
            name = group_data.get('name')
            if not name:
                raise ValidationError({'name': ['this field is required']})
            uid = gen_uid(name=name, cls=Group)
            group_data['uid'] = uid

        cli = CLI()
        group_data.update(parent_uid=self.kwargs['uid'])
        child_group = cli.create_group(group_data)
        cli.add_group_to_group(child_group, parent_group)

        if parent_group.uid == 'intra':
            self._auto_create_manager_group(request, child_group)
        transaction.on_commit(
            lambda: WebhookManager.group_created(child_group))
        return Response(GroupDetailSerializer(child_group).data,
                        status=status.HTTP_201_CREATED)

    @catch_json_load_error
    def patch(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        '''
        调整子组 [PATCH]
        操作包括
        - 排序sort
        - 移动add, 即修改父部门。从无到有的添加,由create负责
        '''
        parent_group = self.get_object()
        data = json.loads(request.body.decode('utf-8'))
        subject = data.get('subject', '')
        if subject not in ['sort', 'add']:
            raise ValidationError(
                {'subject': ['this field must be `sort` or `add`']})

        filters = {}
        if subject == 'sort':
            filters = {'parent': parent_group}

        group_uids = get_patch_scope(request)

        try:
            groups = Group.get_from_pks(pks=group_uids,
                                        pk_name='uid',
                                        raise_exception=True,
                                        **filters)
        except ObjectDoesNotExist as error:
            bad_uid = error.args[0]
            raise ValidationError(
                {'group_uids': ['group:{} invalid'.format(bad_uid)]})

        cli = CLI()
        if subject == 'sort':
            cli.sort_groups_in_group(groups, parent_group)
        elif subject == 'add':
            for group in groups:
                cli.move_group_to_group(group, parent_group)
        return Response(GroupListSerializer(parent_group).data)

    @staticmethod
    def _auto_create_manager_group(request, child_group):
        '''
        当创建大类时,自动创建子管理员组
        成员只有创建者一人,节点范围仅此大类,人员管理范围仅自己,应用管理范围为空
        '''
        cli = CLI()
        data = {
            'uid': gen_uid(name=uuid_utils.uuid4().hex[:6], cls=Group),
            'name': f'管理分组{child_group.name}',
            'manager_group': {
                'nodes': [child_group.node_uid],
                'users': [request.user.username],
                'scope_subject': 2,
            },
        }
        manager_group = cli.create_group(data)
        parent, _ = Group.valid_objects.get_or_create(uid='manager')
        cli.add_group_to_group(manager_group, parent)
        cli.add_users_to_group([request.user], manager_group)
Beispiel #12
0
class UserListCreateAPIView(generics.ListCreateAPIView):
    '''
    用户列表 [GET],[POST]
    :GET
    - 主管理员可见全部
    - 子管理员可见管理范围内的指定人、指定节点及其子孙节点内的所有人
    :POST
    - 主管理员可以创建用户
    - 拥有 system_user_create 权限的子管理员
    '''

    serializer_class = EmployeeSerializer
    pagination_class = DefaultListPaginator

    read_permission_classes = [IsAuthenticated & (IsAdminUser | IsManagerUser)]
    write_permission_classes = [
        IsAuthenticated & (IsAdminUser | CustomPerm('system_user_create'))
    ]

    def get_permissions(self):
        '''
        读写权限
        '''
        if self.request.method in SAFE_METHODS:
            return [perm() for perm in self.read_permission_classes]
        return [perm() for perm in self.write_permission_classes]

    # pylint: disable=too-many-locals
    # pylint: disable=too-many-branches
    # pylint: disable=too-many-statements
    def get_queryset(self):
        '''
        return queryset for list [GET]
        '''
        queryset = User.valid_objects.all()
        keyword = self.request.query_params.get('keyword', '')
        if keyword != '':
            queryset = (queryset.filter(
                Q(username__icontains=keyword)
                | Q(email__icontains=keyword)
                | Q(private_email__icontains=keyword)
                | Q(mobile__icontains=keyword)
                | Q(name__icontains=keyword)).exclude(is_boss=True).exclude(
                    username='******').order_by('id'))
        else:
            queryset = (queryset.exclude(is_boss=True).exclude(
                username='******').order_by('id'))

        # 支持通过 user_id 搜索
        # QueryString 中格式为 '&user_ids=id1 ... idn'
        user_ids = self._get_user_ids(
            self.request.query_params.get('user_ids', ''), 'user')
        queryset = (queryset.filter(
            pk__in=user_ids) if user_ids is not None else queryset)

        # 支持通过 usernames 搜索
        # QueryString 中格式为 '&usernames=username1 ... usernamen'
        usernames = self.request.query_params.get('usernames', '')
        if usernames != '':
            usernames = usernames.split(' ')
            queryset = queryset.filter(username__in=usernames)

        # 支持通过 group_uid 搜索 (保留属于group_uids[]的用户)
        # QueryString 中格式为 '&group_uids=uid1 ... uidn'
        user_ids = self._get_user_ids(
            self.request.query_params.get('group_uids', ''), 'group')
        queryset = (queryset.filter(
            pk__in=user_ids) if user_ids is not None else queryset)

        # 支持通过 -group_uid 搜索 (保留不属于group_uids[]的用户)
        # QueryString 中格式为 '&group_uids=uid1 ... uidn'
        user_ids = self._get_user_ids(
            self.request.query_params.get('-group_uids', ''), 'group')
        queryset = (queryset.exclude(
            pk__in=user_ids) if user_ids is not None else queryset)

        # 支持通过 perm_uid 搜索 (保留拥有perm_uids[]的用户)
        # QueryString 中格式为 '&perm_uids=uid1 ... uidn'
        user_ids = self._get_user_ids(
            self.request.query_params.get('perm_uids', ''), 'perm')
        queryset = (queryset.filter(
            pk__in=user_ids) if user_ids is not None else queryset)

        # 支持通过 -perm_uid 搜索 (保留未拥有perm_uids[]的用户)
        # QueryString 中格式为 '&perm_uids=uid1 ... uidn'
        user_ids = self._get_user_ids(
            self.request.query_params.get('-perm_uids', ''), 'perm')
        queryset = (queryset.exclude(
            pk__in=user_ids) if user_ids is not None else queryset)

        filter_params = (
            'wechat_unionid',
            'name',
            'name__icontains',
            'username',
            'username__icontains',
            'email',
            'email__icontains',
            'private_email',
            'private_email__icontains',
            'mobile',
            'mobile__icontains',
            'gender',
            'remark',
            'remark__icontains',
            'created__lte',
            'created__gte',
            'last_active_time__lte',
            'last_active_time__gte',
            'unbound_wechat',
            'unbound_ding',
            'unbound_alipay',
            'unbound_qq',
        )
        mapper = {
            'wechat_unionid': 'wechat_user__unionid',
            'unbound_wechat': 'wechat_user__isnull',
            'unbound_ding': 'ding_user__isnull',
            'unbound_alipay': 'alipay_user__isnull',
            'unbound_qq': 'qq_user__isnull',
        }
        boolean_params = (
            'unbound_wechat',
            'unbound_ding',
            'unbound_alipay',
            'unbound_qq',
        )
        _boolean_map = {
            'true': True,
            'false': False,
        }

        for param in filter_params:
            value = self.request.query_params.get(param, None)
            # 用户关联账号相关搜索
            if (value is not None and param in boolean_params
                    and value.lower() in _boolean_map.keys()):
                param = mapper.get(param)
                queryset = queryset.filter(
                    **{param: _boolean_map.get(value.lower())})
                continue
            if value is not None:
                param = mapper.get(param, param)
                queryset = queryset.filter(**{param: value})

        # 获取 query string 中自定义字段(*__custom)
        # 支持 *__(lte, gte, lt, gt 等)__custom 形式,需进行范围搜索的字段在存储时保证传入的为string
        suffixes = [
            '__lte__custom',
            '__lt__custom',
            '__gte__custom',
            '__gt__custom',
            '__custom',
        ]
        for key, value in self.request.query_params.items():
            for suffix in suffixes:
                if key.endswith(suffix):
                    _key = 'custom_user__data__"{custom_field}"{suffix}'.format(
                        custom_field=key[:-1 * len(suffix)],
                        suffix=suffix[:-8])
                    queryset = queryset.filter(**{_key: value})
                    break
        # 支持自定义排序
        # QueryString 中格式为 '&sort=field1 ... fieldn'
        _sort = self.request.query_params.get('sort')
        _sort = _sort.split(' ') if _sort else []
        # 校验排序字段合法性
        for field_name in _sort:
            field_name = field_name[1:] if field_name.startswith(
                '-') else field_name
            try:
                # pylint: disable=no-member
                # pylint: disable=protected-access
                _ = User._meta.get_field(field_name)
            except FieldDoesNotExist:
                raise ValidationError(
                    {'sort': f"Invalid order_by argument: '{field_name}'"})
        queryset = queryset.order_by(*_sort)

        user = self.request.user
        if user.is_admin:
            return queryset.select_related('wechat_user', 'custom_user',
                                           'ding_user')

        under_manage_user_ids = set()

        for item in queryset:  # 这种遍历不能接受
            if item.is_visible_to_manager(user):
                under_manage_user_ids.add(item.username)

        under_manage_user_query_set = queryset.filter(
            username__in=under_manage_user_ids)
        return under_manage_user_query_set

    @transaction.atomic()
    def create(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        '''
        create user [POST]
        '''
        data = request.data
        user_info = data.get('user', '')

        group_uids = []
        dept_uids = []

        node_uids = data.get('node_uids', [])
        if node_uids:
            for node_uid in node_uids:
                if node_uid.startswith(Dept.NODE_PREFIX):
                    dept_uids.append(node_uid.replace(Dept.NODE_PREFIX, '', 1))
                elif node_uid.startswith(Group.NODE_PREFIX):
                    group_uids.append(node_uid.replace(
                        Group.NODE_PREFIX,
                        '',
                    ))
        else:
            group_uids = data.get('group_uids', [])
            dept_uids = data.get('dept_uids', [])
        cli = CLI()
        password = user_info.pop('password', None)
        # 创建用户
        user = cli.create_user(user_info)
        if password:
            validate_password(password)
            cli.set_user_password(user, password)
        user.origin = 1  # 管理员添加
        user.save()
        # 分配组和部门
        self.assign_user(user, dept_uids=dept_uids, group_uids=group_uids)
        user_serializer = EmployeeSerializer(user)
        transaction.on_commit(lambda: WebhookManager.user_created(user))
        return Response(
            user_serializer.data,
            status=status.HTTP_201_CREATED,
            headers=self.get_success_headers(user_serializer.data),
        )

    @staticmethod
    def assign_user(user, dept_uids, group_uids):
        '''
        - add_user_to_depts
        - add_user_to_groups
        :param User user:
        :param list dept_uids: list of uid
        :param list group_uids: list of uid
        '''
        depts = []
        for dept_uid in dept_uids:
            try:
                dept = Dept.valid_objects.get(uid=dept_uid)
            except ObjectDoesNotExist:
                raise ValidationError(
                    {'dept_uids': ['dept:{} does not exist'.format(dept_uid)]})
            depts.append(dept)

        groups = []
        for group_uid in group_uids:
            try:
                group = Group.valid_objects.get(uid=group_uid)
            except ObjectDoesNotExist:
                raise ValidationError({
                    'group_uids':
                    ['group:{} does not exist'.format(group_uid)]
                })
            groups.append(group)

        cli = CLI()
        cli.add_user_to_depts(user, depts)
        cli.add_user_to_groups(user, groups)

    def _get_user_ids(self, uids, subject):
        """
        获取即将过滤的 user_ids 列表
        :param uids: 通过 QueryString 获取的 uids
        :param subject: 搜索的标签类型
        """
        if uids == '':
            return None
        user_ids = None
        uids = uids.split(' ')
        if subject == 'group':
            user_ids = (GroupMember.valid_objects.filter(
                owner__uid__in=uids).values('user__id').distinct())
        if subject == 'perm':
            user_perms = UserPerm.valid_objects.filter(perm__uid__in=uids)
            for user_perm in user_perms:  # 校验权限是否在管辖范围之内
                if not user_perm.owner.under_manage(self.request.user):
                    raise PermissionDenied({
                        'perm_uids':
                        f"Invalid perm_uids argument: '{user_perm.perm.uid}'"
                    })
            user_ids = user_perms.filter(
                value=True).values('owner__id').distinct()
        if subject == 'user':
            user_ids = uids
        return user_ids