# -*- coding: utf-8 -*- # import uuid from django.shortcuts import get_object_or_404 from rest_framework.views import APIView, Response from rest_framework.generics import ( ListAPIView, get_object_or_404, RetrieveAPIView ) from rest_framework.pagination import LimitOffsetPagination from common.permissions import IsValidUser, IsOrgAdminOrAppUser, IsOrgAdmin from common.tree import TreeNodeSerializer from common.utils import get_logger from ..utils import ( AssetPermissionUtil, ParserNode, ) from .mixin import ( UserPermissionCacheMixin, GrantAssetsMixin, NodesWithUngroupMixin ) from .. import const from ..hands import User, Asset, Node, SystemUser, NodeSerializer from .. import serializers from ..models import Action logger = get_logger(__name__) __all__ = [ 'UserGrantedAssetsApi', 'UserGrantedNodesApi', 'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi', 'ValidateUserAssetPermissionApi', 'UserGrantedNodesAsTreeApi', 'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi', 'RefreshAssetPermissionCacheApi' ] class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView): """ 用户授权的所有资产 """ permission_classes = (IsOrgAdminOrAppUser,) pagination_class = LimitOffsetPagination def get_object(self): user_id = self.kwargs.get('pk', '') if user_id: user = get_object_or_404(User, id=user_id) else: user = self.request.user return user def get_queryset(self): user = self.get_object() util = AssetPermissionUtil(user, cache_policy=self.cache_policy) queryset = util.get_assets() return queryset def get_permissions(self): if self.kwargs.get('pk') is None: self.permission_classes = (IsValidUser,) return super().get_permissions() class UserGrantedNodeAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView): """ 查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产 """ permission_classes = (IsOrgAdminOrAppUser,) pagination_class = LimitOffsetPagination def get_object(self): user_id = self.kwargs.get('pk', '') if user_id: user = get_object_or_404(User, id=user_id) else: user = self.request.user return user def get_node_key(self): node_id = self.kwargs.get('node_id') if str(node_id) == const.UNGROUPED_NODE_ID: key = self.util.tree.ungrouped_key elif str(node_id) == const.EMPTY_NODE_ID: key = const.EMPTY_NODE_KEY else: node = get_object_or_404(Node, id=node_id) key = node.key return key def get_queryset(self): user = self.get_object() query_all = self.request.query_params.get("all", "0") == "1" self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy) key = self.get_node_key() nodes_items = self.util.get_nodes_with_assets() assets_system_users = {} if query_all: k = "all_assets" else: k = "assets" for item in nodes_items: if item["key"] == key: assets_system_users = item[k] break assets = [] for asset_id, system_users in assets_system_users.items(): assets.append({"id": asset_id, "system_users": system_users}) return assets def get_permissions(self): if self.kwargs.get('pk') is None: self.permission_classes = (IsValidUser,) return super().get_permissions() class UserGrantedNodesApi(UserPermissionCacheMixin, NodesWithUngroupMixin, ListAPIView): """ 查询用户授权的所有节点的API """ permission_classes = (IsOrgAdminOrAppUser,) serializer_class = NodeSerializer pagination_class = LimitOffsetPagination only_fields = NodeSerializer.Meta.only_fields def get_object(self): user_id = self.kwargs.get('pk', '') if user_id: user = get_object_or_404(User, id=user_id) else: user = self.request.user return user def get_nodes(self, nodes_with_assets): node_keys = [n["key"] for n in nodes_with_assets] nodes = Node.objects.filter(key__in=node_keys).only( *self.only_fields ) nodes_map = {n.key: n for n in nodes} self.add_ungrouped_nodes(nodes_map, node_keys) _nodes = [] for n in nodes_with_assets: key = n["key"] node = nodes_map.get(key) node._assets_amount = n["assets_amount"] _nodes.append(node) return _nodes def get_serializer(self, nodes_with_assets, many=True): nodes = self.get_nodes(nodes_with_assets) return super().get_serializer(nodes, many=True) def get_queryset(self): user = self.get_object() self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy) nodes_with_assets = self.util.get_nodes_with_assets() return nodes_with_assets def get_permissions(self): if self.kwargs.get('pk') is None: self.permission_classes = (IsValidUser,) return super().get_permissions() class UserGrantedNodesAsTreeApi(UserGrantedNodesApi): serializer_class = TreeNodeSerializer only_fields = ParserNode.nodes_only_fields def get_serializer(self, nodes_with_assets, many=True): nodes = self.get_nodes(nodes_with_assets) queryset = [] for node in nodes: data = ParserNode.parse_node_to_tree_node(node) queryset.append(data) return self.get_serializer_class()(queryset, many=many) class UserGrantedNodesWithAssetsApi(UserPermissionCacheMixin, NodesWithUngroupMixin, ListAPIView): """ 用户授权的节点并带着节点下资产的api """ permission_classes = (IsOrgAdminOrAppUser,) serializer_class = serializers.NodeGrantedSerializer pagination_class = LimitOffsetPagination nodes_only_fields = serializers.NodeGrantedSerializer.Meta.only_fields assets_only_fields = serializers.NodeGrantedSerializer.assets_only_fields system_users_only_fields = serializers.NodeGrantedSerializer.system_users_only_fields def get_object(self): user_id = self.kwargs.get('pk', '') if not user_id: user = self.request.user else: user = get_object_or_404(User, id=user_id) return user def get_maps(self, nodes_items): """ 查库,并加入构造的ungrouped节点 :return: ({asset.id: asset}, {node.key: node}, {system_user.id: system_user}) """ _nodes_keys = set() _assets_ids = set() _system_users_ids = set() for item in nodes_items: _nodes_keys.add(item["key"]) _assets_ids.update(set(item["assets"].keys())) for _system_users_id in item["assets"].values(): _system_users_ids.update(_system_users_id.keys()) _nodes = Node.objects.filter(key__in=_nodes_keys).only( *self.nodes_only_fields ) _assets = Asset.objects.filter(id__in=_assets_ids).only( *self.assets_only_fields ) _system_users = SystemUser.objects.filter(id__in=_system_users_ids).only( *self.system_users_only_fields ) _nodes_map = {n.key: n for n in _nodes} self.add_ungrouped_nodes(_nodes_map, _nodes_keys) _assets_map = {a.id: a for a in _assets} _system_users_map = {s.id: s for s in _system_users} return _nodes_map, _assets_map, _system_users_map def get_serializer_queryset(self, nodes_items): """ 将id转为object,同时构造queryset :param nodes_items: [ { 'key': node.key, 'assets_amount': 10 'assets': { asset.id: { system_user.id: actions, }, }, }, ] """ queryset = [] _node_map, _assets_map, _system_users_map = self.get_maps(nodes_items) for item in nodes_items: key = item["key"] node = _node_map.get(key) if not node: continue node._assets_amount = item["assets_amount"] assets_granted = [] for asset_id, system_users_ids_action in item["assets"].items(): asset = _assets_map.get(asset_id) if not asset: continue system_user_granted = [] for system_user_id, action in system_users_ids_action.items(): system_user = _system_users_map.get(system_user_id) if not system_user: continue if not asset.has_protocol(system_user.protocol): continue system_user.actions = action system_user_granted.append(system_user) asset.system_users_granted = system_user_granted assets_granted.append(asset) node.assets_granted = assets_granted queryset.append(node) return queryset def get_serializer(self, nodes_items, many=True): queryset = self.get_serializer_queryset(nodes_items) return super().get_serializer(queryset, many=many) def get_queryset(self): user = self.get_object() self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy) system_user_id = self.request.query_params.get('system_user') if system_user_id: self.util.filter_permissions( system_users=system_user_id ) nodes_items = self.util.get_nodes_with_assets() return nodes_items def get_permissions(self): if self.kwargs.get('pk') is None: self.permission_classes = (IsValidUser,) return super().get_permissions() class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodesWithAssetsApi): serializer_class = TreeNodeSerializer permission_classes = (IsOrgAdminOrAppUser,) system_user_id = None nodes_only_fields = ParserNode.nodes_only_fields assets_only_fields = ParserNode.assets_only_fields system_users_only_fields = ParserNode.system_users_only_fields def get_serializer(self, nodes_items, many=True): _queryset = super().get_serializer_queryset(nodes_items) queryset = [] for node in _queryset: data = ParserNode.parse_node_to_tree_node(node) queryset.append(data) for asset in node.assets_granted: system_users = asset.system_users_granted data = ParserNode.parse_asset_to_tree_node(node, asset, system_users) queryset.append(data) queryset = sorted(queryset) return self.serializer_class(queryset, many=True) class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView): permission_classes = (IsOrgAdminOrAppUser,) def get(self, request, *args, **kwargs): user_id = request.query_params.get('user_id', '') asset_id = request.query_params.get('asset_id', '') system_id = request.query_params.get('system_user_id', '') action_name = request.query_params.get('action_name', '') cache_policy = self.request.query_params.get("cache_policy", '0') try: asset_id = uuid.UUID(asset_id) system_id = uuid.UUID(system_id) except ValueError: return Response({'msg': False}, status=403) user = get_object_or_404(User, id=user_id) util = AssetPermissionUtil(user, cache_policy=cache_policy) assets = util.get_assets() for asset in assets: if asset_id == asset["id"]: action = asset["system_users"].get(system_id) if action and action_name in Action.value_to_choices(action): return Response({'msg': True}, status=200) break return Response({'msg': False}, status=403) class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, RetrieveAPIView): permission_classes = (IsOrgAdminOrAppUser,) serializer_class = serializers.ActionsSerializer def get_object(self): user_id = self.request.query_params.get('user_id', '') asset_id = self.request.query_params.get('asset_id', '') system_id = self.request.query_params.get('system_user_id', '') try: user_id = uuid.UUID(user_id) asset_id = uuid.UUID(asset_id) system_id = uuid.UUID(system_id) except ValueError: return Response({'msg': False}, status=403) user = get_object_or_404(User, id=user_id) util = AssetPermissionUtil(user, cache_policy=self.cache_policy) assets = util.get_assets() actions = 0 for asset in assets: if asset_id == asset["id"]: actions = asset["system_users"].get(system_id, 0) break return {"actions": actions} class RefreshAssetPermissionCacheApi(RetrieveAPIView): permission_classes = (IsOrgAdmin,) def retrieve(self, request, *args, **kwargs): # expire all cache AssetPermissionUtil.expire_all_cache() return Response({'msg': True}, status=200)