Skip to content

Commit

Permalink
Merge pull request #114 from longguikeji/sy/bug_user_list
Browse files Browse the repository at this point in the history
fix(user_list): 用户分组管理、账户管理可见性
  • Loading branch information
skoogi authored Feb 25, 2020
2 parents 17b3486 + 8d8a82a commit 661e6fd
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 98 deletions.
2 changes: 1 addition & 1 deletion oneid_meta/models/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def detail_serializer_cls(self):
'''
详情序列化类
'''
from siteapi.v1.serializers.dept import DeptDetailSerializer
from siteapi.v1.serializers.dept import DeptDetailSerializer # pylint: disable=import-outside-toplevel
return DeptDetailSerializer

@property
Expand Down
61 changes: 46 additions & 15 deletions oneid_meta/models/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class NodeVisibilityScope(models.Model):
'''
节点对员工的可见范围
'''
class Meta:
class Meta: # pylint: disable=missing-class-docstring
abstract = True

VISIBILITY_SUBJECT = ( # 此处`对...可见`,为`对...开放`的意思,即使判定不可见,最终也有可能可以看到
Expand Down Expand Up @@ -41,7 +41,7 @@ def is_open_to_employee(self, user):

if self.visibility == 3:
node_uids = map(lambda node: node.uid, self.tree_front_walker()) # pylint: disable=no-member
return self.member_cls.valid_objects.filter(user=user, owner__uid__in=node_uids).exists()
return self.member_cls.valid_objects.filter(user=user, owner__uid__in=node_uids).exists() # pylint: disable=no-member

if self.visibility == 4:
if user.username in self.user_scope: # pylint: disable=no-member, unsupported-membership-test
Expand All @@ -67,7 +67,7 @@ def is_open_to_manager(self, user):
'''
对管理员是否开放,由用户所在管理员组决定
'''
return self.under_manage(user)
return self.under_manage(user) # pylint: disable=no-member

def is_visible_to_manager(self, user):
'''
Expand All @@ -78,11 +78,11 @@ def is_visible_to_manager(self, user):

manage_node_uids = user.manage_node_uids

if set(self.upstream_uids) & manage_node_uids:
if set(self.upstream_uids) & manage_node_uids: # pylint: disable=no-member
return True

for node in self.retrieve_nodes(manage_node_uids):
if self.node_uid in set(node.upstream_uids):
for node in self.retrieve_nodes(manage_node_uids): # pylint: disable=no-member
if self.node_uid in set(node.upstream_uids): # pylint: disable=no-member
return True

return False
Expand All @@ -95,9 +95,9 @@ def refresh_visibility_scope(self):
old_node_scope = set(self.node_scope)
old_user_scope = set(self.user_scope)

valid_node_scope = set(node.node_uid for node in self.retrieve_nodes(old_node_scope))
valid_node_scope = set(node.node_uid for node in self.retrieve_nodes(old_node_scope)) # pylint: disable=no-member

from oneid_meta.models import User
from oneid_meta.models import User # pylint: disable=import-outside-toplevel
valid_user_scope = set(user.username for user in User.get_from_pks(old_user_scope, pk_name='username'))

if valid_node_scope != old_node_scope:
Expand Down Expand Up @@ -191,14 +191,45 @@ def upstream_uids(self):

return chain([self.node_uid], res)

@classmethod
def get_upstream_uids(cls, node_uid):
'''
节点向上追溯的路径,包括该节点本身,包括终点节点,以node_uid形式返回
'''
key = f'oneid:node:{node_uid}:upstream'
res = cache.get(key)
if res is None:
node, _ = cls.retrieve_node(node_uid)
if node:
node_uids = [item.node_uid for item in node.path_up_to()]
cache.set(key, node_uids[1:])
return node_uids

return chain([node_uid], res)

@property
def downstream_uids(self):
'''
节点以及其子孙节点,以node_uid形式返回
目前使用频次不大
'''
for node in self.downstream:
yield node.node_uid
return self.get_downstream_uids(self.node_uid)

@classmethod
def get_downstream_uids(cls, node_uid):
'''
节点以及其子孙节点,以node_uid形式返回
TODO: 继续优化,从子节点的 downstream_uids 聚合
TODO: 删除节点时,删除缓存
'''
key = f'oneid:node:{node_uid}:downstream'
res = cache.get(key)
if res is None:
node, _ = cls.retrieve_node(node_uid)
if node:
res = [item.node_uid for item in node.downstream]
cache.set(key, res[1:0])
return res
return chain([node_uid], res)

@property
def downstream(self):
Expand All @@ -221,7 +252,7 @@ def retrieve_node(node_uid):
'''
通过node_uid 获取node及该节点类型
'''
from oneid_meta.models import Dept, Group
from oneid_meta.models import Dept, Group # pylint: disable=import-outside-toplevel
if node_uid.startswith(Dept.NODE_PREFIX):
uid = node_uid.replace(Dept.NODE_PREFIX, '', 1)
return Dept.valid_objects.filter(uid=uid).first(), 'dept'
Expand All @@ -235,7 +266,7 @@ def retrieve_nodes(node_uids):
'''
通过node_uids 批量获取node
'''
from oneid_meta.models import Dept, Group
from oneid_meta.models import Dept, Group # pylint: disable=import-outside-toplevel
dept_uids = set()
group_uids = set()
for node_uid in node_uids:
Expand Down Expand Up @@ -271,9 +302,9 @@ def under_manage(self, user):
upstream_uids = set(self.upstream_uids)
for manager_group in user.manager_groups:
if manager_group.scope_subject == 2: # 指定节点、人
if upstream_uids & set(manager_group.nodes):
if self.node_uid in manager_group.nodes:
return True
if manager_group.scope_subject == 1: # 所在节点
if manager_group.scope_subject == 1: # 所在节点及下属节点
if upstream_uids & set(user.node_uids):
return True
return False
Expand Down
46 changes: 38 additions & 8 deletions oneid_meta/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,10 @@ def under_manage(self, user):
self_all_node_uids = self.all_node_uids
for manager_group in user.manager_groups:
if manager_group.scope_subject == 2: # 指定节点、人
if user.username in manager_group.users:
return True
if self_all_node_uids & set(manager_group.nodes):
for node in self.nodes:
if node.under_manage(user):
return True
if self.username in manager_group.users:
return True
if manager_group.scope_subject == 1: # 所在节点
if self_all_node_uids & user.node_uids:
Expand All @@ -380,9 +381,16 @@ def under_manage(self, user):
def is_visible_to_manager(self, user):
'''
校验指定管理员是否可见此人
TODO
'''
return self.under_manage(user)
if user.is_admin:
return True
self_all_node_uids = self.all_node_uids
for manager_group in user.manager_groups:
if self.username in manager_group.users:
return True
if self_all_node_uids & set(manager_group.nodes):
return True
return False

def is_visible_to_employee(self, user):
'''
Expand All @@ -399,17 +407,39 @@ def is_visible_to_employee(self, user):
@property
def manage_node_uids(self):
'''
管理的节点(不包含下级)
直接管理的节点(不包含下级)
'''
res = set()
for manager_group in self.manager_groups:
if manager_group.scope_subject == 2:
if manager_group.scope_subject == 2: # 指定节点、人
res.update(manager_group.nodes)
continue
if manager_group.scope_subject == 1:
if manager_group.scope_subject == 1: # 所在节点
res.update(self.node_uids)
return res

@property
def manage_user_uids(self):
'''
直接管理的人员(不包括从管理组继承而来的可管理的人)
'''
res = set()
for manager_group in self.manager_groups:
if manager_group.scope_subject == 2: # 指定节点、人
res.update(manager_group.users)
return res

@property
def all_manage_node_uids(self):
'''
所有可管理的节点(包含直接管理的节点,及其下属节点)
'''

res = set()
for node_uid in self.manage_node_uids:
res.update(Node.get_downstream_uids(node_uid))
return res

def check_password(self, password):
'''
校验密码是否正确
Expand Down
24 changes: 21 additions & 3 deletions siteapi/v1/views/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
)
from rest_framework.permissions import IsAuthenticated, SAFE_METHODS
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from oneid_meta.models import User, Group, Dept
from oneid.permissions import (
IsAdminUser,
IsManagerUser,
IsUserManager,
UserEmployeeReadable,
UserManagerReadable,
Expand All @@ -37,11 +38,17 @@
class UserListCreateAPIView(generics.ListCreateAPIView):
'''
用户列表 [GET],[POST]
:GET
- 主管理员可见全部
- 子管理员可见管理范围内的指定人、指定节点及其子孙节点内的所有人
:POST
- 主管理员可以创建用户
- 拥有 system_user_create 权限的子管理员
'''
serializer_class = EmployeeSerializer
pagination_class = DefaultListPaginator

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

def get_permissions(self):
Expand All @@ -64,7 +71,18 @@ def get_queryset(self):
else:
queryset = User.valid_objects.exclude(is_boss=True).exclude(username='admin').order_by('id')

return queryset
user = self.request.user
if user.is_admin:
return queryset

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
Expand Down
Loading

0 comments on commit 661e6fd

Please sign in to comment.