Compare commits
3 commits
7478d4c851
...
ef00b4c020
| Author | SHA1 | Date | |
|---|---|---|---|
|
ef00b4c020 |
|||
|
867ddf7676 |
|||
|
8dfcd118e5 |
9 changed files with 52 additions and 22 deletions
|
|
@ -23,7 +23,7 @@ def test_sitemap_static_contains_expected_links(
|
||||||
youtube apps as well as some misc static files like /robots.txt.
|
youtube apps as well as some misc static files like /robots.txt.
|
||||||
"""
|
"""
|
||||||
# Ensure deterministic BASE_URL
|
# Ensure deterministic BASE_URL
|
||||||
settings.BASE_URL = "https://ttvdrops.lovinator.space"
|
settings.BASE_URL = "https://ttvdrops.lovinator.space" # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
|
||||||
response = client.get(reverse("sitemap-static"))
|
response = client.get(reverse("sitemap-static"))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
@ -31,7 +31,7 @@ def test_sitemap_static_contains_expected_links(
|
||||||
|
|
||||||
locs = _extract_locs(response.content)
|
locs = _extract_locs(response.content)
|
||||||
|
|
||||||
base = settings.BASE_URL.rstrip("/")
|
base = settings.BASE_URL.rstrip("/") # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
|
||||||
expected_paths = [
|
expected_paths = [
|
||||||
reverse("core:dashboard"),
|
reverse("core:dashboard"),
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ from django.http import Http404
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.shortcuts import reverse
|
|
||||||
from django.template.defaultfilters import filesizeformat
|
from django.template.defaultfilters import filesizeformat
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from kick.models import KickChannel
|
from kick.models import KickChannel
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,20 @@ description = "Get notified when a new drop is available on Twitch."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.14"
|
requires-python = ">=3.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"celery[redis]",
|
||||||
"colorama",
|
"colorama",
|
||||||
"dateparser",
|
"dateparser",
|
||||||
"django-auto-prefetch",
|
"django-auto-prefetch",
|
||||||
|
"django-celery-beat",
|
||||||
|
"django-celery-results",
|
||||||
"django-debug-toolbar",
|
"django-debug-toolbar",
|
||||||
"django-silk",
|
"django-silk",
|
||||||
"django",
|
"django",
|
||||||
|
"flower",
|
||||||
"gunicorn",
|
"gunicorn",
|
||||||
|
"hiredis",
|
||||||
"httpx",
|
"httpx",
|
||||||
|
"index-now-for-python",
|
||||||
"json-repair",
|
"json-repair",
|
||||||
"pillow",
|
"pillow",
|
||||||
"platformdirs",
|
"platformdirs",
|
||||||
|
|
@ -20,17 +26,11 @@ dependencies = [
|
||||||
"pydantic",
|
"pydantic",
|
||||||
"pygments",
|
"pygments",
|
||||||
"python-dotenv",
|
"python-dotenv",
|
||||||
|
"redis",
|
||||||
"sentry-sdk",
|
"sentry-sdk",
|
||||||
"setproctitle",
|
"setproctitle",
|
||||||
"tqdm",
|
|
||||||
"index-now-for-python",
|
|
||||||
"sitemap-parser",
|
"sitemap-parser",
|
||||||
"celery[redis]",
|
"tqdm",
|
||||||
"django-celery-results",
|
|
||||||
"django-celery-beat",
|
|
||||||
"flower",
|
|
||||||
"hiredis",
|
|
||||||
"redis",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,9 +41,9 @@ dev = [
|
||||||
"hypothesis[django]",
|
"hypothesis[django]",
|
||||||
"pytest-cov",
|
"pytest-cov",
|
||||||
"pytest-django",
|
"pytest-django",
|
||||||
|
"pytest-randomly",
|
||||||
"pytest-xdist[psutil]",
|
"pytest-xdist[psutil]",
|
||||||
"pytest",
|
"pytest",
|
||||||
"pytest-randomly",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
<!-- Game image -->
|
<!-- Game image -->
|
||||||
<div style="margin-right: 16px;">
|
<div style="margin-right: 16px;">
|
||||||
{% if game.box_art_best_url %}
|
{% if game.box_art_best_url %}
|
||||||
{% picture game.box_art_best_url alt=game.name width=160 %}
|
{% picture game.box_art_best_url alt="Box art for "|add:game.get_game_name width=160 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<!-- Game Title and Details -->
|
<!-- Game Title and Details -->
|
||||||
|
|
|
||||||
|
|
@ -692,7 +692,7 @@ class OrganizationRSSFeed(TTVDropsBaseFeed):
|
||||||
feed_type = BrowserFriendlyRss201rev2Feed
|
feed_type = BrowserFriendlyRss201rev2Feed
|
||||||
|
|
||||||
title: str = "TTVDrops Twitch Organizations"
|
title: str = "TTVDrops Twitch Organizations"
|
||||||
link: str = "/organizations/"
|
link: str = "/twitch/organizations/"
|
||||||
description: str = "Latest organizations on TTVDrops"
|
description: str = "Latest organizations on TTVDrops"
|
||||||
|
|
||||||
_limit: int | None = None
|
_limit: int | None = None
|
||||||
|
|
@ -921,7 +921,7 @@ class DropCampaignFeed(TTVDropsBaseFeed):
|
||||||
"""RSS feed for latest drop campaigns."""
|
"""RSS feed for latest drop campaigns."""
|
||||||
|
|
||||||
title: str = "Twitch Drop Campaigns"
|
title: str = "Twitch Drop Campaigns"
|
||||||
link: str = "/campaigns/"
|
link: str = "/"
|
||||||
description: str = "Latest Twitch drop campaigns on TTVDrops"
|
description: str = "Latest Twitch drop campaigns on TTVDrops"
|
||||||
item_guid_is_permalink = True
|
item_guid_is_permalink = True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from django.db import migrations
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
def migrate_operation_name_to_list(apps, schema_editor) -> None: # noqa: ANN001, ARG001
|
def migrate_operation_name_to_list(apps, schema_editor) -> None: # noqa: ANN001
|
||||||
"""Convert operation_name string values to operation_names list."""
|
"""Convert operation_name string values to operation_names list."""
|
||||||
DropCampaign = apps.get_model("twitch", "DropCampaign")
|
DropCampaign = apps.get_model("twitch", "DropCampaign")
|
||||||
for campaign in DropCampaign.objects.all():
|
for campaign in DropCampaign.objects.all():
|
||||||
|
|
@ -14,7 +14,7 @@ def migrate_operation_name_to_list(apps, schema_editor) -> None: # noqa: ANN001
|
||||||
campaign.save(update_fields=["operation_names"])
|
campaign.save(update_fields=["operation_names"])
|
||||||
|
|
||||||
|
|
||||||
def reverse_operation_names_to_string(apps, schema_editor) -> None: # noqa: ARG001, ANN001
|
def reverse_operation_names_to_string(apps, schema_editor) -> None: # noqa: ANN001
|
||||||
"""Convert operation_names list back to operation_name string (first item only)."""
|
"""Convert operation_names list back to operation_name string (first item only)."""
|
||||||
DropCampaign = apps.get_model("twitch", "DropCampaign")
|
DropCampaign = apps.get_model("twitch", "DropCampaign")
|
||||||
for campaign in DropCampaign.objects.all():
|
for campaign in DropCampaign.objects.all():
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
def mark_all_drops_fully_imported(apps, schema_editor) -> None: # noqa: ANN001, ARG001
|
def mark_all_drops_fully_imported(apps, schema_editor) -> None: # noqa: ANN001
|
||||||
"""Marks all existing DropCampaigns as fully imported.
|
"""Marks all existing DropCampaigns as fully imported.
|
||||||
|
|
||||||
This was needed to ensure that the Twitch API view only returns campaigns that are ready for display.
|
This was needed to ensure that the Twitch API view only returns campaigns that are ready for display.
|
||||||
|
|
|
||||||
|
|
@ -1410,3 +1410,33 @@ class DiscordFeedTestCase(TestCase):
|
||||||
f"Expected Discord timestamp format &lt;t:UNIX_TIMESTAMP:R&gt; in content, got: {content}"
|
f"Expected Discord timestamp format &lt;t:UNIX_TIMESTAMP:R&gt; in content, got: {content}"
|
||||||
)
|
)
|
||||||
assert "()" not in content
|
assert "()" not in content
|
||||||
|
|
||||||
|
def test_feed_links_return_200(self) -> None:
|
||||||
|
"""Test that all links in the feeds return 200 OK."""
|
||||||
|
feed_urls: list[str] = [
|
||||||
|
reverse("core:organization_feed"),
|
||||||
|
reverse("core:game_feed"),
|
||||||
|
reverse("core:organization_feed_atom"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for feed_url in feed_urls:
|
||||||
|
response: _MonkeyPatchedWSGIResponse = self.client.get(feed_url)
|
||||||
|
assert response.status_code == 200, f"Feed {feed_url} did not return 200."
|
||||||
|
|
||||||
|
# Extract all links from the feed content
|
||||||
|
content: str = response.content.decode("utf-8")
|
||||||
|
links: list[str] = re.findall(r'href=["\'](https?://.*?)["\']', content)
|
||||||
|
|
||||||
|
for link in links:
|
||||||
|
skip_links: list[str] = [
|
||||||
|
"rss_styles.xslt",
|
||||||
|
"twitch.tv",
|
||||||
|
]
|
||||||
|
|
||||||
|
if any(skip in link for skip in skip_links):
|
||||||
|
# Skip testing rss_styles.xslt, external Twitch links, and internal links that may not exist in test environment
|
||||||
|
continue
|
||||||
|
link_response: _MonkeyPatchedWSGIResponse = self.client.get(link)
|
||||||
|
|
||||||
|
msg: str = f"Link {link} in feed {feed_url} did not return 200, got {link_response.status_code}."
|
||||||
|
assert link_response.status_code == 200, msg
|
||||||
|
|
|
||||||
|
|
@ -1883,7 +1883,7 @@ def export_campaigns_json(request: HttpRequest) -> HttpResponse:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def export_games_csv(request: HttpRequest) -> HttpResponse: # noqa: ARG001 # noqa: ARG001
|
def export_games_csv(request: HttpRequest) -> HttpResponse:
|
||||||
"""Export games to CSV format.
|
"""Export games to CSV format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -1923,7 +1923,7 @@ def export_games_csv(request: HttpRequest) -> HttpResponse: # noqa: ARG001 # n
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def export_games_json(request: HttpRequest) -> HttpResponse: # noqa: ARG001 # noqa: ARG001
|
def export_games_json(request: HttpRequest) -> HttpResponse:
|
||||||
"""Export games to JSON format.
|
"""Export games to JSON format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -1958,7 +1958,7 @@ def export_games_json(request: HttpRequest) -> HttpResponse: # noqa: ARG001 #
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def export_organizations_csv(request: HttpRequest) -> HttpResponse: # noqa: ARG001
|
def export_organizations_csv(request: HttpRequest) -> HttpResponse:
|
||||||
"""Export organizations to CSV format.
|
"""Export organizations to CSV format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -1987,7 +1987,7 @@ def export_organizations_csv(request: HttpRequest) -> HttpResponse: # noqa: ARG
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def export_organizations_json(request: HttpRequest) -> HttpResponse: # noqa: ARG001
|
def export_organizations_json(request: HttpRequest) -> HttpResponse:
|
||||||
"""Export organizations to JSON format.
|
"""Export organizations to JSON format.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue