Add RSS feed links in templates
This commit is contained in:
parent
da923f82da
commit
6a62eaa885
13 changed files with 349 additions and 39 deletions
|
|
@ -17,6 +17,19 @@
|
||||||
<a href="{% url 'twitch:organization_detail' owner.twitch_id %}">{{ owner.name }}</a>
|
<a href="{% url 'twitch:organization_detail' owner.twitch_id %}">{{ owner.name }}</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
{% if campaign.game %}
|
||||||
|
<a href="{% url 'twitch:game_campaign_feed' campaign.game.twitch_id %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for {{ campaign.game.display_name }} campaigns">RSS feed for {{ campaign.game.display_name }} campaigns</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if owner %}
|
||||||
|
<a href="{% url 'twitch:organization_campaign_feed' owner.twitch_id %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for {{ owner.name }} campaigns">RSS feed for {{ owner.name }} campaigns</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<!-- Campaign image -->
|
<!-- Campaign image -->
|
||||||
{% if campaign.image_best_url or campaign.image_url %}
|
{% if campaign.image_best_url or campaign.image_url %}
|
||||||
<img id="campaign-image"
|
<img id="campaign-image"
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@
|
||||||
<header>
|
<header>
|
||||||
<h1 id="page-title">Drop Campaigns</h1>
|
<h1 id="page-title">Drop Campaigns</h1>
|
||||||
<p>Browse all available drop campaigns</p>
|
<p>Browse all available drop campaigns</p>
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
<a href="{% url 'twitch:campaign_feed' %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for all campaigns">RSS feed for all campaigns</a>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<form id="filter-form"
|
<form id="filter-form"
|
||||||
method="get"
|
method="get"
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,12 @@
|
||||||
Drops are sorted alphabetically by organization and game. Click on a campaign or game title to see more details.
|
Drops are sorted alphabetically by organization and game. Click on a campaign or game title to see more details.
|
||||||
Hover over the end time to see the exact date and time.
|
Hover over the end time to see the exact date and time.
|
||||||
</pre>
|
</pre>
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
<a href="{% url 'twitch:campaign_feed' %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for all campaigns">RSS feed for campaigns</a>
|
||||||
|
</div>
|
||||||
{% if campaigns_by_org_game %}
|
{% if campaigns_by_org_game %}
|
||||||
{% for org_id, org_data in campaigns_by_org_game.items %}
|
{% for org_id, org_data in campaigns_by_org_game.items %}
|
||||||
<section id="org-section-{{ org_id }}">
|
<section id="org-section-{{ org_id }}">
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
<h1 id="page-title">RSS Feeds Documentation</h1>
|
<h1 id="page-title">RSS Feeds Documentation</h1>
|
||||||
<p>This page lists all available RSS feeds for TTVDrops.</p>
|
<p>This page lists all available RSS feeds for TTVDrops.</p>
|
||||||
<section>
|
<section>
|
||||||
<h2 id="available-feeds-header">Available RSS Feeds</h2>
|
<h2 id="available-feeds-header">Global RSS Feeds</h2>
|
||||||
|
<p>These feeds contain all items across the entire site:</p>
|
||||||
<ul id="feeds-list">
|
<ul id="feeds-list">
|
||||||
{% for feed in feeds %}
|
{% for feed in feeds %}
|
||||||
<li id="feed-{{ forloop.counter }}">
|
<li id="feed-{{ forloop.counter }}">
|
||||||
|
|
@ -21,5 +22,40 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
<section style="margin-top: 2rem;">
|
||||||
|
<h2 id="filtered-feeds-header">Filtered RSS Feeds</h2>
|
||||||
|
<p>
|
||||||
|
You can also subscribe to RSS feeds for specific games or organizations. These feeds are available on each game or organization detail page.
|
||||||
|
</p>
|
||||||
|
<h3>Game-Specific Campaign Feeds</h3>
|
||||||
|
<p>
|
||||||
|
Subscribe to campaigns for a specific game using: <code>/rss/games/<game_id>/campaigns/</code>
|
||||||
|
</p>
|
||||||
|
{% if sample_game %}
|
||||||
|
<p>
|
||||||
|
Example: <a href="{% url 'twitch:game_campaign_feed' sample_game.twitch_id %}">{{ sample_game.display_name }} Campaigns RSS Feed</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<h3>Organization-Specific Campaign Feeds</h3>
|
||||||
|
<p>
|
||||||
|
Subscribe to campaigns for a specific organization using: <code>/rss/organizations/<org_id>/campaigns/</code>
|
||||||
|
</p>
|
||||||
|
{% if sample_org %}
|
||||||
|
<p>
|
||||||
|
Example: <a href="{% url 'twitch:organization_campaign_feed' sample_org.twitch_id %}">{{ sample_org.name }} Campaigns RSS Feed</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
<section style="margin-top: 2rem;">
|
||||||
|
<h2 id="usage-header">How to Use RSS Feeds</h2>
|
||||||
|
<p>
|
||||||
|
RSS feeds allow you to stay updated with new content. You can use any RSS reader application to subscribe to these feeds.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Copy the feed URL</li>
|
||||||
|
<li>Paste it into your favorite RSS reader (Feedly, Inoreader, NetNewsWire, etc.)</li>
|
||||||
|
<li>Get automatic updates when new content is added</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,20 @@
|
||||||
{{ game.display_name }}
|
{{ game.display_name }}
|
||||||
{% if game.display_name != game.name and game.name %}<small>({{ game.name }})</small>{% endif %}
|
{% if game.display_name != game.name and game.name %}<small>({{ game.name }})</small>{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
<a href="{% url 'twitch:game_campaign_feed' game.twitch_id %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for {{ game.display_name }} campaigns">RSS feed for {{ game.display_name }} campaigns</a>
|
||||||
|
{% if owner %}
|
||||||
|
<a href="{% url 'twitch:organization_campaign_feed' owner.twitch_id %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for {{ owner.name }} campaigns">RSS feed for {{ owner.name }} campaigns</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{% url 'twitch:campaign_feed' %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for all campaigns">RSS feed for all campaigns</a>
|
||||||
|
</div>
|
||||||
<!-- Game image -->
|
<!-- Game image -->
|
||||||
{% if game.box_art %}
|
{% if game.box_art %}
|
||||||
<img id="game-image"
|
<img id="game-image"
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,12 @@
|
||||||
<p>
|
<p>
|
||||||
<a href="{% url 'twitch:game_list_simple' %}">List View</a>
|
<a href="{% url 'twitch:game_list_simple' %}">List View</a>
|
||||||
</p>
|
</p>
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
<a href="{% url 'twitch:game_feed' %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for all games">RSS feed for all games</a>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
{% if games_by_org %}
|
{% if games_by_org %}
|
||||||
<section>
|
<section>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@
|
||||||
<p>
|
<p>
|
||||||
<a href="{% url 'twitch:game_list' %}">Grid View</a>
|
<a href="{% url 'twitch:game_list' %}">Grid View</a>
|
||||||
</p>
|
</p>
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
<a href="{% url 'twitch:game_feed' %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for all games">RSS feed for all games</a>
|
||||||
|
</div>
|
||||||
{% if games_by_org %}
|
{% if games_by_org %}
|
||||||
{% for organization, games in games_by_org.items %}
|
{% for organization, games in games_by_org.items %}
|
||||||
<h2 id="org-{{ organization.twitch_id }}">{{ organization.name }}</h2>
|
<h2 id="org-{{ organization.twitch_id }}">{{ organization.name }}</h2>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,12 @@
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 id="page-title">Organizations</h1>
|
<h1 id="page-title">Organizations</h1>
|
||||||
|
<!-- RSS Feeds -->
|
||||||
|
<div style="margin-bottom: 1rem;">
|
||||||
|
<a href="{% url 'twitch:organization_feed' %}"
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
title="RSS feed for all organizations">RSS feed for organizations</a>
|
||||||
|
</div>
|
||||||
{% if orgs %}
|
{% if orgs %}
|
||||||
<ul id="org-list">
|
<ul id="org-list">
|
||||||
{% for organization in orgs %}
|
{% for organization in orgs %}
|
||||||
|
|
|
||||||
|
|
@ -4,36 +4,26 @@
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 id="org-name">{{ organization.name }}</h1>
|
<h1 id="org-name">{{ organization.name }}</h1>
|
||||||
{% if user.is_authenticated %}
|
<!-- RSS Feeds -->
|
||||||
<form id="notification-form"
|
<div style="margin-bottom: 1rem;">
|
||||||
method="post"
|
<a href="{% url 'twitch:organization_campaign_feed' organization.twitch_id %}"
|
||||||
action="{% url 'twitch:subscribe_org_notifications' org_id=organization.twitch_id %}">
|
style="margin-right: 1rem"
|
||||||
{% csrf_token %}
|
title="RSS feed for {{ organization.name }} campaigns">RSS feed for {{ organization.name }} campaigns</a>
|
||||||
<div>
|
</div>
|
||||||
<input type="checkbox"
|
<theader>
|
||||||
id="found"
|
<h2 id="games-header">Games by {{ organization.name }}</h2>
|
||||||
name="notify_found"
|
</theader>
|
||||||
{% if subscription and subscription.notify_found %}checked{% endif %} />
|
<table id="games-table">
|
||||||
<label for="found">🔔 Get notified as soon as a drop for {{ organization.name }} appears on Twitch.</label>
|
<tbody>
|
||||||
</div>
|
{% for game in games %}
|
||||||
<div>
|
<tr id="game-row-{{ game.twitch_id }}">
|
||||||
<input type="checkbox"
|
<td>
|
||||||
id="live"
|
<a href="{% url 'twitch:game_detail' game.twitch_id %}">{{ game }}</a>
|
||||||
name="notify_live"
|
</td>
|
||||||
{% if subscription and subscription.notify_live %}checked{% endif %} />
|
</tr>
|
||||||
<label for="live">🎮 Get notified when the drop is live and ready to be farmed.</label>
|
{% endfor %}
|
||||||
</div>
|
</tbody>
|
||||||
<button id="save-preferences-button" type="submit">Save preferences</button>
|
</table>
|
||||||
</form>
|
<hr />
|
||||||
{% else %}
|
|
||||||
<p id="login-prompt">Login to subscribe!</p>
|
|
||||||
{% endif %}
|
|
||||||
<ul id="games-list">
|
|
||||||
{% for game in games %}
|
|
||||||
<li id="game-{{ game.twitch_id }}">
|
|
||||||
<a href="{% url 'twitch:game_detail' game.twitch_id %}">{{ game }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{{ org_data|safe }}
|
{{ org_data|safe }}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
|
from django.http import HttpRequest
|
||||||
|
|
||||||
|
|
||||||
# MARK: /rss/organizations/
|
# MARK: /rss/organizations/
|
||||||
|
|
@ -239,3 +240,73 @@ class DropCampaignFeed(Feed):
|
||||||
def item_enclosure_mime_type(self, item: DropCampaign) -> str: # noqa: ARG002
|
def item_enclosure_mime_type(self, item: DropCampaign) -> str: # noqa: ARG002
|
||||||
"""Returns the MIME type of the enclosure."""
|
"""Returns the MIME type of the enclosure."""
|
||||||
return "image/jpeg"
|
return "image/jpeg"
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /rss/games/<twitch_id>/campaigns/
|
||||||
|
class GameCampaignFeed(DropCampaignFeed):
|
||||||
|
"""RSS feed for campaigns of a specific game."""
|
||||||
|
|
||||||
|
def get_object(self, request: HttpRequest, twitch_id: str) -> Game: # noqa: ARG002
|
||||||
|
"""Get the game object for this feed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The HTTP request.
|
||||||
|
twitch_id: The Twitch ID of the game.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Game: The game object.
|
||||||
|
"""
|
||||||
|
return Game.objects.get(twitch_id=twitch_id)
|
||||||
|
|
||||||
|
def title(self, obj: Game) -> str:
|
||||||
|
"""Return the feed title."""
|
||||||
|
return f"TTVDrops: {obj.display_name} Campaigns"
|
||||||
|
|
||||||
|
def link(self, obj: Game) -> str:
|
||||||
|
"""Return the link to the game detail."""
|
||||||
|
return reverse("twitch:game_detail", args=[obj.twitch_id])
|
||||||
|
|
||||||
|
def description(self, obj: Game) -> str:
|
||||||
|
"""Return the feed description."""
|
||||||
|
return f"Latest drop campaigns for {obj.display_name}"
|
||||||
|
|
||||||
|
def items(self, obj: Game) -> list[DropCampaign]:
|
||||||
|
"""Return the latest 100 campaigns for this game."""
|
||||||
|
return list(
|
||||||
|
DropCampaign.objects.filter(game=obj).select_related("game").order_by("-added_at")[:100],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /rss/organizations/<twitch_id>/campaigns/
|
||||||
|
class OrganizationCampaignFeed(DropCampaignFeed):
|
||||||
|
"""RSS feed for campaigns of a specific organization."""
|
||||||
|
|
||||||
|
def get_object(self, request: HttpRequest, twitch_id: str) -> Organization: # noqa: ARG002
|
||||||
|
"""Get the organization object for this feed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The HTTP request.
|
||||||
|
twitch_id: The Twitch ID of the organization.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Organization: The organization object.
|
||||||
|
"""
|
||||||
|
return Organization.objects.get(twitch_id=twitch_id)
|
||||||
|
|
||||||
|
def title(self, obj: Organization) -> str:
|
||||||
|
"""Return the feed title."""
|
||||||
|
return f"TTVDrops: {obj.name} Campaigns"
|
||||||
|
|
||||||
|
def link(self, obj: Organization) -> str:
|
||||||
|
"""Return the link to the organization detail."""
|
||||||
|
return reverse("twitch:organization_detail", args=[obj.twitch_id])
|
||||||
|
|
||||||
|
def description(self, obj: Organization) -> str:
|
||||||
|
"""Return the feed description."""
|
||||||
|
return f"Latest drop campaigns for {obj.name}"
|
||||||
|
|
||||||
|
def items(self, obj: Organization) -> list[DropCampaign]:
|
||||||
|
"""Return the latest 100 campaigns for this organization."""
|
||||||
|
return list(
|
||||||
|
DropCampaign.objects.filter(game__owner=obj).select_related("game").order_by("-added_at")[:100],
|
||||||
|
)
|
||||||
|
|
|
||||||
139
twitch/tests/test_feeds.py
Normal file
139
twitch/tests/test_feeds.py
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
"""Test RSS feeds."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from twitch.models import DropCampaign
|
||||||
|
from twitch.models import Game
|
||||||
|
from twitch.models import Organization
|
||||||
|
|
||||||
|
|
||||||
|
class RSSFeedTestCase(TestCase):
|
||||||
|
"""Test RSS feeds."""
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
"""Set up test fixtures."""
|
||||||
|
self.org = Organization.objects.create(
|
||||||
|
twitch_id="test-org-123",
|
||||||
|
name="Test Organization",
|
||||||
|
)
|
||||||
|
self.game = Game.objects.create(
|
||||||
|
twitch_id="test-game-123",
|
||||||
|
slug="test-game",
|
||||||
|
name="Test Game",
|
||||||
|
display_name="Test Game",
|
||||||
|
owner=self.org,
|
||||||
|
)
|
||||||
|
self.campaign = DropCampaign.objects.create(
|
||||||
|
twitch_id="test-campaign-123",
|
||||||
|
name="Test Campaign",
|
||||||
|
game=self.game,
|
||||||
|
start_at=timezone.now(),
|
||||||
|
end_at=timezone.now() + timedelta(days=7),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_organization_feed(self) -> None:
|
||||||
|
"""Test organization feed returns 200."""
|
||||||
|
url = reverse("twitch:organization_feed")
|
||||||
|
response = self.client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||||
|
|
||||||
|
def test_game_feed(self) -> None:
|
||||||
|
"""Test game feed returns 200."""
|
||||||
|
url = reverse("twitch:game_feed")
|
||||||
|
response = self.client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||||
|
|
||||||
|
def test_campaign_feed(self) -> None:
|
||||||
|
"""Test campaign feed returns 200."""
|
||||||
|
url = reverse("twitch:campaign_feed")
|
||||||
|
response = self.client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||||
|
|
||||||
|
def test_game_campaign_feed(self) -> None:
|
||||||
|
"""Test game-specific campaign feed returns 200."""
|
||||||
|
url = reverse("twitch:game_campaign_feed", args=[self.game.twitch_id])
|
||||||
|
response = self.client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||||
|
# Verify the game name is in the feed
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
assert "Test Game" in content
|
||||||
|
|
||||||
|
def test_organization_campaign_feed(self) -> None:
|
||||||
|
"""Test organization-specific campaign feed returns 200."""
|
||||||
|
url = reverse("twitch:organization_campaign_feed", args=[self.org.twitch_id])
|
||||||
|
response = self.client.get(url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||||
|
# Verify the organization name is in the feed
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
assert "Test Organization" in content
|
||||||
|
|
||||||
|
def test_game_campaign_feed_filters_correctly(self) -> None:
|
||||||
|
"""Test game campaign feed only shows campaigns for that game."""
|
||||||
|
# Create another game with a campaign
|
||||||
|
other_game = Game.objects.create(
|
||||||
|
twitch_id="other-game-123",
|
||||||
|
slug="other-game",
|
||||||
|
name="Other Game",
|
||||||
|
display_name="Other Game",
|
||||||
|
owner=self.org,
|
||||||
|
)
|
||||||
|
DropCampaign.objects.create(
|
||||||
|
twitch_id="other-campaign-123",
|
||||||
|
name="Other Campaign",
|
||||||
|
game=other_game,
|
||||||
|
start_at=timezone.now(),
|
||||||
|
end_at=timezone.now() + timedelta(days=7),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get feed for first game
|
||||||
|
url = reverse("twitch:game_campaign_feed", args=[self.game.twitch_id])
|
||||||
|
response = self.client.get(url)
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
|
||||||
|
# Should contain first campaign
|
||||||
|
assert "Test Campaign" in content
|
||||||
|
# Should NOT contain other campaign
|
||||||
|
assert "Other Campaign" not in content
|
||||||
|
|
||||||
|
def test_organization_campaign_feed_filters_correctly(self) -> None:
|
||||||
|
"""Test organization campaign feed only shows campaigns for that organization."""
|
||||||
|
# Create another organization with a game and campaign
|
||||||
|
other_org = Organization.objects.create(
|
||||||
|
twitch_id="other-org-123",
|
||||||
|
name="Other Organization",
|
||||||
|
)
|
||||||
|
other_game = Game.objects.create(
|
||||||
|
twitch_id="other-game-456",
|
||||||
|
slug="other-game-2",
|
||||||
|
name="Other Game 2",
|
||||||
|
display_name="Other Game 2",
|
||||||
|
owner=other_org,
|
||||||
|
)
|
||||||
|
DropCampaign.objects.create(
|
||||||
|
twitch_id="other-campaign-456",
|
||||||
|
name="Other Campaign 2",
|
||||||
|
game=other_game,
|
||||||
|
start_at=timezone.now(),
|
||||||
|
end_at=timezone.now() + timedelta(days=7),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get feed for first organization
|
||||||
|
url = reverse("twitch:organization_campaign_feed", args=[self.org.twitch_id])
|
||||||
|
response = self.client.get(url)
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
|
||||||
|
# Should contain first campaign
|
||||||
|
assert "Test Campaign" in content
|
||||||
|
# Should NOT contain other campaign
|
||||||
|
assert "Other Campaign 2" not in content
|
||||||
|
|
@ -6,7 +6,9 @@ from django.urls import path
|
||||||
|
|
||||||
from twitch import views
|
from twitch import views
|
||||||
from twitch.feeds import DropCampaignFeed
|
from twitch.feeds import DropCampaignFeed
|
||||||
|
from twitch.feeds import GameCampaignFeed
|
||||||
from twitch.feeds import GameFeed
|
from twitch.feeds import GameFeed
|
||||||
|
from twitch.feeds import OrganizationCampaignFeed
|
||||||
from twitch.feeds import OrganizationFeed
|
from twitch.feeds import OrganizationFeed
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
@ -28,7 +30,9 @@ urlpatterns: list[URLPattern] = [
|
||||||
path("channels/", views.ChannelListView.as_view(), name="channel_list"),
|
path("channels/", views.ChannelListView.as_view(), name="channel_list"),
|
||||||
path("channels/<str:twitch_id>/", views.ChannelDetailView.as_view(), name="channel_detail"),
|
path("channels/<str:twitch_id>/", views.ChannelDetailView.as_view(), name="channel_detail"),
|
||||||
path("rss/organizations/", OrganizationFeed(), name="organization_feed"),
|
path("rss/organizations/", OrganizationFeed(), name="organization_feed"),
|
||||||
|
path("rss/organizations/<str:twitch_id>/campaigns/", OrganizationCampaignFeed(), name="organization_campaign_feed"),
|
||||||
path("rss/games/", GameFeed(), name="game_feed"),
|
path("rss/games/", GameFeed(), name="game_feed"),
|
||||||
|
path("rss/games/<str:twitch_id>/campaigns/", GameCampaignFeed(), name="game_campaign_feed"),
|
||||||
path("rss/campaigns/", DropCampaignFeed(), name="campaign_feed"),
|
path("rss/campaigns/", DropCampaignFeed(), name="campaign_feed"),
|
||||||
path("docs/rss/", views.docs_rss_view, name="docs_rss"),
|
path("docs/rss/", views.docs_rss_view, name="docs_rss"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -792,22 +792,35 @@ def docs_rss_view(request: HttpRequest) -> HttpResponse:
|
||||||
"""
|
"""
|
||||||
feeds: list[dict[str, str]] = [
|
feeds: list[dict[str, str]] = [
|
||||||
{
|
{
|
||||||
"title": "Organizations",
|
"title": "All Organizations",
|
||||||
"description": "Latest organizations",
|
"description": "Latest organizations added to TTVDrops",
|
||||||
"url": "/rss/organizations/",
|
"url": "/rss/organizations/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Games",
|
"title": "All Games",
|
||||||
"description": "Latest games",
|
"description": "Latest games added to TTVDrops",
|
||||||
"url": "/rss/games/",
|
"url": "/rss/games/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Drop Campaigns",
|
"title": "All Drop Campaigns",
|
||||||
"description": "Latest drop campaigns",
|
"description": "Latest drop campaigns across all games",
|
||||||
"url": "/rss/campaigns/",
|
"url": "/rss/campaigns/",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
return render(request, "twitch/docs_rss.html", {"feeds": feeds})
|
|
||||||
|
# Get sample game and organization for examples
|
||||||
|
sample_game = Game.objects.first()
|
||||||
|
sample_org = Organization.objects.first()
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"twitch/docs_rss.html",
|
||||||
|
{
|
||||||
|
"feeds": feeds,
|
||||||
|
"sample_game": sample_game,
|
||||||
|
"sample_org": sample_org,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# MARK: /channels/
|
# MARK: /channels/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue