Skip to content

Commit

Permalink
chore(sentry_apps): Move over misc sentry app endpoints to sentry_apps (
Browse files Browse the repository at this point in the history
#77887)

Move the endpoints that weren't in a subdirectory to sentry_apps!
[X] endpoints
[X] tests
[x] typing - turns out we do take in an RpcUser in various places when
creating/updating sentry apps
[] getsentry shim - N/A

issue ref(#73857)

---------

Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
Co-authored-by: Mark Story <[email protected]>
  • Loading branch information
3 people authored and 0Calories committed Sep 25, 2024
1 parent 19811fe commit 8fec0c0
Show file tree
Hide file tree
Showing 31 changed files with 73 additions and 74 deletions.
4 changes: 0 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,7 @@ module = [
"sentry.api.endpoints.group_integration_details",
"sentry.api.endpoints.group_integrations",
"sentry.api.endpoints.index",
"sentry.api.endpoints.integrations.sentry_apps.details",
"sentry.api.endpoints.integrations.sentry_apps.index",
"sentry.api.endpoints.integrations.sentry_apps.internal_app_token.index",
"sentry.api.endpoints.integrations.sentry_apps.publish_request",
"sentry.api.endpoints.integrations.sentry_apps.requests",
"sentry.api.endpoints.integrations.sentry_apps.stats.details",
"sentry.api.endpoints.internal.mail",
"sentry.api.endpoints.organization_details",
Expand Down
6 changes: 1 addition & 5 deletions src/sentry/api/endpoints/avatar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
from .organization import OrganizationAvatarEndpoint
from .sentry_app import SentryAppAvatarEndpoint

__all__ = (
"OrganizationAvatarEndpoint",
"SentryAppAvatarEndpoint",
)
__all__ = ("OrganizationAvatarEndpoint",)
21 changes: 0 additions & 21 deletions src/sentry/api/endpoints/integrations/sentry_apps/__init__.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
from .authorizations import SentryAppAuthorizationsEndpoint
from .components import OrganizationSentryAppComponentsEndpoint, SentryAppComponentsEndpoint
from .details import SentryAppDetailsEndpoint
from .features import SentryAppFeaturesEndpoint
from .index import SentryAppsEndpoint
from .interaction import SentryAppInteractionEndpoint
from .internal_app_token.details import SentryInternalAppTokenDetailsEndpoint
from .internal_app_token.index import SentryInternalAppTokensEndpoint
from .organization_sentry_apps import OrganizationSentryAppsEndpoint
from .publish_request import SentryAppPublishRequestEndpoint
from .requests import SentryAppRequestsEndpoint
from .rotate_secret import SentryAppRotateSecretEndpoint
from .stats.details import SentryAppStatsEndpoint
from .stats.index import SentryAppsStatsEndpoint

__all__ = (
"OrganizationSentryAppComponentsEndpoint",
"OrganizationSentryAppsEndpoint",
"SentryAppAuthorizationsEndpoint",
"SentryAppComponentsEndpoint",
"SentryAppDetailsEndpoint",
"SentryAppFeaturesEndpoint",
"SentryAppInteractionEndpoint",
"SentryAppPublishRequestEndpoint",
"SentryAppRequestsEndpoint",
"SentryAppRotateSecretEndpoint",
"SentryAppsEndpoint",
"SentryAppsStatsEndpoint",
"SentryAppStatsEndpoint",
"SentryInternalAppTokenDetailsEndpoint",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
from sentry.api.api_publish_status import ApiPublishStatus
from sentry.api.base import control_silo_endpoint
from sentry.api.bases import SentryAppBaseEndpoint, SentryInternalAppTokenPermission
from sentry.api.endpoints.integrations.sentry_apps.details import (
PARTNERSHIP_RESTRICTED_ERROR_MESSAGE,
)
from sentry.models.apitoken import ApiToken
from sentry.sentry_apps.api.endpoints.sentry_app_details import PARTNERSHIP_RESTRICTED_ERROR_MESSAGE
from sentry.sentry_apps.models.sentry_app_installation_token import SentryAppInstallationToken


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
from sentry.api.authentication import SessionNoAuthTokenAuthentication
from sentry.api.base import control_silo_endpoint
from sentry.api.bases import SentryAppBaseEndpoint, SentryInternalAppTokenPermission
from sentry.api.endpoints.integrations.sentry_apps.details import (
PARTNERSHIP_RESTRICTED_ERROR_MESSAGE,
)
from sentry.api.serializers.models.apitoken import ApiTokenSerializer
from sentry.exceptions import ApiTokenLimitError
from sentry.models.apitoken import ApiToken
from sentry.sentry_apps.api.endpoints.sentry_app_details import PARTNERSHIP_RESTRICTED_ERROR_MESSAGE
from sentry.sentry_apps.installations import SentryAppInstallationTokenCreator
from sentry.sentry_apps.models.sentry_app import MASKED_VALUE
from sentry.sentry_apps.models.sentry_app_installation import SentryAppInstallation
Expand Down
31 changes: 19 additions & 12 deletions src/sentry/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,25 @@
from sentry.sentry_apps.api.endpoints.installation_external_requests import (
SentryAppInstallationExternalRequestsEndpoint,
)
from sentry.sentry_apps.api.endpoints.organization_sentry_apps import OrganizationSentryAppsEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_authorizations import (
SentryAppAuthorizationsEndpoint,
)
from sentry.sentry_apps.api.endpoints.sentry_app_avatar import SentryAppAvatarEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_components import (
OrganizationSentryAppComponentsEndpoint,
SentryAppComponentsEndpoint,
)
from sentry.sentry_apps.api.endpoints.sentry_app_details import SentryAppDetailsEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_features import SentryAppFeaturesEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_installations import SentryAppInstallationsEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_interaction import SentryAppInteractionEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_publish_request import (
SentryAppPublishRequestEndpoint,
)
from sentry.sentry_apps.api.endpoints.sentry_app_requests import SentryAppRequestsEndpoint
from sentry.sentry_apps.api.endpoints.sentry_app_rotate_secret import SentryAppRotateSecretEndpoint
from sentry.sentry_apps.api.endpoints.sentry_apps import SentryAppsEndpoint
from sentry.uptime.endpoints.project_uptime_alert_details import ProjectUptimeAlertDetailsEndpoint
from sentry.uptime.endpoints.project_uptime_alert_index import ProjectUptimeAlertIndexEndpoint
from sentry.users.api.endpoints.authenticator_index import AuthenticatorIndexEndpoint
Expand Down Expand Up @@ -335,7 +353,7 @@
from .endpoints.auth_index import AuthIndexEndpoint
from .endpoints.auth_login import AuthLoginEndpoint
from .endpoints.auth_validate import AuthValidateEndpoint
from .endpoints.avatar import OrganizationAvatarEndpoint, SentryAppAvatarEndpoint
from .endpoints.avatar import OrganizationAvatarEndpoint
from .endpoints.broadcast_details import BroadcastDetailsEndpoint
from .endpoints.broadcast_index import BroadcastIndexEndpoint
from .endpoints.builtin_symbol_sources import BuiltinSymbolSourcesEndpoint
Expand Down Expand Up @@ -380,17 +398,6 @@
from .endpoints.grouping_configs import GroupingConfigsEndpoint
from .endpoints.index import IndexEndpoint
from .endpoints.integrations.sentry_apps import (
OrganizationSentryAppComponentsEndpoint,
OrganizationSentryAppsEndpoint,
SentryAppAuthorizationsEndpoint,
SentryAppComponentsEndpoint,
SentryAppDetailsEndpoint,
SentryAppFeaturesEndpoint,
SentryAppInteractionEndpoint,
SentryAppPublishRequestEndpoint,
SentryAppRequestsEndpoint,
SentryAppRotateSecretEndpoint,
SentryAppsEndpoint,
SentryAppsStatsEndpoint,
SentryAppStatsEndpoint,
SentryInternalAppTokenDetailsEndpoint,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from sentry.sentry_apps.logic import SentryAppUpdater
from sentry.sentry_apps.models.sentry_app import SentryApp
from sentry.sentry_apps.models.sentry_app_installation import SentryAppInstallation
from sentry.users.models.user import User
from sentry.users.services.user.model import RpcUser
from sentry.utils.audit import create_audit_entry

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -91,6 +93,10 @@ def put(self, request: Request, sentry_app) -> Response:

if serializer.is_valid():
result = serializer.validated_data

assert isinstance(
request.user, (User, RpcUser)
), "User must be authenticated to update a Sentry App"
updated_app = SentryAppUpdater(
sentry_app=sentry_app,
name=result.get("name"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from collections.abc import Iterable

from rest_framework.request import Request
from rest_framework.response import Response

Expand All @@ -10,6 +12,8 @@
from sentry.models.avatars.sentry_app_avatar import SentryAppAvatar, SentryAppAvatarTypes
from sentry.models.organizationmapping import OrganizationMapping
from sentry.sentry_apps.logic import SentryAppUpdater
from sentry.users.models.user import User
from sentry.users.services.user.model import RpcUser
from sentry.utils import email


Expand Down Expand Up @@ -54,6 +58,9 @@ def post(self, request: Request, sentry_app) -> Response:
status=400,
)

assert isinstance(request.user, User) or isinstance(
request.user, RpcUser
), "User must be authenticated to update a Sentry App"
SentryAppUpdater(
sentry_app=sentry_app,
status=SentryAppStatus.PUBLISH_REQUEST_INPROGRESS_STR,
Expand All @@ -65,8 +72,11 @@ def post(self, request: Request, sentry_app) -> Response:
org_slug = "<unknown>" if org_mapping is None else org_mapping.slug
message = f"User {request.user.email} of organization {org_slug} wants to publish {sentry_app.slug}\n"

for question_pair in request.data.get("questionnaire"):
message += "\n\n>{}\n{}".format(question_pair["question"], question_pair["answer"])
questionnaire: Iterable[dict[str, str]] = request.data.get("questionnaire", [])
for question_pair in questionnaire:
message += "\n\n>{}\n{}".format(
question_pair.get("question", ""), question_pair.get("answer", "")
)

subject = "Sentry Integration Publication Request from %s" % org_slug

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
INVALID_DATE_FORMAT_MESSAGE = "Invalid date format. Format must be YYYY-MM-DD HH:MM:SS."


def filter_by_date(request: Mapping[str, Any], start: float, end: float) -> bool:
def filter_by_date(request: Mapping[str, Any], start: datetime, end: datetime) -> bool:
date_str = request.get("date")
if not date_str:
return False
timestamp = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S.%f+00:00").replace(microsecond=0)
return start <= timestamp <= end


def filter_by_organization(request: Mapping[str, Any], organization: Organization) -> bool:
def filter_by_organization(request: Mapping[str, Any], organization: Organization | None) -> bool:
if not organization:
return True
return request["organization_id"] == organization.id
Expand Down Expand Up @@ -57,27 +57,31 @@ def get(self, request: Request, sentry_app) -> Response:
:qparam string start: Optionally specify a date to begin at. Format must be YYYY-MM-DD HH:MM:SS
:qparam string end: Optionally specify a date to end at. Format must be YYYY-MM-DD HH:MM:SS
"""

date_format = "%Y-%m-%d %H:%M:%S"
now = datetime.now().strftime(date_format)
default_start = "2000-01-01 00:00:00"
start_time: datetime = datetime.strptime("2000-01-01 00:00:00", date_format)
end_time: datetime = datetime.now()

event_type = request.GET.get("eventType")
errors_only = request.GET.get("errorsOnly")
org_slug = request.GET.get("organizationSlug")
start = request.GET.get("start", default_start)
end = request.GET.get("end", now)
start_parameter = request.GET.get("start", None)
end_parameter = request.GET.get("end", None)

try:
start = datetime.strptime(start, date_format)
start_time = (
datetime.strptime(start_parameter, date_format) if start_parameter else start_time
)
except ValueError:
return Response({"detail": INVALID_DATE_FORMAT_MESSAGE}, status=400)

try:
end = datetime.strptime(end, date_format)

end_time = datetime.strptime(end_parameter, date_format) if end_parameter else end_time
except ValueError:
return Response({"detail": INVALID_DATE_FORMAT_MESSAGE}, status=400)

kwargs = {}
kwargs: dict[Any, Any] = {}
if event_type:
if event_type not in EXTENDED_VALID_EVENTS:
return Response({"detail": "Invalid event type."}, status=400)
Expand All @@ -95,7 +99,9 @@ def get(self, request: Request, sentry_app) -> Response:

filtered_requests = []
for i, req in enumerate(buffer.get_requests(**kwargs)):
if filter_by_date(req, start, end) and filter_by_organization(req, organization):
if filter_by_date(req, start_time, end_time) and filter_by_organization(
req, organization
):
filtered_requests.append(BufferedRequest(id=i, data=req))

return Response(serialize(filtered_requests, request.user, RequestSerializer(sentry_app)))
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from sentry.constants import SentryAppStatus
from sentry.sentry_apps.logic import SentryAppCreator
from sentry.sentry_apps.models.sentry_app import SentryApp
from sentry.users.models.user import User
from sentry.users.services.user.model import RpcUser
from sentry.users.services.user.service import user_service

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -115,6 +117,9 @@ def post(self, request: Request, organization) -> Response:
data["author"] = data["author"] or organization.name

try:
assert isinstance(
request.user, (User, RpcUser)
), "User must be authenticated to create a Sentry App"
sentry_app = SentryAppCreator(
name=data["name"],
author=data["author"],
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/sentry_apps/installations.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class SentryAppInstallationTokenCreator:
expires_at: datetime.date | None = None
generate_audit: bool = False

def run(self, user: User, request: HttpRequest | None = None) -> ApiToken:
def run(self, user: User | RpcUser, request: HttpRequest | None = None) -> ApiToken:
with transaction.atomic(router.db_for_write(ApiToken)):
self._check_token_limit()
api_token = self._create_api_token()
Expand Down
18 changes: 9 additions & 9 deletions src/sentry/sentry_apps/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class SentryAppUpdater:
popularity: int | None = None
features: list[int] | None = None

def run(self, user: User) -> SentryApp:
def run(self, user: User | RpcUser) -> SentryApp:
with transaction.atomic(router.db_for_write(User)):
self._update_name()
self._update_author()
Expand All @@ -122,7 +122,7 @@ def run(self, user: User) -> SentryApp:
self.record_analytics(user, new_schema_elements)
return self.sentry_app

def _update_features(self, user: User) -> None:
def _update_features(self, user: User | RpcUser) -> None:
if self.features is not None:
if not _is_elevated_user(user) and self.sentry_app.status == SentryAppStatus.PUBLISHED:
raise APIError("Cannot update features on a published integration.")
Expand All @@ -141,7 +141,7 @@ def _update_author(self) -> None:
if self.author is not None:
self.sentry_app.author = self.author

def _update_status(self, user: User) -> None:
def _update_status(self, user: User | RpcUser) -> None:
if self.status is not None:
if _is_elevated_user(user):
if self.status == SentryAppStatus.PUBLISHED_STR:
Expand Down Expand Up @@ -239,7 +239,7 @@ def _update_allowed_origins(self) -> None:
self.sentry_app.application.allowed_origins = "\n".join(self.allowed_origins)
self.sentry_app.application.save()

def _update_popularity(self, user: User) -> None:
def _update_popularity(self, user: User | RpcUser) -> None:
if self.popularity is not None:
if _is_elevated_user(user):
self.sentry_app.popularity = self.popularity
Expand Down Expand Up @@ -269,7 +269,7 @@ def _create_ui_components(self) -> None:
type=element["type"], sentry_app_id=self.sentry_app.id, schema=element
)

def record_analytics(self, user: User, new_schema_elements: set[str] | None) -> None:
def record_analytics(self, user: User | RpcUser, new_schema_elements: set[str] | None) -> None:
analytics.record(
"sentry_app.updated",
user_id=user.id,
Expand Down Expand Up @@ -306,7 +306,7 @@ def __post_init__(self) -> None:
def run(
self,
*,
user: User,
user: User | RpcUser,
request: HttpRequest | None = None,
skip_default_auth_token: bool = False,
) -> SentryApp:
Expand Down Expand Up @@ -407,7 +407,7 @@ def _create_integration_feature(self, sentry_app: SentryApp) -> None:
sentry_sdk.capture_message("IntegrityError while creating IntegrationFeature")

def _install(
self, *, slug: str, user: User, request: HttpRequest | None
self, *, slug: str, user: User | RpcUser, request: HttpRequest | None
) -> SentryAppInstallation:
return SentryAppInstallationCreator(
organization_id=self.organization_id,
Expand All @@ -416,7 +416,7 @@ def _install(
).run(user=user, request=request)

def _create_access_token(
self, user: User, install: SentryAppInstallation, request: HttpRequest | None
self, user: User | RpcUser, install: SentryAppInstallation, request: HttpRequest | None
) -> None:
install.api_token = SentryAppInstallationTokenCreator(sentry_app_installation=install).run(
request=request, user=user
Expand Down Expand Up @@ -444,7 +444,7 @@ def audit(self, request: HttpRequest | None, sentry_app: SentryApp) -> None:
data={"name": sentry_app.name},
)

def record_analytics(self, user: User, sentry_app: SentryApp) -> None:
def record_analytics(self, user: User | RpcUser, sentry_app: SentryApp) -> None:
analytics.record(
"sentry_app.created",
user_id=user.id,
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import orjson

from sentry import audit_log, deletions
from sentry.api.endpoints.integrations.sentry_apps.details import (
PARTNERSHIP_RESTRICTED_ERROR_MESSAGE,
)
from sentry.constants import SentryAppStatus
from sentry.models.auditlogentry import AuditLogEntry
from sentry.models.organizationmember import OrganizationMember
from sentry.sentry_apps.api.endpoints.sentry_app_details import PARTNERSHIP_RESTRICTED_ERROR_MESSAGE
from sentry.sentry_apps.models.sentry_app import SentryApp
from sentry.sentry_apps.models.sentry_app_installation import SentryAppInstallation
from sentry.sentry_apps.models.servicehook import ServiceHook
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from django.urls import reverse

from sentry.api.endpoints.integrations.sentry_apps.requests import INVALID_DATE_FORMAT_MESSAGE
from sentry.sentry_apps.api.endpoints.sentry_app_requests import INVALID_DATE_FORMAT_MESSAGE
from sentry.testutils.cases import APITestCase
from sentry.testutils.helpers.datetime import before_now, freeze_time, iso_format
from sentry.testutils.skips import requires_snuba
Expand Down

0 comments on commit 8fec0c0

Please sign in to comment.