diff --git a/.env.example b/.env.example
index 47e3f66..a24a778 100644
--- a/.env.example
+++ b/.env.example
@@ -2,3 +2,4 @@ DJANGO_SECRET_KEY=
DEBUG=True
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
+DISCORD_WEBHOOK_URL=
diff --git a/config/settings.py b/config/settings.py
index 4883d2c..ce40619 100644
--- a/config/settings.py
+++ b/config/settings.py
@@ -59,6 +59,7 @@ DEFAULT_FROM_EMAIL: str = os.getenv(
default="webmaster@localhost",
)
SERVER_EMAIL: str = os.getenv(key="EMAIL_HOST_USER", default="webmaster@localhost")
+DISCORD_WEBHOOK_URL: str = os.getenv(key="DISCORD_WEBHOOK_URL", default="")
INSTALLED_APPS: list[str] = [
"core.apps.CoreConfig",
diff --git a/core/discord.py b/core/discord.py
new file mode 100644
index 0000000..59e9529
--- /dev/null
+++ b/core/discord.py
@@ -0,0 +1,31 @@
+import logging
+from typing import TYPE_CHECKING
+
+from discord_webhook import DiscordWebhook
+from django.conf import settings
+
+if TYPE_CHECKING:
+ from requests import Response
+
+logger: logging.Logger = logging.getLogger(__name__)
+
+
+def send(message: str) -> None:
+ """Send a message to Discord.
+
+ Args:
+ message: The message to send.
+ """
+ webhook_url = str(settings.DISCORD_WEBHOOK_URL)
+ if not webhook_url:
+ logger.error("No Discord webhook URL found.")
+ return
+
+ webhook = DiscordWebhook(
+ url=webhook_url,
+ content=message,
+ username="TTVDrops",
+ rate_limit_retry=True,
+ )
+ response: Response = webhook.execute()
+ logger.debug(response)
diff --git a/core/templates/index.html b/core/templates/index.html
index 15808b8..59a1bd2 100644
--- a/core/templates/index.html
+++ b/core/templates/index.html
@@ -131,7 +131,18 @@
-
+
+
{% for drop_benefit in game_data.drop_benefits %}
diff --git a/core/urls.py b/core/urls.py
index 97915a1..100e505 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -9,4 +9,5 @@ app_name: str = "core"
urlpatterns: list[URLPattern | URLResolver] = [
path(route="", view=views.index, name="index"),
+ path(route="test/", view=views.test_webhook, name="test"),
]
diff --git a/core/views.py b/core/views.py
index 54415eb..a7ff37a 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,8 +1,11 @@
+import logging
from typing import TYPE_CHECKING
+from django.db.models.manager import BaseManager
from django.http import HttpRequest, HttpResponse
from django.template.response import TemplateResponse
+from core.discord import send
from twitch.models import (
DropBenefit,
DropCampaign,
@@ -13,6 +16,9 @@ from twitch.models import (
if TYPE_CHECKING:
from django.db.models.manager import BaseManager
+from django.views.decorators.http import require_POST
+
+logger = logging.getLogger(__name__)
def index(request: HttpRequest) -> HttpResponse:
@@ -48,7 +54,7 @@ def index(request: HttpRequest) -> HttpResponse:
for benefit in drop_benefits:
orgs_data[org]["games"][benefit.game]["drop_benefits"].append(benefit)
- time_based_drops = TimeBasedDrop.objects.filter(
+ time_based_drops: BaseManager[TimeBasedDrop] = TimeBasedDrop.objects.filter(
benefits__in=drop_benefits,
).distinct()
for drop in time_based_drops:
@@ -58,7 +64,9 @@ def index(request: HttpRequest) -> HttpResponse:
drop,
)
- drop_campaigns = DropCampaign.objects.filter(owner=org)
+ drop_campaigns: BaseManager[DropCampaign] = DropCampaign.objects.filter(
+ owner=org,
+ )
for campaign in drop_campaigns:
orgs_data[org]["drop_campaigns"].append(campaign)
@@ -67,3 +75,36 @@ def index(request: HttpRequest) -> HttpResponse:
template="index.html",
context={"orgs_data": orgs_data},
)
+
+
+@require_POST
+def test_webhook(
+ request: HttpRequest,
+ *args, # noqa: ANN002, ARG001
+ **kwargs, # noqa: ARG001, ANN003
+) -> HttpResponse:
+ """Test webhook.
+
+ Args:
+ request: The request.
+ args: Additional arguments.
+ kwargs: Additional keyword arguments.
+
+ Returns:
+ HttpResponse: Returns a response.
+ """
+ org_id: str | None = request.POST.get("org_id")
+ if not org_id:
+ return HttpResponse(status=400)
+
+ campaign: DropCampaign = DropCampaign.objects.get(id=org_id)
+
+ msg: str = f"""
+Found new drop for {campaign.game.display_name}:\n
+{campaign.name}\n
+{campaign.description}\n
+<{campaign.details_url}>
+"""
+ send(msg.strip())
+
+ return HttpResponse(status=200)
diff --git a/requirements.txt b/requirements.txt
index 6116719..c06c7a1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,3 +11,4 @@ whitenoise[brotli]
platformdirs
playwright
django-ninja
+discord-webhook
diff --git a/twitch/api.py b/twitch/api.py
index 587e96f..9464c84 100644
--- a/twitch/api.py
+++ b/twitch/api.py
@@ -72,6 +72,15 @@ class DropCampaignSchema(Schema):
account_link_url: str | None = None
description: str | None = None
details_url: str | None = None
+ end_at: datetime.datetime | None = None
+ image_url: str | None = None
+ name: str | None = None
+ start_at: datetime.datetime | None = None
+ status: str | None = None
+ game: GameSchema | None = None
+ owner: OrganizationSchema | None = None
+ channels: list[ChannelSchema] | None = None
+ time_based_drops: list[TimeBasedDropSchema] | None = None
added_at: datetime.datetime | None = None
modified_at: datetime.datetime | None = None