mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 06:11:07 -05:00
- Remove first_name and last_name fields from User model - Add user deletion and social provider services - Restructure auth serializers into separate directory - Update avatar upload functionality and API endpoints - Remove django-moderation integration documentation - Add mandatory compliance enforcement rules - Update frontend documentation with API usage examples
273 lines
7.4 KiB
Python
273 lines
7.4 KiB
Python
"""
|
|
Selectors for user and account-related data retrieval.
|
|
Following Django styleguide pattern for separating data access from business logic.
|
|
"""
|
|
|
|
from typing import Dict, Any
|
|
from django.db.models import QuerySet, Q, F, Count
|
|
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(display_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")
|
|
)
|