mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-09-09 11:19:08 +00:00
perf: Connect methods acl allow accept action
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from common.serializers import CommonBulkModelSerializer
|
||||
from common.serializers.mixin import CommonBulkModelSerializer
|
||||
from .base import BaseUserAssetAccountACLSerializer as BaseSerializer
|
||||
from ..const import ActionChoices
|
||||
from ..models import ConnectMethodACL
|
||||
@@ -11,11 +11,10 @@ class ConnectMethodACLSerializer(BaseSerializer, CommonBulkModelSerializer):
|
||||
model = ConnectMethodACL
|
||||
fields = [
|
||||
i for i in BaseSerializer.Meta.fields + ['connect_methods']
|
||||
if i not in ['assets', 'accounts']
|
||||
if i not in ['assets', 'accounts', 'org_id']
|
||||
]
|
||||
action_choices_exclude = BaseSerializer.Meta.action_choices_exclude + [
|
||||
ActionChoices.review,
|
||||
ActionChoices.accept,
|
||||
ActionChoices.notice,
|
||||
ActionChoices.face_verify,
|
||||
ActionChoices.face_online,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from common.serializers import CommonBulkModelSerializer
|
||||
from common.serializers import MethodSerializer
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
from .base import BaseUserACLSerializer
|
||||
from .rules import RuleSerializer
|
||||
from ..const import ActionChoices
|
||||
@@ -12,12 +12,12 @@ __all__ = ["LoginACLSerializer"]
|
||||
common_help_text = _("With * indicating a match all. ")
|
||||
|
||||
|
||||
class LoginACLSerializer(BaseUserACLSerializer):
|
||||
class LoginACLSerializer(BaseUserACLSerializer, CommonBulkModelSerializer):
|
||||
rules = MethodSerializer(label=_('Rule'))
|
||||
|
||||
class Meta(BaseUserACLSerializer.Meta):
|
||||
model = LoginACL
|
||||
fields = BaseUserACLSerializer.Meta.fields + ['rules', ]
|
||||
fields = list((set(BaseUserACLSerializer.Meta.fields) | {'rules'}) - {'org_id'})
|
||||
action_choices_exclude = [
|
||||
ActionChoices.warning,
|
||||
ActionChoices.notify_and_warn,
|
||||
|
@@ -5,7 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db.models import Model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
from rest_framework.fields import ChoiceField, empty
|
||||
from rest_framework.fields import empty
|
||||
|
||||
from common.db.fields import TreeChoices, JSONManyToManyField as ModelJSONManyToManyField
|
||||
from common.utils import decrypt_password, is_uuid
|
||||
@@ -54,54 +54,19 @@ class EncryptedField(serializers.CharField):
|
||||
|
||||
|
||||
class LabeledChoiceField(serializers.ChoiceField):
|
||||
def __init__(self, **kwargs):
|
||||
self.attrs = kwargs.pop("attrs", None) or ("value", "label")
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def to_representation(self, value):
|
||||
if not value:
|
||||
return value
|
||||
data = {}
|
||||
for attr in self.attrs:
|
||||
if not hasattr(value, attr):
|
||||
continue
|
||||
data[attr] = getattr(value, attr)
|
||||
return data
|
||||
def to_representation(self, key):
|
||||
if key is None:
|
||||
return key
|
||||
label = self.choices.get(key, key)
|
||||
return {"value": key, "label": label}
|
||||
|
||||
def to_internal_value(self, data):
|
||||
if not data:
|
||||
return data
|
||||
if isinstance(data, dict):
|
||||
return data.get("value") or data.get("label")
|
||||
return data
|
||||
data = data.get("value")
|
||||
|
||||
def get_schema(self):
|
||||
"""
|
||||
为 drf-spectacular 提供 OpenAPI schema
|
||||
"""
|
||||
if getattr(self, 'many', False):
|
||||
return {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'value': {'type': 'string'},
|
||||
'label': {'type': 'string'}
|
||||
}
|
||||
},
|
||||
'description': getattr(self, 'help_text', ''),
|
||||
'title': getattr(self, 'label', ''),
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'value': {'type': 'string'},
|
||||
'label': {'type': 'string'}
|
||||
},
|
||||
'description': getattr(self, 'help_text', ''),
|
||||
'title': getattr(self, 'label', ''),
|
||||
}
|
||||
if isinstance(data, str) and "(" in data and data.endswith(")"):
|
||||
data = data.strip(")").split('(')[-1]
|
||||
return super(LabeledChoiceField, self).to_internal_value(data)
|
||||
|
||||
|
||||
class LabeledMultipleChoiceField(serializers.MultipleChoiceField):
|
||||
@@ -221,7 +186,7 @@ class ObjectRelatedField(serializers.RelatedField):
|
||||
"""
|
||||
# 获取字段的基本信息
|
||||
field_type = 'array' if self.many else 'object'
|
||||
|
||||
|
||||
if field_type == 'array':
|
||||
# 如果是多对多关系
|
||||
return {
|
||||
@@ -250,7 +215,7 @@ class ObjectRelatedField(serializers.RelatedField):
|
||||
获取对象的 OpenAPI schema
|
||||
"""
|
||||
properties = {}
|
||||
|
||||
|
||||
# 动态分析 attrs 中的属性类型
|
||||
for attr in self.attrs:
|
||||
# 尝试从 queryset 的 model 中获取字段信息
|
||||
@@ -259,7 +224,7 @@ class ObjectRelatedField(serializers.RelatedField):
|
||||
'type': field_type,
|
||||
'description': f'{attr} field'
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
'type': 'object',
|
||||
'properties': properties,
|
||||
@@ -280,7 +245,7 @@ class ObjectRelatedField(serializers.RelatedField):
|
||||
return self._map_django_field_type(field)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
# 如果没有 queryset 或无法获取字段信息,使用启发式规则
|
||||
return self._heuristic_field_type(attr_name)
|
||||
|
||||
@@ -289,7 +254,7 @@ class ObjectRelatedField(serializers.RelatedField):
|
||||
将 Django 字段类型映射到 OpenAPI 类型
|
||||
"""
|
||||
field_type = type(field).__name__
|
||||
|
||||
|
||||
# 整数类型
|
||||
if 'Integer' in field_type or 'BigInteger' in field_type or 'SmallInteger' in field_type:
|
||||
return 'integer'
|
||||
@@ -314,7 +279,7 @@ class ObjectRelatedField(serializers.RelatedField):
|
||||
启发式推断字段类型
|
||||
"""
|
||||
# 基于属性名的启发式规则
|
||||
|
||||
|
||||
if attr_name in ['is_active', 'enabled', 'visible'] or attr_name.startswith('is_'):
|
||||
return 'boolean'
|
||||
elif attr_name in ['count', 'number', 'size', 'amount']:
|
||||
|
@@ -240,9 +240,17 @@ class ConnectMethodUtil:
|
||||
def get_user_allowed_connect_methods(cls, os, user):
|
||||
from acls.models import ConnectMethodACL
|
||||
methods = cls.get_filtered_protocols_connect_methods(os)
|
||||
acls = ConnectMethodACL.get_user_acls(user)
|
||||
disabled_connect_methods = acls.values_list('connect_methods', flat=True)
|
||||
disabled_connect_methods = set(itertools.chain.from_iterable(disabled_connect_methods))
|
||||
accept_methods = set(itertools.chain.from_iterable(
|
||||
ConnectMethodACL.get_user_acls(user)
|
||||
.filter(action=ConnectMethodACL.ActionChoices.accept)
|
||||
.values_list('connect_methods', flat=True)
|
||||
))
|
||||
# 在禁用的基础上放行一些连接方法
|
||||
disabled_connect_methods = set(itertools.chain.from_iterable(
|
||||
ConnectMethodACL.get_user_acls(user)
|
||||
.filter(action=ConnectMethodACL.ActionChoices.reject)
|
||||
.values_list('connect_methods', flat=True)
|
||||
)) - accept_methods
|
||||
|
||||
new_queryset = {}
|
||||
for protocol, methods in methods.items():
|
||||
|
Reference in New Issue
Block a user