def get(self, request, organization): """ List an Organization's Teams ```````````````````````````` Return a list of teams bound to a organization. :pparam string organization_slug: the slug of the organization for which the teams should be listed. :auth: required """ # TODO(dcramer): this should be system-wide default for organization # based endpoints if request.auth and hasattr(request.auth, 'project'): return Response(status=403) team_list = list( Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE, ).order_by('name', 'slug')) return Response( serialize(team_list, request.user, TeamWithProjectsSerializer()))
def test_simple(self): 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') project2 = self.create_project(teams=[team], organization=organization, name='bar') result = serialize(team, user, TeamWithProjectsSerializer()) result.pop('dateCreated') # don't compare dateCreated because of mysql serialized_projects = serialize([project2, project], user) for p in serialized_projects: p.pop('dateCreated') for p in result['projects']: p.pop('dateCreated') assert result == { 'slug': team.slug, 'name': team.name, 'hasAccess': True, 'isPending': False, 'isMember': False, 'id': six.text_type(team.id), 'projects': serialized_projects, 'avatar': { 'avatarType': 'letter_avatar', 'avatarUuid': None, }, 'memberCount': 0 }
def post(self, request, organization, member_id, team_slug): """ Join a team Join or request access to a team. If the user is already a member of the team, this will simply return a 204. If the user needs permission to join the team, an access request will be generated and the returned status code will be 202. """ try: om = self._get_member(request, organization, member_id) except OrganizationMember.DoesNotExist: raise ResourceDoesNotExist if not self._can_access(request, om): return Response({'detail': ERR_INSUFFICIENT_ROLE}, status=400) try: team = Team.objects.get( organization=organization, slug=team_slug, ) except Team.DoesNotExist: raise ResourceDoesNotExist try: omt = OrganizationMemberTeam.objects.get( team=team, organizationmember=om, ) except OrganizationMemberTeam.DoesNotExist: if not (request.access.has_scope('org:write') or organization.flags.allow_joinleave): omt, created = OrganizationAccessRequest.objects.get_or_create( team=team, member=om, ) if created: omt.send_request_email() return Response(status=202) omt = OrganizationMemberTeam.objects.create( team=team, organizationmember=om, ) else: return Response(status=204) self.create_audit_entry( request=request, organization=organization, target_object=omt.id, target_user=om.user, event=AuditLogEntryEvent.MEMBER_JOIN_TEAM, data=omt.get_audit_log_data(), ) return Response(serialize(team, request.user, TeamWithProjectsSerializer()), status=201)
def serialize(self, obj, attrs, user): from sentry import features from sentry.app import env from sentry.api.serializers.models.team import TeamWithProjectsSerializer team_list = list( Team.objects.filter( organization=obj, status=TeamStatus.VISIBLE, )) for team in team_list: team._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: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 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, TeamWithProjectsSerializer()) 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 from sentry.app import env from sentry.api.serializers.models.team import TeamWithProjectsSerializer team_list = list( Team.objects.filter( organization=obj, status=TeamStatus.VISIBLE, )) for team in team_list: team._organization_cache = obj onboarding_tasks = list( OrganizationOnboardingTask.objects.filter( organization=obj, ).select_related('user')) feature_list = [] if features.has('organizations:repos', obj, actor=user): feature_list.append('repos') if features.has('organizations:sso', obj, actor=user): feature_list.append('sso') if features.has('organizations:callsigns', obj, actor=user): feature_list.append('callsigns') 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 getattr(obj.flags, 'allow_joinleave'): feature_list.append('open-membership') if not getattr(obj.flags, 'disable_shared_issues'): feature_list.append('shared-issues') context = super(DetailedOrganizationSerializer, self).serialize(obj, attrs, user) context['quota'] = { 'maxRate': quotas.get_organization_quota(obj), 'projectLimit': int( OrganizationOption.objects.get_value( organization=obj, key='sentry:project-rate-limit', default=100, )), } context['teams'] = serialize(team_list, user, TeamWithProjectsSerializer()) 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 post(self, request, organization, member_id, team_slug): """ Join a team Join or request access to a team. If the user is already a member of the team, this will simply return a 204. If the user needs permission to join the team, an access request will be generated and the returned status code will be 202. """ try: om = self._get_member(request, organization, member_id) except OrganizationMember.DoesNotExist: raise ResourceDoesNotExist if not self._can_access(request, om): return Response({'detail': ERR_INSUFFICIENT_ROLE}, status=400) try: team = Team.objects.get( organization=organization, slug=team_slug, ) except Team.DoesNotExist: raise ResourceDoesNotExist if not om.has_global_access: try: omt = OrganizationMemberTeam.objects.get( team=team, organizationmember=om, ) except OrganizationMemberTeam.DoesNotExist: # TODO(dcramer): this should create a pending request and # return a 202 if not organization.flags.allow_joinleave: omt, created = OrganizationAccessRequest.objects.get_or_create( team=team, member=om, ) if created: omt.send_request_email() return Response(status=202) omt = OrganizationMemberTeam( team=team, organizationmember=om, is_active=False, ) if omt.is_active: return Response(status=204) else: try: omt = OrganizationMemberTeam.objects.get( team=team, organizationmember=om, ) except OrganizationMemberTeam.DoesNotExist: # if the relationship doesnt exist, they're already a member return Response(status=204) omt.is_active = True omt.save() self.create_audit_entry( request=request, organization=organization, target_object=omt.id, target_user=om.user, event=AuditLogEntryEvent.MEMBER_JOIN_TEAM, data=omt.get_audit_log_data(), ) return Response(serialize(team, request.user, TeamWithProjectsSerializer()), status=201)
def delete(self, request, organization, member_id, team_slug): """ Leave a team Leave a team. """ try: om = self._get_member(request, organization, member_id) except OrganizationMember.DoesNotExist: raise ResourceDoesNotExist if not self._can_access(request, om): return Response({'detail': ERR_INSUFFICIENT_ROLE}, status=400) try: team = Team.objects.get( organization=organization, slug=team_slug, ) except Team.DoesNotExist: raise ResourceDoesNotExist if not om.has_global_access: try: omt = OrganizationMemberTeam.objects.get( team=team, organizationmember=om, ) except OrganizationMemberTeam.DoesNotExist: # if the relationship doesnt exist, they're already a member return Response(serialize(team, request.user, TeamWithProjectsSerializer()), status=200) else: try: omt = OrganizationMemberTeam.objects.get( team=team, organizationmember=om, is_active=True, ) except OrganizationMemberTeam.DoesNotExist: omt = OrganizationMemberTeam( team=team, organizationmember=om, is_active=True, ) if omt.is_active: omt.is_active = False omt.save() self.create_audit_entry( request=request, organization=organization, target_object=omt.id, target_user=om.user, event=AuditLogEntryEvent.MEMBER_LEAVE_TEAM, data=omt.get_audit_log_data(), ) return Response(serialize(team, request.user, TeamWithProjectsSerializer()), status=200)