# -*- coding: utf-8 -*- # import uuid from hashlib import md5 from django.core.cache import cache from django.db.models import Q from django.conf import settings from rest_framework.views import Response from django.utils.decorators import method_decorator from django.views.decorators.http import condition from django.utils.translation import ugettext as _ from common.utils import get_logger from assets.utils import LabelFilterMixin from .. import const from ..hands import Asset, Node, SystemUser from .. import serializers logger = get_logger(__name__) __all__ = ['UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin'] # def get_etag(request, *args, **kwargs): # cache_policy = request.GET.get("cache_policy") # if cache_policy != '1': # return None # if not UserPermissionCacheMixin.CACHE_ENABLE: # return None # view = request.parser_context.get("view") # if not view: # return None # etag = view.get_meta_cache_id() # return etag class UserPermissionCacheMixin: pass # cache_policy = '0' # RESP_CACHE_KEY = '_PERMISSION_RESPONSE_CACHE_V2_{}' # CACHE_ENABLE = settings.ASSETS_PERM_CACHE_ENABLE # CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME # _object = None # # def get_object(self): # return None # # # 内部使用可控制缓存 # def _get_object(self): # if not self._object: # self._object = self.get_object() # return self._object # # def get_object_id(self): # obj = self._get_object() # if obj: # return str(obj.id) # return None # # def get_request_md5(self): # path = self.request.path # query = {k: v for k, v in self.request.GET.items()} # query.pop("_", None) # query = "&".join(["{}={}".format(k, v) for k, v in query.items()]) # full_path = "{}?{}".format(path, query) # return md5(full_path.encode()).hexdigest() # # def get_meta_cache_id(self): # obj = self._get_object() # util = AssetPermissionUtil(obj, cache_policy=self.cache_policy) # meta_cache_id = util.cache_meta.get('id') # return meta_cache_id # # def get_response_cache_id(self): # obj_id = self.get_object_id() # request_md5 = self.get_request_md5() # meta_cache_id = self.get_meta_cache_id() # resp_cache_id = '{}_{}_{}'.format(obj_id, request_md5, meta_cache_id) # return resp_cache_id # # def get_response_from_cache(self): # # 没有数据缓冲 # meta_cache_id = self.get_meta_cache_id() # if not meta_cache_id: # logger.debug("Not get meta id: {}".format(meta_cache_id)) # return None # # 从响应缓冲里获取响应 # key = self.get_response_key() # data = cache.get(key) # if not data: # logger.debug("Not get response from cache: {}".format(key)) # return None # logger.debug("Get user permission from cache: {}".format(self.get_object())) # response = Response(data) # return response # # def expire_response_cache(self): # obj_id = self.get_object_id() # expire_cache_id = '{}_{}'.format(obj_id, '*') # key = self.RESP_CACHE_KEY.format(expire_cache_id) # cache.delete_pattern(key) # # def get_response_key(self): # resp_cache_id = self.get_response_cache_id() # key = self.RESP_CACHE_KEY.format(resp_cache_id) # return key # # def set_response_to_cache(self, response): # key = self.get_response_key() # cache.set(key, response.data, self.CACHE_TIME) # logger.debug("Set response to cache: {}".format(key)) # # @method_decorator(condition(etag_func=get_etag)) # def get(self, request, *args, **kwargs): # if not self.CACHE_ENABLE: # self.cache_policy = '0' # else: # self.cache_policy = request.GET.get('cache_policy', '0') # # obj = self._get_object() # if obj is None: # logger.debug("Not get response from cache: obj is none") # return super().get(request, *args, **kwargs) # # if AssetPermissionUtil.is_not_using_cache(self.cache_policy): # logger.debug("Not get resp from cache: {}".format(self.cache_policy)) # return super().get(request, *args, **kwargs) # elif AssetPermissionUtil.is_refresh_cache(self.cache_policy): # logger.debug("Not get resp from cache: {}".format(self.cache_policy)) # self.expire_response_cache() # # logger.debug("Try get response from cache") # resp = self.get_response_from_cache() # if not resp: # resp = super().get(request, *args, **kwargs) # self.set_response_to_cache(resp) # return resp class NodesWithUngroupMixin: util = None @staticmethod def get_ungrouped_node(ungroup_key): return Node(key=ungroup_key, id=const.UNGROUPED_NODE_ID, value=_("ungrouped")) @staticmethod def get_empty_node(): return Node(key=const.EMPTY_NODE_KEY, id=const.EMPTY_NODE_ID, value=_("empty")) def add_ungrouped_nodes(self, node_map, node_keys): ungroup_key = '1:-1' for key in node_keys: if key.endswith('-1'): ungroup_key = key break ungroup_node = self.get_ungrouped_node(ungroup_key) empty_node = self.get_empty_node() node_map[ungroup_key] = ungroup_node node_map[const.EMPTY_NODE_KEY] = empty_node class GrantAssetsMixin(LabelFilterMixin): serializer_class = serializers.AssetGrantedSerializer def get_serializer_queryset(self, queryset): assets_ids = [] system_users_ids = set() for asset in queryset: assets_ids.append(asset["id"]) system_users_ids.update(set(asset["system_users"])) assets = Asset.objects.filter(id__in=assets_ids).only( *self.serializer_class.Meta.only_fields ) assets_map = {asset.id: asset for asset in assets} system_users = SystemUser.objects.filter(id__in=system_users_ids).only( *self.serializer_class.system_users_only_fields ) system_users_map = {s.id: s for s in system_users} data = [] for item in queryset: i = item["id"] asset = assets_map.get(i) if not asset: continue _system_users = item["system_users"] system_users_granted = [] for sid, action in _system_users.items(): system_user = system_users_map.get(sid) if not system_user: continue if not asset.has_protocol(system_user.protocol): continue system_user.actions = action system_users_granted.append(system_user) asset.system_users_granted = system_users_granted data.append(asset) return data def get_serializer(self, assets_items=None, many=True): if assets_items is None: assets_items = [] assets_items = self.get_serializer_queryset(assets_items) return super().get_serializer(assets_items, many=many) def filter_queryset_by_id(self, assets_items): i = self.request.query_params.get("id") if not i: return assets_items try: pk = uuid.UUID(i) except ValueError: return assets_items assets_map = {asset['id']: asset for asset in assets_items} if pk in assets_map: return [assets_map.get(pk)] else: return [] def search_queryset(self, assets_items): search = self.request.query_params.get("search") if not search: return assets_items assets_map = {asset['id']: asset for asset in assets_items} assets_ids = set(assets_map.keys()) assets_ids_search = Asset.objects.filter(id__in=assets_ids).filter( Q(hostname__icontains=search) | Q(ip__icontains=search) ).values_list('id', flat=True) return [assets_map.get(asset_id) for asset_id in assets_ids_search] def filter_queryset_by_label(self, assets_items): labels_id = self.get_filter_labels_ids() if not labels_id: return assets_items assets_map = {asset['id']: asset for asset in assets_items} assets_matched = Asset.objects.filter(id__in=assets_map.keys()) for label_id in labels_id: assets_matched = assets_matched.filter(labels=label_id) assets_ids_matched = assets_matched.values_list('id', flat=True) return [assets_map.get(asset_id) for asset_id in assets_ids_matched] def sort_queryset(self, assets_items): order_by = self.request.query_params.get('order', 'hostname') if order_by not in ['hostname', '-hostname', 'ip', '-ip']: order_by = 'hostname' assets_map = {asset['id']: asset for asset in assets_items} assets_ids_search = Asset.objects.filter(id__in=assets_map.keys())\ .order_by(order_by)\ .values_list('id', flat=True) return [assets_map.get(asset_id) for asset_id in assets_ids_search] def filter_queryset(self, assets_items): assets_items = self.filter_queryset_by_id(assets_items) assets_items = self.search_queryset(assets_items) assets_items = self.filter_queryset_by_label(assets_items) assets_items = self.sort_queryset(assets_items) return assets_items