Skip to content

Commit

Permalink
fix(apis/web/resource/view): 修复资源未修改但触发更新问题 (#1106)
Browse files Browse the repository at this point in the history
  • Loading branch information
F-cq authored Nov 8, 2024
1 parent 8774bc2 commit 50030cc
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 16 deletions.
62 changes: 46 additions & 16 deletions src/dashboard/apigateway/apigateway/apis/web/resource/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from apigateway.apis.web.constants import ExportTypeEnum
from apigateway.apps.audit.constants import OpTypeEnum
from apigateway.apps.label.models import ResourceLabel
from apigateway.apps.plugin.constants import PluginBindingScopeEnum
from apigateway.apps.plugin.models import PluginBinding
from apigateway.apps.support.constants import DocLanguageEnum
Expand Down Expand Up @@ -187,6 +188,33 @@ class ResourceRetrieveUpdateDestroyApi(ResourceQuerySetMixin, generics.RetrieveU
serializer_class = ResourceInputSLZ
lookup_field = "id"

def _check_if_changed(self, input_data: Dict[str, Any], instance: Resource) -> bool:

resource_fields = ["name", "description", "method", "path", "match_subpath",
"enable_websocket", "is_public", "allow_apply_permission"]

current_resource_data = get_model_dict(instance)
for field in resource_fields:
if input_data[field] != current_resource_data[field]:
return True

current_auth_config = ResourceAuthContext().get_config(instance.id)
input_data["auth_config"]["skip_auth_verification"] = False
if input_data["auth_config"] != current_auth_config:
return True

proxy = Proxy.objects.get(resource_id=instance.id)
current_backend = {"id": proxy.backend.id, "config": proxy.config}
input_backend = {"id": input_data["backend"].id, "config": dict(input_data["backend_config"])}
if input_backend != current_backend:
return True

current_label_ids = ResourceLabel.objects.filter(resource_id=instance.id).values_list("api_label_id", flat=True)
if sorted(input_data["label_ids"]) != sorted(current_label_ids):
return True

return False

def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
slz = ResourceOutputSLZ(
Expand Down Expand Up @@ -215,23 +243,25 @@ def update(self, request, *args, **kwargs):
)
slz.is_valid(raise_exception=True)

saver = ResourcesSaver.from_resources(
gateway=request.gateway,
resources=[slz.validated_data],
username=request.user.username,
)
resources = saver.save()
instance = resources[0]
if self._check_if_changed(dict(slz.validated_data), instance):
saver = ResourcesSaver.from_resources(
gateway=request.gateway,
resources=[slz.validated_data],
username=request.user.username,
)

Auditor.record_resource_op_success(
op_type=OpTypeEnum.MODIFY,
username=request.user.username,
gateway_id=request.gateway.id,
instance_id=instance.id,
instance_name=instance.identity,
data_before=data_before,
data_after=get_model_dict(instance),
)
resources = saver.save()
instance = resources[0]

Auditor.record_resource_op_success(
op_type=OpTypeEnum.MODIFY,
username=request.user.username,
gateway_id=request.gateway.id,
instance_id=instance.id,
instance_name=instance.identity,
data_before=data_before,
data_after=get_model_dict(instance),
)

return OKJsonResponse(status=status.HTTP_204_NO_CONTENT)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
from ddf import G
from django.utils import timezone

from apigateway.apis.web.resource.serializers import ResourceInputSLZ
from apigateway.apis.web.resource.views import (
BackendHostIsEmpty,
BackendPathCheckApi,
ResourceRetrieveUpdateDestroyApi,
)
from apigateway.apps.label.models import APILabel, ResourceLabel
from apigateway.biz.resource import ResourceHandler
from apigateway.biz.resource.savers import ResourcesSaver
from apigateway.common.contexts import ResourceAuthContext
from apigateway.core import constants
from apigateway.core.models import Backend, BackendConfig, Context, Proxy, Resource, Stage
Expand Down Expand Up @@ -204,6 +207,84 @@ def test_destroy(self, request_view, fake_resource):
assert not Proxy.objects.filter(resource=fake_resource)
assert not Context.objects.filter(type="resource", scope_id=fake_resource.id)

@pytest.mark.parametrize(
"data",
[
{
"name": "test",
"description": "desc",
"path": "/e/",
"method": "GET",
"match_subpath": False,
"enable_websocket": False,
"auth_config": {
"skip_auth_verification": False,
"auth_verified_required": True,
"app_verified_required": True,
"resource_perm_required": True
},
"is_public": True,
"allow_apply_permission": True,
"label_ids": [],
"backend": {
"name": "default",
"config": {
"method": "GET",
"path": "/e/",
"match_subpath": False,
"timeout": 0
}
}
},
],
)
def test_check_if_changed(self, request_view, fake_gateway, data):
backend = G(Backend, gateway=fake_gateway, name="default")
label_a = G(APILabel, gateway=fake_gateway, name="aaa")
label_b = G(APILabel, gateway=fake_gateway, name="bbb")
label_c = G(APILabel, gateway=fake_gateway, name="ccc")

data["backend"]["id"] = backend.id
data["label_ids"] = [label_a.id, label_b.id]

slz = ResourceInputSLZ(
data=data,
context={
"gateway": fake_gateway,
"stages": Stage.objects.filter(gateway=fake_gateway),
},
)
slz.is_valid(raise_exception=True)

saver = ResourcesSaver.from_resources(
gateway=fake_gateway,
resources=[slz.validated_data],
username='root',
)

resources = saver.save()
instance = resources[0]

view = ResourceRetrieveUpdateDestroyApi()

slz.validated_data["name"] = "test2"
assert view._check_if_changed(slz.validated_data, instance)

slz.validated_data["name"] = "test"
slz.validated_data["auth_config"]["resource_perm_required"] = False
assert view._check_if_changed(slz.validated_data, instance)

slz.validated_data["name"] = "test"
slz.validated_data["auth_config"]["resource_perm_required"] = True
slz.validated_data["backend_config"]["path"] = "/ee/"
assert view._check_if_changed(slz.validated_data, instance)

slz.validated_data["name"] = "test"
slz.validated_data["auth_config"]["resource_perm_required"] = True
slz.validated_data["backend_config"]["path"] = "/e/"
slz.validated_data["label_ids"] = [label_c.id, label_b.id, label_a.id]
assert view._check_if_changed(slz.validated_data, instance)


class TestResourceBatchUpdateDestroyApi:
def test_update(self, request_view, fake_resource):
Expand Down

0 comments on commit 50030cc

Please sign in to comment.