165 lines
8 KiB
Python
165 lines
8 KiB
Python
from collections import defaultdict, OrderedDict
|
|
from django.views.generic import TemplateView
|
|
from django.urls import reverse_lazy
|
|
from django.db.models import Count, Q, Prefetch, Sum, F, IntegerField, Value, BooleanField, Case, When
|
|
from django.db.models.functions import Coalesce
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
from trades.models import TradeOffer, TradeAcceptance, TradeOfferHaveCard, TradeOfferWantCard
|
|
from cards.models import Card
|
|
from django.utils.decorators import method_decorator
|
|
from django.template.response import TemplateResponse
|
|
from django.http import HttpResponseRedirect
|
|
import logging
|
|
from django.views import View
|
|
from django.http import HttpResponse
|
|
import contextlib
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class HomePageView(TemplateView):
|
|
template_name = "home/home.html"
|
|
|
|
#@silk_profile(name='Home Page')
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
try:
|
|
# Get all cards ordered by name, exclude cards with rarity level > 5
|
|
context["cards"] = Card.objects.filter(rarity_level__lte=5).order_by("name", "rarity_level")
|
|
|
|
# Reuse base trade offer queryset for market stats
|
|
base_offer_qs = TradeOffer.objects.filter(is_closed=False)
|
|
|
|
# Recent Offers
|
|
try:
|
|
recent_offers_qs = base_offer_qs.order_by("-created_at")[:6]
|
|
context["recent_offers"] = recent_offers_qs
|
|
context["cache_key_recent_offers"] = f"recent_offers_{recent_offers_qs.values_list('pk', 'updated_at')}"
|
|
except Exception as e:
|
|
logger.error(f"Error fetching recent offers: {str(e)}")
|
|
context["recent_offers"] = []
|
|
context["cache_key_recent_offers"] = "recent_offers_error"
|
|
|
|
# Most Offered Cards
|
|
try:
|
|
most_offered_cards_qs = (
|
|
Card.objects.filter(tradeofferhavecard__isnull=False).filter(rarity_level__lte=5)
|
|
.annotate(offer_count=Sum("tradeofferhavecard__quantity"))
|
|
.order_by("-offer_count")[:6]
|
|
)
|
|
context["most_offered_cards"] = most_offered_cards_qs
|
|
context["cache_key_most_offered_cards"] = f"most_offered_cards_{most_offered_cards_qs.values_list('pk', 'updated_at')}"
|
|
except Exception as e:
|
|
logger.error(f"Error fetching most offered cards: {str(e)}")
|
|
context["most_offered_cards"] = []
|
|
context["cache_key_most_offered_cards"] = "most_offered_cards_error"
|
|
# Most Wanted Cards
|
|
try:
|
|
most_wanted_cards_qs = (
|
|
Card.objects.filter(tradeofferwantcard__isnull=False).filter(rarity_level__lte=5)
|
|
.annotate(offer_count=Sum("tradeofferwantcard__quantity"))
|
|
.order_by("-offer_count")[:6]
|
|
)
|
|
context["most_wanted_cards"] = most_wanted_cards_qs
|
|
context["cache_key_most_wanted_cards"] = f"most_wanted_cards_{most_wanted_cards_qs.values_list('pk', 'updated_at')}"
|
|
except Exception as e:
|
|
logger.error(f"Error fetching most wanted cards: {str(e)}")
|
|
context["most_wanted_cards"] = []
|
|
|
|
# Least Offered Cards
|
|
try:
|
|
least_offered_cards_qs = (
|
|
Card.objects.filter(rarity_level__lte=5).annotate(
|
|
offer_count=Coalesce(Sum("tradeofferhavecard__quantity"), 0)
|
|
)
|
|
.order_by("offer_count")[:6]
|
|
)
|
|
context["least_offered_cards"] = least_offered_cards_qs
|
|
context["cache_key_least_offered_cards"] = f"least_offered_cards_{least_offered_cards_qs.values_list('pk', 'updated_at')}"
|
|
except Exception as e:
|
|
logger.error(f"Error fetching least offered cards: {str(e)}")
|
|
context["least_offered_cards"] = []
|
|
context["cache_key_least_offered_cards"] = "least_offered_cards_error"
|
|
# Build featured offers with custom ordering
|
|
featured = OrderedDict()
|
|
# Featured "All" offers remains fixed at the top
|
|
try:
|
|
featured["All"] = base_offer_qs.order_by("created_at")[:6]
|
|
except Exception as e:
|
|
logger.error(f"Error fetching 'All' featured offers: {str(e)}")
|
|
featured["All"] = []
|
|
|
|
try:
|
|
# Pull out distinct (rarity_level, rarity_icon) tuples
|
|
distinct_rarities = base_offer_qs.values_list("rarity_level", "rarity_icon").distinct()
|
|
|
|
# Prepare a list that holds tuples of (rarity_level, rarity_icon, offers)
|
|
rarity_offers = []
|
|
for rarity_level, rarity_icon in distinct_rarities:
|
|
offers = base_offer_qs.filter(rarity_level=rarity_level).order_by("created_at")[:6]
|
|
rarity_offers.append((rarity_level, rarity_icon, offers))
|
|
|
|
# Sort by rarity_level (from greatest to least)
|
|
rarity_offers.sort(key=lambda x: x[0], reverse=True)
|
|
|
|
# Add the sorted offers to the OrderedDict
|
|
for rarity_level, rarity_icon, offers in rarity_offers:
|
|
featured[rarity_icon] = offers
|
|
except Exception as e:
|
|
logger.error(f"Error processing rarity-based featured offers: {str(e)}")
|
|
|
|
context["featured_offers"] = featured
|
|
# Generate a cache key based on the pks and updated_at timestamps of all featured offers
|
|
all_offer_identifiers = []
|
|
for section_name,section_offers in featured.items():
|
|
# featured_section is a QuerySet. Fetch (pk, updated_at) tuples.
|
|
identifiers = section_offers.values_list('pk', 'updated_at')
|
|
# Format each tuple as "pk_timestamp" and add to the list
|
|
section_strings = [f"{section_name}_{pk}_{ts.timestamp()}" for pk, ts in identifiers]
|
|
all_offer_identifiers.extend(section_strings)
|
|
|
|
# Join all identifiers into a single string, sorted for consistency regardless of order
|
|
combined_identifiers = "|".join(sorted(all_offer_identifiers))
|
|
context["cache_key_featured_offers"] = f"featured_offers_{combined_identifiers}"
|
|
except Exception as e:
|
|
logger.error(f"Unhandled error in HomePageView.get_context_data: {str(e)}")
|
|
# Provide fallback empty data
|
|
context["cards"] = None
|
|
context["recent_offers"] = []
|
|
context["most_offered_cards"] = []
|
|
context["most_wanted_cards"] = []
|
|
context["least_offered_cards"] = []
|
|
context["featured_offers"] = OrderedDict([("All", [])])
|
|
|
|
return context
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
"""Override get method to add caching"""
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
class HealthCheckView(View):
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
try:
|
|
from django.db import connection
|
|
connection.cursor().execute("SELECT 1")
|
|
except Exception as e:
|
|
return HttpResponse("Database connection failed", status=500)
|
|
|
|
try:
|
|
from trades.models import TradeOffer
|
|
with contextlib.redirect_stdout(None):
|
|
print(TradeOffer.objects.count())
|
|
except Exception as e:
|
|
return HttpResponse("DB models not reachable, but db is reachable", status=500)
|
|
|
|
try:
|
|
from django.core.cache import cache
|
|
cache.set("test", "test")
|
|
with contextlib.redirect_stdout(None):
|
|
print(cache.get("test"))
|
|
except Exception as e:
|
|
return HttpResponse("Cache not reachable", status=500)
|
|
|
|
logger.info("OK/HEALTHY")
|
|
return HttpResponse("OK/HEALTHY")
|