Remove /rss/organizations/<org_id>/campaigns/

This commit is contained in:
Joakim Hellsén 2026-03-09 05:56:57 +01:00
commit 6b936f4cf7
Signed by: Joakim Hellsén
SSH key fingerprint: SHA256:/9h/CsExpFp+PRhsfA0xznFx2CGfTT5R/kpuFfUgEQk
6 changed files with 17 additions and 302 deletions

View file

@ -306,9 +306,8 @@ def _construct_drops_summary(
class OrganizationRSSFeed(Feed):
"""RSS feed for latest organizations."""
# Spec: https://cyber.harvard.edu/rss/rss.html
feed_type = feedgenerator.Rss201rev2Feed
title: str = "TTVDrops Organizations"
title: str = "TTVDrops Twitch Organizations"
link: str = "/organizations/"
description: str = "Latest organizations on TTVDrops"
feed_copyright: str = "Information wants to be free."
@ -378,11 +377,11 @@ class OrganizationRSSFeed(Feed):
# MARK: /rss/games/
class GameFeed(Feed):
"""RSS feed for latest games."""
"""RSS feed for newly added games."""
title: str = "Games - TTVDrops"
link: str = "/games/"
description: str = "Latest games on TTVDrops"
description: str = "Newly added games on TTVDrops"
feed_copyright: str = "Information wants to be free."
_limit: int | None = None
@ -810,159 +809,6 @@ class GameCampaignFeed(Feed):
return "image/jpeg"
# MARK: /rss/organizations/<twitch_id>/campaigns/
class OrganizationCampaignFeed(Feed):
"""RSS feed for campaigns of a specific organization."""
_limit: int | None = None
def __call__(
self,
request: HttpRequest,
*args: object,
**kwargs: object,
) -> HttpResponse:
"""Override to capture limit parameter from request.
Args:
request (HttpRequest): The incoming HTTP request, potentially containing a 'limit' query parameter
*args: Additional positional arguments.
**kwargs: Additional keyword arguments.
Returns:
HttpResponse: The HTTP response generated by the parent Feed class after processing the request.
"""
if request.GET.get("limit"):
try:
self._limit = int(request.GET.get("limit", 200))
except ValueError, TypeError:
self._limit = None
return super().__call__(request, *args, **kwargs)
def get_object(self, request: HttpRequest, twitch_id: str) -> Organization: # noqa: ARG002
"""Retrieve the Organization instance for the given Twitch ID.
Returns:
Organization: The corresponding Organization object.
"""
return Organization.objects.get(twitch_id=twitch_id)
def item_link(self, item: DropCampaign) -> str:
"""Return the link to the campaign detail."""
return reverse("twitch:campaign_detail", args=[item.twitch_id])
def title(self, obj: Organization) -> str:
"""Return the feed title for the organization's campaigns."""
return f"TTVDrops: {obj.name} Campaigns"
def link(self, obj: Organization) -> str:
"""Return the absolute URL to the organization detail page."""
return reverse("twitch:organization_detail", args=[obj.twitch_id])
def description(self, obj: Organization) -> str:
"""Return a description for the feed."""
return f"Latest drop campaigns for organization {obj.name}"
def items(self, obj: Organization) -> list[DropCampaign]:
"""Return the latest drop campaigns for this organization, ordered by most recent start date (default 200, or limited by ?limit query param)."""
limit: int = self._limit if self._limit is not None else 200
queryset: QuerySet[DropCampaign] = DropCampaign.objects.filter(
game__owners=obj,
).order_by("-start_at")
return list(_with_campaign_related(queryset)[:limit])
def item_author_name(self, item: DropCampaign) -> str:
"""Return the author name for the campaign, typically the game name."""
return item.get_feed_author_name()
def item_guid(self, item: DropCampaign) -> str:
"""Return a unique identifier for each campaign."""
return item.get_feed_guid()
def item_enclosure_url(self, item: DropCampaign) -> str:
"""Returns the URL of the campaign image for enclosure."""
return item.get_feed_enclosure_url()
def item_enclosure_length(self, item: DropCampaign) -> int: # noqa: ARG002
"""Returns the length of the enclosure."""
# TODO(TheLovinator): Track image size for proper length # noqa: TD003
return 0
def item_enclosure_mime_type(self, item: DropCampaign) -> str: # noqa: ARG002
"""Returns the MIME type of the enclosure."""
# TODO(TheLovinator): Determine actual MIME type if needed # noqa: TD003
return "image/jpeg"
def item_categories(self, item: DropCampaign) -> tuple[str, ...]:
"""Returns the associated game's name as a category."""
return item.get_feed_categories()
def item_updateddate(self, item: DropCampaign) -> datetime.datetime:
"""Returns the campaign's last update time."""
return item.updated_at
def item_pubdate(self, item: DropCampaign) -> datetime.datetime:
"""Returns the publication date to the feed item.
Uses start_at (when the drop starts). Fallback to added_at or now if missing.
"""
if item.start_at:
return item.start_at
if item.added_at:
return item.added_at
return timezone.now()
def item_description(self, item: DropCampaign) -> SafeText:
"""Return a description of the campaign."""
drops_data: list[dict] = []
channels: list[Channel] | None = getattr(item, "channels_ordered", None)
channel_name: str | None = channels[0].name if channels else None
drops: QuerySet[TimeBasedDrop] | None = getattr(item, "time_based_drops", None)
if drops:
drops_data = _build_drops_data(drops.all())
parts: list[SafeText] = []
image_url: str | None = getattr(item, "image_url", None)
if image_url:
item_name: str = getattr(item, "name", str(object=item))
parts.append(
format_html(
'<img src="{}" alt="{}" width="160" height="160" />',
image_url,
item_name,
),
)
desc_text: str | None = getattr(item, "description", None)
if desc_text:
parts.append(format_html("<p>{}</p>", desc_text))
# Insert start and end date info
insert_date_info(item, parts)
if drops_data:
parts.append(
format_html(
"<p>{}</p>",
_construct_drops_summary(drops_data, channel_name=channel_name),
),
)
# Only show channels if drop is not subscription only
if not getattr(item, "is_subscription_only", False) and channels is not None:
game: Game | None = getattr(item, "game", None)
parts.append(_build_channels_html(channels, game=game))
details_url: str | None = getattr(item, "details_url", None)
if details_url:
parts.append(format_html('<a href="{}">About</a>', details_url))
return SafeText("".join(str(p) for p in parts))
# MARK: /rss/reward-campaigns/
class RewardCampaignFeed(Feed):
"""RSS feed for latest reward campaigns (Quest rewards)."""