mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-15 08:32:48 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
634e3a8e25 | ||
|
|
8f792dc4b6 | ||
|
|
d8ab81b53e | ||
|
|
06008e5ac9 | ||
|
|
19a8a0806e | ||
|
|
49c17d18b3 | ||
|
|
02b8533ea0 | ||
|
|
5c46ff20de | ||
|
|
074121b957 | ||
|
|
0eff79c47a | ||
|
|
10ff7730ec | ||
|
|
4f70e313b4 | ||
|
|
c225fd584d | ||
|
|
8ed6a64a9e | ||
|
|
d7e97629aa | ||
|
|
2c20889540 | ||
|
|
7d325856b9 | ||
|
|
28879d9314 |
@@ -18,6 +18,11 @@ WORKDIR /opt/jumpserver
|
|||||||
|
|
||||||
COPY ./requirements ./requirements
|
COPY ./requirements ./requirements
|
||||||
RUN useradd jumpserver
|
RUN useradd jumpserver
|
||||||
|
|
||||||
|
RUN wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo \
|
||||||
|
&& sed -i 's@/centos/@/centos-vault/@g' /etc/yum.repos.d/CentOS-Base.repo \
|
||||||
|
&& sed -i 's@$releasever@6.10@g' /etc/yum.repos.d/CentOS-Base.repo
|
||||||
|
|
||||||
RUN yum -y install epel-release && \
|
RUN yum -y install epel-release && \
|
||||||
echo -e "[mysql]\nname=mysql\nbaseurl=${MYSQL_MIRROR}\ngpgcheck=0\nenabled=1" > /etc/yum.repos.d/mysql.repo
|
echo -e "[mysql]\nname=mysql\nbaseurl=${MYSQL_MIRROR}\ngpgcheck=0\nenabled=1" > /etc/yum.repos.d/mysql.repo
|
||||||
RUN yum -y install $(cat requirements/rpm_requirements.txt)
|
RUN yum -y install $(cat requirements/rpm_requirements.txt)
|
||||||
|
|||||||
@@ -355,3 +355,4 @@ class Asset(ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
|||||||
class Meta:
|
class Meta:
|
||||||
unique_together = [('org_id', 'hostname')]
|
unique_together = [('org_id', 'hostname')]
|
||||||
verbose_name = _("Asset")
|
verbose_name = _("Asset")
|
||||||
|
ordering = ['-date_created']
|
||||||
|
|||||||
@@ -158,9 +158,11 @@ class AuthMixin:
|
|||||||
if update_fields:
|
if update_fields:
|
||||||
self.save(update_fields=update_fields)
|
self.save(update_fields=update_fields)
|
||||||
|
|
||||||
def has_special_auth(self, asset=None):
|
def has_special_auth(self, asset=None, username=None):
|
||||||
from .authbook import AuthBook
|
from .authbook import AuthBook
|
||||||
queryset = AuthBook.objects.filter(username=self.username)
|
if username is None:
|
||||||
|
username = self.username
|
||||||
|
queryset = AuthBook.objects.filter(username=username)
|
||||||
if asset:
|
if asset:
|
||||||
queryset = queryset.filter(asset=asset)
|
queryset = queryset.filter(asset=asset)
|
||||||
return queryset.exists()
|
return queryset.exists()
|
||||||
|
|||||||
@@ -140,6 +140,11 @@ class SystemUser(BaseUser):
|
|||||||
def is_need_test_asset_connective(self):
|
def is_need_test_asset_connective(self):
|
||||||
return self.protocol not in [self.PROTOCOL_MYSQL]
|
return self.protocol not in [self.PROTOCOL_MYSQL]
|
||||||
|
|
||||||
|
def has_special_auth(self, asset=None, username=None):
|
||||||
|
if username is None and self.username_same_with_user:
|
||||||
|
raise TypeError('System user is dynamic, username should be pass')
|
||||||
|
return super().has_special_auth(asset=asset, username=username)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def can_perm_to_asset(self):
|
def can_perm_to_asset(self):
|
||||||
return self.protocol not in [self.PROTOCOL_MYSQL]
|
return self.protocol not in [self.PROTOCOL_MYSQL]
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ def on_system_user_groups_change(instance, action, pk_set, reverse, **kwargs):
|
|||||||
logger.info("System user groups update signal recv: {}".format(instance))
|
logger.info("System user groups update signal recv: {}".format(instance))
|
||||||
|
|
||||||
users = User.objects.filter(groups__id__in=pk_set).distinct()
|
users = User.objects.filter(groups__id__in=pk_set).distinct()
|
||||||
instance.users.add(users)
|
instance.users.add(*users)
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=Asset.nodes.through)
|
@receiver(m2m_changed, sender=Asset.nodes.through)
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ def get_push_windows_system_user_tasks(system_user, username=None):
|
|||||||
|
|
||||||
tasks = []
|
tasks = []
|
||||||
if not password:
|
if not password:
|
||||||
|
logger.error("Error: no password found")
|
||||||
return tasks
|
return tasks
|
||||||
task = {
|
task = {
|
||||||
'name': 'Add user {}'.format(username),
|
'name': 'Add user {}'.format(username),
|
||||||
@@ -209,14 +210,15 @@ def push_system_user_util(system_user, assets, task_name, username=None):
|
|||||||
print(_("Start push system user for platform: [{}]").format(platform))
|
print(_("Start push system user for platform: [{}]").format(platform))
|
||||||
print(_("Hosts count: {}").format(len(_hosts)))
|
print(_("Hosts count: {}").format(len(_hosts)))
|
||||||
|
|
||||||
if not system_user.has_special_auth():
|
# 如果没有特殊密码设置,就不需要单独推送某台机器了
|
||||||
|
if not system_user.has_special_auth(username=username):
|
||||||
logger.debug("System user not has special auth")
|
logger.debug("System user not has special auth")
|
||||||
tasks = get_push_system_user_tasks(system_user, platform, username=username)
|
tasks = get_push_system_user_tasks(system_user, platform, username=username)
|
||||||
run_task(tasks, _hosts)
|
run_task(tasks, _hosts)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for _host in _hosts:
|
for _host in _hosts:
|
||||||
system_user.load_asset_special_auth(_host)
|
system_user.load_asset_special_auth(_host, username=username)
|
||||||
tasks = get_push_system_user_tasks(system_user, platform, username=username)
|
tasks = get_push_system_user_tasks(system_user, platform, username=username)
|
||||||
run_task(tasks, [_host])
|
run_task(tasks, [_host])
|
||||||
|
|
||||||
@@ -241,8 +243,8 @@ def push_system_user_a_asset_manual(system_user, asset, username=None):
|
|||||||
|
|
||||||
@shared_task(queue="ansible")
|
@shared_task(queue="ansible")
|
||||||
def push_system_user_to_assets(system_user, assets, username=None):
|
def push_system_user_to_assets(system_user, assets, username=None):
|
||||||
task_name = _("Push system users to assets: {}").format(system_user.name)
|
|
||||||
system_user = get_object_if_need(SystemUser, system_user)
|
system_user = get_object_if_need(SystemUser, system_user)
|
||||||
|
task_name = _("Push system users to assets: {}").format(system_user.name)
|
||||||
assets = get_objects_if_need(Asset, assets)
|
assets = get_objects_if_need(Asset, assets)
|
||||||
return push_system_user_util(system_user, assets, task_name, username=username)
|
return push_system_user_util(system_user, assets, task_name, username=username)
|
||||||
|
|
||||||
|
|||||||
@@ -54,12 +54,3 @@ class UserConnectionTokenApi(RootOrgViewMixin, APIView):
|
|||||||
return Response(value)
|
return Response(value)
|
||||||
else:
|
else:
|
||||||
return Response({'user': value['user']})
|
return Response({'user': value['user']})
|
||||||
|
|
||||||
def get_permissions(self):
|
|
||||||
if self.request.query_params.get('user-only', None):
|
|
||||||
self.permission_classes = (AllowAny,)
|
|
||||||
return super().get_permissions()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ def common_exception_handler(exc, context):
|
|||||||
if getattr(exc, 'wait', None):
|
if getattr(exc, 'wait', None):
|
||||||
headers['Retry-After'] = '%d' % exc.wait
|
headers['Retry-After'] = '%d' % exc.wait
|
||||||
|
|
||||||
if isinstance(exc.detail, (list, dict)):
|
if isinstance(exc.detail, str) and isinstance(exc.get_codes(), str):
|
||||||
data = exc.detail
|
data = {'detail': exc.detail, 'code': exc.get_codes()}
|
||||||
else:
|
else:
|
||||||
data = {'detail': exc.detail}
|
data = exc.detail
|
||||||
|
|
||||||
set_rollback()
|
set_rollback()
|
||||||
return Response(data, status=exc.status_code, headers=headers)
|
return Response(data, status=exc.status_code, headers=headers)
|
||||||
|
|||||||
@@ -242,6 +242,9 @@ CACHES = {
|
|||||||
'host': CONFIG.REDIS_HOST,
|
'host': CONFIG.REDIS_HOST,
|
||||||
'port': CONFIG.REDIS_PORT,
|
'port': CONFIG.REDIS_PORT,
|
||||||
'db': CONFIG.REDIS_DB_CACHE,
|
'db': CONFIG.REDIS_DB_CACHE,
|
||||||
|
},
|
||||||
|
'OPTIONS': {
|
||||||
|
"REDIS_CLIENT_KWARGS": {"health_check_interval": 30}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ class AdHocResultCallback(CallbackMixin, CallbackModule, CMDCallBackModule):
|
|||||||
"""
|
"""
|
||||||
Task result Callback
|
Task result Callback
|
||||||
"""
|
"""
|
||||||
|
context = None
|
||||||
|
|
||||||
def clean_result(self, t, host, task_name, task_result):
|
def clean_result(self, t, host, task_name, task_result):
|
||||||
contacted = self.results_summary["contacted"]
|
contacted = self.results_summary["contacted"]
|
||||||
dark = self.results_summary["dark"]
|
dark = self.results_summary["dark"]
|
||||||
@@ -133,7 +135,11 @@ class AdHocResultCallback(CallbackMixin, CallbackModule, CMDCallBackModule):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def set_play_context(self, context):
|
def set_play_context(self, context):
|
||||||
context.ssh_args = '-C -o ControlMaster=no'
|
# for k, v in context._attributes.items():
|
||||||
|
# print("{} ==> {}".format(k, v))
|
||||||
|
if self.context and isinstance(self.context, dict):
|
||||||
|
for k, v in self.context.items():
|
||||||
|
setattr(context, k, v)
|
||||||
|
|
||||||
|
|
||||||
class CommandResultCallback(AdHocResultCallback):
|
class CommandResultCallback(AdHocResultCallback):
|
||||||
|
|||||||
@@ -182,6 +182,13 @@ class AdHocRunner:
|
|||||||
_options.update(options)
|
_options.update(options)
|
||||||
return _options
|
return _options
|
||||||
|
|
||||||
|
def set_control_master_if_need(self, cleaned_tasks):
|
||||||
|
modules = [task.get('action', {}).get('module') for task in cleaned_tasks]
|
||||||
|
if {'ping', 'win_ping'} & set(modules):
|
||||||
|
self.results_callback.context = {
|
||||||
|
'ssh_args': '-C -o ControlMaster=no'
|
||||||
|
}
|
||||||
|
|
||||||
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no'):
|
def run(self, tasks, pattern, play_name='Ansible Ad-hoc', gather_facts='no'):
|
||||||
"""
|
"""
|
||||||
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
|
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
|
||||||
@@ -193,6 +200,7 @@ class AdHocRunner:
|
|||||||
self.check_pattern(pattern)
|
self.check_pattern(pattern)
|
||||||
self.results_callback = self.get_result_callback()
|
self.results_callback = self.get_result_callback()
|
||||||
cleaned_tasks = self.clean_tasks(tasks)
|
cleaned_tasks = self.clean_tasks(tasks)
|
||||||
|
self.set_control_master_if_need(cleaned_tasks)
|
||||||
context.CLIARGS = ImmutableDict(self.options)
|
context.CLIARGS = ImmutableDict(self.options)
|
||||||
|
|
||||||
play_source = dict(
|
play_source = dict(
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ class CeleryLogWebsocket(JsonWebsocketConsumer):
|
|||||||
disconnected = False
|
disconnected = False
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
self.accept()
|
user = self.scope["user"]
|
||||||
|
if user.is_authenticated and user.is_org_admin:
|
||||||
|
self.accept()
|
||||||
|
else:
|
||||||
|
self.close()
|
||||||
|
|
||||||
def receive(self, text_data=None, bytes_data=None, **kwargs):
|
def receive(self, text_data=None, bytes_data=None, **kwargs):
|
||||||
data = json.loads(text_data)
|
data = json.loads(text_data)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ router = DefaultRouter()
|
|||||||
bulk_router = BulkRouter()
|
bulk_router = BulkRouter()
|
||||||
|
|
||||||
router.register(r'orgs', api.OrgViewSet, 'org')
|
router.register(r'orgs', api.OrgViewSet, 'org')
|
||||||
bulk_router.register(r'org-memeber-relation', api.OrgMemberRelationBulkViewSet, 'org-memeber-relation')
|
bulk_router.register(r'org-member-relation', api.OrgMemberRelationBulkViewSet, 'org-member-relation')
|
||||||
|
|
||||||
old_version_urlpatterns = [
|
old_version_urlpatterns = [
|
||||||
re_path('(?P<resource>org)/.*', capi.redirect_plural_name_api)
|
re_path('(?P<resource>org)/.*', capi.redirect_plural_name_api)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
from common.permissions import IsOrgAdmin
|
from common.permissions import IsOrgAdmin
|
||||||
from orgs.mixins.api import OrgModelViewSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from ..models import AssetPermission
|
from ..models import AssetPermission
|
||||||
from ..hands import (
|
from ..hands import (
|
||||||
@@ -17,7 +17,7 @@ __all__ = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionViewSet(OrgModelViewSet):
|
class AssetPermissionViewSet(OrgBulkModelViewSet):
|
||||||
"""
|
"""
|
||||||
资产授权列表的增删改查api
|
资产授权列表的增删改查api
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from rest_framework.request import Request
|
|||||||
|
|
||||||
from common.permissions import IsOrgAdminOrAppUser, IsValidUser
|
from common.permissions import IsOrgAdminOrAppUser, IsValidUser
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
|
from orgs.utils import tmp_to_root_org
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from perms.models import UserGrantedMappingNode
|
from perms.models import UserGrantedMappingNode
|
||||||
|
|
||||||
@@ -47,6 +48,10 @@ class ForUserMixin:
|
|||||||
permission_classes = (IsValidUser,)
|
permission_classes = (IsValidUser,)
|
||||||
request: Request
|
request: Request
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
with tmp_to_root_org():
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def user(self):
|
def user(self):
|
||||||
return self.request.user
|
return self.request.user
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from perms.api.user_permission.mixin import UserNodeGrantStatusDispatchMixin
|
from perms.api.user_permission.mixin import UserNodeGrantStatusDispatchMixin
|
||||||
from rest_framework.generics import ListAPIView
|
from rest_framework.generics import ListAPIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -10,7 +9,6 @@ from assets.api.mixin import SerializeToTreeNodeMixin
|
|||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from perms.pagination import GrantedAssetLimitOffsetPagination
|
from perms.pagination import GrantedAssetLimitOffsetPagination
|
||||||
from assets.models import Asset, Node, FavoriteAsset
|
from assets.models import Asset, Node, FavoriteAsset
|
||||||
from orgs.utils import tmp_to_root_org
|
|
||||||
from ... import serializers
|
from ... import serializers
|
||||||
from ...utils.user_asset_permission import (
|
from ...utils.user_asset_permission import (
|
||||||
get_node_all_granted_assets, get_user_direct_granted_assets,
|
get_node_all_granted_assets, get_user_direct_granted_assets,
|
||||||
@@ -22,7 +20,6 @@ from .mixin import ForAdminMixin, ForUserMixin
|
|||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
|
||||||
class UserDirectGrantedAssetsApi(ListAPIView):
|
class UserDirectGrantedAssetsApi(ListAPIView):
|
||||||
"""
|
"""
|
||||||
用户直接授权的资产的列表,也就是授权规则上直接授权的资产,并非是来自节点的
|
用户直接授权的资产的列表,也就是授权规则上直接授权的资产,并非是来自节点的
|
||||||
@@ -40,7 +37,6 @@ class UserDirectGrantedAssetsApi(ListAPIView):
|
|||||||
return assets
|
return assets
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
|
||||||
class UserFavoriteGrantedAssetsApi(ListAPIView):
|
class UserFavoriteGrantedAssetsApi(ListAPIView):
|
||||||
serializer_class = serializers.AssetGrantedSerializer
|
serializer_class = serializers.AssetGrantedSerializer
|
||||||
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
|
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
|
||||||
@@ -55,7 +51,6 @@ class UserFavoriteGrantedAssetsApi(ListAPIView):
|
|||||||
return assets
|
return assets
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
|
||||||
class AssetsAsTreeMixin(SerializeToTreeNodeMixin):
|
class AssetsAsTreeMixin(SerializeToTreeNodeMixin):
|
||||||
"""
|
"""
|
||||||
将 资产 序列化成树的结构返回
|
将 资产 序列化成树的结构返回
|
||||||
@@ -82,12 +77,10 @@ class MyFavoriteGrantedAssetsApi(ForUserMixin, UserFavoriteGrantedAssetsApi):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
|
||||||
class UserDirectGrantedAssetsAsTreeForAdminApi(ForAdminMixin, AssetsAsTreeMixin, UserDirectGrantedAssetsApi):
|
class UserDirectGrantedAssetsAsTreeForAdminApi(ForAdminMixin, AssetsAsTreeMixin, UserDirectGrantedAssetsApi):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
|
||||||
class MyUngroupAssetsAsTreeApi(ForUserMixin, AssetsAsTreeMixin, UserDirectGrantedAssetsApi):
|
class MyUngroupAssetsAsTreeApi(ForUserMixin, AssetsAsTreeMixin, UserDirectGrantedAssetsApi):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
@@ -96,9 +89,11 @@ class MyUngroupAssetsAsTreeApi(ForUserMixin, AssetsAsTreeMixin, UserDirectGrante
|
|||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
class UserAllGrantedAssetsApi(ForAdminMixin, ListAPIView):
|
||||||
class UserAllGrantedAssetsApi(ListAPIView):
|
|
||||||
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
|
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
|
||||||
|
serializer_class = serializers.AssetGrantedSerializer
|
||||||
|
filter_fields = ['hostname', 'ip', 'id', 'comment']
|
||||||
|
search_fields = ['hostname', 'ip', 'comment']
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = get_user_granted_all_assets(self.user)
|
queryset = get_user_granted_all_assets(self.user)
|
||||||
@@ -106,11 +101,14 @@ class UserAllGrantedAssetsApi(ListAPIView):
|
|||||||
return queryset.only(*self.only_fields)
|
return queryset.only(*self.only_fields)
|
||||||
|
|
||||||
|
|
||||||
|
class MyAllGrantedAssetsApi(ForUserMixin, UserAllGrantedAssetsApi):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MyAllAssetsAsTreeApi(ForUserMixin, AssetsAsTreeMixin, UserAllGrantedAssetsApi):
|
class MyAllAssetsAsTreeApi(ForUserMixin, AssetsAsTreeMixin, UserAllGrantedAssetsApi):
|
||||||
search_fields = ['hostname', 'ip']
|
search_fields = ['hostname', 'ip']
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(tmp_to_root_org(), name='list')
|
|
||||||
class UserGrantedNodeAssetsApi(UserNodeGrantStatusDispatchMixin, ListAPIView):
|
class UserGrantedNodeAssetsApi(UserNodeGrantStatusDispatchMixin, ListAPIView):
|
||||||
serializer_class = serializers.AssetGrantedSerializer
|
serializer_class = serializers.AssetGrantedSerializer
|
||||||
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
|
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ from rest_framework.generics import (
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
from orgs.utils import tmp_to_root_org
|
|
||||||
from assets.api.mixin import SerializeToTreeNodeMixin
|
from assets.api.mixin import SerializeToTreeNodeMixin
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .mixin import ForAdminMixin, ForUserMixin, UserNodeGrantStatusDispatchMixin
|
from .mixin import ForAdminMixin, ForUserMixin, UserNodeGrantStatusDispatchMixin
|
||||||
@@ -59,7 +58,6 @@ class NodeChildrenMixin:
|
|||||||
class BaseGrantedNodeApi(_GrantedNodeStructApi, metaclass=abc.ABCMeta):
|
class BaseGrantedNodeApi(_GrantedNodeStructApi, metaclass=abc.ABCMeta):
|
||||||
serializer_class = serializers.NodeGrantedSerializer
|
serializer_class = serializers.NodeGrantedSerializer
|
||||||
|
|
||||||
@tmp_to_root_org()
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
rebuild_user_tree_if_need(request, self.user)
|
rebuild_user_tree_if_need(request, self.user)
|
||||||
nodes = self.get_nodes()
|
nodes = self.get_nodes()
|
||||||
@@ -72,7 +70,6 @@ class BaseNodeChildrenApi(NodeChildrenMixin, BaseGrantedNodeApi, metaclass=abc.A
|
|||||||
|
|
||||||
|
|
||||||
class BaseGrantedNodeAsTreeApi(SerializeToTreeNodeMixin, _GrantedNodeStructApi, metaclass=abc.ABCMeta):
|
class BaseGrantedNodeAsTreeApi(SerializeToTreeNodeMixin, _GrantedNodeStructApi, metaclass=abc.ABCMeta):
|
||||||
@tmp_to_root_org()
|
|
||||||
def list(self, request: Request, *args, **kwargs):
|
def list(self, request: Request, *args, **kwargs):
|
||||||
rebuild_user_tree_if_need(request, self.user)
|
rebuild_user_tree_if_need(request, self.user)
|
||||||
nodes = self.get_nodes()
|
nodes = self.get_nodes()
|
||||||
|
|||||||
@@ -9,12 +9,11 @@ from common.permissions import IsValidUser
|
|||||||
from common.utils import get_logger, get_object_or_none
|
from common.utils import get_logger, get_object_or_none
|
||||||
from .mixin import UserNodeGrantStatusDispatchMixin, ForUserMixin, ForAdminMixin
|
from .mixin import UserNodeGrantStatusDispatchMixin, ForUserMixin, ForAdminMixin
|
||||||
from ...utils.user_asset_permission import (
|
from ...utils.user_asset_permission import (
|
||||||
get_user_resources_q_granted_by_permissions,
|
|
||||||
get_indirect_granted_node_children, UNGROUPED_NODE_KEY, FAVORITE_NODE_KEY,
|
get_indirect_granted_node_children, UNGROUPED_NODE_KEY, FAVORITE_NODE_KEY,
|
||||||
get_user_direct_granted_assets, get_top_level_granted_nodes,
|
get_user_direct_granted_assets, get_top_level_granted_nodes,
|
||||||
get_user_granted_nodes_list_via_mapping_node,
|
get_user_granted_nodes_list_via_mapping_node,
|
||||||
get_user_granted_all_assets, rebuild_user_tree_if_need,
|
get_user_granted_all_assets, rebuild_user_tree_if_need,
|
||||||
get_user_all_assetpermission_ids,
|
get_user_all_assetpermissions_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
from assets.models import Asset, FavoriteAsset
|
from assets.models import Asset, FavoriteAsset
|
||||||
@@ -66,7 +65,7 @@ class UserGrantedNodeChildrenWithAssetsAsTreeForAdminApi(ForAdminMixin, UserNode
|
|||||||
|
|
||||||
def get_data_on_node_indirect_granted(self, key):
|
def get_data_on_node_indirect_granted(self, key):
|
||||||
user = self.user
|
user = self.user
|
||||||
asset_perm_ids = get_user_all_assetpermission_ids(user)
|
asset_perm_ids = get_user_all_assetpermissions_id(user)
|
||||||
|
|
||||||
nodes = get_indirect_granted_node_children(user, key)
|
nodes = get_indirect_granted_node_children(user, key)
|
||||||
|
|
||||||
@@ -102,7 +101,6 @@ class UserGrantedNodeChildrenWithAssetsAsTreeForAdminApi(ForAdminMixin, UserNode
|
|||||||
if node:
|
if node:
|
||||||
return node.key
|
return node.key
|
||||||
|
|
||||||
@tmp_to_root_org()
|
|
||||||
def list(self, request: Request, *args, **kwargs):
|
def list(self, request: Request, *args, **kwargs):
|
||||||
key = self.request.query_params.get('key')
|
key = self.request.query_params.get('key')
|
||||||
if key is None:
|
if key is None:
|
||||||
|
|||||||
@@ -43,12 +43,14 @@ class AssetPermissionSerializer(BulkOrgResourceModelSerializer):
|
|||||||
model = AssetPermission
|
model = AssetPermission
|
||||||
mini_fields = ['id', 'name']
|
mini_fields = ['id', 'name']
|
||||||
small_fields = mini_fields + [
|
small_fields = mini_fields + [
|
||||||
'is_active', 'is_expired', 'is_valid', 'actions', 'created_by', 'date_created',
|
'is_active', 'is_expired', 'is_valid', 'actions',
|
||||||
'date_expired', 'date_start', 'comment'
|
'created_by', 'date_created', 'date_expired',
|
||||||
|
'date_start', 'comment'
|
||||||
]
|
]
|
||||||
m2m_fields = [
|
m2m_fields = [
|
||||||
'users', 'user_groups', 'assets', 'nodes', 'system_users',
|
'users', 'user_groups', 'assets', 'nodes', 'system_users',
|
||||||
'users_amount', 'user_groups_amount', 'assets_amount', 'nodes_amount', 'system_users_amount',
|
'users_amount', 'user_groups_amount', 'assets_amount',
|
||||||
|
'nodes_amount', 'system_users_amount',
|
||||||
]
|
]
|
||||||
fields = small_fields + m2m_fields
|
fields = small_fields + m2m_fields
|
||||||
read_only_fields = ['created_by', 'date_created']
|
read_only_fields = ['created_by', 'date_created']
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ user_permission_urlpatterns = [
|
|||||||
# 直接授权:在 `AssetPermission` 中关联的对象
|
# 直接授权:在 `AssetPermission` 中关联的对象
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# 获取用户所有直接授权的资产
|
|
||||||
|
|
||||||
# 以 serializer 格式返回
|
# 以 serializer 格式返回
|
||||||
path('<uuid:pk>/assets/', api.UserDirectGrantedAssetsForAdminApi.as_view(), name='user-assets'),
|
path('<uuid:pk>/assets/', api.UserAllGrantedAssetsApi.as_view(), name='user-assets'),
|
||||||
path('assets/', api.MyDirectGrantedAssetsApi.as_view(), name='my-assets'),
|
path('assets/', api.MyAllAssetsAsTreeApi.as_view(), name='my-assets'),
|
||||||
|
|
||||||
# Tree Node 的数据格式返回
|
# Tree Node 的数据格式返回
|
||||||
path('<uuid:pk>/assets/tree/', api.UserDirectGrantedAssetsAsTreeForAdminApi.as_view(), name='user-assets-as-tree'),
|
path('<uuid:pk>/assets/tree/', api.UserDirectGrantedAssetsAsTreeForAdminApi.as_view(), name='user-assets-as-tree'),
|
||||||
|
|||||||
@@ -11,16 +11,19 @@ logger = get_logger(__file__)
|
|||||||
|
|
||||||
|
|
||||||
def get_asset_system_users_id_with_actions(asset_perm_queryset: BasePermissionQuerySet, asset: Asset):
|
def get_asset_system_users_id_with_actions(asset_perm_queryset: BasePermissionQuerySet, asset: Asset):
|
||||||
|
asset_perms_id = set(asset_perm_queryset.values_list('id', flat=True))
|
||||||
|
|
||||||
nodes = asset.get_nodes()
|
nodes = asset.get_nodes()
|
||||||
node_keys = set()
|
node_keys = set()
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
ancestor_keys = node.get_ancestor_keys(with_self=True)
|
ancestor_keys = node.get_ancestor_keys(with_self=True)
|
||||||
node_keys.update(ancestor_keys)
|
node_keys.update(ancestor_keys)
|
||||||
|
|
||||||
queryset = asset_perm_queryset.filter(
|
queryset = AssetPermission.objects.filter(id__in=asset_perms_id).filter(
|
||||||
Q(assets=asset) |
|
Q(assets=asset) |
|
||||||
Q(nodes__key__in=node_keys)
|
Q(nodes__key__in=node_keys)
|
||||||
)
|
)
|
||||||
|
|
||||||
asset_protocols = asset.protocols_as_dict.keys()
|
asset_protocols = asset.protocols_as_dict.keys()
|
||||||
values = queryset.filter(
|
values = queryset.filter(
|
||||||
system_users__protocol__in=asset_protocols
|
system_users__protocol__in=asset_protocols
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from functools import reduce, wraps
|
from functools import reduce, wraps
|
||||||
from operator import or_, and_
|
from operator import or_
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
import threading
|
import threading
|
||||||
import inspect
|
import inspect
|
||||||
@@ -32,27 +32,6 @@ TMP_ASSET_GRANTED_FIELD = '_asset_granted'
|
|||||||
TMP_GRANTED_ASSETS_AMOUNT_FIELD = '_granted_assets_amount'
|
TMP_GRANTED_ASSETS_AMOUNT_FIELD = '_granted_assets_amount'
|
||||||
|
|
||||||
|
|
||||||
# 使用场景
|
|
||||||
# Asset.objects.filter(get_user_resources_q_granted_by_permissions(user))
|
|
||||||
def get_user_resources_q_granted_by_permissions(user: User):
|
|
||||||
"""
|
|
||||||
获取用户关联的 asset permission 或者 用户组关联的 asset permission 获取规则,
|
|
||||||
前提 AssetPermission 对象中的 related_name 为 granted_by_permissions
|
|
||||||
:param user:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
_now = now()
|
|
||||||
return reduce(and_, (
|
|
||||||
Q(granted_by_permissions__date_start__lt=_now),
|
|
||||||
Q(granted_by_permissions__date_expired__gt=_now),
|
|
||||||
Q(granted_by_permissions__is_active=True),
|
|
||||||
(
|
|
||||||
Q(granted_by_permissions__users=user) |
|
|
||||||
Q(granted_by_permissions__user_groups__users=user)
|
|
||||||
)
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
# 使用场景
|
# 使用场景
|
||||||
# `Node.objects.annotate(**node_annotate_mapping_node)`
|
# `Node.objects.annotate(**node_annotate_mapping_node)`
|
||||||
node_annotate_mapping_node = {
|
node_annotate_mapping_node = {
|
||||||
@@ -147,12 +126,15 @@ def rebuild_user_mapping_nodes_with_lock(user: User):
|
|||||||
|
|
||||||
|
|
||||||
@tmp_to_root_org()
|
@tmp_to_root_org()
|
||||||
def compute_tmp_mapping_node_from_perm(user: User):
|
def compute_tmp_mapping_node_from_perm(user: User, asset_perms_id=None):
|
||||||
node_only_fields = ('id', 'key', 'parent_key', 'assets_amount')
|
node_only_fields = ('id', 'key', 'parent_key', 'assets_amount')
|
||||||
|
|
||||||
|
if asset_perms_id is None:
|
||||||
|
asset_perms_id = get_user_all_assetpermissions_id(user)
|
||||||
|
|
||||||
# 查询直接授权节点
|
# 查询直接授权节点
|
||||||
nodes = Node.objects.filter(
|
nodes = Node.objects.filter(
|
||||||
get_user_resources_q_granted_by_permissions(user)
|
granted_by_permissions__id__in=asset_perms_id
|
||||||
).distinct().only(*node_only_fields)
|
).distinct().only(*node_only_fields)
|
||||||
granted_key_set = {_node.key for _node in nodes}
|
granted_key_set = {_node.key for _node in nodes}
|
||||||
|
|
||||||
@@ -178,7 +160,7 @@ def compute_tmp_mapping_node_from_perm(user: User):
|
|||||||
def process_direct_granted_assets():
|
def process_direct_granted_assets():
|
||||||
# 查询直接授权资产
|
# 查询直接授权资产
|
||||||
asset_ids = Asset.objects.filter(
|
asset_ids = Asset.objects.filter(
|
||||||
get_user_resources_q_granted_by_permissions(user)
|
granted_by_permissions__id__in=asset_perms_id
|
||||||
).distinct().values_list('id', flat=True)
|
).distinct().values_list('id', flat=True)
|
||||||
# 查询授权资产关联的节点设置
|
# 查询授权资产关联的节点设置
|
||||||
granted_asset_nodes = Node.objects.filter(
|
granted_asset_nodes = Node.objects.filter(
|
||||||
@@ -211,7 +193,7 @@ def compute_tmp_mapping_node_from_perm(user: User):
|
|||||||
return [*leaf_nodes, *ancestors]
|
return [*leaf_nodes, *ancestors]
|
||||||
|
|
||||||
|
|
||||||
def create_mapping_nodes(user, nodes, clear=True):
|
def create_mapping_nodes(user, nodes):
|
||||||
to_create = []
|
to_create = []
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
_granted = getattr(node, TMP_GRANTED_FIELD, False)
|
_granted = getattr(node, TMP_GRANTED_FIELD, False)
|
||||||
@@ -227,12 +209,10 @@ def create_mapping_nodes(user, nodes, clear=True):
|
|||||||
assets_amount=_granted_assets_amount,
|
assets_amount=_granted_assets_amount,
|
||||||
))
|
))
|
||||||
|
|
||||||
if clear:
|
|
||||||
UserGrantedMappingNode.objects.filter(user=user).delete()
|
|
||||||
UserGrantedMappingNode.objects.bulk_create(to_create)
|
UserGrantedMappingNode.objects.bulk_create(to_create)
|
||||||
|
|
||||||
|
|
||||||
def set_node_granted_assets_amount(user, node):
|
def set_node_granted_assets_amount(user, node, asset_perms_id=None):
|
||||||
"""
|
"""
|
||||||
不依赖`UserGrantedMappingNode`直接查询授权计算资产数量
|
不依赖`UserGrantedMappingNode`直接查询授权计算资产数量
|
||||||
"""
|
"""
|
||||||
@@ -241,17 +221,25 @@ def set_node_granted_assets_amount(user, node):
|
|||||||
assets_amount = node.assets_amount
|
assets_amount = node.assets_amount
|
||||||
else:
|
else:
|
||||||
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
|
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
|
||||||
assets_amount = count_direct_granted_node_assets(user, node.key)
|
assets_amount = count_direct_granted_node_assets(user, node.key, asset_perms_id)
|
||||||
else:
|
else:
|
||||||
assets_amount = count_node_all_granted_assets(user, node.key)
|
assets_amount = count_node_all_granted_assets(user, node.key, asset_perms_id)
|
||||||
setattr(node, TMP_GRANTED_ASSETS_AMOUNT_FIELD, assets_amount)
|
setattr(node, TMP_GRANTED_ASSETS_AMOUNT_FIELD, assets_amount)
|
||||||
|
|
||||||
|
|
||||||
|
@tmp_to_root_org()
|
||||||
def rebuild_user_mapping_nodes(user):
|
def rebuild_user_mapping_nodes(user):
|
||||||
logger.info(f'>>> {dt_formater(now())} start rebuild {user} mapping nodes')
|
logger.info(f'>>> {dt_formater(now())} start rebuild {user} mapping nodes')
|
||||||
tmp_nodes = compute_tmp_mapping_node_from_perm(user)
|
|
||||||
|
# 先删除用户旧的授权树🌲
|
||||||
|
UserGrantedMappingNode.objects.filter(user=user).delete()
|
||||||
|
asset_perms_id = get_user_all_assetpermissions_id(user)
|
||||||
|
if not asset_perms_id:
|
||||||
|
# 没有授权直接返回
|
||||||
|
return
|
||||||
|
tmp_nodes = compute_tmp_mapping_node_from_perm(user, asset_perms_id)
|
||||||
for _node in tmp_nodes:
|
for _node in tmp_nodes:
|
||||||
set_node_granted_assets_amount(user, _node)
|
set_node_granted_assets_amount(user, _node, asset_perms_id)
|
||||||
create_mapping_nodes(user, tmp_nodes)
|
create_mapping_nodes(user, tmp_nodes)
|
||||||
logger.info(f'>>> {dt_formater(now())} end rebuild {user} mapping nodes')
|
logger.info(f'>>> {dt_formater(now())} end rebuild {user} mapping nodes')
|
||||||
|
|
||||||
@@ -303,7 +291,7 @@ def get_user_granted_nodes_list_via_mapping_node(user):
|
|||||||
|
|
||||||
|
|
||||||
def get_user_granted_all_assets(user, via_mapping_node=True):
|
def get_user_granted_all_assets(user, via_mapping_node=True):
|
||||||
asset_perm_ids = get_user_all_assetpermission_ids(user)
|
asset_perm_ids = get_user_all_assetpermissions_id(user)
|
||||||
if via_mapping_node:
|
if via_mapping_node:
|
||||||
granted_node_keys = UserGrantedMappingNode.objects.filter(
|
granted_node_keys = UserGrantedMappingNode.objects.filter(
|
||||||
user=user, granted=True,
|
user=user, granted=True,
|
||||||
@@ -365,7 +353,8 @@ def get_node_all_granted_assets(user: User, key):
|
|||||||
|
|
||||||
if only_asset_granted_nodes_qs:
|
if only_asset_granted_nodes_qs:
|
||||||
only_asset_granted_nodes_q = reduce(or_, only_asset_granted_nodes_qs)
|
only_asset_granted_nodes_q = reduce(or_, only_asset_granted_nodes_qs)
|
||||||
only_asset_granted_nodes_q &= get_user_resources_q_granted_by_permissions(user)
|
asset_perms_id = get_user_all_assetpermissions_id(user)
|
||||||
|
only_asset_granted_nodes_q &= Q(granted_by_permissions__id__in=asset_perms_id)
|
||||||
q.append(only_asset_granted_nodes_q)
|
q.append(only_asset_granted_nodes_q)
|
||||||
|
|
||||||
if q:
|
if q:
|
||||||
@@ -373,13 +362,16 @@ def get_node_all_granted_assets(user: User, key):
|
|||||||
return assets
|
return assets
|
||||||
|
|
||||||
|
|
||||||
def get_direct_granted_node_ids(user: User, key):
|
def get_direct_granted_node_ids(user: User, key, asset_perms_id=None):
|
||||||
granted_q = get_user_resources_q_granted_by_permissions(user)
|
if asset_perms_id is None:
|
||||||
|
asset_perms_id = get_user_all_assetpermissions_id(user)
|
||||||
|
|
||||||
# 先查出该节点下的直接授权节点
|
# 先查出该节点下的直接授权节点
|
||||||
granted_nodes = Node.objects.filter(
|
granted_nodes = Node.objects.filter(
|
||||||
Q(key__startswith=f'{key}:') | Q(key=key)
|
Q(key__startswith=f'{key}:') | Q(key=key)
|
||||||
).filter(granted_q).distinct().only('id', 'key')
|
).filter(
|
||||||
|
granted_by_permissions__id__in=asset_perms_id
|
||||||
|
).distinct().only('id', 'key')
|
||||||
|
|
||||||
node_ids = set()
|
node_ids = set()
|
||||||
# 根据直接授权节点查询他们的子节点
|
# 根据直接授权节点查询他们的子节点
|
||||||
@@ -394,33 +386,38 @@ def get_direct_granted_node_ids(user: User, key):
|
|||||||
return node_ids
|
return node_ids
|
||||||
|
|
||||||
|
|
||||||
def get_node_all_granted_assets_from_perm(user: User, key):
|
def get_node_all_granted_assets_from_perm(user: User, key, asset_perms_id=None):
|
||||||
"""
|
"""
|
||||||
此算法依据 `AssetPermission` 的数据查询
|
此算法依据 `AssetPermission` 的数据查询
|
||||||
1. 查询该节点下的直接授权节点
|
1. 查询该节点下的直接授权节点
|
||||||
2. 查询该节点下授权资产关联的节点
|
2. 查询该节点下授权资产关联的节点
|
||||||
"""
|
"""
|
||||||
granted_q = get_user_resources_q_granted_by_permissions(user)
|
if asset_perms_id is None:
|
||||||
|
asset_perms_id = get_user_all_assetpermissions_id(user)
|
||||||
|
|
||||||
# 直接授权资产查询条件
|
# 直接授权资产查询条件
|
||||||
q = (Q(nodes__key__startswith=f'{key}:') | Q(nodes__key=key)) & granted_q
|
q = (
|
||||||
node_ids = get_direct_granted_node_ids(user, key)
|
Q(nodes__key__startswith=f'{key}:') | Q(nodes__key=key)
|
||||||
|
) & Q(granted_by_permissions__id__in=asset_perms_id)
|
||||||
|
|
||||||
|
node_ids = get_direct_granted_node_ids(user, key, asset_perms_id)
|
||||||
q |= Q(nodes__id__in=node_ids)
|
q |= Q(nodes__id__in=node_ids)
|
||||||
asset_qs = Asset.objects.filter(q).distinct()
|
asset_qs = Asset.objects.filter(q).distinct()
|
||||||
return asset_qs
|
return asset_qs
|
||||||
|
|
||||||
|
|
||||||
def get_direct_granted_node_assets_from_perm(user: User, key):
|
def get_direct_granted_node_assets_from_perm(user: User, key, asset_perms_id=None):
|
||||||
node_ids = get_direct_granted_node_ids(user, key)
|
node_ids = get_direct_granted_node_ids(user, key, asset_perms_id)
|
||||||
asset_qs = Asset.objects.filter(nodes__id__in=node_ids).distinct()
|
asset_qs = Asset.objects.filter(nodes__id__in=node_ids).distinct()
|
||||||
return asset_qs
|
return asset_qs
|
||||||
|
|
||||||
|
|
||||||
def count_node_all_granted_assets(user: User, key):
|
def count_node_all_granted_assets(user: User, key, asset_perms_id=None):
|
||||||
return get_node_all_granted_assets_from_perm(user, key).count()
|
return get_node_all_granted_assets_from_perm(user, key, asset_perms_id).count()
|
||||||
|
|
||||||
|
|
||||||
def count_direct_granted_node_assets(user: User, key):
|
def count_direct_granted_node_assets(user: User, key, asset_perms_id=None):
|
||||||
return get_direct_granted_node_assets_from_perm(user, key).count()
|
return get_direct_granted_node_assets_from_perm(user, key, asset_perms_id).count()
|
||||||
|
|
||||||
|
|
||||||
def get_indirect_granted_node_children(user, key=''):
|
def get_indirect_granted_node_children(user, key=''):
|
||||||
@@ -453,7 +450,7 @@ def get_top_level_granted_nodes(user):
|
|||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def get_user_all_assetpermission_ids(user: User):
|
def get_user_all_assetpermissions_id(user: User):
|
||||||
asset_perm_ids = set()
|
asset_perm_ids = set()
|
||||||
asset_perm_ids.update(
|
asset_perm_ids.update(
|
||||||
AssetPermission.objects.valid().filter(users=user).distinct().values_list('id', flat=True)
|
AssetPermission.objects.valid().filter(users=user).distinct().values_list('id', flat=True)
|
||||||
@@ -466,7 +463,7 @@ def get_user_all_assetpermission_ids(user: User):
|
|||||||
|
|
||||||
def get_user_direct_granted_assets(user, asset_perm_ids=None):
|
def get_user_direct_granted_assets(user, asset_perm_ids=None):
|
||||||
if asset_perm_ids is None:
|
if asset_perm_ids is None:
|
||||||
asset_perm_ids = get_user_all_assetpermission_ids(user)
|
asset_perm_ids = get_user_all_assetpermissions_id(user)
|
||||||
assets = Asset.org_objects.filter(granted_by_permissions__id__in=asset_perm_ids).distinct()
|
assets = Asset.org_objects.filter(granted_by_permissions__id__in=asset_perm_ids).distinct()
|
||||||
return assets
|
return assets
|
||||||
|
|
||||||
@@ -507,4 +504,7 @@ def rebuild_user_tree_if_need(request, user):
|
|||||||
rebuild_user_mapping_nodes_with_lock(user)
|
rebuild_user_mapping_nodes_with_lock(user)
|
||||||
except lock.SomeoneIsDoingThis:
|
except lock.SomeoneIsDoingThis:
|
||||||
# 您的数据正在初始化,请稍等
|
# 您的数据正在初始化,请稍等
|
||||||
raise lock.SomeoneIsDoingThis(detail=_('Please wait while your data is being initialized'))
|
raise lock.SomeoneIsDoingThis(
|
||||||
|
detail=_('Please wait while your data is being initialized'),
|
||||||
|
code='rebuild_tree_conflict'
|
||||||
|
)
|
||||||
|
|||||||
@@ -55,11 +55,13 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||||||
post_user_create.send(self.__class__, user=user)
|
post_user_create.send(self.__class__, user=user)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_users_to_org(users, org_roles):
|
def set_users_to_org(users, org_roles, update=False):
|
||||||
# 只有真实存在的组织才真正关联用户
|
# 只有真实存在的组织才真正关联用户
|
||||||
if not current_org or not current_org.is_real():
|
if not current_org or not current_org.is_real():
|
||||||
return
|
return
|
||||||
for user, roles in zip(users, org_roles):
|
for user, roles in zip(users, org_roles):
|
||||||
|
if update and roles is None:
|
||||||
|
continue
|
||||||
if not roles:
|
if not roles:
|
||||||
# 当前组织创建的用户,至少是该组织的`User`
|
# 当前组织创建的用户,至少是该组织的`User`
|
||||||
roles = [ORG_ROLE.USER]
|
roles = [ORG_ROLE.USER]
|
||||||
@@ -107,7 +109,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||||||
users = serializer.save()
|
users = serializer.save()
|
||||||
if isinstance(users, User):
|
if isinstance(users, User):
|
||||||
users = [users]
|
users = [users]
|
||||||
self.set_users_to_org(users, org_roles)
|
self.set_users_to_org(users, org_roles, update=True)
|
||||||
|
|
||||||
def perform_bulk_update(self, serializer):
|
def perform_bulk_update(self, serializer):
|
||||||
# TODO: 需要测试
|
# TODO: 需要测试
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ python-dateutil==2.6.1
|
|||||||
python-gssapi==0.6.4
|
python-gssapi==0.6.4
|
||||||
pytz==2018.3
|
pytz==2018.3
|
||||||
PyYAML==5.1
|
PyYAML==5.1
|
||||||
redis==3.2.0
|
redis==3.5.3
|
||||||
requests==2.22.0
|
requests==2.22.0
|
||||||
jms-storage==0.0.34
|
jms-storage==0.0.34
|
||||||
s3transfer==0.3.3
|
s3transfer==0.3.3
|
||||||
|
|||||||
Reference in New Issue
Block a user