Fix type errors
This commit is contained in:
parent
b2eef830d8
commit
e2283eb920
2 changed files with 150 additions and 147 deletions
232
twitch/feeds.py
232
twitch/feeds.py
|
|
@ -3,36 +3,41 @@ from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from django.contrib.syndication.views import Feed
|
from django.contrib.syndication.views import Feed
|
||||||
|
from django.db.models.query import QuerySet
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
from django.utils.safestring import SafeText
|
||||||
|
|
||||||
from twitch.models import DropCampaign, Game, Organization
|
from twitch.models import DropCampaign, Game, Organization, TimeBasedDrop
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from django.db.models import Model, QuerySet
|
||||||
|
|
||||||
|
|
||||||
# MARK: /rss/organizations/
|
# MARK: /rss/organizations/
|
||||||
class OrganizationFeed(Feed):
|
class OrganizationFeed(Feed):
|
||||||
"""RSS feed for latest organizations."""
|
"""RSS feed for latest organizations."""
|
||||||
|
|
||||||
title = "TTVDrops Organizations"
|
title: str = "TTVDrops Organizations"
|
||||||
link = "/organizations/"
|
link: str = "/organizations/"
|
||||||
description = "Latest organizations on TTVDrops"
|
description: str = "Latest organizations on TTVDrops"
|
||||||
|
|
||||||
def items(self) -> list[Organization]:
|
def items(self) -> list[Organization]:
|
||||||
"""Return the latest 100 organizations."""
|
"""Return the latest 100 organizations."""
|
||||||
return list(Organization.objects.order_by("-id")[:100])
|
return list(Organization.objects.order_by("-id")[:100])
|
||||||
|
|
||||||
def item_title(self, item: Organization) -> str:
|
def item_title(self, item: Model) -> SafeText:
|
||||||
"""Return the organization name as the item title."""
|
"""Return the organization name as the item title."""
|
||||||
return item.name
|
return SafeText(getattr(item, "name", str(item)))
|
||||||
|
|
||||||
def item_description(self, item: Organization) -> str:
|
def item_description(self, item: Model) -> SafeText:
|
||||||
"""Return a description of the organization."""
|
"""Return a description of the organization."""
|
||||||
return f"Organization {item.name}"
|
return SafeText(f"Organization {getattr(item, 'name', str(item))}")
|
||||||
|
|
||||||
def item_link(self, item: Organization) -> str:
|
def item_link(self, item: Model) -> str:
|
||||||
"""Return the link to the organization detail."""
|
"""Return the link to the organization detail."""
|
||||||
return reverse("twitch:organization_detail", args=[item.pk])
|
return reverse("twitch:organization_detail", args=[item.pk])
|
||||||
|
|
||||||
|
|
@ -41,23 +46,23 @@ class OrganizationFeed(Feed):
|
||||||
class GameFeed(Feed):
|
class GameFeed(Feed):
|
||||||
"""RSS feed for latest games."""
|
"""RSS feed for latest games."""
|
||||||
|
|
||||||
title = "TTVDrops Games"
|
title: str = "TTVDrops Games"
|
||||||
link = "/games/"
|
link: str = "/games/"
|
||||||
description = "Latest games on TTVDrops"
|
description: str = "Latest games on TTVDrops"
|
||||||
|
|
||||||
def items(self) -> list[Game]:
|
def items(self) -> list[Game]:
|
||||||
"""Return the latest 100 games."""
|
"""Return the latest 100 games."""
|
||||||
return list(Game.objects.order_by("-id")[:100])
|
return list(Game.objects.order_by("-id")[:100])
|
||||||
|
|
||||||
def item_title(self, item: Game) -> str:
|
def item_title(self, item: Model) -> SafeText:
|
||||||
"""Return the game name as the item title."""
|
"""Return the game name as the item title (SafeText for RSS)."""
|
||||||
return str(item)
|
return SafeText(str(item))
|
||||||
|
|
||||||
def item_description(self, item: Game) -> str:
|
def item_description(self, item: Model) -> SafeText:
|
||||||
"""Return a description of the game."""
|
"""Return a description of the game."""
|
||||||
return f"Game {item.display_name}"
|
return SafeText(f"Game {getattr(item, 'display_name', str(item))}")
|
||||||
|
|
||||||
def item_link(self, item: Game) -> str:
|
def item_link(self, item: Model) -> str:
|
||||||
"""Return the link to the game detail."""
|
"""Return the link to the game detail."""
|
||||||
return reverse("twitch:game_detail", args=[item.pk])
|
return reverse("twitch:game_detail", args=[item.pk])
|
||||||
|
|
||||||
|
|
@ -66,117 +71,116 @@ class GameFeed(Feed):
|
||||||
class DropCampaignFeed(Feed):
|
class DropCampaignFeed(Feed):
|
||||||
"""RSS feed for latest drop campaigns."""
|
"""RSS feed for latest drop campaigns."""
|
||||||
|
|
||||||
title = "Twitch Drop Campaigns"
|
title: str = "Twitch Drop Campaigns"
|
||||||
link = "/campaigns/"
|
link: str = "/campaigns/"
|
||||||
description = "Latest Twitch drop campaigns"
|
description: str = "Latest Twitch drop campaigns"
|
||||||
feed_url = "/rss/campaigns/"
|
feed_url: str = "/rss/campaigns/"
|
||||||
feed_copyright = "Information wants to be free."
|
feed_copyright: str = "Information wants to be free."
|
||||||
|
|
||||||
def items(self) -> list[DropCampaign]:
|
def items(self) -> list[DropCampaign]:
|
||||||
"""Return the latest 100 drop campaigns."""
|
"""Return the latest 100 drop campaigns."""
|
||||||
return list(DropCampaign.objects.select_related("game").order_by("-added_at")[:100])
|
return list(DropCampaign.objects.select_related("game").order_by("-added_at")[:100])
|
||||||
|
|
||||||
def item_title(self, item: DropCampaign) -> str:
|
def item_title(self, item: Model) -> SafeText:
|
||||||
"""Return the campaign name as the item title."""
|
"""Return the campaign name as the item title (SafeText for RSS)."""
|
||||||
return f"{item.game.display_name}: {item.clean_name}"
|
game: Game | None = getattr(item, "game", None)
|
||||||
|
game_name: str = getattr(game, "display_name", str(game)) if game else ""
|
||||||
|
clean_name: str = getattr(item, "clean_name", str(item))
|
||||||
|
return SafeText(f"{game_name}: {clean_name}")
|
||||||
|
|
||||||
def item_description(self, item: DropCampaign) -> str:
|
def item_description(self, item: Model) -> SafeText: # noqa: PLR0915
|
||||||
"""Return a description of the campaign."""
|
"""Return a description of the campaign."""
|
||||||
description = ""
|
description: str = ""
|
||||||
|
image_url: str | None = getattr(item, "image_url", None)
|
||||||
# Include the campaign image if available
|
name: str = getattr(item, "name", str(item))
|
||||||
if item.image_url:
|
if image_url:
|
||||||
description += format_html(
|
description += format_html(
|
||||||
'<img src="{}" alt="{}"><br><br>',
|
'<img src="{}" alt="{}"><br><br>',
|
||||||
item.image_url,
|
image_url,
|
||||||
item.name,
|
name,
|
||||||
)
|
)
|
||||||
|
desc_text: str | None = getattr(item, "description", None)
|
||||||
# Add the campaign description text
|
if desc_text:
|
||||||
description += format_html("<p>{}</p>", item.description) if item.description else ""
|
description += format_html("<p>{}</p>", desc_text)
|
||||||
|
start_at: datetime.datetime | None = getattr(item, "start_at", None)
|
||||||
# Add start and end dates for clarity
|
end_at: datetime.datetime | None = getattr(item, "end_at", None)
|
||||||
if item.start_at:
|
if start_at:
|
||||||
description += f"<p><strong>Starts:</strong> {item.start_at.strftime('%Y-%m-%d %H:%M %Z')}</p>"
|
description += f"<p><strong>Starts:</strong> {start_at.strftime('%Y-%m-%d %H:%M %Z')}</p>"
|
||||||
if item.end_at:
|
if end_at:
|
||||||
description += f"<p><strong>Ends:</strong> {item.end_at.strftime('%Y-%m-%d %H:%M %Z')}</p>"
|
description += f"<p><strong>Ends:</strong> {end_at.strftime('%Y-%m-%d %H:%M %Z')}</p>"
|
||||||
|
drops: QuerySet[TimeBasedDrop] | None = getattr(item, "time_based_drops", None)
|
||||||
# Add information about the drops in this campaign
|
|
||||||
drops = item.time_based_drops.select_related().prefetch_related("benefits").all() # type: ignore[attr-defined]
|
|
||||||
if drops:
|
if drops:
|
||||||
description += "<h3>Drops in this campaign:</h3>"
|
drops_qs: QuerySet[TimeBasedDrop] = drops.select_related().prefetch_related("benefits").all()
|
||||||
table_header = (
|
if drops_qs:
|
||||||
'<table style="border-collapse: collapse; width: 100%;">'
|
description += "<h3>Drops in this campaign:</h3>"
|
||||||
"<thead><tr>"
|
table_header = (
|
||||||
'<th style="border: 1px solid #ddd; padding: 8px;">Benefits</th>'
|
'<table style="border-collapse: collapse; width: 100%;">'
|
||||||
'<th style="border: 1px solid #ddd; padding: 8px;">Drop Name</th>'
|
"<thead><tr>"
|
||||||
'<th style="border: 1px solid #ddd; padding: 8px;">Requirements</th>'
|
'<th style="border: 1px solid #ddd; padding: 8px;">Benefits</th>'
|
||||||
'<th style="border: 1px solid #ddd; padding: 8px;">Period</th>'
|
'<th style="border: 1px solid #ddd; padding: 8px;">Drop Name</th>'
|
||||||
"</tr></thead><tbody>"
|
'<th style="border: 1px solid #ddd; padding: 8px;">Requirements</th>'
|
||||||
)
|
'<th style="border: 1px solid #ddd; padding: 8px;">Period</th>'
|
||||||
description += table_header
|
"</tr></thead><tbody>"
|
||||||
|
)
|
||||||
|
description += table_header
|
||||||
|
for drop in drops_qs:
|
||||||
|
description += "<tr>"
|
||||||
|
description += '<td style="border: 1px solid #ddd; padding: 8px;">'
|
||||||
|
for benefit in drop.benefits.all():
|
||||||
|
if getattr(benefit, "image_asset_url", None):
|
||||||
|
description += format_html(
|
||||||
|
'<img height="60" width="60" style="object-fit: cover; margin-right: 5px;" src="{}" alt="{}">',
|
||||||
|
benefit.image_asset_url,
|
||||||
|
benefit.name,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
placeholder_img = (
|
||||||
|
'<img height="60" width="60" style="object-fit: cover; margin-right: 5px;" '
|
||||||
|
'src="/static/images/placeholder.png" alt="No Image Available">'
|
||||||
|
)
|
||||||
|
description += placeholder_img
|
||||||
|
description += "</td>"
|
||||||
|
description += f'<td style="border: 1px solid #ddd; padding: 8px;">{getattr(drop, "name", str(drop))}</td>'
|
||||||
|
requirements: str = ""
|
||||||
|
if getattr(drop, "required_minutes_watched", None):
|
||||||
|
requirements = f"{drop.required_minutes_watched} minutes watched"
|
||||||
|
if getattr(drop, "required_subs", 0) > 0:
|
||||||
|
if requirements:
|
||||||
|
requirements += f" and {drop.required_subs} subscriptions required"
|
||||||
|
else:
|
||||||
|
requirements = f"{drop.required_subs} subscriptions required"
|
||||||
|
description += f'<td style="border: 1px solid #ddd; padding: 8px;">{requirements}</td>'
|
||||||
|
period: str = ""
|
||||||
|
start_at = getattr(drop, "start_at", None)
|
||||||
|
end_at = getattr(drop, "end_at", None)
|
||||||
|
if start_at is not None:
|
||||||
|
period += start_at.strftime("%Y-%m-%d %H:%M %Z")
|
||||||
|
if end_at is not None:
|
||||||
|
if period:
|
||||||
|
period += " - " + end_at.strftime("%Y-%m-%d %H:%M %Z")
|
||||||
|
else:
|
||||||
|
period = end_at.strftime("%Y-%m-%d %H:%M %Z")
|
||||||
|
description += f'<td style="border: 1px solid #ddd; padding: 8px;">{period}</td>'
|
||||||
|
description += "</tr>"
|
||||||
|
description += "</tbody></table><br>"
|
||||||
|
details_url: str | None = getattr(item, "details_url", None)
|
||||||
|
if details_url:
|
||||||
|
description += format_html('<p><a href="{}">About this drop</a></p>', details_url)
|
||||||
|
return SafeText(description)
|
||||||
|
|
||||||
for drop in drops:
|
def item_link(self, item: Model) -> str:
|
||||||
description += "<tr>"
|
|
||||||
# Benefits column with images
|
|
||||||
description += '<td style="border: 1px solid #ddd; padding: 8px;">'
|
|
||||||
for benefit in drop.benefits.all():
|
|
||||||
if benefit.image_asset_url:
|
|
||||||
description += format_html(
|
|
||||||
'<img height="60" width="60" style="object-fit: cover; margin-right: 5px;" src="{}" alt="{}">',
|
|
||||||
benefit.image_asset_url,
|
|
||||||
benefit.name,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
placeholder_img = (
|
|
||||||
'<img height="60" width="60" style="object-fit: cover; margin-right: 5px;" '
|
|
||||||
'src="/static/images/placeholder.png" alt="No Image Available">'
|
|
||||||
)
|
|
||||||
description += placeholder_img
|
|
||||||
description += "</td>"
|
|
||||||
|
|
||||||
# Drop name
|
|
||||||
description += f'<td style="border: 1px solid #ddd; padding: 8px;">{drop.name}</td>'
|
|
||||||
|
|
||||||
# Requirements
|
|
||||||
requirements = ""
|
|
||||||
if drop.required_minutes_watched:
|
|
||||||
requirements = f"{drop.required_minutes_watched} minutes watched"
|
|
||||||
if drop.required_subs > 0:
|
|
||||||
if requirements:
|
|
||||||
requirements += f" and {drop.required_subs} subscriptions required"
|
|
||||||
else:
|
|
||||||
requirements = f"{drop.required_subs} subscriptions required"
|
|
||||||
description += f'<td style="border: 1px solid #ddd; padding: 8px;">{requirements}</td>'
|
|
||||||
|
|
||||||
# Period
|
|
||||||
period = ""
|
|
||||||
if drop.start_at:
|
|
||||||
period += drop.start_at.strftime("%Y-%m-%d %H:%M %Z")
|
|
||||||
if drop.end_at:
|
|
||||||
if period:
|
|
||||||
period += " - " + drop.end_at.strftime("%Y-%m-%d %H:%M %Z")
|
|
||||||
else:
|
|
||||||
period = drop.end_at.strftime("%Y-%m-%d %H:%M %Z")
|
|
||||||
description += f'<td style="border: 1px solid #ddd; padding: 8px;">{period}</td>'
|
|
||||||
|
|
||||||
description += "</tr>"
|
|
||||||
|
|
||||||
description += "</tbody></table><br>"
|
|
||||||
|
|
||||||
# Add a clear link to the campaign details page
|
|
||||||
if item.details_url:
|
|
||||||
description += format_html('<p><a href="{}">About this drop</a></p>', item.details_url)
|
|
||||||
|
|
||||||
return f"{description}"
|
|
||||||
|
|
||||||
def item_link(self, item: DropCampaign) -> str:
|
|
||||||
"""Return the link to the campaign detail."""
|
"""Return the link to the campaign detail."""
|
||||||
return reverse("twitch:campaign_detail", args=[item.pk])
|
return reverse("twitch:campaign_detail", args=[item.pk])
|
||||||
|
|
||||||
def item_pubdate(self, item: DropCampaign) -> datetime.datetime:
|
def item_pubdate(self, item: Model) -> datetime.datetime:
|
||||||
"""Returns the publication date to the feed item."""
|
"""Returns the publication date to the feed item. Fallback to updated_at or now if missing."""
|
||||||
return item.start_at
|
start_at: datetime.datetime | None = getattr(item, "start_at", None)
|
||||||
|
if start_at:
|
||||||
|
return start_at
|
||||||
|
updated_at: datetime.datetime | None = getattr(item, "updated_at", None)
|
||||||
|
if updated_at:
|
||||||
|
return updated_at
|
||||||
|
return timezone.now()
|
||||||
|
|
||||||
def item_updateddate(self, item: DropCampaign) -> datetime.datetime:
|
def item_updateddate(self, item: DropCampaign) -> datetime.datetime:
|
||||||
"""Returns the campaign's last update time."""
|
"""Returns the campaign's last update time."""
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
|
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
|
||||||
from django.core.serializers import serialize
|
from django.core.serializers import serialize
|
||||||
from django.db.models import Count, F, Prefetch, Q
|
from django.db.models import BaseManager, Count, F, Model, Prefetch, Q
|
||||||
from django.db.models.functions import Trim
|
from django.db.models.functions import Trim
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
|
@ -118,28 +118,27 @@ class OrgDetailView(DetailView):
|
||||||
Returns:
|
Returns:
|
||||||
dict: Context data.
|
dict: Context data.
|
||||||
"""
|
"""
|
||||||
context = super().get_context_data(**kwargs)
|
context: dict[str, Any] = super().get_context_data(**kwargs)
|
||||||
organization: Organization = self.object
|
organization: Organization = self.get_object() # pyright: ignore[reportAssignmentType]
|
||||||
|
games: QuerySet[Game] = organization.games.all() # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
|
||||||
games: QuerySet[Game, Game] = organization.games.all() # pyright: ignore[reportAttributeAccessIssue]
|
serialized_org: str = serialize(
|
||||||
|
|
||||||
serialized_org = serialize(
|
|
||||||
"json",
|
"json",
|
||||||
[organization],
|
[organization],
|
||||||
fields=("name",),
|
fields=("name",),
|
||||||
)
|
)
|
||||||
org_data = json.loads(serialized_org)
|
org_data: list[dict] = json.loads(serialized_org)
|
||||||
|
|
||||||
if games.exists():
|
if games.exists():
|
||||||
serialized_games = serialize(
|
serialized_games: str = serialize(
|
||||||
"json",
|
"json",
|
||||||
games,
|
games,
|
||||||
fields=("slug", "name", "display_name", "box_art"),
|
fields=("slug", "name", "display_name", "box_art"),
|
||||||
)
|
)
|
||||||
games_data = json.loads(serialized_games)
|
games_data: list[dict] = json.loads(serialized_games)
|
||||||
org_data[0]["fields"]["games"] = games_data
|
org_data[0]["fields"]["games"] = games_data
|
||||||
|
|
||||||
pretty_org_data = json.dumps(org_data[0], indent=4)
|
pretty_org_data: str = json.dumps(org_data[0], indent=4)
|
||||||
|
|
||||||
context.update({
|
context.update({
|
||||||
"games": games,
|
"games": games,
|
||||||
|
|
@ -186,9 +185,9 @@ class DropCampaignListView(ListView):
|
||||||
context["games"] = Game.objects.all().order_by("display_name")
|
context["games"] = Game.objects.all().order_by("display_name")
|
||||||
context["status_options"] = ["active", "upcoming", "expired"]
|
context["status_options"] = ["active", "upcoming", "expired"]
|
||||||
context["now"] = timezone.now()
|
context["now"] = timezone.now()
|
||||||
context["selected_game"] = str(self.request.GET.get(key="game", default=""))
|
context["selected_game"] = self.request.GET.get("game", "")
|
||||||
context["selected_per_page"] = self.paginate_by
|
context["selected_per_page"] = self.paginate_by
|
||||||
context["selected_status"] = self.request.GET.get(key="status", default="")
|
context["selected_status"] = self.request.GET.get("status", "")
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
@ -214,7 +213,7 @@ class DropCampaignDetailView(DetailView):
|
||||||
template_name = "twitch/campaign_detail.html"
|
template_name = "twitch/campaign_detail.html"
|
||||||
context_object_name = "campaign"
|
context_object_name = "campaign"
|
||||||
|
|
||||||
def get_object(self, queryset: QuerySet[DropCampaign] | None = None) -> DropCampaign:
|
def get_object(self, queryset: QuerySet[DropCampaign] | None = None) -> Model:
|
||||||
"""Get the campaign object with related data prefetched.
|
"""Get the campaign object with related data prefetched.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -240,8 +239,8 @@ class DropCampaignDetailView(DetailView):
|
||||||
dict: Context data.
|
dict: Context data.
|
||||||
"""
|
"""
|
||||||
context: dict[str, Any] = super().get_context_data(**kwargs)
|
context: dict[str, Any] = super().get_context_data(**kwargs)
|
||||||
campaign = context["campaign"]
|
campaign: DropCampaign = context["campaign"]
|
||||||
drops: QuerySet[TimeBasedDrop, TimeBasedDrop] = (
|
drops: BaseManager[TimeBasedDrop] = (
|
||||||
TimeBasedDrop.objects.filter(campaign=campaign).select_related("campaign").prefetch_related("benefits").order_by("required_minutes_watched")
|
TimeBasedDrop.objects.filter(campaign=campaign).select_related("campaign").prefetch_related("benefits").order_by("required_minutes_watched")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -276,11 +275,11 @@ class DropCampaignDetailView(DetailView):
|
||||||
"end_at",
|
"end_at",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
drops_data = json.loads(serialized_drops)
|
drops_data: list[dict[str, Any]] = json.loads(serialized_drops)
|
||||||
|
|
||||||
for i, drop in enumerate(drops):
|
for i, drop in enumerate(drops):
|
||||||
benefits = drop.benefits.all()
|
benefits: list[DropBenefit] = list(drop.benefits.all())
|
||||||
if benefits.exists():
|
if benefits:
|
||||||
serialized_benefits = serialize(
|
serialized_benefits = serialize(
|
||||||
"json",
|
"json",
|
||||||
benefits,
|
benefits,
|
||||||
|
|
@ -292,11 +291,11 @@ class DropCampaignDetailView(DetailView):
|
||||||
campaign_data[0]["fields"]["drops"] = drops_data
|
campaign_data[0]["fields"]["drops"] = drops_data
|
||||||
|
|
||||||
# Enhance drops with additional context data
|
# Enhance drops with additional context data
|
||||||
enhanced_drops = []
|
enhanced_drops: list[dict[str, TimeBasedDrop | datetime.datetime | str | None]] = []
|
||||||
now: datetime.datetime = timezone.now()
|
now: datetime.datetime = timezone.now()
|
||||||
for drop in drops:
|
for drop in drops:
|
||||||
# Ensure benefits are loaded
|
# Ensure benefits are loaded
|
||||||
benefits = list(drop.benefits.all())
|
benefits: list[DropBenefit] = list(drop.benefits.all())
|
||||||
|
|
||||||
# Calculate countdown text
|
# Calculate countdown text
|
||||||
if drop.end_at and drop.end_at > now:
|
if drop.end_at and drop.end_at > now:
|
||||||
|
|
@ -318,7 +317,7 @@ class DropCampaignDetailView(DetailView):
|
||||||
else:
|
else:
|
||||||
countdown_text = "Expired"
|
countdown_text = "Expired"
|
||||||
|
|
||||||
enhanced_drop: dict[str, str | datetime.datetime | TimeBasedDrop] = {
|
enhanced_drop: dict[str, TimeBasedDrop | datetime.datetime | str | None] = {
|
||||||
"drop": drop,
|
"drop": drop,
|
||||||
"local_start": drop.start_at,
|
"local_start": drop.start_at,
|
||||||
"local_end": drop.end_at,
|
"local_end": drop.end_at,
|
||||||
|
|
@ -380,7 +379,7 @@ class GamesGridView(ListView):
|
||||||
context: dict[str, Any] = super().get_context_data(**kwargs)
|
context: dict[str, Any] = super().get_context_data(**kwargs)
|
||||||
now: datetime.datetime = timezone.now()
|
now: datetime.datetime = timezone.now()
|
||||||
|
|
||||||
games_with_campaigns: QuerySet[Game, Game] = (
|
games_with_campaigns: BaseManager[Game] = (
|
||||||
Game.objects.filter(drop_campaigns__isnull=False)
|
Game.objects.filter(drop_campaigns__isnull=False)
|
||||||
.select_related("owner")
|
.select_related("owner")
|
||||||
.annotate(
|
.annotate(
|
||||||
|
|
@ -426,10 +425,10 @@ class GameDetailView(DetailView):
|
||||||
Expired campaigns are filtered based on either end date or status.
|
Expired campaigns are filtered based on either end date or status.
|
||||||
"""
|
"""
|
||||||
context: dict[str, Any] = super().get_context_data(**kwargs)
|
context: dict[str, Any] = super().get_context_data(**kwargs)
|
||||||
game: Game = self.get_object()
|
game: Game = self.get_object() # pyright: ignore[reportAssignmentType]
|
||||||
|
|
||||||
now: datetime.datetime = timezone.now()
|
now: datetime.datetime = timezone.now()
|
||||||
all_campaigns: QuerySet[DropCampaign, DropCampaign] = (
|
all_campaigns: BaseManager[DropCampaign] = (
|
||||||
DropCampaign.objects.filter(game=game)
|
DropCampaign.objects.filter(game=game)
|
||||||
.select_related("game__owner")
|
.select_related("game__owner")
|
||||||
.prefetch_related(
|
.prefetch_related(
|
||||||
|
|
@ -456,14 +455,14 @@ class GameDetailView(DetailView):
|
||||||
|
|
||||||
# Add unique sorted benefits to each campaign object
|
# Add unique sorted benefits to each campaign object
|
||||||
for campaign in all_campaigns:
|
for campaign in all_campaigns:
|
||||||
benefits_dict = {} # Use dict to track unique benefits by ID
|
benefits_dict: dict[int, DropBenefit] = {} # Use dict to track unique benefits by ID
|
||||||
for drop in campaign.time_based_drops.all(): # type: ignore[attr-defined]
|
for drop in campaign.time_based_drops.all(): # type: ignore[attr-defined]
|
||||||
for benefit in drop.benefits.all():
|
for benefit in drop.benefits.all():
|
||||||
benefits_dict[benefit.id] = benefit
|
benefits_dict[benefit.id] = benefit
|
||||||
# Sort benefits by name and attach to campaign
|
# Sort benefits by name and attach to campaign
|
||||||
campaign.sorted_benefits = sorted(benefits_dict.values(), key=lambda b: b.name) # type: ignore[attr-defined]
|
campaign.sorted_benefits = sorted(benefits_dict.values(), key=lambda b: b.name) # type: ignore[attr-defined]
|
||||||
|
|
||||||
serialized_game = serialize(
|
serialized_game: str = serialize(
|
||||||
"json",
|
"json",
|
||||||
[game],
|
[game],
|
||||||
fields=(
|
fields=(
|
||||||
|
|
@ -474,7 +473,7 @@ class GameDetailView(DetailView):
|
||||||
"owner",
|
"owner",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
game_data = json.loads(serialized_game)
|
game_data: list[dict[str, Any]] = json.loads(serialized_game)
|
||||||
|
|
||||||
if all_campaigns.exists():
|
if all_campaigns.exists():
|
||||||
serialized_campaigns = serialize(
|
serialized_campaigns = serialize(
|
||||||
|
|
@ -491,7 +490,7 @@ class GameDetailView(DetailView):
|
||||||
"is_account_connected",
|
"is_account_connected",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
campaigns_data = json.loads(serialized_campaigns)
|
campaigns_data: list[dict[str, Any]] = json.loads(serialized_campaigns)
|
||||||
game_data[0]["fields"]["campaigns"] = campaigns_data
|
game_data[0]["fields"]["campaigns"] = campaigns_data
|
||||||
|
|
||||||
context.update({
|
context.update({
|
||||||
|
|
@ -500,7 +499,7 @@ class GameDetailView(DetailView):
|
||||||
"expired_campaigns": expired_campaigns,
|
"expired_campaigns": expired_campaigns,
|
||||||
"owner": game.owner,
|
"owner": game.owner,
|
||||||
"now": now,
|
"now": now,
|
||||||
"game_data": format_and_color_json(game_data[0]),
|
"game_data": format_and_color_json(json.dumps(game_data[0], indent=4)),
|
||||||
})
|
})
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
@ -718,10 +717,10 @@ class ChannelDetailView(DetailView):
|
||||||
dict: Context data with active, upcoming, and expired campaigns for this channel.
|
dict: Context data with active, upcoming, and expired campaigns for this channel.
|
||||||
"""
|
"""
|
||||||
context: dict[str, Any] = super().get_context_data(**kwargs)
|
context: dict[str, Any] = super().get_context_data(**kwargs)
|
||||||
channel: Channel = self.get_object()
|
channel: Channel = self.get_object() # pyright: ignore[reportAssignmentType]
|
||||||
|
|
||||||
now: datetime.datetime = timezone.now()
|
now: datetime.datetime = timezone.now()
|
||||||
all_campaigns: QuerySet[DropCampaign, DropCampaign] = (
|
all_campaigns: QuerySet[DropCampaign] = (
|
||||||
DropCampaign.objects.filter(allow_channels=channel)
|
DropCampaign.objects.filter(allow_channels=channel)
|
||||||
.select_related("game__owner")
|
.select_related("game__owner")
|
||||||
.prefetch_related(
|
.prefetch_related(
|
||||||
|
|
@ -749,7 +748,7 @@ class ChannelDetailView(DetailView):
|
||||||
|
|
||||||
# Add unique sorted benefits to each campaign object
|
# Add unique sorted benefits to each campaign object
|
||||||
for campaign in all_campaigns:
|
for campaign in all_campaigns:
|
||||||
benefits_dict = {} # Use dict to track unique benefits by ID
|
benefits_dict: dict[int, DropBenefit] = {} # Use dict to track unique benefits by ID
|
||||||
for drop in campaign.time_based_drops.all(): # type: ignore[attr-defined]
|
for drop in campaign.time_based_drops.all(): # type: ignore[attr-defined]
|
||||||
for benefit in drop.benefits.all():
|
for benefit in drop.benefits.all():
|
||||||
benefits_dict[benefit.id] = benefit
|
benefits_dict[benefit.id] = benefit
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue