From 06bd0454f670bab09170e648533b5c037710a14b Mon Sep 17 00:00:00 2001 From: Vadim Stepanov Date: Tue, 23 May 2023 17:23:06 +0100 Subject: [PATCH] Fix MultipleObjectsReturned error on webhook endpoints (#1996) # What this PR does Sometimes `CustomButtonView` returns HTTP 500 with the following error: ``` apps.alerts.models.custom_button.CustomButton.MultipleObjectsReturned: get() returned more than one CustomButton -- it returned 3! ``` This PR fixes it by adding `.distinct()` to the `CustomButton` queryset when retrieving an instance + does the same for `WebhooksView`. ## Which issue(s) this PR fixes Related to https://github.com/grafana/oncall-private/issues/1828 ## 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] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- CHANGELOG.md | 1 + engine/apps/api/views/custom_button.py | 6 +++++- engine/apps/api/views/webhooks.py | 2 +- engine/common/api_helpers/mixins.py | 4 ++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aefb580..c6cff975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Improve plugin authentication by @vadimkerr ([#1995](https://github.com/grafana/oncall/pull/1995)) +- Fix MultipleObjectsReturned error on webhook endpoints by @vadimkerr ([#1996](https://github.com/grafana/oncall/pull/1996)) ## v1.2.27 (2023-05-23) diff --git a/engine/apps/api/views/custom_button.py b/engine/apps/api/views/custom_button.py index 9b8653d6..079d6f7f 100644 --- a/engine/apps/api/views/custom_button.py +++ b/engine/apps/api/views/custom_button.py @@ -64,7 +64,11 @@ class CustomButtonView(TeamFilteringMixin, PublicPrimaryKeyMixin, ModelViewSet): pk = self.kwargs["pk"] organization = self.request.auth.organization try: - obj = organization.custom_buttons.filter(*self.available_teams_lookup_args).get(public_primary_key=pk) + obj = ( + organization.custom_buttons.filter(*self.available_teams_lookup_args) + .distinct() + .get(public_primary_key=pk) + ) except ObjectDoesNotExist: raise NotFound diff --git a/engine/apps/api/views/webhooks.py b/engine/apps/api/views/webhooks.py index 8eaf3126..3b76b99a 100644 --- a/engine/apps/api/views/webhooks.py +++ b/engine/apps/api/views/webhooks.py @@ -63,7 +63,7 @@ class WebhooksView(TeamFilteringMixin, PublicPrimaryKeyMixin, ModelViewSet): pk = self.kwargs["pk"] organization = self.request.auth.organization try: - obj = organization.webhooks.filter(*self.available_teams_lookup_args).get(public_primary_key=pk) + obj = organization.webhooks.filter(*self.available_teams_lookup_args).distinct().get(public_primary_key=pk) except ObjectDoesNotExist: raise NotFound diff --git a/engine/common/api_helpers/mixins.py b/engine/common/api_helpers/mixins.py index 53b29c77..cba754db 100644 --- a/engine/common/api_helpers/mixins.py +++ b/engine/common/api_helpers/mixins.py @@ -197,6 +197,10 @@ class TeamFilteringMixin: @property def available_teams_lookup_args(self): + """ + This property returns a list of Q objects that are used to filter instances by teams available to the user. + NOTE: use .distinct() after filtering by available teams as it may return duplicate instances. + """ available_teams_lookup_args = [] if not self.request.user.role == LegacyAccessControlRole.ADMIN: available_teams_lookup_args = [