140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
from typing import Optional
|
|
|
|
import structlog
|
|
from notifications.signals import notify
|
|
from sendgrid import Mail, SendGridAPIClient
|
|
from storages.utils import setting
|
|
|
|
from vbv_lernwelt.core.models import User
|
|
from vbv_lernwelt.notify.models import Notification, NotificationType
|
|
|
|
logger = structlog.get_logger(__name__)
|
|
|
|
|
|
class EmailService:
|
|
_sendgrid_client = SendGridAPIClient(setting("SENDGRID_API_KEY"))
|
|
|
|
@classmethod
|
|
def send_email(cls, recipient: User, verb: str, target_url) -> bool:
|
|
message = Mail(
|
|
from_email="info@iterativ.ch",
|
|
to_emails=recipient.email,
|
|
subject=f"myVBV - {verb}",
|
|
## TODO: Add HTML content.
|
|
html_content=f"{verb}: <a href='{target_url}'>Link</a>",
|
|
)
|
|
try:
|
|
cls._sendgrid_client.send(message)
|
|
logger.info(f"Successfully sent email to {recipient}", label="email")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(
|
|
f"Failed to send email to {recipient}: {e}",
|
|
exc_info=True,
|
|
label="email",
|
|
)
|
|
return False
|
|
|
|
|
|
class NotificationService:
|
|
@classmethod
|
|
def send_user_interaction_notification(
|
|
cls, recipient: User, verb: str, sender: User, course: str, target_url: str
|
|
) -> None:
|
|
cls._send_notification(
|
|
recipient=recipient,
|
|
verb=verb,
|
|
sender=sender,
|
|
course=course,
|
|
target_url=target_url,
|
|
notification_type=NotificationType.USER_INTERACTION,
|
|
)
|
|
|
|
@classmethod
|
|
def send_progress_notification(
|
|
cls, recipient: User, verb: str, course: str, target_url: str
|
|
) -> None:
|
|
cls._send_notification(
|
|
recipient=recipient,
|
|
verb=verb,
|
|
course=course,
|
|
target_url=target_url,
|
|
notification_type=NotificationType.PROGRESS,
|
|
)
|
|
|
|
@classmethod
|
|
def send_information_notification(
|
|
cls, recipient: User, verb: str, target_url: str
|
|
) -> None:
|
|
cls._send_notification(
|
|
recipient=recipient,
|
|
verb=verb,
|
|
target_url=target_url,
|
|
notification_type=NotificationType.INFORMATION,
|
|
)
|
|
|
|
@classmethod
|
|
def _send_notification(
|
|
cls,
|
|
recipient: User,
|
|
verb: str,
|
|
notification_type: NotificationType,
|
|
sender: Optional[User] = None,
|
|
course: Optional[str] = None,
|
|
target_url: Optional[str] = None,
|
|
) -> None:
|
|
actor_avatar_url: Optional[str] = None
|
|
if not sender:
|
|
sender = User.objects.get(email="admin")
|
|
else:
|
|
actor_avatar_url = sender.avatar_url
|
|
emailed = False
|
|
if cls._should_send_email(notification_type, recipient):
|
|
emailed = cls._send_email(recipient, verb, target_url)
|
|
log = logger.bind(
|
|
verb=verb,
|
|
notification_type=notification_type,
|
|
sender=sender.get_full_name(),
|
|
recipient=recipient.get_full_name(),
|
|
course=course,
|
|
target_url=target_url,
|
|
)
|
|
try:
|
|
response = notify.send(
|
|
sender=sender,
|
|
recipient=recipient,
|
|
verb=verb,
|
|
)
|
|
sent_notification: Notification = response[0][1][0]
|
|
sent_notification.target_url = target_url
|
|
sent_notification.notification_type = notification_type
|
|
sent_notification.course = course
|
|
sent_notification.actor_avatar_url = actor_avatar_url
|
|
sent_notification.emailed = emailed
|
|
sent_notification.save()
|
|
except Exception as e:
|
|
log.bind(exception=e)
|
|
log.error("Failed to send notification")
|
|
else:
|
|
log.info("Notification sent successfully")
|
|
|
|
@staticmethod
|
|
def _should_send_email(
|
|
notification_type: NotificationType, recipient: User
|
|
) -> bool:
|
|
return str(notification_type) in recipient.additional_json_data.get(
|
|
"email_notification_types", []
|
|
)
|
|
|
|
@staticmethod
|
|
def _send_email(recipient: User, verb: str, target_url: Optional[str]) -> bool:
|
|
try:
|
|
return EmailService.send_email(
|
|
recipient=recipient,
|
|
verb=verb,
|
|
target_url=target_url,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to send email to {recipient}: {e}")
|
|
return False
|