diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/admin.py b/src/dashboard/apigateway/apigateway/apps/gateway/admin.py new file mode 100644 index 000000000..ef53cc8b1 --- /dev/null +++ b/src/dashboard/apigateway/apigateway/apps/gateway/admin.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# +from django.contrib import admin + +from .models import GatewayAppBinding + + +class GatewayAppBindingAdmin(admin.ModelAdmin): + list_display = ["id", "gateway", "bk_app_code", "updated_time"] + search_fields = ["gateway__id", "bk_app_code"] + list_filter = ["gateway"] + + +admin.site.register(GatewayAppBinding, GatewayAppBindingAdmin) diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/apps.py b/src/dashboard/apigateway/apigateway/apps/gateway/apps.py new file mode 100644 index 000000000..d8a55cefc --- /dev/null +++ b/src/dashboard/apigateway/apigateway/apps/gateway/apps.py @@ -0,0 +1,22 @@ +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# +from django.apps import AppConfig + + +class GatewayConfig(AppConfig): + name = "apigateway.apps.gateway" diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/migrations/0001_initial.py b/src/dashboard/apigateway/apigateway/apps/gateway/migrations/0001_initial.py new file mode 100644 index 000000000..59d00fd5f --- /dev/null +++ b/src/dashboard/apigateway/apigateway/apps/gateway/migrations/0001_initial.py @@ -0,0 +1,49 @@ +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# +# Generated by Django 3.2.18 on 2023-11-08 03:52 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('core', '0032_gateway__developers'), + ] + + operations = [ + migrations.CreateModel( + name='GatewayAppBinding', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_time', models.DateTimeField(auto_now_add=True, null=True)), + ('updated_time', models.DateTimeField(auto_now=True, null=True)), + ('created_by', models.CharField(blank=True, max_length=32, null=True)), + ('updated_by', models.CharField(blank=True, max_length=32, null=True)), + ('bk_app_code', models.CharField(db_index=True, max_length=32)), + ('gateway', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.gateway')), + ], + options={ + 'db_table': 'gateway_app_binding', + 'unique_together': {('gateway', 'bk_app_code')}, + }, + ), + ] diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/migrations/__init__.py b/src/dashboard/apigateway/apigateway/apps/gateway/migrations/__init__.py new file mode 100644 index 000000000..2941673fe --- /dev/null +++ b/src/dashboard/apigateway/apigateway/apps/gateway/migrations/__init__.py @@ -0,0 +1,17 @@ +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/models.py b/src/dashboard/apigateway/apigateway/apps/gateway/models.py new file mode 100644 index 000000000..20ddee7eb --- /dev/null +++ b/src/dashboard/apigateway/apigateway/apps/gateway/models.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# +from django.db import models + +from apigateway.common.mixins.models import OperatorModelMixin, TimestampedModelMixin +from apigateway.core.models import Gateway + + +class GatewayAppBinding(TimestampedModelMixin, OperatorModelMixin): + """ + 网关绑定的蓝鲸应用 + - 仅影响 HomePage 中运维开发分数的计算 + """ + + gateway = models.ForeignKey(Gateway, on_delete=models.CASCADE) + bk_app_code = models.CharField(max_length=32, db_index=True) + + def __str__(self): + return f"" + + class Meta: + db_table = "gateway_app_binding" + unique_together = ("gateway", "bk_app_code") diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/serializers.py b/src/dashboard/apigateway/apigateway/apps/gateway/serializers.py index 9089031f7..b36071008 100644 --- a/src/dashboard/apigateway/apigateway/apps/gateway/serializers.py +++ b/src/dashboard/apigateway/apigateway/apps/gateway/serializers.py @@ -23,8 +23,15 @@ from tencent_apigateway_common.i18n.field import SerializerTranslatedField from apigateway.apps.gateway.utils import get_gateway_feature_flags +from apigateway.biz.gateway_app_binding import GatewayAppBindingHandler from apigateway.common.contexts import APIAuthContext, APIFeatureFlagContext -from apigateway.core.constants import API_NAME_PATTERN, APIHostingTypeEnum, APITypeEnum, UserAuthTypeEnum +from apigateway.core.constants import ( + API_NAME_PATTERN, + APP_CODE_PATTERN, + APIHostingTypeEnum, + APITypeEnum, + UserAuthTypeEnum, +) from apigateway.core.models import Gateway from apigateway.core.validators import ReservedAPINameValidator from apigateway.utils.crypto import calculate_fingerprint @@ -47,6 +54,11 @@ class GatewayCreateSLZ(serializers.ModelSerializer): choices=APIHostingTypeEnum.get_choices(), default=settings.DEFAULT_GATEWAY_HOSTING_TYPE, ) + bk_app_codes = serializers.ListField( + child=serializers.RegexField(APP_CODE_PATTERN), + allow_empty=True, + required=False, + ) class Meta: model = Gateway @@ -59,8 +71,9 @@ class Meta: "is_public", "user_auth_type", "hosting_type", + "bk_app_codes", ) - no_write_fields = ["user_auth_type"] + no_write_fields = ["user_auth_type", "bk_app_codes"] lookup_field = "id" # 使用 UniqueTogetherValidator,方便错误提示信息统一处理 @@ -96,6 +109,11 @@ def create(self, validated_data): class GatewayUpdateSLZ(serializers.ModelSerializer): maintainers = serializers.ListField(child=serializers.CharField(), allow_empty=True) developers = serializers.ListField(child=serializers.CharField(), allow_empty=True, default=list) + bk_app_codes = serializers.ListField( + child=serializers.RegexField(APP_CODE_PATTERN), + allow_empty=True, + required=False, + ) class Meta: model = Gateway @@ -104,6 +122,7 @@ class Meta: "maintainers", "developers", "is_public", + "bk_app_codes", ) lookup_field = "id" @@ -133,6 +152,7 @@ class GatewayDetailSLZ(serializers.ModelSerializer): max_length=512, required=False, ) + bk_app_codes = serializers.SerializerMethodField() class Meta: model = Gateway @@ -156,6 +176,7 @@ class Meta: "public_key_fingerprint", "feature_flags", "is_official", + "bk_app_codes", ) extra_kwargs = { "description_en": { @@ -185,6 +206,9 @@ def get_is_official(self, obj): api_type = self.context["auth_config"]["api_type"] return APITypeEnum.is_official(api_type) + def get_bk_app_codes(self, obj): + return self.context.get("bk_app_codes", []) + @classmethod def from_instance(cls, instance: Gateway): # 根据网关实例创建,简化调用 @@ -193,6 +217,7 @@ def from_instance(cls, instance: Gateway): context={ "auth_config": APIAuthContext().get_config(instance.pk), "feature_flags": APIFeatureFlagContext().get_config(instance.pk, {}), + "bk_app_codes": GatewayAppBindingHandler.get_bound_app_codes(instance), }, ) diff --git a/src/dashboard/apigateway/apigateway/apps/gateway/views.py b/src/dashboard/apigateway/apigateway/apps/gateway/views.py index 1e8f7cdf2..d00b4f041 100644 --- a/src/dashboard/apigateway/apigateway/apps/gateway/views.py +++ b/src/dashboard/apigateway/apigateway/apps/gateway/views.py @@ -26,6 +26,7 @@ from apigateway.apps.audit.utils import record_audit_log from apigateway.apps.gateway import serializers from apigateway.biz.gateway import GatewayHandler +from apigateway.biz.gateway_app_binding import GatewayAppBindingHandler from apigateway.common.contexts import APIAuthContext from apigateway.common.error_codes import error_codes from apigateway.controller.tasks import revoke_release, rolling_update_release @@ -67,6 +68,7 @@ def create(self, request, *args, **kwargs): gateway=slz.instance, user_auth_type=slz.validated_data["user_auth_type"], username=request.user.username, + app_codes_to_binding=slz.validated_data.get("bk_app_codes"), ) # 3. record audit log @@ -114,10 +116,16 @@ def update(self, request, *args, **kwargs): slz = serializers.GatewayUpdateSLZ(instance, data=request.data) slz.is_valid(raise_exception=True) + bk_app_codes = slz.validated_data.pop("bk_app_codes", None) + slz.save( updated_by=request.user.username, ) + # 更新绑定的应用 + if bk_app_codes is not None: + GatewayAppBindingHandler.update_gateway_app_bindings(instance, bk_app_codes) + GatewayHandler().add_update_audit_log(slz.instance, request.user.username) return OKJsonResponse("OK") diff --git a/src/dashboard/apigateway/apigateway/biz/gateway.py b/src/dashboard/apigateway/apigateway/biz/gateway.py index b54c5bc1e..587e73016 100644 --- a/src/dashboard/apigateway/apigateway/biz/gateway.py +++ b/src/dashboard/apigateway/apigateway/biz/gateway.py @@ -30,6 +30,7 @@ from apigateway.apps.audit.utils import record_audit_log from apigateway.apps.monitor.models import AlarmStrategy from apigateway.apps.plugin.models import PluginBinding +from apigateway.biz.gateway_app_binding import GatewayAppBindingHandler from apigateway.biz.iam import IAMHandler from apigateway.common.contexts import APIAuthContext from apigateway.core.api_auth import APIAuthConfig @@ -132,6 +133,7 @@ def save_related_data( user_config: Optional[dict] = None, unfiltered_sensitive_keys: Optional[List[str]] = None, api_type: Optional[APITypeEnum] = None, + app_codes_to_binding: Optional[List[str]] = None, ): # 1. save api auth_config GatewayHandler().save_auth_config( @@ -158,7 +160,11 @@ def save_related_data( if related_app_code: APIRelatedApp.objects.add_related_app(gateway.id, related_app_code) - # 6. 在权限中心注册分级管理员,创建用户组 + # 6. 更新待绑定的应用 + if app_codes_to_binding is not None: + GatewayAppBindingHandler.update_gateway_app_bindings(gateway, app_codes_to_binding) + + # 7. 在权限中心注册分级管理员,创建用户组 if settings.USE_BK_IAM_PERMISSION: IAMHandler.register_grade_manager_and_builtin_user_groups(gateway) diff --git a/src/dashboard/apigateway/apigateway/biz/gateway_app_binding.py b/src/dashboard/apigateway/apigateway/biz/gateway_app_binding.py new file mode 100644 index 000000000..e6bde578b --- /dev/null +++ b/src/dashboard/apigateway/apigateway/biz/gateway_app_binding.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# +from typing import List + +from apigateway.apps.gateway.models import GatewayAppBinding +from apigateway.core.models import Gateway + + +class GatewayAppBindingHandler: + @classmethod + def update_gateway_app_bindings(cls, gateway: Gateway, bk_app_codes: List[str]): + """ + 更新网关应用的绑定 + - 1. 如果 bk_app_codes 中应用未绑定,则新增绑定 + - 2. 如果已绑定的应用未在 bk_app_codes 中,则删除 + """ + bound_app_codes = cls.get_bound_app_codes(gateway) + app_codes_to_add = set(bk_app_codes) - set(bound_app_codes) + app_codes_to_delete = set(bound_app_codes) - set(bk_app_codes) + + if app_codes_to_add: + GatewayAppBinding.objects.bulk_create( + [GatewayAppBinding(gateway=gateway, bk_app_code=code) for code in app_codes_to_add] + ) + + if app_codes_to_delete: + GatewayAppBinding.objects.filter(gateway=gateway, bk_app_code__in=app_codes_to_delete).delete() + + @staticmethod + def get_bound_app_codes(gateway: Gateway) -> List[str]: + """获取已绑定的应用""" + return list(GatewayAppBinding.objects.filter(gateway=gateway).values_list("bk_app_code", flat=True)) diff --git a/src/dashboard/apigateway/apigateway/conf/default.py b/src/dashboard/apigateway/apigateway/conf/default.py index 493481793..29a6c2e28 100644 --- a/src/dashboard/apigateway/apigateway/conf/default.py +++ b/src/dashboard/apigateway/apigateway/conf/default.py @@ -88,6 +88,7 @@ "apigateway.apps.monitor", "apigateway.schema", "apigateway.core", + "apigateway.apps.gateway", "apigateway.apps.access_strategy", "apigateway.apps.plugin", "apigateway.apps.label", @@ -793,6 +794,7 @@ "MENU_ITEM_ESB_API_DOC": env.bool("FEATURE_FLAG_MENU_ITEM_ESB_API_DOC", True), "SYNC_ESB_TO_APIGW_ENABLED": env.bool("FEATURE_FLAG_SYNC_ESB_TO_APIGW_ENABLED", True), "GATEWAY_DEVELOPERS_ENABLED": env.bool("FEATURE_FLAG_GATEWAY_DEVELOPERS_ENABLED", False), + "GATEWAY_APP_BINDING_ENABLED": env.bool("FEATURE_FLAG_GATEWAY_APP_BINDING_ENABLED", False), # api-support "ENABLE_SDK": env.bool("FEATURE_FLAG_ENABLE_SDK", False), "ALLOW_CREATE_APPCHAT": env.bool("FEATURE_FLAG_ALLOW_CREATE_APPCHAT", False), diff --git a/src/dashboard/apigateway/apigateway/core/migrations/0030_auto_20230802_1451.py b/src/dashboard/apigateway/apigateway/core/migrations/0030_auto_20230802_1451.py index 9e40a4155..180c7b8e4 100644 --- a/src/dashboard/apigateway/apigateway/core/migrations/0030_auto_20230802_1451.py +++ b/src/dashboard/apigateway/apigateway/core/migrations/0030_auto_20230802_1451.py @@ -1,3 +1,20 @@ +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# # Generated by Django 3.2.18 on 2023-08-02 06:51 from django.db import migrations, models diff --git a/src/dashboard/apigateway/apigateway/core/migrations/0031_alter_publishevent_unique_together.py b/src/dashboard/apigateway/apigateway/core/migrations/0031_alter_publishevent_unique_together.py index ddf588364..c013344a4 100644 --- a/src/dashboard/apigateway/apigateway/core/migrations/0031_alter_publishevent_unique_together.py +++ b/src/dashboard/apigateway/apigateway/core/migrations/0031_alter_publishevent_unique_together.py @@ -1,3 +1,20 @@ +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# # Generated by Django 3.2.18 on 2023-08-04 03:47 from django.db import migrations diff --git a/src/dashboard/apigateway/apigateway/core/migrations/0032_gateway__developers.py b/src/dashboard/apigateway/apigateway/core/migrations/0032_gateway__developers.py index cfd3d86d8..f75025d07 100644 --- a/src/dashboard/apigateway/apigateway/core/migrations/0032_gateway__developers.py +++ b/src/dashboard/apigateway/apigateway/core/migrations/0032_gateway__developers.py @@ -1,3 +1,20 @@ +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# # Generated by Django 3.2.18 on 2023-09-25 08:48 from django.db import migrations, models diff --git a/src/dashboard/apigateway/apigateway/core/models.py b/src/dashboard/apigateway/apigateway/core/models.py index 9c7316f1e..d39424870 100644 --- a/src/dashboard/apigateway/apigateway/core/models.py +++ b/src/dashboard/apigateway/apigateway/core/models.py @@ -688,7 +688,10 @@ class Meta: class APIRelatedApp(TimestampedModelMixin): - """网关关联的蓝鲸应用""" + """ + 网关关联的蓝鲸应用 + - 应用可以通过 openapi 操作网关数据 + """ api = models.ForeignKey(Gateway, on_delete=models.CASCADE) bk_app_code = models.CharField(max_length=32, db_index=True) diff --git a/src/dashboard/apigateway/apigateway/tests/apps/gateway/test_serializers.py b/src/dashboard/apigateway/apigateway/tests/apps/gateway/test_serializers.py index b1dc4414c..e7e178369 100644 --- a/src/dashboard/apigateway/apigateway/tests/apps/gateway/test_serializers.py +++ b/src/dashboard/apigateway/apigateway/tests/apps/gateway/test_serializers.py @@ -56,6 +56,7 @@ def setUpTestData(self): "status": 1, "is_public": True, "user_auth_type": "ieod", + "bk_app_codes": ["app1", "app2"], }, { "name": "test", @@ -66,6 +67,7 @@ def setUpTestData(self): "is_public": True, "hosting_type": 0, "user_auth_type": "ieod", + "bk_app_codes": ["app1", "app2"], }, False, ), @@ -217,12 +219,14 @@ def test(self): "developers": ["foo"], "description": "test", "is_public": True, + "bk_app_codes": ["app1", "app2"], "will_error": False, "expected": { "maintainers": ["admin"], "developers": ["foo"], "description": "test", "is_public": True, + "bk_app_codes": ["app1", "app2"], }, }, # ok, is_public is str @@ -352,6 +356,7 @@ def test_to_representation(self, mocker): "public_key_fingerprint": calculate_fingerprint(self.jwt.public_key), "feature_flags": {"MICRO_GATEWAY_ENABLED": True}, "is_official": False, + "bk_app_codes": [], }, } result = GatewayDetailSLZ.from_instance(self.api) diff --git a/src/dashboard/apigateway/apigateway/tests/biz/test_gateway.py b/src/dashboard/apigateway/apigateway/tests/biz/test_gateway.py index d8a74438d..66a1899bd 100644 --- a/src/dashboard/apigateway/apigateway/tests/biz/test_gateway.py +++ b/src/dashboard/apigateway/apigateway/tests/biz/test_gateway.py @@ -21,10 +21,19 @@ from django.core.exceptions import ObjectDoesNotExist from django_dynamic_fixture import G +from apigateway.apps.gateway.models import GatewayAppBinding from apigateway.apps.monitor.models import AlarmStrategy from apigateway.biz.gateway import GatewayHandler from apigateway.core.constants import APITypeEnum, ContextScopeTypeEnum, ContextTypeEnum -from apigateway.core.models import JWT, APIRelatedApp, Context, Gateway, Release, ResourceVersion, Stage +from apigateway.core.models import ( + JWT, + APIRelatedApp, + Context, + Gateway, + Release, + ResourceVersion, + Stage, +) class TestGatewayHandler: @@ -213,7 +222,7 @@ def test_save_related_data(self, mocker, fake_gateway): } ), ) - GatewayHandler().save_related_data(fake_gateway, "default", "admin", "test") + GatewayHandler().save_related_data(fake_gateway, "default", "admin", "test", app_codes_to_binding=["app1"]) assert Context.objects.filter( scope_type=ContextScopeTypeEnum.API.value, type=ContextTypeEnum.API_AUTH.value, scope_id=fake_gateway.id @@ -223,6 +232,7 @@ def test_save_related_data(self, mocker, fake_gateway): assert Stage.objects.filter(api=fake_gateway).exists() assert AlarmStrategy.objects.filter(api=fake_gateway).exists() assert APIRelatedApp.objects.filter(api=fake_gateway, bk_app_code="test").exists() + assert GatewayAppBinding.objects.filter(gateway=fake_gateway, bk_app_code="app1").exists() def test_delete_api( self, diff --git a/src/dashboard/apigateway/apigateway/tests/biz/test_gateway_app_binding.py b/src/dashboard/apigateway/apigateway/tests/biz/test_gateway_app_binding.py new file mode 100644 index 000000000..60b132e91 --- /dev/null +++ b/src/dashboard/apigateway/apigateway/tests/biz/test_gateway_app_binding.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# +# TencentBlueKing is pleased to support the open source community by making +# 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. +# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +# Licensed under the MIT License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://opensource.org/licenses/MIT +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on 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. +# +# We undertake not to change the open source license (MIT license) applicable +# to the current version of the project delivered to anyone in the future. +# +from apigateway.apps.gateway.models import GatewayAppBinding +from apigateway.biz.gateway_app_binding import GatewayAppBindingHandler + + +class TestGatewayAppBindingHandler: + def test_update_gateway_app_bindings(self, fake_gateway): + GatewayAppBindingHandler.update_gateway_app_bindings(fake_gateway, ["app1", "app2"]) + assert GatewayAppBinding.objects.filter(gateway=fake_gateway).count() == 2 + + GatewayAppBindingHandler.update_gateway_app_bindings(fake_gateway, ["app3", "app2"]) + assert GatewayAppBinding.objects.filter(gateway=fake_gateway).count() == 2 + + GatewayAppBindingHandler.update_gateway_app_bindings(fake_gateway, ["app1"]) + assert GatewayAppBinding.objects.filter(gateway=fake_gateway).count() == 1 + + GatewayAppBindingHandler.update_gateway_app_bindings(fake_gateway, []) + assert GatewayAppBinding.objects.filter(gateway=fake_gateway).count() == 0 + + def test_get_bound_app_codes(self, fake_gateway): + GatewayAppBindingHandler.update_gateway_app_bindings(fake_gateway, ["app1", "app2"]) + result = GatewayAppBindingHandler.get_bound_app_codes(gateway=fake_gateway) + assert set(result) == {"app1", "app2"}