Skip to content

Commit

Permalink
Allow webhook modification by API for advanced webhook (#4175)
Browse files Browse the repository at this point in the history
# What this PR does

Enables the API to perform updates on the advanced webhooks created via
the UI

## Which issue(s) this PR closes

Closes #3958 

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
  • Loading branch information
ravishankar15 authored Apr 23, 2024
1 parent cb613de commit 6f3f4e3
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 5 deletions.
9 changes: 8 additions & 1 deletion engine/apps/public_api/serializers/webhooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from apps.webhooks.models import Webhook, WebhookResponse
from apps.webhooks.models.webhook import PUBLIC_WEBHOOK_HTTP_METHODS, WEBHOOK_FIELD_PLACEHOLDER
from apps.webhooks.presets.preset_options import WebhookPresetOptions
from common.api_helpers.custom_fields import IntegrationFilteredByOrganizationField, TeamPrimaryKeyRelatedField
from common.api_helpers.exceptions import BadRequest
from common.api_helpers.utils import CurrentOrganizationDefault, CurrentTeamDefault, CurrentUserDefault
Expand Down Expand Up @@ -158,7 +159,13 @@ def validate_preset(self, preset):
raise serializers.ValidationError(PRESET_VALIDATION_MESSAGE)

def validate(self, data):
if self.instance and self.instance.preset:
if (
self.instance
and self.instance.preset
and WebhookPresetOptions.ADVANCED_PRESET_META_DATA
and WebhookPresetOptions.ADVANCED_PRESET_META_DATA.id
and self.instance.preset != WebhookPresetOptions.ADVANCED_PRESET_META_DATA.id
):
raise serializers.ValidationError(PRESET_VALIDATION_MESSAGE)
return data

Expand Down
22 changes: 21 additions & 1 deletion engine/apps/public_api/tests/test_webhooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from apps.public_api.serializers.webhooks import PRESET_VALIDATION_MESSAGE
from apps.webhooks.models import Webhook
from apps.webhooks.tests.test_webhook_presets import TEST_WEBHOOK_PRESET_ID
from apps.webhooks.tests.test_webhook_presets import ADVANCED_WEBHOOK_PRESET_ID, TEST_WEBHOOK_PRESET_ID


def _get_expected_result(webhook):
Expand Down Expand Up @@ -437,3 +437,23 @@ def test_webhook_block_preset_update(
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["non_field_errors"][0] == PRESET_VALIDATION_MESSAGE


@pytest.mark.django_db
def test_webhook_advanced_preset_update(
make_organization_and_user_with_token,
make_custom_webhook,
webhook_preset_api_setup,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
webhook = make_custom_webhook(organization=organization, preset=ADVANCED_WEBHOOK_PRESET_ID)
webhook.refresh_from_db()

url = reverse("api-public:webhooks-detail", kwargs={"pk": webhook.public_primary_key})
data = {
"name": "Test rename preset webhook",
}
response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_200_OK
assert response.data["name"] == data["name"]
3 changes: 3 additions & 0 deletions engine/apps/webhooks/presets/preset_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@

class WebhookPresetOptions:
WEBHOOK_PRESETS = {}
ADVANCED_PRESET_META_DATA = {}
for webhook_preset_config in settings.INSTALLED_WEBHOOK_PRESETS:
module_path, class_name = webhook_preset_config.rsplit(".", 1)
module = import_module(module_path)
preset = getattr(module, class_name)()
WEBHOOK_PRESETS[preset.metadata.id] = preset
if webhook_preset_config == settings.ADVANCED_WEBHOOK_PRESET:
ADVANCED_PRESET_META_DATA = preset.metadata

WEBHOOK_PRESET_CHOICES = [webhook_preset.metadata for webhook_preset in WEBHOOK_PRESETS.values()]

Expand Down
6 changes: 6 additions & 0 deletions engine/apps/webhooks/tests/test_webhook_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from apps.webhooks.models import Webhook
from apps.webhooks.models.webhook import WEBHOOK_FIELD_PLACEHOLDER
from apps.webhooks.presets.advanced import AdvancedWebhookPreset
from apps.webhooks.presets.preset import WebhookPreset, WebhookPresetMetadata
from apps.webhooks.tasks.trigger_webhook import make_request
from apps.webhooks.tests.test_trigger_webhook import MockResponse
Expand All @@ -20,6 +21,7 @@
TEST_WEBHOOK_MASK_HEADER = "X-Secret-Header"
TEST_WEBHOOK_MASK_HEADER_VALUE = "abc123"
INVALID_PRESET_ID = "invalid_preset_id"
ADVANCED_WEBHOOK_PRESET_ID = "advanced_webhook"


class TestWebhookPreset(WebhookPreset):
Expand Down Expand Up @@ -47,6 +49,10 @@ def get_masked_headers(self) -> typing.List[str]:
return [TEST_WEBHOOK_MASK_HEADER]


class TestAdvancedWebhookPreset(AdvancedWebhookPreset):
pass


@pytest.mark.django_db
def test_create_webhook_from_preset(make_organization, webhook_preset_api_setup, make_custom_webhook):
organization = make_organization()
Expand Down
12 changes: 10 additions & 2 deletions engine/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,12 @@
from apps.user_management.tests.factories import OrganizationFactory, RegionFactory, TeamFactory, UserFactory
from apps.webhooks.presets.preset_options import WebhookPresetOptions
from apps.webhooks.tests.factories import CustomWebhookFactory, WebhookResponseFactory
from apps.webhooks.tests.test_webhook_presets import TEST_WEBHOOK_PRESET_ID, TestWebhookPreset
from apps.webhooks.tests.test_webhook_presets import (
ADVANCED_WEBHOOK_PRESET_ID,
TEST_WEBHOOK_PRESET_ID,
TestAdvancedWebhookPreset,
TestWebhookPreset,
)

register(OrganizationFactory)
register(UserFactory)
Expand Down Expand Up @@ -987,7 +992,10 @@ def _shift_swap_request_setup(**kwargs):

@pytest.fixture()
def webhook_preset_api_setup():
WebhookPresetOptions.WEBHOOK_PRESETS = {TEST_WEBHOOK_PRESET_ID: TestWebhookPreset()}
WebhookPresetOptions.WEBHOOK_PRESETS = {
TEST_WEBHOOK_PRESET_ID: TestWebhookPreset(),
ADVANCED_WEBHOOK_PRESET_ID: TestAdvancedWebhookPreset(),
}
WebhookPresetOptions.WEBHOOK_PRESET_CHOICES = [
preset.metadata for preset in WebhookPresetOptions.WEBHOOK_PRESETS.values()
]
Expand Down
3 changes: 2 additions & 1 deletion engine/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,9 +837,10 @@ class BrokerTypes:
"config_integrations.direct_paging",
]

ADVANCED_WEBHOOK_PRESET = "apps.webhooks.presets.advanced.AdvancedWebhookPreset"
INSTALLED_WEBHOOK_PRESETS = [
"apps.webhooks.presets.simple.SimpleWebhookPreset",
"apps.webhooks.presets.advanced.AdvancedWebhookPreset",
ADVANCED_WEBHOOK_PRESET,
]

if IS_OPEN_SOURCE:
Expand Down

0 comments on commit 6f3f4e3

Please sign in to comment.