Source code for superdjango.contrib.notifications.shortcuts

# Imports

from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import send_mail
from django.utils.module_loading import import_string
# from importlib import import_module
from superdjango.shortcuts import parse_template
from .constants import LEVEL
from .models import Notification, NotificationUser

UserModel = get_user_model()

# Exports

__all__ = (
    "get_promoted_notification",
    "get_sms_callback",
    "get_unread_notification_count",
    "get_unread_notifications",
    "has_unread_notifications",
    "notify",
    "Message",
)

# Constants

FROM_EMAIL = getattr(settings, "SUPERDJANGO_NOTIFICATIONS_FROM_EMAIL")
FROM_NAME = getattr(settings, "SUPERDJANGO_NOTIFICATIONS_FROM_NAME", "Webmaster")
FROM_NUMBER = getattr(settings, "SUPERDJANGO_NOTIFICATIONS_FROM_NUMBER", None)

# Functions


[docs]def get_promoted_notification(user): """Get the (first) promoted notification for the given user. :param user: The user instance to be checked. :type user: AUTH_USER_MODEL :rtype: NotificationUser | None """ criteria = { 'has_been_viewed': False, 'notification__is_promoted': True, 'user': user, } try: return NotificationUser.objects.filter(**criteria).order_by("notification__added_dt").latest("pk") except NotificationUser.DoesNotExist: return None
[docs]def get_sms_callback(raise_exception=True): """Get the callback function used to send SMS/text messages. The callback is defined using ``SUPERDJANGO_NOTIFICATIONS_SMS_CALLBACK`` which is the dotted path to a callable that accepts a body, mobile number, and optionally a from number. .. code-block:: python def send_sms(body, number, from_number=None): # ... """ dotted = getattr(settings, "SUPERDJANGO_NOTIFICATIONS_SMS_CALLBACK", None) if dotted is None: if raise_exception: raise ImproperlyConfigured("You must define SUPERDJANGO_NOTIFICATIONS_SMS_CALLBACK.") return None try: return import_string(dotted) except ImportError as e: if raise_exception: raise ImproperlyConfigured('SMS callback is defined (%s) but could not be imported: %s' % (dotted, e)) return None
[docs]def get_unread_notification_count(user): """Get the unread notification count for a user. :param user: The user instance to be checked. :type user: AUTH_USER_MODEL :rtype: int """ criteria = { 'has_been_viewed': False, 'user': user, } return NotificationUser.objects.filter(**criteria).count() or 0
[docs]def get_unread_notifications(user): """Get the unread notifications for a user. :param user: The user instance to be checked. :type user: AUTH_USER_MODEL :rtype: QuerySet """ criteria = { 'has_been_viewed': False, 'user': user, } return NotificationUser.objects.filter(**criteria)
[docs]def has_unread_notifications(user): """Indicates whether a given user has unread notifications. :param user: The user instance to be checked. :type user: AUTH_USER_MODEL :rtype: bool """ criteria = { 'has_been_viewed': False, 'user': user, } return NotificationUser.objects.filter(**criteria).exists()
[docs]def notify(body, subject, action_url=None, email_enabled=False, icon_override=None, level=LEVEL.INFO, users=None): """Issue a notification. :param body: The body of the notification. :type body: str :param subject: The subject of the notification. :type subject: str :param action_url: The URL to which the user is directed. :type action_url: str :param email_enabled: Indicates the notification should be sent via email. Otherwise, it is only an in-app notification. :type email_enabled: bool :param icon_override: The icon to use for the notification. Overrides the default. :type icon_override: str :param level: The notification level. :type level: int :param users: The users to which the notification should be sent. It omitted, all active users are notified. :type users: list[AUTH_USER_MODEL] :rtype: Notification """ notification = Notification( action_url=action_url, body=body, icon_override=icon_override, level=level, subject=subject ) notification.save() if not email_enabled: notification.mark_sent() if users is None: users = UserModel.objects.filter(is_active=True) for user in users: link = NotificationUser(notification=notification, user=user) link.save() return notification
[docs]class Message(object): """Represents a single email and/or SMS message to a user."""
[docs] def __init__(self, notification, user, preferences=None): """Initialize a message. :param notification: The notification instance. :type notification: superdjango.contrib.notifications.models.Notification :param user: The user instance. :type user: AUTH_USER_MODEL :param preferences: The user preference instance. :type preferences: superdjango.contrib.notifications.models.UserPreference """ self.notification = notification self.preferences = preferences self.user = user
[docs] def email(self): """Send a notification via email. :rtype: bool :returns: ``True`` if the email was sent. """ # Mandatory messages ignore preferences. if self.notification.is_mandatory: pass else: # Otherwise, preferences must be defined and email enabled. if self.preferences is None: return False if not self.preferences.email_enabled: return False context = { 'from_email': FROM_EMAIL, 'from_name': FROM_NAME, 'notification': self.notification, 'user': self.user, } body = parse_template("notifications/templates/email_notification_body.txt", context) body_html = None if self.notification.html_enabled: body_html = parse_template("notifications/templates/email_notification_body.html", context) send_mail( self.notification.subject, body, "%s <%s>" % (FROM_NAME, FROM_EMAIL), [self.user.email], html_message=body_html ) return True
[docs] def sms(self): """Send a notification via SMS/text. :rtype: bool :returns: ``True`` if the SMS was sent. """ send_sms = get_sms_callback(raise_exception=False) if send_sms is None: return False if self.preferences is None: return False if not self.preferences.sms_enabled: return False if not self.preferences.mobile_number: return False send_sms( self.notification.body_sms, self.preferences.mobile_number, from_number=FROM_NUMBER ) return True