diff --git a/src/sentry/api/serializers/models/dashboard.py b/src/sentry/api/serializers/models/dashboard.py index 3c33a3d97741..3a33ae13c804 100644 --- a/src/sentry/api/serializers/models/dashboard.py +++ b/src/sentry/api/serializers/models/dashboard.py @@ -682,9 +682,20 @@ def get_attrs(self, item_list, user, **kwargs): user=user, ) + creator_ids = [d.created_by_id for d in item_list if d.created_by_id is not None] + serialized_creators = ( + user_service.serialize_many(filter={"user_ids": creator_ids}) if creator_ids else [] + ) + serialized_users = {u["id"]: u for u in serialized_creators} + for dashboard in item_list: dashboard_widgets = [w for w in widgets if w and w["dashboardId"] == str(dashboard.id)] - result[dashboard] = {"widgets": dashboard_widgets} + created_by = ( + serialized_users.get(str(dashboard.created_by_id)) + if dashboard.created_by_id is not None + else None + ) + result[dashboard] = {"widgets": dashboard_widgets, "created_by": created_by} return result @@ -695,11 +706,7 @@ def serialize(self, obj, attrs, user, **kwargs) -> DashboardDetailsResponse: "id": str(obj.id), "title": obj.title, "dateCreated": obj.date_added, - "createdBy": ( - user_service.serialize_many(filter={"user_ids": [obj.created_by_id]})[0] - if obj.created_by_id - else None - ), + "createdBy": attrs.get("created_by"), "widgets": attrs["widgets"], "filters": tag_filters, "permissions": serialize(obj.permissions) if hasattr(obj, "permissions") else None, diff --git a/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py b/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py index 631f4799031d..917f5c4fe99a 100644 --- a/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py +++ b/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py @@ -128,6 +128,19 @@ def test_get(self) -> None: assert len(widgets[1]["queries"]) == 1 self.assert_serialized_widget_query(widgets[1]["queries"][0], self.widget_2_data_1) + def test_get_created_by_is_none_when_creator_deleted(self) -> None: + # Simulate a dashboard whose creator has been deleted: user_service returns + # an empty list for that user ID, which should yield createdBy=None instead + # of raising IndexError. + with mock.patch( + "sentry.api.serializers.models.dashboard.user_service.serialize_many", + return_value=[], + ): + response = self.do_request("get", self.url(self.dashboard.id)) + + assert response.status_code == 200, response.content + assert response.data["createdBy"] is None + def test_dashboard_does_not_exist(self) -> None: response = self.do_request("get", self.url(1234567890)) assert response.status_code == 404