165 lines
5.5 KiB
Python
165 lines
5.5 KiB
Python
import logging
|
|
import os
|
|
from typing import TYPE_CHECKING
|
|
|
|
from discord_webhook import DiscordWebhook
|
|
from django.db.models.signals import post_save
|
|
from django.dispatch import receiver
|
|
|
|
from core.discord import convert_time_to_discord_timestamp
|
|
from core.models import DropCampaign, Game, Owner, User, Webhook
|
|
|
|
if TYPE_CHECKING:
|
|
import requests
|
|
|
|
logger: logging.Logger = logging.getLogger(__name__)
|
|
|
|
|
|
def generate_message(game: Game, drop: DropCampaign) -> str:
|
|
"""Generate a message for a game.
|
|
|
|
Args:
|
|
game (Game): The game to generate a message for.
|
|
drop (DropCampaign): The drop campaign to generate a message for.
|
|
|
|
Returns:
|
|
str: The message.
|
|
"""
|
|
# TODO(TheLovinator): Add a twitch link to a stream that has drops enabled. # noqa: TD003
|
|
game_name: str = game.name or "Unknown game"
|
|
description: str = drop.description or "No description available."
|
|
start_at: str = convert_time_to_discord_timestamp(drop.starts_at)
|
|
end_at: str = convert_time_to_discord_timestamp(drop.ends_at)
|
|
msg: str = f"**{game_name}**\n\n{description}\n\nStarts: {start_at}\nEnds: {end_at}"
|
|
|
|
logger.debug(msg)
|
|
|
|
return msg
|
|
|
|
|
|
@receiver(signal=post_save, sender=User)
|
|
def handle_user_signed_up(sender: User, instance: User, created: bool, **kwargs) -> None: # noqa: ANN003, ARG001, FBT001
|
|
"""Send a message to Discord when a user signs up.
|
|
|
|
Webhook URL is read from .env file.
|
|
|
|
Args:
|
|
sender (User): The model we are sending the signal from.
|
|
instance (User): The instance of the model that was created.
|
|
created (bool): Whether the instance was created or updated.
|
|
**kwargs: Additional keyword arguments.
|
|
"""
|
|
if not created:
|
|
logger.debug("User '%s' was updated.", instance.username)
|
|
return
|
|
|
|
webhook_url: str | None = os.getenv("DISCORD_WEBHOOK_URL")
|
|
if not webhook_url:
|
|
logger.error("No webhook URL provided.")
|
|
return
|
|
|
|
webhook = DiscordWebhook(
|
|
url=webhook_url,
|
|
content=f"New user signed up: '{instance.username}'",
|
|
username="TTVDrops",
|
|
rate_limit_retry=True,
|
|
)
|
|
response: requests.Response = webhook.execute()
|
|
logger.debug(response)
|
|
|
|
|
|
def notify_users_of_new_drop(sender: DropCampaign, instance: DropCampaign, created: bool, **kwargs) -> None: # noqa: ANN003, ARG001, FBT001
|
|
"""Send message to all webhooks subscribed to new drops.
|
|
|
|
Args:
|
|
sender (DropCampaign): The model we are sending the signal from.
|
|
instance (DropCampaign): The instance of the model that was created.
|
|
created (bool): Whether the instance was created or updated.
|
|
**kwargs: Additional keyword arguments.
|
|
"""
|
|
if not created:
|
|
logger.debug("Drop campaign '%s' was updated.", instance.name)
|
|
return
|
|
|
|
game: Game | None = instance.game
|
|
if not game:
|
|
logger.error("No game found. %s", instance)
|
|
return
|
|
|
|
if game.owner: # type: ignore # noqa: PGH003
|
|
handle_owner_drops(instance, game)
|
|
else:
|
|
logger.error("No owner found. %s", instance)
|
|
|
|
if game := instance.game:
|
|
handle_game_drops(instance, game)
|
|
else:
|
|
logger.error("No game found. %s", instance)
|
|
|
|
|
|
def handle_game_drops(instance: DropCampaign, game: Game) -> None:
|
|
"""Send message to all webhooks subscribed to new drops for this game.
|
|
|
|
Args:
|
|
instance (DropCampaign): The drop campaign that was created.
|
|
game (Game): The game that the drop campaign is for.
|
|
"""
|
|
webhooks: list[Webhook] = game.subscribed_new_games.all() # type: ignore # noqa: PGH003
|
|
for hook in webhooks:
|
|
# Don't spam the same drop campaign.
|
|
if hook in hook.seen_drops.all():
|
|
logger.error("Already seen drop campaign '%s'.", instance.name)
|
|
continue
|
|
|
|
# Set the webhook as seen so we don't spam it.
|
|
hook.seen_drops.add(instance)
|
|
|
|
# Send the webhook.
|
|
webhook_url: str = hook.get_webhook_url()
|
|
if not webhook_url:
|
|
logger.error("No webhook URL provided.")
|
|
continue
|
|
|
|
webhook = DiscordWebhook(
|
|
url=webhook_url,
|
|
content=generate_message(game, instance),
|
|
username=f"{game.name} Twitch drops",
|
|
rate_limit_retry=True,
|
|
)
|
|
response: requests.Response = webhook.execute()
|
|
logger.debug(response)
|
|
|
|
|
|
def handle_owner_drops(instance: DropCampaign, game: Game) -> None:
|
|
"""Send message to all webhooks subscribed to new drops for this owner/organization.
|
|
|
|
Args:
|
|
instance (DropCampaign): The drop campaign that was created.
|
|
game (Game): The game that the drop campaign is for.
|
|
"""
|
|
owner: Owner = game.owner # type: ignore # noqa: PGH003
|
|
webhooks: list[Webhook] = owner.subscribed_new_games.all() # type: ignore # noqa: PGH003
|
|
for hook in webhooks:
|
|
# Don't spam the same drop campaign.
|
|
if hook in hook.seen_drops.all():
|
|
logger.error("Already seen drop campaign '%s'.", instance.name)
|
|
continue
|
|
|
|
# Set the webhook as seen so we don't spam it.
|
|
hook.seen_drops.add(instance)
|
|
|
|
# Send the webhook.
|
|
webhook_url: str = hook.get_webhook_url()
|
|
if not webhook_url:
|
|
logger.error("No webhook URL provided.")
|
|
continue
|
|
|
|
webhook = DiscordWebhook(
|
|
url=webhook_url,
|
|
content=generate_message(game, instance),
|
|
username=f"{game.name} Twitch drops",
|
|
rate_limit_retry=True,
|
|
)
|
|
response: requests.Response = webhook.execute()
|
|
logger.debug(response)
|