feat: add public profiles list endpoint with search and pagination

- Add new /profiles/ endpoint for listing user profiles
- Support search by username/display name with ordering options
- Include pagination with configurable page size (max 100)
- Add comprehensive OpenAPI schema documentation
- Refactor passkey authentication state management in MFA flow
- Update URL routing and imports for new list_profiles view

This enables user discovery, leaderboards, and friend-finding features
with a publicly accessible, well-documented API endpoint.
This commit is contained in:
pacnpal
2026-01-10 13:00:02 -05:00
parent 22ff0d1c49
commit 692c0bbbbf
9 changed files with 424 additions and 45 deletions

View File

@@ -823,6 +823,119 @@ def check_user_deletion_eligibility(request, user_id):
)
# === PUBLIC PROFILE LIST ENDPOINT ===
@extend_schema(
operation_id="list_profiles",
summary="List user profiles with search and pagination",
description=(
"Returns a paginated list of public user profiles. "
"Supports search by username or display name, and filtering by various criteria. "
"This endpoint is used for user discovery, leaderboards, and friend finding."
),
parameters=[
OpenApiParameter(
name="search",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
description="Search term for username or display name",
),
OpenApiParameter(
name="ordering",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
description="Order by field: date_joined, -date_joined, username, -username",
),
OpenApiParameter(
name="page",
type=OpenApiTypes.INT,
location=OpenApiParameter.QUERY,
description="Page number for pagination",
),
OpenApiParameter(
name="page_size",
type=OpenApiTypes.INT,
location=OpenApiParameter.QUERY,
description="Number of results per page (max 100)",
),
],
responses={
200: {
"description": "Paginated list of public profiles",
"example": {
"count": 150,
"next": "https://api.thrillwiki.com/api/v1/accounts/profiles/?page=2",
"previous": None,
"results": [
{
"user_id": "uuid-1",
"username": "thrillseeker",
"date_joined": "2024-01-01T00:00:00Z",
"role": "USER",
"profile": {
"profile_id": "uuid-profile",
"display_name": "Thrill Seeker",
"avatar_url": "https://example.com/avatar.jpg",
"bio": "Coaster enthusiast!",
"total_credits": 150,
},
}
],
},
},
},
tags=["User Profile"],
)
@api_view(["GET"])
@permission_classes([AllowAny])
def list_profiles(request):
"""
List public user profiles with search and pagination.
This endpoint provides the missing /accounts/profiles/ list endpoint
that the frontend expects for user discovery features.
"""
from django.db.models import Q
from rest_framework.pagination import PageNumberPagination
# Base queryset: only active users with public profiles
queryset = User.objects.filter(
is_active=True,
).select_related("profile").order_by("-date_joined")
# Search filter
search = request.query_params.get("search", "").strip()
if search:
queryset = queryset.filter(
Q(username__icontains=search) |
Q(profile__display_name__icontains=search)
)
# Ordering
ordering = request.query_params.get("ordering", "-date_joined")
valid_orderings = ["date_joined", "-date_joined", "username", "-username"]
if ordering in valid_orderings:
queryset = queryset.order_by(ordering)
# Pagination
class ProfilePagination(PageNumberPagination):
page_size = 20
page_size_query_param = "page_size"
max_page_size = 100
paginator = ProfilePagination()
page = paginator.paginate_queryset(queryset, request)
if page is not None:
serializer = PublicUserSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
# Fallback if pagination fails
serializer = PublicUserSerializer(queryset[:20], many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
# === USER PROFILE ENDPOINTS ===