diff --git a/chzzk/tests/test_views.py b/chzzk/tests/test_views.py index 4e036f9..38c1284 100644 --- a/chzzk/tests/test_views.py +++ b/chzzk/tests/test_views.py @@ -2,6 +2,7 @@ from datetime import timedelta from typing import TYPE_CHECKING from django.test import TestCase +from django.test.client import _MonkeyPatchedWSGIResponse from django.urls import reverse from django.utils import timezone @@ -60,3 +61,46 @@ class ChzzkDashboardViewTests(TestCase): assert included in campaigns assert all(c.state != "TESTING" for c in campaigns) + + def test_campaign_detail_view_renders_chzzk_campaign_and_rewards(self) -> None: + """Test that the campaign detail view correctly renders the details of a chzzk campaign and its rewards.""" + now: datetime = timezone.now() + + campaign: ChzzkCampaign = ChzzkCampaign.objects.create( + campaign_no=2001, + title="Campaign Detail Test", + description="Detailed campaign description", + category_type="game", + category_id="1", + category_value="TestGame", + service_id="chzzk", + state="ACTIVE", + start_date=now - timedelta(days=1), + end_date=now + timedelta(days=1), + has_ios_based_reward=False, + drops_campaign_not_started=False, + source_api="unit-test", + ) + + campaign.rewards.create( # pyright: ignore[reportAttributeAccessIssue] + reward_no=10, + title="Reward A", + reward_type="ITEM", + campaign_reward_type="Standard", + condition_type="watch", + condition_for_minutes=15, + ios_based_reward=False, + code_remaining_count=100, + ) + + response: _MonkeyPatchedWSGIResponse = self.client.get( + reverse("chzzk:campaign_detail", args=[campaign.campaign_no]), + ) + assert response.status_code == 200 + + content: str = response.content.decode() + assert campaign.title in content + assert "Reward A" in content + assert "watch" in content + assert "100" in content + assert "No" in content # ios_based_reward=False diff --git a/chzzk/views.py b/chzzk/views.py index 7687c43..3cb332b 100644 --- a/chzzk/views.py +++ b/chzzk/views.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING from django.db.models.query import QuerySet +from django.shortcuts import get_object_or_404 from django.shortcuts import render from django.urls import reverse from django.utils import timezone @@ -62,7 +63,8 @@ def campaign_detail_view(request: HttpRequest, campaign_no: int) -> HttpResponse Returns: HttpResponse: The HTTP response containing the rendered campaign detail page. """ - campaign: models.ChzzkCampaign = models.ChzzkCampaign.objects.get( + campaign: models.ChzzkCampaign = get_object_or_404( + models.ChzzkCampaign, campaign_no=campaign_no, ) rewards: QuerySet[models.ChzzkReward, models.ChzzkReward] = campaign.rewards.all() # pyright: ignore[reportAttributeAccessIssue] diff --git a/templates/chzzk/campaign_detail.html b/templates/chzzk/campaign_detail.html index 7a38c83..51a36d5 100644 --- a/templates/chzzk/campaign_detail.html +++ b/templates/chzzk/campaign_detail.html @@ -1,52 +1,161 @@ {% extends "base.html" %} +{% load static %} +{% load image_tags %} {% block title %} {{ campaign.title }} {% endblock title %} +{% block extra_head %} + + + +{% endblock extra_head %} {% block content %} -
-

{{ campaign.title }}

- - {% if campaign.image_url %} - {{ campaign.title }} - {% endif %} - {% if campaign.description %} -
- {{ campaign.description|linebreaksbr }} -
- {% endif %} -
- {% if campaign.starts_at %} -
- Starts: -
+
+ +
+ {% if campaign.image_url %} + {{ campaign.title }} {% endif %} - {% if campaign.ends_at %} -
- Ends: -
- {% endif %} -
-
-

Rewards

- {% if rewards %} - - {% else %} -

No rewards available.

- {% endif %} - {% if campaign.external_url %} -

- View on chzzk -

- {% endif %} -
+ + +
+

{{ campaign.title }}

+ +
+ chzzk > Campaigns > {{ campaign.title }} +
+ +

{{ campaign.description|linebreaksbr }}

+
+ Published + {% if campaign.scraped_at %} + ({{ campaign.scraped_at|timesince }} ago) + {% elif campaign.start_date %} + ({{ campaign.start_date|timesince }} ago) + {% else %} + unknown + {% endif %} +
+
+ Last updated + {% if campaign.scraped_at %} + ({{ campaign.scraped_at|timesince }} ago) + {% elif campaign.updated_at %} + ({{ campaign.updated_at|timesince }} ago) + {% else %} + unknown + {% endif %} +
+ +
+ {% if campaign.end_date %} + {% if campaign.end_date < now %} + Ended + ({{ campaign.end_date|timesince }} ago) + {% else %} + Ends in + (in {{ campaign.end_date|timeuntil }}) + {% endif %} + {% else %} + Ends unknown + {% endif %} +
+ +
+ {% if campaign.start_date %} + {% if campaign.start_date > now %} + Starts in + (in {{ campaign.start_date|timeuntil }}) + {% else %} + Started + ({{ campaign.start_date|timesince }} ago) + {% endif %} + {% else %} + Starts unknown + {% endif %} +
+ +
+ Duration is + {% if campaign.start_date and campaign.end_date %} + + {% else %} + unknown + {% endif %} +
+ +
+ {% if campaign.pc_link_url %}[details]{% endif %} + {% if campaign.account_link_url %}[connect]{% endif %} +
+
+ +
Campaign Info
+ {% if rewards %} + + + + + + + + + + + + + {% for reward in rewards %} + + + + + + + {% if reward.reward_type == "CODE_FIRST_COME" %} + + {% else %} + + {% endif %} + + {% endfor %} + +
ImageRewardTypeConditioniOS RewardCodes Left
+ {% if reward.image_url %} + {{ reward.title }} + {% endif %} + + {{ reward.title }} + {% if reward.condition_for_minutes %} +
{{ reward.condition_for_minutes }} minutes watched
+ {% endif %} +
{{ reward.reward_type }}{{ reward.condition_type }}{{ reward.ios_based_reward|yesno:"Yes,No" }}{{ reward.code_remaining_count }}Unlimited
+ {% else %} +

No rewards available for this campaign.

+ {% endif %} {% endblock content %}