diff --git a/README.md b/README.md index e5d67a72..09f0652d 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ camply campgrounds --search "Fire Lookout Towers" --state CA Search for available campsites, get a notification whenever one becomes available, and continue searching after the first one is found. The below command is using `silent` notifications as an example but camply also supports `Email`, -`Slack`, `Twilio` (SMS), `Pushover`, `Pushbullet`, `Ntfy`, `Apprise`, and `Telegram`. +`Slack`, `Discord`, `Twilio` (SMS), `Pushover`, `Pushbullet`, `Ntfy`, `Apprise`, and `Telegram`. ```commandline camply campsites \ diff --git a/camply/config/__init__.py b/camply/config/__init__.py index 529ba254..dd755b06 100644 --- a/camply/config/__init__.py +++ b/camply/config/__init__.py @@ -7,6 +7,7 @@ from .file_config import FileConfig from .notification_config import ( AppriseConfig, + DiscordConfig, EmailConfig, NtfyConfig, PushbulletConfig, @@ -31,6 +32,7 @@ "PushbulletConfig", "PushoverConfig", "SlackConfig", + "DiscordConfig", "TelegramConfig", "TwilioConfig", "SearchConfig", diff --git a/camply/config/file_config.py b/camply/config/file_config.py index 1de430fc..8561fd04 100644 --- a/camply/config/file_config.py +++ b/camply/config/file_config.py @@ -27,6 +27,7 @@ class FileConfig: "notes": "Enables Pushbullet Notifications", }, SLACK_WEBHOOK={"default": "", "notes": "Enables Slack Notifications"}, + DISCORD_WEBHOOK={"default": "", "notes": "Enables Discord Notifications"}, TELEGRAM_BOT_TOKEN={"default": "", "notes": "Enables Telegram Notifications"}, TELEGRAM_CHAT_ID={ "default": "", diff --git a/camply/config/notification_config.py b/camply/config/notification_config.py index 16f6dccc..322f4f54 100644 --- a/camply/config/notification_config.py +++ b/camply/config/notification_config.py @@ -104,6 +104,13 @@ class SlackConfig: SLACK_WEBHOOK: Optional[str] = getenv("SLACK_WEBHOOK", None) +class DiscordConfig: + """ + Discord Notification Config Class + """ + + DISCORD_WEBHOOK: Optional[str] = getenv("DISCORD_WEBHOOK", None) + class TelegramConfig: """ diff --git a/camply/notifications/__init__.py b/camply/notifications/__init__.py index c199c020..2bdf3c8d 100644 --- a/camply/notifications/__init__.py +++ b/camply/notifications/__init__.py @@ -3,6 +3,7 @@ """ from .apprise import AppriseNotifications +from .discord import DiscordNotifications from .email_notifications import EmailNotifications from .multi_provider_notifications import CAMPSITE_NOTIFICATIONS, MultiNotifierProvider from .pushbullet import PushbulletNotifications @@ -17,6 +18,7 @@ "PushbulletNotifications", "PushoverNotifications", "TelegramNotifications", + "DiscordNotifications", "TwilioNotifications", "EmailNotifications", "SilentNotifications", diff --git a/camply/notifications/discord.py b/camply/notifications/discord.py new file mode 100755 index 00000000..2c6bfcc9 --- /dev/null +++ b/camply/notifications/discord.py @@ -0,0 +1,109 @@ +""" +Push Notifications via Discord +""" + +import logging +from typing import List + +import requests + +from camply.config import DiscordConfig +from camply.containers import AvailableCampsite +from camply.notifications.base_notifications import BaseNotifications + +logger = logging.getLogger(__name__) + + +class DiscordNotifications(BaseNotifications): + """ + Push Notifications via Discord + """ + + def __init__(self): + super().__init__() + self.session.headers.update({"Content-Type": "application/json"}) + if any([DiscordConfig.DISCORD_WEBHOOK is None, DiscordConfig.DISCORD_WEBHOOK == ""]): + warning_message = ( + "Discord is not configured properly. To send Discord messages " + "make sure to run `camply configure` or set the " + "proper environment variable: `DISCORD_WEBHOOK`." + ) + logger.error(warning_message) + raise EnvironmentError(warning_message) + + def send_message(self, message: str, **kwargs) -> requests.Response: + """ + Send a message via Discord - if environment variables are configured. + + Parameters + ---------- + message: str + + Returns + ------- + requests.Response + """ + message_json = kwargs + if message: + message_json["content"] = message + + logger.debug(message_json) + response = self.session.post( + url=DiscordConfig.DISCORD_WEBHOOK, + json=message_json, + ) + try: + response.raise_for_status() + except requests.HTTPError as he: + logger.warning( + "Notifications weren't able to be sent to Discord. " + "Your configuration might be incorrect." + ) + raise ConnectionError(response.text) from he + return response + + def block_for_campsite(self, campsite: AvailableCampsite): + message_title, formatted_dict = self.format_standard_campsites( + campsite=campsite, + ) + + # Remove items that will be templated as part of the embed. + del formatted_dict["Recreation Area"] + del formatted_dict["Booking Date"] + del formatted_dict["Booking End Date"] + del formatted_dict["Facility Name"] + del formatted_dict["Booking Link"] + del formatted_dict["Campsite Site Name"] + del formatted_dict["Campsite Loop Name"] + + return { + "author": { + "name": f"🏕 {campsite.recreation_area}" + }, + "title": f"{campsite.facility_name} {campsite.campsite_loop_name} #{campsite.campsite_site_name}", + "description": f"{campsite.booking_date} to {campsite.booking_end_date}", + "url": campsite.booking_url, + "color": 2375436, + "fields": [ + { + "name": key, + "value": str(value) + } for key, value in formatted_dict.items() + ], + "footer": { + "text": "camply, the campsite finder ⛺️" + } + } + + def send_campsites(self, campsites: List[AvailableCampsite], **kwargs): + """ + Send a message with a campsite object + + Parameters + ---------- + campsites: AvailableCampsite + """ + self.send_message( + message="", + embeds=[self.block_for_campsite(campsite) for campsite in campsites], + ) diff --git a/camply/notifications/multi_provider_notifications.py b/camply/notifications/multi_provider_notifications.py index 5725c6cd..c81bf142 100644 --- a/camply/notifications/multi_provider_notifications.py +++ b/camply/notifications/multi_provider_notifications.py @@ -7,6 +7,7 @@ from typing import Dict, List, Type, Union from camply.containers import AvailableCampsite +from camply.notifications import DiscordNotifications from camply.notifications.apprise import AppriseNotifications from camply.notifications.base_notifications import BaseNotifications, NotificationError from camply.notifications.email_notifications import EmailNotifications @@ -27,6 +28,7 @@ "apprise": AppriseNotifications, "pushbullet": PushbulletNotifications, "slack": SlackNotifications, + "discord": DiscordNotifications, "telegram": TelegramNotifications, "twilio": TwilioNotifications, "silent": SilentNotifications, diff --git a/docs/command_line_usage.md b/docs/command_line_usage.md index 77b05d66..a1fbdb55 100644 --- a/docs/command_line_usage.md +++ b/docs/command_line_usage.md @@ -144,7 +144,7 @@ and a link to make the booking. Required parameters include `--start-date`, `--e [\*\*_example_](#continue-looking-after-the-first-match-is-found) - `--notifications`: `NOTIFICATIONS` - Enables continuous searching. Types of notifications to receive. Options available - are `pushover`, `email`, `ntfy`, `apprise`, `pushbullet`, `slack`, `telegram`, `twilio`, `silent`. + are `pushover`, `email`, `ntfy`, `apprise`, `pushbullet`, `slack`, `discord`, `telegram`, `twilio`, `silent`. Defaults to `silent` - which just logs messages to console. [\*\*_example_](#send-a-push-notification) - `--equipment` @@ -457,6 +457,7 @@ camply supports notifications via a number of services: - [Apprise](https://github.com/caronc/apprise) - [Pushbullet](https://www.pushbullet.com/#settings/account) - [Slack](https://slack.com) +- [Discord](https://discord.com) - [Telegram](https://core.telegram.org/bots) - [Twilio (SMS)](https://www.twilio.com) - Silent diff --git a/docs/examples/example.camply b/docs/examples/example.camply index 528c2def..fb15b0b7 100644 --- a/docs/examples/example.camply +++ b/docs/examples/example.camply @@ -10,6 +10,9 @@ PUSHBULLET_API_TOKEN="" # REQUIRED TO SEND SLACK NOTIFICATIONS SLACK_WEBHOOK="" +# REQUIRED TO SEND DISCORD NOTIFICATIONS +DISCORD_WEBHOOK="" + # REQUIRED TO SEND TELEGRAM NOTIFICATIONS TELEGRAM_BOT_TOKEN="" TELEGRAM_CHAT_ID="" diff --git a/docs/how_to_run.md b/docs/how_to_run.md index ec798e5c..3dcb9e3d 100644 --- a/docs/how_to_run.md +++ b/docs/how_to_run.md @@ -139,6 +139,8 @@ available. - `TWILIO_DEST_NUMBERS` - Slack Notifications - `SLACK_WEBHOOK` +- Discord Notifications + - `DISCORD_WEBHOOK` - Telegram Notifications - `TELEGRAM_BOT_TOKEN` - `TELEGRAM_CHAT_ID`