(self, request: Request, *args: Any, **kwargs: Any)
| 177 | ) |
| 178 | @action(detail=True, methods=["GET"], url_path="members") |
| 179 | def members(self, request: Request, *args: Any, **kwargs: Any) -> Response: |
| 180 | user: "FFAdminUser" = request.user # type: ignore[assignment] |
| 181 | project = self.get_project() |
| 182 | # Fetch by pk directly rather than via get_object()/get_queryset(): the |
| 183 | # latter applies the list endpoint's `q` (segment-name search), which |
| 184 | # would filter this segment out when `q` is used here to search members. |
| 185 | segment = get_object_or_404( |
| 186 | Segment.live_objects.filter(project=project, is_system_segment=False), |
| 187 | pk=self.kwargs["pk"], |
| 188 | ) |
| 189 | self.check_object_permissions(request, segment) |
| 190 | if not is_membership_enabled(project.organisation): |
| 191 | raise NotFound() |
| 192 | |
| 193 | query_serializer = SegmentMembersQuerySerializer(data=request.query_params) |
| 194 | query_serializer.is_valid(raise_exception=True) |
| 195 | environment = get_object_or_404( |
| 196 | Environment.objects.filter(project=project), |
| 197 | pk=query_serializer.validated_data["environment"], |
| 198 | ) |
| 199 | if not user.has_environment_permission(VIEW_IDENTITIES, environment): |
| 200 | raise PermissionDenied() |
| 201 | |
| 202 | limit = query_serializer.validated_data["limit"] |
| 203 | cursor = query_serializer.validated_data.get("cursor") |
| 204 | q = query_serializer.validated_data.get("q") |
| 205 | with flagsmith_segment_membership_read_duration_seconds.time(): |
| 206 | # Fetch one extra row to detect whether a further page exists, so the |
| 207 | # last page doesn't advertise a phantom (empty) next page. |
| 208 | members = get_segment_members_page( |
| 209 | segment, environment, cursor=cursor, limit=limit + 1, q=q |
| 210 | ) |
| 211 | |
| 212 | has_more = len(members) > limit |
| 213 | members = members[:limit] |
| 214 | next_cursor = members[-1]["identifier"] if has_more else None |
| 215 | return Response({"results": members, "next_cursor": next_cursor}) |
| 216 | |
| 217 | def destroy(self, request: Request, *args: Any, **kwargs: Any) -> Response: |
| 218 | segment = self.get_object() |
nothing calls this directly
no test coverage detected