mirror of
https://github.com/wagtail/wagtail.git
synced 2024-11-30 01:46:24 +01:00
Add GroupApprovalTaskStateNotifier
This commit is contained in:
parent
8f5535d5bb
commit
cfeef13cfd
@ -9,7 +9,7 @@ from django.utils.text import get_valid_filename
|
|||||||
from django.utils.translation import override
|
from django.utils.translation import override
|
||||||
|
|
||||||
from wagtail.admin.auth import users_with_page_permission
|
from wagtail.admin.auth import users_with_page_permission
|
||||||
from wagtail.core.models import Page, PageRevision
|
from wagtail.core.models import Page, PageRevision, GroupApprovalTaskState, WorkflowState
|
||||||
from wagtail.users.models import UserProfile
|
from wagtail.users.models import UserProfile
|
||||||
|
|
||||||
|
|
||||||
@ -17,6 +17,7 @@ logger = logging.getLogger('wagtail.admin')
|
|||||||
|
|
||||||
|
|
||||||
class OpenedConnection:
|
class OpenedConnection:
|
||||||
|
"""Context manager for mail connections to ensure they are closed when manually opened"""
|
||||||
def __init__(self, connection):
|
def __init__(self, connection):
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
|
||||||
@ -133,96 +134,161 @@ def send_notification(page_revision_id, notification, excluded_user_id):
|
|||||||
return sent_count == len(email_recipients)
|
return sent_count == len(email_recipients)
|
||||||
|
|
||||||
|
|
||||||
def send_group_approval_task_state_notification(task_state, notification, triggering_user):
|
class Notifier:
|
||||||
recipients = []
|
"""Class for sending email notifications upon events: callable, taking a notifying_instance and a notification (str)
|
||||||
page = task_state.workflow_state.page
|
and sending email notifications using rendered templates"""
|
||||||
if notification in ('approved', 'rejected'):
|
|
||||||
requested_by = task_state.workflow_state.requested_by
|
|
||||||
if requested_by != triggering_user:
|
|
||||||
recipients = [requested_by]
|
|
||||||
elif notification == 'submitted':
|
|
||||||
recipients = task_state.task.specific.group.user_set
|
|
||||||
include_superusers = getattr(settings, 'WAGTAILADMIN_NOTIFICATION_INCLUDE_SUPERUSERS', True)
|
|
||||||
if include_superusers:
|
|
||||||
recipients = recipients | get_user_model().objects.filter(is_superuser=True)
|
|
||||||
recipients = recipients.exclude(pk=triggering_user.pk).distinct()
|
|
||||||
context = {
|
|
||||||
"page": page,
|
|
||||||
"settings": settings,
|
|
||||||
"task": task_state.task,
|
|
||||||
}
|
|
||||||
send_notification_emails(recipients, notification, context, template_base_prefix='group_approval_task_')
|
|
||||||
|
|
||||||
|
def __init__(self, valid_classes, valid_notifications):
|
||||||
|
self.valid_classes = valid_classes
|
||||||
|
self.valid_notifications = valid_notifications
|
||||||
|
|
||||||
def send_workflow_state_notification(workflow_state, notification, triggering_user):
|
def can_handle_class(self, instance):
|
||||||
recipients = []
|
return type(instance) in self.valid_classes
|
||||||
page = workflow_state.page
|
|
||||||
if notification in ('approved', 'rejected'):
|
|
||||||
requested_by = workflow_state.requested_by
|
|
||||||
if requested_by != triggering_user:
|
|
||||||
recipients = [requested_by]
|
|
||||||
elif notification == 'submitted':
|
|
||||||
include_superusers = getattr(settings, 'WAGTAILADMIN_NOTIFICATION_INCLUDE_SUPERUSERS', True)
|
|
||||||
if include_superusers:
|
|
||||||
recipients = get_user_model().objects.filter(is_superuser=True).exclude(pk=triggering_user.pk)
|
|
||||||
context = {
|
|
||||||
"page": page,
|
|
||||||
"settings": settings,
|
|
||||||
"workflow": workflow_state.workflow,
|
|
||||||
}
|
|
||||||
send_notification_emails(recipients, notification, context, template_base_prefix='workflow_')
|
|
||||||
|
|
||||||
|
def can_handle_notification(self, notification):
|
||||||
|
return notification in self.valid_notifications
|
||||||
|
|
||||||
def send_notification_emails(recipients, notification, context, template_base_prefix=''):
|
def can_handle(self, notifying_instance, notification):
|
||||||
|
return self.can_handle_class(notifying_instance) and self.can_handle_notification(notification)
|
||||||
|
|
||||||
# Get list of email addresses
|
def get_recipient_users(self, notifying_instance, notification, **kwargs):
|
||||||
email_recipients = [
|
return set()
|
||||||
recipient for recipient in recipients
|
|
||||||
if recipient.email and getattr(
|
def get_valid_recipients(self, notifying_instance, notification, **kwargs):
|
||||||
|
"""Filters notification recipients to those allowing the notification type on their UserProfile, and those
|
||||||
|
with an email address"""
|
||||||
|
return {recipient for recipient in self.get_recipient_users(notifying_instance, notification, **kwargs) if recipient.email and getattr(
|
||||||
UserProfile.get_for_user(recipient),
|
UserProfile.get_for_user(recipient),
|
||||||
notification + '_notifications'
|
notification + '_notifications'
|
||||||
)
|
)}
|
||||||
]
|
|
||||||
|
|
||||||
# Return if there are no email addresses
|
def get_template_base_prefix(self, notifying_instance):
|
||||||
if not email_recipients:
|
return get_valid_filename(type(notifying_instance).__name__)+'_'
|
||||||
return True
|
|
||||||
|
|
||||||
# Get template
|
def get_template_set(self, notifying_instance, notification):
|
||||||
template_base = template_base_prefix + notification
|
"""Return a dictionary of template paths for the templates for the email subject and the text and html
|
||||||
|
alternatives"""
|
||||||
|
template_base = self.get_template_base_prefix(notifying_instance) + notification
|
||||||
|
|
||||||
template_subject = 'wagtailadmin/notifications/' + template_base + '_subject.txt'
|
template_subject = 'wagtailadmin/notifications/' + template_base + '_subject.txt'
|
||||||
template_text = 'wagtailadmin/notifications/' + template_base + '.txt'
|
template_text = 'wagtailadmin/notifications/' + template_base + '.txt'
|
||||||
template_html = 'wagtailadmin/notifications/' + template_base + '.html'
|
template_html = 'wagtailadmin/notifications/' + template_base + '.html'
|
||||||
|
|
||||||
connection = get_connection()
|
return {
|
||||||
|
'subject': template_subject,
|
||||||
|
'text': template_text,
|
||||||
|
'html': template_html,
|
||||||
|
}
|
||||||
|
|
||||||
with OpenedConnection(connection) as open_connection:
|
def get_context(self, notifying_instance, notification, **kwargs):
|
||||||
|
return {'settings': settings}
|
||||||
|
|
||||||
# Send emails
|
def send_emails(self, template_set, context, recipients):
|
||||||
sent_count = 0
|
connection = get_connection()
|
||||||
for recipient in email_recipients:
|
|
||||||
try:
|
|
||||||
# update context with this recipient
|
|
||||||
context["user"] = recipient
|
|
||||||
|
|
||||||
# Translate text to the recipient language settings
|
with OpenedConnection(connection) as open_connection:
|
||||||
with override(recipient.wagtail_userprofile.get_preferred_language()):
|
|
||||||
# Get email subject and content
|
|
||||||
email_subject = render_to_string(template_subject, context).strip()
|
|
||||||
email_content = render_to_string(template_text, context).strip()
|
|
||||||
|
|
||||||
kwargs = {}
|
# Send emails
|
||||||
if getattr(settings, 'WAGTAILADMIN_NOTIFICATION_USE_HTML', False):
|
sent_count = 0
|
||||||
kwargs['html_message'] = render_to_string(template_html, context)
|
for recipient in recipients:
|
||||||
|
try:
|
||||||
|
# update context with this recipient
|
||||||
|
context["user"] = recipient
|
||||||
|
|
||||||
# Send email
|
# Translate text to the recipient language settings
|
||||||
send_mail(email_subject, email_content, [recipient.email], connection=open_connection, **kwargs)
|
with override(recipient.wagtail_userprofile.get_preferred_language()):
|
||||||
sent_count += 1
|
# Get email subject and content
|
||||||
except Exception:
|
email_subject = render_to_string(template_set['subject'], context).strip()
|
||||||
logger.exception(
|
email_content = render_to_string(template_set['text'], context).strip()
|
||||||
"Failed to send notification email '%s' to %s",
|
|
||||||
email_subject, recipient.email
|
|
||||||
)
|
|
||||||
|
|
||||||
return sent_count == len(email_recipients)
|
kwargs = {}
|
||||||
|
if getattr(settings, 'WAGTAILADMIN_NOTIFICATION_USE_HTML', False):
|
||||||
|
kwargs['html_message'] = render_to_string(template_set['html'], context)
|
||||||
|
|
||||||
|
# Send email
|
||||||
|
send_mail(email_subject, email_content, [recipient.email], connection=open_connection, **kwargs)
|
||||||
|
sent_count += 1
|
||||||
|
except Exception:
|
||||||
|
logger.exception(
|
||||||
|
"Failed to send notification email '%s' to %s",
|
||||||
|
email_subject, recipient.email
|
||||||
|
)
|
||||||
|
|
||||||
|
return sent_count == len(recipients)
|
||||||
|
|
||||||
|
def __call__(self, notifying_instance, notification, **kwargs):
|
||||||
|
"""Send emails corresponding to the notification (eg 'approved') from an instance, notifying_instance"""
|
||||||
|
|
||||||
|
if not self.can_handle(notifying_instance, notification):
|
||||||
|
return False
|
||||||
|
|
||||||
|
recipients = self.get_valid_recipients(notifying_instance, notification, **kwargs)
|
||||||
|
|
||||||
|
if not recipients:
|
||||||
|
return True
|
||||||
|
|
||||||
|
template_set = self.get_template_set(notifying_instance, notification)
|
||||||
|
|
||||||
|
context = self.get_context(notifying_instance, notification, **kwargs)
|
||||||
|
|
||||||
|
return self.send_emails(template_set, context, recipients)
|
||||||
|
|
||||||
|
|
||||||
|
class WorkflowStateNotifier(Notifier):
|
||||||
|
"""A Notifier to send updates for WorkflowState events"""
|
||||||
|
|
||||||
|
def __init__(self, valid_notifications):
|
||||||
|
super().__init__({WorkflowState}, valid_notifications)
|
||||||
|
|
||||||
|
def get_recipient_users(self, workflow_state, notification, **kwargs):
|
||||||
|
triggering_user = kwargs.get('user', None)
|
||||||
|
recipients = {}
|
||||||
|
if notification in ('approved', 'rejected'):
|
||||||
|
requested_by = workflow_state.requested_by
|
||||||
|
if requested_by != triggering_user:
|
||||||
|
recipients = {requested_by}
|
||||||
|
elif notification == 'submitted':
|
||||||
|
include_superusers = getattr(settings, 'WAGTAILADMIN_NOTIFICATION_INCLUDE_SUPERUSERS', True)
|
||||||
|
if include_superusers:
|
||||||
|
recipients = get_user_model().objects.filter(is_superuser=True)
|
||||||
|
if triggering_user:
|
||||||
|
recipients.exclude(pk=triggering_user.pk)
|
||||||
|
|
||||||
|
return recipients
|
||||||
|
|
||||||
|
def get_context(self, workflow_state, notification, **kwargs):
|
||||||
|
context = super().get_context(workflow_state, notification, **kwargs)
|
||||||
|
context['page'] = workflow_state.page
|
||||||
|
context['workflow'] = workflow_state.workflow
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class GroupApprovalTaskStateNotifier(Notifier):
|
||||||
|
"""A Notifier to send updates for GroupApprovalTask events"""
|
||||||
|
|
||||||
|
def __init__(self, valid_notifications):
|
||||||
|
super().__init__({GroupApprovalTaskState}, valid_notifications)
|
||||||
|
|
||||||
|
def get_context(self, task_state, notification, **kwargs):
|
||||||
|
context = super().get_context(task_state, notification, **kwargs)
|
||||||
|
context['page'] = task_state.revision.page
|
||||||
|
context['task'] = task_state.task.specific
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_recipient_users(self, task_state, notification, **kwargs):
|
||||||
|
triggering_user = kwargs.get('user', None)
|
||||||
|
requested_by = task_state.workflow_state.requested_by
|
||||||
|
group_members = task_state.task.specific.group.user_set
|
||||||
|
|
||||||
|
recipients = requested_by | group_members
|
||||||
|
|
||||||
|
include_superusers = getattr(settings, 'WAGTAILADMIN_NOTIFICATION_INCLUDE_SUPERUSERS', True)
|
||||||
|
if include_superusers:
|
||||||
|
superusers = get_user_model().objects.filter(is_superuser=True)
|
||||||
|
recipients = recipients | superusers
|
||||||
|
|
||||||
|
if triggering_user:
|
||||||
|
"""Exclude"""
|
||||||
|
recipients = recipients.exclude(pk=triggering_user.pk)
|
||||||
|
|
||||||
|
return recipients
|
||||||
|
Loading…
Reference in New Issue
Block a user