diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e620a22..b7aaca1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,13 +21,13 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/adamchainz/django-upgrade
- rev: 1.31.1
+ rev: 1.32.0
hooks:
- id: django-upgrade
args: [--target-version, "6.0"]
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.16.2
+ rev: v0.16.4
hooks:
- id: ruff-check
args: ["--fix", "--exit-non-zero-on-fix"]
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ee505c3..5576f87 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -63,6 +63,7 @@
"pytest",
"Ravendawn",
"regularuser",
+ "rewa",
"rewardcampaign",
"runserver",
"s3cret",
@@ -72,10 +73,12 @@
"speculationrules",
"staticfiles",
"Sunkwi",
+ "sunkwibot",
"testchannel",
"testpass",
"thelovinator",
"timebaseddrop",
+ "topdown",
"tqdm",
"trixie",
"ttvdrops",
diff --git a/core/tests/test_views.py b/core/tests/test_views.py
index 938c24b..2e4c853 100644
--- a/core/tests/test_views.py
+++ b/core/tests/test_views.py
@@ -1,16 +1,20 @@
from datetime import UTC
from datetime import datetime as dt
+from datetime import timedelta
from typing import TYPE_CHECKING
from django.test import RequestFactory
from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse
+from django.utils import timezone
from core.views import _build_base_url
from kick.models import KickCategory
from kick.models import KickDropCampaign
from kick.models import KickOrganization
+from twitch.models import Reward
+from twitch.models import RewardCampaign
if TYPE_CHECKING:
from django.test.client import _MonkeyPatchedWSGIResponse
@@ -121,3 +125,32 @@ class TestCoreDashboardKickSection(TestCase):
org_url: str = reverse("kick:organization_detail", args=[org.kick_id])
assert org_url in content
assert "Unknown Category" not in content
+
+
+class TestCoreDashboardRewardCampaigns(TestCase):
+ """Tests for the reward campaign section within the core dashboard."""
+
+ def test_core_dashboard_renders_reward_campaign_rewards(self) -> None:
+ """Core dashboard reward cards should list their individual rewards."""
+ now = timezone.now()
+ campaign: RewardCampaign = RewardCampaign.objects.create(
+ twitch_id="core-dashboard-reward",
+ name="Core Dashboard Reward",
+ brand="Core Brand",
+ starts_at=now - timedelta(hours=1),
+ ends_at=now + timedelta(hours=1),
+ status="ACTIVE",
+ )
+ Reward.objects.create(
+ reward_campaign=campaign,
+ twitch_id="core-dashboard-reward-item-1",
+ name="Core Dashboard Reward Item",
+ )
+
+ response: _MonkeyPatchedWSGIResponse = self.client.get(
+ reverse("core:dashboard"),
+ )
+ content: str = response.content.decode()
+
+ assert response.status_code == 200
+ assert "Core Dashboard Reward Item" in content
diff --git a/core/views.py b/core/views.py
index c3c7dde..0473653 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1229,6 +1229,7 @@ def dashboard(request: HttpRequest) -> HttpResponse: # ruff:ignore[too-many-loc
RewardCampaign.objects
.filter(starts_at__lte=now, ends_at__gte=now)
.select_related("game")
+ .prefetch_related("rewards")
.order_by("-starts_at")
)
diff --git a/templates/core/dashboard.html b/templates/core/dashboard.html
index 2a7185d..02c9df4 100644
--- a/templates/core/dashboard.html
+++ b/templates/core/dashboard.html
@@ -323,6 +323,12 @@
{% if campaign.summary %}
diff --git a/templates/twitch/game_less_rewards.html b/templates/twitch/game_less_rewards.html
index 6012efd..0b1f545 100644
--- a/templates/twitch/game_less_rewards.html
+++ b/templates/twitch/game_less_rewards.html
@@ -66,6 +66,7 @@
| Campaign |
Brand |
+ Rewards |
Type |
Ends |
@@ -87,6 +88,11 @@
{% endif %}
{{ campaign.brand|default:"-" }} |
+
+ {% for reward in campaign.rewards.all %}
+ {{ reward.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ |
{% if campaign.is_sitewide %}
Site-wide
@@ -114,6 +120,7 @@
|
| Campaign |
Brand |
+ Rewards |
Type |
Starts |
@@ -135,6 +142,11 @@
{% endif %}
{{ campaign.brand|default:"-" }} |
+
+ {% for reward in campaign.rewards.all %}
+ {{ reward.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ |
{% if campaign.is_sitewide %}
Site-wide
@@ -162,6 +174,7 @@
|
| Campaign |
Brand |
+ Rewards |
Type |
Ended |
@@ -183,6 +196,11 @@
{% endif %}
{{ campaign.brand|default:"-" }} |
+
+ {% for reward in campaign.rewards.all %}
+ {{ reward.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ |
{% if campaign.is_sitewide %}
Site-wide
diff --git a/templates/twitch/includes/reward_campaign_card.html b/templates/twitch/includes/reward_campaign_card.html
index dc8611a..d7f6d3e 100644
--- a/templates/twitch/includes/reward_campaign_card.html
+++ b/templates/twitch/includes/reward_campaign_card.html
@@ -1,50 +1,86 @@
{% load image_tags %}
-
- {% picture campaign.image_best_url alt="Image for "|add:campaign.name width=120 %}
-
-
-
- {% if campaign.starts_at <= now and campaign.ends_at >= now %}
- - Ends
- -
-
-
- {% elif campaign.starts_at > now %}
- - Starts
- -
-
-
- {% else %}
- - Ended
- -
-
-
- {% endif %}
- {% if campaign.game %}
- - Game
- - {{ campaign.game.display_name }}
- {% elif campaign.is_sitewide %}
- - Type
- - Site-wide reward campaign
- {% else %}
- - Type
- - Brand reward
- {% endif %}
- - Data source
- - {{ campaign.data_source }}
-
- {% if campaign.summary %}
- {{ campaign.summary }}
- {% endif %}
-
+
+ {% picture campaign.image_best_url alt="Image for "|add:campaign.name width=120 %}
+
+
+
+ {% if campaign.starts_at <= now and campaign.ends_at >= now %}
+ - Ends
+ -
+
+
+ {% elif campaign.starts_at > now %}
+ - Starts
+ -
+
+
+ {% else %}
+ - Ended
+ -
+
+
+ {% endif %}
+ {% if campaign.game %}
+ - Game
+ - {{ campaign.game.display_name }}
+ {% elif campaign.is_sitewide %}
+ - Type
+ -
+ Site-wide reward campaign
+
+ {% else %}
+ - Type
+ - Brand reward
+ {% endif %}
+ - Data source
+ -
+ {{ campaign.data_source }}
+
+
+ {% if campaign.summary %}
+ {{ campaign.summary }}
+ {% endif %}
+ {% if campaign.rewards.all %}
+
+ Rewards
+
+ {% for reward in campaign.rewards.all %}
+ -
+ {% if reward.thumbnail_image_url or reward.banner_image_url %}
+ {% picture reward.image_best_url alt=reward.name width=48 %}
+ {% endif %}
+ {{ reward.name }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
diff --git a/templates/twitch/reward_campaign_detail.html b/templates/twitch/reward_campaign_detail.html
index 59b9d17..17f5a3c 100644
--- a/templates/twitch/reward_campaign_detail.html
+++ b/templates/twitch/reward_campaign_detail.html
@@ -174,6 +174,47 @@
+ {% if reward_campaign.rewards.all %}
+ Rewards
+
+ {% endif %}
{% endblock content %}
diff --git a/templates/twitch/sitewide_rewards.html b/templates/twitch/sitewide_rewards.html
index 788bb39..f4ccc26 100644
--- a/templates/twitch/sitewide_rewards.html
+++ b/templates/twitch/sitewide_rewards.html
@@ -86,6 +86,7 @@
| Campaign |
Brand |
+ Rewards |
Ends |
@@ -106,6 +107,11 @@
{% endif %}
|
{{ campaign.brand|default:"-" }} |
+
+ {% for reward in campaign.rewards.all %}
+ {{ reward.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ |
|
{{ campaign.brand|default:"-" }} |
+
+ {% for reward in campaign.rewards.all %}
+ {{ reward.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ |
|
{{ campaign.brand|default:"-" }} |
+
+ {% for reward in campaign.rewards.all %}
+ {{ reward.name }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ |
|