mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' of github.com:jumpserver/jumpserver into dev
commit
a69bba8702
|
@ -60,6 +60,7 @@ class SerializeToTreeNodeMixin:
|
|||
'isParent': False,
|
||||
'open': False,
|
||||
'iconSkin': self.get_platform(asset),
|
||||
'chkDisabled': not asset.is_active,
|
||||
'meta': {
|
||||
'type': 'asset',
|
||||
'asset': {
|
||||
|
|
|
@ -9,9 +9,8 @@ from django.db.models.signals import (
|
|||
from django.db.models import Q, F
|
||||
from django.dispatch import receiver
|
||||
|
||||
from common.local import thread_local
|
||||
from common.exceptions import M2MReverseNotAllowed
|
||||
from common.const.signals import PRE_ADD, POST_ADD, POST_REMOVE, PRE_CLEAR
|
||||
from common.const.signals import PRE_ADD, POST_ADD, POST_REMOVE, PRE_CLEAR, PRE_REMOVE
|
||||
from common.utils import get_logger
|
||||
from common.decorator import on_transaction_commit
|
||||
from .models import Asset, SystemUser, Node, compute_parent_key
|
||||
|
@ -321,26 +320,26 @@ def update_nodes_assets_amount(action, instance, reverse, pk_set, **kwargs):
|
|||
_update_nodes_asset_amount(node_keys, asset_pk, operator)
|
||||
|
||||
|
||||
ASSET_DELETE_SIGNAL_FOR_NODE_TREE_PARAMS = 'asset_delete_signal_for_node_tree_params'
|
||||
RELATED_NODE_IDS = '_related_node_ids'
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=Asset)
|
||||
def on_asset_delete(instance: Asset, **kwargs):
|
||||
node_keys = Node.objects.filter(
|
||||
def on_asset_delete(instance: Asset, using, **kwargs):
|
||||
node_ids = set(Node.objects.filter(
|
||||
assets=instance
|
||||
).distinct().values_list('key', flat=True)
|
||||
|
||||
params = {
|
||||
'node_keys': set(node_keys),
|
||||
'asset_pk': instance.id,
|
||||
'operator': sub
|
||||
}
|
||||
|
||||
setattr(thread_local, ASSET_DELETE_SIGNAL_FOR_NODE_TREE_PARAMS, params)
|
||||
).distinct().values_list('id', flat=True))
|
||||
setattr(instance, RELATED_NODE_IDS, node_ids)
|
||||
m2m_changed.send(
|
||||
sender=Asset.nodes.through, instance=instance, reverse=False,
|
||||
model=Node, pk_set=node_ids, using=using, action=PRE_REMOVE
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Asset)
|
||||
def on_asset_post_delete(instance: Asset, **kwargs):
|
||||
params = getattr(thread_local, ASSET_DELETE_SIGNAL_FOR_NODE_TREE_PARAMS, None)
|
||||
if params and params.get('asset_pk') == instance.id:
|
||||
_update_nodes_asset_amount(**params)
|
||||
def on_asset_post_delete(instance: Asset, using, **kwargs):
|
||||
node_ids = getattr(instance, RELATED_NODE_IDS, None)
|
||||
if node_ids:
|
||||
m2m_changed.send(
|
||||
sender=Asset.nodes.through, instance=instance, reverse=False,
|
||||
model=Node, pk_set=node_ids, using=using, action=POST_REMOVE
|
||||
)
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
#
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.db.models import Q
|
||||
from rest_framework import status, generics
|
||||
from rest_framework import status
|
||||
from rest_framework.views import Response
|
||||
from rest_framework_bulk import BulkModelViewSet
|
||||
from rest_framework.mixins import CreateModelMixin
|
||||
|
||||
from common.permissions import IsSuperUserOrAppUser
|
||||
from common.drf.api import JMSBulkRelationModelViewSet
|
||||
from common.drf.api import JMSBulkRelationModelViewSet, JMSModelViewSet
|
||||
from .models import Organization, ROLE
|
||||
from .serializers import (
|
||||
OrgSerializer, OrgReadSerializer,
|
||||
|
|
|
@ -231,7 +231,7 @@ def _none2list(*args):
|
|||
|
||||
|
||||
def _users2pks(users, admins, auditors):
|
||||
return [user.pk for user in chain(users, admins, auditors)]
|
||||
return [user.pk for user in chain(users, admins, auditors) if hasattr(user, 'pk')]
|
||||
|
||||
|
||||
class UserRoleMapper(dict):
|
||||
|
@ -295,17 +295,17 @@ class OrgMemeberManager(models.Manager):
|
|||
)
|
||||
|
||||
oms_add = []
|
||||
for users, role in add_mapper:
|
||||
for user in users:
|
||||
if isinstance(user, models.Model):
|
||||
user = user.id
|
||||
oms_add.append(self.model(org_id=org.id, user_id=user, role=role))
|
||||
for _users, _role in add_mapper:
|
||||
for _user in _users:
|
||||
if isinstance(_user, models.Model):
|
||||
_user = _user.id
|
||||
oms_add.append(self.model(org_id=org.id, user_id=_user, role=_role))
|
||||
|
||||
send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False,
|
||||
model=User, pk_set=_users2pks(users, admins, auditors), using=self.db)
|
||||
|
||||
send(action='pre_add')
|
||||
self.bulk_create(oms_add)
|
||||
self.bulk_create(oms_add, ignore_conflicts=True)
|
||||
send(action='post_add')
|
||||
|
||||
def _get_remove_add_set(self, new_users, old_users):
|
||||
|
|
|
@ -43,6 +43,7 @@ class MyGrantedNodesWithAssetsAsTreeApi(SerializeToTreeNodeMixin, ListAPIView):
|
|||
all_nodes = get_user_granted_nodes_list_via_mapping_node(user)
|
||||
all_assets = get_user_granted_all_assets(user)
|
||||
all_assets = all_assets.annotate(parent_key=F('nodes__key'))
|
||||
all_assets = all_assets.prefetch_related('platform')
|
||||
|
||||
data = [
|
||||
*self.serialize_nodes(all_nodes, with_asset_amount=True),
|
||||
|
|
|
@ -75,7 +75,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
|
|||
model = Asset
|
||||
only_fields = [
|
||||
"id", "hostname", "ip", "protocols", "os", 'domain',
|
||||
"platform", "comment", "org_id",
|
||||
"platform", "comment", "org_id", "is_active"
|
||||
]
|
||||
fields = only_fields + ['org_name']
|
||||
read_only_fields = fields
|
||||
|
|
|
@ -37,12 +37,12 @@ def get_asset_system_users_id_with_actions(asset_perm_queryset: BasePermissionQu
|
|||
def get_asset_system_users_id_with_actions_by_user(user: User, asset: Asset):
|
||||
queryset = AssetPermission.objects.filter(
|
||||
Q(users=user) | Q(user_groups__users=user)
|
||||
)
|
||||
).valid()
|
||||
return get_asset_system_users_id_with_actions(queryset, asset)
|
||||
|
||||
|
||||
def get_asset_system_users_id_with_actions_by_group(group: UserGroup, asset: Asset):
|
||||
queryset = AssetPermission.objects.filter(
|
||||
user_groups=group
|
||||
)
|
||||
).valid()
|
||||
return get_asset_system_users_id_with_actions(queryset, asset)
|
||||
|
|
|
@ -17,7 +17,7 @@ from common.utils import get_logger
|
|||
from orgs.utils import current_org
|
||||
from orgs.models import ROLE as ORG_ROLE, OrganizationMember
|
||||
from .. import serializers
|
||||
from ..serializers import UserSerializer, UserRetrieveSerializer, MiniUserSerializer
|
||||
from ..serializers import UserSerializer, UserRetrieveSerializer, MiniUserSerializer, InviteSerializer
|
||||
from .mixins import UserQuerysetMixin
|
||||
from ..models import User
|
||||
from ..signals import post_user_create
|
||||
|
@ -38,7 +38,8 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||
serializer_classes = {
|
||||
'default': UserSerializer,
|
||||
'retrieve': UserRetrieveSerializer,
|
||||
'suggestion': MiniUserSerializer
|
||||
'suggestion': MiniUserSerializer,
|
||||
'invite': InviteSerializer,
|
||||
}
|
||||
extra_filter_backends = [OrgRoleUserFilterBackend]
|
||||
|
||||
|
@ -118,7 +119,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||
self.check_object_permissions(self.request, user)
|
||||
return super().perform_bulk_update(serializer)
|
||||
|
||||
@action(methods=['get'], detail=False, permission_classes=(IsOrgAdminOrAppUser,))
|
||||
@action(methods=['get'], detail=False, permission_classes=(IsOrgAdmin,))
|
||||
def suggestion(self, request):
|
||||
queryset = User.objects.exclude(role=User.ROLE.APP)
|
||||
queryset = self.filter_queryset(queryset)
|
||||
|
@ -132,6 +133,25 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||
serializer = self.get_serializer(queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(methods=['post'], detail=False, permission_classes=(IsOrgAdmin,))
|
||||
def invite(self, request):
|
||||
data = request.data
|
||||
if not isinstance(data, list):
|
||||
data = [request.data]
|
||||
if not current_org or not current_org.is_real():
|
||||
error = {"error": "Not a valid org"}
|
||||
return Response(error, status=400)
|
||||
|
||||
serializer_cls = self.get_serializer_class()
|
||||
serializer = serializer_cls(data=data, many=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
validated_data = serializer.validated_data
|
||||
for i in validated_data:
|
||||
i['org_id'] = current_org.org_id()
|
||||
relations = [OrganizationMember(**i) for i in validated_data]
|
||||
OrganizationMember.objects.bulk_create(relations, ignore_conflicts=True)
|
||||
return Response(serializer.data, status=201)
|
||||
|
||||
|
||||
class UserChangePasswordApi(UserQuerysetMixin, generics.RetrieveUpdateAPIView):
|
||||
permission_classes = (IsOrgAdmin,)
|
||||
|
|
|
@ -8,9 +8,8 @@ from rest_framework import serializers
|
|||
from common.utils import validate_ssh_public_key
|
||||
from common.mixins import CommonBulkSerializerMixin
|
||||
from common.permissions import CanUpdateDeleteUser
|
||||
from common.drf.fields import GroupConcatedPrimaryKeyRelatedField
|
||||
from orgs.models import ROLE as ORG_ROLE
|
||||
from ..models import User, UserGroup
|
||||
from ..models import User
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
@ -18,7 +17,7 @@ __all__ = [
|
|||
'ChangeUserPasswordSerializer', 'ResetOTPSerializer',
|
||||
'UserProfileSerializer', 'UserOrgSerializer',
|
||||
'UserUpdatePasswordSerializer', 'UserUpdatePublicKeySerializer',
|
||||
'UserRetrieveSerializer', 'MiniUserSerializer',
|
||||
'UserRetrieveSerializer', 'MiniUserSerializer', 'InviteSerializer'
|
||||
]
|
||||
|
||||
|
||||
|
@ -339,3 +338,10 @@ class MiniUserSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = User
|
||||
fields = ['id', 'name', 'username']
|
||||
|
||||
|
||||
class InviteSerializer(serializers.Serializer):
|
||||
user = serializers.PrimaryKeyRelatedField(
|
||||
queryset=User.objects.exclude(role=User.ROLE.APP)
|
||||
)
|
||||
role = serializers.ChoiceField(choices=ORG_ROLE.choices)
|
||||
|
|
Loading…
Reference in New Issue