CONT: fixed the previous changes.
This commit is contained in:
@@ -3,12 +3,12 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from dav_events.workflow import DEFAULT_EVENT_STATI
|
||||
from dav_events.models.eventstatus import get_or_create_event_status
|
||||
|
||||
|
||||
def create_stati(apps, schema_editor):
|
||||
l = ('draft', 'submitted', 'accepted', 'publishing', 'published', 'expired')
|
||||
for c in l:
|
||||
for c in DEFAULT_EVENT_STATI.keys():
|
||||
get_or_create_event_status(c)
|
||||
|
||||
|
||||
|
||||
@@ -250,7 +250,6 @@ class Event(models.Model):
|
||||
verbose_name = _(u'Veranstaltung')
|
||||
verbose_name_plural = _(u'Veranstaltungen')
|
||||
ordering = ['first_day']
|
||||
# default_permissions = ('view', 'edit', 'delete')
|
||||
|
||||
def __unicode__(self):
|
||||
return u'{number} - {title} ({date})'.format(number=self.get_number(),
|
||||
@@ -498,6 +497,7 @@ class Event(models.Model):
|
||||
return template.render(self.get_template_context())
|
||||
|
||||
|
||||
# TODO: can we put this into a separated file?
|
||||
class EventFlag(models.Model):
|
||||
event = models.ForeignKey(Event, related_name='flags')
|
||||
status = models.ForeignKey(EventStatus,
|
||||
@@ -510,7 +510,7 @@ class EventFlag(models.Model):
|
||||
related_name='+')
|
||||
|
||||
class Meta:
|
||||
ordering = ['event', 'status', 'timestamp']
|
||||
ordering = ['event', 'timestamp', 'status']
|
||||
|
||||
def __unicode__(self):
|
||||
s = u'{status} - {timestamp}'
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from django.db import models
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from ..validators import IdStringValidator
|
||||
@@ -26,18 +25,10 @@ class EventStatus(models.Model):
|
||||
ordering = ['severity']
|
||||
|
||||
def __unicode__(self):
|
||||
return u'{label} ({severity} - {code})'.format(code=self.code,
|
||||
return u'{severity} - {code} ({label})'.format(code=self.code,
|
||||
severity=self.severity,
|
||||
label=self.label)
|
||||
|
||||
def get_bootstrap_label(self):
|
||||
context = self.bootstrap_context or 'default'
|
||||
return format_html(u'<span class="label label-{context}">{label}</span>',
|
||||
context=context,
|
||||
label=self.label)
|
||||
#return u'<span class="label label-{context}">{label}</span>'.format(context=context,
|
||||
# label=self.label)
|
||||
|
||||
|
||||
def get_or_create_event_status(code):
|
||||
try:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right">
|
||||
{% render_event_status event show_void='False' %}
|
||||
{% render_event_status event show_void=False %}
|
||||
</div>
|
||||
<span class="panel-title">{{ number }} - {{ title }}</span>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn btn-success" href="{% url 'dav_events:confirmstatus' event.pk 'submitted' %}">
|
||||
<a class="btn btn-success" href="{% url 'dav_events:updatestatus' event.pk 'submitted' %}">
|
||||
{% bootstrap_icon 'ok' %} 
|
||||
{% trans 'Ja, alles klar!' %}
|
||||
</a>
|
||||
@@ -51,7 +51,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn btn-success" href="{% url 'dav_events:confirmstatus' event.pk 'accepted' %}">
|
||||
<a class="btn btn-success" href="{% url 'dav_events:updatestatus' event.pk 'accepted' %}">
|
||||
{% bootstrap_icon 'ok' %} 
|
||||
{% trans 'Ja, passt schon!' %}
|
||||
</a>
|
||||
@@ -84,15 +84,15 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn btn-info" href="{% if event.planned_publication_date %}{% url 'dav_events:confirmstatus' event.pk 'publishing_facebook' %}{% else %}{% url 'dav_events:confirmstatus' event.pk 'published' %}{% endif %}">
|
||||
<a class="btn btn-info" href="{% url 'dav_events:updatestatus' event.pk 'publishing_facebook' %}">
|
||||
{% bootstrap_icon 'ok' %} 
|
||||
{% trans 'Facebook' %}
|
||||
</a>
|
||||
<a class="btn btn-primary" href="{% if event.planned_publication_date %}{% url 'dav_events:confirmstatus' event.pk 'publishing_web' %}{% else %}{% url 'dav_events:confirmstatus' event.pk 'published' %}{% endif %}">
|
||||
<a class="btn btn-primary" href="{% url 'dav_events:updatestatus' event.pk 'publishing_web' %}">
|
||||
{% bootstrap_icon 'ok' %} 
|
||||
{% trans 'Webseite' %}
|
||||
</a>
|
||||
<a class="btn btn-success" href="{% if event.planned_publication_date %}{% url 'dav_events:confirmstatus' event.pk 'publishing' %}{% else %}{% url 'dav_events:confirmstatus' event.pk 'published' %}{% endif %}">
|
||||
<a class="btn btn-success" href="{% url 'dav_events:updatestatus' event.pk 'publishing' %}">
|
||||
{% bootstrap_icon 'ok' %} 
|
||||
{% trans 'Überall' %}
|
||||
</a>
|
||||
@@ -132,9 +132,9 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if has_permission_publish %}
|
||||
<a class="btn {% if is_accepted and not is_publishing %}btn-success{% else %}btn-default disabled{% endif %}"
|
||||
<a class="btn {% if is_accepted and not is_publishing and not is_published %}btn-success{% else %}btn-default disabled{% endif %}"
|
||||
data-toggle="modal" data-target="#modal-confirmpublication-dialog">
|
||||
{% if is_publishing %}
|
||||
{% if is_publishing_any %}
|
||||
{% bootstrap_icon 'check' %} 
|
||||
{% else %}
|
||||
{% bootstrap_icon 'unchecked' %} 
|
||||
@@ -171,7 +171,7 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
<div class="col-sm-7">
|
||||
<h5>Status-Log</h5>
|
||||
{% for flag in event.flags.all %}
|
||||
<div class="row">
|
||||
@@ -186,17 +186,15 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<h5>{% trans 'Veröffentlichen' %}</h5>
|
||||
<div class="col-sm-5">
|
||||
<h5>{% trans 'Veröffentlichung' %}</h5>
|
||||
{% if event.planned_publication_date %}
|
||||
{{ event.planned_publication_date|date:'l, d. F Y' }}
|
||||
{% else %}
|
||||
{% trans 'Unverzüglich' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{% if event.internal_note %}
|
||||
<h5>{% trans 'Bearbeitungshinweis' %}</h5>
|
||||
<h5 style="margin-top: 1em;">{% trans 'Bearbeitungshinweis' %}</h5>
|
||||
<div class="well well-sm"><small>{{ event.internal_note|linebreaksbr }}</small></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
{% trans 'Diese Veranstaltung ist bereits ausgelaufen.' %}
|
||||
</div>
|
||||
{% elif is_publishing %}
|
||||
{% elif is_publishing_any %}
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<strong>{% trans 'Achtung!' %}</strong> {% trans 'Diese Veranstaltung wird/wurde bereits veröffentlicht.' %}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
from django import template
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from ..models.eventstatus import get_or_create_event_status
|
||||
from ..models.eventstatus import EventStatus, get_or_create_event_status
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def render_event_status(event, show_void=True):
|
||||
label_html = u'<span class="label label-{context}">{label}</span> '
|
||||
|
||||
html = u''
|
||||
|
||||
status_list = event.workflow.get_status_list()
|
||||
@@ -15,6 +18,15 @@ def render_event_status(event, show_void=True):
|
||||
status_list = [get_or_create_event_status('void')]
|
||||
|
||||
for status in status_list:
|
||||
html += status.get_bootstrap_label()
|
||||
if isinstance(status, EventStatus):
|
||||
label = status.label
|
||||
context = status.bootstrap_context
|
||||
else:
|
||||
label = status.get('label')
|
||||
context = status.get('bootstrap_context', 'default')
|
||||
|
||||
html += format_html(label_html,
|
||||
label=label,
|
||||
context=context)
|
||||
|
||||
return mark_safe(html)
|
||||
|
||||
@@ -7,8 +7,8 @@ urlpatterns = [
|
||||
url(r'^$', views.events.EventListView.as_view(), name='list'),
|
||||
url(r'^export$', views.events.EventListExportView.as_view(), name='list_export'),
|
||||
url(r'^create$', views.events.EventCreateView.as_view(), name='create'),
|
||||
url(r'^(?P<pk>\d+)/confirm/(?P<status>[a-z0-9][a-z0-9]*)',
|
||||
views.events.EventConfirmStatusView.as_view(), name='confirmstatus'),
|
||||
url(r'^(?P<pk>\d+)/status/(?P<status>[a-z0-9._-][a-z0-9._-]*)',
|
||||
views.events.EventUpdateStatusView.as_view(), name='updatestatus'),
|
||||
url(r'^(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='update'),
|
||||
url(r'^(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='detail'),
|
||||
url(r'^action/(?P<pk>[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})/',
|
||||
|
||||
@@ -7,6 +7,8 @@ from django.db.models import Q
|
||||
app_config = apps.get_containing_app_config(__package__)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# TODO: most of the functions here are auth stuff.
|
||||
|
||||
|
||||
def get_system_user():
|
||||
return get_user_model().objects.get_or_create(username='-system-')[0]
|
||||
|
||||
@@ -148,6 +148,8 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
|
||||
context['is_submitted'] = obj.workflow.has_reached_status('submitted')
|
||||
context['is_accepted'] = obj.workflow.has_reached_status('accepted')
|
||||
context['is_publishing'] = obj.workflow.has_reached_status('publishing')
|
||||
context['is_publishing_any'] = obj.workflow.has_reached_status('publishing*')
|
||||
context['is_published'] = obj.workflow.has_reached_status('published')
|
||||
return context
|
||||
|
||||
@method_decorator(login_required)
|
||||
@@ -155,7 +157,7 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
|
||||
return super(EventDetailView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class EventConfirmStatusView(EventPermissionMixin, generic.DetailView):
|
||||
class EventUpdateStatusView(EventPermissionMixin, generic.DetailView):
|
||||
model = models.Event
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
@@ -217,6 +219,7 @@ class EventUpdateView(EventPermissionMixin, generic.UpdateView):
|
||||
context['has_permission_publish'] = self.has_permission('publish', obj)
|
||||
context['is_expired'] = obj.workflow.has_reached_status('expired')
|
||||
context['is_publishing'] = obj.workflow.has_reached_status('publishing')
|
||||
context['is_publishing_any'] = obj.workflow.has_reached_status('publishing*')
|
||||
context['is_accepted'] = obj.workflow.has_reached_status('accepted')
|
||||
return context
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ DEFAULT_EVENT_STATI = {
|
||||
'draft': (10, _(u'Entwurf'), 'info'),
|
||||
'submitted': (30, _(u'Eingereicht'), 'danger'),
|
||||
'accepted': (50, _(u'Freigegeben'), 'warning'),
|
||||
'publishing_facebook': (68, _(u'Veröffentlichung Facebook am {planned_publication_date}'), 'warning'),
|
||||
'publishing_web': (69, _(u'Veröffentlichung Web am {planned_publication_date}'), 'warning'),
|
||||
'publishing': (70, _(u'Veröffentlichung am {planned_publication_date}'), 'warning'),
|
||||
'published_facebook': (78, _(u'Veröffentlicht Facebook'), 'success'),
|
||||
'published_web': (79, _(u'Veröffentlicht Web'), 'success'),
|
||||
'publishing_facebook': (68, _(u'Veröffentlichung (Facebook)'), 'warning'),
|
||||
'publishing_web': (69, _(u'Veröffentlichung (Web)'), 'warning'),
|
||||
'publishing': (70, _(u'Veröffentlichung'), 'warning'),
|
||||
'published_facebook': (78, _(u'Veröffentlicht (Facebook)'), 'success'),
|
||||
'published_web': (79, _(u'Veröffentlicht (Web)'), 'success'),
|
||||
'published': (80, _(u'Veröffentlicht'), 'success'),
|
||||
'expired': (100, _(u'Ausgelaufen'), None),
|
||||
}
|
||||
@@ -49,10 +49,10 @@ class BasicWorkflow(object):
|
||||
year = event.first_day.year
|
||||
year_begin = datetime.date(year, 1, 1)
|
||||
year_end = datetime.date(year, 12, 31)
|
||||
qs = event.objects.filter(number__isnull=False,
|
||||
sport=event.sport,
|
||||
first_day__gte=year_begin,
|
||||
first_day__lte=year_end).order_by('number')
|
||||
qs = event.__class__.objects.filter(number__isnull=False,
|
||||
sport=event.sport,
|
||||
first_day__gte=year_begin,
|
||||
first_day__lte=year_end).order_by('number')
|
||||
last = qs.last()
|
||||
if last:
|
||||
match = re.match(r'^(?P<sport>[A-Z])(?P<count>[0-9][0-9]*)/(?P<year>[0-9][0-9]*)', last.number)
|
||||
@@ -65,6 +65,8 @@ class BasicWorkflow(object):
|
||||
event.save(implicit_update=True)
|
||||
return event.number
|
||||
|
||||
# TODO: the name/intention of this method is unclear.
|
||||
# Could we make it obsolete? At least it should be private
|
||||
def check_status(self, code=None):
|
||||
event = self._event
|
||||
if not event.id:
|
||||
@@ -104,6 +106,7 @@ class BasicWorkflow(object):
|
||||
'published_web',
|
||||
'published')).order_by('timestamp')
|
||||
|
||||
publishing = pub_flags.filter(status__code='publishing')
|
||||
publishing_web = pub_flags.filter(status__code='publishing_web')
|
||||
publishing_facebook = pub_flags.filter(status__code='publishing_facebook')
|
||||
published_web = pub_flags.filter(status__code='published_web')
|
||||
@@ -112,7 +115,7 @@ class BasicWorkflow(object):
|
||||
if not event.planned_publication_date or event.planned_publication_date <= today:
|
||||
# Event is due to be published.
|
||||
|
||||
# Timestamp of the detected action flag. No very good.
|
||||
# Timestamp of the detected action flag. No very good. TODO
|
||||
if event.planned_publication_date:
|
||||
timestamp = timezone.make_aware(datetime.datetime.combine(
|
||||
event.planned_publication_date,
|
||||
@@ -157,12 +160,13 @@ class BasicWorkflow(object):
|
||||
timestamp = pub_flags.last().timestamp
|
||||
logger.info('Detected general published state of Event %s', event)
|
||||
event.set_flag(status='published', timestamp=timestamp)
|
||||
elif publishing_web.exists() and publishing_facebook.exists():
|
||||
elif not publishing.exists() and publishing_web.exists() and publishing_facebook.exists():
|
||||
# Event is not due to be published yet,
|
||||
# does not have a general publishing flag,
|
||||
# but all publishers have confirmed the publication date,
|
||||
# so we set a general publishing flag.
|
||||
logger.info('Detected publishing state of Event %s', event)
|
||||
flags = event.flags.filter(status_code__in=('publishing_web', 'publishing_facebook'))
|
||||
flags = event.flags.filter(status__code__in=('publishing_web', 'publishing_facebook'))
|
||||
timestamp = flags.order_by('timestamp').last().timestamp
|
||||
event.set_flag(status='publishing', timestamp=timestamp)
|
||||
|
||||
@@ -190,9 +194,9 @@ class BasicWorkflow(object):
|
||||
|
||||
def has_reached_status(self, code):
|
||||
self.check_status(code)
|
||||
if code == 'publishing':
|
||||
if code == 'publishing*':
|
||||
codes = ['publishing', 'publishing_web', 'publishing_facebook']
|
||||
elif code == 'published':
|
||||
elif code == 'published*':
|
||||
codes = ['published', 'published_web', 'published_facebook']
|
||||
else:
|
||||
codes = [code]
|
||||
@@ -235,7 +239,7 @@ class BasicWorkflow(object):
|
||||
if flag:
|
||||
return flag
|
||||
|
||||
valid, return_code, message = self.validate_status_update(code, user)
|
||||
valid, return_code, message = self.validate_status_update(code)
|
||||
if not valid:
|
||||
logger.warning(u'Invalid status update to \'%s\': %s Event: %s', code, message, event)
|
||||
|
||||
@@ -251,10 +255,10 @@ class BasicWorkflow(object):
|
||||
status_list = []
|
||||
event.workflow.check_status()
|
||||
|
||||
last_flag = event.flags.last()
|
||||
if last_flag:
|
||||
flags = [last_flag]
|
||||
last_status = last_flag.status
|
||||
heaviest_flag = event.flags.order_by('status').last()
|
||||
if heaviest_flag:
|
||||
flags = []
|
||||
last_status = heaviest_flag.status
|
||||
if last_status.code.startswith('publishing_'):
|
||||
flags += event.flags.filter(status__code='accepted')
|
||||
elif last_status.code.startswith('published_'):
|
||||
@@ -262,12 +266,20 @@ class BasicWorkflow(object):
|
||||
flags += event.flags.filter(status__code='publishing')
|
||||
else:
|
||||
flags += event.flags.filter(status__code='accepted')
|
||||
flags.append(heaviest_flag)
|
||||
|
||||
deferred_publishing = event.planned_publication_date and event.planned_publication_date > today
|
||||
add_publishing_date = False
|
||||
|
||||
for flag in flags:
|
||||
format_kwargs = event.get_template_context()
|
||||
label = flag.status.label.format(**format_kwargs)
|
||||
flag.status.label = label
|
||||
status_list.append(flag.status)
|
||||
if deferred_publishing and flag.status.code.startswith('publishing'):
|
||||
add_publishing_date = True
|
||||
|
||||
if add_publishing_date:
|
||||
date_str = event.planned_publication_date.strftime('%d.%m.%Y')
|
||||
label = _(u'Veröffentlichung am {date}').format(date=date_str)
|
||||
status_list.append({'label': label})
|
||||
|
||||
return status_list
|
||||
|
||||
@@ -313,6 +325,7 @@ class BasicWorkflow(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
# TODO: is a class method a good idea?
|
||||
@classmethod
|
||||
def has_global_permission(cls, user, permission):
|
||||
if user.is_superuser:
|
||||
@@ -325,6 +338,8 @@ class BasicWorkflow(object):
|
||||
#
|
||||
# Signal handlers
|
||||
#
|
||||
# TODO: the signal handlers should not be part of the workflow class,
|
||||
# but call a method from the workflow of the particular event.
|
||||
@classmethod
|
||||
def send_emails_on_event_update(cls, sender, **kwargs):
|
||||
event = kwargs.get('event')
|
||||
@@ -344,7 +359,6 @@ class BasicWorkflow(object):
|
||||
recipients = [event.owner]
|
||||
if event.workflow.has_reached_status('submitted'):
|
||||
# If the event is already submitted, add managers to the recipients.
|
||||
recipients += get_users_by_role('manager_super')
|
||||
recipients += get_users_by_role('manager_{}'.format(event.sport.lower()))
|
||||
if event.workflow.has_reached_status('accepted'):
|
||||
# If the event is already published, add publishers to the recipients.
|
||||
@@ -375,8 +389,7 @@ class BasicWorkflow(object):
|
||||
# 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.
|
||||
recipients = get_users_by_role('manager_super')
|
||||
recipients += get_users_by_role('manager_{}'.format(event.sport.lower()))
|
||||
recipients = get_users_by_role('manager_{}'.format(event.sport.lower()))
|
||||
OneClickAction = app_config.get_model('OneClickAction')
|
||||
for recipient in recipients:
|
||||
if recipient.email:
|
||||
@@ -429,6 +442,7 @@ class BasicWorkflow(object):
|
||||
#
|
||||
# Misc logic
|
||||
#
|
||||
# TODO: is a class method a good idea?
|
||||
@classmethod
|
||||
def plan_publication(cls, first_day, deadline=None):
|
||||
app_config = apps.get_containing_app_config(__package__)
|
||||
|
||||
Reference in New Issue
Block a user