CONT: continue the previous change.
This commit is contained in:
@@ -31,6 +31,6 @@ class AppConfig(_AppConfig):
|
||||
default_settings = DEFAULT_SETTINGS
|
||||
|
||||
def ready(self):
|
||||
from .workflow import workflow
|
||||
signals.event_updated.connect(workflow.send_emails_on_event_update)
|
||||
signals.event_status_updated.connect(workflow.send_emails_on_event_status_update)
|
||||
from .workflow import DefaultWorkflow
|
||||
signals.event_updated.connect(DefaultWorkflow.send_emails_on_event_update)
|
||||
signals.event_status_updated.connect(DefaultWorkflow.send_emails_on_event_status_update)
|
||||
|
||||
@@ -13,7 +13,7 @@ from datetimewidget.widgets import DateWidget, TimeWidget, DateTimeWidget
|
||||
from .. import choices
|
||||
from .. import config
|
||||
from .. import models
|
||||
from ..workflow import workflow
|
||||
from ..workflow import DefaultWorkflow
|
||||
from .generic import ChainedForm, ModelMixin
|
||||
|
||||
app_config = apps.get_containing_app_config(__package__)
|
||||
@@ -955,7 +955,7 @@ class SummaryForm(EventCreateForm):
|
||||
deadline = None
|
||||
|
||||
first_day = self._session_data.get('first_day')
|
||||
issue_date, issue = workflow.plan_publication(first_day, deadline)
|
||||
issue_date, issue = DefaultWorkflow.plan_publication(first_day, deadline)
|
||||
if issue_date:
|
||||
self.fields['planned_publication_date'].initial = issue_date
|
||||
self.fields['planned_publication_issue'].initial = issue
|
||||
@@ -3,13 +3,13 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from dav_events.models.eventstatus import get_event_status
|
||||
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:
|
||||
get_event_status(c)
|
||||
get_or_create_event_status(c)
|
||||
|
||||
|
||||
def create_flags(apps, schema_editor):
|
||||
|
||||
@@ -19,9 +19,9 @@ from .. import choices
|
||||
from .. import config
|
||||
from .. import signals
|
||||
from ..utils import get_ghost_user, get_system_user
|
||||
from ..workflow import workflow
|
||||
from ..workflow import DefaultWorkflow
|
||||
|
||||
from .eventstatus import EventStatus, get_event_status
|
||||
from .eventstatus import EventStatus, get_or_create_event_status
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -232,6 +232,10 @@ class Event(models.Model):
|
||||
internal_note = models.TextField(blank=True,
|
||||
verbose_name=_(u'Bearbeitungshinweis'))
|
||||
|
||||
@property
|
||||
def workflow(self):
|
||||
return DefaultWorkflow(self)
|
||||
|
||||
@property
|
||||
def editor(self):
|
||||
if not hasattr(self, '_editor'):
|
||||
@@ -302,7 +306,7 @@ class Event(models.Model):
|
||||
if creating:
|
||||
logger.info('Event created: %s', self)
|
||||
signals.event_created.send(sender=self.__class__, event=self)
|
||||
self.confirm_status('draft', self.editor)
|
||||
self.workflow.update_status('draft', self.editor)
|
||||
elif not implicit_update:
|
||||
modified_text = self.render_as_text(show_internal_fields=True)
|
||||
o_lines = original_text.split('\n')
|
||||
@@ -311,9 +315,10 @@ class Event(models.Model):
|
||||
logger.info('Event updated: %s', self)
|
||||
signals.event_updated.send(sender=self.__class__, event=self, diff=diff_lines, user=self.editor)
|
||||
|
||||
# TODO: move this into workflow
|
||||
def set_flag(self, status, **kwargs):
|
||||
if not isinstance(status, EventStatus):
|
||||
status = get_event_status(status)
|
||||
status = get_or_create_event_status(status)
|
||||
kwargs['event'] = self
|
||||
kwargs['status'] = status
|
||||
flag = EventFlag(**kwargs)
|
||||
@@ -321,80 +326,8 @@ class Event(models.Model):
|
||||
logger.info('Flagging status \'%s\' for %s', status.code, self)
|
||||
return flag
|
||||
|
||||
def is_flagged(self, status):
|
||||
if isinstance(status, EventStatus):
|
||||
code = status.code
|
||||
else:
|
||||
code = status
|
||||
workflow.status_code_update(self, code)
|
||||
if self.flags.filter(status__code=code).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_status_flags(self):
|
||||
return workflow.get_status_flags(self)
|
||||
|
||||
def get_status(self):
|
||||
workflow.status_code_update(self)
|
||||
|
||||
last_flag = self.flags.last()
|
||||
if last_flag:
|
||||
return last_flag.status
|
||||
return get_event_status('void')
|
||||
|
||||
def get_status_codes(self):
|
||||
workflow.status_code_update(self)
|
||||
return [flag.status.code for flag in self.flags.all()]
|
||||
|
||||
def confirm_status(self, status, user):
|
||||
if isinstance(status, EventStatus):
|
||||
code = status.code
|
||||
else:
|
||||
code = status
|
||||
|
||||
flag = self.flags.filter(status__code=code).last()
|
||||
if flag:
|
||||
return flag
|
||||
|
||||
valid, return_code, message = workflow.validate_status_code_update(code, self)
|
||||
if not valid:
|
||||
logger.warning(u'Invalid status update to \'%s\': %s Event: %s', code, message, self)
|
||||
|
||||
flag = self.set_flag(status=code, user=user)
|
||||
|
||||
workflow.status_code_update(self, code)
|
||||
signals.event_status_updated.send(sender=self.__class__, event=self, flag=flag)
|
||||
|
||||
return flag
|
||||
|
||||
def get_number(self):
|
||||
number = workflow.get_number(self)
|
||||
if number:
|
||||
return number
|
||||
else:
|
||||
return '%s**/%d' % (self.sport, self.first_day.year % 100)
|
||||
|
||||
def set_next_number(self):
|
||||
counter = 0
|
||||
|
||||
year = self.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=self.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)
|
||||
if match:
|
||||
gd = match.groupdict()
|
||||
counter = int(gd['count'])
|
||||
|
||||
counter += 1
|
||||
self.number = '%s%02d/%d' % (self.sport, counter, year % 100)
|
||||
self.save(implicit_update=True)
|
||||
return self.number
|
||||
return self.workflow.get_number()
|
||||
|
||||
def get_formated_date(self, begin_date=None, end_date=None, format='normalized_long'):
|
||||
if begin_date is None:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.db import models
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from ..validators import IdStringValidator
|
||||
@@ -12,34 +12,6 @@ BOOTSTRAP_CONTEXT_CHOICES = (
|
||||
('warning', 'warning'),
|
||||
('danger', 'danger'),
|
||||
)
|
||||
DEFAULT_EVENT_STATI = {
|
||||
'void': (0, _(u'Ungültig'), None),
|
||||
'draft': (10, _(u'Entwurf'), 'info'),
|
||||
'submitted': (30, _(u'Eingereicht'), 'danger'),
|
||||
'accepted': (50, _(u'Freigegeben'), 'warning'),
|
||||
'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),
|
||||
}
|
||||
|
||||
|
||||
def get_event_status(code):
|
||||
try:
|
||||
obj = EventStatus.objects.get(code=code)
|
||||
except EventStatus.DoesNotExist as e:
|
||||
if code not in DEFAULT_EVENT_STATI:
|
||||
raise e
|
||||
severity = DEFAULT_EVENT_STATI[code][0]
|
||||
label = DEFAULT_EVENT_STATI[code][1]
|
||||
obj = EventStatus(code=code, severity=severity, label=label)
|
||||
if DEFAULT_EVENT_STATI[code][2]:
|
||||
obj.bootstrap_context = DEFAULT_EVENT_STATI[code][2]
|
||||
obj.save()
|
||||
return obj
|
||||
|
||||
|
||||
class EventStatus(models.Model):
|
||||
@@ -60,5 +32,24 @@ class EventStatus(models.Model):
|
||||
|
||||
def get_bootstrap_label(self):
|
||||
context = self.bootstrap_context or 'default'
|
||||
return u'<span class="label label-{context}">{label}</span>'.format(context=context,
|
||||
label=self.label)
|
||||
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:
|
||||
obj = EventStatus.objects.get(code=code)
|
||||
except EventStatus.DoesNotExist as e:
|
||||
from ..workflow import DEFAULT_EVENT_STATI
|
||||
if code not in DEFAULT_EVENT_STATI:
|
||||
raise e
|
||||
severity = DEFAULT_EVENT_STATI[code][0]
|
||||
label = DEFAULT_EVENT_STATI[code][1]
|
||||
obj = EventStatus(code=code, severity=severity, label=label)
|
||||
if DEFAULT_EVENT_STATI[code][2]:
|
||||
obj.bootstrap_context = DEFAULT_EVENT_STATI[code][2]
|
||||
obj.save()
|
||||
return obj
|
||||
|
||||
@@ -86,7 +86,7 @@ class OneClickAction(models.Model):
|
||||
'user': flag.user.get_full_name(),
|
||||
})
|
||||
else:
|
||||
flag = event.confirm_status(status_code, user)
|
||||
flag = event.workflow.update_status(status_code, user)
|
||||
message = (ugettext(u'Der Status wurde auf \'%(status)s\' gesetzt.') %
|
||||
{'status': flag.status.label})
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
{% load i18n %}
|
||||
{% load dav_events %}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right">
|
||||
{% for flag in event.get_status_flags %}
|
||||
{{ flag.status.get_bootstrap_label|safe }}
|
||||
{% if planned_publication_date and flag.status.code|slice:":10" == 'publishing' %}
|
||||
<span class="label label-{{ flag.status.bootstrap_context|default:'default' }}">{{ planned_publication_date|date:'d.m.Y' }}</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% render_event_status event show_void='False' %}
|
||||
</div>
|
||||
<span class="panel-title">{{ number }} - {{ title }}</span>
|
||||
</div>
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">{% trans 'Wird/Wurde diese Veranstaltung veröffentlicht?' %}</h4>
|
||||
<h4 class="modal-title">{% trans 'Wo wird/wurde diese Veranstaltung veröffentlicht?' %}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-center">
|
||||
@@ -84,13 +84,21 @@
|
||||
</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 %}">
|
||||
{% 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 %}">
|
||||
{% 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 %}">
|
||||
{% bootstrap_icon 'ok' %} 
|
||||
{% trans 'Ja' %}
|
||||
{% trans 'Überall' %}
|
||||
</a>
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal">
|
||||
{% bootstrap_icon 'remove' %} 
|
||||
{% trans 'Nein' %}
|
||||
{% trans 'Nirgends' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -102,9 +110,9 @@
|
||||
<div class="action-tabs">
|
||||
<div class="pull-right">
|
||||
{% if has_permission_submit %}
|
||||
<a class="btn {% if 'submitted' in event.get_status_codes %}btn-default disabled{% else %}btn-success{% endif %}"
|
||||
<a class="btn {% if not is_submitted %}btn-success{% else %}btn-default disabled{% endif %}"
|
||||
data-toggle="modal" data-target="#modal-submit-dialog">
|
||||
{% if 'submitted' in event.get_status_codes %}
|
||||
{% if is_submitted %}
|
||||
{% bootstrap_icon 'check' %} 
|
||||
{% else %}
|
||||
{% bootstrap_icon 'unchecked' %} 
|
||||
@@ -113,9 +121,9 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if has_permission_accept %}
|
||||
<a class="btn {% if 'accepted' in event.get_status_codes %}btn-default disabled{% else %}btn-success{% endif %}"
|
||||
<a class="btn {% if is_submitted and not is_accepted %}btn-success{% else %}btn-default disabled{% endif %}"
|
||||
data-toggle="modal" data-target="#modal-accept-dialog">
|
||||
{% if 'accepted' in event.get_status_codes %}
|
||||
{% if is_accepted %}
|
||||
{% bootstrap_icon 'check' %} 
|
||||
{% else %}
|
||||
{% bootstrap_icon 'unchecked' %} 
|
||||
@@ -124,9 +132,9 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if has_permission_publish %}
|
||||
<a class="btn {% if event.get_status.code == 'accepted' %}btn-success{% else %}btn-default disabled{% endif %}"
|
||||
<a class="btn {% if is_accepted and not is_publishing %}btn-success{% else %}btn-default disabled{% endif %}"
|
||||
data-toggle="modal" data-target="#modal-confirmpublication-dialog">
|
||||
{% if 'publishing' in event.get_status_codes or 'published' in event.get_status_codes %}
|
||||
{% if is_publishing %}
|
||||
{% bootstrap_icon 'check' %} 
|
||||
{% else %}
|
||||
{% bootstrap_icon 'unchecked' %} 
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% extends 'dav_events/base.html' %}
|
||||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
{% load dav_events %}
|
||||
|
||||
{% block page-container-fluid %}
|
||||
<div class="action-tabs">
|
||||
@@ -43,11 +44,13 @@
|
||||
<tbody>
|
||||
{% for event in event_list %}
|
||||
<tr>
|
||||
<td data-order="{{ event.get_number|slice:':1' }}{{ event.get_number|slice:'-2:' }}{{ event.get_number|slice:'1:-2'|cut:'/' }}"
|
||||
data-search="{{ event.get_number }} ({{ event.get_sport_display }})">
|
||||
<a href="{% url 'dav_events:detail' event.pk %}">{{ event.get_number }}</a><br />
|
||||
{% with number=event.get_number %}
|
||||
<td data-order="{{ number|slice:':1' }}{{ number|slice:'-2:' }}{{ number|slice:'1:-2'|cut:'/' }}"
|
||||
data-search="{{ number }} ({{ event.get_sport_display }})">
|
||||
<a href="{% url 'dav_events:detail' event.pk %}">{{ number }}</a><br />
|
||||
<small>({{ event.get_sport_display }})</small>
|
||||
</td>
|
||||
{% endwith %}
|
||||
<td>
|
||||
<a href="{% url 'dav_events:detail' event.pk %}">{{ event.title }}</a>
|
||||
</td>
|
||||
@@ -65,14 +68,7 @@
|
||||
{{ event.get_numeric_date }}
|
||||
</td>
|
||||
<td>
|
||||
{% for flag in event.get_status_flags %}
|
||||
{{ flag.status.get_bootstrap_label|safe }}
|
||||
{% if event.planned_publication_date and flag.status.code|slice:':10' == 'publishing' %}
|
||||
<span class="label label-{{ flag.status.bootstrap_context|default:'default' }}">{{ event.planned_publication_date|date:'d.m.Y' }}</span>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
{{ event.get_status.get_bootstrap_label|safe }}
|
||||
{% endfor %}
|
||||
{% render_event_status event %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -21,18 +21,18 @@
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% if 'expired' in event.get_status_codes %}
|
||||
{% if is_expired %}
|
||||
<div class="alert alert-info alert-dismissible" role="alert">
|
||||
<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 'publishing' in event.get_status_codes or 'published' in event.get_status_codes %}
|
||||
{% elif is_publishing %}
|
||||
<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.' %}
|
||||
{% trans 'Änderungen müssen mit allen Beteiligten abgesprochen werden.' %}
|
||||
</div>
|
||||
{% elif 'accepted' in event.get_status_codes %}
|
||||
{% elif is_accepted %}
|
||||
<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 wurde bereits freigegeben.' %}
|
||||
|
||||
0
dav_events/templatetags/__init__.py
Normal file
0
dav_events/templatetags/__init__.py
Normal file
20
dav_events/templatetags/dav_events.py
Normal file
20
dav_events/templatetags/dav_events.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from ..models.eventstatus import get_or_create_event_status
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def render_event_status(event, show_void=True):
|
||||
html = u''
|
||||
|
||||
status_list = event.workflow.get_status_list()
|
||||
if show_void and len(status_list) < 1:
|
||||
status_list = [get_or_create_event_status('void')]
|
||||
|
||||
for status in status_list:
|
||||
html += status.get_bootstrap_label()
|
||||
|
||||
return mark_safe(html)
|
||||
@@ -19,7 +19,7 @@ from .. import choices
|
||||
from .. import forms
|
||||
from .. import models
|
||||
from ..utils import has_role
|
||||
from ..workflow import workflow
|
||||
from ..workflow import DefaultWorkflow
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -54,7 +54,7 @@ class EventListView(generic.ListView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventListView, self).get_context_data(**kwargs)
|
||||
user = self.request.user
|
||||
context['has_permission_export'] = workflow.has_global_permission(user, 'export')
|
||||
context['has_permission_export'] = DefaultWorkflow.has_global_permission(user, 'export')
|
||||
return context
|
||||
|
||||
@method_decorator(login_required)
|
||||
@@ -112,7 +112,7 @@ class EventListExportView(generic.FormView):
|
||||
@method_decorator(login_required)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
user = request.user
|
||||
if not workflow.has_global_permission(user, 'export'):
|
||||
if not DefaultWorkflow.has_global_permission(user, 'export'):
|
||||
raise PermissionDenied('export')
|
||||
return super(EventListExportView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
@@ -122,7 +122,7 @@ class EventPermissionMixin(object):
|
||||
|
||||
def has_permission(self, permission, obj):
|
||||
user = self.request.user
|
||||
return workflow.has_object_permission(user, permission, obj)
|
||||
return obj.workflow.has_permission(user, permission)
|
||||
|
||||
def enforce_permission(self, obj):
|
||||
permission = self.permission
|
||||
@@ -145,6 +145,9 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
|
||||
context['has_permission_accept'] = self.has_permission('accept', obj)
|
||||
context['has_permission_publish'] = self.has_permission('publish', obj)
|
||||
context['has_permission_update'] = self.has_permission('update', obj)
|
||||
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')
|
||||
return context
|
||||
|
||||
@method_decorator(login_required)
|
||||
@@ -172,7 +175,7 @@ class EventConfirmStatusView(EventPermissionMixin, generic.DetailView):
|
||||
if not self.has_permission('update', event):
|
||||
raise PermissionDenied(status)
|
||||
|
||||
valid, return_code, message = workflow.validate_status_code_update(status, event)
|
||||
valid, return_code, message = event.workflow.validate_status_update(status)
|
||||
if not valid:
|
||||
if return_code == 'not-submitted':
|
||||
message = _(u'Veranstaltung ist noch nicht eingereicht.')
|
||||
@@ -181,7 +184,7 @@ class EventConfirmStatusView(EventPermissionMixin, generic.DetailView):
|
||||
messages.error(request, message)
|
||||
return HttpResponseRedirect(event.get_absolute_url())
|
||||
|
||||
event.confirm_status(status, request.user)
|
||||
event.workflow.update_status(status, request.user)
|
||||
|
||||
if status.startswith('submit'):
|
||||
messages.success(request, _(u'Veranstaltung eingereicht.'))
|
||||
@@ -212,6 +215,9 @@ class EventUpdateView(EventPermissionMixin, generic.UpdateView):
|
||||
context['has_permission_accept'] = self.has_permission('accept', obj)
|
||||
context['has_permission_update'] = self.has_permission('update', obj)
|
||||
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_accepted'] = obj.workflow.has_reached_status('accepted')
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
@@ -278,7 +284,7 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
|
||||
event.editor = self.request.user
|
||||
event.save()
|
||||
if 'submit' in form.data:
|
||||
event.confirm_status('submitted', event.owner)
|
||||
event.workflow.update_status('submitted', event.owner)
|
||||
messages.success(self.request, _(u'Veranstaltung eingereicht.'))
|
||||
else:
|
||||
messages.success(self.request, _(u'Veranstaltung angelegt.'))
|
||||
|
||||
@@ -1,50 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
import logging
|
||||
import re
|
||||
from django.apps import apps
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from . import emails
|
||||
from . import signals
|
||||
from .utils import get_users_by_role, has_role
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
today = datetime.date.today()
|
||||
|
||||
DEFAULT_EVENT_STATI = {
|
||||
'void': (0, _(u'Ungültig'), None),
|
||||
'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'),
|
||||
'published': (80, _(u'Veröffentlicht'), 'success'),
|
||||
'expired': (100, _(u'Ausgelaufen'), None),
|
||||
}
|
||||
|
||||
|
||||
class BasicWorkflow(object):
|
||||
#
|
||||
# Status updates
|
||||
#
|
||||
@classmethod
|
||||
def validate_status_code_update(cls, code, event, callback=None, *args, **kwargs):
|
||||
valid = True
|
||||
return_code = 'OK'
|
||||
message = u'OK'
|
||||
if code.startswith('accept'):
|
||||
if not event.is_flagged('submitted'):
|
||||
valid = False
|
||||
return_code = 'not-submitted'
|
||||
message = u'Event is not submitted.'
|
||||
elif code.startswith('publishing'):
|
||||
if not event.is_flagged('accepted'):
|
||||
valid = False
|
||||
return_code = 'not-accepted'
|
||||
message = u'Event is not accepted.'
|
||||
elif code.startswith('published'):
|
||||
if event.planned_publication_date and event.planned_publication_date > today:
|
||||
valid = False
|
||||
return_code = 'not-due'
|
||||
message = u'Event is not due to publication.'
|
||||
elif not event.is_flagged('accepted'):
|
||||
valid = False
|
||||
return_code = 'not-accepted'
|
||||
message = u'Event is not accepted.'
|
||||
def __init__(self, event=None):
|
||||
self._event = event
|
||||
|
||||
if callback is not None:
|
||||
callback(valid, return_code, message, *args, **kwargs)
|
||||
return valid, return_code, message
|
||||
#
|
||||
# Status
|
||||
#
|
||||
def get_number(self):
|
||||
event = self._event
|
||||
if event.number and event.flags.filter(status__code='accepted').exists():
|
||||
return event.number
|
||||
else:
|
||||
return '%s**/%d' % (event.sport, event.first_day.year % 100)
|
||||
|
||||
@classmethod
|
||||
def status_code_update(cls, event, code=None):
|
||||
def set_number(self):
|
||||
event = self._event
|
||||
counter = 0
|
||||
|
||||
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')
|
||||
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)
|
||||
if match:
|
||||
gd = match.groupdict()
|
||||
counter = int(gd['count'])
|
||||
|
||||
counter += 1
|
||||
event.number = '%s%02d/%d' % (event.sport, counter, year % 100)
|
||||
event.save(implicit_update=True)
|
||||
return event.number
|
||||
|
||||
def check_status(self, code=None):
|
||||
event = self._event
|
||||
if not event.id:
|
||||
return
|
||||
|
||||
@@ -60,7 +82,7 @@ class BasicWorkflow(object):
|
||||
# Check if event with accepted flag has a number.
|
||||
if event.flags.filter(status__code='accepted').exists():
|
||||
if not event.number:
|
||||
event.set_next_number()
|
||||
self.set_number()
|
||||
logger.info('Setting number on Event %s', event)
|
||||
|
||||
if code in (None,
|
||||
@@ -166,36 +188,131 @@ class BasicWorkflow(object):
|
||||
timestamp = timezone.make_aware(datetime.datetime.combine(expired_at, midnight))
|
||||
event.set_flag(status='expired', timestamp=timestamp)
|
||||
|
||||
@classmethod
|
||||
def get_status_flags(cls, event):
|
||||
cls.status_code_update(event)
|
||||
last_flag = event.flags.last()
|
||||
if not last_flag:
|
||||
#last_flag = event.set_flag('void')
|
||||
return []
|
||||
flags = [last_flag]
|
||||
|
||||
last_status = last_flag.status
|
||||
if last_status.code.startswith('publishing_'):
|
||||
flags += event.flags.filter(status__code='accepted')
|
||||
elif last_status.code.startswith('published_'):
|
||||
if event.is_flagged('publishing'):
|
||||
flags += event.flags.filter(status__code='publishing')
|
||||
else:
|
||||
flags += event.flags.filter(status__code='accepted')
|
||||
|
||||
return flags
|
||||
|
||||
@classmethod
|
||||
def get_number(cls, event):
|
||||
if event.number and event.flags.filter(status__code='accepted').exists():
|
||||
return event.number
|
||||
def has_reached_status(self, code):
|
||||
self.check_status(code)
|
||||
if code == 'publishing':
|
||||
codes = ['publishing', 'publishing_web', 'publishing_facebook']
|
||||
elif code == 'published':
|
||||
codes = ['published', 'published_web', 'published_facebook']
|
||||
else:
|
||||
return None
|
||||
codes = [code]
|
||||
return self._event.flags.filter(status__code__in=codes).exists()
|
||||
|
||||
def validate_status_update(self, code, callback=None, *args, **kwargs):
|
||||
valid = True
|
||||
return_code = 'OK'
|
||||
message = u'OK'
|
||||
|
||||
event = self._event
|
||||
if code.startswith('accept'):
|
||||
if not self.has_reached_status('submitted'):
|
||||
valid = False
|
||||
return_code = 'not-submitted'
|
||||
message = u'Event is not submitted.'
|
||||
elif code.startswith('publishing'):
|
||||
if not self.has_reached_status('accepted'):
|
||||
valid = False
|
||||
return_code = 'not-accepted'
|
||||
message = u'Event is not accepted.'
|
||||
elif code.startswith('published'):
|
||||
if event.planned_publication_date and event.planned_publication_date > today:
|
||||
valid = False
|
||||
return_code = 'not-due'
|
||||
message = u'Event is not due to publication.'
|
||||
elif not self.has_reached_status('accepted'):
|
||||
valid = False
|
||||
return_code = 'not-accepted'
|
||||
message = u'Event is not accepted.'
|
||||
|
||||
if callback is not None:
|
||||
callback(valid, return_code, message, *args, **kwargs)
|
||||
return valid, return_code, message
|
||||
|
||||
def update_status(self, code, user):
|
||||
event = self._event
|
||||
|
||||
flag = event.flags.filter(status__code=code).last()
|
||||
if flag:
|
||||
return flag
|
||||
|
||||
valid, return_code, message = self.validate_status_update(code, user)
|
||||
if not valid:
|
||||
logger.warning(u'Invalid status update to \'%s\': %s Event: %s', code, message, event)
|
||||
|
||||
flag = event.set_flag(status=code, user=user)
|
||||
self.check_status(code)
|
||||
signals.event_status_updated.send(sender=self.__class__, event=event, flag=flag)
|
||||
|
||||
return flag
|
||||
|
||||
def get_status_list(self):
|
||||
event = self._event
|
||||
|
||||
status_list = []
|
||||
event.workflow.check_status()
|
||||
|
||||
last_flag = event.flags.last()
|
||||
if last_flag:
|
||||
flags = [last_flag]
|
||||
last_status = last_flag.status
|
||||
if last_status.code.startswith('publishing_'):
|
||||
flags += event.flags.filter(status__code='accepted')
|
||||
elif last_status.code.startswith('published_'):
|
||||
if event.flags.filter(status__code='publishing').exists():
|
||||
flags += event.flags.filter(status__code='publishing')
|
||||
else:
|
||||
flags += event.flags.filter(status__code='accepted')
|
||||
|
||||
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)
|
||||
|
||||
return status_list
|
||||
|
||||
#
|
||||
# Permissions
|
||||
# Permission
|
||||
#
|
||||
def has_permission(self, user, permission):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
event = self._event
|
||||
|
||||
if permission == 'view':
|
||||
if user == event.owner:
|
||||
return True
|
||||
if has_role(user, 'manager_super'):
|
||||
return True
|
||||
if has_role(user, 'manager_{}'.format(event.sport.lower())):
|
||||
return True
|
||||
if has_role(user, 'publisher') and self.has_reached_status('accepted'):
|
||||
return True
|
||||
elif permission == 'submit':
|
||||
if user == event.owner:
|
||||
return True
|
||||
elif permission == 'accept':
|
||||
if has_role(user, 'manager_super'):
|
||||
return True
|
||||
if has_role(user, 'manager_{}'.format(event.sport.lower())):
|
||||
return True
|
||||
elif permission == 'publish':
|
||||
if has_role(user, 'publisher'):
|
||||
return True
|
||||
elif permission == 'update':
|
||||
if not self.has_reached_status('submitted'):
|
||||
if user == event.owner:
|
||||
return True
|
||||
elif not self.has_reached_status('accepted'):
|
||||
if has_role(user, 'manager_super'):
|
||||
return True
|
||||
if has_role(user, 'manager_{}'.format(event.sport.lower())):
|
||||
return True
|
||||
elif has_role(user, 'publisher'):
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def has_global_permission(cls, user, permission):
|
||||
if user.is_superuser:
|
||||
@@ -205,44 +322,6 @@ class BasicWorkflow(object):
|
||||
return has_role(user, 'publisher')
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def has_object_permission(cls, user, permission, obj):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
if permission == 'view':
|
||||
if user == obj.owner:
|
||||
return True
|
||||
if has_role(user, 'manager_super'):
|
||||
return True
|
||||
if has_role(user, 'manager_{}'.format(obj.sport.lower())):
|
||||
return True
|
||||
if has_role(user, 'publisher') and obj.is_flagged('accepted'):
|
||||
return True
|
||||
elif permission == 'submit':
|
||||
if user == obj.owner:
|
||||
return True
|
||||
elif permission == 'accept':
|
||||
if has_role(user, 'manager_super'):
|
||||
return True
|
||||
if has_role(user, 'manager_{}'.format(obj.sport.lower())):
|
||||
return True
|
||||
elif permission == 'publish':
|
||||
if has_role(user, 'publisher'):
|
||||
return True
|
||||
elif permission == 'update':
|
||||
if not obj.is_flagged('submitted'):
|
||||
if user == obj.owner:
|
||||
return True
|
||||
elif not obj.is_flagged('accepted'):
|
||||
if has_role(user, 'manager_super'):
|
||||
return True
|
||||
if has_role(user, 'manager_{}'.format(obj.sport.lower())):
|
||||
return True
|
||||
elif has_role(user, 'publisher'):
|
||||
return True
|
||||
return False
|
||||
|
||||
#
|
||||
# Signal handlers
|
||||
#
|
||||
@@ -263,11 +342,11 @@ class BasicWorkflow(object):
|
||||
|
||||
# Who should be informed about the update?
|
||||
recipients = [event.owner]
|
||||
if event.is_flagged('submitted'):
|
||||
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.is_flagged('accepted'):
|
||||
if event.workflow.has_reached_status('accepted'):
|
||||
# If the event is already published, add publishers to the recipients.
|
||||
recipients += get_users_by_role('publisher_web')
|
||||
recipients += get_users_by_role('publisher_facebook')
|
||||
@@ -379,4 +458,4 @@ class BasicWorkflow(object):
|
||||
return None, None
|
||||
|
||||
|
||||
workflow = BasicWorkflow
|
||||
DefaultWorkflow = BasicWorkflow
|
||||
|
||||
Reference in New Issue
Block a user