str:
- """Build the base URL for the application.
-
- Returns:
- str: The base URL as configured in settings.BASE_URL.
- """
- return settings.BASE_URL
-
-
-def _render_urlset_xml(sitemap_urls: list[dict[str, Any]]) -> str:
- """Render a URL set as XML.
-
- Args:
- sitemap_urls: List of sitemap URL entry dictionaries.
-
- Returns:
- str: Serialized XML for a containing the provided URLs.
- """
- urlset = Element("urlset")
- urlset.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")
-
- for url_entry in sitemap_urls:
- url = SubElement(urlset, "url")
- loc = url_entry.get("loc")
- if loc:
- child = SubElement(url, "loc")
- child.text = loc
-
- return tostring(urlset, encoding="unicode")
diff --git a/core/views.py b/core/views.py
index 464ded6..4c3000c 100644
--- a/core/views.py
+++ b/core/views.py
@@ -15,15 +15,14 @@ from django.db.models import Max
from django.db.models import OuterRef
from django.db.models import Prefetch
from django.db.models import Q
-from django.db.models import QuerySet
from django.db.models.functions import Trim
+from django.db.models.query import QuerySet
from django.http import FileResponse
from django.http import Http404
-from django.http import HttpRequest
from django.http import HttpResponse
from django.shortcuts import render
-from django.shortcuts import reverse
from django.template.defaultfilters import filesizeformat
+from django.urls import reverse
from django.utils import timezone
from kick.models import KickChannel
@@ -89,9 +88,6 @@ def _build_seo_context( # noqa: PLR0913, PLR0917
Returns:
Dict with SEO context variables to pass to render().
"""
- if page_url and not page_url.startswith("http"):
- page_url = f"{settings.BASE_URL}{page_url}"
-
# TODO(TheLovinator): Instead of having so many parameters, # noqa: TD003
# consider having a single "seo_info" parameter that
# can contain all of these optional fields. This would make
@@ -140,13 +136,11 @@ def _render_urlset_xml(
xml += '\n'
for url_entry in url_entries:
xml += " \n"
- loc = url_entry.get("loc") or url_entry.get("url") # Handle both keys
- if loc:
- xml += f" {loc}\n"
- if "lastmod" in url_entry:
+ xml += f" {url_entry['url']}\n"
+ if url_entry.get("lastmod"):
xml += f" {url_entry['lastmod']}\n"
xml += " \n"
- xml += "\n"
+ xml += ""
return xml
@@ -171,9 +165,9 @@ def _render_sitemap_index_xml(sitemap_entries: list[dict[str, str]]) -> str:
return xml
-def _build_base_url() -> str:
- """Return the base URL for the site using settings.BASE_URL."""
- return getattr(settings, "BASE_URL", "https://ttvdrops.lovinator.space")
+def _build_base_url(request: HttpRequest) -> str:
+ """Return base url including scheme and host."""
+ return f"{request.scheme}://{request.get_host()}"
# MARK: /sitemap.xml
@@ -186,7 +180,7 @@ def sitemap_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap index XML.
"""
- base_url: str = _build_base_url()
+ base_url: str = _build_base_url(request)
# Compute last modified per-section so search engines can more intelligently crawl.
# Do not fabricate a lastmod date if the section has no data.
@@ -255,63 +249,66 @@ def sitemap_static_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap XML.
"""
- # `request` is unused but required by Django's view signature.
- base_url: str = _build_base_url().rstrip("/")
- sitemap_urls: list[dict[str, str]] = [
- {"loc": f"{base_url}{reverse('core:dashboard')}"},
- {"loc": f"{base_url}{reverse('core:search')}"},
- {"loc": f"{base_url}{reverse('core:debug')}"},
- {"loc": f"{base_url}{reverse('core:dataset_backups')}"},
- {"loc": f"{base_url}{reverse('core:docs_rss')}"},
- # Core RSS/Atom/Discord feeds
- {"loc": f"{base_url}{reverse('core:campaign_feed')}"},
- {"loc": f"{base_url}{reverse('core:game_feed')}"},
- {"loc": f"{base_url}{reverse('core:organization_feed')}"},
- {"loc": f"{base_url}{reverse('core:reward_campaign_feed')}"},
- {"loc": f"{base_url}{reverse('core:campaign_feed_atom')}"},
- {"loc": f"{base_url}{reverse('core:game_feed_atom')}"},
- {"loc": f"{base_url}{reverse('core:organization_feed_atom')}"},
- {"loc": f"{base_url}{reverse('core:reward_campaign_feed_atom')}"},
- {"loc": f"{base_url}{reverse('core:campaign_feed_discord')}"},
- {"loc": f"{base_url}{reverse('core:game_feed_discord')}"},
- {"loc": f"{base_url}{reverse('core:organization_feed_discord')}"},
- {"loc": f"{base_url}{reverse('core:reward_campaign_feed_discord')}"},
- # Twitch app pages
- {"loc": f"{base_url}{reverse('twitch:dashboard')}"},
- {"loc": f"{base_url}{reverse('twitch:campaign_list')}"},
- {"loc": f"{base_url}{reverse('twitch:games_grid')}"},
- {"loc": f"{base_url}{reverse('twitch:games_list')}"},
- {"loc": f"{base_url}{reverse('twitch:channel_list')}"},
- {"loc": f"{base_url}{reverse('twitch:badge_list')}"},
- {"loc": f"{base_url}{reverse('twitch:emote_gallery')}"},
- {"loc": f"{base_url}{reverse('twitch:org_list')}"},
- {"loc": f"{base_url}{reverse('twitch:reward_campaign_list')}"},
- {"loc": f"{base_url}{reverse('twitch:export_campaigns_csv')}"},
- {"loc": f"{base_url}{reverse('twitch:export_games_csv')}"},
- {"loc": f"{base_url}{reverse('twitch:export_organizations_csv')}"},
- {"loc": f"{base_url}{reverse('twitch:export_campaigns_json')}"},
- {"loc": f"{base_url}{reverse('twitch:export_games_json')}"},
- {"loc": f"{base_url}{reverse('twitch:export_organizations_json')}"},
- # Kick app pages and feeds
- {"loc": f"{base_url}{reverse('kick:dashboard')}"},
- {"loc": f"{base_url}{reverse('kick:campaign_list')}"},
- {"loc": f"{base_url}{reverse('kick:game_list')}"},
- {"loc": f"{base_url}{reverse('kick:organization_list')}"},
- {"loc": f"{base_url}{reverse('kick:campaign_feed')}"},
- {"loc": f"{base_url}{reverse('kick:game_feed')}"},
- {"loc": f"{base_url}{reverse('kick:organization_feed')}"},
- {"loc": f"{base_url}{reverse('kick:campaign_feed_atom')}"},
- {"loc": f"{base_url}{reverse('kick:game_feed_atom')}"},
- {"loc": f"{base_url}{reverse('kick:organization_feed_atom')}"},
- {"loc": f"{base_url}{reverse('kick:campaign_feed_discord')}"},
- {"loc": f"{base_url}{reverse('kick:game_feed_discord')}"},
- {"loc": f"{base_url}{reverse('kick:organization_feed_discord')}"},
+ base_url: str = _build_base_url(request)
+
+ # Include the canonical top-level pages, the main app dashboards, and key list views.
+ # Using reverse() keeps these URLs correct if route patterns change.
+ static_route_names: list[str] = [
+ "core:dashboard",
+ # "core:search",
+ "core:dataset_backups",
+ "core:docs_rss",
+ # Core RSS/Atom feeds
+ # "core:campaign_feed",
+ # "core:game_feed",
+ # "core:organization_feed",
+ # "core:reward_campaign_feed",
+ # "core:campaign_feed_atom",
+ # "core:game_feed_atom",
+ # "core:organization_feed_atom",
+ # "core:reward_campaign_feed_atom",
+ # "core:campaign_feed_discord",
+ # "core:game_feed_discord",
+ # "core:organization_feed_discord",
+ # "core:reward_campaign_feed_discord",
+ # Twitch pages
+ "twitch:dashboard",
+ "twitch:badge_list",
+ "twitch:campaign_list",
+ "twitch:channel_list",
+ "twitch:emote_gallery",
+ "twitch:games_grid",
+ "twitch:games_list",
+ "twitch:org_list",
+ "twitch:reward_campaign_list",
+ # Kick pages
+ "kick:dashboard",
+ "kick:campaign_list",
+ "kick:game_list",
+ "kick:category_list",
+ "kick:organization_list",
+ # Kick RSS/Atom feeds
+ # "kick:campaign_feed",
+ # "kick:game_feed",
+ # "kick:category_feed",
+ # "kick:organization_feed",
+ # "kick:campaign_feed_atom",
+ # "kick:game_feed_atom",
+ # "kick:category_feed_atom",
+ # "kick:organization_feed_atom",
+ # "kick:campaign_feed_discord",
+ # "kick:game_feed_discord",
+ # "kick:category_feed_discord",
+ # "kick:organization_feed_discord",
# YouTube
- {"loc": f"{base_url}{reverse('youtube:index')}"},
- # Misc/static
- {"loc": f"{base_url}/about/"},
- {"loc": f"{base_url}/robots.txt"},
+ "youtube:index",
]
+
+ sitemap_urls: list[dict[str, str]] = []
+ for route_name in static_route_names:
+ url = reverse(route_name)
+ sitemap_urls.append({"url": f"{base_url}{url}"})
+
xml_content: str = _render_urlset_xml(sitemap_urls)
return HttpResponse(xml_content, content_type="application/xml")
@@ -326,15 +323,14 @@ def sitemap_twitch_channels_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap XML.
"""
- # `request` is unused but required by Django's view signature.
- base_url: str = _build_base_url()
+ base_url: str = _build_base_url(request)
sitemap_urls: list[dict[str, str]] = []
channels: QuerySet[Channel] = Channel.objects.all()
for channel in channels:
resource_url: str = reverse("twitch:channel_detail", args=[channel.twitch_id])
full_url: str = f"{base_url}{resource_url}"
- entry: dict[str, str] = {"loc": full_url}
+ entry: dict[str, str] = {"url": full_url}
if channel.updated_at:
entry["lastmod"] = channel.updated_at.isoformat()
sitemap_urls.append(entry)
@@ -353,8 +349,7 @@ def sitemap_twitch_drops_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap XML.
"""
- # `request` is unused but required by Django's view signature.
- base_url: str = _build_base_url()
+ base_url: str = _build_base_url(request)
sitemap_urls: list[dict[str, str]] = []
campaigns: QuerySet[DropCampaign] = DropCampaign.objects.filter(
@@ -363,7 +358,7 @@ def sitemap_twitch_drops_view(request: HttpRequest) -> HttpResponse:
for campaign in campaigns:
resource_url: str = reverse("twitch:campaign_detail", args=[campaign.twitch_id])
full_url: str = f"{base_url}{resource_url}"
- campaign_url_entry: dict[str, str] = {"loc": full_url}
+ campaign_url_entry: dict[str, str] = {"url": full_url}
if campaign.updated_at:
campaign_url_entry["lastmod"] = campaign.updated_at.isoformat()
sitemap_urls.append(campaign_url_entry)
@@ -376,7 +371,7 @@ def sitemap_twitch_drops_view(request: HttpRequest) -> HttpResponse:
)
full_url: str = f"{base_url}{resource_url}"
- reward_campaign_url_entry: dict[str, str] = {"loc": full_url}
+ reward_campaign_url_entry: dict[str, str] = {"url": full_url}
if reward_campaign.updated_at:
reward_campaign_url_entry["lastmod"] = (
reward_campaign.updated_at.isoformat()
@@ -398,15 +393,14 @@ def sitemap_twitch_others_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap XML.
"""
- # `request` is unused but required by Django's view signature.
- base_url: str = _build_base_url()
+ base_url: str = _build_base_url(request)
sitemap_urls: list[dict[str, str]] = []
games: QuerySet[Game] = Game.objects.all()
for game in games:
resource_url: str = reverse("twitch:game_detail", args=[game.twitch_id])
full_url: str = f"{base_url}{resource_url}"
- entry: dict[str, str] = {"loc": full_url}
+ entry: dict[str, str] = {"url": full_url}
if game.updated_at:
entry["lastmod"] = game.updated_at.isoformat()
@@ -417,7 +411,7 @@ def sitemap_twitch_others_view(request: HttpRequest) -> HttpResponse:
for org in orgs:
resource_url: str = reverse("twitch:organization_detail", args=[org.twitch_id])
full_url: str = f"{base_url}{resource_url}"
- entry: dict[str, str] = {"loc": full_url}
+ entry: dict[str, str] = {"url": full_url}
if org.updated_at:
entry["lastmod"] = org.updated_at.isoformat()
@@ -428,10 +422,10 @@ def sitemap_twitch_others_view(request: HttpRequest) -> HttpResponse:
for badge_set in badge_sets:
resource_url = reverse("twitch:badge_set_detail", args=[badge_set.set_id])
full_url = f"{base_url}{resource_url}"
- sitemap_urls.append({"loc": full_url})
+ sitemap_urls.append({"url": full_url})
# Emotes currently don't have individual detail pages, but keep a listing here.
- sitemap_urls.append({"loc": f"{base_url}/emotes/"})
+ sitemap_urls.append({"url": f"{base_url}/emotes/"})
xml_content: str = _render_urlset_xml(sitemap_urls)
return HttpResponse(xml_content, content_type="application/xml")
@@ -447,8 +441,7 @@ def sitemap_kick_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap XML.
"""
- # `request` is unused but required by Django's view signature.
- base_url: str = _build_base_url()
+ base_url: str = _build_base_url(request)
sitemap_urls: list[dict[str, str]] = []
kick_campaigns: QuerySet[KickDropCampaign] = KickDropCampaign.objects.filter(
@@ -457,11 +450,19 @@ def sitemap_kick_view(request: HttpRequest) -> HttpResponse:
for campaign in kick_campaigns:
resource_url: str = reverse("kick:campaign_detail", args=[campaign.kick_id])
full_url: str = f"{base_url}{resource_url}"
- entry: dict[str, str] = {"loc": full_url}
+ entry: dict[str, str] = {"url": full_url}
+
if campaign.updated_at:
entry["lastmod"] = campaign.updated_at.isoformat()
+
sitemap_urls.append(entry)
+ # Include Kick organizations and game list pages
+ sitemap_urls.extend((
+ {"url": f"{base_url}/kick/organizations/"},
+ {"url": f"{base_url}/kick/games/"},
+ ))
+
xml_content: str = _render_urlset_xml(sitemap_urls)
return HttpResponse(xml_content, content_type="application/xml")
@@ -476,10 +477,10 @@ def sitemap_youtube_view(request: HttpRequest) -> HttpResponse:
Returns:
HttpResponse: The rendered sitemap XML.
"""
- # `request` is unused but required by Django's view signature.
- base_url: str = _build_base_url()
+ base_url: str = _build_base_url(request)
+
sitemap_urls: list[dict[str, str]] = [
- {"loc": f"{base_url}{reverse('youtube:index')}"},
+ {"url": f"{base_url}{reverse('youtube:index')}"},
]
xml_content: str = _render_urlset_xml(sitemap_urls)
@@ -774,7 +775,7 @@ def dataset_backups_view(request: HttpRequest) -> HttpResponse:
def dataset_backup_download_view(
- request: HttpRequest,
+ request: HttpRequest, # noqa: ARG001
relative_path: str,
) -> FileResponse:
"""Download a dataset backup from the data directory.
diff --git a/pyproject.toml b/pyproject.toml
index 28e688f..8a42e43 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -49,7 +49,7 @@ dev = [
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "config.settings"
python_files = ["test_*.py", "*_test.py"]
-addopts = ""
+addopts = "-n 4"
filterwarnings = [
"ignore:Parsing dates involving a day of month without a year specified is ambiguous:DeprecationWarning",
]
@@ -87,7 +87,6 @@ lint.ignore = [
"PLR0912", # Checks for functions or methods with too many branches, including (nested) if, elif, and else branches, for loops, try-except clauses, and match and case statements.
"PLR6301", # Checks for the presence of unused self parameter in methods definitions.
"RUF012", # Checks for mutable default values in class attributes.
- "ARG001", # Checks for the presence of unused arguments in function definitions.
# Conflicting lint rules when using Ruff's formatter
# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
diff --git a/templates/core/dashboard.html b/templates/core/dashboard.html
index b634498..44155b8 100644
--- a/templates/core/dashboard.html
+++ b/templates/core/dashboard.html
@@ -140,18 +140,6 @@
... and {{ campaign_data.allowed_channels|length|add:"-5" }} more
{% endif %}
- {% else %}
- {% if campaign_data.campaign.game.twitch_directory_url %}
-
-
- Go to a participating live channel
-
-
- {% else %}
- Failed to get Twitch directory URL :(
- {% endif %}
{% endif %}
diff --git a/twitch/models.py b/twitch/models.py
index 1ed2a57..6e85870 100644
--- a/twitch/models.py
+++ b/twitch/models.py
@@ -2,7 +2,6 @@ import logging
from typing import TYPE_CHECKING
import auto_prefetch
-from django.conf import settings
from django.contrib.postgres.indexes import GinIndex
from django.db import models
from django.urls import reverse
@@ -65,7 +64,7 @@ class Organization(auto_prefetch.Model):
def feed_description(self: Organization) -> str:
"""Return a description of the organization for RSS feeds."""
name: str = self.name or "Unknown Organization"
- url: str = f"{settings.BASE_URL}{reverse('twitch:organization_detail', args=[self.twitch_id])}"
+ url: str = reverse("twitch:organization_detail", args=[self.twitch_id])
return format_html(
'New Twitch organization added to TTVDrops:
\n{}
',
diff --git a/twitch/tests/test_feeds.py b/twitch/tests/test_feeds.py
index b69e9cb..cb1fdec 100644
--- a/twitch/tests/test_feeds.py
+++ b/twitch/tests/test_feeds.py
@@ -177,12 +177,11 @@ class RSSFeedTestCase(TestCase):
assert 'rel="self"' in content, msg
msg: str = f"Expected self link to point to campaign feed URL, got: {content}"
- assert 'href="https://ttvdrops.lovinator.space/atom/campaigns/"' in content, msg
+ assert 'href="http://testserver/atom/campaigns/"' in content, msg
msg: str = f"Expected entry ID to be the campaign URL, got: {content}"
assert (
- "https://ttvdrops.lovinator.space/twitch/campaigns/test-campaign-123/"
- in content
+ "http://testserver/twitch/campaigns/test-campaign-123/" in content
), msg
def test_all_atom_feeds_use_url_ids_and_correct_self_links(self) -> None:
@@ -191,27 +190,27 @@ class RSSFeedTestCase(TestCase):
(
"core:campaign_feed_atom",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
+ f"http://testserver{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
),
(
"core:game_feed_atom",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:game_detail', args=[self.game.twitch_id])}",
+ f"http://testserver{reverse('twitch:game_detail', args=[self.game.twitch_id])}",
),
(
"core:game_campaign_feed_atom",
{"twitch_id": self.game.twitch_id},
- f"https://ttvdrops.lovinator.space{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
+ f"http://testserver{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
),
(
"core:organization_feed_atom",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:organization_detail', args=[self.org.twitch_id])}",
+ f"http://testserver{reverse('twitch:organization_detail', args=[self.org.twitch_id])}",
),
(
"core:reward_campaign_feed_atom",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:reward_campaign_detail', args=[self.reward_campaign.twitch_id])}",
+ f"http://testserver{reverse('twitch:reward_campaign_detail', args=[self.reward_campaign.twitch_id])}",
),
]
@@ -222,7 +221,7 @@ class RSSFeedTestCase(TestCase):
assert response.status_code == 200
content: str = response.content.decode("utf-8")
- expected_self_link: str = f'href="https://ttvdrops.lovinator.space{url}"'
+ expected_self_link: str = f'href="http://testserver{url}"'
msg: str = f"Expected self link in Atom feed {url_name}, got: {content}"
assert 'rel="self"' in content, msg
@@ -318,7 +317,7 @@ class RSSFeedTestCase(TestCase):
msg: str = (
f"Expected absolute media enclosure URLs for {url}, got: {content}"
)
- assert "https://ttvdrops.lovinator.space/media/" in content, msg
+ assert "http://testserver/media/" in content, msg
assert 'url="/media/' not in content, msg
assert 'href="/media/' not in content, msg
@@ -1322,27 +1321,27 @@ class DiscordFeedTestCase(TestCase):
(
"core:campaign_feed_discord",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
+ f"http://testserver{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
),
(
"core:game_feed_discord",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:game_detail', args=[self.game.twitch_id])}",
+ f"http://testserver{reverse('twitch:game_detail', args=[self.game.twitch_id])}",
),
(
"core:game_campaign_feed_discord",
{"twitch_id": self.game.twitch_id},
- f"https://ttvdrops.lovinator.space{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
+ f"http://testserver{reverse('twitch:campaign_detail', args=[self.campaign.twitch_id])}",
),
(
"core:organization_feed_discord",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:organization_detail', args=[self.org.twitch_id])}",
+ f"http://testserver{reverse('twitch:organization_detail', args=[self.org.twitch_id])}",
),
(
"core:reward_campaign_feed_discord",
{},
- f"https://ttvdrops.lovinator.space{reverse('twitch:reward_campaign_detail', args=[self.reward_campaign.twitch_id])}",
+ f"http://testserver{reverse('twitch:reward_campaign_detail', args=[self.reward_campaign.twitch_id])}",
),
]
@@ -1353,7 +1352,7 @@ class DiscordFeedTestCase(TestCase):
assert response.status_code == 200
content: str = response.content.decode("utf-8")
- expected_self_link: str = f'href="https://ttvdrops.lovinator.space{url}"'
+ expected_self_link: str = f'href="http://testserver{url}"'
msg: str = f"Expected self link in Discord feed {url_name}, got: {content}"
assert 'rel="self"' in content, msg
diff --git a/twitch/tests/test_views.py b/twitch/tests/test_views.py
index 03f67d6..6186662 100644
--- a/twitch/tests/test_views.py
+++ b/twitch/tests/test_views.py
@@ -41,12 +41,6 @@ if TYPE_CHECKING:
from twitch.views import Page
-@pytest.fixture(autouse=True)
-def apply_base_url_override(settings: object) -> None:
- """Ensure BASE_URL is globally overridden for all tests."""
- settings.BASE_URL = "https://ttvdrops.lovinator.space" # pyright: ignore[reportAttributeAccessIssue]
-
-
@pytest.mark.django_db
class TestSearchView:
"""Tests for the search_view function."""
@@ -1568,14 +1562,14 @@ class TestSitemapView:
# Check for the homepage and a few key list views across apps.
assert (
- "https://ttvdrops.lovinator.space/" in content
+ "http://testserver/" in content
or "http://localhost:8000/" in content
)
- assert "https://ttvdrops.lovinator.space/twitch/" in content
- assert "https://ttvdrops.lovinator.space/kick/" in content
- assert "https://ttvdrops.lovinator.space/youtube/" in content
- assert "https://ttvdrops.lovinator.space/twitch/campaigns/" in content
- assert "https://ttvdrops.lovinator.space/twitch/games/" in content
+ assert "http://testserver/twitch/" in content
+ assert "http://testserver/kick/" in content
+ assert "http://testserver/youtube/" in content
+ assert "http://testserver/twitch/campaigns/" in content
+ assert "http://testserver/twitch/games/" in content
def test_sitemap_contains_game_detail_pages(
self,
@@ -1611,13 +1605,13 @@ class TestSitemapView:
response: _MonkeyPatchedWSGIResponse = client.get("/sitemap-twitch-drops.xml")
content: str = response.content.decode()
- active_loc: str = f"https://ttvdrops.lovinator.space/twitch/campaigns/{active_campaign.twitch_id}/"
+ active_loc: str = f"http://testserver/twitch/campaigns/{active_campaign.twitch_id}/"
active_index: int = content.find(active_loc)
assert active_index != -1
active_end: int = content.find("", active_index)
assert active_end != -1
- inactive_loc: str = f"https://ttvdrops.lovinator.space/twitch/campaigns/{inactive_campaign.twitch_id}/"
+ inactive_loc: str = f"http://testserver/twitch/campaigns/{inactive_campaign.twitch_id}/"
inactive_index: int = content.find(inactive_loc)
assert inactive_index != -1
inactive_end: int = content.find("", inactive_index)
@@ -1635,13 +1629,17 @@ class TestSitemapView:
response: _MonkeyPatchedWSGIResponse = client.get("/sitemap-kick.xml")
content: str = response.content.decode()
- active_loc: str = f"https://ttvdrops.lovinator.space/kick/campaigns/{active_campaign.kick_id}/"
+ active_loc: str = (
+ f"http://testserver/kick/campaigns/{active_campaign.kick_id}/"
+ )
active_index: int = content.find(active_loc)
assert active_index != -1
active_end: int = content.find("", active_index)
assert active_end != -1
- inactive_loc: str = f"https://ttvdrops.lovinator.space/kick/campaigns/{inactive_campaign.kick_id}/"
+ inactive_loc: str = (
+ f"http://testserver/kick/campaigns/{inactive_campaign.kick_id}/"
+ )
inactive_index: int = content.find(inactive_loc)
assert inactive_index != -1
inactive_end: int = content.find("", inactive_index)
@@ -1974,7 +1972,7 @@ class TestImageObjectStructuredData:
assert img["creator"] == {
"@type": "Organization",
"name": org.name,
- "url": f"https://ttvdrops.lovinator.space{reverse('twitch:organization_detail', args=[org.twitch_id])}",
+ "url": f"http://testserver{reverse('twitch:organization_detail', args=[org.twitch_id])}",
}
def test_game_schema_no_image_when_no_box_art(
@@ -2086,7 +2084,7 @@ class TestImageObjectStructuredData:
assert img["creator"] == {
"@type": "Organization",
"name": org.name,
- "url": f"https://ttvdrops.lovinator.space{reverse('twitch:organization_detail', args=[org.twitch_id])}",
+ "url": f"http://testserver{reverse('twitch:organization_detail', args=[org.twitch_id])}",
}
def test_campaign_schema_no_image_when_no_image_url(