Skip to content

Commit

Permalink
fix(stats): hide stats if no project access (#81162)
Browse files Browse the repository at this point in the history
Second attempt of #80447

Comparing with the previous attempt, we now also allow project stats for
staff users (`or user.is_staff`).

The superuser case is already covered in this code:

https://github.com/getsentry/sentry/blob/2e5e0654c717adfa569be7875f44cb7e2bda4a74/src/sentry/api/serializers/models/project.py#L131-L136
`is_superuser` is True, therefore `has_access` is True, and the first
condition in this snippet works:
```
if attrs["has_access"] or user.is_staff:
```
  • Loading branch information
oioki authored Nov 22, 2024
1 parent a875e05 commit 2e810df
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 9 deletions.
18 changes: 10 additions & 8 deletions src/sentry/api/serializers/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,14 +770,16 @@ def serialize(
)
if not self._collapse(LATEST_DEPLOYS_KEY):
context[LATEST_DEPLOYS_KEY] = attrs["deploys"]
if "stats" in attrs:
context.update(stats=attrs["stats"])
if "transactionStats" in attrs:
context.update(transactionStats=attrs["transactionStats"])
if "sessionStats" in attrs:
context.update(sessionStats=attrs["sessionStats"])
if "options" in attrs:
context.update(options=attrs["options"])

if attrs["has_access"] or user.is_staff:
if "stats" in attrs:
context.update(stats=attrs["stats"])
if "transactionStats" in attrs:
context.update(transactionStats=attrs["transactionStats"])
if "sessionStats" in attrs:
context.update(sessionStats=attrs["sessionStats"])
if "options" in attrs:
context.update(options=attrs["options"])

return context

Expand Down
67 changes: 66 additions & 1 deletion tests/sentry/api/endpoints/test_organization_projects.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from django.urls import reverse

from sentry.models.apikey import ApiKey
Expand All @@ -6,7 +7,7 @@
from sentry.testutils.silo import assume_test_silo_mode
from sentry.testutils.skips import requires_snuba

pytestmark = [requires_snuba]
pytestmark = [pytest.mark.sentry_metrics, requires_snuba]


class OrganizationProjectsTestBase(APITestCase):
Expand Down Expand Up @@ -85,6 +86,70 @@ def test_with_stats(self):
self.organization.slug, qs_params={"statsPeriod": "48h"}, status_code=400
)

def test_staff_with_stats(self):
projects = [self.create_project(teams=[self.team])]

# disable Open Membership
self.organization.flags.allow_joinleave = False
self.organization.save()

staff_user = self.create_user(is_staff=True)
self.login_as(user=staff_user, staff=True)

response = self.get_success_response(
self.organization.slug,
qs_params={"statsPeriod": "24h", "transactionStats": "1", "sessionStats": "1"},
)
self.check_valid_response(response, projects)

assert "stats" in response.data[0]
assert "transactionStats" in response.data[0]
assert "sessionStats" in response.data[0]

def test_superuser_with_stats(self):
projects = [self.create_project(teams=[self.team])]

# disable Open Membership
self.organization.flags.allow_joinleave = False
self.organization.save()

superuser = self.create_user(is_superuser=True)
self.login_as(user=superuser, superuser=True)

response = self.get_success_response(
self.organization.slug,
qs_params={"statsPeriod": "24h", "transactionStats": "1", "sessionStats": "1"},
)
self.check_valid_response(response, projects)

assert "stats" in response.data[0]
assert "transactionStats" in response.data[0]
assert "sessionStats" in response.data[0]

def test_no_stats_if_no_project_access(self):
projects = [self.create_project(teams=[self.team])]

# disable Open Membership
self.organization.flags.allow_joinleave = False
self.organization.save()

# user has no access to the first project
user_no_team = self.create_user(is_superuser=False)
self.create_member(
user=user_no_team, organization=self.organization, role="member", teams=[]
)
self.login_as(user_no_team)

response = self.get_success_response(
self.organization.slug,
qs_params={"statsPeriod": "24h", "transactionStats": "1", "sessionStats": "1"},
)
self.check_valid_response(response, projects)

assert "stats" not in response.data[0]
assert "transactionStats" not in response.data[0]
assert "sessionStats" not in response.data[0]

def test_search(self):
project = self.create_project(teams=[self.team], name="bar", slug="bar")

Expand Down

0 comments on commit 2e810df

Please sign in to comment.