Added a model for event state (including data migration, signal based

notifications, etc.)
This commit is contained in:
2018-07-04 16:56:13 +02:00
parent 0e7c14ace9
commit 3c7ef05099
27 changed files with 712 additions and 355 deletions

View File

@@ -1,15 +1,23 @@
from django.contrib import admin
from .models import Event, OneClickAction
from .models import EventStatus, EventFlag, Event, OneClickAction
class EventAdmin(admin.ModelAdmin):
@admin.register(EventStatus)
class EventStatusAdmin(admin.ModelAdmin):
pass
class EventFlagInline(admin.TabularInline):
model = EventFlag
extra = 1
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
inlines = [EventFlagInline]
@admin.register(OneClickAction)
class OneClickActionAdmin(admin.ModelAdmin):
pass
admin.site.register(Event, EventAdmin)
admin.site.register(OneClickAction, OneClickActionAdmin)

View File

@@ -1,5 +1,6 @@
from django.core.exceptions import ImproperlyConfigured
from . import signals
from .config import AppConfig as _AppConfig, DefaultSetting
DEFAULT_SETTINGS = (
@@ -28,3 +29,9 @@ class AppConfig(_AppConfig):
name = 'dav_events'
verbose_name = u'DAV Veranstaltungen'
default_settings = DEFAULT_SETTINGS
def ready(self):
signals.event_submitted.connect(signals.notify_submitted_event)
signals.event_submitted.connect(signals.notify_to_accept_event)
signals.event_accepted.connect(signals.notify_accepted_event)
signals.event_accepted.connect(signals.notify_to_publish_event)

View File

@@ -5,38 +5,20 @@ from django.core.exceptions import ImproperlyConfigured
from django.core.mail import EmailMessage
from django.template.loader import get_template
from .utils import get_users_by_role
app_config = apps.get_containing_app_config(__package__)
logger = logging.getLogger(__name__)
def get_recipients(task, sport=None):
users = []
if task == 'accept':
role = 'manage_all'
users += get_users_by_role(role)
if sport:
role = 'manage_{}'.format(sport.lower())
users += get_users_by_role(role)
elif task == 'publish':
role = 'incremental_publisher'
users += get_users_by_role(role)
else:
raise ValueError('utils.get_recipients(): invalid value for task')
return [u'{name} <{addr}>'.format(name=u.get_full_name(), addr=u.email) for u in users]
class AbstractMail(object):
_sender = app_config.settings.email_sender
_subject = u''
_template_name = None
def _get_sender(self):
app_config = apps.get_containing_app_config(__package__)
return app_config.settings.email_sender
def _get_subject(self, **kwargs):
s = self._subject
app_config = apps.get_containing_app_config(__package__)
if app_config.settings.email_subject_prefix:
s = u'%s %s' % (app_config.settings.email_subject_prefix, s)
s.format(**kwargs)
@@ -48,6 +30,7 @@ class AbstractMail(object):
return get_template(self._template_name)
def _get_context_data(self, extra_context=None):
app_config = apps.get_containing_app_config(__package__)
context = {
'base_url': app_config.settings.email_base_url,
}
@@ -66,7 +49,7 @@ class AbstractMail(object):
def send(self):
subject = self._get_subject()
body = self._get_body()
sender = self._sender
sender = self._get_sender()
recipients = self._get_recipients()
emo = EmailMessage(subject=subject, body=body, from_email=sender, to=recipients)
@@ -92,11 +75,6 @@ class AbstractEventMail(AbstractMail):
context.update(self._event.get_template_context())
return context
def send(self):
if not app_config.settings.enable_email_notifications:
return None
return super(AbstractEventMail, self).send()
class NewEventMail(AbstractEventMail):
_template_name = 'dav_events/emails/new_event.txt'

View File

@@ -2,6 +2,7 @@ import logging
from django import forms
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
from django.db.models.manager import Manager
from .. import converters
@@ -165,8 +166,11 @@ class ModelMixin(object):
data = {}
for field in instance._meta.get_fields():
v = getattr(instance, field.name)
if v is not None:
data[field.name] = getattr(instance, field.name)
if v is None:
continue
if isinstance(v, Manager):
continue
data[field.name] = getattr(instance, field.name)
self.is_bound = True
self.data = data
return data

View File

@@ -79,7 +79,7 @@ class Migration(migrations.Migration):
('trainer_3_phone', models.CharField(blank=True, max_length=250)),
('charge', models.FloatField(default=0)),
('additional_costs', models.CharField(blank=True, max_length=250)),
('owner', models.ForeignKey(null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='events', to=settings.AUTH_USER_MODEL)),
('owner', models.ForeignKey(null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='events', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['first_day'],

View File

@@ -19,7 +19,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='event',
name='accepted_by',
field=models.ForeignKey(null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='event',

View File

@@ -22,7 +22,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='event',
name='accepted_by',
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='event',

View File

@@ -28,6 +28,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='event',
name='published_by',
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
),
]

View File

@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='event',
name='accepted_by',
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Freigegeben durch'),
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Freigegeben durch'),
),
migrations.AlterField(
model_name='event',
@@ -239,7 +239,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='event',
name='owner',
field=models.ForeignKey(null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='events', to=settings.AUTH_USER_MODEL, verbose_name='Ersteller'),
field=models.ForeignKey(null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='events', to=settings.AUTH_USER_MODEL, verbose_name='Ersteller'),
),
migrations.AlterField(
model_name='event',
@@ -269,7 +269,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='event',
name='publication_confirmed_by',
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.models.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Ver\xf6ffentlichung best\xe4tigt durch'),
field=models.ForeignKey(blank=True, null=True, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Ver\xf6ffentlichung best\xe4tigt durch'),
),
migrations.AlterField(
model_name='event',

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-07-04 12:02
from __future__ import unicode_literals
import dav_events.models.event
import dav_events.utils
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('dav_events', '0019_auto_20180306_2101'),
]
operations = [
migrations.CreateModel(
name='EventFlag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='flags', to='dav_events.Event')),
],
options={
'ordering': ['event', 'status', 'timestamp'],
},
),
migrations.CreateModel(
name='EventStatus',
fields=[
('code', models.CharField(max_length=254, primary_key=True, serialize=False, validators=[django.core.validators.RegexValidator(b'^[0-9a-z]*$', b'Only characters a-z and digits 0-9 are allowed.')])),
('severity', models.IntegerField(unique=True)),
('label', models.CharField(max_length=254, unique=True)),
('bootstrap_context', models.CharField(blank=True, choices=[(b'default', b'default'), (b'primary', b'primary'), (b'success', b'success'), (b'info', b'info'), (b'warning', b'warning'), (b'danger', b'danger')], max_length=20)),
],
options={
'ordering': ['severity'],
'verbose_name': 'Veranstaltungsstatus',
'verbose_name_plural': 'Veranstaltungsstati',
},
),
migrations.AddField(
model_name='eventflag',
name='status',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='dav_events.EventStatus'),
),
migrations.AddField(
model_name='eventflag',
name='user',
field=models.ForeignKey(default=dav_events.models.event.get_system_user_id, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
),
]

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
from dav_events.models.eventstatus import get_event_status
def create_stati(apps, schema_editor):
l = ('draft', 'submitted', 'accepted', 'publishing', 'published', 'expired')
for c in l:
get_event_status(c)
def create_flags(apps, schema_editor):
EventStatus = apps.get_model('dav_events', 'EventStatus')
EventFlag = apps.get_model('dav_events', 'EventFlag')
Event = apps.get_model('dav_events', 'Event')
for event in Event.objects.all():
if not len(event.flags.filter(status__code='draft')):
status = EventStatus.objects.get(code='draft')
flag = EventFlag(event=event, status=status, timestamp=event.created_at, user=event.owner)
flag.save()
if not len(event.flags.filter(status__code='submitted')):
status = EventStatus.objects.get(code='submitted')
flag = EventFlag(event=event, status=status, timestamp=event.created_at, user=event.owner)
flag.save()
if event.accepted and not len(event.flags.filter(status__code='accepted')):
status = EventStatus.objects.get(code='accepted')
flag = EventFlag(event=event, status=status, timestamp=event.accepted_at, user=event.accepted_by)
flag.save()
if event.publication_confirmed:
if event.planned_publication_date:
if not len(event.flags.filter(status__code='publishing')):
status = EventStatus.objects.get(code='publishing')
flag = EventFlag(event=event, status=status,
timestamp=event.publication_confirmed_at,
user=event.publication_confirmed_by)
flag.save()
else:
if not len(event.flags.filter(status__code='published')):
status = EventStatus.objects.get(code='published')
flag = EventFlag(event=event, status=status,
timestamp=event.publication_confirmed_at,
user=event.publication_confirmed_by)
flag.save()
class Migration(migrations.Migration):
dependencies = [
('dav_events', '0020_auto_20180704_1202'),
]
operations = [
migrations.RunPython(create_stati),
migrations.RunPython(create_flags),
]

View File

@@ -0,0 +1,3 @@
from .event import Event, EventFlag
from .eventstatus import EventStatus
from .oneclickaction import OneClickAction

View File

@@ -4,7 +4,6 @@ import logging
import os
import re
import unicodedata
import uuid
from babel.dates import format_date
from django.conf import settings
from django.contrib.auth import get_user_model
@@ -12,19 +11,22 @@ from django.core.urlresolvers import reverse
from django.db import models
from django.template.loader import get_template
from django.utils import timezone
from django.utils.translation import get_language, ugettext, ugettext_lazy as _
from django.utils.translation import get_language, ugettext_lazy as _
from django_countries.fields import CountryField
from . import choices
from . import config
from . import emails
from .utils import get_users_by_role
from .. import choices
from .. import config
from .. import signals
from ..utils import get_ghost_user, get_system_user
from .eventstatus import EventStatus, get_event_status
logger = logging.getLogger(__name__)
def get_ghost_user():
return get_user_model().objects.get_or_create(username='-deleted-')[0]
def get_system_user_id():
return get_system_user().id
class Event(models.Model):
@@ -294,90 +296,115 @@ class Event(models.Model):
super(Event, self).save(**kwargs)
if creating:
self.confirm_status('draft', self.owner)
logger.info('Event created: %s', self)
managers = get_users_by_role('manage_all')
managers += get_users_by_role('manage_{}'.format(self.sport.lower()))
for user in managers:
if user.email:
action = OneClickAction(command='EA')
action.parameters = '{event},{user}'.format(event=self.id, user=user.id)
action.save()
email = emails.EventToAcceptMail(recipient=user, event=self, accept_action=action)
email.send()
def update_flags(self):
if not self.id:
return
if self.owner.email:
email = emails.NewEventMail(recipient=self.owner, event=self)
email.send()
today = datetime.date.today()
midnight = datetime.time(00, 00, 00)
def accept(self, user=None):
if not self.accepted:
if not self.number:
self.number = self.get_next_number()
self.accepted = True
self.accepted_at = timezone.now()
if user:
self.accepted_by = user
else:
logger.warning('Event.accept(): no user given! (Event: %s)', self.event)
self.save()
logger.info('Event is accepted: %s', self)
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.save()
logger.info('Detected draft state of Event %s', self)
publishers = get_users_by_role('publish_incremental')
for user in publishers:
if user.email:
action = OneClickAction(command='EP')
action.parameters = '{event},{user}'.format(event=self.id, user=user.id)
action.save()
email = emails.EventToPublishMail(recipient=user, event=self, confirm_publication_action=action)
email.send()
if (self.flags.filter(status__code='publishing').exists() and
not self.flags.filter(status__code='published').exists()):
if not self.planned_publication_date:
flag = self.flags.filter(status__code='publishing').last()
new_status = get_event_status('published')
new_flag = EventFlag(event=self, status=new_status, timestamp=flag.timestamp)
new_flag.save()
logger.info('Detected published state of Event %s', self)
elif self.planned_publication_date <= today:
new_status = get_event_status('published')
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.save()
logger.info('Detected published state of Event %s', self)
if self.owner.email:
email = emails.EventAcceptedMail(recipient=self.owner, event=self)
email.send()
if not self.flags.filter(status__code='expired').exists():
expired_at = None
return self.number
if self.alt_last_day:
if self.alt_last_day < today:
expired_at = self.alt_last_day
elif self.last_day:
if self.last_day < today:
expired_at = self.last_day
elif self.alt_first_day:
if self.alt_first_day < today:
expired_at = self.alt_first_day
elif self.first_day and self.first_day < today:
expired_at = self.first_day
if expired_at:
new_timestamp = timezone.make_aware(datetime.datetime.combine(expired_at, midnight))
new_flag = EventFlag(event=self, status=get_event_status('expired'), timestamp=new_timestamp)
new_flag.save()
logger.info('Detected expired state of Event %s', self)
def is_flagged(self, status):
self.update_flags()
if isinstance(status, EventStatus):
code = status.code
else:
return None
def confirm_publication(self, user=None):
if not self.accepted:
logger.warning('Event.confirm_publication(): event is not accepted yet! (Event: %s)', self.event)
if not self.publication_confirmed:
self.publication_confirmed = True
self.publication_confirmed_at = timezone.now()
if user:
self.publication_confirmed_by = user
else:
logger.warning('Event.confirm_publication(): no user given! (Event: %s)', self.event)
self.save()
logger.info('Event is published: %s', self)
code = status
if self.flags.filter(status__code=code).exists():
return True
return False
def get_status(self):
today = datetime.date.today()
if self.alt_last_day:
if self.alt_last_day < today:
return 'expired'
elif self.last_day:
if self.last_day < today:
return 'expired'
elif self.alt_first_day:
if self.alt_first_day < today:
return 'expired'
elif self.first_day and self.first_day < today:
return 'expired'
self.update_flags()
last_flag = self.flags.last()
if last_flag:
return last_flag.status
return get_event_status('void')
if self.publication_confirmed and self.planned_publication_date and self.planned_publication_date > today:
return 'publishing'
elif self.publication_confirmed:
return 'published'
elif self.accepted:
return 'accepted'
elif self.owner:
return 'submitted'
def get_status_codes(self):
self.update_flags()
return [flag.status.code for flag in self.flags.all()]
return 'draft'
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
if code == 'accepted':
if not self.is_flagged('submitted'):
logger.warning('Event.confirm_status(): yet not submitted event got accepted! (Event: %s)', self)
if not self.number:
self.number = self.get_next_number()
self.save()
elif code == 'publishing' or code == 'published':
if not self.is_flagged('accepted'):
logger.warning('Event.confirm_status(): yet not accepted event got published! (Event: %s)', self)
status_obj = get_event_status(code)
flag = EventFlag(event=self, status=status_obj, user=user)
flag.save()
logger.info('Flagging status \'%s\' for %s', code, self)
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
def get_next_number(self):
counter = 0
@@ -576,134 +603,23 @@ class Event(models.Model):
return template.render(self.get_template_context())
class OneClickAction(models.Model):
COMMANDS = (
('EA', 'accept event'),
('EP', 'confirm publication of an event'),
('EL', 'login and go to event list')
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
allow_repeat = models.BooleanField(default=False)
done = models.BooleanField(default=False)
done_at = models.DateTimeField(blank=True,
null=True)
command = models.CharField(max_length=2, choices=COMMANDS)
parameters = models.TextField(blank=True)
class EventFlag(models.Model):
event = models.ForeignKey(Event, related_name='flags')
status = models.ForeignKey(EventStatus,
on_delete=models.PROTECT,
related_name='+')
timestamp = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(settings.AUTH_USER_MODEL,
default=get_system_user_id,
on_delete=models.SET(get_ghost_user),
related_name='+')
class Meta:
verbose_name = _(u'One-Click-Action')
ordering = ['event', 'status', 'timestamp']
def __unicode__(self):
s = u'{command}({parameters}) - {description}'.format(description=self.get_command_display(),
command=self.command,
parameters=self.parameters)
if self.done and not self.allow_repeat:
s += u' - done'
return s
def get_absolute_url(self):
return reverse('dav_events:action_run', kwargs={'pk': self.pk})
def run(self):
result = {}
if self.done and not self.allow_repeat:
result['context'] = {
'status': 'warning',
'message': ugettext(u'Diese Aktion hast du bereits ausgeführt.'),
}
return result
logger.info('OneClickAction.run(): %s(%s)', self.command, self.parameters)
if self.command == 'EA':
text = u''
try:
event_id, user_id = self.parameters.split(',')
event = Event.objects.get(id=event_id)
user = get_user_model().objects.get(id=user_id)
number = event.accept(user)
if number:
status = 'success'
message = ugettext(u'Veranstaltung freigegeben.')
text = unicode(event)
else:
status = 'info'
message = (ugettext(u'Veranstaltung wurde bereits von %(fullname)s freigegeben.') %
{'fullname': event.accepted_by.get_full_name()})
text = unicode(event)
text += u'\n'
text += (ugettext(u'Freigegeben am: %(date)s') %
{'date': event.accepted_at.strftime('%d.%m.%Y %H:%M:%S')})
self.done = True
self.done_at = timezone.now()
self.save()
except Exception as e:
status = 'danger'
message = str(e)
logger.error('OneClickAction.run(): %s(%s): %s', self.command, self.parameters, message)
result['context'] = {
'status': status,
'message': message,
'text': text,
}
elif self.command == 'EP':
text = u''
try:
event_id, user_id = self.parameters.split(',')
event = Event.objects.get(id=event_id)
user = get_user_model().objects.get(id=user_id)
if event.publication_confirmed:
status = 'info'
message = (ugettext(u'Veröffentlichung wurde bereits von %(fullname)s bestätigt.') %
{'fullname': event.publication_confirmed_by.get_full_name()})
text = unicode(event)
text += u'\n'
text += (ugettext(u'Bestätigt am: %(date)s') %
{'date': event.publication_confirmed_at.strftime('%d.%m.%Y %H:%M:%S')})
else:
event.confirm_publication(user)
status = 'success'
message = ugettext(u'Veröffentlichung registriert.')
text = unicode(event)
self.done = True
self.done_at = timezone.now()
self.save()
except Exception as e:
status = 'danger'
message = str(e)
logger.error('OneClickAction.run(): %s(%s): %s', self.command, self.parameters, message)
result['context'] = {
'status': status,
'message': message,
'text': text,
}
elif self.command == 'EL':
try:
user_id = self.parameters
user = get_user_model().objects.get(id=user_id)
url = reverse('dav_events:event_list')
result['location'] = url
result['login'] = user
except Exception as e:
message = str(e)
logger.error('OneClickAction.run(): %s(%s): %s', self.command, self.parameters, message)
result['context'] = {
'status': 'danger',
'message': message,
}
else:
result['context'] = {
'status': 'danger',
'message': ugettext(u'Invalid Command. Code on fire!'),
}
return result
s = u'{status} - {timestamp}'
if self.user:
s += u' by user {user}'
return s.format(status=self.status, timestamp=self.timestamp.strftime('%d.%m.%Y %H:%M:%S'),
user=self.user)

View File

@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.utils.translation import ugettext_lazy as _
from ..validators import LowerAlphanumericValidator
BOOTSTRAP_CONTEXT_CHOICES = (
('default', 'default'),
('primary', 'primary'),
('success', 'success'),
('info', 'info'),
('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': (70, _(u'Veröffentlichung'), 'warning'),
'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):
code = models.CharField(primary_key=True, max_length=254, validators=[LowerAlphanumericValidator])
severity = models.IntegerField(unique=True)
label = models.CharField(unique=True, max_length=254)
bootstrap_context = models.CharField(max_length=20, blank=True, choices=BOOTSTRAP_CONTEXT_CHOICES)
class Meta:
verbose_name = _(u'Veranstaltungsstatus')
verbose_name_plural = _(u'Veranstaltungsstati')
ordering = ['severity']
def __unicode__(self):
return u'{label} ({severity} {code})'.format(code=self.code,
severity=self.severity,
label=self.label)
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)

View File

@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
import logging
import uuid
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext, ugettext_lazy as _
from .event import Event
logger = logging.getLogger(__name__)
class OneClickAction(models.Model):
COMMANDS = (
('EA', 'accept event'),
('EP', 'confirm publication of an event'),
('EL', 'login and go to event list')
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
allow_repeat = models.BooleanField(default=False)
done = models.BooleanField(default=False)
done_at = models.DateTimeField(blank=True,
null=True)
command = models.CharField(max_length=2, choices=COMMANDS)
parameters = models.TextField(blank=True)
class Meta:
verbose_name = _(u'One-Click-Action')
def __unicode__(self):
s = u'{command}({parameters}) - {description}'.format(description=self.get_command_display(),
command=self.command,
parameters=self.parameters)
if self.done and not self.allow_repeat:
s += u' - done'
return s
def get_absolute_url(self):
return reverse('dav_events:action_run', kwargs={'pk': self.pk})
def run(self):
result = {}
if self.done and not self.allow_repeat:
result['context'] = {
'status': 'warning',
'message': ugettext(u'Diese Aktion hast du bereits ausgeführt.'),
}
return result
logger.info('OneClickAction.run(): %s(%s)', self.command, self.parameters)
if self.command == 'EA':
text = u''
try:
event_id, user_id = self.parameters.split(',')
event = Event.objects.get(id=event_id)
user = get_user_model().objects.get(id=user_id)
number = event.accept(user)
if number:
status = 'success'
message = ugettext(u'Veranstaltung freigegeben.')
text = unicode(event)
else:
status = 'info'
message = (ugettext(u'Veranstaltung wurde bereits von %(fullname)s freigegeben.') %
{'fullname': event.accepted_by.get_full_name()})
text = unicode(event)
text += u'\n'
text += (ugettext(u'Freigegeben am: %(date)s') %
{'date': event.accepted_at.strftime('%d.%m.%Y %H:%M:%S')})
self.done = True
self.done_at = timezone.now()
self.save()
except Exception as e:
status = 'danger'
message = str(e)
logger.error('OneClickAction.run(): %s(%s): %s', self.command, self.parameters, message)
result['context'] = {
'status': status,
'message': message,
'text': text,
}
elif self.command == 'EP':
text = u''
try:
event_id, user_id = self.parameters.split(',')
event = Event.objects.get(id=event_id)
user = get_user_model().objects.get(id=user_id)
if event.publication_confirmed:
status = 'info'
message = (ugettext(u'Veröffentlichung wurde bereits von %(fullname)s bestätigt.') %
{'fullname': event.publication_confirmed_by.get_full_name()})
text = unicode(event)
text += u'\n'
text += (ugettext(u'Bestätigt am: %(date)s') %
{'date': event.publication_confirmed_at.strftime('%d.%m.%Y %H:%M:%S')})
else:
event.confirm_publication(user)
status = 'success'
message = ugettext(u'Veröffentlichung registriert.')
text = unicode(event)
self.done = True
self.done_at = timezone.now()
self.save()
except Exception as e:
status = 'danger'
message = str(e)
logger.error('OneClickAction.run(): %s(%s): %s', self.command, self.parameters, message)
result['context'] = {
'status': status,
'message': message,
'text': text,
}
elif self.command == 'EL':
try:
user_id = self.parameters
user = get_user_model().objects.get(id=user_id)
url = reverse('dav_events:event_list')
result['location'] = url
result['login'] = user
except Exception as e:
message = str(e)
logger.error('OneClickAction.run(): %s(%s): %s', self.command, self.parameters, message)
result['context'] = {
'status': 'danger',
'message': message,
}
else:
result['context'] = {
'status': 'danger',
'message': ugettext(u'Invalid Command. Code on fire!'),
}
return result

61
dav_events/signals.py Normal file
View File

@@ -0,0 +1,61 @@
from django.apps import apps
from django.dispatch import Signal
from . import emails
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.NewEventMail(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()

View File

@@ -63,6 +63,11 @@ thead input {
margin-bottom: 1.5rem;
}
#page-body h5 {
margin-top: 0px;
font-weight: bold;
}
#page-footer {
position: absolute;
bottom: 0px;

View File

@@ -3,16 +3,11 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
{% if status == 'expired' %}
<span class="label label-info">{% trans 'Ausgelaufen' %}</span>
{% elif status == 'published' %}
<span class="label label-success">{% trans 'Veröffentlicht' %}</span>
{% elif status == 'publishing' %}
<span class="label label-warning">{% trans 'Veröffentlichung' %}: {{ event.planned_publication_date|date:'d.m.Y' }}</span>
{% elif status == 'accepted' %}
<span class="label label-warning">{% trans 'Freigegeben' %}</span>
{% elif status == 'submitted' %}
<span class="label label-danger">{% trans 'Eingereicht' %}</span>
{% if status.code != 'void' %}
{{ status.get_bootstrap_label|safe }}
{% if status.code == 'publishing' %}
<span class="label label-{{ status.bootstrap_context|default:'default' }}">{{ planned_publication_date|date:'d.m.Y' }}</span>
{% endif %}
{% endif %}
</div>
<span class="panel-title">{{ number }} - {{ title }}</span>

View File

@@ -28,9 +28,9 @@
{% endblock form-fields-visible %}
{% block form-buttons %}
{% buttons %}
<button type="submit" class="btn btn-success">
<button type="submit" name="submit" class="btn btn-success">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Einsenden' %}
{% trans 'Speichern und Einsenden' %}
</button>
<a class="btn btn-warning" href="?back">
{% bootstrap_icon 'repeat' %}&thinsp;
@@ -40,5 +40,9 @@
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</a>
<button type="submit" name="save" class="btn btn-info">
{% bootstrap_icon 'hdd' %}&thinsp;
{% trans 'Als Entwurf speichern' %}
</button>
{% endbuttons %}
{% endblock form-buttons %}

View File

@@ -5,6 +5,36 @@
{% block head-title %}{{ event }} - {{ block.super }}{% endblock head-title %}
{% block modals %}
<div id="modal-submit-dialog" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<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 'Veranstaltung einreichen?' %}</h4>
</div>
<div class="modal-body">
<p class="text-center">
<strong>{{ event }}</strong>
</p>
<p>
Die Veranstaltungsdaten werden an die Tourenreferenten und zuständigen Fachbereichsleiter
zur Freigabe weitergeleitet.<br />
Nach dem Einreichen können die Veranstaltungsdaten nicht mehr von dir geändert werden.
</p>
</div>
<div class="modal-footer">
<a class="btn btn-success" href="{% url 'dav_events:event_confirmstatus' event.pk 'submitted' %}">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Ja, alles klar!' %}
</a>
<button type="button" class="btn btn-danger" data-dismiss="modal">
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</button>
</div>
</div>
</div>
</div>
<div id="modal-accept-dialog" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
@@ -16,11 +46,14 @@
<p class="text-center">
<strong>{{ event }}</strong>
</p>
<p>
Die Veranstaltungsdaten werden an die Redaktion zur Veröffentlichung weitergeleitet.
</p>
</div>
<div class="modal-footer">
<a class="btn btn-success" href="{% url 'dav_events:event_accept' event.pk %}">
<a class="btn btn-success" href="{% url 'dav_events:event_confirmstatus' event.pk 'accepted' %}">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Ja, mach schon!' %}
{% trans 'Ja, passt schon!' %}
</a>
<button type="button" class="btn btn-danger" data-dismiss="modal">
{% bootstrap_icon 'remove' %}&thinsp;
@@ -41,9 +74,17 @@
<p class="text-center">
<strong>{{ event }}</strong>
</p>
<p class="text-center">
<strong>{% trans 'Zeitpunkt der Veröffentlichung' %}:</strong>
{% if event.planned_publication_date %}
{{ event.planned_publication_date|date:'l, d. F Y' }}
{% else %}
{% trans 'Unverzüglich' %}
{% endif %}
</p>
</div>
<div class="modal-footer">
<a class="btn btn-success" href="{% url 'dav_events:event_confirmpublication' event.pk %}">
<a class="btn btn-success" href="{% if event.planned_publication_date %}{% url 'dav_events:event_confirmstatus' event.pk 'publishing' %}{% else %}{% url 'dav_events:event_confirmstatus' event.pk 'published' %}{% endif %}">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Ja' %}
</a>
@@ -60,10 +101,21 @@
{% block page-container-fluid %}
<div class="action-tabs">
<div class="pull-right">
{% if has_permission_submit %}
<a class="btn {% if event.get_status.code == 'draft' %}btn-success{% else %}btn-default disabled{% endif %}"
data-toggle="modal" data-target="#modal-submit-dialog">
{% if 'submitted' in event.get_status_codes %}
{% bootstrap_icon 'check' %}&thinsp;
{% else %}
{% bootstrap_icon 'unchecked' %}&thinsp;
{% endif %}
{% trans 'Einreichen' %}
</a>
{% endif %}
{% if has_permission_accept %}
<a class="btn {% if event.get_status == 'submitted' %}btn-success{% else %}btn-default disabled{% endif %}"
<a class="btn {% if event.get_status.code == 'submitted' %}btn-success{% else %}btn-default disabled{% endif %}"
data-toggle="modal" data-target="#modal-accept-dialog">
{% if event.accepted %}
{% if 'accepted' in event.get_status_codes %}
{% bootstrap_icon 'check' %}&thinsp;
{% else %}
{% bootstrap_icon 'unchecked' %}&thinsp;
@@ -72,9 +124,9 @@
</a>
{% endif %}
{% if has_permission_publish %}
<a class="btn {% if event.get_status == 'accepted' %}btn-success{% else %}btn-default disabled{% endif %}"
<a class="btn {% if event.get_status.code == 'accepted' %}btn-success{% else %}btn-default disabled{% endif %}"
data-toggle="modal" data-target="#modal-confirmpublication-dialog">
{% if event.publication_confirmed %}
{% if 'publishing' in event.get_status_codes or 'published' in event.get_status_codes %}
{% bootstrap_icon 'check' %}&thinsp;
{% else %}
{% bootstrap_icon 'unchecked' %}&thinsp;
@@ -112,55 +164,22 @@
<div class="panel-body">
<div class="row">
<div class="col-sm-5">
<h5>Status-Log</h5>
{% for flag in event.flags.all %}
<div class="row">
<div class="col-sm-4">
<span class="text-danger">{% bootstrap_icon 'check' %}</span>
&thinsp;<strong>{% trans 'Eingereicht' %}:</strong>
<div class="col-sm-5">
<span class="text-{{ flag.status.bootstrap_context|default:'default' }}">{% bootstrap_icon 'check' %}</span>
<strong>{{ flag.status.label }}:</strong>
</div>
<div class="col-sm-8">
{{ event.created_at|date:'l, d. F Y, H:i' }} {% trans 'Uhr' %}<br />
{% trans 'von' %} {{ event.owner.get_full_name }}
</div>
</div>
<div class="row">
<div class="col-sm-4">
{% if event.accepted %}
<span class="text-warning">{% bootstrap_icon 'check' %}</span>
{% else %}
{% bootstrap_icon 'unchecked' %}
{% endif %}
&thinsp;<strong>{% trans 'Freigegeben' %}:</strong>
</div>
<div class="col-sm-8">
{% if event.accepted %}
{{ event.accepted_at|date:'l, d. F Y, H:i' }} {% trans 'Uhr' %}<br />
{% trans 'von' %} {{ event.accepted_by.get_full_name }}
{% else %}
<br /><br />
{% endif %}
</div>
</div>
<div class="row">
<div class="col-sm-4">
{% if event.publication_confirmed %}
<span class="text-success">{% bootstrap_icon 'check' %}</span>
{% else %}
{% bootstrap_icon 'unchecked' %}
{% endif %}
&thinsp;<strong>{% trans 'Veröffentlicht' %}:</strong>
</div>
<div class="col-sm-8">
{% if event.publication_confirmed %}
{{ event.publication_confirmed_at|date:'l, d. F Y, H:i' }} {% trans 'Uhr' %}<br />
{% trans 'von' %} {{ event.publication_confirmed_by.get_full_name }}
{% else %}
<br /><br />
{% endif %}
<div class="col-sm-7">
{{ flag.timestamp|date:'l, d. F Y, H:i' }} {% trans 'Uhr' %}<br />
{% trans 'von' %} {{ flag.user.get_full_name|default:flag.user }}
</div>
</div>
{% endfor %}
</div>
<div class="col-sm-3">
<strong>{% trans 'Veröffentlichen' %}</strong><br />
<h5>{% trans 'Veröffentlichen' %}</h5>
{% if event.planned_publication_date %}
{{ event.planned_publication_date|date:'l, d. F Y' }}
{% else %}
@@ -169,7 +188,7 @@
</div>
<div class="col-sm-4">
{% if event.internal_note %}
<strong>{% trans 'Bearbeitungshinweis' %}</strong>
<h5>{% trans 'Bearbeitungshinweis' %}</h5>
<div class="well well-sm"><small>{{ event.internal_note|linebreaksbr }}</small></div>
{% endif %}
</div>

View File

@@ -64,18 +64,9 @@
{{ event.get_numeric_date }}
</td>
<td>
{% if event.get_status == 'expired' %}
<span class="label label-info">{% trans 'Ausgelaufen' %}</span>
{% elif event.get_status == 'published' %}
<span class="label label-success">{% trans 'Veröffentlicht' %}</span>
{% elif event.get_status == 'publishing' %}
<span class="label label-warning">{% trans 'Veröffentlichung' %}: {{ event.planned_publication_date|date:'d.m.Y' }}</span>
{% elif event.get_status == 'accepted' %}
<span class="label label-warning">{% trans 'Freigegeben' %}</span>
{% elif event.get_status == 'submitted' %}
<span class="label label-danger">{% trans 'Eingereicht' %}</span>
{% else %}
<span class="label label-default">{% trans 'Kaputt' %} ({{ event.get_status }})</span>
{{ event.get_status.get_bootstrap_label|safe }}
{% if event.get_status.code == 'publishing' %}
<span class="label label-{{ event.get_status.bootstrap_context|default:'default' }}">{{ event.planned_publication_date|date:'d.m.Y' }}</span>
{% endif %}
</td>
</tr>

View File

@@ -21,18 +21,18 @@
<form action="" method="post">
{% csrf_token %}
{% if event.get_status == 'expired' %}
{% if 'expired' in event.get_status_codes %}
<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 event.get_status == 'published' or event.get_status == 'publishing' %}
{% elif 'publishing' in event.get_status_codes or 'published' in event.get_status_codes %}
<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 event.get_status == 'accepted' %}
{% elif 'accepted' in event.get_status_codes %}
<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

@@ -11,9 +11,8 @@ urlpatterns = [
url(r'^events$', views.events.EventListView.as_view(), name='event_list'),
url(r'^events/export$', views.events.EventListExportView.as_view(), name='event_list_export'),
url(r'^events/create$', views.events.EventCreateView.as_view(), name='event_create'),
url(r'^events/(?P<pk>\d+)/confirmpublication',
views.events.EventConfirmPublicationView.as_view(), name='event_confirmpublication'),
url(r'^events/(?P<pk>\d+)/accept', views.events.EventAcceptView.as_view(), name='event_accept'),
url(r'^events/(?P<pk>\d+)/confirm/(?P<status>[a-z0-9][a-z0-9]*)',
views.events.EventConfirmStatusView.as_view(), name='event_confirmstatus'),
url(r'^events/(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='event_update'),
url(r'^events/(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='event_detail'),
url(r'^action/(?P<pk>[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})/',

View File

@@ -1,11 +1,20 @@
import logging
from django.apps import apps
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
app_config = apps.get_containing_app_config(__package__)
logger = logging.getLogger(__name__)
def get_system_user():
return get_user_model().objects.get_or_create(username='-system-')[0]
def get_ghost_user():
return get_user_model().objects.get_or_create(username='-deleted-')[0]
def get_group_members(group_name, ignore_missing=False):
users = []
try:

5
dav_events/validators.py Normal file
View File

@@ -0,0 +1,5 @@
from django.core.validators import RegexValidator
AlphanumericValidator = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only characters A-Z, a-z and digits 0-9 are allowed.')
LowerAlphanumericValidator = RegexValidator(r'^[0-9a-z]*$', 'Only characters a-z and digits 0-9 are allowed.')

View File

@@ -45,7 +45,7 @@ class EventListView(generic.ListView):
filter |= Q(sport__in=user_sports_list)
if has_role(user, 'publish') or has_role(user, 'publish_incremental'):
filter |= Q(accepted=True)
filter |= Q(flags__status__code='accepted')
qs = self.model.objects.filter(filter)
@@ -89,7 +89,7 @@ class EventListExportView(generic.FormView):
txt = u''
event_qs = models.Event.objects.filter(**filter_kwargs).order_by('sport', 'first_day')
for event in event_qs:
if exclude_expired and event.get_status() == 'expired':
if exclude_expired and event.is_flagged('expired'):
continue
txt += event.render_as_text(format='ka-alpin')
if event.internal_note:
@@ -120,30 +120,38 @@ class EventPermissionMixin(object):
return True
if permission == 'view':
if obj.owner == user:
if user == obj.owner:
return True
if has_role(user, 'manage_all'):
return True
if has_role(user, 'manage_{}'.format(obj.sport.lower())):
return True
if obj.accepted and (has_role(user, 'publish') or has_role(user, 'publish_incremental')):
if has_role(user, 'publish_incremental') and obj.is_flagged('accepted'):
return True
if has_role(user, 'publish') and obj.is_flagged('accepted'):
return True
elif permission == 'submit':
if user == obj.owner:
return True
elif permission == 'accept':
if has_role(user, 'manage_all'):
return True
if has_role(user, 'manage_{}'.format(obj.sport.lower())):
return True
elif permission == 'publish':
if has_role(user, 'publish') or has_role(user, 'publish_incremental'):
return True
elif permission == 'update':
if not obj.accepted and not obj.publication_confirmed:
if not obj.is_flagged('submitted'):
if user == obj.owner:
return True
elif not obj.is_flagged('accepted'):
if has_role(user, 'manage_all'):
return True
if has_role(user, 'manage_{}'.format(obj.sport.lower())):
return True
elif has_role(user, 'publish') or has_role(user, 'publish_incremental'):
return True
elif permission == 'publish':
if has_role(user, 'publish') or has_role(user, 'publish_incremental'):
return True
return False
@@ -164,9 +172,10 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
def get_context_data(self, **kwargs):
context = super(EventDetailView, self).get_context_data(**kwargs)
obj = context.get('event')
context['has_permission_submit'] = self.has_permission('submit', obj)
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['has_permission_update'] = self.has_permission('update', obj)
return context
@method_decorator(login_required)
@@ -174,26 +183,43 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
return super(EventDetailView, self).dispatch(request, *args, **kwargs)
class EventAcceptView(EventDetailView):
permission = 'accept'
class EventConfirmStatusView(EventPermissionMixin, generic.DetailView):
model = models.Event
def get(self, request, *args, **kwargs):
status = kwargs.get('status')
event = self.get_object()
event.accept(request.user)
messages.success(request, _(u'Veranstaltung freigegeben.'))
return HttpResponseRedirect(event.get_absolute_url())
if status == 'submitted':
if not self.has_permission('submit', event):
raise PermissionDenied(status)
elif status == 'accepted':
if not self.has_permission('accept', event):
raise PermissionDenied(status)
if not event.is_flagged('submitted'):
messages.error(request, _(u'Veranstaltung ist noch nicht eingereicht.'))
return HttpResponseRedirect(event.get_absolute_url())
elif status == 'publishing' or status == 'published':
if not self.has_permission('publish', event):
raise PermissionDenied(status)
if not event.is_flagged('accepted'):
messages.error(request, _(u'Veranstaltung ist noch nicht freigegeben.'))
return HttpResponseRedirect(event.get_absolute_url())
else:
if not self.has_permission('update', event):
raise PermissionDenied(status)
class EventConfirmPublicationView(EventDetailView):
permission = 'publish'
event.confirm_status(status, request.user)
def get(self, request, *args, **kwargs):
event = self.get_object()
if event.accepted:
event.confirm_publication(request.user)
if status == 'submitted':
messages.success(request, _(u'Veranstaltung eingereicht.'))
elif status == 'accepted':
messages.success(request, _(u'Veranstaltung freigegeben.'))
elif status == 'publishing' or status == 'published':
messages.success(request, _(u'Veröffentlichung registriert.'))
else:
messages.error(request, _(u'Veranstaltung ist noch nicht freigegeben.'))
messages.success(request, _(u'Veranstaltungsstatus registriert.'))
return HttpResponseRedirect(event.get_absolute_url())
@@ -273,8 +299,12 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
return self.render_to_response(self.get_context_data(form=next_form, event=event))
else:
event.save()
if 'submit' in form.data:
event.confirm_status('submitted', event.owner)
messages.success(self.request, _(u'Veranstaltung eingereicht.'))
else:
messages.success(self.request, _(u'Veranstaltung angelegt.'))
form.flush_session_data()
messages.success(self.request, _(u'Veranstaltung angelegt.'))
owner = event.owner
self.clean_session_data()
if self.request.user.is_authenticated: