mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 07:11:08 -05:00
- Implemented extensive test cases for the Parks API, covering endpoints for listing, retrieving, creating, updating, and deleting parks. - Added tests for filtering, searching, and ordering parks in the API. - Created tests for error handling in the API, including malformed JSON and unsupported methods. - Developed model tests for Park, ParkArea, Company, and ParkReview models, ensuring validation and constraints are enforced. - Introduced utility mixins for API and model testing to streamline assertions and enhance test readability. - Included integration tests to validate complete workflows involving park creation, retrieval, updating, and deletion.
227 lines
6.9 KiB
Python
227 lines
6.9 KiB
Python
"""
|
|
Selectors for user and account-related data retrieval.
|
|
Following Django styleguide pattern for separating data access from business logic.
|
|
"""
|
|
|
|
from typing import Optional, Dict, Any, List
|
|
from django.db.models import QuerySet, Q, F, Count, Avg, Prefetch
|
|
from django.contrib.auth import get_user_model
|
|
from django.utils import timezone
|
|
from datetime import timedelta
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
def user_profile_optimized(*, user_id: int) -> Any:
|
|
"""
|
|
Get a user with optimized queries for profile display.
|
|
|
|
Args:
|
|
user_id: User ID
|
|
|
|
Returns:
|
|
User instance with prefetched related data
|
|
|
|
Raises:
|
|
User.DoesNotExist: If user doesn't exist
|
|
"""
|
|
return User.objects.prefetch_related(
|
|
'park_reviews',
|
|
'ride_reviews',
|
|
'socialaccount_set'
|
|
).annotate(
|
|
park_review_count=Count('park_reviews', filter=Q(park_reviews__is_published=True)),
|
|
ride_review_count=Count('ride_reviews', filter=Q(ride_reviews__is_published=True)),
|
|
total_review_count=F('park_review_count') + F('ride_review_count')
|
|
).get(id=user_id)
|
|
|
|
|
|
def active_users_with_stats() -> QuerySet:
|
|
"""
|
|
Get active users with review statistics.
|
|
|
|
Returns:
|
|
QuerySet of active users with review counts
|
|
"""
|
|
return User.objects.filter(
|
|
is_active=True
|
|
).annotate(
|
|
park_review_count=Count('park_reviews', filter=Q(park_reviews__is_published=True)),
|
|
ride_review_count=Count('ride_reviews', filter=Q(ride_reviews__is_published=True)),
|
|
total_review_count=F('park_review_count') + F('ride_review_count')
|
|
).order_by('-total_review_count')
|
|
|
|
|
|
def users_with_recent_activity(*, days: int = 30) -> QuerySet:
|
|
"""
|
|
Get users who have been active in the last N days.
|
|
|
|
Args:
|
|
days: Number of days to look back for activity
|
|
|
|
Returns:
|
|
QuerySet of recently active users
|
|
"""
|
|
cutoff_date = timezone.now() - timedelta(days=days)
|
|
|
|
return User.objects.filter(
|
|
Q(last_login__gte=cutoff_date) |
|
|
Q(park_reviews__created_at__gte=cutoff_date) |
|
|
Q(ride_reviews__created_at__gte=cutoff_date)
|
|
).annotate(
|
|
recent_park_reviews=Count('park_reviews', filter=Q(park_reviews__created_at__gte=cutoff_date)),
|
|
recent_ride_reviews=Count('ride_reviews', filter=Q(ride_reviews__created_at__gte=cutoff_date)),
|
|
recent_total_reviews=F('recent_park_reviews') + F('recent_ride_reviews')
|
|
).order_by('-last_login').distinct()
|
|
|
|
|
|
def top_reviewers(*, limit: int = 10) -> QuerySet:
|
|
"""
|
|
Get top users by review count.
|
|
|
|
Args:
|
|
limit: Maximum number of users to return
|
|
|
|
Returns:
|
|
QuerySet of top reviewers
|
|
"""
|
|
return User.objects.filter(
|
|
is_active=True
|
|
).annotate(
|
|
park_review_count=Count('park_reviews', filter=Q(park_reviews__is_published=True)),
|
|
ride_review_count=Count('ride_reviews', filter=Q(ride_reviews__is_published=True)),
|
|
total_review_count=F('park_review_count') + F('ride_review_count')
|
|
).filter(
|
|
total_review_count__gt=0
|
|
).order_by('-total_review_count')[:limit]
|
|
|
|
|
|
def moderator_users() -> QuerySet:
|
|
"""
|
|
Get users with moderation permissions.
|
|
|
|
Returns:
|
|
QuerySet of users who can moderate content
|
|
"""
|
|
return User.objects.filter(
|
|
Q(is_staff=True) |
|
|
Q(groups__name='Moderators') |
|
|
Q(user_permissions__codename__in=['change_parkreview', 'change_ridereview'])
|
|
).distinct().order_by('username')
|
|
|
|
|
|
def users_by_registration_date(*, start_date, end_date) -> QuerySet:
|
|
"""
|
|
Get users who registered within a date range.
|
|
|
|
Args:
|
|
start_date: Start of date range
|
|
end_date: End of date range
|
|
|
|
Returns:
|
|
QuerySet of users registered in the date range
|
|
"""
|
|
return User.objects.filter(
|
|
date_joined__date__gte=start_date,
|
|
date_joined__date__lte=end_date
|
|
).order_by('-date_joined')
|
|
|
|
|
|
def user_search_autocomplete(*, query: str, limit: int = 10) -> QuerySet:
|
|
"""
|
|
Get users matching a search query for autocomplete functionality.
|
|
|
|
Args:
|
|
query: Search string
|
|
limit: Maximum number of results
|
|
|
|
Returns:
|
|
QuerySet of matching users for autocomplete
|
|
"""
|
|
return User.objects.filter(
|
|
Q(username__icontains=query) |
|
|
Q(first_name__icontains=query) |
|
|
Q(last_name__icontains=query),
|
|
is_active=True
|
|
).order_by('username')[:limit]
|
|
|
|
|
|
def users_with_social_accounts() -> QuerySet:
|
|
"""
|
|
Get users who have connected social accounts.
|
|
|
|
Returns:
|
|
QuerySet of users with social account connections
|
|
"""
|
|
return User.objects.filter(
|
|
socialaccount__isnull=False
|
|
).prefetch_related(
|
|
'socialaccount_set'
|
|
).distinct().order_by('username')
|
|
|
|
|
|
def user_statistics_summary() -> Dict[str, Any]:
|
|
"""
|
|
Get overall user statistics for dashboard/analytics.
|
|
|
|
Returns:
|
|
Dictionary containing user statistics
|
|
"""
|
|
total_users = User.objects.count()
|
|
active_users = User.objects.filter(is_active=True).count()
|
|
staff_users = User.objects.filter(is_staff=True).count()
|
|
|
|
# Users with reviews
|
|
users_with_reviews = User.objects.filter(
|
|
Q(park_reviews__isnull=False) |
|
|
Q(ride_reviews__isnull=False)
|
|
).distinct().count()
|
|
|
|
# Recent registrations (last 30 days)
|
|
cutoff_date = timezone.now() - timedelta(days=30)
|
|
recent_registrations = User.objects.filter(
|
|
date_joined__gte=cutoff_date
|
|
).count()
|
|
|
|
return {
|
|
'total_users': total_users,
|
|
'active_users': active_users,
|
|
'inactive_users': total_users - active_users,
|
|
'staff_users': staff_users,
|
|
'users_with_reviews': users_with_reviews,
|
|
'recent_registrations': recent_registrations,
|
|
'review_participation_rate': (users_with_reviews / total_users * 100) if total_users > 0 else 0
|
|
}
|
|
|
|
|
|
def users_needing_email_verification() -> QuerySet:
|
|
"""
|
|
Get users who haven't verified their email addresses.
|
|
|
|
Returns:
|
|
QuerySet of users with unverified emails
|
|
"""
|
|
return User.objects.filter(
|
|
is_active=True,
|
|
emailaddress__verified=False
|
|
).distinct().order_by('date_joined')
|
|
|
|
|
|
def users_by_review_activity(*, min_reviews: int = 1) -> QuerySet:
|
|
"""
|
|
Get users who have written at least a minimum number of reviews.
|
|
|
|
Args:
|
|
min_reviews: Minimum number of reviews required
|
|
|
|
Returns:
|
|
QuerySet of users with sufficient review activity
|
|
"""
|
|
return User.objects.annotate(
|
|
park_review_count=Count('park_reviews', filter=Q(park_reviews__is_published=True)),
|
|
ride_review_count=Count('ride_reviews', filter=Q(ride_reviews__is_published=True)),
|
|
total_review_count=F('park_review_count') + F('ride_review_count')
|
|
).filter(
|
|
total_review_count__gte=min_reviews
|
|
).order_by('-total_review_count')
|