def test_has_sessions_flag(self): result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["hasSessions"] is False self.project.first_event = timezone.now() self.project.update(flags=F("flags").bitor(Project.flags.has_sessions)) result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["hasSessions"] is True
def test_first_event_properties(self): result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["firstEvent"] is None assert result["firstTransactionEvent"] is False self.project.first_event = timezone.now() self.project.update(flags=F("flags").bitor(Project.flags.has_transactions)) result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["firstEvent"] assert result["firstTransactionEvent"] is True
def test_avoid_hidden_and_no_env(self): hidden_env = Environment.objects.create( organization_id=self.organization.id, name="staging 2") EnvironmentProject.objects.create(project=self.project, environment=hidden_env, is_hidden=True) no_env = Environment.objects.create( organization_id=self.organization.id, name="") no_env.add_project(self.project) no_env.save() result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["id"] == six.text_type(self.project.id) assert result["name"] == self.project.name assert result["slug"] == self.project.slug assert result["firstEvent"] == self.project.first_event assert "releases" in result["features"] assert result["platform"] == self.project.platform assert result["latestDeploys"] == { "production": { "dateFinished": self.date, "version": self.release.version } } assert result["latestRelease"] == {"version": self.release.version} assert result["environments"] == ["production", "staging"]
def test_stats_with_transactions(self): two_min_ago = before_now(minutes=2) self.store_event( data={ "event_id": "d" * 32, "message": "oh no", "timestamp": iso_format(two_min_ago) }, project_id=self.project.id, ) transaction = load_data("transaction", timestamp=two_min_ago) self.store_event(data=transaction, project_id=self.project.id) serializer = ProjectSummarySerializer(stats_period="24h", transaction_stats=True) results = serialize([self.project], self.user, serializer) assert "stats" in results[0] assert 24 == len(results[0]["stats"]) assert [1] == [v[1] for v in results[0]["stats"] if v[1] > 0] assert "transactionStats" in results[0] assert 24 == len(results[0]["transactionStats"]) assert [1] == [ v[1] for v in results[0]["transactionStats"] if v[1] > 0 ]
def test_avoid_hidden_and_no_env(self): hidden_env = Environment.objects.create( organization_id=self.organization.id, name='staging 2', ) EnvironmentProject.objects.create( project=self.project, environment=hidden_env, is_hidden=True, ) no_env = Environment.objects.create( organization_id=self.organization.id, name='', ) no_env.add_project(self.project) no_env.save() result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result['id'] == six.text_type(self.project.id) assert result['name'] == self.project.name assert result['slug'] == self.project.slug assert result['firstEvent'] == self.project.first_event assert 'releases' in result['features'] assert result['platform'] == self.project.platform assert result['latestDeploys'] == { 'production': { 'dateFinished': self.date, 'version': self.release.version } } assert result['latestRelease'] == {'version': self.release.version} assert result['environments'] == ['production', 'staging']
def test_stats_with_sessions_and_none_crash_free_rates( self, get_current_and_previous_crash_free_rates, check_has_health_data): """ Test that ensures if both `currentCrashFreeRate` and `previousCrashFreeRate` are None, then we need to make a call to `check_has_health_data` to know if we have health data in that specific project_id(s) """ check_has_health_data.return_value = {self.project.id} get_current_and_previous_crash_free_rates.return_value = { self.project.id: { "currentCrashFreeRate": None, "previousCrashFreeRate": None, } } serializer = ProjectSummarySerializer(stats_period="24h", session_stats=True) results = serialize([self.project], self.user, serializer) assert "sessionStats" in results[0] assert results[0]["sessionStats"]["previousCrashFreeRate"] is None assert results[0]["sessionStats"]["currentCrashFreeRate"] is None assert results[0]["sessionStats"]["hasHealthData"] check_has_health_data.assert_called() # NOQA
def serialize_on_result(result): environment_id = self._get_environment_id_from_request( request, organization.id) serializer = ProjectSummarySerializer( environment_id=environment_id, stats_period=stats_period, ) return serialize(result, request.user, serializer)
def serialize_on_result(result): transaction_stats = request.GET.get("transactionStats") environment_id = self._get_environment_id_from_request(request, organization.id) serializer = ProjectSummarySerializer( environment_id=environment_id, stats_period=stats_period, transaction_stats=transaction_stats, ) return serialize(result, request.user, serializer)
def test_stats_errors(self): two_min_ago = before_now(minutes=2) self.store_event( data={"event_id": "d" * 32, "message": "oh no", "timestamp": iso_format(two_min_ago)}, project_id=self.project.id, ) serializer = ProjectSummarySerializer(stats_period="24h") results = serialize([self.project], self.user, serializer) assert "stats" in results[0] assert 24 == len(results[0]["stats"]) assert [1] == [v[1] for v in results[0]["stats"] if v[1] > 0]
def test_user_reports(self): result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["hasUserReports"] is False UserReport.objects.create( project=self.project, event_id="1", name="foo", email="*****@*****.**", comments="It broke!", ) UserReport.objects.create( project=self.project, event_id="2", name="foo", email="*****@*****.**", comments="It broke again!", ) result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["hasUserReports"] is True
def serialize(self, obj, attrs, user, access): from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer context = super().serialize(obj, attrs, user, access) team_list = self._team_list(obj, access) project_list = self._project_list(obj, access) context["teams"] = serialize(team_list, user, TeamSerializer()) context["projects"] = serialize(project_list, user, ProjectSummarySerializer()) return context
def test_simple(self): result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["id"] == str(self.project.id) assert result["name"] == self.project.name assert result["slug"] == self.project.slug assert result["firstEvent"] == self.project.first_event assert "releases" in result["features"] assert result["platform"] == self.project.platform assert result["latestDeploys"] == { "production": {"dateFinished": self.date, "version": self.release.version} } assert result["latestRelease"] == {"version": self.release.version} assert result["environments"] == ["production", "staging"]
def serialize(self, obj, attrs, user, access): from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer context = super(DetailedOrganizationSerializerWithProjectsAndTeams, self).serialize(obj, attrs, user, access) team_list = self._team_list(obj, access) project_list = self._project_list(obj, access) context['teams'] = serialize(team_list, user, TeamSerializer()) context['projects'] = serialize(project_list, user, ProjectSummarySerializer()) return context
def test_simple(self): result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result['id'] == six.text_type(self.project.id) assert result['name'] == self.project.name assert result['slug'] == self.project.slug assert result['firstEvent'] == self.project.first_event assert 'releases' in result['features'] assert result['platform'] == self.project.platform assert result['latestDeploys'] == { 'production': {'dateFinished': self.date, 'version': self.release.version} } assert result['latestRelease'] == serialize(self.release) assert result['environments'] == ['production', 'staging']
def test_simple(self): date = datetime.datetime(2018, 1, 12, 3, 8, 25, tzinfo=timezone.utc) user = self.create_user(username='******') organization = self.create_organization(owner=user) team = self.create_team(organization=organization) project = self.create_project(teams=[team], organization=organization, name='foo') project.flags.has_releases = True project.save() release = Release.objects.create( organization_id=organization.id, version='1', ) environment = Environment.objects.create( organization_id=organization.id, name='production', ) deploy = Deploy.objects.create(environment_id=environment.id, organization_id=organization.id, release=release, date_finished=date) ReleaseProjectEnvironment.objects.create(project_id=project.id, release_id=release.id, environment_id=environment.id, last_deploy_id=deploy.id) result = serialize(project, user, ProjectSummarySerializer()) assert result['id'] == six.text_type(project.id) assert result['name'] == project.name assert result['slug'] == project.slug assert result['firstEvent'] == project.first_event assert 'releases' in result['features'] assert result['platform'] == project.platform assert result['latestDeploys'] == { 'production': { 'dateFinished': date, 'version': '1' } }
def test_no_enviroments(self): # remove environments and related models Deploy.objects.all().delete() Release.objects.all().delete() Environment.objects.all().delete() result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result['id'] == six.text_type(self.project.id) assert result['name'] == self.project.name assert result['slug'] == self.project.slug assert result['firstEvent'] == self.project.first_event assert 'releases' in result['features'] assert result['platform'] == self.project.platform assert result['latestDeploys'] is None assert result['latestRelease'] is None assert result['environments'] == []
def serialize( # type: ignore self, obj: Organization, attrs: Mapping[str, Any], user: User, access: Access ) -> DetailedOrganizationSerializerWithProjectsAndTeamsResponse: from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer context = cast( DetailedOrganizationSerializerWithProjectsAndTeamsResponse, super().serialize(obj, attrs, user, access), ) team_list = self._team_list(obj, access) project_list = self._project_list(obj, access) context["teams"] = serialize(team_list, user, TeamSerializer()) context["projects"] = serialize(project_list, user, ProjectSummarySerializer()) return context
def test_no_environments(self): # remove environments and related models Deploy.objects.all().delete() Release.objects.all().delete() Environment.objects.all().delete() result = serialize(self.project, self.user, ProjectSummarySerializer()) assert result["id"] == six.text_type(self.project.id) assert result["name"] == self.project.name assert result["slug"] == self.project.slug assert result["firstEvent"] == self.project.first_event assert "releases" in result["features"] assert result["platform"] == self.project.platform assert result["latestDeploys"] is None assert result["latestRelease"] is None assert result["environments"] == []
def test_stats_with_sessions(self, get_current_and_previous_crash_free_rates, check_has_health_data): get_current_and_previous_crash_free_rates.return_value = { self.project.id: { "currentCrashFreeRate": 75.63453, "previousCrashFreeRate": 99.324543, } } serializer = ProjectSummarySerializer(stats_period="24h", session_stats=True) results = serialize([self.project], self.user, serializer) assert "sessionStats" in results[0] assert results[0]["sessionStats"]["previousCrashFreeRate"] == 99.324543 assert results[0]["sessionStats"]["currentCrashFreeRate"] == 75.63453 assert results[0]["sessionStats"]["hasHealthData"] check_has_health_data.assert_not_called() # NOQA
def test_simple(self): date = datetime.datetime(2018, 1, 12, 3, 8, 25, tzinfo=timezone.utc) user = self.create_user(username='******') organization = self.create_organization(owner=user) team = self.create_team(organization=organization) project = self.create_project(teams=[team], organization=organization, name='foo') release = Release.objects.create( organization_id=organization.id, version='1', ) environment = Environment.objects.create( organization_id=organization.id, name='production', ) deploy = Deploy.objects.create(environment_id=environment.id, organization_id=organization.id, release=release, date_finished=date) ReleaseProjectEnvironment.objects.create(project_id=project.id, release_id=release.id, environment_id=environment.id, last_deploy_id=deploy.id) result = serialize(project, user, ProjectSummarySerializer()) assert result['latestDeploys'] == { 'production': { 'dateFinished': date, 'version': '1' } }
def serialize(self, obj, attrs, user, access): from sentry import experiments from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer team_list = self._team_list(obj, access) project_list = self._project_list(obj, access) onboarding_tasks = list( OrganizationOnboardingTask.objects.filter( organization=obj, ).select_related('user')) experiment_assignments = experiments.all(org=obj, actor=user) context = super(DetailedOrganizationSerializer, self).serialize(obj, attrs, user) max_rate = quotas.get_maximum_quota(obj) context['experiments'] = experiment_assignments context['quota'] = { 'maxRate': max_rate[0], 'maxRateInterval': max_rate[1], 'accountLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:account-rate-limit', default=ACCOUNT_RATE_LIMIT_DEFAULT, )), 'projectLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:project-rate-limit', default=PROJECT_RATE_LIMIT_DEFAULT, )), } context.update({ 'isDefault': obj.is_default, 'defaultRole': obj.default_role, 'availableRoles': [{ 'id': r.id, 'name': r.name, } for r in roles.get_all()], 'openMembership': bool(obj.flags.allow_joinleave), 'require2FA': bool(obj.flags.require_2fa), 'allowSharedIssues': not obj.flags.disable_shared_issues, 'enhancedPrivacy': bool(obj.flags.enhanced_privacy), 'dataScrubber': bool( obj.get_option('sentry:require_scrub_data', REQUIRE_SCRUB_DATA_DEFAULT)), 'dataScrubberDefaults': bool( obj.get_option('sentry:require_scrub_defaults', REQUIRE_SCRUB_DEFAULTS_DEFAULT)), 'sensitiveFields': obj.get_option('sentry:sensitive_fields', SENSITIVE_FIELDS_DEFAULT) or [], 'safeFields': obj.get_option('sentry:safe_fields', SAFE_FIELDS_DEFAULT) or [], 'storeCrashReports': bool( obj.get_option('sentry:store_crash_reports', STORE_CRASH_REPORTS_DEFAULT)), 'scrubIPAddresses': bool( obj.get_option('sentry:require_scrub_ip_address', REQUIRE_SCRUB_IP_ADDRESS_DEFAULT)), 'scrapeJavaScript': bool( obj.get_option('sentry:scrape_javascript', SCRAPE_JAVASCRIPT_DEFAULT)), 'trustedRelays': obj.get_option('sentry:trusted-relays', TRUSTED_RELAYS_DEFAULT) or [], }) context['teams'] = serialize(team_list, user, TeamSerializer()) context['projects'] = serialize(project_list, user, ProjectSummarySerializer()) context['access'] = access.scopes context[ 'pendingAccessRequests'] = OrganizationAccessRequest.objects.filter( team__organization=obj, ).count() context['onboardingTasks'] = serialize(onboarding_tasks, user, OnboardingTasksSerializer()) return context
def test_multiple_environments_deploys(self): env_1_release = self.create_release(self.project) env_1_deploy = Deploy.objects.create( environment_id=self.environment_1.id, organization_id=self.organization.id, release=env_1_release, date_finished=self.date + timedelta(minutes=20), ) ReleaseProjectEnvironment.objects.create( project_id=self.project.id, release_id=env_1_release.id, environment_id=self.environment_1.id, last_deploy_id=env_1_deploy.id, ) env_2_release = self.create_release(self.project) Deploy.objects.create( environment_id=self.environment_2.id, organization_id=self.organization.id, release=env_2_release, date_finished=self.date - timedelta(days=5), ) env_2_deploy = Deploy.objects.create( environment_id=self.environment_2.id, organization_id=self.organization.id, release=env_2_release, date_finished=self.date, ) ReleaseProjectEnvironment.objects.create( project_id=self.project.id, release_id=env_2_release.id, environment_id=self.environment_2.id, last_deploy_id=env_2_deploy.id, ) other_project = self.create_project() other_project_release = self.create_release(other_project) other_project_deploy = Deploy.objects.create( environment_id=self.environment_2.id, organization_id=self.organization.id, release=other_project_release, date_finished=self.date - timedelta(minutes=350), ) ReleaseProjectEnvironment.objects.create( project_id=other_project.id, release_id=other_project_release.id, environment_id=self.environment_2.id, last_deploy_id=other_project_deploy.id, ) result = serialize([self.project, other_project], self.user, ProjectSummarySerializer()) assert result[0]["id"] == six.text_type(self.project.id) assert result[0]["latestDeploys"] == { self.environment_1.name: { "version": env_1_release.version, "dateFinished": env_1_deploy.date_finished, }, self.environment_2.name: { "version": env_2_release.version, "dateFinished": env_2_deploy.date_finished, }, } assert result[1]["id"] == six.text_type(other_project.id) assert result[1]["latestDeploys"] == { self.environment_2.name: { "version": other_project_release.version, "dateFinished": other_project_deploy.date_finished, } }
def get(self, request: Request, organization) -> Response: """ List an Organization's Projects ``````````````````````````````` Return a list of projects bound to a organization. :pparam string organization_slug: the slug of the organization for which the projects should be listed. :auth: required """ stats_period = request.GET.get("statsPeriod") collapse = request.GET.getlist("collapse", []) if stats_period not in (None, "", "1h", "24h", "7d", "14d", "30d"): return Response( { "error": { "params": { "stats_period": { "message": ERR_INVALID_STATS_PERIOD } } } }, status=400, ) elif not stats_period: # disable stats stats_period = None if request.auth and not request.user.is_authenticated: # TODO: remove this, no longer supported probably if hasattr(request.auth, "project"): team_list = list(request.auth.project.teams.all()) queryset = Project.objects.filter(id=request.auth.project.id) elif request.auth.organization is not None: org = request.auth.organization team_list = list(Team.objects.filter(organization=org)) queryset = Project.objects.filter(teams__in=team_list) else: return Response( { "detail": "Current access does not point to " "organization." }, status=400) else: queryset = Project.objects.filter(organization=organization) order_by = ["slug"] if request.user.is_authenticated: queryset = queryset.extra( select={ "is_bookmarked": """exists ( select * from sentry_projectbookmark spb where spb.project_id = sentry_project.id and spb.user_id = %s )""" }, select_params=(request.user.id, ), ) order_by.insert(0, "-is_bookmarked") query = request.GET.get("query") if query: tokens = tokenize_query(query) for key, value in tokens.items(): if key == "query": value = " ".join(value) queryset = queryset.filter( Q(name__icontains=value) | Q(slug__icontains=value)) elif key == "id": queryset = queryset.filter(id__in=value) elif key == "slug": queryset = queryset.filter(slug__in=value) elif key == "team": team_list = list(Team.objects.filter(slug__in=value)) queryset = queryset.filter(teams__in=team_list) elif key == "!team": team_list = list(Team.objects.filter(slug__in=value)) queryset = queryset.exclude(teams__in=team_list) elif key == "is_member": queryset = queryset.filter( teams__organizationmember__user=request.user) else: queryset = queryset.none() queryset = queryset.filter(status=ProjectStatus.VISIBLE).distinct() # TODO(davidenwang): remove this after frontend requires only paginated projects get_all_projects = request.GET.get("all_projects") == "1" if get_all_projects: queryset = queryset.order_by("slug").select_related("organization") return Response( serialize(list(queryset), request.user, ProjectSummarySerializer(collapse=collapse))) else: def serialize_on_result(result): transaction_stats = request.GET.get("transactionStats") session_stats = request.GET.get("sessionStats") environment_id = self._get_environment_id_from_request( request, organization.id) serializer = ProjectSummarySerializer( environment_id=environment_id, stats_period=stats_period, transaction_stats=transaction_stats, session_stats=session_stats, collapse=collapse, ) return serialize(result, request.user, serializer) return self.paginate( request=request, queryset=queryset, order_by=order_by, on_results=serialize_on_result, paginator_cls=OffsetPaginator, )
def serialize(self, obj, attrs, user): from sentry import features, experiments from sentry.app import env from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer team_list = sorted(Team.objects.filter( organization=obj, status=TeamStatus.VISIBLE, ), key=lambda x: x.slug) for team in team_list: team._organization_cache = obj project_list = sorted(Project.objects.filter( organization=obj, status=ProjectStatus.VISIBLE, ), key=lambda x: x.slug) for project in project_list: project._organization_cache = obj onboarding_tasks = list( OrganizationOnboardingTask.objects.filter( organization=obj, ).select_related('user')) feature_list = [] if features.has('organizations:sso', obj, actor=user): feature_list.append('sso') if features.has('organizations:onboarding', obj, actor=user) and \ not OrganizationOption.objects.filter(organization=obj).exists(): feature_list.append('onboarding') if features.has('organizations:api-keys', obj, actor=user) or \ ApiKey.objects.filter(organization=obj).exists(): feature_list.append('api-keys') if features.has('organizations:group-unmerge', obj, actor=user): feature_list.append('group-unmerge') if features.has('organizations:github-apps', obj, actor=user): feature_list.append('github-apps') if features.has('organizations:require-2fa', obj, actor=user): feature_list.append('require-2fa') if features.has('organizations:repos', obj, actor=user): feature_list.append('repos') if features.has('organizations:internal-catchall', obj, actor=user): feature_list.append('internal-catchall') if features.has('organizations:new-issue-ui', obj, actor=user): feature_list.append('new-issue-ui') if features.has('organizations:github-enterprise', obj, actor=user): feature_list.append('github-enterprise') if features.has('organizations:bitbucket-integration', obj, actor=user): feature_list.append('bitbucket-integration') if features.has('organizations:jira-integration', obj, actor=user): feature_list.append('jira-integration') if features.has('organizations:vsts-integration', obj, actor=user): feature_list.append('vsts-integration') if features.has('organizations:integrations-issue-basic', obj, actor=user): feature_list.append('integrations-issue-basic') if features.has('organizations:integrations-issue-sync', obj, actor=user): feature_list.append('integrations-issue-sync') if features.has('organizations:suggested-commits', obj, actor=user): feature_list.append('suggested-commits') if features.has('organizations:new-teams', obj, actor=user): feature_list.append('new-teams') if features.has('organizations:unreleased-changes', obj, actor=user): feature_list.append('unreleased-changes') if features.has('organizations:relay', obj, actor=user): feature_list.append('relay') if features.has('organizations:js-loader', obj, actor=user): feature_list.append('js-loader') if features.has('organizations:health', obj, actor=user): feature_list.append('health') if features.has('organizations:discover', obj, actor=user): feature_list.append('discover') if features.has('organizations:events-stream', obj, actor=user): feature_list.append('events-stream') if OrganizationOption.objects.filter( organization=obj, key__in=LEGACY_RATE_LIMIT_OPTIONS).exists(): feature_list.append('legacy-rate-limits') if getattr(obj.flags, 'allow_joinleave'): feature_list.append('open-membership') if not getattr(obj.flags, 'disable_shared_issues'): feature_list.append('shared-issues') if getattr(obj.flags, 'require_2fa'): feature_list.append('require-2fa') if features.has('organizations:event-attachments', obj, actor=user): feature_list.append('event-attachments') experiment_assignments = experiments.all(org=obj) context = super(DetailedOrganizationSerializer, self).serialize(obj, attrs, user) max_rate = quotas.get_maximum_quota(obj) context['experiments'] = experiment_assignments context['quota'] = { 'maxRate': max_rate[0], 'maxRateInterval': max_rate[1], 'accountLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:account-rate-limit', default=ACCOUNT_RATE_LIMIT_DEFAULT, )), 'projectLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:project-rate-limit', default=PROJECT_RATE_LIMIT_DEFAULT, )), } context.update({ 'isDefault': obj.is_default, 'defaultRole': obj.default_role, 'availableRoles': [{ 'id': r.id, 'name': r.name, } for r in roles.get_all()], 'openMembership': bool(obj.flags.allow_joinleave), 'require2FA': bool(obj.flags.require_2fa), 'allowSharedIssues': not obj.flags.disable_shared_issues, 'enhancedPrivacy': bool(obj.flags.enhanced_privacy), 'dataScrubber': bool( obj.get_option('sentry:require_scrub_data', REQUIRE_SCRUB_DATA_DEFAULT)), 'dataScrubberDefaults': bool( obj.get_option('sentry:require_scrub_defaults', REQUIRE_SCRUB_DEFAULTS_DEFAULT)), 'sensitiveFields': obj.get_option('sentry:sensitive_fields', SENSITIVE_FIELDS_DEFAULT) or [], 'safeFields': obj.get_option('sentry:safe_fields', SAFE_FIELDS_DEFAULT) or [], 'storeCrashReports': bool( obj.get_option('sentry:store_crash_reports', STORE_CRASH_REPORTS_DEFAULT)), 'scrubIPAddresses': bool( obj.get_option('sentry:require_scrub_ip_address', REQUIRE_SCRUB_IP_ADDRESS_DEFAULT)), 'scrapeJavaScript': bool( obj.get_option('sentry:scrape_javascript', SCRAPE_JAVASCRIPT_DEFAULT)), 'trustedRelays': obj.get_option('sentry:trusted-relays', TRUSTED_RELAYS_DEFAULT) or [], }) context['teams'] = serialize(team_list, user, TeamSerializer()) context['projects'] = serialize(project_list, user, ProjectSummarySerializer()) if env.request: context['access'] = access.from_request(env.request, obj).scopes else: context['access'] = access.from_user(user, obj).scopes context['features'] = feature_list context[ 'pendingAccessRequests'] = OrganizationAccessRequest.objects.filter( team__organization=obj, ).count() context['onboardingTasks'] = serialize(onboarding_tasks, user, OnboardingTasksSerializer()) return context
def serialize(self, obj, attrs, user): from sentry import features, experiments from sentry.features.base import OrganizationFeature from sentry.app import env from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer team_list = sorted(Team.objects.filter( organization=obj, status=TeamStatus.VISIBLE, ), key=lambda x: x.slug) for team in team_list: team._organization_cache = obj project_list = sorted(Project.objects.filter( organization=obj, status=ProjectStatus.VISIBLE, ), key=lambda x: x.slug) for project in project_list: project._organization_cache = obj onboarding_tasks = list( OrganizationOnboardingTask.objects.filter( organization=obj, ).select_related('user') ) # Retrieve all registered organization features org_features = features.all(feature_type=OrganizationFeature).keys() feature_list = set() for feature_name in org_features: if not feature_name.startswith('organizations:'): continue if features.has(feature_name, obj, actor=user): # Remove the organization scope prefix feature_list.add(feature_name[len('organizations:'):]) # Do not include the onboarding feature if OrganizationOptions exist if 'onboarding' in feature_list and \ OrganizationOption.objects.filter(organization=obj).exists(): feature_list.remove('onboarding') # Include api-keys feature if they previously had any api-keys if 'api-keys' not in feature_list and ApiKey.objects.filter(organization=obj).exists(): feature_list.add('api-keys') # Organization flag features (not provided through the features module) if OrganizationOption.objects.filter( organization=obj, key__in=LEGACY_RATE_LIMIT_OPTIONS).exists(): feature_list.add('legacy-rate-limits') if getattr(obj.flags, 'allow_joinleave'): # noqa: B009 feature_list.add('open-membership') if not getattr(obj.flags, 'disable_shared_issues'): # noqa: B009 feature_list.add('shared-issues') if getattr(obj.flags, 'require_2fa'): # noqa: B009 feature_list.add('require-2fa') experiment_assignments = experiments.all(org=obj, actor=user) context = super(DetailedOrganizationSerializer, self).serialize(obj, attrs, user) max_rate = quotas.get_maximum_quota(obj) context['experiments'] = experiment_assignments context['quota'] = { 'maxRate': max_rate[0], 'maxRateInterval': max_rate[1], 'accountLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:account-rate-limit', default=ACCOUNT_RATE_LIMIT_DEFAULT, ) ), 'projectLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:project-rate-limit', default=PROJECT_RATE_LIMIT_DEFAULT, ) ), } context.update({ 'isDefault': obj.is_default, 'defaultRole': obj.default_role, 'availableRoles': [{ 'id': r.id, 'name': r.name, } for r in roles.get_all()], 'openMembership': bool(obj.flags.allow_joinleave), 'require2FA': bool(obj.flags.require_2fa), 'allowSharedIssues': not obj.flags.disable_shared_issues, 'enhancedPrivacy': bool(obj.flags.enhanced_privacy), 'dataScrubber': bool(obj.get_option('sentry:require_scrub_data', REQUIRE_SCRUB_DATA_DEFAULT)), 'dataScrubberDefaults': bool(obj.get_option('sentry:require_scrub_defaults', REQUIRE_SCRUB_DEFAULTS_DEFAULT)), 'sensitiveFields': obj.get_option('sentry:sensitive_fields', SENSITIVE_FIELDS_DEFAULT) or [], 'safeFields': obj.get_option('sentry:safe_fields', SAFE_FIELDS_DEFAULT) or [], 'storeCrashReports': bool(obj.get_option('sentry:store_crash_reports', STORE_CRASH_REPORTS_DEFAULT)), 'scrubIPAddresses': bool(obj.get_option('sentry:require_scrub_ip_address', REQUIRE_SCRUB_IP_ADDRESS_DEFAULT)), 'scrapeJavaScript': bool(obj.get_option('sentry:scrape_javascript', SCRAPE_JAVASCRIPT_DEFAULT)), 'trustedRelays': obj.get_option('sentry:trusted-relays', TRUSTED_RELAYS_DEFAULT) or [], }) context['teams'] = serialize(team_list, user, TeamSerializer()) context['projects'] = serialize(project_list, user, ProjectSummarySerializer()) if env.request: context['access'] = access.from_request(env.request, obj).scopes else: context['access'] = access.from_user(user, obj).scopes context['features'] = feature_list context['pendingAccessRequests'] = OrganizationAccessRequest.objects.filter( team__organization=obj, ).count() context['onboardingTasks'] = serialize(onboarding_tasks, user, OnboardingTasksSerializer()) return context
def get(self, request, organization): """ List an Organization's Projects ``````````````````````````````` Return a list of projects bound to a organization. :pparam string organization_slug: the slug of the organization for which the projects should be listed. :auth: required """ stats_period = request.GET.get('statsPeriod') if stats_period not in (None, '', '24h', '14d', '30d'): return Response( { 'error': { 'params': { 'stats_period': { 'message': ERR_INVALID_STATS_PERIOD }, }, } }, status=400) elif not stats_period: # disable stats stats_period = None if request.auth and not request.user.is_authenticated(): # TODO: remove this, no longer supported probably if hasattr(request.auth, 'project'): team_list = list(request.auth.project.teams.all()) queryset = Project.objects.filter( id=request.auth.project.id, ).prefetch_related('teams') elif request.auth.organization is not None: org = request.auth.organization team_list = list(Team.objects.filter(organization=org, )) queryset = Project.objects.filter( teams__in=team_list, ).prefetch_related('teams') else: return Response( { 'detail': 'Current access does not point to ' 'organization.' }, status=400) else: team_list = list(request.access.teams) queryset = Project.objects.filter( teams__in=team_list, ).prefetch_related('teams') query = request.GET.get('query') if query: tokens = tokenize_query(query) for key, value in six.iteritems(tokens): if key == 'query': value = ' '.join(value) queryset = queryset.filter( Q(name__icontains=value) | Q(slug__icontains=value)) else: queryset = queryset.none() queryset = queryset.distinct() return self.paginate( request=request, queryset=queryset, order_by='slug', on_results=lambda x: serialize( x, request.user, ProjectSummarySerializer( environment_id=self._get_environment_id_from_request( request, organization.id, ), stats_period=stats_period, )), paginator_cls=OffsetPaginator, )
def get(self, request, organization): """ List an Organization's Projects ``````````````````````````````` Return a list of projects bound to a organization. :pparam string organization_slug: the slug of the organization for which the projects should be listed. :auth: required """ stats_period = request.GET.get("statsPeriod") if stats_period not in (None, "", "24h", "14d", "30d"): return Response( { "error": { "params": { "stats_period": { "message": ERR_INVALID_STATS_PERIOD } } } }, status=400, ) elif not stats_period: # disable stats stats_period = None if request.auth and not request.user.is_authenticated(): # TODO: remove this, no longer supported probably if hasattr(request.auth, "project"): team_list = list(request.auth.project.teams.all()) queryset = Project.objects.filter( id=request.auth.project.id).prefetch_related("teams") elif request.auth.organization is not None: org = request.auth.organization team_list = list(Team.objects.filter(organization=org)) queryset = Project.objects.filter( teams__in=team_list).prefetch_related("teams") else: return Response( { "detail": "Current access does not point to " "organization." }, status=400) else: queryset = Project.objects.filter( organization=organization).prefetch_related("teams") order_by = ["slug"] if request.user.is_authenticated(): queryset = queryset.extra( select={ "is_bookmarked": """exists ( select * from sentry_projectbookmark spb where spb.project_id = sentry_project.id and spb.user_id = %s )""" }, select_params=(request.user.id, ), ) order_by.insert(0, "-is_bookmarked") query = request.GET.get("query") if query: tokens = tokenize_query(query) for key, value in six.iteritems(tokens): if key == "query": value = " ".join(value) queryset = queryset.filter( Q(name__icontains=value) | Q(slug__icontains=value)) elif key == "id": queryset = queryset.filter(id__in=value) elif key == "slug": queryset = queryset.filter(slug__in=value) elif key == "team": team_list = list(Team.objects.filter(slug__in=value)) queryset = queryset.filter(teams__in=team_list) elif key == "!team": team_list = list(Team.objects.filter(slug__in=value)) queryset = queryset.exclude(teams__in=team_list) else: queryset = queryset.none() queryset = queryset.filter(status=ProjectStatus.VISIBLE).distinct() return self.paginate( request=request, queryset=queryset, order_by=order_by, on_results=lambda x: serialize( x, request.user, ProjectSummarySerializer( environment_id=self._get_environment_id_from_request( request, organization.id), stats_period=stats_period, ), ), paginator_cls=OffsetPaginator, )
def serialize(self, obj, attrs, user): from sentry import features from sentry.app import env from sentry.api.serializers.models.project import ProjectSummarySerializer from sentry.api.serializers.models.team import TeamSerializer team_list = list(Team.objects.filter( organization=obj, status=TeamStatus.VISIBLE, )) for team in team_list: team._organization_cache = obj project_list = list(Project.objects.filter( organization=obj, status=ProjectStatus.VISIBLE, )) for project in project_list: project._organization_cache = obj onboarding_tasks = list( OrganizationOnboardingTask.objects.filter( organization=obj, ).select_related('user') ) feature_list = [] if features.has('organizations:sso', obj, actor=user): feature_list.append('sso') if features.has('organizations:onboarding', obj, actor=user) and \ not OrganizationOption.objects.filter(organization=obj).exists(): feature_list.append('onboarding') if features.has('organizations:api-keys', obj, actor=user) or \ ApiKey.objects.filter(organization=obj).exists(): feature_list.append('api-keys') if features.has('organizations:group-unmerge', obj, actor=user): feature_list.append('group-unmerge') if features.has('organizations:github-apps', obj, actor=user): feature_list.append('github-apps') if features.has('organizations:integrations-v3', obj, actor=user): feature_list.append('integrations-v3') if features.has('organizations:new-settings', obj, actor=user): feature_list.append('new-settings') if features.has('organizations:require-2fa', obj, actor=user): feature_list.append('require-2fa') if features.has('organizations:environments', obj, actor=user): feature_list.append('environments') if features.has('organizations:repos', obj, actor=user): feature_list.append('repos') if features.has('organizations:internal-catchall', obj, actor=user): feature_list.append('internal-catchall') if features.has('organizations:suggested-commits', obj, actor=user): feature_list.append('suggested-commits') if features.has('organizations:new-teams', obj, actor=user): feature_list.append('new-teams') if features.has('organizations:unreleased-changes', obj, actor=user): feature_list.append('unreleased-changes') if features.has('organizations:relay', obj, actor=user): feature_list.append('relay') if features.has('organizations:health', obj, actor=user): feature_list.append('health') if getattr(obj.flags, 'allow_joinleave'): feature_list.append('open-membership') if not getattr(obj.flags, 'disable_shared_issues'): feature_list.append('shared-issues') if getattr(obj.flags, 'require_2fa'): feature_list.append('require-2fa') context = super(DetailedOrganizationSerializer, self).serialize(obj, attrs, user) max_rate = quotas.get_maximum_quota(obj) context['quota'] = { 'maxRate': max_rate[0], 'maxRateInterval': max_rate[1], 'accountLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:account-rate-limit', default=0, ) ), 'projectLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:project-rate-limit', default=100, ) ), } context.update({ 'isDefault': obj.is_default, 'defaultRole': obj.default_role, 'availableRoles': [{ 'id': r.id, 'name': r.name, } for r in roles.get_all()], 'openMembership': bool(obj.flags.allow_joinleave), 'require2FA': bool(obj.flags.require_2fa), 'allowSharedIssues': not obj.flags.disable_shared_issues, 'enhancedPrivacy': bool(obj.flags.enhanced_privacy), 'dataScrubber': bool(obj.get_option('sentry:require_scrub_data', False)), 'dataScrubberDefaults': bool(obj.get_option('sentry:require_scrub_defaults', False)), 'sensitiveFields': obj.get_option('sentry:sensitive_fields', None) or [], 'safeFields': obj.get_option('sentry:safe_fields', None) or [], 'scrubIPAddresses': bool(obj.get_option('sentry:require_scrub_ip_address', False)), }) context['teams'] = serialize(team_list, user, TeamSerializer()) context['projects'] = serialize(project_list, user, ProjectSummarySerializer()) if env.request: context['access'] = access.from_request(env.request, obj).scopes else: context['access'] = access.from_user(user, obj).scopes context['features'] = feature_list context['pendingAccessRequests'] = OrganizationAccessRequest.objects.filter( team__organization=obj, ).count() context['onboardingTasks'] = serialize(onboarding_tasks, user, OnboardingTasksSerializer()) return context