CONT: continue the previous change.

This commit is contained in:
2019-01-29 17:25:03 +01:00
parent e6a5f9818a
commit 7667277862
14 changed files with 281 additions and 252 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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):

View File

@@ -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:

View File

@@ -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

View File

@@ -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})

View File

@@ -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>

View File

@@ -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">&times;</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' %}&thinsp;
{% 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' %}&thinsp;
{% 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' %}&thinsp;
{% trans 'Ja' %}
{% trans 'Überall' %}
</a>
<button type="button" class="btn btn-danger" data-dismiss="modal">
{% bootstrap_icon 'remove' %}&thinsp;
{% 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' %}&thinsp;
{% else %}
{% bootstrap_icon 'unchecked' %}&thinsp;
@@ -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' %}&thinsp;
{% else %}
{% bootstrap_icon 'unchecked' %}&thinsp;
@@ -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' %}&thinsp;
{% else %}
{% bootstrap_icon 'unchecked' %}&thinsp;

View File

@@ -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 %}

View File

@@ -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">&times;</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">&times;</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">&times;</span></button>
<strong>{% trans 'Achtung!' %}</strong> {% trans 'Diese Veranstaltung wurde bereits freigegeben.' %}

View File

View 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)

View File

@@ -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.'))

View File

@@ -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