def test_unignoring_group(self, send_robust): group = self.create_group(status=GroupStatus.IGNORED) request = self.make_request(user=self.user, method="GET") request.user = self.user request.data = {"status": "unresolved"} request.GET = QueryDict(query_string="id={}".format(group.id)) search_fn = Mock() update_groups(request, [self.project], self.organization.id, search_fn) group.refresh_from_db() assert group.status == GroupStatus.UNRESOLVED assert send_robust.called
def put(self, request, project): """ Bulk Mutate a List of Issues ```````````````````````````` Bulk mutate various attributes on issues. The list of issues to modify is given through the `id` query parameter. It is repeated for each issue that should be modified. - For non-status updates, the `id` query parameter is required. - For status updates, the `id` query parameter may be omitted for a batch "update all" query. - An optional `status` query parameter may be used to restrict mutations to only events with the given status. The following attributes can be modified and are supplied as JSON object in the body: If any ids are out of scope this operation will succeed without any data mutation. :qparam int id: a list of IDs of the issues to be mutated. This parameter shall be repeated for each issue. It is optional only if a status is mutated in which case an implicit `update all` is assumed. :qparam string status: optionally limits the query to issues of the specified status. Valid values are ``"resolved"``, ``"unresolved"`` and ``"ignored"``. :pparam string organization_slug: the slug of the organization the issues belong to. :pparam string project_slug: the slug of the project the issues belong to. :param string status: the new status for the issues. Valid values are ``"resolved"``, ``"resolvedInNextRelease"``, ``"unresolved"``, and ``"ignored"``. :param map statusDetails: additional details about the resolution. Valid values are ``"inRelease"``, ``"inNextRelease"``, ``"inCommit"``, ``"ignoreDuration"``, ``"ignoreCount"``, ``"ignoreWindow"``, ``"ignoreUserCount"``, and ``"ignoreUserWindow"``. :param int ignoreDuration: the number of minutes to ignore this issue. :param boolean isPublic: sets the issue to public or private. :param boolean merge: allows to merge or unmerge different issues. :param string assignedTo: the actor id (or username) of the user or team that should be assigned to this issue. :param boolean hasSeen: in case this API call is invoked with a user context this allows changing of the flag that indicates if the user has seen the event. :param boolean isBookmarked: in case this API call is invoked with a user context this allows changing of the bookmark flag. :auth: required """ search_fn = functools.partial(self._search, request, project) return update_groups(request, [project], project.organization_id, search_fn)
def test_ignoring_group(self, send_robust): group = self.create_group() add_group_to_inbox(group, GroupInboxReason.NEW) request = self.make_request(user=self.user, method="GET") request.user = self.user request.data = {"status": "ignored"} request.GET = QueryDict(query_string="id={}".format(group.id)) search_fn = Mock() update_groups(request, [self.project], self.organization.id, search_fn) group.refresh_from_db() assert group.status == GroupStatus.IGNORED assert send_robust.called assert not GroupInbox.objects.filter(group=group).exists()
def test_unresolving_resolved_group(self, send_robust, send_unresolved): resolved_group = self.create_group(status=GroupStatus.RESOLVED) assert resolved_group.status == GroupStatus.RESOLVED request = self.make_request(user=self.user, method="GET") request.user = self.user request.data = {"status": "unresolved"} request.GET = QueryDict(query_string=f"id={resolved_group.id}") search_fn = Mock() update_groups(request, [self.project], self.organization.id, search_fn) resolved_group.refresh_from_db() assert resolved_group.status == GroupStatus.UNRESOLVED assert not send_robust.called assert send_unresolved.called
def test_mark_reviewed_group(self, send_robust): group = self.create_group() add_group_to_inbox(group, GroupInboxReason.NEW) request = self.make_request(user=self.user, method="GET") request.user = self.user request.data = {"inbox": False} request.GET = QueryDict(query_string=f"id={group.id}") search_fn = Mock() update_groups(request, request.GET.getlist("id"), [self.project], self.organization.id, search_fn) group.refresh_from_db() assert not GroupInbox.objects.filter(group=group).exists() assert send_robust.called
def test_resolving_unresolved_group(self, send_robust): unresolved_group = self.create_group(status=GroupStatus.UNRESOLVED) add_group_to_inbox(unresolved_group, GroupInboxReason.NEW) assert unresolved_group.status == GroupStatus.UNRESOLVED request = self.make_request(user=self.user, method="GET") request.user = self.user request.data = {"status": "resolved"} request.GET = QueryDict(query_string=f"id={unresolved_group.id}") search_fn = Mock() update_groups(request, [self.project], self.organization.id, search_fn) unresolved_group.refresh_from_db() assert unresolved_group.status == GroupStatus.RESOLVED assert not GroupInbox.objects.filter(group=unresolved_group).exists() assert send_robust.called
def test_resolving_unresolved_group(self, send_robust): unresolved_group = self.create_group(status=GroupStatus.UNRESOLVED) add_group_to_inbox(unresolved_group, GroupInboxReason.NEW) assert unresolved_group.status == GroupStatus.UNRESOLVED request = self.make_request(user=self.user, method="GET") request.user = self.user request.data = {"status": "resolved"} request.GET = QueryDict(query_string="id={}".format(unresolved_group.id)) search_fn = Mock() update_groups(request, [self.project], self.organization.id, search_fn) unresolved_group.refresh_from_db() assert unresolved_group.status == GroupStatus.RESOLVED # TODO: Chris F.: This is temporarily removed while we perform some migrations. # assert not GroupInbox.objects.filter(group=unresolved_group).exists() assert send_robust.called
def update_group( group: Group, identity: Identity, data: Mapping[str, str], request: Request, ) -> Response: if not group.organization.has_access(identity.user): raise ApiClient.ApiError( status_code=403, body="The user does not have access to the organization.") return update_groups( request=request, group_ids=[group.id], projects=[group.project], organization_id=group.organization.id, search_fn=None, user=identity.user, data=data, )
def put(self, request, organization): """ Bulk Mutate a List of Issues ```````````````````````````` Bulk mutate various attributes on issues. The list of issues to modify is given through the `id` query parameter. It is repeated for each issue that should be modified. - For non-status updates, the `id` query parameter is required. - For status updates, the `id` query parameter may be omitted for a batch "update all" query. - An optional `status` query parameter may be used to restrict mutations to only events with the given status. The following attributes can be modified and are supplied as JSON object in the body: If any ids are out of scope this operation will succeed without any data mutation. :qparam int id: a list of IDs of the issues to be mutated. This parameter shall be repeated for each issue. It is optional only if a status is mutated in which case an implicit `update all` is assumed. :qparam string status: optionally limits the query to issues of the specified status. Valid values are ``"resolved"``, ``"unresolved"`` and ``"ignored"``. :pparam string organization_slug: the slug of the organization the issues belong to. :param string status: the new status for the issues. Valid values are ``"resolved"``, ``"resolvedInNextRelease"``, ``"unresolved"``, and ``"ignored"``. Status updates that include release data are only allowed for groups within a single project. :param map statusDetails: additional details about the resolution. Valid values are ``"inRelease"``, ``"inNextRelease"``, ``"inCommit"``, ``"ignoreDuration"``, ``"ignoreCount"``, ``"ignoreWindow"``, ``"ignoreUserCount"``, and ``"ignoreUserWindow"``. Status detail updates that include release data are only allowed for groups within a single project. :param int ignoreDuration: the number of minutes to ignore this issue. :param boolean isPublic: sets the issue to public or private. :param boolean merge: allows to merge or unmerge different issues. :param string assignedTo: the user or team that should be assigned to these issues. Can be of the form ``"<user_id>"``, ``"user:<user_id>"``, ``"<username>"``, ``"<user_primary_email>"``, or ``"team:<team_id>"``. Bulk assigning issues is limited to groups within a single project. :param boolean hasSeen: in case this API call is invoked with a user context this allows changing of the flag that indicates if the user has seen the event. :param boolean isBookmarked: in case this API call is invoked with a user context this allows changing of the bookmark flag. :auth: required """ projects = self.get_projects(request, organization) if len(projects) > 1 and not features.has( "organizations:global-views", organization, actor=request.user ): return Response( {"detail": "You do not have the multi project stream feature enabled"}, status=400 ) search_fn = functools.partial( self._search, request, organization, projects, self.get_environments(request, organization), ) return update_groups(request, projects, organization.id, search_fn)
def put(self, request: Request, group) -> Response: """ Update an Issue ``````````````` Updates an individual issue's attributes. Only the attributes submitted are modified. :pparam string issue_id: the ID of the group to retrieve. :param string status: the new status for the issue. Valid values are ``"resolved"``, ``resolvedInNextRelease``, ``"unresolved"``, and ``"ignored"``. :param string assignedTo: the user or team that should be assigned to this issue. Can be of the form ``"<user_id>"``, ``"user:<user_id>"``, ``"<username>"``, ``"<user_primary_email>"``, or ``"team:<team_id>"``. :param string assignedBy: ``"suggested_assignee"`` | ``"assignee_selector"`` :param boolean hasSeen: in case this API call is invoked with a user context this allows changing of the flag that indicates if the user has seen the event. :param boolean isBookmarked: in case this API call is invoked with a user context this allows changing of the bookmark flag. :param boolean isSubscribed: :param boolean isPublic: sets the issue to public or private. :auth: required """ try: discard = request.data.get("discard") project = group.project search_fn = functools.partial(prep_search, self, request, project) response = update_groups(request, [group.id], [project], project.organization_id, search_fn) # if action was discard, there isn't a group to serialize anymore # if response isn't 200, return the response update_groups gave us (i.e. helpful error) # instead of serializing the updated group if discard or response.status_code != 200: return response # we need to fetch the object against as the bulk mutation endpoint # only returns a delta, and object mutation returns a complete updated # entity. # TODO(dcramer): we should update the API and have this be an explicit # flag (or remove it entirely) so that delta's are the primary response # for mutation. group = Group.objects.get(id=group.id) serialized = serialize( group, request.user, GroupSerializer(environment_func=self._get_environment_func( request, group.project.organization_id)), ) return Response(serialized, status=response.status_code) except client.ApiError as e: logging.error( "group_details:put client.ApiError", exc_info=True, ) return Response(e.body, status=e.status_code) except Exception: raise
def put(self, request, organization): """ Bulk Mutate a List of Issues ```````````````````````````` Bulk mutate various attributes on issues. The list of issues to modify is given through the `id` query parameter. It is repeated for each issue that should be modified. - For non-status updates, the `id` query parameter is required. - For status updates, the `id` query parameter may be omitted for a batch "update all" query. - An optional `status` query parameter may be used to restrict mutations to only events with the given status. The following attributes can be modified and are supplied as JSON object in the body: If any ids are out of scope this operation will succeed without any data mutation. :qparam int id: a list of IDs of the issues to be mutated. This parameter shall be repeated for each issue. It is optional only if a status is mutated in which case an implicit `update all` is assumed. :qparam string status: optionally limits the query to issues of the specified status. Valid values are ``"resolved"``, ``"unresolved"`` and ``"ignored"``. :pparam string organization_slug: the slug of the organization the issues belong to. :param string status: the new status for the issues. Valid values are ``"resolved"``, ``"resolvedInNextRelease"``, ``"unresolved"``, and ``"ignored"``. Status updates that include release data are only allowed for groups within a single project. :param map statusDetails: additional details about the resolution. Valid values are ``"inRelease"``, ``"inNextRelease"``, ``"inCommit"``, ``"ignoreDuration"``, ``"ignoreCount"``, ``"ignoreWindow"``, ``"ignoreUserCount"``, and ``"ignoreUserWindow"``. Status detail updates that include release data are only allowed for groups within a single project. :param int ignoreDuration: the number of minutes to ignore this issue. :param boolean isPublic: sets the issue to public or private. :param boolean merge: allows to merge or unmerge different issues. :param string assignedTo: the actor id (or username) of the user or team that should be assigned to this issue. Bulk assigning issues is limited to groups within a single project. :param boolean hasSeen: in case this API call is invoked with a user context this allows changing of the flag that indicates if the user has seen the event. :param boolean isBookmarked: in case this API call is invoked with a user context this allows changing of the bookmark flag. :auth: required """ projects = self.get_projects(request, organization) if len(projects) > 1 and not features.has( 'organizations:global-views', organization, actor=request.user): return Response({ 'detail': 'You do not have the multi project stream feature enabled' }, status=400) search_fn = functools.partial( self._search, request, organization, projects, self.get_environments(request, organization), ) return update_groups( request, projects, organization.id, search_fn, )