ADD: added support for Event Updated Mail.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
from . import signals
|
from . import signals
|
||||||
|
from . import workflow
|
||||||
from .config import AppConfig as _AppConfig, DefaultSetting
|
from .config import AppConfig as _AppConfig, DefaultSetting
|
||||||
|
|
||||||
DEFAULT_SETTINGS = (
|
DEFAULT_SETTINGS = (
|
||||||
@@ -31,7 +32,5 @@ class AppConfig(_AppConfig):
|
|||||||
default_settings = DEFAULT_SETTINGS
|
default_settings = DEFAULT_SETTINGS
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
signals.event_submitted.connect(signals.notify_submitted_event)
|
signals.event_updated.connect(workflow.email_event_update)
|
||||||
signals.event_submitted.connect(signals.notify_to_accept_event)
|
signals.event_status_updated.connect(workflow.email_event_status_update)
|
||||||
signals.event_accepted.connect(signals.notify_accepted_event)
|
|
||||||
signals.event_accepted.connect(signals.notify_to_publish_event)
|
|
||||||
@@ -21,7 +21,7 @@ class AbstractMail(object):
|
|||||||
app_config = apps.get_containing_app_config(__package__)
|
app_config = apps.get_containing_app_config(__package__)
|
||||||
if app_config.settings.email_subject_prefix:
|
if app_config.settings.email_subject_prefix:
|
||||||
s = u'%s %s' % (app_config.settings.email_subject_prefix, s)
|
s = u'%s %s' % (app_config.settings.email_subject_prefix, s)
|
||||||
s.format(**kwargs)
|
s = s.format(**kwargs)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def _get_template(self):
|
def _get_template(self):
|
||||||
@@ -64,6 +64,12 @@ class AbstractEventMail(AbstractMail):
|
|||||||
self._recipient = recipient
|
self._recipient = recipient
|
||||||
self._event = event
|
self._event = event
|
||||||
|
|
||||||
|
def _get_subject(self, **kwargs):
|
||||||
|
if 'number' not in kwargs:
|
||||||
|
kwargs['number'] = self._event.get_number()
|
||||||
|
s = super(AbstractEventMail, self)._get_subject(**kwargs)
|
||||||
|
return s
|
||||||
|
|
||||||
def _get_recipients(self):
|
def _get_recipients(self):
|
||||||
r = u'"{fullname}" <{email}>'.format(fullname=self._recipient.get_full_name(),
|
r = u'"{fullname}" <{email}>'.format(fullname=self._recipient.get_full_name(),
|
||||||
email=self._recipient.email)
|
email=self._recipient.email)
|
||||||
@@ -76,6 +82,22 @@ class AbstractEventMail(AbstractMail):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventUpdatedMail(AbstractEventMail):
|
||||||
|
_subject = u'{number}: Veranstaltung geändert'
|
||||||
|
_template_name = 'dav_events/emails/event_updated.txt'
|
||||||
|
|
||||||
|
def __init__(self, diff=None, editor=None, *args, **kwargs):
|
||||||
|
self._diff = diff
|
||||||
|
self._editor = editor
|
||||||
|
super(EventUpdatedMail, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _get_context_data(self, extra_context=None):
|
||||||
|
context = super(EventUpdatedMail, self)._get_context_data(extra_context=extra_context)
|
||||||
|
context['diff'] = self._diff
|
||||||
|
context['editor'] = self._editor.get_full_name()
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventSubmittedMail(AbstractEventMail):
|
class EventSubmittedMail(AbstractEventMail):
|
||||||
_template_name = 'dav_events/emails/event_submitted.txt'
|
_template_name = 'dav_events/emails/event_submitted.txt'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import datetime
|
import datetime
|
||||||
|
import difflib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -252,6 +253,16 @@ class Event(models.Model):
|
|||||||
internal_note = models.TextField(blank=True,
|
internal_note = models.TextField(blank=True,
|
||||||
verbose_name=_(u'Bearbeitungshinweis'))
|
verbose_name=_(u'Bearbeitungshinweis'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def editor(self):
|
||||||
|
if not hasattr(self, '_editor'):
|
||||||
|
self._editor = None
|
||||||
|
return self._editor
|
||||||
|
|
||||||
|
@editor.setter
|
||||||
|
def editor(self, editor):
|
||||||
|
self._editor = editor
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u'Veranstaltung')
|
verbose_name = _(u'Veranstaltung')
|
||||||
verbose_name_plural = _(u'Veranstaltungen')
|
verbose_name_plural = _(u'Veranstaltungen')
|
||||||
@@ -268,6 +279,7 @@ class Event(models.Model):
|
|||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
creating = False
|
creating = False
|
||||||
|
original_text = ''
|
||||||
|
|
||||||
if not self.id:
|
if not self.id:
|
||||||
user_model = get_user_model()
|
user_model = get_user_model()
|
||||||
@@ -295,27 +307,56 @@ class Event(models.Model):
|
|||||||
owner.save()
|
owner.save()
|
||||||
logger.info('Owner created: %s', owner.username)
|
logger.info('Owner created: %s', owner.username)
|
||||||
|
|
||||||
|
if self.editor and self.editor.is_authenticated and self.editor != owner:
|
||||||
|
logger.warning('Event is not created by its owner (Current user: %s, Owner: %s)!', self.editor, owner)
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
creating = True
|
creating = True
|
||||||
|
else:
|
||||||
|
original = Event.objects.get(id=self.id)
|
||||||
|
original_text = original.render_as_text()
|
||||||
|
|
||||||
|
if not self.editor or not self.editor.is_authenticated:
|
||||||
|
self.editor = self.owner
|
||||||
|
|
||||||
super(Event, self).save(**kwargs)
|
super(Event, self).save(**kwargs)
|
||||||
|
|
||||||
if creating:
|
if creating:
|
||||||
self.confirm_status('draft', self.owner)
|
|
||||||
logger.info('Event created: %s', self)
|
logger.info('Event created: %s', self)
|
||||||
|
self.confirm_status('draft', self.editor)
|
||||||
|
else:
|
||||||
|
modified_text = self.render_as_text()
|
||||||
|
o_lines = original_text.split('\n')
|
||||||
|
m_lines = modified_text.split('\n')
|
||||||
|
diff_lines = list(difflib.unified_diff(o_lines, m_lines, n=len(m_lines), lineterm=''))
|
||||||
|
diff_text = '\n'.join(diff_lines[3:])
|
||||||
|
signals.event_updated.send(sender=self.__class__, event=self, diff=diff_text, user=self.editor)
|
||||||
|
logger.info('Event updated: %s', self)
|
||||||
|
|
||||||
def update_flags(self):
|
def _internal_update(self):
|
||||||
|
if not self.id:
|
||||||
|
logger.critical('Event._internal_update() was called before Event was saved properly.')
|
||||||
|
raise Exception('Code is on fire!')
|
||||||
|
super(Event, self).save()
|
||||||
|
|
||||||
|
def update_flags(self, for_status=None):
|
||||||
if not self.id:
|
if not self.id:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if isinstance(for_status, EventStatus):
|
||||||
|
code = for_status.code
|
||||||
|
else:
|
||||||
|
code = for_status
|
||||||
|
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
midnight = datetime.time(00, 00, 00)
|
midnight = datetime.time(00, 00, 00)
|
||||||
|
|
||||||
|
if code in (None, 'draft'):
|
||||||
if not self.flags.filter(status__code='draft').exists():
|
if not self.flags.filter(status__code='draft').exists():
|
||||||
new_flag = EventFlag(event=self, status=get_event_status('draft'), timestamp=self.created_at)
|
new_flag = EventFlag(event=self, status=get_event_status('draft'), timestamp=self.created_at)
|
||||||
new_flag.save()
|
new_flag.save()
|
||||||
logger.info('Detected draft state of Event %s', self)
|
logger.info('Detected draft state of Event %s', self)
|
||||||
|
|
||||||
|
if code in (None, 'published', 'publishing'):
|
||||||
if (self.flags.filter(status__code='publishing').exists() and
|
if (self.flags.filter(status__code='publishing').exists() and
|
||||||
not self.flags.filter(status__code='published').exists()):
|
not self.flags.filter(status__code='published').exists()):
|
||||||
if not self.planned_publication_date:
|
if not self.planned_publication_date:
|
||||||
@@ -326,11 +367,13 @@ class Event(models.Model):
|
|||||||
logger.info('Detected published state of Event %s', self)
|
logger.info('Detected published state of Event %s', self)
|
||||||
elif self.planned_publication_date <= today:
|
elif self.planned_publication_date <= today:
|
||||||
new_status = get_event_status('published')
|
new_status = get_event_status('published')
|
||||||
new_timestamp = timezone.make_aware(datetime.datetime.combine(self.planned_publication_date, midnight))
|
new_timestamp = timezone.make_aware(datetime.datetime.combine(self.planned_publication_date,
|
||||||
|
midnight))
|
||||||
new_flag = EventFlag(event=self, status=new_status, timestamp=new_timestamp)
|
new_flag = EventFlag(event=self, status=new_status, timestamp=new_timestamp)
|
||||||
new_flag.save()
|
new_flag.save()
|
||||||
logger.info('Detected published state of Event %s', self)
|
logger.info('Detected published state of Event %s', self)
|
||||||
|
|
||||||
|
if code in (None, 'expired'):
|
||||||
if not self.flags.filter(status__code='expired').exists():
|
if not self.flags.filter(status__code='expired').exists():
|
||||||
expired_at = None
|
expired_at = None
|
||||||
|
|
||||||
@@ -353,7 +396,7 @@ class Event(models.Model):
|
|||||||
logger.info('Detected expired state of Event %s', self)
|
logger.info('Detected expired state of Event %s', self)
|
||||||
|
|
||||||
def is_flagged(self, status):
|
def is_flagged(self, status):
|
||||||
self.update_flags()
|
self.update_flags(status)
|
||||||
if isinstance(status, EventStatus):
|
if isinstance(status, EventStatus):
|
||||||
code = status.code
|
code = status.code
|
||||||
else:
|
else:
|
||||||
@@ -388,7 +431,7 @@ class Event(models.Model):
|
|||||||
logger.warning('Event.confirm_status(): yet not submitted event got accepted! (Event: %s)', self)
|
logger.warning('Event.confirm_status(): yet not submitted event got accepted! (Event: %s)', self)
|
||||||
if not self.number:
|
if not self.number:
|
||||||
self.number = self.get_next_number()
|
self.number = self.get_next_number()
|
||||||
self.save()
|
self._internal_update()
|
||||||
elif code == 'publishing' or code == 'published':
|
elif code == 'publishing' or code == 'published':
|
||||||
if not self.is_flagged('accepted'):
|
if not self.is_flagged('accepted'):
|
||||||
logger.warning('Event.confirm_status(): yet not accepted event got published! (Event: %s)', self)
|
logger.warning('Event.confirm_status(): yet not accepted event got published! (Event: %s)', self)
|
||||||
@@ -397,17 +440,7 @@ class Event(models.Model):
|
|||||||
flag = EventFlag(event=self, status=status_obj, user=user)
|
flag = EventFlag(event=self, status=status_obj, user=user)
|
||||||
flag.save()
|
flag.save()
|
||||||
logger.info('Flagging status \'%s\' for %s', code, self)
|
logger.info('Flagging status \'%s\' for %s', code, self)
|
||||||
|
signals.event_status_updated.send(sender=self.__class__, event=self, flag=flag)
|
||||||
if code == 'submitted':
|
|
||||||
signals.event_submitted.send(sender=self.__class__, event=self)
|
|
||||||
elif code == 'accepted':
|
|
||||||
signals.event_accepted.send(sender=self.__class__, event=self)
|
|
||||||
elif code == 'publishing':
|
|
||||||
signals.event_publishing.send(sender=self.__class__, event=self)
|
|
||||||
elif code == 'published':
|
|
||||||
signals.event_published.send(sender=self.__class__, event=self)
|
|
||||||
elif code == 'expired':
|
|
||||||
signals.event_expired.send(sender=self.__class__, event=self)
|
|
||||||
|
|
||||||
return flag
|
return flag
|
||||||
|
|
||||||
|
|||||||
@@ -1,61 +1,4 @@
|
|||||||
from django.apps import apps
|
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal
|
||||||
|
|
||||||
from . import emails
|
event_updated = Signal(providing_args=['event', 'diff', 'user'])
|
||||||
|
event_status_updated = Signal(providing_args=['event', 'flag'])
|
||||||
event_submitted = Signal(providing_args=['event'])
|
|
||||||
event_accepted = Signal(providing_args=['event'])
|
|
||||||
event_publishing = Signal(providing_args=['event'])
|
|
||||||
event_published = Signal(providing_args=['event'])
|
|
||||||
event_expired = Signal(providing_args=['event'])
|
|
||||||
|
|
||||||
|
|
||||||
def notify_submitted_event(sender, **kwargs):
|
|
||||||
event = kwargs.get('event')
|
|
||||||
app_config = apps.get_containing_app_config(__package__)
|
|
||||||
if app_config.settings.enable_email_notifications:
|
|
||||||
if event.owner.email:
|
|
||||||
email = emails.EventSubmittedMail(recipient=event.owner, event=event)
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
|
|
||||||
def notify_accepted_event(sender, **kwargs):
|
|
||||||
event = kwargs.get('event')
|
|
||||||
app_config = apps.get_containing_app_config(__package__)
|
|
||||||
if app_config.settings.enable_email_notifications:
|
|
||||||
if event.owner.email:
|
|
||||||
email = emails.EventAcceptedMail(recipient=event.owner, event=event)
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
|
|
||||||
def notify_to_accept_event(sender, **kwargs):
|
|
||||||
event = kwargs.get('event')
|
|
||||||
app_config = apps.get_containing_app_config(__package__)
|
|
||||||
if app_config.settings.enable_email_notifications:
|
|
||||||
from .utils import get_users_by_role
|
|
||||||
managers = get_users_by_role('manage_all')
|
|
||||||
managers += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
|
||||||
OneClickAction = app_config.get_model('OneClickAction')
|
|
||||||
for user in managers:
|
|
||||||
if user.email:
|
|
||||||
action = OneClickAction(command='EA')
|
|
||||||
action.parameters = '{event},{user}'.format(event=event.id, user=user.id)
|
|
||||||
action.save()
|
|
||||||
email = emails.EventToAcceptMail(recipient=user, event=event, accept_action=action)
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
|
|
||||||
def notify_to_publish_event(sender, **kwargs):
|
|
||||||
event = kwargs.get('event')
|
|
||||||
app_config = apps.get_containing_app_config(__package__)
|
|
||||||
if app_config.settings.enable_email_notifications:
|
|
||||||
from .utils import get_users_by_role
|
|
||||||
publishers = get_users_by_role('publish_incremental')
|
|
||||||
OneClickAction = app_config.get_model('OneClickAction')
|
|
||||||
for user in publishers:
|
|
||||||
if user.email:
|
|
||||||
action = OneClickAction(command='EP')
|
|
||||||
action.parameters = '{event},{user}'.format(event=event.id, user=user.id)
|
|
||||||
action.save()
|
|
||||||
email = emails.EventToPublishMail(recipient=user, event=event, confirm_publication_action=action)
|
|
||||||
email.send()
|
|
||||||
|
|||||||
14
dav_events/templates/dav_events/emails/event_updated.txt
Normal file
14
dav_events/templates/dav_events/emails/event_updated.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Hallo {{ recipient.first_name }},
|
||||||
|
|
||||||
|
{{ editor }} hat die folgende Veranstaltung geändert:
|
||||||
|
{{ event }}
|
||||||
|
|
||||||
|
Link zur Veranstaltung:
|
||||||
|
{{ base_url }}{{ event.get_absolute_url }}
|
||||||
|
|
||||||
|
Voraussichtliche Veröffentlichung: {% if planned_publication_date %}{{ planned_publication_date|date:'l, d. F Y' }}{% else %}In wenigen Tagen{% endif %}
|
||||||
|
|
||||||
|
----------
|
||||||
|
{{ diff }}----------
|
||||||
|
{% if internal_note %}Bearbeitungshinweis:
|
||||||
|
{{ internal_note }}{% endif %}
|
||||||
@@ -242,6 +242,11 @@ class EventUpdateView(EventPermissionMixin, generic.UpdateView):
|
|||||||
context['has_permission_publish'] = self.has_permission('publish', obj)
|
context['has_permission_publish'] = self.has_permission('publish', obj)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.editor = self.request.user
|
||||||
|
self.object = form.save()
|
||||||
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
return super(EventUpdateView, self).dispatch(request, *args, **kwargs)
|
return super(EventUpdateView, self).dispatch(request, *args, **kwargs)
|
||||||
@@ -298,6 +303,7 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
|
|||||||
next_form = next_form_class(request=self.request)
|
next_form = next_form_class(request=self.request)
|
||||||
return self.render_to_response(self.get_context_data(form=next_form, event=event))
|
return self.render_to_response(self.get_context_data(form=next_form, event=event))
|
||||||
else:
|
else:
|
||||||
|
event.editor = self.request.user
|
||||||
event.save()
|
event.save()
|
||||||
if 'submit' in form.data:
|
if 'submit' in form.data:
|
||||||
event.confirm_status('submitted', event.owner)
|
event.confirm_status('submitted', event.owner)
|
||||||
@@ -309,6 +315,12 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
|
|||||||
self.clean_session_data()
|
self.clean_session_data()
|
||||||
if self.request.user.is_authenticated:
|
if self.request.user.is_authenticated:
|
||||||
next_url = reverse('dav_events:event_list')
|
next_url = reverse('dav_events:event_list')
|
||||||
|
if self.request.user != event.owner:
|
||||||
|
messages.warning(self.request,
|
||||||
|
u'%s %s' % (
|
||||||
|
_(u'Du hast jemand anderen als Tourenleiter eingetragen.'),
|
||||||
|
_(u'Warum machst du sowas?')
|
||||||
|
))
|
||||||
elif owner.has_usable_password():
|
elif owner.has_usable_password():
|
||||||
next_url = reverse('dav_events:event_list')
|
next_url = reverse('dav_events:event_list')
|
||||||
else:
|
else:
|
||||||
|
|||||||
79
dav_events/workflow.py
Normal file
79
dav_events/workflow.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
from django.apps import apps
|
||||||
|
|
||||||
|
from . import emails
|
||||||
|
|
||||||
|
|
||||||
|
def email_event_update(sender, **kwargs):
|
||||||
|
event = kwargs.get('event')
|
||||||
|
diff = kwargs.get('diff')
|
||||||
|
updater = kwargs.get('user')
|
||||||
|
|
||||||
|
app_config = apps.get_containing_app_config(__package__)
|
||||||
|
if not app_config.settings.enable_email_notifications:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Who should be informed about the update?
|
||||||
|
recipients = [event.owner]
|
||||||
|
if event.is_flagged('submitted'):
|
||||||
|
# If the event is already submitted, add managers to the recipients.
|
||||||
|
from .utils import get_users_by_role
|
||||||
|
recipients += get_users_by_role('manage_all')
|
||||||
|
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
||||||
|
if event.is_flagged('accepted'):
|
||||||
|
# If the event is already published, add publishers to the recipients.
|
||||||
|
recipients += get_users_by_role('publish_incremental')
|
||||||
|
|
||||||
|
for recipient in recipients:
|
||||||
|
if recipient.email and recipient.email != updater.email:
|
||||||
|
email = emails.EventUpdatedMail(recipient=recipient, event=event, diff=diff, editor=updater)
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
|
||||||
|
def email_event_status_update(sender, **kwargs):
|
||||||
|
event = kwargs.get('event')
|
||||||
|
flag = kwargs.get('flag')
|
||||||
|
|
||||||
|
app_config = apps.get_containing_app_config(__package__)
|
||||||
|
if not app_config.settings.enable_email_notifications:
|
||||||
|
return
|
||||||
|
|
||||||
|
if flag.status.code == 'submitted':
|
||||||
|
# Inform event owner about his event (so he can keep the mail as a reminder for the event).
|
||||||
|
if event.owner.email:
|
||||||
|
email = emails.EventSubmittedMail(recipient=event.owner, event=event)
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
# Inform managers that they have to accept the event.
|
||||||
|
# Also create OneClickActions for all of them and add the link to the mail,
|
||||||
|
# so they can accept the event with a click into the mail.
|
||||||
|
from .utils import get_users_by_role
|
||||||
|
recipients = get_users_by_role('manage_all')
|
||||||
|
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
||||||
|
OneClickAction = app_config.get_model('OneClickAction')
|
||||||
|
for recipient in recipients:
|
||||||
|
if recipient.email:
|
||||||
|
action = OneClickAction(command='EA')
|
||||||
|
action.parameters = '{event},{user}'.format(event=event.id, user=recipient.id)
|
||||||
|
action.save()
|
||||||
|
email = emails.EventToAcceptMail(recipient=recipient, event=event, accept_action=action)
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
elif flag.status.code == 'accepted':
|
||||||
|
# Inform event owner about the acceptance of his event.
|
||||||
|
if event.owner.email:
|
||||||
|
email = emails.EventAcceptedMail(recipient=event.owner, event=event)
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
# Inform publishers that they have to publish the event.
|
||||||
|
# Also create OneClickActions for all of them and add the link to the mail,
|
||||||
|
# so they can confirm the publication with a click into the mail.
|
||||||
|
from .utils import get_users_by_role
|
||||||
|
recipients = get_users_by_role('publish_incremental')
|
||||||
|
OneClickAction = app_config.get_model('OneClickAction')
|
||||||
|
for recipient in recipients:
|
||||||
|
if recipient.email:
|
||||||
|
action = OneClickAction(command='EP')
|
||||||
|
action.parameters = '{event},{user}'.format(event=event.id, user=recipient.id)
|
||||||
|
action.save()
|
||||||
|
email = emails.EventToPublishMail(recipient=recipient, event=event, confirm_publication_action=action)
|
||||||
|
email.send()
|
||||||
Reference in New Issue
Block a user