""" 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')