Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented recipients per basket #442

Merged
merged 13 commits into from
Jan 14, 2024
4 changes: 3 additions & 1 deletion config.sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Enabled = false
## Subject and Body options are optional.
## Subject and Body options can use variables as described below
## The Body option is interpreted as HTML
## If "RecipientsPerItem" is included, multiple different recipients may be defined for notification. Notifications for items not listed in the JSON are sent to "Recipients".
Enabled = false
Host = smtp.gmail.com
Port = 587
Expand All @@ -106,6 +107,7 @@ TLS = true
SSL = false
Sender = max.mustermann@gmail.com
Recipients = max.mustermann@gmail.com
; RecipientsPerItem = {"123" : ["max.mustermann@example.com", "moritz.mustermann@example.com"], "456" : ["max.mustermann@example.com"], "789": "marta.mustermann@example.com"}
; Cron =
; Subject =
; Body =
Expand Down Expand Up @@ -146,7 +148,7 @@ Topic =
; Cron =

## To use Telegram notifications you have to create a bot using the @botfather
## If you only provide the token of the bot will use the last chat it reseived a message on
## If you only provide the token of the bot will use the last chat it received a message on
## You can add multiple chat ids as a comma seperated list
## The message body is optional and is interpreted as markdown text
## You can use the same variables as described for the Webhook notifier below
Expand Down
3 changes: 3 additions & 0 deletions tgtg_scanner/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class SMTPConfig(NotifierConfig):
use_ssl: bool = False
sender: Union[str, None] = None
recipients: list[str] = field(default_factory=list)
Der-Henning marked this conversation as resolved.
Show resolved Hide resolved
recipients_per_item: Union[str, None] = None
subject: str = "New Magic Bags"
body: str = "<b>${{display_name}}</b> </br>New Amount: ${{items_available}}"

Expand All @@ -261,6 +262,7 @@ def _read_ini(self, parser: configparser.ConfigParser):
log.warning(DEPRECIATION_WARNING.format("[SMTP] Recipient", "Recipients"))
self._ini_get_list(parser, "SMTP", "Recipient", "recipients") # legacy support
self._ini_get_list(parser, "SMTP", "Recipients", "recipients")
self._ini_get(parser, "SMTP", "RecipientsPerItem", "recipients_per_item")
self._ini_get(parser, "SMTP", "Subject", "subject")
self._ini_get(parser, "SMTP", "Body", "body")

Expand All @@ -278,6 +280,7 @@ def _read_env(self):
log.warning(DEPRECIATION_WARNING.format("SMTP_RECIPIENT", "SMTP_RECIPIENTS"))
self._env_get_list("SMTP_RECIPIENT", "recipients") # legacy support
self._env_get_list("SMTP_RECIPIENTS", "recipients")
self._env_get("SMTP_RECIPIENTS_PER_ITEM", "recipients_per_item")
self._env_get("SMTP_SUBJECT", "subject")
self._env_get("SMTP_BODY", "body")

Expand Down
29 changes: 24 additions & 5 deletions tgtg_scanner/notifiers/smtp.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import logging
import smtplib
from email.mime.multipart import MIMEMultipart
Expand Down Expand Up @@ -29,6 +30,8 @@
self.password = config.smtp.password
self.sender = config.smtp.sender
self.recipients = config.smtp.recipients
self.recipients_per_item = config.smtp.recipients_per_item
lars-devs marked this conversation as resolved.
Show resolved Hide resolved
self.item_recipients: dict[str, list[str]] = {}
self.subject = config.smtp.subject
self.body = config.smtp.body
self.cron = config.smtp.cron
Expand All @@ -44,6 +47,17 @@
self._connect()
except Exception as exc:
raise SMTPConfigurationError(exc) from exc
if config.smtp.recipients_per_item is not None:
item_recipients = None
try:
item_recipients = json.loads(config.smtp.recipients_per_item)
except json.decoder.JSONDecodeError:
raise SMTPConfigurationError("Recipients per Item is not a valid dictionary")
if not isinstance(item_recipients, dict) or any(

Check warning on line 56 in tgtg_scanner/notifiers/smtp.py

View check run for this annotation

Codecov / codecov/patch

tgtg_scanner/notifiers/smtp.py#L51-L56

Added lines #L51 - L56 were not covered by tests
not isinstance(value, (list, str)) for value in item_recipients.values()
):
raise SMTPConfigurationError("Recipients per Item is not a valid dictionary")
self.item_recipients = {k: v if isinstance(v, list) else [v] for k, v in item_recipients.items()}

Check warning on line 60 in tgtg_scanner/notifiers/smtp.py

View check run for this annotation

Codecov / codecov/patch

tgtg_scanner/notifiers/smtp.py#L59-L60

Added lines #L59 - L60 were not covered by tests

def __del__(self):
"""Closes SMTP connection when shutdown"""
Expand Down Expand Up @@ -79,29 +93,34 @@
if status != 250:
self._connect()

def _send_mail(self, subject: str, html: str) -> None:
def _send_mail(self, subject: str, html: str, item_id: int) -> None:
lars-devs marked this conversation as resolved.
Show resolved Hide resolved
"""Sends mail with html body"""
if self.server is None:
self._connect()
if self.sender is None or self.recipients is None or self.server is None:
raise SMTPConfigurationError()
message = MIMEMultipart("alternative")
message["From"] = self.sender
message["To"] = ", ".join(self.recipients)

# Contains either the main recipient(s) or recipient(s) that should be
# notified for the specific item. First, initalize with main recipient(s)
recipients = self.item_recipients.get(str(item_id), self.recipients)

message["To"] = ", ".join(recipients)
message["Subject"] = subject
message.attach(MIMEText(html, "html", "utf-8"))
body = message.as_string()
self._stay_connected()
try:
self.server.sendmail(self.sender, self.recipients, body)
self.server.sendmail(self.sender, recipients, body)
except SMTPException:
self._connect()
self.server.sendmail(self.sender, self.recipients, body)
self.server.sendmail(self.sender, recipients, body)

Check warning on line 118 in tgtg_scanner/notifiers/smtp.py

View check run for this annotation

Codecov / codecov/patch

tgtg_scanner/notifiers/smtp.py#L118

Added line #L118 was not covered by tests

def _send(self, item: Union[Item, Reservation]) -> None:
"""Sends item information via Mail."""
if isinstance(item, Item):
self._send_mail(item.unmask(self.subject), item.unmask(self.body))
self._send_mail(item.unmask(self.subject), item.unmask(self.body), item.item_id)

def __repr__(self) -> str:
return f"SMTP: {self.recipients}"
1 change: 1 addition & 0 deletions wiki/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ You can combine multiple crons as semicolon separated list.
| Password | SMTP_PASSWORD | login password |
| Sender | SMTP_SENDER | email sender |
| Recipients | SMTP_RECIPIENTS | email recipients | | YES |
| RecipientsPerItem | SMTP_RECIPIENTS | email recipients per item as JSON | | |
| Subject | SMTP_SUBJECT | email subject | `New Magic Bags` | | YES |
| Body | SMTP_BODY | email html body | `<b>${{display_name}}</b> </br> New Amount: ${{items_available}}` | | YES |
| Cron | SMTP_CRON | enable notification only on schedule | `* * * * *` |
Expand Down
Loading