diff --git a/src/bk-user/bkuser/apis/web/data_source/serializers.py b/src/bk-user/bkuser/apis/web/data_source/serializers.py index b94aeaac5..84c96dd50 100644 --- a/src/bk-user/bkuser/apis/web/data_source/serializers.py +++ b/src/bk-user/bkuser/apis/web/data_source/serializers.py @@ -33,6 +33,7 @@ class DataSourceSearchOutputSLZ(serializers.Serializer): id = serializers.IntegerField(help_text="数据源 ID") name = serializers.CharField(help_text="数据源名称") owner_tenant_id = serializers.CharField(help_text="数据源所属租户 ID") + plugin_id = serializers.CharField(help_text="数据源插件 ID") plugin_name = serializers.SerializerMethodField(help_text="数据源插件名称") cooperation_tenants = serializers.SerializerMethodField(help_text="协作公司") status = serializers.CharField(help_text="数据源状态") diff --git a/src/bk-user/bkuser/apis/web/data_source/views.py b/src/bk-user/bkuser/apis/web/data_source/views.py index b6d203580..b2582624d 100644 --- a/src/bk-user/bkuser/apis/web/data_source/views.py +++ b/src/bk-user/bkuser/apis/web/data_source/views.py @@ -27,6 +27,7 @@ from bkuser.apis.web.mixins import CurrentUserTenantMixin from bkuser.apps.data_source.constants import DataSourceStatus from bkuser.apps.data_source.models import DataSource, DataSourcePlugin +from bkuser.apps.data_source.plugins.constants import DATA_SOURCE_PLUGIN_CONFIG_SCHEMA_MAP from bkuser.apps.data_source.signals import post_create_data_source, post_update_data_source from bkuser.common.error_codes import error_codes from bkuser.common.views import ExcludePatchAPIViewMixin, ExcludePutAPIViewMixin @@ -77,7 +78,10 @@ def get(self, request, *args, **kwargs): tags=["data_source"], operation_description="新建数据源", request_body=DataSourceCreateInputSLZ(), - responses={status.HTTP_201_CREATED: DataSourceCreateOutputSLZ()}, + responses={ + status.HTTP_201_CREATED: DataSourceCreateOutputSLZ(), + **DATA_SOURCE_PLUGIN_CONFIG_SCHEMA_MAP, + }, ) def post(self, request, *args, **kwargs): slz = DataSourceCreateInputSLZ(data=request.data) @@ -115,7 +119,10 @@ def get_queryset(self): @swagger_auto_schema( tags=["data_source"], operation_description="数据源详情", - responses={status.HTTP_200_OK: DataSourceRetrieveOutputSLZ()}, + responses={ + status.HTTP_200_OK: DataSourceRetrieveOutputSLZ(), + **DATA_SOURCE_PLUGIN_CONFIG_SCHEMA_MAP, + }, ) def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) @@ -124,7 +131,10 @@ def get(self, request, *args, **kwargs): tags=["data_source"], operation_description="更新数据源", request_body=DataSourceUpdateInputSLZ(), - responses={status.HTTP_204_NO_CONTENT: ""}, + responses={ + status.HTTP_204_NO_CONTENT: "", + **DATA_SOURCE_PLUGIN_CONFIG_SCHEMA_MAP, + }, ) def put(self, request, *args, **kwargs): data_source = self.get_object() diff --git a/src/bk-user/bkuser/apps/data_source/plugins/constants.py b/src/bk-user/bkuser/apps/data_source/plugins/constants.py index 4b01d529d..159a1470a 100644 --- a/src/bk-user/bkuser/apps/data_source/plugins/constants.py +++ b/src/bk-user/bkuser/apps/data_source/plugins/constants.py @@ -11,8 +11,15 @@ from bkuser.apps.data_source.constants import DataSourcePluginEnum from bkuser.apps.data_source.plugins.local.models import LocalDataSourcePluginConfig +from bkuser.utils.pydantic import gen_openapi_schema # 数据源插件配置类映射表 DATA_SOURCE_PLUGIN_CONFIG_CLASS_MAP = { DataSourcePluginEnum.LOCAL: LocalDataSourcePluginConfig, } + +# 数据源插件配置类 JsonSchema 映射表 +DATA_SOURCE_PLUGIN_CONFIG_SCHEMA_MAP = { + f"plugin_config:{plugin_id}": gen_openapi_schema(model) + for plugin_id, model in DATA_SOURCE_PLUGIN_CONFIG_CLASS_MAP.items() +} diff --git a/src/bk-user/bkuser/utils/pydantic.py b/src/bk-user/bkuser/utils/pydantic.py index 97715d97c..da6016e6f 100644 --- a/src/bk-user/bkuser/utils/pydantic.py +++ b/src/bk-user/bkuser/utils/pydantic.py @@ -8,7 +8,12 @@ an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ -from pydantic import ValidationError +import json +from typing import Type + +import jsonref +from drf_yasg import openapi +from pydantic import BaseModel, ValidationError def stringify_pydantic_error(exc: ValidationError) -> str: @@ -26,3 +31,13 @@ def stringify_pydantic_error(exc: ValidationError) -> str: err_msgs.append(msg) return ", ".join(err_msgs) + + +def gen_openapi_schema(model: Type[BaseModel]) -> openapi.Schema: + """Convert pydantic model as drf_yasg openapi schema (without any jsonRef)""" + # Q: why need json dumps and jsonref.loads? + # A: according to https://github.com/pydantic/pydantic/issues/889 + # pydantic generate json schema with jsonRef, + # which is not compatible with drf_yasg.openapi.schema + json_schema = jsonref.loads(json.dumps(model.model_json_schema())) + return openapi.Schema(**json_schema) diff --git a/src/bk-user/poetry.lock b/src/bk-user/poetry.lock index bccd8fec0..68fe51750 100644 --- a/src/bk-user/poetry.lock +++ b/src/bk-user/poetry.lock @@ -1397,6 +1397,22 @@ type = "legacy" url = "https://mirrors.tencent.com/pypi/simple" reference = "tencent" +[[package]] +name = "jsonref" +version = "1.1.0" +description = "jsonref is a library for automatic dereferencing of JSON Reference objects for Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jsonref-1.1.0-py3-none-any.whl", hash = "sha256:590dc7773df6c21cbf948b5dac07a72a251db28b0238ceecce0a2abfa8ec30a9"}, + {file = "jsonref-1.1.0.tar.gz", hash = "sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552"}, +] + +[package.source] +type = "legacy" +url = "https://mirrors.tencent.com/pypi/simple" +reference = "tencent" + [[package]] name = "kombu" version = "5.3.1" @@ -3330,4 +3346,4 @@ reference = "tencent" [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.11" -content-hash = "a7c918d81d9696550a61de22f76461a66adcbfe14df738e758c327189114015c" +content-hash = "8621ce9c3c22fd0b4cb8804c34424cfef9559bc27dddf5a753029c59cf663a0d" diff --git a/src/bk-user/pyproject.toml b/src/bk-user/pyproject.toml index da5b7d0b5..af10a88ab 100644 --- a/src/bk-user/pyproject.toml +++ b/src/bk-user/pyproject.toml @@ -46,6 +46,7 @@ django-redis = "5.3.0" pydantic = "2.1.1" zxcvbn = "4.4.28" phonenumbers = "8.13.18" +jsonref = "1.1.0" [tool.poetry.group.dev.dependencies] ruff = "^0.0.277"