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])
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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])
Ejemplo n.º 5
0
    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])
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)