UPD: dav_events: decoupled event model and eventflag model.

This commit is contained in:
2019-02-18 15:57:09 +01:00
parent a62d573b98
commit 6e1a07f3f6
5 changed files with 96 additions and 86 deletions

View File

@@ -52,6 +52,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='eventflag', model_name='eventflag',
name='user', 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), field=models.ForeignKey(default=dav_events.models.eventflag.get_system_user_id, on_delete=models.SET(dav_events.utils.get_ghost_user), related_name='+', to=settings.AUTH_USER_MODEL),
), ),
] ]

View File

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

View File

@@ -11,26 +11,22 @@ from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.template.loader import get_template from django.template.loader import get_template
from django.utils import timezone
from django.utils.translation import get_language, ugettext_lazy as _ from django.utils.translation import get_language, ugettext_lazy as _
from django_countries.fields import CountryField from django_countries.fields import CountryField
from .. import choices from .. import choices
from .. import config from .. import config
from .. import signals from .. import signals
from ..utils import get_ghost_user, get_system_user from ..utils import get_ghost_user
from ..workflow import DefaultWorkflow from ..workflow import DefaultWorkflow
from .eventflag import EventFlag
from .eventstatus import EventStatus, get_or_create_event_status from .eventstatus import EventStatus, get_or_create_event_status
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_system_user_id():
return get_system_user().id
class Event(models.Model): class Event(models.Model):
# Metadata # Metadata
owner = models.ForeignKey(settings.AUTH_USER_MODEL, owner = models.ForeignKey(settings.AUTH_USER_MODEL,
@@ -314,17 +310,6 @@ class Event(models.Model):
logger.info('Event updated: %s', self) logger.info('Event updated: %s', self)
signals.event_updated.send(sender=self.__class__, event=self, diff=diff_lines, user=self.editor) signals.event_updated.send(sender=self.__class__, event=self, diff=diff_lines, user=self.editor)
# TODO: move this into workflow
def set_flag(self, status, **kwargs):
if not isinstance(status, EventStatus):
status = get_or_create_event_status(status)
kwargs['event'] = self
kwargs['status'] = status
flag = EventFlag(**kwargs)
flag.save()
logger.info('Flagging status \'%s\' for %s', status.code, self)
return flag
def get_number(self): def get_number(self):
return self.workflow.get_number() return self.workflow.get_number()
@@ -495,26 +480,3 @@ class Event(models.Model):
template_name = os.path.join('dav_events', 'event', 'default.html') template_name = os.path.join('dav_events', 'event', 'default.html')
template = get_template(template_name) template = get_template(template_name)
return template.render(self.get_template_context()) return template.render(self.get_template_context())
# TODO: can we put this into a separated file?
class EventFlag(models.Model):
event = models.ForeignKey(Event, related_name='flags')
status = models.ForeignKey(EventStatus,
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:
ordering = ['event', 'timestamp', 'status']
def __unicode__(self):
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,31 @@
from django.conf import settings
from django.db import models
from django.utils import timezone
from ..utils import get_ghost_user, get_system_user
def get_system_user_id():
return get_system_user().id
class EventFlag(models.Model):
event = models.ForeignKey('dav_events.Event', related_name='flags')
status = models.ForeignKey('dav_events.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:
ordering = ['event', 'timestamp', 'status']
def __unicode__(self):
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

@@ -8,6 +8,8 @@ from django.utils.translation import ugettext_lazy as _
from . import emails from . import emails
from . import signals from . import signals
from .models.eventflag import EventFlag
from .models.eventstatus import get_or_create_event_status
from .utils import get_users_by_role, has_role from .utils import get_users_by_role, has_role
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -35,39 +37,20 @@ class BasicWorkflow(object):
# #
# Status changes # Status changes
# #
def get_number(self):
# We use EventFlags to store the status information
def _add_flag(self, code, **kwargs):
event = self._event event = self._event
if event.number and event.flags.filter(status__code='accepted').exists(): status = get_or_create_event_status(code)
return event.number kwargs['event'] = event
else: kwargs['status'] = status
return '%s**/%d' % (event.sport, event.first_day.year % 100) flag = EventFlag(**kwargs)
flag.save()
logger.info('Flagging status \'%s\' for %s', status.code, event)
return flag
def set_number(self): # TODO: the name/intention of this method is unclear. Could we make it obsolete?
event = self._event def _check_status(self, code=None):
counter = 0
year = event.first_day.year
year_begin = datetime.date(year, 1, 1)
year_end = datetime.date(year, 12, 31)
qs = event.__class__.objects.filter(number__isnull=False,
sport=event.sport,
first_day__gte=year_begin,
first_day__lte=year_end).order_by('number')
last = qs.last()
if last:
match = re.match(r'^(?P<sport>[A-Z])(?P<count>[0-9][0-9]*)/(?P<year>[0-9][0-9]*)', last.number)
if match:
gd = match.groupdict()
counter = int(gd['count'])
counter += 1
event.number = '%s%02d/%d' % (event.sport, counter, year % 100)
event.save(implicit_update=True)
return event.number
# TODO: the name/intention of this method is unclear.
# Could we make it obsolete? At least it should be private
def check_status(self, code=None):
event = self._event event = self._event
if not event.id: if not event.id:
return return
@@ -78,7 +61,7 @@ class BasicWorkflow(object):
# Check if event has a draft flag. # Check if event has a draft flag.
if not event.flags.filter(status__code='draft').exists(): if not event.flags.filter(status__code='draft').exists():
logger.info('Detected draft state of Event %s', event) logger.info('Detected draft state of Event %s', event)
event.set_flag(status='draft', timestamp=event.created_at) self._add_flag('draft', timestamp=event.created_at)
if code in (None, 'accepted'): if code in (None, 'accepted'):
# Check if event with accepted flag has a number. # Check if event with accepted flag has a number.
@@ -130,7 +113,7 @@ class BasicWorkflow(object):
if not timestamp: if not timestamp:
timestamp = event.flags.filter(status__code='publishing').last().timestamp timestamp = event.flags.filter(status__code='publishing').last().timestamp
logger.info('Detected published state of Event %s', event) logger.info('Detected published state of Event %s', event)
event.set_flag(status='published', timestamp=timestamp) self._add_flag('published', timestamp=timestamp)
elif ((publishing_web.exists() or published_web.exists()) and elif ((publishing_web.exists() or published_web.exists()) and
(publishing_facebook.exists() or published_facebook.exists())): (publishing_facebook.exists() or published_facebook.exists())):
# All publishers have confirmed the publication date or have published already # All publishers have confirmed the publication date or have published already
@@ -138,7 +121,7 @@ class BasicWorkflow(object):
if not timestamp: if not timestamp:
timestamp = pub_flags.last().timestamp timestamp = pub_flags.last().timestamp
logger.info('Detected general published state of Event %s', event) logger.info('Detected general published state of Event %s', event)
event.set_flag(status='published', timestamp=timestamp) self._add_flag('published', timestamp=timestamp)
else: else:
if publishing_web.exists() and not published_web.exists(): if publishing_web.exists() and not published_web.exists():
# One publisher has confirmed the publication date, # One publisher has confirmed the publication date,
@@ -146,20 +129,20 @@ class BasicWorkflow(object):
if not timestamp: if not timestamp:
timestamp = event.flags.filter(status__code='publishing_web').last().timestamp timestamp = event.flags.filter(status__code='publishing_web').last().timestamp
logger.info('Detected published_web state of Event %s', event) logger.info('Detected published_web state of Event %s', event)
event.set_flag(status='published_web', timestamp=timestamp) self._add_flag('published_web', timestamp=timestamp)
if publishing_facebook.exists() and not published_facebook.exists(): if publishing_facebook.exists() and not published_facebook.exists():
# One publisher has confirmed the publication date, # One publisher has confirmed the publication date,
# so we can flag, that he/she has published. # so we can flag, that he/she has published.
if not timestamp: if not timestamp:
timestamp = event.flags.filter(status__code='publishing_facebook').last().timestamp timestamp = event.flags.filter(status__code='publishing_facebook').last().timestamp
logger.info('Detected published_facebook state of Event %s', event) logger.info('Detected published_facebook state of Event %s', event)
event.set_flag(status='published_facebook', timestamp=timestamp) self._add_flag('published_facebook', timestamp=timestamp)
if published_web.exists() and published_facebook.exists(): if published_web.exists() and published_facebook.exists():
# All publishers have published, # All publishers have published,
# so we can flag the complete published state. # so we can flag the complete published state.
timestamp = pub_flags.last().timestamp timestamp = pub_flags.last().timestamp
logger.info('Detected general published state of Event %s', event) logger.info('Detected general published state of Event %s', event)
event.set_flag(status='published', timestamp=timestamp) self._add_flag('published', timestamp=timestamp)
elif not publishing.exists() and publishing_web.exists() and publishing_facebook.exists(): elif not publishing.exists() and publishing_web.exists() and publishing_facebook.exists():
# Event is not due to be published yet, # Event is not due to be published yet,
# does not have a general publishing flag, # does not have a general publishing flag,
@@ -168,7 +151,7 @@ class BasicWorkflow(object):
logger.info('Detected publishing state of Event %s', event) logger.info('Detected publishing state of Event %s', event)
flags = event.flags.filter(status__code__in=('publishing_web', 'publishing_facebook')) flags = event.flags.filter(status__code__in=('publishing_web', 'publishing_facebook'))
timestamp = flags.order_by('timestamp').last().timestamp timestamp = flags.order_by('timestamp').last().timestamp
event.set_flag(status='publishing', timestamp=timestamp) self._add_flag('publishing', timestamp=timestamp)
if code in (None, 'expired'): if code in (None, 'expired'):
# Check if event is expired now and need a expired flag. # Check if event is expired now and need a expired flag.
@@ -190,10 +173,10 @@ class BasicWorkflow(object):
if expired_at: if expired_at:
logger.info('Detected expired state of Event %s', event) logger.info('Detected expired state of Event %s', event)
timestamp = timezone.make_aware(datetime.datetime.combine(expired_at, midnight)) timestamp = timezone.make_aware(datetime.datetime.combine(expired_at, midnight))
event.set_flag(status='expired', timestamp=timestamp) self._add_flag('expired', timestamp=timestamp)
def has_reached_status(self, code): def has_reached_status(self, code):
self.check_status(code) self._check_status(code)
if code == 'publishing*': if code == 'publishing*':
codes = ['publishing', 'publishing_web', 'publishing_facebook'] codes = ['publishing', 'publishing_web', 'publishing_facebook']
elif code == 'published*': elif code == 'published*':
@@ -243,8 +226,8 @@ class BasicWorkflow(object):
if not valid: if not valid:
logger.warning(u'Invalid status update to \'%s\': %s Event: %s', code, message, event) logger.warning(u'Invalid status update to \'%s\': %s Event: %s', code, message, event)
flag = event.set_flag(status=code, user=user) flag = self._add_flag(code, user=user)
self.check_status(code) self._check_status(code)
signals.event_status_updated.send(sender=self.__class__, event=event, flag=flag) signals.event_status_updated.send(sender=self.__class__, event=event, flag=flag)
return flag return flag
@@ -253,7 +236,7 @@ class BasicWorkflow(object):
event = self._event event = self._event
status_list = [] status_list = []
event.workflow.check_status() self._check_status()
heaviest_flag = event.flags.order_by('status').last() heaviest_flag = event.flags.order_by('status').last()
if heaviest_flag: if heaviest_flag:
@@ -283,6 +266,39 @@ class BasicWorkflow(object):
return status_list return status_list
#
# Status related event properties
#
def get_number(self):
event = self._event
if event.number and event.flags.filter(status__code='accepted').exists():
return event.number
else:
return '%s**/%d' % (event.sport, event.first_day.year % 100)
def set_number(self):
event = self._event
counter = 0
year = event.first_day.year
year_begin = datetime.date(year, 1, 1)
year_end = datetime.date(year, 12, 31)
qs = event.__class__.objects.filter(number__isnull=False,
sport=event.sport,
first_day__gte=year_begin,
first_day__lte=year_end).order_by('number')
last = qs.last()
if last:
match = re.match(r'^(?P<sport>[A-Z])(?P<count>[0-9][0-9]*)/(?P<year>[0-9][0-9]*)', last.number)
if match:
gd = match.groupdict()
counter = int(gd['count'])
counter += 1
event.number = '%s%02d/%d' % (event.sport, counter, year % 100)
event.save(implicit_update=True)
return event.number
# #
# Notifications (loose coupled via signals) # Notifications (loose coupled via signals)
# #
@@ -381,7 +397,7 @@ class BasicWorkflow(object):
email.send() email.send()
# #
# Permission # Permissions
# #
def has_permission(self, user, permission): def has_permission(self, user, permission):
if user.is_superuser: if user.is_superuser: