mirror of https://github.com/jumpserver/jumpserver
Merge branch 'v3' of github.com:jumpserver/jumpserver into v3
commit
df1950d063
|
@ -33,11 +33,13 @@ ARG TOOLS=" \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
curl \
|
curl \
|
||||||
default-libmysqlclient-dev \
|
default-libmysqlclient-dev \
|
||||||
|
default-mysql-client \
|
||||||
locales \
|
locales \
|
||||||
openssh-client \
|
openssh-client \
|
||||||
sshpass \
|
sshpass \
|
||||||
telnet \
|
telnet \
|
||||||
unzip \
|
unzip \
|
||||||
|
vim \
|
||||||
wget"
|
wget"
|
||||||
|
|
||||||
ARG APT_MIRROR=http://mirrors.ustc.edu.cn
|
ARG APT_MIRROR=http://mirrors.ustc.edu.cn
|
||||||
|
|
|
@ -33,11 +33,13 @@ ARG TOOLS=" \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
curl \
|
curl \
|
||||||
default-libmysqlclient-dev \
|
default-libmysqlclient-dev \
|
||||||
|
default-mysql-client \
|
||||||
locales \
|
locales \
|
||||||
openssh-client \
|
openssh-client \
|
||||||
sshpass \
|
sshpass \
|
||||||
telnet \
|
telnet \
|
||||||
unzip \
|
unzip \
|
||||||
|
vim \
|
||||||
wget"
|
wget"
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from urllib3.exceptions import MaxRetryError
|
from urllib3.exceptions import MaxRetryError
|
||||||
from urllib.parse import urlencode, parse_qsl
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from kubernetes import client
|
from kubernetes import client
|
||||||
from kubernetes.client import api_client
|
from kubernetes.client import api_client
|
||||||
from kubernetes.client.api import core_v1_api
|
from kubernetes.client.api import core_v1_api
|
||||||
from kubernetes.client.exceptions import ApiException
|
from kubernetes.client.exceptions import ApiException
|
||||||
|
|
||||||
from rest_framework.generics import get_object_or_404
|
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from assets.models import Account, Asset
|
|
||||||
|
|
||||||
from ..const import CloudTypes, Category
|
from ..const import CloudTypes, Category
|
||||||
|
|
||||||
|
@ -94,57 +91,45 @@ class KubernetesClient:
|
||||||
return f'{gateway.address}:{gateway.port}'
|
return f'{gateway.address}:{gateway.port}'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_kubernetes_data(cls, app_id, username):
|
def get_kubernetes_data(cls, asset, secret):
|
||||||
asset = get_object_or_404(Asset, id=app_id)
|
|
||||||
account = get_object_or_404(Account, asset=asset, username=username)
|
|
||||||
k8s_url = f'{asset.address}:{asset.port}'
|
k8s_url = f'{asset.address}:{asset.port}'
|
||||||
proxy_url = cls.get_proxy_url(asset)
|
proxy_url = cls.get_proxy_url(asset)
|
||||||
k8s = cls(k8s_url, account.secret, proxy=proxy_url)
|
k8s = cls(k8s_url, secret, proxy=proxy_url)
|
||||||
return k8s.get_pods()
|
return k8s.get_pods()
|
||||||
|
|
||||||
|
|
||||||
class KubernetesTree:
|
class KubernetesTree:
|
||||||
def __init__(self, tree_id):
|
def __init__(self, asset, secret):
|
||||||
self.tree_id = str(tree_id)
|
self.asset = asset
|
||||||
|
self.secret = secret
|
||||||
|
|
||||||
@staticmethod
|
def as_asset_tree_node(self):
|
||||||
def create_tree_id(pid, tp, v):
|
i = str(self.asset.id)
|
||||||
i = dict(parse_qsl(pid))
|
name = str(self.asset)
|
||||||
i[tp] = v
|
|
||||||
tree_id = urlencode(i)
|
|
||||||
return tree_id
|
|
||||||
|
|
||||||
def as_tree_node(self, app):
|
|
||||||
pid = app.create_app_tree_pid(self.tree_id)
|
|
||||||
app_id = str(app.id)
|
|
||||||
node = self.create_tree_node(
|
node = self.create_tree_node(
|
||||||
app_id, pid, app.name, 'k8s'
|
i, i, name, 'asset', is_open=True,
|
||||||
)
|
)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def as_asset_tree_node(self, asset):
|
def as_namespace_node(self, name, tp, counts=0):
|
||||||
i = urlencode({'asset_id': self.tree_id})
|
i = urlencode({'namespace': name})
|
||||||
node = self.create_tree_node(
|
pid = str(self.asset.id)
|
||||||
i, str(asset.id), str(asset), 'asset', is_open=True,
|
name = f'{name}({counts})'
|
||||||
)
|
node = self.create_tree_node(i, pid, name, tp, icon='cloud')
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def as_account_tree_node(self, account, parent_info):
|
def as_pod_tree_node(self, namespace, name, tp, counts=0):
|
||||||
username = account.username
|
pid = urlencode({'namespace': namespace})
|
||||||
name = str(account)
|
i = urlencode({'namespace': namespace, 'pod': name})
|
||||||
pid = urlencode({'asset_id': self.tree_id})
|
name = f'{name}({counts})'
|
||||||
i = self.create_tree_id(pid, 'account', username)
|
node = self.create_tree_node(i, pid, name, tp, icon='cloud')
|
||||||
parent_info.update({'account': username})
|
|
||||||
node = self.create_tree_node(
|
|
||||||
i, pid, name, 'account', icon='user-tie'
|
|
||||||
)
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def as_namespace_pod_tree_node(self, name, tp, counts=0, is_container=False):
|
def as_container_tree_node(self, namespace, pod, name, tp):
|
||||||
i = self.create_tree_id(self.tree_id, tp, name)
|
pid = urlencode({'namespace': namespace, 'pod': pod})
|
||||||
name = name if is_container else f'{name}({counts})'
|
i = urlencode({'namespace': namespace, 'pod': pod, 'container': name})
|
||||||
node = self.create_tree_node(
|
node = self.create_tree_node(
|
||||||
i, self.tree_id, name, tp, icon='cloud', is_container=is_container
|
i, pid, name, tp, icon='cloud', is_container=True
|
||||||
)
|
)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
@ -169,36 +154,31 @@ class KubernetesTree:
|
||||||
}
|
}
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def async_tree_node(self, parent_info):
|
def async_tree_node(self, namespace, pod):
|
||||||
pod_name = parent_info.get('pod')
|
|
||||||
asset_id = parent_info.get('asset_id')
|
|
||||||
namespace = parent_info.get('namespace')
|
|
||||||
account_username = parent_info.get('account')
|
|
||||||
|
|
||||||
tree = []
|
tree = []
|
||||||
data = KubernetesClient.get_kubernetes_data(asset_id, account_username)
|
data = KubernetesClient.get_kubernetes_data(self.asset, self.secret)
|
||||||
if not data:
|
if not data:
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
if pod_name:
|
if pod:
|
||||||
for container in next(
|
for container in next(
|
||||||
filter(
|
filter(
|
||||||
lambda x: x['pod_name'] == pod_name, data[namespace]
|
lambda x: x['pod_name'] == pod, data[namespace]
|
||||||
)
|
)
|
||||||
)['containers']:
|
)['containers']:
|
||||||
container_node = self.as_namespace_pod_tree_node(
|
container_node = self.as_container_tree_node(
|
||||||
container, 'container', is_container=True
|
namespace, pod, container, 'container'
|
||||||
)
|
)
|
||||||
tree.append(container_node)
|
tree.append(container_node)
|
||||||
elif namespace:
|
elif namespace:
|
||||||
for pod in data[namespace]:
|
for pod in data[namespace]:
|
||||||
pod_nodes = self.as_namespace_pod_tree_node(
|
pod_nodes = self.as_pod_tree_node(
|
||||||
pod['pod_name'], 'pod', len(pod['containers'])
|
namespace, pod['pod_name'], 'pod', len(pod['containers'])
|
||||||
)
|
)
|
||||||
tree.append(pod_nodes)
|
tree.append(pod_nodes)
|
||||||
elif account_username:
|
else:
|
||||||
for namespace, pods in data.items():
|
for namespace, pods in data.items():
|
||||||
namespace_node = self.as_namespace_pod_tree_node(
|
namespace_node = self.as_namespace_node(
|
||||||
namespace, 'namespace', len(pods)
|
namespace, 'namespace', len(pods)
|
||||||
)
|
)
|
||||||
tree.append(namespace_node)
|
tree.append(namespace_node)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from common.drf.fields import EncryptedField
|
||||||
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
|
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
|
||||||
from ..models import ConnectionToken
|
from ..models import ConnectionToken
|
||||||
|
|
||||||
|
@ -11,6 +12,9 @@ __all__ = [
|
||||||
|
|
||||||
class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
||||||
expire_time = serializers.IntegerField(read_only=True, label=_('Expired time'))
|
expire_time = serializers.IntegerField(read_only=True, label=_('Expired time'))
|
||||||
|
input_secret = EncryptedField(
|
||||||
|
label=_("Input secret"), max_length=40960, required=False, allow_blank=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConnectionToken
|
model = ConnectionToken
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
- 此文件中添加代码的时候,注意不要跟 `django.db.models` 中的命名冲突
|
- 此文件中添加代码的时候,注意不要跟 `django.db.models` 中的命名冲突
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import inspect
|
|
||||||
import uuid
|
import uuid
|
||||||
from functools import reduce, partial
|
from functools import reduce
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
@ -96,87 +95,6 @@ def output_as_string(field_name):
|
||||||
return ExpressionWrapper(F(field_name), output_field=models.CharField())
|
return ExpressionWrapper(F(field_name), output_field=models.CharField())
|
||||||
|
|
||||||
|
|
||||||
class UnionQuerySet(QuerySet):
|
|
||||||
after_union = ['order_by']
|
|
||||||
not_return_qs = [
|
|
||||||
'query', 'get', 'create', 'get_or_create',
|
|
||||||
'update_or_create', 'bulk_create', 'count',
|
|
||||||
'latest', 'earliest', 'first', 'last', 'aggregate',
|
|
||||||
'exists', 'update', 'delete', 'as_manager', 'explain',
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, *queryset_list):
|
|
||||||
self.queryset_list = queryset_list
|
|
||||||
self.after_union_items = []
|
|
||||||
self.before_union_items = []
|
|
||||||
|
|
||||||
def __execute(self):
|
|
||||||
queryset_list = []
|
|
||||||
for qs in self.queryset_list:
|
|
||||||
for attr, args, kwargs in self.before_union_items:
|
|
||||||
qs = getattr(qs, attr)(*args, **kwargs)
|
|
||||||
queryset_list.append(qs)
|
|
||||||
union_qs = reduce(lambda x, y: x.union(y), queryset_list)
|
|
||||||
for attr, args, kwargs in self.after_union_items:
|
|
||||||
union_qs = getattr(union_qs, attr)(*args, **kwargs)
|
|
||||||
return union_qs
|
|
||||||
|
|
||||||
def __before_union_perform(self, item, *args, **kwargs):
|
|
||||||
self.before_union_items.append((item, args, kwargs))
|
|
||||||
return self.__clone(*self.queryset_list)
|
|
||||||
|
|
||||||
def __after_union_perform(self, item, *args, **kwargs):
|
|
||||||
self.after_union_items.append((item, args, kwargs))
|
|
||||||
return self.__clone(*self.queryset_list)
|
|
||||||
|
|
||||||
def __clone(self, *queryset_list):
|
|
||||||
uqs = UnionQuerySet(*queryset_list)
|
|
||||||
uqs.after_union_items = self.after_union_items
|
|
||||||
uqs.before_union_items = self.before_union_items
|
|
||||||
return uqs
|
|
||||||
|
|
||||||
def __getattribute__(self, item):
|
|
||||||
if item.startswith('__') or item in UnionQuerySet.__dict__ or item in [
|
|
||||||
'queryset_list', 'after_union_items', 'before_union_items'
|
|
||||||
]:
|
|
||||||
return object.__getattribute__(self, item)
|
|
||||||
|
|
||||||
if item in UnionQuerySet.not_return_qs:
|
|
||||||
return getattr(self.__execute(), item)
|
|
||||||
|
|
||||||
origin_item = object.__getattribute__(self, 'queryset_list')[0]
|
|
||||||
origin_attr = getattr(origin_item, item, None)
|
|
||||||
if not inspect.ismethod(origin_attr):
|
|
||||||
return getattr(self.__execute(), item)
|
|
||||||
|
|
||||||
if item in UnionQuerySet.after_union:
|
|
||||||
attr = partial(self.__after_union_perform, item)
|
|
||||||
else:
|
|
||||||
attr = partial(self.__before_union_perform, item)
|
|
||||||
return attr
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
return self.__execute()[item]
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return iter(self.__execute())
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.__execute())
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return repr(self.__execute())
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def test_it(cls):
|
|
||||||
from assets.models import Asset
|
|
||||||
assets1 = Asset.objects.filter(hostname__startswith='a')
|
|
||||||
assets2 = Asset.objects.filter(hostname__startswith='b')
|
|
||||||
|
|
||||||
qs = cls(assets1, assets2)
|
|
||||||
return qs
|
|
||||||
|
|
||||||
|
|
||||||
class MultiTableChildQueryset(QuerySet):
|
class MultiTableChildQueryset(QuerySet):
|
||||||
|
|
||||||
def bulk_create(self, objs, batch_size=None):
|
def bulk_create(self, objs, batch_size=None):
|
||||||
|
|
|
@ -15,6 +15,8 @@ class AdHocViewSet(OrgBulkModelViewSet):
|
||||||
permission_classes = ()
|
permission_classes = ()
|
||||||
model = AdHoc
|
model = AdHoc
|
||||||
|
|
||||||
|
def allow_bulk_destroy(self, qs, filtered):
|
||||||
|
return True
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
return queryset.filter(creator=self.request.user)
|
return queryset.filter(creator=self.request.user)
|
||||||
|
|
|
@ -23,6 +23,9 @@ class JobViewSet(OrgBulkModelViewSet):
|
||||||
permission_classes = ()
|
permission_classes = ()
|
||||||
model = Job
|
model = Job
|
||||||
|
|
||||||
|
def allow_bulk_destroy(self, qs, filtered):
|
||||||
|
return True
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
queryset = queryset.filter(creator=self.request.user)
|
queryset = queryset.filter(creator=self.request.user)
|
||||||
|
@ -31,20 +34,21 @@ class JobViewSet(OrgBulkModelViewSet):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
|
run_after_save = serializer.validated_data.pop('run_after_save', False)
|
||||||
instance = serializer.save()
|
instance = serializer.save()
|
||||||
run_after_save = serializer.validated_data.get('run_after_save', False)
|
|
||||||
if instance.instant or run_after_save:
|
if instance.instant or run_after_save:
|
||||||
self.run_job(instance, serializer)
|
self.run_job(instance, serializer)
|
||||||
|
|
||||||
def perform_update(self, serializer):
|
def perform_update(self, serializer):
|
||||||
|
run_after_save = serializer.validated_data.pop('run_after_save', False)
|
||||||
instance = serializer.save()
|
instance = serializer.save()
|
||||||
run_after_save = serializer.validated_data.get('run_after_save', False)
|
|
||||||
if run_after_save:
|
if run_after_save:
|
||||||
self.run_job(instance, serializer)
|
self.run_job(instance, serializer)
|
||||||
|
|
||||||
@staticmethod
|
def run_job(self, job, serializer):
|
||||||
def run_job(job, serializer):
|
|
||||||
execution = job.create_execution()
|
execution = job.create_execution()
|
||||||
|
execution.creator = self.request.user
|
||||||
|
execution.save()
|
||||||
task = run_ops_job_execution.delay(execution.id)
|
task = run_ops_job_execution.delay(execution.id)
|
||||||
set_task_to_serializer_data(serializer, task)
|
set_task_to_serializer_data(serializer, task)
|
||||||
|
|
||||||
|
@ -58,6 +62,7 @@ class JobExecutionViewSet(OrgBulkModelViewSet):
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
instance = serializer.save()
|
instance = serializer.save()
|
||||||
instance.job_version = instance.job.version
|
instance.job_version = instance.job.version
|
||||||
|
instance.creator = self.request.user
|
||||||
instance.save()
|
instance.save()
|
||||||
task = run_ops_job_execution.delay(instance.id)
|
task = run_ops_job_execution.delay(instance.id)
|
||||||
set_task_to_serializer_data(serializer, task)
|
set_task_to_serializer_data(serializer, task)
|
||||||
|
|
|
@ -21,6 +21,9 @@ class PlaybookViewSet(OrgBulkModelViewSet):
|
||||||
permission_classes = ()
|
permission_classes = ()
|
||||||
model = Playbook
|
model = Playbook
|
||||||
|
|
||||||
|
def allow_bulk_destroy(self, qs, filtered):
|
||||||
|
return True
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
queryset = queryset.filter(creator=self.request.user)
|
queryset = queryset.filter(creator=self.request.user)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-12-21 07:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ops', '0031_auto_20221220_1956'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='historicaljob',
|
||||||
|
name='created_by',
|
||||||
|
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='historicaljob',
|
||||||
|
name='updated_by',
|
||||||
|
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -163,9 +163,9 @@ class JobExecution(JMSOrgBaseModel):
|
||||||
def compile_shell(self):
|
def compile_shell(self):
|
||||||
if self.current_job.type != 'adhoc':
|
if self.current_job.type != 'adhoc':
|
||||||
return
|
return
|
||||||
result = "{}{}{} ".format('\'', self.current_job.args, '\'')
|
result = self.current_job.args
|
||||||
result += " chdir={}".format(self.current_job.chdir)
|
result += " chdir={}".format(self.current_job.chdir)
|
||||||
return result
|
return self.job.args
|
||||||
|
|
||||||
def get_runner(self):
|
def get_runner(self):
|
||||||
inv = self.current_job.inventory
|
inv = self.current_job.inventory
|
||||||
|
|
|
@ -9,12 +9,11 @@ from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
|
|
||||||
class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin):
|
class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin):
|
||||||
creator = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
creator = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
||||||
run_after_save = serializers.BooleanField(label=_("Run after save"), read_only=True, default=False, required=False)
|
run_after_save = serializers.BooleanField(label=_("Run after save"), default=False, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Job
|
model = Job
|
||||||
read_only_fields = ["id", "date_last_run", "date_created", "date_updated", "average_time_cost",
|
read_only_fields = ["id", "date_last_run", "date_created", "date_updated", "average_time_cost"]
|
||||||
"run_after_save"]
|
|
||||||
fields = read_only_fields + [
|
fields = read_only_fields + [
|
||||||
"name", "instant", "type", "module", "args", "playbook", "assets", "runas_policy", "runas", "creator",
|
"name", "instant", "type", "module", "args", "playbook", "assets", "runas_policy", "runas", "creator",
|
||||||
"use_parameter_define",
|
"use_parameter_define",
|
||||||
|
@ -23,7 +22,7 @@ class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin):
|
||||||
"chdir",
|
"chdir",
|
||||||
"comment",
|
"comment",
|
||||||
"summary",
|
"summary",
|
||||||
"is_periodic", "interval", "crontab"
|
"is_periodic", "interval", "crontab", "run_after_save"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
from perms import serializers
|
from perms import serializers
|
||||||
from perms import models
|
from perms import models
|
||||||
from perms.utils.user_permission import UserGrantedAssetsQueryUtils
|
from perms.utils import AssetPermissionPermAssetUtil
|
||||||
from assets.serializers import AccountSerializer
|
from assets.serializers import AccountSerializer
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -95,8 +95,7 @@ class AssetPermissionAllAssetListApi(generics.ListAPIView):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
pk = self.kwargs.get("pk")
|
pk = self.kwargs.get("pk")
|
||||||
query_utils = UserGrantedAssetsQueryUtils(None, asset_perm_ids=[pk])
|
assets = AssetPermissionPermAssetUtil(perm_ids=[pk]).get_all_assets()
|
||||||
assets = query_utils.get_all_granted_assets()
|
|
||||||
return assets
|
return assets
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from assets.api.asset.asset import AssetFilterSet
|
||||||
from perms import serializers
|
from perms import serializers
|
||||||
from perms.pagination import AllPermedAssetPagination
|
from perms.pagination import AllPermedAssetPagination
|
||||||
from perms.pagination import NodePermedAssetPagination
|
from perms.pagination import NodePermedAssetPagination
|
||||||
from perms.utils.user_permission import UserGrantedAssetsQueryUtils
|
from perms.utils import UserPermAssetUtil
|
||||||
from common.utils import get_logger, lazyproperty
|
from common.utils import get_logger, lazyproperty
|
||||||
|
|
||||||
from .mixin import (
|
from .mixin import (
|
||||||
|
@ -43,21 +43,23 @@ class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView):
|
||||||
def get_assets(self):
|
def get_assets(self):
|
||||||
return Asset.objects.none()
|
return Asset.objects.none()
|
||||||
|
|
||||||
|
query_asset_util: UserPermAssetUtil
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def query_asset_util(self):
|
def query_asset_util(self):
|
||||||
return UserGrantedAssetsQueryUtils(self.user)
|
return UserPermAssetUtil(self.user)
|
||||||
|
|
||||||
|
|
||||||
class UserAllPermedAssetsApi(BaseUserPermedAssetsApi):
|
class UserAllPermedAssetsApi(BaseUserPermedAssetsApi):
|
||||||
pagination_class = AllPermedAssetPagination
|
pagination_class = AllPermedAssetPagination
|
||||||
|
|
||||||
def get_assets(self):
|
def get_assets(self):
|
||||||
return self.query_asset_util.get_all_granted_assets()
|
return self.query_asset_util.get_all_assets()
|
||||||
|
|
||||||
|
|
||||||
class UserDirectPermedAssetsApi(BaseUserPermedAssetsApi):
|
class UserDirectPermedAssetsApi(BaseUserPermedAssetsApi):
|
||||||
def get_assets(self):
|
def get_assets(self):
|
||||||
return self.query_asset_util.get_direct_granted_assets()
|
return self.query_asset_util.get_direct_assets()
|
||||||
|
|
||||||
|
|
||||||
class UserFavoriteAssetsApi(BaseUserPermedAssetsApi):
|
class UserFavoriteAssetsApi(BaseUserPermedAssetsApi):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from rest_framework.generics import ListAPIView
|
||||||
from assets.models import Node
|
from assets.models import Node
|
||||||
from common.utils import get_logger, lazyproperty
|
from common.utils import get_logger, lazyproperty
|
||||||
from perms import serializers
|
from perms import serializers
|
||||||
from perms.utils.user_permission import UserGrantedNodesQueryUtils
|
from perms.utils import UserPermNodeUtil
|
||||||
from .mixin import SelfOrPKUserMixin
|
from .mixin import SelfOrPKUserMixin
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
@ -32,7 +32,7 @@ class BaseUserPermedNodesApi(SelfOrPKUserMixin, ListAPIView):
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def query_node_util(self):
|
def query_node_util(self):
|
||||||
return UserGrantedNodesQueryUtils(self.user)
|
return UserPermNodeUtil(self.user)
|
||||||
|
|
||||||
|
|
||||||
class UserAllPermedNodesApi(BaseUserPermedNodesApi):
|
class UserAllPermedNodesApi(BaseUserPermedNodesApi):
|
||||||
|
|
|
@ -3,23 +3,22 @@ from urllib.parse import parse_qsl
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import F, Value, CharField
|
from django.db.models import F, Value, CharField
|
||||||
from rest_framework.generics import ListAPIView
|
|
||||||
from rest_framework.generics import get_object_or_404
|
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.generics import ListAPIView
|
||||||
|
from rest_framework.generics import get_object_or_404
|
||||||
|
from rest_framework.exceptions import PermissionDenied, NotFound
|
||||||
|
|
||||||
from assets.api import SerializeToTreeNodeMixin
|
|
||||||
from assets.models import Asset, Account
|
|
||||||
from assets.utils import KubernetesTree
|
from assets.utils import KubernetesTree
|
||||||
|
from assets.models import Asset, Account
|
||||||
|
from assets.api import SerializeToTreeNodeMixin
|
||||||
|
from authentication.models import ConnectionToken
|
||||||
from common.utils import get_object_or_none, lazyproperty
|
from common.utils import get_object_or_none, lazyproperty
|
||||||
from common.utils.common import timeit
|
from common.utils.common import timeit
|
||||||
from perms.hands import Node
|
from perms.hands import Node
|
||||||
from perms.models import PermNode
|
from perms.models import PermNode
|
||||||
from perms.utils import PermAccountUtil
|
from perms.utils import PermAccountUtil, UserPermNodeUtil, AssetPermissionUtil
|
||||||
from perms.utils.permission import AssetPermissionUtil
|
from perms.utils import UserPermAssetUtil
|
||||||
from perms.utils.user_permission import (
|
|
||||||
UserGrantedNodesQueryUtils, UserGrantedAssetsQueryUtils,
|
|
||||||
)
|
|
||||||
from .mixin import RebuildTreeMixin
|
from .mixin import RebuildTreeMixin
|
||||||
from ..mixin import SelfOrPKUserMixin
|
from ..mixin import SelfOrPKUserMixin
|
||||||
|
|
||||||
|
@ -52,13 +51,12 @@ class BaseUserNodeWithAssetAsTreeApi(
|
||||||
|
|
||||||
|
|
||||||
class UserPermedNodesWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
|
class UserPermedNodesWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
|
||||||
query_node_util: UserGrantedNodesQueryUtils
|
query_node_util: UserPermNodeUtil
|
||||||
query_asset_util: UserGrantedAssetsQueryUtils
|
query_asset_util: UserPermAssetUtil
|
||||||
|
|
||||||
def get_nodes_assets(self):
|
def get_nodes_assets(self):
|
||||||
perm_ids = AssetPermissionUtil().get_permissions_for_user(self.request.user, flat=True)
|
self.query_node_util = UserPermNodeUtil(self.request.user)
|
||||||
self.query_node_util = UserGrantedNodesQueryUtils(self.request.user, perm_ids)
|
self.query_asset_util = UserPermAssetUtil(self.request.user)
|
||||||
self.query_asset_util = UserGrantedAssetsQueryUtils(self.request.user, perm_ids)
|
|
||||||
ung_nodes, ung_assets = self._get_nodes_assets_for_ungrouped()
|
ung_nodes, ung_assets = self._get_nodes_assets_for_ungrouped()
|
||||||
fav_nodes, fav_assets = self._get_nodes_assets_for_favorite()
|
fav_nodes, fav_assets = self._get_nodes_assets_for_favorite()
|
||||||
all_nodes, all_assets = self._get_nodes_assets_for_all()
|
all_nodes, all_assets = self._get_nodes_assets_for_all()
|
||||||
|
@ -87,9 +85,9 @@ class UserPermedNodesWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
|
||||||
def _get_nodes_assets_for_all(self):
|
def _get_nodes_assets_for_all(self):
|
||||||
nodes = self.query_node_util.get_whole_tree_nodes(with_special=False)
|
nodes = self.query_node_util.get_whole_tree_nodes(with_special=False)
|
||||||
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
|
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
|
||||||
assets = self.query_asset_util.get_direct_granted_nodes_assets()
|
assets = self.query_asset_util.get_perm_nodes_assets()
|
||||||
else:
|
else:
|
||||||
assets = self.query_asset_util.get_all_granted_assets()
|
assets = self.query_asset_util.get_all_assets()
|
||||||
assets = assets.annotate(parent_key=F('nodes__key')).prefetch_related('platform')
|
assets = assets.annotate(parent_key=F('nodes__key')).prefetch_related('platform')
|
||||||
return nodes, assets
|
return nodes, assets
|
||||||
|
|
||||||
|
@ -98,20 +96,21 @@ class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
|
||||||
""" 用户授权的节点的子节点与资产树 """
|
""" 用户授权的节点的子节点与资产树 """
|
||||||
|
|
||||||
def get_nodes_assets(self):
|
def get_nodes_assets(self):
|
||||||
nodes = PermNode.objects.none()
|
query_node_util = UserPermNodeUtil(self.user)
|
||||||
assets = Asset.objects.none()
|
query_asset_util = UserPermAssetUtil(self.user)
|
||||||
query_node_util = UserGrantedNodesQueryUtils(self.user)
|
|
||||||
query_asset_util = UserGrantedAssetsQueryUtils(self.user)
|
|
||||||
node_key = self.query_node_key
|
node_key = self.query_node_key
|
||||||
if not node_key:
|
if not node_key:
|
||||||
nodes = query_node_util.get_top_level_nodes()
|
nodes = query_node_util.get_top_level_nodes()
|
||||||
|
assets = Asset.objects.none()
|
||||||
elif node_key == PermNode.UNGROUPED_NODE_KEY:
|
elif node_key == PermNode.UNGROUPED_NODE_KEY:
|
||||||
|
nodes = PermNode.objects.none()
|
||||||
assets = query_asset_util.get_ungroup_assets()
|
assets = query_asset_util.get_ungroup_assets()
|
||||||
elif node_key == PermNode.FAVORITE_NODE_KEY:
|
elif node_key == PermNode.FAVORITE_NODE_KEY:
|
||||||
|
nodes = PermNode.objects.none()
|
||||||
assets = query_asset_util.get_favorite_assets()
|
assets = query_asset_util.get_favorite_assets()
|
||||||
else:
|
else:
|
||||||
nodes = query_node_util.get_node_children(node_key)
|
nodes = query_node_util.get_node_children(node_key)
|
||||||
assets = query_asset_util.get_node_assets(node_key)
|
assets = query_asset_util.get_node_assets(key=node_key)
|
||||||
assets = assets.prefetch_related('platform')
|
assets = assets.prefetch_related('platform')
|
||||||
return nodes, assets
|
return nodes, assets
|
||||||
|
|
||||||
|
@ -133,41 +132,48 @@ class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
|
||||||
class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView):
|
class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView):
|
||||||
""" 用户授权的K8s树 """
|
""" 用户授权的K8s树 """
|
||||||
|
|
||||||
@staticmethod
|
def get_token(self):
|
||||||
def asset(asset_id):
|
token_id = self.request.query_params.get('token')
|
||||||
kwargs = {'id': asset_id, 'is_active': True}
|
token = get_object_or_404(ConnectionToken, pk=token_id)
|
||||||
asset = get_object_or_404(Asset, **kwargs)
|
if token.is_expired:
|
||||||
return asset
|
raise PermissionDenied('Token is expired')
|
||||||
|
token.renewal()
|
||||||
|
return token
|
||||||
|
|
||||||
def get_accounts(self, asset):
|
def get_account_secret(self, token: ConnectionToken):
|
||||||
util = PermAccountUtil()
|
util = PermAccountUtil()
|
||||||
accounts = util.get_permed_accounts_for_user(self.user, asset)
|
accounts = util.get_permed_accounts_for_user(self.user, token.asset)
|
||||||
ignore_username = [Account.AliasAccount.INPUT, Account.AliasAccount.USER]
|
account_username = token.account
|
||||||
accounts = filter(lambda x: x.username not in ignore_username, accounts)
|
accounts = filter(lambda x: x.username == account_username, accounts)
|
||||||
accounts = list(accounts)
|
accounts = list(accounts)
|
||||||
return accounts
|
if not accounts:
|
||||||
|
raise NotFound('Account is not found')
|
||||||
|
account = accounts[0]
|
||||||
|
if account.username in [
|
||||||
|
Account.AliasAccount.INPUT, Account.AliasAccount.USER
|
||||||
|
]:
|
||||||
|
return token.input_secret
|
||||||
|
else:
|
||||||
|
return account.secret
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_namespace_and_pod(key):
|
||||||
|
namespace_and_pod = dict(parse_qsl(key))
|
||||||
|
pod = namespace_and_pod.get('pod')
|
||||||
|
namespace = namespace_and_pod.get('namespace')
|
||||||
|
return namespace, pod
|
||||||
|
|
||||||
def list(self, request: Request, *args, **kwargs):
|
def list(self, request: Request, *args, **kwargs):
|
||||||
tree_id = request.query_params.get('tree_id')
|
token = self.get_token()
|
||||||
key = request.query_params.get('key', {})
|
asset = token.asset
|
||||||
|
secret = self.get_account_secret(token)
|
||||||
|
key = self.request.query_params.get('key')
|
||||||
|
namespace, pod = self.get_namespace_and_pod(key)
|
||||||
|
|
||||||
tree = []
|
tree = []
|
||||||
parent_info = dict(parse_qsl(key))
|
k8s_tree_instance = KubernetesTree(asset, secret)
|
||||||
account_username = parent_info.get('account')
|
if not any([namespace, pod]) and not key:
|
||||||
|
asset_node = k8s_tree_instance.as_asset_tree_node()
|
||||||
asset_id = parent_info.get('asset_id')
|
|
||||||
asset_id = tree_id if not asset_id else asset_id
|
|
||||||
|
|
||||||
if tree_id and not key and not account_username:
|
|
||||||
asset = self.asset(asset_id)
|
|
||||||
accounts = self.get_accounts(asset)
|
|
||||||
asset_node = KubernetesTree(tree_id).as_asset_tree_node(asset)
|
|
||||||
tree.append(asset_node)
|
tree.append(asset_node)
|
||||||
for account in accounts:
|
tree.extend(k8s_tree_instance.async_tree_node(namespace, pod))
|
||||||
account_node = KubernetesTree(tree_id).as_account_tree_node(
|
|
||||||
account, parent_info,
|
|
||||||
)
|
|
||||||
tree.append(account_node)
|
|
||||||
elif key and account_username:
|
|
||||||
tree = KubernetesTree(key).async_tree_node(parent_info)
|
|
||||||
return Response(data=tree)
|
return Response(data=tree)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
from django.db.models import QuerySet, Q
|
from django.db.models import QuerySet, Q
|
||||||
|
|
||||||
from common.db.models import UnionQuerySet
|
|
||||||
from common.drf.filters import BaseFilterSet
|
from common.drf.filters import BaseFilterSet
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from users.models import User, UserGroup
|
from users.models import User, UserGroup
|
||||||
|
@ -169,10 +168,10 @@ class AssetPermissionFilter(PermissionBaseFilter):
|
||||||
inherit_all_node_ids = Node.objects.filter(key__in=inherit_all_node_keys).values_list('id', flat=True)
|
inherit_all_node_ids = Node.objects.filter(key__in=inherit_all_node_keys).values_list('id', flat=True)
|
||||||
inherit_all_node_ids = list(inherit_all_node_ids)
|
inherit_all_node_ids = list(inherit_all_node_ids)
|
||||||
|
|
||||||
qs1 = queryset.filter(assets__in=asset_ids).distinct()
|
qs1_ids = queryset.filter(assets__in=asset_ids).distinct().values_list('id', flat=True)
|
||||||
qs2 = queryset.filter(nodes__in=inherit_all_node_ids).distinct()
|
qs2_ids = queryset.filter(nodes__in=inherit_all_node_ids).distinct().values_list('id', flat=True)
|
||||||
|
qs_ids = list(qs1_ids) + list(qs2_ids)
|
||||||
qs = UnionQuerySet(qs1, qs2)
|
qs = queryset.filter(id__in=qs_ids)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def filter_effective(self, queryset):
|
def filter_effective(self, queryset):
|
||||||
|
|
|
@ -41,11 +41,6 @@ class Migration(migrations.Migration):
|
||||||
name='created_by',
|
name='created_by',
|
||||||
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
|
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
|
||||||
model_name='userassetgrantedtreenoderelation',
|
|
||||||
name='id',
|
|
||||||
field=models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='userassetgrantedtreenoderelation',
|
model_name='userassetgrantedtreenoderelation',
|
||||||
name='updated_by',
|
name='updated_by',
|
||||||
|
|
|
@ -5,14 +5,14 @@ from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from users.models import User
|
||||||
from assets.models import Asset, Account
|
from assets.models import Asset, Account
|
||||||
from common.db.models import UnionQuerySet
|
|
||||||
from common.utils import date_expired_default
|
|
||||||
from common.utils.timezone import local_now
|
|
||||||
from orgs.mixins.models import JMSOrgBaseModel
|
from orgs.mixins.models import JMSOrgBaseModel
|
||||||
from orgs.mixins.models import OrgManager
|
from orgs.mixins.models import OrgManager
|
||||||
|
from common.utils import date_expired_default
|
||||||
|
from common.utils.timezone import local_now
|
||||||
|
|
||||||
from perms.const import ActionChoices
|
from perms.const import ActionChoices
|
||||||
from users.models import User
|
|
||||||
|
|
||||||
__all__ = ['AssetPermission', 'ActionChoices']
|
__all__ = ['AssetPermission', 'ActionChoices']
|
||||||
|
|
||||||
|
@ -104,9 +104,10 @@ class AssetPermission(JMSOrgBaseModel):
|
||||||
group_ids = self.user_groups.all().values_list('id', flat=True)
|
group_ids = self.user_groups.all().values_list('id', flat=True)
|
||||||
user_ids = list(user_ids)
|
user_ids = list(user_ids)
|
||||||
group_ids = list(group_ids)
|
group_ids = list(group_ids)
|
||||||
qs1 = User.objects.filter(id__in=user_ids).distinct()
|
qs1_ids = User.objects.filter(id__in=user_ids).distinct().values_list('id', flat=True)
|
||||||
qs2 = User.objects.filter(groups__id__in=group_ids).distinct()
|
qs2_ids = User.objects.filter(groups__id__in=group_ids).distinct().values_list('id', flat=True)
|
||||||
qs = UnionQuerySet(qs1, qs2)
|
qs_ids = list(qs1_ids) + list(qs2_ids)
|
||||||
|
qs = User.objects.filter(id__in=qs_ids)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def get_all_assets(self, flat=False):
|
def get_all_assets(self, flat=False):
|
||||||
|
|
|
@ -16,12 +16,18 @@ class NodeFrom(TextChoices):
|
||||||
class UserAssetGrantedTreeNodeRelation(FamilyMixin, JMSOrgBaseModel):
|
class UserAssetGrantedTreeNodeRelation(FamilyMixin, JMSOrgBaseModel):
|
||||||
NodeFrom = NodeFrom
|
NodeFrom = NodeFrom
|
||||||
|
|
||||||
|
id = models.AutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name=_('ID')
|
||||||
|
)
|
||||||
user = models.ForeignKey('users.User', db_constraint=False, on_delete=models.CASCADE)
|
user = models.ForeignKey('users.User', db_constraint=False, on_delete=models.CASCADE)
|
||||||
node = models.ForeignKey('assets.Node', default=None, on_delete=models.CASCADE,
|
node = models.ForeignKey(
|
||||||
db_constraint=False, null=False, related_name='granted_node_rels')
|
'assets.Node', default=None, on_delete=models.CASCADE, db_constraint=False, null=False,
|
||||||
|
related_name='granted_node_rels'
|
||||||
|
)
|
||||||
node_key = models.CharField(max_length=64, verbose_name=_("Key"), db_index=True)
|
node_key = models.CharField(max_length=64, verbose_name=_("Key"), db_index=True)
|
||||||
node_parent_key = models.CharField(max_length=64, default='', verbose_name=_('Parent key'),
|
node_parent_key = models.CharField(
|
||||||
db_index=True)
|
max_length=64, default='', verbose_name=_('Parent key'), db_index=True
|
||||||
|
)
|
||||||
node_from = models.CharField(choices=NodeFrom.choices, max_length=16, db_index=True)
|
node_from = models.CharField(choices=NodeFrom.choices, max_length=16, db_index=True)
|
||||||
node_assets_amount = models.IntegerField(default=0)
|
node_assets_amount = models.IntegerField(default=0)
|
||||||
comment = ''
|
comment = ''
|
||||||
|
@ -35,15 +41,14 @@ class UserAssetGrantedTreeNodeRelation(FamilyMixin, JMSOrgBaseModel):
|
||||||
return self.node_parent_key
|
return self.node_parent_key
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_node_granted_status(cls, user, key):
|
def get_node_from_with_node(cls, user, key):
|
||||||
ancestor_keys = set(cls.get_node_ancestor_keys(key, with_self=True))
|
ancestor_keys = set(cls.get_node_ancestor_keys(key, with_self=True))
|
||||||
ancestor_rel_nodes = cls.objects.filter(user=user, node_key__in=ancestor_keys)
|
ancestor_nodes = cls.objects.filter(user=user, node_key__in=ancestor_keys)
|
||||||
|
for node in ancestor_nodes:
|
||||||
for rel_node in ancestor_rel_nodes:
|
if node.key == key:
|
||||||
if rel_node.key == key:
|
return node.node_from, node
|
||||||
return rel_node.node_from, rel_node
|
if node.node_from == cls.NodeFrom.granted:
|
||||||
if rel_node.node_from == cls.NodeFrom.granted:
|
return node.node_from, None
|
||||||
return cls.NodeFrom.granted, None
|
|
||||||
return '', None
|
return '', None
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,6 +73,9 @@ class PermNode(Node):
|
||||||
'node_from': F('granted_node_rels__node_from')
|
'node_from': F('granted_node_rels__node_from')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.name}'
|
||||||
|
|
||||||
def use_granted_assets_amount(self):
|
def use_granted_assets_amount(self):
|
||||||
self.assets_amount = self.granted_assets_amount
|
self.assets_amount = self.granted_assets_amount
|
||||||
|
|
||||||
|
@ -90,15 +98,16 @@ class PermNode(Node):
|
||||||
node.assets_amount = assets_amount
|
node.assets_amount = assets_amount
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def get_granted_status(self, user):
|
def compute_node_from_and_assets_amount(self, user):
|
||||||
status, rel_node = UserAssetGrantedTreeNodeRelation.get_node_granted_status(user, self.key)
|
node_from, node = UserAssetGrantedTreeNodeRelation.get_node_from_with_node(
|
||||||
self.node_from = status
|
user, self.key
|
||||||
if rel_node:
|
)
|
||||||
self.granted_assets_amount = rel_node.node_assets_amount
|
self.node_from = node_from
|
||||||
return status
|
if node:
|
||||||
|
self.granted_assets_amount = node.node_assets_amount
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
# 这是个只读 Model
|
""" 这是个只读 Model """
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from .permission import *
|
from .permission import *
|
||||||
from .user_permission import *
|
|
||||||
from .account import *
|
from .account import *
|
||||||
from .user_perm_tree import *
|
from .user_perm_tree import *
|
||||||
|
from .user_perm import *
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
from assets.models import FavoriteAsset, Asset
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from common.utils.common import timeit
|
||||||
|
|
||||||
|
from perms.models import AssetPermission, PermNode, UserAssetGrantedTreeNodeRelation
|
||||||
|
|
||||||
|
from .permission import AssetPermissionUtil
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['AssetPermissionPermAssetUtil', 'UserPermAssetUtil', 'UserPermNodeUtil']
|
||||||
|
|
||||||
|
|
||||||
|
class AssetPermissionPermAssetUtil:
|
||||||
|
|
||||||
|
def __init__(self, perm_ids):
|
||||||
|
self.perm_ids = perm_ids
|
||||||
|
|
||||||
|
def get_all_assets(self):
|
||||||
|
""" 获取所有授权的资产 """
|
||||||
|
node_asset_ids = self.get_perm_nodes_assets(flat=True)
|
||||||
|
direct_asset_ids = self.get_direct_assets(flat=True)
|
||||||
|
asset_ids = list(node_asset_ids) + list(direct_asset_ids)
|
||||||
|
assets = Asset.objects.filter(id__in=asset_ids)
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def get_perm_nodes_assets(self, flat=False):
|
||||||
|
""" 获取所有授权节点下的资产 """
|
||||||
|
node_ids = AssetPermission.nodes.through.objects \
|
||||||
|
.filter(assetpermission_id__in=self.perm_ids) \
|
||||||
|
.values_list('node_id', flat=True) \
|
||||||
|
.distinct()
|
||||||
|
node_ids = list(node_ids)
|
||||||
|
nodes = PermNode.objects.filter(id__in=node_ids).only('id', 'key')
|
||||||
|
assets = PermNode.get_nodes_all_assets(*nodes)
|
||||||
|
if flat:
|
||||||
|
return assets.values_list('id', flat=True)
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def get_direct_assets(self, flat=False):
|
||||||
|
""" 获取直接授权的资产 """
|
||||||
|
assets = Asset.objects.order_by() \
|
||||||
|
.filter(granted_by_permissions__id__in=self.perm_ids) \
|
||||||
|
.distinct()
|
||||||
|
if flat:
|
||||||
|
return assets.values_list('id', flat=True)
|
||||||
|
return assets
|
||||||
|
|
||||||
|
|
||||||
|
class UserPermAssetUtil(AssetPermissionPermAssetUtil):
|
||||||
|
|
||||||
|
def __init__(self, user):
|
||||||
|
self.user = user
|
||||||
|
perm_ids = AssetPermissionUtil().get_permissions_for_user(self.user, flat=True)
|
||||||
|
super().__init__(perm_ids)
|
||||||
|
|
||||||
|
def get_ungroup_assets(self):
|
||||||
|
return self.get_direct_assets()
|
||||||
|
|
||||||
|
def get_favorite_assets(self):
|
||||||
|
assets = self.get_all_assets()
|
||||||
|
asset_ids = FavoriteAsset.objects.filter(user=self.user).values_list('asset_id', flat=True)
|
||||||
|
assets = assets.filter(id__in=list(asset_ids))
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def get_node_assets(self, key):
|
||||||
|
node = PermNode.objects.get(key=key)
|
||||||
|
node.compute_node_from_and_assets_amount(self.user)
|
||||||
|
if node.node_from == node.NodeFrom.granted:
|
||||||
|
assets = Asset.objects.filter(nodes__id=node.id).order_by()
|
||||||
|
elif node.node_from == node.NodeFrom.asset:
|
||||||
|
assets = self._get_indirect_perm_node_assets(node)
|
||||||
|
else:
|
||||||
|
assets = Asset.objects.none()
|
||||||
|
assets = assets.order_by('name')
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def get_node_all_assets(self, node_id):
|
||||||
|
""" 获取节点下的所有资产 """
|
||||||
|
node = PermNode.objects.get(id=node_id)
|
||||||
|
node.compute_node_from_and_assets_amount(self.user)
|
||||||
|
if node.node_from == node.NodeFrom.granted:
|
||||||
|
assets = PermNode.get_nodes_all_assets()
|
||||||
|
elif node.node_from in (node.NodeFrom.asset, node.NodeFrom.child):
|
||||||
|
node.assets_amount = node.granted_assets_amount
|
||||||
|
assets = self._get_indirect_perm_node_all_assets(node)
|
||||||
|
else:
|
||||||
|
node.assets_amount = 0
|
||||||
|
assets = Asset.objects.none()
|
||||||
|
return node, assets
|
||||||
|
|
||||||
|
def _get_indirect_perm_node_assets(self, node):
|
||||||
|
""" 获取间接授权节点下的直接资产 """
|
||||||
|
assets = self.get_direct_assets()
|
||||||
|
assets = assets.filter(nodes__id=node.id).order_by().distinct()
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def _get_indirect_perm_node_all_assets(self, node):
|
||||||
|
""" 获取间接授权节点下的所有资产
|
||||||
|
此算法依据 `UserAssetGrantedTreeNodeRelation` 的数据查询
|
||||||
|
1. 查询该节点下的直接授权节点
|
||||||
|
2. 查询该节点下授权资产关联的节点
|
||||||
|
"""
|
||||||
|
# 查询节点下直接授权的子节点
|
||||||
|
asset_ids = set()
|
||||||
|
children_from_granted = UserAssetGrantedTreeNodeRelation.objects \
|
||||||
|
.filter(user=self.user) \
|
||||||
|
.filter(node_key__startwith=f'{node.key}:', node_from=node.NodeFrom.granted) \
|
||||||
|
.only('node_id', 'node_key')
|
||||||
|
for n in children_from_granted:
|
||||||
|
n.id = n.node_id
|
||||||
|
_assets = PermNode.get_nodes_all_assets(*children_from_granted)
|
||||||
|
_asset_ids = _assets.values_list('id', flat=True)
|
||||||
|
asset_ids.update(list(_asset_ids))
|
||||||
|
|
||||||
|
# 查询节点下资产授权的节点
|
||||||
|
children_from_assets = UserAssetGrantedTreeNodeRelation.objects \
|
||||||
|
.filter(user=self.user) \
|
||||||
|
.filter(node_key__startwith=f'{node.key}:', node_from=node.NodeFrom.asset) \
|
||||||
|
.values_list('node_id', flat=True)
|
||||||
|
children_from_assets = set(children_from_assets)
|
||||||
|
if node.node_from == node.NodeFrom.asset:
|
||||||
|
children_from_assets.add(node.id)
|
||||||
|
_asset_ids = Asset.objects \
|
||||||
|
.filter(node__id__in=children_from_assets) \
|
||||||
|
.filter(granted_by_permissions__id__in=self.perm_ids) \
|
||||||
|
.distinct() \
|
||||||
|
.order_by() \
|
||||||
|
.values_list('id', flat=True)
|
||||||
|
asset_ids.update(list(_asset_ids))
|
||||||
|
|
||||||
|
return Asset.objects.filter(id__in=asset_ids)
|
||||||
|
|
||||||
|
|
||||||
|
class UserPermNodeUtil:
|
||||||
|
|
||||||
|
def __init__(self, user):
|
||||||
|
self.user = user
|
||||||
|
self.perm_ids = AssetPermissionUtil().get_permissions_for_user(self.user, flat=True)
|
||||||
|
|
||||||
|
def get_favorite_node(self):
|
||||||
|
assets_amount = UserPermAssetUtil(self.user).get_favorite_assets().count()
|
||||||
|
return PermNode.get_favorite_node(assets_amount)
|
||||||
|
|
||||||
|
def get_ungrouped_node(self):
|
||||||
|
assets_amount = UserPermAssetUtil(self.user).get_direct_assets().count()
|
||||||
|
return PermNode.get_favorite_node(assets_amount)
|
||||||
|
|
||||||
|
def get_top_level_nodes(self):
|
||||||
|
nodes = self.get_special_nodes()
|
||||||
|
real_nodes = self._get_indirect_perm_node_children(key='')
|
||||||
|
nodes.extend(real_nodes)
|
||||||
|
if len(real_nodes) == 1:
|
||||||
|
children = self.get_node_children(real_nodes[0].key)
|
||||||
|
nodes.extend(children)
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
def get_special_nodes(self):
|
||||||
|
nodes = []
|
||||||
|
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
|
||||||
|
ung_node = self.get_ungrouped_node()
|
||||||
|
nodes.append(ung_node)
|
||||||
|
fav_node = self.get_favorite_node()
|
||||||
|
nodes.append(fav_node)
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
def get_node_children(self, key):
|
||||||
|
if not key:
|
||||||
|
return self.get_top_level_nodes()
|
||||||
|
|
||||||
|
if key in [PermNode.FAVORITE_NODE_KEY, PermNode.UNGROUPED_NODE_KEY]:
|
||||||
|
return PermNode.objects.none()
|
||||||
|
|
||||||
|
node = PermNode.objects.get(key=key)
|
||||||
|
node.compute_node_from_and_assets_amount(self.user)
|
||||||
|
if node.node_from == node.NodeFrom.granted:
|
||||||
|
children = PermNode.objects.filter(parent_key=key)
|
||||||
|
elif node.node_from in (node.NodeFrom.asset, node.NodeFrom.child):
|
||||||
|
children = self._get_indirect_perm_node_children(key)
|
||||||
|
else:
|
||||||
|
children = PermNode.objects.none()
|
||||||
|
children = sorted(children, key=lambda x: x.value)
|
||||||
|
return children
|
||||||
|
|
||||||
|
def _get_indirect_perm_node_children(self, key):
|
||||||
|
""" 获取未直接授权节点的子节点 """
|
||||||
|
children = PermNode.objects.filter(granted_node_rels__user=self.user, parent_key=key)
|
||||||
|
children = children.annotate(**PermNode.annotate_granted_node_rel_fields).distinct()
|
||||||
|
for node in children:
|
||||||
|
node.assets_amount = node.granted_assets_amount
|
||||||
|
return children
|
||||||
|
|
||||||
|
@timeit
|
||||||
|
def get_whole_tree_nodes(self, with_special=True):
|
||||||
|
user_nodes = PermNode.objects.filter(granted_node_rels__user=self.user)
|
||||||
|
user_nodes = user_nodes.annotate(**PermNode.annotate_granted_node_rel_fields).distinct()
|
||||||
|
|
||||||
|
key_node_mapper = {}
|
||||||
|
q_nodes_descendant = Q()
|
||||||
|
for node in user_nodes:
|
||||||
|
node.assets_amount = node.granted_assets_amount
|
||||||
|
key_node_mapper[node.key] = node
|
||||||
|
if node.node_from == node.NodeFrom.granted:
|
||||||
|
""" 直接授权的节点, 增加后代节点的过滤条件 """
|
||||||
|
q_nodes_descendant |= Q(key__startswith=f'{node.key}:')
|
||||||
|
if q_nodes_descendant:
|
||||||
|
descendant_nodes = PermNode.objects.filter(q_nodes_descendant)
|
||||||
|
for node in descendant_nodes:
|
||||||
|
key_node_mapper[node.key] = node
|
||||||
|
|
||||||
|
nodes = []
|
||||||
|
if with_special:
|
||||||
|
special_nodes = self.get_special_nodes()
|
||||||
|
nodes.extend(special_nodes)
|
||||||
|
nodes.extend(list(key_node_mapper.values()))
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
|
|
@ -1,280 +0,0 @@
|
||||||
from collections import defaultdict
|
|
||||||
from typing import List, Tuple
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db.models import Q, QuerySet
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
from users.models import User
|
|
||||||
from assets.utils import NodeAssetsUtil
|
|
||||||
from assets.models import (
|
|
||||||
Asset,
|
|
||||||
FavoriteAsset,
|
|
||||||
AssetQuerySet,
|
|
||||||
NodeQuerySet
|
|
||||||
)
|
|
||||||
from orgs.utils import (
|
|
||||||
tmp_to_org,
|
|
||||||
current_org,
|
|
||||||
ensure_in_real_or_default_org,
|
|
||||||
)
|
|
||||||
from common.db.models import output_as_string, UnionQuerySet
|
|
||||||
from common.utils import get_logger
|
|
||||||
from common.utils.common import lazyproperty, timeit
|
|
||||||
|
|
||||||
from perms.models import (
|
|
||||||
AssetPermission,
|
|
||||||
PermNode,
|
|
||||||
UserAssetGrantedTreeNodeRelation
|
|
||||||
)
|
|
||||||
from .permission import AssetPermissionUtil
|
|
||||||
|
|
||||||
NodeFrom = UserAssetGrantedTreeNodeRelation.NodeFrom
|
|
||||||
NODE_ONLY_FIELDS = ('id', 'key', 'parent_key', 'org_id')
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class UserGrantedUtilsBase:
|
|
||||||
user: User
|
|
||||||
|
|
||||||
def __init__(self, user, asset_perm_ids=None):
|
|
||||||
self.user = user
|
|
||||||
self._asset_perm_ids = asset_perm_ids and set(asset_perm_ids)
|
|
||||||
|
|
||||||
@lazyproperty
|
|
||||||
def asset_perm_ids(self) -> set:
|
|
||||||
if self._asset_perm_ids:
|
|
||||||
return self._asset_perm_ids
|
|
||||||
|
|
||||||
asset_perm_ids = AssetPermissionUtil().get_permissions_for_user(self.user, flat=True)
|
|
||||||
return asset_perm_ids
|
|
||||||
|
|
||||||
|
|
||||||
class UserGrantedAssetsQueryUtils(UserGrantedUtilsBase):
|
|
||||||
|
|
||||||
def get_favorite_assets(self) -> QuerySet:
|
|
||||||
assets = self.get_all_granted_assets()
|
|
||||||
asset_ids = FavoriteAsset.objects.filter(user=self.user).values_list('asset_id', flat=True)
|
|
||||||
assets = assets.filter(id__in=list(asset_ids))
|
|
||||||
return assets
|
|
||||||
|
|
||||||
def get_ungroup_assets(self) -> AssetQuerySet:
|
|
||||||
return self.get_direct_granted_assets()
|
|
||||||
|
|
||||||
def get_direct_granted_assets(self) -> AssetQuerySet:
|
|
||||||
queryset = Asset.objects.order_by().filter(
|
|
||||||
granted_by_permissions__id__in=self.asset_perm_ids
|
|
||||||
).distinct()
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def get_direct_granted_nodes_assets(self) -> AssetQuerySet:
|
|
||||||
granted_node_ids = AssetPermission.nodes.through.objects.filter(
|
|
||||||
assetpermission_id__in=self.asset_perm_ids
|
|
||||||
).values_list('node_id', flat=True).distinct()
|
|
||||||
granted_node_ids = list(granted_node_ids)
|
|
||||||
granted_nodes = PermNode.objects.filter(id__in=granted_node_ids).only('id', 'key')
|
|
||||||
queryset = PermNode.get_nodes_all_assets(*granted_nodes)
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def get_all_granted_assets(self) -> QuerySet:
|
|
||||||
nodes_assets = self.get_direct_granted_nodes_assets()
|
|
||||||
assets = self.get_direct_granted_assets()
|
|
||||||
# queryset = UnionQuerySet(nodes_assets, assets)
|
|
||||||
# return queryset
|
|
||||||
node_asset_ids = nodes_assets.values_list('id', flat=True)
|
|
||||||
direct_asset_ids = assets.values_list('id', flat=True)
|
|
||||||
asset_ids = list(node_asset_ids) + list(direct_asset_ids)
|
|
||||||
asset = Asset.objects.filter(id__in=asset_ids)
|
|
||||||
return asset
|
|
||||||
|
|
||||||
def get_node_all_assets(self, id) -> Tuple[PermNode, QuerySet]:
|
|
||||||
node = PermNode.objects.get(id=id)
|
|
||||||
granted_status = node.get_granted_status(self.user)
|
|
||||||
if granted_status == NodeFrom.granted:
|
|
||||||
assets = PermNode.get_nodes_all_assets(node)
|
|
||||||
return node, assets
|
|
||||||
elif granted_status in (NodeFrom.asset, NodeFrom.child):
|
|
||||||
node.use_granted_assets_amount()
|
|
||||||
assets = self._get_indirect_granted_node_all_assets(node)
|
|
||||||
return node, assets
|
|
||||||
else:
|
|
||||||
node.assets_amount = 0
|
|
||||||
return node, Asset.objects.none()
|
|
||||||
|
|
||||||
def get_node_assets(self, key) -> AssetQuerySet:
|
|
||||||
node = PermNode.objects.get(key=key)
|
|
||||||
granted_status = node.get_granted_status(self.user)
|
|
||||||
|
|
||||||
if granted_status == NodeFrom.granted:
|
|
||||||
assets = Asset.objects.order_by().filter(nodes__id=node.id)
|
|
||||||
elif granted_status == NodeFrom.asset:
|
|
||||||
assets = self._get_indirect_granted_node_assets(node.id)
|
|
||||||
else:
|
|
||||||
assets = Asset.objects.none()
|
|
||||||
assets = assets.order_by('name')
|
|
||||||
return assets
|
|
||||||
|
|
||||||
def _get_indirect_granted_node_assets(self, id) -> AssetQuerySet:
|
|
||||||
assets = Asset.objects.order_by().filter(nodes__id=id).distinct() & self.get_direct_granted_assets()
|
|
||||||
return assets
|
|
||||||
|
|
||||||
def _get_indirect_granted_node_all_assets(self, node) -> QuerySet:
|
|
||||||
"""
|
|
||||||
此算法依据 `UserAssetGrantedTreeNodeRelation` 的数据查询
|
|
||||||
1. 查询该节点下的直接授权节点
|
|
||||||
2. 查询该节点下授权资产关联的节点
|
|
||||||
"""
|
|
||||||
user = self.user
|
|
||||||
|
|
||||||
# 查询该节点下的授权节点
|
|
||||||
granted_nodes = UserAssetGrantedTreeNodeRelation.objects.filter(
|
|
||||||
user=user, node_from=NodeFrom.granted
|
|
||||||
).filter(
|
|
||||||
Q(node_key__startswith=f'{node.key}:')
|
|
||||||
).only('node_id', 'node_key')
|
|
||||||
|
|
||||||
for n in granted_nodes:
|
|
||||||
n.id = n.node_id
|
|
||||||
|
|
||||||
node_assets = PermNode.get_nodes_all_assets(*granted_nodes)
|
|
||||||
|
|
||||||
# 查询该节点下的资产授权节点
|
|
||||||
only_asset_granted_node_ids = UserAssetGrantedTreeNodeRelation.objects.filter(
|
|
||||||
user=user, node_from=NodeFrom.asset
|
|
||||||
).filter(
|
|
||||||
Q(node_key__startswith=f'{node.key}:')
|
|
||||||
).values_list('node_id', flat=True)
|
|
||||||
|
|
||||||
only_asset_granted_node_ids = list(only_asset_granted_node_ids)
|
|
||||||
if node.node_from == NodeFrom.asset:
|
|
||||||
only_asset_granted_node_ids.append(node.id)
|
|
||||||
|
|
||||||
assets = Asset.objects.filter(
|
|
||||||
nodes__id__in=only_asset_granted_node_ids,
|
|
||||||
granted_by_permissions__id__in=self.asset_perm_ids
|
|
||||||
).distinct().order_by()
|
|
||||||
granted_assets = UnionQuerySet(node_assets, assets)
|
|
||||||
return granted_assets
|
|
||||||
|
|
||||||
|
|
||||||
class UserGrantedNodesQueryUtils(UserGrantedUtilsBase):
|
|
||||||
def sort(self, nodes):
|
|
||||||
nodes = sorted(nodes, key=lambda x: x.value)
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
def get_node_children(self, key):
|
|
||||||
if not key:
|
|
||||||
return self.get_top_level_nodes()
|
|
||||||
|
|
||||||
nodes = PermNode.objects.none()
|
|
||||||
if key in [PermNode.FAVORITE_NODE_KEY, PermNode.UNGROUPED_NODE_KEY]:
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
node = PermNode.objects.get(key=key)
|
|
||||||
granted_status = node.get_granted_status(self.user)
|
|
||||||
if granted_status == NodeFrom.granted:
|
|
||||||
nodes = PermNode.objects.filter(parent_key=key)
|
|
||||||
elif granted_status in (NodeFrom.asset, NodeFrom.child):
|
|
||||||
nodes = self.get_indirect_granted_node_children(key)
|
|
||||||
nodes = self.sort(nodes)
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
def get_indirect_granted_node_children(self, key):
|
|
||||||
"""
|
|
||||||
获取用户授权树中未授权节点的子节点
|
|
||||||
只匹配在 `UserAssetGrantedTreeNodeRelation` 中存在的节点
|
|
||||||
"""
|
|
||||||
user = self.user
|
|
||||||
nodes = PermNode.objects.filter(
|
|
||||||
granted_node_rels__user=user,
|
|
||||||
parent_key=key
|
|
||||||
).annotate(
|
|
||||||
**PermNode.annotate_granted_node_rel_fields
|
|
||||||
).distinct()
|
|
||||||
|
|
||||||
# 设置节点授权资产数量
|
|
||||||
for node in nodes:
|
|
||||||
node.use_granted_assets_amount()
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
def get_top_level_nodes(self):
|
|
||||||
nodes = self.get_special_nodes()
|
|
||||||
real_nodes = self.get_indirect_granted_node_children('')
|
|
||||||
nodes.extend(real_nodes)
|
|
||||||
if len(real_nodes) == 1:
|
|
||||||
children = self.get_node_children(real_nodes[0].key)
|
|
||||||
nodes.extend(children)
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
def get_ungrouped_node(self):
|
|
||||||
assets_util = UserGrantedAssetsQueryUtils(self.user, self.asset_perm_ids)
|
|
||||||
assets_amount = assets_util.get_direct_granted_assets().count()
|
|
||||||
return PermNode.get_ungrouped_node(assets_amount)
|
|
||||||
|
|
||||||
def get_favorite_node(self):
|
|
||||||
assets_query_utils = UserGrantedAssetsQueryUtils(self.user, self.asset_perm_ids)
|
|
||||||
assets_amount = assets_query_utils.get_favorite_assets().values_list('id').count()
|
|
||||||
return PermNode.get_favorite_node(assets_amount)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_root_node():
|
|
||||||
name = _('My assets')
|
|
||||||
node = {
|
|
||||||
'id': '',
|
|
||||||
'name': name,
|
|
||||||
'title': name,
|
|
||||||
'pId': '',
|
|
||||||
'open': True,
|
|
||||||
'isParent': True,
|
|
||||||
'meta': {
|
|
||||||
'type': 'root'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node
|
|
||||||
|
|
||||||
def get_special_nodes(self):
|
|
||||||
nodes = []
|
|
||||||
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
|
|
||||||
ungrouped_node = self.get_ungrouped_node()
|
|
||||||
nodes.append(ungrouped_node)
|
|
||||||
favorite_node = self.get_favorite_node()
|
|
||||||
nodes.append(favorite_node)
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
@timeit
|
|
||||||
def get_whole_tree_nodes(self, with_special=True):
|
|
||||||
"""
|
|
||||||
这里的 granted nodes, 是整棵树需要的node,推算出来的也算
|
|
||||||
:param with_special:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
nodes = PermNode.objects.filter(granted_node_rels__user=self.user) \
|
|
||||||
.annotate(**PermNode.annotate_granted_node_rel_fields) \
|
|
||||||
.distinct()
|
|
||||||
|
|
||||||
key_to_node_mapper = {}
|
|
||||||
nodes_descendant_q = Q()
|
|
||||||
|
|
||||||
for node in nodes:
|
|
||||||
node.use_granted_assets_amount()
|
|
||||||
key_to_node_mapper[node.key] = node
|
|
||||||
|
|
||||||
if node.node_from == NodeFrom.granted:
|
|
||||||
# 直接授权的节点
|
|
||||||
# 增加查询后代节点的过滤条件
|
|
||||||
nodes_descendant_q |= Q(key__startswith=f'{node.key}:')
|
|
||||||
|
|
||||||
if nodes_descendant_q:
|
|
||||||
descendant_nodes = PermNode.objects.filter(
|
|
||||||
nodes_descendant_q
|
|
||||||
)
|
|
||||||
for node in descendant_nodes:
|
|
||||||
key_to_node_mapper[node.key] = node
|
|
||||||
|
|
||||||
all_nodes = []
|
|
||||||
if with_special:
|
|
||||||
special_nodes = self.get_special_nodes()
|
|
||||||
all_nodes.extend(special_nodes)
|
|
||||||
all_nodes.extend(key_to_node_mapper.values())
|
|
||||||
return all_nodes
|
|
|
@ -153,7 +153,7 @@ class ConnectMethodUtil:
|
||||||
protocols = {
|
protocols = {
|
||||||
TerminalType.koko: {
|
TerminalType.koko: {
|
||||||
'web_methods': [WebMethod.web_cli, WebMethod.web_sftp],
|
'web_methods': [WebMethod.web_cli, WebMethod.web_sftp],
|
||||||
'listen': [Protocol.ssh, Protocol.http],
|
'listen': [Protocol.http],
|
||||||
'support': [
|
'support': [
|
||||||
Protocol.ssh, Protocol.telnet,
|
Protocol.ssh, Protocol.telnet,
|
||||||
Protocol.mysql, Protocol.postgresql,
|
Protocol.mysql, Protocol.postgresql,
|
||||||
|
|
Loading…
Reference in New Issue