mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-10-23 00:38:39 +00:00
* feat: 添加 RBAC 应用模块 * feat: 添加 RBAC Model、API * feat: 添加 RBAC Model、API 2 * feat: 添加 RBAC Model、API 3 * feat: 添加 RBAC Model、API 4 * feat: RBAC * feat: RBAC * feat: RBAC * feat: RBAC * feat: RBAC * feat: RBAC 整理权限位 * feat: RBAC 整理权限位2 * feat: RBAC 整理权限位2 * feat: RBAC 整理权限位 * feat: RBAC 添加默认角色 * feat: RBAC 添加迁移文件;迁移用户角色->用户角色绑定 * feat: RBAC 添加迁移文件;迁移用户角色->用户角色绑定 * feat: RBAC 修改用户模块API * feat: RBAC 添加组织模块迁移文件 & 修改组织模块API * feat: RBAC 添加组织模块迁移文件 & 修改组织模块API * feat: RBAC 修改用户角色属性的使用 * feat: RBAC No.1 * xxx * perf: 暂存 * perf: ... * perf(rbac): 添加 perms 到 profile serializer 中 * stash * perf: 使用init * perf: 修改migrations * perf: rbac * stash * stash * pref: 修改rbac * stash it * stash: 先去修复其他bug * perf: 修改 role 添加 users * pref: 修改 RBAC Model * feat: 添加权限的 tree api * stash: 暂存一下 * stash: 暂存一下 * perf: 修改 model verbose name * feat: 添加model各种 verbose name * perf: 生成 migrations * perf: 优化权限位 * perf: 添加迁移脚本 * feat: 添加组织角色迁移 * perf: 添加迁移脚本 * stash * perf: 添加migrateion * perf: 暂存一下 * perf: 修改rbac * perf: stash it * fix: 迁移冲突 * fix: 迁移冲突 * perf: 暂存一下 * perf: 修改 rbac 逻辑 * stash: 暂存一下 * perf: 修改内置角色 * perf: 解决 root 组织的问题 * perf: stash it * perf: 优化 rbac * perf: 优化 rolebinding 处理 * perf: 完成用户离开组织的问题 * perf: 暂存一下 * perf: 修改翻译 * perf: 去掉了 IsSuperUser * perf: IsAppUser 去掉完成 * perf: 修改 connection token 的权限 * perf: 去掉导入的问题 * perf: perms define 格式,修改 app 用户 的全新啊 * perf: 修改 permission * perf: 去掉一些 org admin * perf: 去掉部分 org admin * perf: 再去掉点 org admin role * perf: 再去掉部分 org admin * perf: user 角色搜索 * perf: 去掉很多 js * perf: 添加权限位 * perf: 修改权限 * perf: 去掉一个 todo * merge: with dev * fix: 修复冲突 Co-authored-by: Bai <bugatti_it@163.com> Co-authored-by: Michael Bai <baijiangjie@gmail.com> Co-authored-by: ibuler <ibuler@qq.com>
139 lines
4.7 KiB
Python
139 lines
4.7 KiB
Python
# coding: utf-8
|
|
#
|
|
|
|
from rest_framework import viewsets, generics, status
|
|
from rest_framework.response import Response
|
|
from rest_framework.request import Request
|
|
from rest_framework.decorators import action
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django_filters import utils
|
|
|
|
from terminal import const
|
|
from common.const.http import GET
|
|
from terminal.filters import CommandStorageFilter, CommandFilter, CommandFilterForStorageTree
|
|
from ..models import CommandStorage, ReplayStorage
|
|
from ..serializers import CommandStorageSerializer, ReplayStorageSerializer
|
|
|
|
|
|
__all__ = [
|
|
'CommandStorageViewSet', 'CommandStorageTestConnectiveApi',
|
|
'ReplayStorageViewSet', 'ReplayStorageTestConnectiveApi'
|
|
]
|
|
|
|
|
|
class BaseStorageViewSetMixin:
|
|
|
|
def destroy(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
if instance.type_null_or_server:
|
|
data = {'msg': _('Deleting the default storage is not allowed')}
|
|
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
|
if instance.is_use():
|
|
data = {'msg': _('Cannot delete storage that is being used')}
|
|
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
|
return super().destroy(request, *args, **kwargs)
|
|
|
|
|
|
class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
|
|
search_fields = ('name', 'type')
|
|
queryset = CommandStorage.objects.all()
|
|
serializer_class = CommandStorageSerializer
|
|
filterset_class = CommandStorageFilter
|
|
rbac_perms = {
|
|
'tree': 'terminal.view_commandstorage'
|
|
}
|
|
|
|
@action(methods=[GET], detail=False, filterset_class=CommandFilterForStorageTree)
|
|
def tree(self, request: Request):
|
|
storage_qs = self.get_queryset().exclude(name='null')
|
|
storages_with_count = []
|
|
invalid_storages = []
|
|
|
|
for storage in storage_qs:
|
|
if not storage.is_valid():
|
|
invalid_storages.append(storage)
|
|
continue
|
|
|
|
command_qs = storage.get_command_queryset()
|
|
filterset = CommandFilter(
|
|
data=request.query_params, queryset=command_qs,
|
|
request=request
|
|
)
|
|
if not filterset.is_valid():
|
|
raise utils.translate_validation(filterset.errors)
|
|
command_qs = filterset.qs
|
|
if storage.type == const.CommandStorageTypeChoices.es:
|
|
command_count = command_qs.count(limit_to_max_result_window=False)
|
|
else:
|
|
command_count = command_qs.count()
|
|
storages_with_count.append((storage, command_count))
|
|
|
|
root = {
|
|
'id': 'root',
|
|
'name': _('Command storages'),
|
|
'title': _('Command storages'),
|
|
'pId': '',
|
|
'isParent': True,
|
|
'open': True,
|
|
}
|
|
|
|
invalid = _('Invalid')
|
|
nodes = [
|
|
{
|
|
'id': storage.id,
|
|
'name': f'{storage.name}({storage.type})({command_count})',
|
|
'title': f'{storage.name}({storage.type})',
|
|
'pId': 'root',
|
|
'isParent': False,
|
|
'open': False,
|
|
'valid': True,
|
|
} for storage, command_count in storages_with_count
|
|
] + [
|
|
{
|
|
'id': storage.id,
|
|
'name': f'{storage.name}({storage.type}) *{invalid}',
|
|
'title': f'{storage.name}({storage.type})',
|
|
'pId': 'root',
|
|
'isParent': False,
|
|
'open': False,
|
|
'valid': False,
|
|
} for storage in invalid_storages
|
|
]
|
|
nodes.append(root)
|
|
return Response(data=nodes)
|
|
|
|
|
|
class ReplayStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
|
|
filterset_fields = ('name', 'type', 'is_default')
|
|
search_fields = filterset_fields
|
|
queryset = ReplayStorage.objects.all()
|
|
serializer_class = ReplayStorageSerializer
|
|
|
|
|
|
class BaseStorageTestConnectiveMixin:
|
|
def retrieve(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
try:
|
|
is_valid = instance.is_valid()
|
|
except Exception as e:
|
|
is_valid = False
|
|
msg = _("Test failure: {}".format(str(e)))
|
|
else:
|
|
if is_valid:
|
|
msg = _("Test successful")
|
|
else:
|
|
msg = _("Test failure: Account invalid")
|
|
data = {
|
|
'is_valid': is_valid,
|
|
'msg': msg
|
|
}
|
|
return Response(data)
|
|
|
|
|
|
class CommandStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
|
|
queryset = CommandStorage.objects.all()
|
|
|
|
|
|
class ReplayStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
|
|
queryset = ReplayStorage.objects.all()
|