-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(browser-starfish): Add project settings endpoint for images (#62025
) Work for #60482 This PR adds a new endpoint to enable/disable images for the resource module as a project settings. Complements #62131 , this PR shall be merged and deployed first. TODO: - [x] Add some more error handling - [x] Add tests <img width="767" alt="image" src="https://github.com/getsentry/sentry/assets/44422760/84196e45-3311-459f-b16b-c7693a659063">
- Loading branch information
1 parent
f7c08bb
commit ae2ccdf
Showing
4 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
75 changes: 75 additions & 0 deletions
75
src/sentry/api/endpoints/project_performance_general_settings.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
from rest_framework import serializers, status | ||
from rest_framework.request import Request | ||
from rest_framework.response import Response | ||
|
||
from sentry import features | ||
from sentry.api.api_owners import ApiOwner | ||
from sentry.api.api_publish_status import ApiPublishStatus | ||
from sentry.api.base import region_silo_endpoint | ||
from sentry.api.bases.project import ProjectEndpoint, ProjectSettingPermission | ||
from sentry.api.permissions import SuperuserPermission | ||
from sentry.models.project import Project | ||
from sentry.projectoptions.defaults import DEFAULT_PROJECT_PERFORMANCE_GENERAL_SETTINGS | ||
|
||
SETTINGS_PROJECT_OPTION_KEY = "sentry:performance_general_settings" | ||
|
||
|
||
class ProjectPerformanceGeneralSettingsSerializer(serializers.Serializer): | ||
enable_images = serializers.BooleanField(required=False) | ||
|
||
|
||
class ProjectOwnerOrSuperUserPermissions(ProjectSettingPermission): | ||
def has_object_permission(self, request: Request, view, project): | ||
return super().has_object_permission( | ||
request, view, project | ||
) or SuperuserPermission().has_permission(request, view) | ||
|
||
|
||
@region_silo_endpoint | ||
class ProjectPerformanceGeneralSettingsEndpoint(ProjectEndpoint): | ||
owner = ApiOwner.PERFORMANCE | ||
publish_status = { | ||
"DELETE": ApiPublishStatus.PRIVATE, | ||
"GET": ApiPublishStatus.PRIVATE, | ||
"POST": ApiPublishStatus.PRIVATE, | ||
} | ||
permission_classes = (ProjectOwnerOrSuperUserPermissions,) | ||
|
||
def get(self, request: Request, project) -> Response: | ||
if not self.has_feature(project, request): | ||
return self.respond(status=status.HTTP_404_NOT_FOUND) | ||
|
||
if not project: | ||
return Response(status=status.HTTP_404_NOT_FOUND) | ||
|
||
project_option_settings = self.get_current_settings(project) | ||
return Response(project_option_settings) | ||
|
||
def post(self, request: Request, project: Project) -> Response: | ||
if not self.has_feature(project, request): | ||
return self.respond(status=status.HTTP_404_NOT_FOUND) | ||
|
||
if not project: | ||
return Response(status=status.HTTP_404_NOT_FOUND) | ||
|
||
serializer = ProjectPerformanceGeneralSettingsSerializer(data=request.data) | ||
|
||
if not serializer.is_valid(): | ||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) | ||
|
||
self.update_settings(project, request.data) | ||
return Response(status=status.HTTP_204_NO_CONTENT) | ||
|
||
def has_feature(self, project, request) -> bool: | ||
return features.has( | ||
"organizations:performance-view", project.organization, actor=request.user | ||
) | ||
|
||
def get_current_settings(self, project: Project): | ||
return project.get_option( | ||
SETTINGS_PROJECT_OPTION_KEY, DEFAULT_PROJECT_PERFORMANCE_GENERAL_SETTINGS | ||
) | ||
|
||
def update_settings(self, project: Project, new_settings: dict): | ||
current_settings = self.get_current_settings(project) | ||
project.update_option(SETTINGS_PROJECT_OPTION_KEY, {**current_settings, **new_settings}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
tests/sentry/api/endpoints/test_project_performance_general_settings.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
from django.urls import reverse | ||
from rest_framework.exceptions import ErrorDetail | ||
|
||
from sentry.testutils.cases import APITestCase | ||
from sentry.testutils.silo import region_silo_test | ||
|
||
PERFORMANCE_SETTINGS_FEATURES = { | ||
"organizations:performance-view": True, | ||
} | ||
|
||
|
||
@region_silo_test | ||
class ProjectPerformanceGeneralSettingsTest(APITestCase): | ||
endpoint = "sentry-api-0-project-performance-general-settings" | ||
|
||
def setUp(self) -> None: | ||
super().setUp() | ||
self.login_as(user=self.user, superuser=True) | ||
self.project = self.create_project() | ||
|
||
self.url = reverse( | ||
self.endpoint, | ||
kwargs={ | ||
"organization_slug": self.project.organization.slug, | ||
"project_slug": self.project.slug, | ||
}, | ||
) | ||
|
||
def test_get_project_general_settings_defaults(self): | ||
with self.feature(PERFORMANCE_SETTINGS_FEATURES): | ||
response = self.client.get(self.url, format="json") | ||
|
||
assert response.status_code == 200, response.content | ||
|
||
assert response.data["enable_images"] is False | ||
|
||
def test_get_returns_error_without_feature_enabled(self): | ||
with self.feature({}): | ||
response = self.client.get(self.url, format="json") | ||
assert response.status_code == 404 | ||
|
||
def test_updates_to_new_value(self): | ||
with self.feature(PERFORMANCE_SETTINGS_FEATURES): | ||
response = self.client.post( | ||
self.url, | ||
data={ | ||
"enable_images": True, | ||
}, | ||
) | ||
response = self.client.get(self.url, format="json") | ||
assert response.data["enable_images"] is True | ||
|
||
response = self.client.post( | ||
self.url, | ||
data={ | ||
"enable_images": False, | ||
}, | ||
) | ||
response = self.client.get(self.url, format="json") | ||
assert response.data["enable_images"] is False | ||
|
||
def test_update_project_setting_check_validation(self): | ||
with self.feature(PERFORMANCE_SETTINGS_FEATURES): | ||
response = self.client.post( | ||
self.url, | ||
data={ | ||
"enable_images": -1, | ||
}, | ||
) | ||
|
||
assert response.status_code == 400, response.content | ||
assert response.data == { | ||
"enable_images": [ErrorDetail(string="Must be a valid boolean.", code="invalid")] | ||
} |