From 4f79abe6784c43cf00f9f8e70f80d306048f521c Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Tue, 2 Sep 2025 17:22:36 +0800 Subject: [PATCH] perf: Connect methods acl allow accept action --- apps/acls/serializers/connect_method.py | 5 +- apps/acls/serializers/login_acl.py | 6 +-- apps/common/serializers/fields.py | 67 ++++++------------------- apps/terminal/connect_methods.py | 14 ++++-- 4 files changed, 32 insertions(+), 60 deletions(-) diff --git a/apps/acls/serializers/connect_method.py b/apps/acls/serializers/connect_method.py index 514a4ae20..a1af15be0 100644 --- a/apps/acls/serializers/connect_method.py +++ b/apps/acls/serializers/connect_method.py @@ -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, diff --git a/apps/acls/serializers/login_acl.py b/apps/acls/serializers/login_acl.py index a9b677d9e..3d37b976d 100644 --- a/apps/acls/serializers/login_acl.py +++ b/apps/acls/serializers/login_acl.py @@ -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, diff --git a/apps/common/serializers/fields.py b/apps/common/serializers/fields.py index 38d261aa0..6fe4b2170 100644 --- a/apps/common/serializers/fields.py +++ b/apps/common/serializers/fields.py @@ -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']: diff --git a/apps/terminal/connect_methods.py b/apps/terminal/connect_methods.py index 779407c60..f136817df 100644 --- a/apps/terminal/connect_methods.py +++ b/apps/terminal/connect_methods.py @@ -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():