perf: Connect methods acl allow accept action

pull/15972/head
wangruidong 2025-09-02 17:22:36 +08:00 committed by 老广
parent ae9956ff91
commit 4f79abe678
4 changed files with 32 additions and 60 deletions

View File

@ -1,4 +1,4 @@
from common.serializers import CommonBulkModelSerializer from common.serializers.mixin import CommonBulkModelSerializer
from .base import BaseUserAssetAccountACLSerializer as BaseSerializer from .base import BaseUserAssetAccountACLSerializer as BaseSerializer
from ..const import ActionChoices from ..const import ActionChoices
from ..models import ConnectMethodACL from ..models import ConnectMethodACL
@ -11,11 +11,10 @@ class ConnectMethodACLSerializer(BaseSerializer, CommonBulkModelSerializer):
model = ConnectMethodACL model = ConnectMethodACL
fields = [ fields = [
i for i in BaseSerializer.Meta.fields + ['connect_methods'] 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 + [ action_choices_exclude = BaseSerializer.Meta.action_choices_exclude + [
ActionChoices.review, ActionChoices.review,
ActionChoices.accept,
ActionChoices.notice, ActionChoices.notice,
ActionChoices.face_verify, ActionChoices.face_verify,
ActionChoices.face_online, ActionChoices.face_online,

View File

@ -1,7 +1,7 @@
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from common.serializers import CommonBulkModelSerializer
from common.serializers import MethodSerializer from common.serializers import MethodSerializer
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from .base import BaseUserACLSerializer from .base import BaseUserACLSerializer
from .rules import RuleSerializer from .rules import RuleSerializer
from ..const import ActionChoices from ..const import ActionChoices
@ -12,12 +12,12 @@ __all__ = ["LoginACLSerializer"]
common_help_text = _("With * indicating a match all. ") common_help_text = _("With * indicating a match all. ")
class LoginACLSerializer(BaseUserACLSerializer): class LoginACLSerializer(BaseUserACLSerializer, CommonBulkModelSerializer):
rules = MethodSerializer(label=_('Rule')) rules = MethodSerializer(label=_('Rule'))
class Meta(BaseUserACLSerializer.Meta): class Meta(BaseUserACLSerializer.Meta):
model = LoginACL model = LoginACL
fields = BaseUserACLSerializer.Meta.fields + ['rules', ] fields = list((set(BaseUserACLSerializer.Meta.fields) | {'rules'}) - {'org_id'})
action_choices_exclude = [ action_choices_exclude = [
ActionChoices.warning, ActionChoices.warning,
ActionChoices.notify_and_warn, ActionChoices.notify_and_warn,

View File

@ -5,7 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Model from django.db.models import Model
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers 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.db.fields import TreeChoices, JSONManyToManyField as ModelJSONManyToManyField
from common.utils import decrypt_password, is_uuid from common.utils import decrypt_password, is_uuid
@ -54,54 +54,19 @@ class EncryptedField(serializers.CharField):
class LabeledChoiceField(serializers.ChoiceField): class LabeledChoiceField(serializers.ChoiceField):
def __init__(self, **kwargs): def to_representation(self, key):
self.attrs = kwargs.pop("attrs", None) or ("value", "label") if key is None:
super().__init__(**kwargs) return key
label = self.choices.get(key, key)
def to_representation(self, value): return {"value": key, "label": label}
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_internal_value(self, data): def to_internal_value(self, data):
if not data:
return data
if isinstance(data, dict): if isinstance(data, dict):
return data.get("value") or data.get("label") data = data.get("value")
return data
def get_schema(self): if isinstance(data, str) and "(" in data and data.endswith(")"):
""" data = data.strip(")").split('(')[-1]
drf-spectacular 提供 OpenAPI schema return super(LabeledChoiceField, self).to_internal_value(data)
"""
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', ''),
}
class LabeledMultipleChoiceField(serializers.MultipleChoiceField): class LabeledMultipleChoiceField(serializers.MultipleChoiceField):
@ -221,7 +186,7 @@ class ObjectRelatedField(serializers.RelatedField):
""" """
# 获取字段的基本信息 # 获取字段的基本信息
field_type = 'array' if self.many else 'object' field_type = 'array' if self.many else 'object'
if field_type == 'array': if field_type == 'array':
# 如果是多对多关系 # 如果是多对多关系
return { return {
@ -250,7 +215,7 @@ class ObjectRelatedField(serializers.RelatedField):
获取对象的 OpenAPI schema 获取对象的 OpenAPI schema
""" """
properties = {} properties = {}
# 动态分析 attrs 中的属性类型 # 动态分析 attrs 中的属性类型
for attr in self.attrs: for attr in self.attrs:
# 尝试从 queryset 的 model 中获取字段信息 # 尝试从 queryset 的 model 中获取字段信息
@ -259,7 +224,7 @@ class ObjectRelatedField(serializers.RelatedField):
'type': field_type, 'type': field_type,
'description': f'{attr} field' 'description': f'{attr} field'
} }
return { return {
'type': 'object', 'type': 'object',
'properties': properties, 'properties': properties,
@ -280,7 +245,7 @@ class ObjectRelatedField(serializers.RelatedField):
return self._map_django_field_type(field) return self._map_django_field_type(field)
except Exception: except Exception:
pass pass
# 如果没有 queryset 或无法获取字段信息,使用启发式规则 # 如果没有 queryset 或无法获取字段信息,使用启发式规则
return self._heuristic_field_type(attr_name) return self._heuristic_field_type(attr_name)
@ -289,7 +254,7 @@ class ObjectRelatedField(serializers.RelatedField):
Django 字段类型映射到 OpenAPI 类型 Django 字段类型映射到 OpenAPI 类型
""" """
field_type = type(field).__name__ field_type = type(field).__name__
# 整数类型 # 整数类型
if 'Integer' in field_type or 'BigInteger' in field_type or 'SmallInteger' in field_type: if 'Integer' in field_type or 'BigInteger' in field_type or 'SmallInteger' in field_type:
return 'integer' return 'integer'
@ -314,7 +279,7 @@ class ObjectRelatedField(serializers.RelatedField):
启发式推断字段类型 启发式推断字段类型
""" """
# 基于属性名的启发式规则 # 基于属性名的启发式规则
if attr_name in ['is_active', 'enabled', 'visible'] or attr_name.startswith('is_'): if attr_name in ['is_active', 'enabled', 'visible'] or attr_name.startswith('is_'):
return 'boolean' return 'boolean'
elif attr_name in ['count', 'number', 'size', 'amount']: elif attr_name in ['count', 'number', 'size', 'amount']:

View File

@ -240,9 +240,17 @@ class ConnectMethodUtil:
def get_user_allowed_connect_methods(cls, os, user): def get_user_allowed_connect_methods(cls, os, user):
from acls.models import ConnectMethodACL from acls.models import ConnectMethodACL
methods = cls.get_filtered_protocols_connect_methods(os) methods = cls.get_filtered_protocols_connect_methods(os)
acls = ConnectMethodACL.get_user_acls(user) accept_methods = set(itertools.chain.from_iterable(
disabled_connect_methods = acls.values_list('connect_methods', flat=True) ConnectMethodACL.get_user_acls(user)
disabled_connect_methods = set(itertools.chain.from_iterable(disabled_connect_methods)) .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 = {} new_queryset = {}
for protocol, methods in methods.items(): for protocol, methods in methods.items():