def _can_admin_team(self, request: Request, organization, team_slug): global_roles = [r.id for r in roles.with_scope("org:write") if r.is_global] team_roles = [r.id for r in roles.with_scope("team:write")] # must be a team admin or have global write access return OrganizationMember.objects.filter( Q(role__in=global_roles) | Q(organizationmemberteam__team__slug=team_slug, role__in=team_roles), organization=organization, user__id=request.user.id, user__is_active=True, ).exists()
def send_request_email(self): from sentry.models import OrganizationMember from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { "email": email, "name": user.get_display_name(), "organization": organization, "team": self.team, "url": absolute_uri( reverse( "sentry-organization-members-requests", kwargs={"organization_slug": organization.slug}, )), } if self.requester: context.update({"requester": self.requester.get_display_name()}) msg = MessageBuilder( subject="Sentry Access Request", template="sentry/emails/request-team-access.txt", html_template="sentry/emails/request-team-access.html", type="team.access.request", context=context, ) global_roles = [ r.id for r in roles.with_scope("org:write") if r.is_global ] team_roles = [r.id for r in roles.with_scope("team:write")] # find members which are either team scoped or have access to all teams member_list = OrganizationMember.objects.filter( Q(role__in=global_roles) | Q(teams=self.team, role__in=team_roles), organization=self.team.organization, user__isnull=False, ).select_related("user") msg.send_async([m.user.email for m in member_list])
def get(self, request, wizard_hash): """ This opens a page where with an active session fill stuff into the cache Redirects to organization whenever cache has been deleted """ context = {'hash': wizard_hash} key = '%s%s' % (SETUP_WIZARD_CACHE_KEY, wizard_hash) wizard_data = default_cache.get(key) if wizard_data is None: return self.redirect_to_org(request) orgs = Organization.objects.filter( member_set__role__in=[x.id for x in roles.with_scope('org:read')], member_set__user=request.user, status=OrganizationStatus.VISIBLE, ).order_by('-date_added')[:50] filled_projects = [] for org in orgs: projects = list( Project.objects.filter( organization=org, status=ProjectStatus.VISIBLE, ).order_by('-date_added')[:50]) for project in projects: enriched_project = serialize(project) enriched_project['organization'] = serialize(org) keys = list( ProjectKey.objects.filter( project=project, roles=F('roles').bitor(ProjectKey.roles.store), status=ProjectKeyStatus.ACTIVE, )) enriched_project['keys'] = serialize(keys) filled_projects.append(enriched_project) # Fetching or creating a token token = None tokens = [ x for x in ApiToken.objects.filter(user=request.user).all() if 'project:releases' in x.get_scopes() ] if not tokens: token = ApiToken.objects.create( user=request.user, scope_list=['project:releases'], refresh_token=None, expires_at=None, ) else: token = tokens[0] result = {'apiKeys': serialize(token), 'projects': filled_projects} key = '%s%s' % (SETUP_WIZARD_CACHE_KEY, wizard_hash) default_cache.set(key, result, SETUP_WIZARD_CACHE_TIMEOUT) return render_to_response('sentry/setup-wizard.html', context, request)
def send_request_email(self): from sentry.models import OrganizationMember from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { 'email': email, 'name': user.get_display_name(), 'organization': organization, 'team': self.team, 'url': absolute_uri( reverse('sentry-organization-members', kwargs={ 'organization_slug': organization.slug, }) + '?ref=access-requests'), } msg = MessageBuilder( subject='Sentry Access Request', template='sentry/emails/request-team-access.txt', html_template='sentry/emails/request-team-access.html', type='team.access.request', context=context, ) global_roles = [ r.id for r in roles.with_scope('org:write') if r.is_global ] team_roles = [r.id for r in roles.with_scope('team:write')] # find members which are either team scoped or have access to all teams member_list = OrganizationMember.objects.filter( Q(role__in=global_roles) | Q(teams=self.team, role__in=team_roles), organization=self.team.organization, user__isnull=False, ).select_related('user') msg.send_async([m.user.email for m in member_list])
def send_request_email(self): from sentry.models import OrganizationMember from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { 'email': email, 'name': user.get_display_name(), 'organization': organization, 'team': self.team, 'url': absolute_uri(reverse('sentry-organization-members', kwargs={ 'organization_slug': organization.slug, }) + '?ref=access-requests'), } msg = MessageBuilder( subject='Sentry Access Request', template='sentry/emails/request-team-access.txt', html_template='sentry/emails/request-team-access.html', type='team.access.request', context=context, ) global_roles = [ r.id for r in roles.with_scope('org:write') if r.is_global ] team_roles = [ r.id for r in roles.with_scope('team:write') ] # find members which are either team scoped or have access to all teams member_list = OrganizationMember.objects.filter( Q(role__in=global_roles) | Q(teams=self.team, role__in=team_roles), organization=self.team.organization, user__isnull=False, ).select_related('user') msg.send_async([m.user.email for m in member_list])
def send_request_email(self): from sentry.models import OrganizationMember from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { "email": email, "name": user.get_display_name(), "organization": organization, "team": self.team, "url": absolute_uri( reverse("sentry-organization-members", kwargs={"organization_slug": organization.slug}) + "?ref=access-requests" ), } msg = MessageBuilder( subject="Sentry Access Request", template="sentry/emails/request-team-access.txt", html_template="sentry/emails/request-team-access.html", context=context, ) global_roles = [r.id for r in roles.with_scope("org:write") if r.is_global] team_roles = [r.id for r in roles.with_scope("team:write")] # find members which are either team scoped or have access to all teams member_list = OrganizationMember.objects.filter( Q(role__in=global_roles) | Q(teams=self.team, role__in=team_roles), organization=self.team.organization, user__isnull=False, ).select_related("user") msg.send_async([m.user.email for m in member_list])
def delete(self, request, user): """ Delete User Account Also removes organizations if they are an owner :pparam string user_id: user id :param boolean hard_delete: Completely remove the user from the database (requires super user) :param list organizations: List of organization ids to remove :auth required: """ serializer = DeleteUserSerializer(data=request.data) if not serializer.is_valid(): return Response(status=status.HTTP_400_BAD_REQUEST) # from `frontend/remove_account.py` org_list = Organization.objects.filter( member_set__role__in=[x.id for x in roles.with_scope("org:admin")], member_set__user=user, status=OrganizationStatus.VISIBLE, ) org_results = [] for org in org_list: org_results.append({ "organization": org, "single_owner": org.has_single_owner() }) avail_org_slugs = {o["organization"].slug for o in org_results} orgs_to_remove = set(serializer.validated_data.get( "organizations")).intersection(avail_org_slugs) for result in org_results: if result["single_owner"]: orgs_to_remove.add(result["organization"].slug) for org_slug in orgs_to_remove: client.delete(path=f"/organizations/{org_slug}/", request=request, is_sudo=True) remaining_org_ids = [ o.id for o in org_list if o.slug in avail_org_slugs.difference(orgs_to_remove) ] if remaining_org_ids: OrganizationMember.objects.filter( organization__in=remaining_org_ids, user=user).delete() logging_data = { "actor_id": request.user.id, "ip_address": request.META["REMOTE_ADDR"], "user_id": user.id, } hard_delete = serializer.validated_data.get("hardDelete", False) # Only active superusers can hard delete accounts if hard_delete and not is_active_superuser(request): return Response( {"detail": "Only superusers may hard delete a user account"}, status=status.HTTP_403_FORBIDDEN, ) is_current_user = request.user.id == user.id if hard_delete: user.delete() delete_logger.info("user.removed", extra=logging_data) else: User.objects.filter(id=user.id).update(is_active=False) delete_logger.info("user.deactivate", extra=logging_data) # if the user deleted their own account log them out if is_current_user: logout(request) return Response(status=status.HTTP_204_NO_CONTENT)
def delete(self, request, user): """ Delete User Account Also removes organizations if they are an owner :pparam string user_id: user id :param list organizations: List of organization ids to remove :auth required: """ serializer = OrganizationsSerializer(data=request.DATA) if not serializer.is_valid(): return Response(status=status.HTTP_400_BAD_REQUEST) # from `frontend/remove_account.py` org_list = Organization.objects.filter( member_set__role__in=[x.id for x in roles.with_scope('org:admin')], member_set__user=user, status=OrganizationStatus.VISIBLE, ) org_results = [] for org in org_list: org_results.append({ 'organization': org, 'single_owner': org.has_single_owner(), }) avail_org_slugs = set([o['organization'].slug for o in org_results]) orgs_to_remove = set(serializer.object.get( 'organizations')).intersection(avail_org_slugs) for result in org_results: if result['single_owner']: orgs_to_remove.add(result['organization'].slug) delete_logger.info('user.deactivate', extra={ 'actor_id': request.user.id, 'ip_address': request.META['REMOTE_ADDR'], }) for org_slug in orgs_to_remove: client.delete(path='/organizations/{}/'.format(org_slug), request=request, is_sudo=True) remaining_org_ids = [ o.id for o in org_list if o.slug in avail_org_slugs.difference(orgs_to_remove) ] if remaining_org_ids: OrganizationMember.objects.filter( organization__in=remaining_org_ids, user=request.user, ).delete() User.objects.filter(id=request.user.id, ).update(is_active=False, ) logout(request) return Response(status=status.HTTP_204_NO_CONTENT)
def get(self, request, wizard_hash): """ This opens a page where with an active session fill stuff into the cache Redirects to organization whenever cache has been deleted """ context = { 'hash': wizard_hash } key = '%s%s' % (SETUP_WIZARD_CACHE_KEY, wizard_hash) wizard_data = default_cache.get(key) if wizard_data is None: return self.redirect_to_org(request) orgs = Organization.objects.filter( member_set__role__in=[x.id for x in roles.with_scope('org:read')], member_set__user=request.user, status=OrganizationStatus.VISIBLE, ).order_by('-date_added')[:50] filled_projects = [] for org in orgs: projects = list(Project.objects.filter( organization=org, status=ProjectStatus.VISIBLE, ).order_by('-date_added')[:50]) for project in projects: enriched_project = serialize(project) enriched_project['organization'] = serialize(org) keys = list(ProjectKey.objects.filter( project=project, roles=ProjectKey.roles.store, status=ProjectKeyStatus.ACTIVE, )) enriched_project['keys'] = serialize(keys) filled_projects.append(enriched_project) # Fetching or creating a token token = None tokens = [ x for x in ApiToken.objects.filter(user=request.user).all() if 'project:releases' in x.get_scopes() ] if not tokens: token = ApiToken.objects.create( user=request.user, scope_list=['project:releases'], refresh_token=None, expires_at=None, ) else: token = tokens[0] result = { 'apiKeys': serialize(token), 'projects': filled_projects } key = '%s%s' % (SETUP_WIZARD_CACHE_KEY, wizard_hash) default_cache.set(key, result, SETUP_WIZARD_CACHE_TIMEOUT) return render_to_response('sentry/setup-wizard.html', context, request)
def delete(self, request, user): """ Delete User Account Also removes organizations if they are an owner :pparam string user_id: user id :param list organizations: List of organization ids to remove :auth required: """ serializer = OrganizationsSerializer(data=request.DATA) if not serializer.is_valid(): return Response(status=status.HTTP_400_BAD_REQUEST) # from `frontend/remove_account.py` org_list = Organization.objects.filter( member_set__role__in=[x.id for x in roles.with_scope('org:admin')], member_set__user=user, status=OrganizationStatus.VISIBLE, ) org_results = [] for org in org_list: org_results.append({ 'organization': org, 'single_owner': org.has_single_owner(), }) avail_org_slugs = set([o['organization'].slug for o in org_results]) orgs_to_remove = set(serializer.object.get('organizations')).intersection(avail_org_slugs) for result in org_results: if result['single_owner']: orgs_to_remove.add(result['organization'].slug) delete_logger.info( 'user.deactivate', extra={ 'actor_id': request.user.id, 'ip_address': request.META['REMOTE_ADDR'], } ) for org_slug in orgs_to_remove: client.delete( path='/organizations/{}/'.format(org_slug), request=request, is_sudo=True) remaining_org_ids = [ o.id for o in org_list if o.slug in avail_org_slugs.difference(orgs_to_remove) ] if remaining_org_ids: OrganizationMember.objects.filter( organization__in=remaining_org_ids, user=request.user, ).delete() User.objects.filter( id=request.user.id, ).update( is_active=False, ) logout(request) return Response(status=status.HTTP_204_NO_CONTENT)