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

@@ -24,7 +24,7 @@ INSTALLATION
The creation of a separated python environment is very easy with the
virtualenv tool (a python package).
If you decide to not use virtualenv, proceed with step 2.
If you decide to not use virtualenv, confirm_status with step 2.
- Create the python environment in a directory called ./env/python:

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: