未验证 提交 164f48e1 编写于 作者: 老广 提交者: GitHub

Dev beta (#3048)

* [Update] 统一url地址

* [Update] 修改api

* [Update] 使用规范的签名

* [Update] 修改url

* [Update] 修改swagger

* [Update] 添加serializer class避免报错

* [Update] 修改token

* [Update] 支持api key

* [Update] 支持生成api key

* [Update] 修改api重定向

* [Update] 修改翻译

* [Update] 添加说明文档

* [Update] 修复浏览器关闭后session不失效的问题

* [Update] 修改一些内容

* [Update] 修改 jms脚本

* [Update] 修改重定向

* [Update] 修改搜索trim

* [Update] 修改搜索trim

* [Update] 添加sys log

* [Bugfix] 修改登陆错误

* [Update] 优化User操作private_token的接口 (#3091)

* [Update] 优化User操作private_token的接口

* [Update] 优化User操作private_token的接口 2

* [Bugfix] 解决授权了一个节点,当移动节点后,被移动的节点下的资产会放到未分组节点下的问题

* [Update] 升级jquery

* [Update] 默认使用page

* [Update] 修改使用Orgmodel view set

* [Update] 支持 nv的硬盘 https://github.com/jumpserver/jumpserver/issues/1804

* [UPdate] 解决命令执行宽度问题

* [Update] 优化节点

* [Update] 修改nodes过多时创建比较麻烦

* [Update] 修改导入

* [Update] 节点获取更新

* [Update] 修改nodes

* [Update] nodes显示full value

* [Update] 统一使用nodes select2 函数

* [Update] 修改磁盘大小小数

* [Update] 修改 Node service

* [Update] 优化授权节点

* [Update] 修改 node permission

* [Update] 修改asset permission

* [Stash]

* [Update] 修改node assets api

* [Update] 修改tree service,支持资产数量

* [Update] 修改暂时完成

* [Update] 修改一些bug
上级 fe6f7bcf
......@@ -3,9 +3,8 @@
from rest_framework import generics
from rest_framework.pagination import LimitOffsetPagination
from rest_framework_bulk import BulkModelViewSet
from orgs.mixins.api import OrgBulkModelViewSet
from ..hands import IsOrgAdmin, IsAppUser
from ..models import RemoteApp
from ..serializers import RemoteAppSerializer, RemoteAppConnectionInfoSerializer
......@@ -16,13 +15,12 @@ __all__ = [
]
class RemoteAppViewSet(BulkModelViewSet):
class RemoteAppViewSet(OrgBulkModelViewSet):
filter_fields = ('name',)
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
queryset = RemoteApp.objects.all()
serializer_class = RemoteAppSerializer
pagination_class = LimitOffsetPagination
class RemoteAppConnectionInfoApi(generics.RetrieveAPIView):
......
......@@ -4,7 +4,7 @@
from django.utils.translation import ugettext as _
from django import forms
from orgs.mixins import OrgModelForm
from orgs.mixins.forms import OrgModelForm
from assets.models import SystemUser
from ..models import RemoteApp
......
......@@ -5,7 +5,7 @@ import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from orgs.mixins import OrgModelMixin
from orgs.mixins.models import OrgModelMixin
from common.fields.model import EncryptJsonDictTextField
from .. import const
......
......@@ -5,7 +5,7 @@
from rest_framework import serializers
from common.serializers import AdaptedBulkListSerializer
from orgs.mixins import BulkOrgResourceModelSerializer
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from .. import const
from ..models import RemoteApp
......
# coding:utf-8
#
from django.urls import path
from django.urls import path, re_path
from rest_framework_bulk.routes import BulkRouter
from common import api as capi
from .. import api
app_name = 'applications'
router = BulkRouter()
router.register(r'remote-app', api.RemoteAppViewSet, 'remote-app')
router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app')
urlpatterns = [
path('remote-apps/<uuid:pk>/connection-info/',
api.RemoteAppConnectionInfoApi.as_view(),
name='remote-app-connection-info')
]
old_version_urlpatterns = [
re_path('(?P<resource>remote-app)/.*', capi.redirect_plural_name_api)
]
urlpatterns += router.urls
urlpatterns += router.urls + old_version_urlpatterns
......@@ -17,8 +17,7 @@ from django.db import transaction
from django.shortcuts import get_object_or_404
from rest_framework import generics
from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
from rest_framework.pagination import LimitOffsetPagination
from orgs.mixins.api import OrgBulkModelViewSet
from common.mixins import IDInCacheFilterMixin
from common.utils import get_logger
......@@ -36,7 +35,7 @@ __all__ = [
]
class AdminUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
class AdminUserViewSet(OrgBulkModelViewSet):
"""
Admin user api set, for add,delete,update,list,retrieve resource
"""
......@@ -46,11 +45,6 @@ class AdminUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
queryset = AdminUser.objects.all()
serializer_class = serializers.AdminUserSerializer
permission_classes = (IsOrgAdmin,)
pagination_class = LimitOffsetPagination
def get_queryset(self):
queryset = super().get_queryset().all()
return queryset
class AdminUserAuthApi(generics.UpdateAPIView):
......@@ -98,7 +92,6 @@ class AdminUserTestConnectiveApi(generics.RetrieveAPIView):
class AdminUserAssetsListView(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.AssetSimpleSerializer
pagination_class = LimitOffsetPagination
filter_fields = ("hostname", "ip")
http_method_names = ['get']
search_fields = filter_fields
......
# -*- coding: utf-8 -*-
#
import uuid
import random
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
from rest_framework.pagination import LimitOffsetPagination
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.core.cache import cache
from django.db.models import Q
from common.mixins import IDInCacheFilterMixin, ApiMessageMixin
from common.utils import get_logger, get_object_or_none
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from orgs.mixins import OrgBulkModelViewSet
from ..const import CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX
from orgs.mixins.api import OrgBulkModelViewSet
from ..models import Asset, AdminUser, Node
from .. import serializers
from ..tasks import update_asset_hardware_info_manual, \
......@@ -31,9 +21,9 @@ from ..utils import LabelFilter
logger = get_logger(__file__)
__all__ = [
'AssetViewSet', 'AssetListUpdateApi',
'AssetViewSet',
'AssetRefreshHardwareApi', 'AssetAdminUserTestApi',
'AssetGatewayApi', 'AssetBulkUpdateSelectAPI'
'AssetGatewayApi',
]
......@@ -46,7 +36,6 @@ class AssetViewSet(LabelFilter, OrgBulkModelViewSet):
ordering_fields = ("hostname", "ip", "port", "cpu_cores")
queryset = Asset.objects.all()
serializer_class = serializers.AssetSerializer
pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser,)
success_message = _("%(hostname)s was %(action)s successfully")
......@@ -73,19 +62,21 @@ class AssetViewSet(LabelFilter, OrgBulkModelViewSet):
node = get_object_or_404(Node, id=node_id)
show_current_asset = self.request.query_params.get("show_current_asset") in ('1', 'true')
# 当前节点是顶层节点, 并且仅显示直接资产
if node.is_root() and show_current_asset:
queryset = queryset.filter(
Q(nodes=node_id) | Q(nodes__isnull=True)
)
).distinct()
# 当前节点是顶层节点,显示所有资产
elif node.is_root() and not show_current_asset:
pass
return queryset
# 当前节点不是鼎城节点,只显示直接资产
elif not node.is_root() and show_current_asset:
queryset = queryset.filter(nodes=node)
else:
queryset = queryset.filter(
nodes__key__regex='^{}(:[0-9]+)*$'.format(node.key),
)
return queryset.distinct()
children = node.get_all_children(with_self=True)
queryset = queryset.filter(nodes__in=children).distinct()
return queryset
def filter_admin_user_id(self, queryset):
admin_user_id = self.request.query_params.get('admin_user_id')
......@@ -102,30 +93,6 @@ class AssetViewSet(LabelFilter, OrgBulkModelViewSet):
return queryset
class AssetListUpdateApi(IDInCacheFilterMixin, ListBulkCreateUpdateDestroyAPIView):
"""
Asset bulk update api
"""
queryset = Asset.objects.all()
serializer_class = serializers.AssetSerializer
permission_classes = (IsOrgAdmin,)
class AssetBulkUpdateSelectAPI(APIView):
permission_classes = (IsOrgAdmin,)
def post(self, request, *args, **kwargs):
assets_id = request.data.get('assets_id', '')
if assets_id:
spm = uuid.uuid4().hex
key = CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX.format(spm)
cache.set(key, assets_id, 300)
url = reverse_lazy('assets:asset-bulk-update') + '?spm=%s' % spm
return Response({'url': url})
error = _('Please select assets that need to be updated')
return Response({'error': error}, status=400)
class AssetRefreshHardwareApi(generics.RetrieveAPIView):
"""
Refresh asset hardware info
......
......@@ -2,11 +2,11 @@
#
from rest_framework.response import Response
from rest_framework import viewsets, status, generics
from rest_framework.pagination import LimitOffsetPagination
from rest_framework import generics
from rest_framework import filters
from rest_framework_bulk import BulkModelViewSet
from django.shortcuts import get_object_or_404
from django.http import Http404
from common.permissions import IsOrgAdminOrAppUser, NeedMFAVerify
from common.utils import get_object_or_none, get_logger
......@@ -53,7 +53,6 @@ class AssetUserSearchBackend(filters.BaseFilterBackend):
class AssetUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
pagination_class = LimitOffsetPagination
serializer_class = serializers.AssetUserSerializer
permission_classes = [IsOrgAdminOrAppUser]
http_method_names = ['get', 'post']
......@@ -67,6 +66,9 @@ class AssetUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
AssetUserFilterBackend, AssetUserSearchBackend,
)
def allow_bulk_destroy(self, qs, filtered):
return False
def get_queryset(self):
# 尽可能先返回更少的数据
username = self.request.GET.get('username')
......@@ -115,14 +117,6 @@ class AssetUserAuthInfoApi(generics.RetrieveAPIView):
serializer_class = serializers.AssetUserAuthInfoSerializer
permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
status_code = status.HTTP_200_OK
if not instance:
status_code = status.HTTP_400_BAD_REQUEST
return Response(serializer.data, status=status_code)
def get_object(self):
query_params = self.request.query_params
username = query_params.get('username')
......@@ -133,8 +127,7 @@ class AssetUserAuthInfoApi(generics.RetrieveAPIView):
manger = AssetUserManager()
instance = manger.get(username, asset, prefer=prefer)
except Exception as e:
logger.error(e, exc_info=True)
return None
raise Http404("Not found")
else:
return instance
......
# -*- coding: utf-8 -*-
#
from rest_framework_bulk import BulkModelViewSet
from rest_framework.pagination import LimitOffsetPagination
from django.shortcuts import get_object_or_404
from orgs.mixins.api import OrgBulkModelViewSet
from ..hands import IsOrgAdmin
from ..models import CommandFilter, CommandFilterRule
from .. import serializers
......@@ -13,21 +12,19 @@ from .. import serializers
__all__ = ['CommandFilterViewSet', 'CommandFilterRuleViewSet']
class CommandFilterViewSet(BulkModelViewSet):
class CommandFilterViewSet(OrgBulkModelViewSet):
filter_fields = ("name",)
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
queryset = CommandFilter.objects.all()
serializer_class = serializers.CommandFilterSerializer
pagination_class = LimitOffsetPagination
class CommandFilterRuleViewSet(BulkModelViewSet):
class CommandFilterRuleViewSet(OrgBulkModelViewSet):
filter_fields = ("content",)
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.CommandFilterRuleSerializer
pagination_class = LimitOffsetPagination
def get_queryset(self):
fpk = self.kwargs.get('filter_pk')
......
# ~*~ coding: utf-8 ~*~
from rest_framework_bulk import BulkModelViewSet
from rest_framework.views import APIView, Response
from rest_framework.pagination import LimitOffsetPagination
from django.views.generic.detail import SingleObjectMixin
from common.utils import get_logger
from common.permissions import IsOrgAdmin, IsAppUser, IsOrgAdminOrAppUser
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from orgs.mixins.api import OrgBulkModelViewSet
from ..models import Domain, Gateway
from .. import serializers
......@@ -16,11 +14,10 @@ logger = get_logger(__file__)
__all__ = ['DomainViewSet', 'GatewayViewSet', "GatewayTestConnectionApi"]
class DomainViewSet(BulkModelViewSet):
class DomainViewSet(OrgBulkModelViewSet):
queryset = Domain.objects.all()
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.DomainSerializer
pagination_class = LimitOffsetPagination
def get_queryset(self):
queryset = super().get_queryset().all()
......@@ -37,13 +34,12 @@ class DomainViewSet(BulkModelViewSet):
return super().get_permissions()
class GatewayViewSet(BulkModelViewSet):
class GatewayViewSet(OrgBulkModelViewSet):
filter_fields = ("domain__name", "name", "username", "ip", "domain")
search_fields = filter_fields
queryset = Gateway.objects.all()
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.GatewaySerializer
pagination_class = LimitOffsetPagination
class GatewayTestConnectionApi(SingleObjectMixin, APIView):
......
......@@ -13,11 +13,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from rest_framework.pagination import LimitOffsetPagination
from django.db.models import Count
from common.utils import get_logger
from orgs.mixins import OrgBulkModelViewSet
from orgs.mixins.api import OrgBulkModelViewSet
from ..hands import IsOrgAdmin
from ..models import Label
from .. import serializers
......@@ -32,7 +31,6 @@ class LabelViewSet(OrgBulkModelViewSet):
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.LabelSerializer
pagination_class = LimitOffsetPagination
def list(self, request, *args, **kwargs):
if request.query_params.get("distinct"):
......
......@@ -13,7 +13,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from rest_framework import generics, mixins, viewsets
import time
from rest_framework import generics
from rest_framework.serializers import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
......@@ -22,11 +24,11 @@ from django.shortcuts import get_object_or_404
from common.utils import get_logger, get_object_or_none
from common.tree import TreeNodeSerializer
from orgs.mixins.api import OrgModelViewSet
from ..hands import IsOrgAdmin
from ..models import Node
from ..tasks import update_assets_hardware_info_util, test_asset_connectivity_util
from .. import serializers
from ..utils import NodeUtil
logger = get_logger(__file__)
......@@ -39,29 +41,25 @@ __all__ = [
]
class NodeViewSet(viewsets.ModelViewSet):
filter_fields = ('value', 'key', )
search_fields = filter_fields
class NodeViewSet(OrgModelViewSet):
filter_fields = ('value', 'key', 'id')
search_fields = ('value', )
queryset = Node.objects.all()
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.NodeSerializer
# 仅支持根节点指直接创建,子节点下的节点需要通过children接口创建
def perform_create(self, serializer):
child_key = Node.root().get_next_child_key()
serializer.validated_data["key"] = child_key
serializer.save()
def update(self, request, *args, **kwargs):
def perform_update(self, serializer):
node = self.get_object()
if node.is_root():
node_value = node.value
post_value = request.data.get('value')
if node_value != post_value:
return Response(
{"msg": _("You can't update the root node name")},
status=400
)
return super().update(request, *args, **kwargs)
if node.is_root() and node.value != serializer.validated_data['value']:
msg = _("You can't update the root node name")
raise ValidationError({"error": msg})
return super().perform_update(serializer)
class NodeListAsTreeApi(generics.ListAPIView):
......@@ -79,21 +77,72 @@ class NodeListAsTreeApi(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = TreeNodeSerializer
@staticmethod
def to_tree_queryset(queryset):
queryset = [node.as_tree_node() for node in queryset]
return queryset
def get_queryset(self):
queryset = Node.objects.all()
util = NodeUtil()
nodes = util.get_nodes_by_queryset(queryset)
queryset = [node.as_tree_node() for node in nodes]
return queryset
@staticmethod
def refresh_nodes(queryset):
Node.expire_nodes_assets_amount()
Node.expire_nodes_full_value()
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
queryset = self.to_tree_queryset(queryset)
return queryset
class NodeChildrenApi(generics.ListCreateAPIView):
queryset = Node.objects.all()
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.NodeSerializer
instance = None
def initial(self, request, *args, **kwargs):
self.instance = self.get_object()
return super().initial(request, *args, **kwargs)
def perform_create(self, serializer):
data = serializer.validated_data
_id = data.get("id")
value = data.get("value")
if not value:
value = self.instance.get_next_child_preset_name()
node = self.instance.create_child(value=value, _id=_id)
# 避免查询 full value
node._full_value = node.value
serializer.instance = node
def get_object(self):
pk = self.kwargs.get('pk') or self.request.query_params.get('id')
key = self.request.query_params.get("key")
if not pk and not key:
node = Node.root()
return node
if pk:
node = get_object_or_404(Node, pk=pk)
else:
node = get_object_or_404(Node, key=key)
return node
def get_queryset(self):
query_all = self.request.query_params.get("all", "0") == "all"
if not self.instance:
return Node.objects.none()
if self.instance.is_root():
with_self = True
else:
with_self = False
if query_all:
queryset = self.instance.get_all_children(with_self=with_self)
else:
queryset = self.instance.get_children(with_self=with_self)
return queryset
class NodeChildrenAsTreeApi(generics.ListAPIView):
class NodeChildrenAsTreeApi(NodeChildrenApi):
"""
节点子节点作为树返回,
[
......@@ -106,39 +155,26 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
]
"""
permission_classes = (IsOrgAdmin,)
serializer_class = TreeNodeSerializer
node = None
is_root = False
http_method_names = ['get']
def get_queryset(self):
self.check_need_refresh_nodes()
node_key = self.request.query_params.get('key')
util = NodeUtil()
# 是否包含自己
with_self = False
if not node_key:
node_key = Node.root().key
with_self = True
self.node = util.get_node_by_key(node_key)
queryset = self.node.get_children(with_self=with_self)
queryset = super().get_queryset()
queryset = [node.as_tree_node() for node in queryset]
queryset = self.add_assets_if_need(queryset)
queryset = sorted(queryset)
return queryset
def filter_assets(self, queryset):
def add_assets_if_need(self, queryset):
include_assets = self.request.query_params.get('assets', '0') == '1'
if not include_assets:
return queryset
assets = self.node.get_assets().only(
"id", "hostname", "ip", 'platform', "os", "org_id", "protocols",
assets = self.instance.get_assets().only(
"id", "hostname", "ip", 'platform', "os",
"org_id", "protocols",
)
for asset in assets:
queryset.append(asset.as_tree_node(self.node))
return queryset
def filter_queryset(self, queryset):
queryset = self.filter_assets(queryset)
queryset.append(asset.as_tree_node(self.instance))
return queryset
def check_need_refresh_nodes(self):
......@@ -146,59 +182,6 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
Node.refresh_nodes()
class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
queryset = Node.objects.all()
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.NodeSerializer
instance = None