diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index 4491e177edd356..892a8ff726b901 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -19,6 +19,7 @@ GroupSearchViewValidatorResponse, ) from sentry.models.groupsearchview import DEFAULT_TIME_FILTER, GroupSearchView +from sentry.models.groupsearchviewstarred import GroupSearchViewStarred from sentry.models.organization import Organization from sentry.models.project import Project from sentry.models.savedsearch import SortOptions @@ -239,6 +240,12 @@ def _update_existing_view( gsv.time_filters = view["timeFilters"] gsv.save() + GroupSearchViewStarred.objects.update_or_create( + organization=org, + user_id=user_id, + group_search_view=gsv, + defaults={"position": position}, + ) except GroupSearchView.DoesNotExist: # It is possible – though unlikely under normal circumstances – for a view to come in that # doesn't exist anymore. If, for example, the user has the issue stream open in separate @@ -263,3 +270,10 @@ def _create_view( ) if "projects" in view: gsv.projects.set(view["projects"] or []) + + GroupSearchViewStarred.objects.create( + organization=org, + user_id=user_id, + group_search_view=gsv, + position=position, + ) diff --git a/tests/sentry/issues/endpoints/test_organization_group_search_views.py b/tests/sentry/issues/endpoints/test_organization_group_search_views.py index e700dfdb5bc2d4..57613c46563179 100644 --- a/tests/sentry/issues/endpoints/test_organization_group_search_views.py +++ b/tests/sentry/issues/endpoints/test_organization_group_search_views.py @@ -5,6 +5,7 @@ from sentry.api.serializers.rest_framework.groupsearchview import GroupSearchViewValidatorResponse from sentry.issues.endpoints.organization_group_search_views import DEFAULT_VIEWS from sentry.models.groupsearchview import GroupSearchView +from sentry.models.groupsearchviewstarred import GroupSearchViewStarred from sentry.testutils.cases import APITestCase, TransactionTestCase from sentry.testutils.helpers.features import with_feature @@ -159,9 +160,18 @@ def setUp(self) -> None: @with_feature({"organizations:issue-stream-custom-views": True}) @with_feature({"organizations:global-views": True}) def test_deletes_missing_views(self) -> None: + starred_views = GroupSearchViewStarred.objects.filter( + organization=self.organization, user_id=self.user.id + ) + + # Verify that no starred views exist initially + assert len(starred_views) == 0 + views = self.client.get(self.url).data update_custom_view_three = views[2] + # Store the ID of the view we're going to delete + deleted_view_id = views[1]["id"] views.pop(1) response = self.get_success_response(self.organization.slug, views=views) @@ -175,6 +185,22 @@ def test_deletes_missing_views(self) -> None: assert are_views_equal(response.data[0], views[0]) assert are_views_equal(response.data[1], update_custom_view_three) + starred_views = GroupSearchViewStarred.objects.filter( + organization=self.organization, user_id=self.user.id + ) + assert len(starred_views) == len(response.data) + for idx, view in enumerate(response.data): + assert starred_views[idx].position == idx + assert starred_views[idx].position == view["position"] + assert str(starred_views[idx].group_search_view.id) == view["id"] + + # Verify that the deleted view is no longer in the starred table + assert not GroupSearchViewStarred.objects.filter( + organization=self.organization, + user_id=self.user.id, + group_search_view_id=deleted_view_id, + ).exists() + @with_feature({"organizations:issue-stream-custom-views": True}) @with_feature({"organizations:global-views": True}) def test_adds_view_with_no_id(self) -> None: @@ -194,6 +220,15 @@ def test_adds_view_with_no_id(self) -> None: assert response.data[3]["query"] == "is:unresolved" assert response.data[3]["querySort"] == "date" + starred_views = GroupSearchViewStarred.objects.filter( + organization=self.organization, user_id=self.user.id + ) + assert len(starred_views) == len(response.data) + for idx, view in enumerate(response.data): + assert starred_views[idx].position == idx + assert starred_views[idx].position == view["position"] + assert str(starred_views[idx].group_search_view.id) == view["id"] + @with_feature({"organizations:issue-stream-custom-views": True}) @with_feature({"organizations:global-views": True}) def test_reorder_views(self) -> None: @@ -214,6 +249,15 @@ def test_reorder_views(self) -> None: assert are_views_equal(response.data[1], view_one) assert are_views_equal(response.data[2], views[2]) + starred_views = GroupSearchViewStarred.objects.filter( + organization=self.organization, user_id=self.user.id + ) + assert len(starred_views) == len(response.data) + for idx, view in enumerate(response.data): + assert starred_views[idx].position == idx + assert starred_views[idx].position == view["position"] + assert str(starred_views[idx].group_search_view.id) == view["id"] + @with_feature({"organizations:issue-stream-custom-views": True}) @with_feature({"organizations:global-views": True}) def test_rename_views(self) -> None: @@ -264,6 +308,15 @@ def test_change_everything(self) -> None: assert response.data[0]["query"] == "is:resolved" assert response.data[0]["querySort"] == "freq" + starred_views = GroupSearchViewStarred.objects.filter( + organization=self.organization, user_id=self.user.id + ) + assert len(starred_views) == len(response.data) + for idx, view in enumerate(response.data): + assert starred_views[idx].position == idx + assert starred_views[idx].position == view["position"] + assert str(starred_views[idx].group_search_view.id) == view["id"] + @with_feature({"organizations:issue-stream-custom-views": True}) @with_feature({"organizations:global-views": True}) def test_invalid_no_views(self) -> None: @@ -343,6 +396,15 @@ def test_updated_deleted_view(self) -> None: assert response.data[1]["querySort"] == view_one["querySort"] assert are_views_equal(response.data[2], views[2]) + starred_views = GroupSearchViewStarred.objects.filter( + organization=self.organization, user_id=self.user.id + ) + assert len(starred_views) == len(response.data) + for idx, view in enumerate(response.data): + assert starred_views[idx].position == idx + assert starred_views[idx].position == view["position"] + assert str(starred_views[idx].group_search_view.id) == view["id"] + class OrganizationGroupSearchViewsWithPageFiltersPutTest(BaseGSVTestCase): endpoint = "sentry-api-0-organization-group-search-views"