Refactor dashboard view to group campaigns by game, preventing duplicates for multi-owner games
This commit is contained in:
parent
92ce21938e
commit
5fe4ed4eb1
3 changed files with 160 additions and 122 deletions
|
|
@ -1,11 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Any
|
||||
from typing import Literal
|
||||
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from twitch.models import Channel
|
||||
from twitch.models import DropBenefit
|
||||
|
|
@ -405,6 +407,39 @@ class TestChannelListView:
|
|||
assert response.status_code == 200
|
||||
assert "active_campaigns" in response.context
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_dashboard_dedupes_campaigns_for_multi_owner_game(self, client: Client) -> None:
|
||||
"""Dashboard should not render duplicate campaign cards when a game has multiple owners."""
|
||||
now = timezone.now()
|
||||
org1: Organization = Organization.objects.create(twitch_id="org_a", name="Org A")
|
||||
org2: Organization = Organization.objects.create(twitch_id="org_b", name="Org B")
|
||||
game: Game = Game.objects.create(twitch_id="game_multi_owner", name="game", display_name="Multi Owner")
|
||||
game.owners.add(org1, org2)
|
||||
|
||||
campaign: DropCampaign = DropCampaign.objects.create(
|
||||
twitch_id="camp1",
|
||||
name="Campaign",
|
||||
game=game,
|
||||
operation_name="DropCampaignDetails",
|
||||
start_at=now - datetime.timedelta(hours=1),
|
||||
end_at=now + datetime.timedelta(hours=1),
|
||||
)
|
||||
|
||||
response: _MonkeyPatchedWSGIResponse = client.get(reverse("twitch:dashboard"))
|
||||
assert response.status_code == 200
|
||||
|
||||
context: ContextList | dict[str, Any] = response.context
|
||||
if isinstance(context, list):
|
||||
context = context[-1]
|
||||
|
||||
assert "campaigns_by_game" in context
|
||||
assert game.twitch_id in context["campaigns_by_game"]
|
||||
assert len(context["campaigns_by_game"][game.twitch_id]["campaigns"]) == 1
|
||||
|
||||
# Template renders each campaign with a stable id, so we can assert it appears once.
|
||||
html = response.content.decode("utf-8")
|
||||
assert html.count(f"campaign-article-{campaign.twitch_id}") == 1
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_debug_view(self, client: Client) -> None:
|
||||
"""Test debug view returns 200 and has games_without_owner in context."""
|
||||
|
|
|
|||
|
|
@ -675,6 +675,7 @@ def dashboard(request: HttpRequest) -> HttpResponse:
|
|||
active_campaigns: QuerySet[DropCampaign] = (
|
||||
DropCampaign.objects
|
||||
.filter(start_at__lte=now, end_at__gte=now)
|
||||
.select_related("game")
|
||||
.prefetch_related("game__owners")
|
||||
.prefetch_related(
|
||||
"allow_channels",
|
||||
|
|
@ -682,34 +683,30 @@ def dashboard(request: HttpRequest) -> HttpResponse:
|
|||
.order_by("-start_at")
|
||||
)
|
||||
|
||||
# Use OrderedDict to preserve insertion order (newest campaigns first)
|
||||
campaigns_by_org_game: OrderedDict[str, Any] = OrderedDict()
|
||||
# Preserve insertion order (newest campaigns first). Group by game so games with multiple owners
|
||||
# don't render duplicate campaign cards.
|
||||
campaigns_by_game: OrderedDict[str, dict[str, Any]] = OrderedDict()
|
||||
|
||||
for campaign in active_campaigns:
|
||||
for owner in campaign.game.owners.all():
|
||||
org_id: str = owner.twitch_id if owner else "unknown"
|
||||
org_name: str = owner.name if owner else "Unknown"
|
||||
game_id: str = campaign.game.twitch_id
|
||||
game_name: str = campaign.game.display_name
|
||||
game: Game = campaign.game
|
||||
game_id: str = game.twitch_id
|
||||
|
||||
if org_id not in campaigns_by_org_game:
|
||||
campaigns_by_org_game[org_id] = {"name": org_name, "games": OrderedDict()}
|
||||
if game_id not in campaigns_by_game:
|
||||
campaigns_by_game[game_id] = {
|
||||
"name": game.display_name,
|
||||
"box_art": game.box_art_best_url,
|
||||
"owners": list(game.owners.all()),
|
||||
"campaigns": [],
|
||||
}
|
||||
|
||||
if game_id not in campaigns_by_org_game[org_id]["games"]:
|
||||
campaigns_by_org_game[org_id]["games"][game_id] = {
|
||||
"name": game_name,
|
||||
"box_art": campaign.game.box_art,
|
||||
"campaigns": [],
|
||||
}
|
||||
|
||||
campaigns_by_org_game[org_id]["games"][game_id]["campaigns"].append(campaign)
|
||||
campaigns_by_game[game_id]["campaigns"].append(campaign)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"twitch/dashboard.html",
|
||||
{
|
||||
"active_campaigns": active_campaigns,
|
||||
"campaigns_by_org_game": campaigns_by_org_game,
|
||||
"campaigns_by_game": campaigns_by_game,
|
||||
"now": now,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue