fix diff update/delete on schedule change; fix match algorithms

This commit is contained in:
bkfox 2017-08-31 19:54:48 +02:00
parent 28dab0185a
commit a0968d35f6
3 changed files with 63 additions and 50 deletions

View File

@ -527,7 +527,8 @@ class Schedule(models.Model):
This is needed since datetime are stored as UTC date and we want This is needed since datetime are stored as UTC date and we want
to get it as local time. to get it as local time.
""" """
if not hasattr(self, '_local_date') or self._tz.zone != self.timezone: if not hasattr(self, '_local_date') or \
self.changed(fields = ('timezone','date')):
self._local_date = tz.localtime(self.date, self.tz) self._local_date = tz.localtime(self.date, self.tz)
return self._local_date return self._local_date
@ -549,7 +550,7 @@ class Schedule(models.Model):
# initial cached data # initial cached data
__initial = None __initial = None
def changed(self, fields = ['date','duration','frequency']): def changed(self, fields = ['date','duration','frequency','timezone']):
initial = self._Schedule__initial initial = self._Schedule__initial
if not initial: if not initial:
return return
@ -573,9 +574,17 @@ class Schedule(models.Model):
Return True if the given datetime matches the schedule Return True if the given datetime matches the schedule
""" """
date = utils.date_or_default(date) date = utils.date_or_default(date)
if self.date.weekday() == date.weekday() and self.match_week(date): print('match...', date, self.date, self.match_week(date), self.date.weekday() == date.weekday())
return self.date.time() == date.time() if check_time else True if self.date.weekday() != date.weekday() or not self.match_week(date):
return False return False
if not check_time:
return True
# we check against a normalized version (norm_date will have
# schedule's date.
norm_date = self.normalize(date)
return date == norm_date
def match_week(self, date = None): def match_week(self, date = None):
""" """
@ -601,13 +610,13 @@ class Schedule(models.Model):
# weeks of month # weeks of month
if week == 4: if week == 4:
# fifth week: return if for every week # fifth week: return if for every week
return self.frequency == 0b1111 return self.frequency == self.Frequency.every
return (self.frequency & (0b0001 << week) > 0) return (self.frequency & (0b0001 << week) > 0)
def normalize(self, date): def normalize(self, date):
""" """
Set the time of a datetime to the schedule's one Return a new datetime with schedule time. Timezone is handled
Ensure timezone awareness. using `schedule.timezone`.
""" """
local_date = self.local_date local_date = self.local_date
date = tz.datetime(date.year, date.month, date.day, date = tz.datetime(date.year, date.month, date.day,

View File

@ -1,9 +1,12 @@
from django.db.models.signals import post_save, pre_save, pre_delete, m2m_changed import pytz
from django.contrib.auth.models import User, Group, Permission
from django.dispatch import receiver from django.contrib.auth.models import User, Group, Permission
from django.utils.translation import ugettext as _, ugettext_lazy
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import F
from django.db.models.signals import post_save, pre_save, pre_delete, m2m_changed
from django.dispatch import receiver
from django.utils import timezone as tz
from django.utils.translation import ugettext as _, ugettext_lazy
import aircox.models as models import aircox.models as models
import aircox.utils as utils import aircox.utils as utils
@ -36,9 +39,10 @@ def user_default_groups(sender, instance, created, *args, **kwargs):
# FIXME: avoid copy of the code in schedule_post_saved and # FIXME: avoid copy of the code in schedule_post_saved and
# schedule_pre_delete # schedule_pre_delete
@receiver(post_save, sender=models.Schedule) @receiver(post_save, sender=models.Schedule)
def schedule_post_saved(sender, instance, created, *args, **kwargs): def schedule_post_saved(sender, instance, created, *args, **kwargs):
# TODO: case instance.program has changed # TODO: case instance.program | instance.frequency has changed
if not instance.program.sync: if not instance.program.sync:
return return
@ -46,29 +50,28 @@ def schedule_post_saved(sender, instance, created, *args, **kwargs):
if not initial or not instance.changed(['date','duration', 'frequency']): if not initial or not instance.changed(['date','duration', 'frequency']):
return return
if not initial.get('date') or not initial.get('duration') or not initial.get('frequency'): if not initial.get('date') or not initial.get('duration') \
or not initial.get('frequency'):
return return
# old schedule and timedelta # old schedule and timedelta
old_sched = models.Schedule( old = models.Schedule(**{ key: initial.get(key)
program = instance.program, for key in ('date','timezone','duration','frequency')
date = initial['date'], })
duration = initial['duration'], start_delta = instance.local_date - old.local_date
frequency = initial['frequency'],
)
delta = instance.date - old_sched.date
# update diffusions... old.date = old.local_date.astimezone(pytz.UTC)
qs = models.Diffusion.objects.after(
qs = models.Diffusion.objects.station(
instance.program.station, instance.program.station,
program = instance.program
) )
for diff in qs:
if not old_sched.match(diff.date): pks = [ item.pk for item in qs if old.match(item.date) ]
continue qs.filter(pk__in = pks).update(
diff.start += delta start = F('start') + start_delta,
diff.end = diff.start + utils.to_timedelta(instance.duration) end = F('start') + start_delta + utils.to_timedelta(instance.duration)
diff.save() )
return
@receiver(pre_delete, sender=models.Schedule) @receiver(pre_delete, sender=models.Schedule)
def schedule_pre_delete(sender, instance, *args, **kwargs): def schedule_pre_delete(sender, instance, *args, **kwargs):
@ -79,17 +82,14 @@ def schedule_pre_delete(sender, instance, *args, **kwargs):
if not initial or not instance.changed(['date','duration', 'frequency']): if not initial or not instance.changed(['date','duration', 'frequency']):
return return
old_sched = models.Schedule( old = models.Schedule(**{ key: initial.get(key)
date = initial['date'], for key in ('date','timezone','duration','frequency')
duration = initial['duration'], })
frequency = initial['frequency'],
qs = models.Diffusion.objects.station(
instance.program.station,
) )
qs = models.Diffusion.objects.after(instance.program.station).filter( pks = [ item.pk for item in qs if old.match(item.date) ]
program = instance.program qs.filter(pk__in = pks).delete()
)
for diff in qs:
if not old_sched.match(diff.date):
continue
diff.delete()

View File

@ -277,13 +277,14 @@ class BaseList(models.Model):
def __get_related(self, qs): def __get_related(self, qs):
related = self.related and self.related.specific related = self.related and self.related.specific
filter = self.RelationFilter filter = self.RelationFilter
if self.relation in (filter.subpages, filter.subpages_or_siblings): if self.relation in (filter.subpages, filter.subpages_or_siblings):
qs = qs.descendant_of(related) qs_ = qs.descendant_of(related)
if not qs.count() and self.relation == filter.subpages_or_siblings: if self.relation == filter.subpages_or_siblings and \
qs = qs.sibling_of(related) not qs.count():
qs_ = qs.sibling_of(related)
qs = qs_
else: else:
qs = qs.sibling_of(related) qs = qs.sibling_of(related)
@ -393,7 +394,7 @@ class BaseList(models.Model):
'asc': self.asc, 'asc': self.asc,
'date_filter': self.get_date_filter_display(), 'date_filter': self.get_date_filter_display(),
'model': self.model and self.model.model, 'model': self.model and self.model.model,
'relation': self.get_relation_display(), 'relation': self.relation,
'search': self.search, 'search': self.search,
'tags': self.tags 'tags': self.tags
} }
@ -437,7 +438,13 @@ class BaseList(models.Model):
""" """
date_filter = request.GET.get('date_filter') date_filter = request.GET.get('date_filter')
model = request.GET.get('model') model = request.GET.get('model')
relation = request.GET.get('relation') relation = request.GET.get('relation')
if relation is not None:
try:
relation = int(relation)
except:
relation = None
related_= request.GET.get('related') related_= request.GET.get('related')
if related_: if related_:
@ -459,10 +466,7 @@ class BaseList(models.Model):
DiffusionPage if model == 'diffusion' else DiffusionPage if model == 'diffusion' else
EventPage if model == 'event' else None, EventPage if model == 'event' else None,
'related': related_, 'related': related_,
'relation': 'relation': relation,
int(getattr(cl.RelationFilter, relation))
if relation and hasattr(cl.RelationFilter, relation)
else None,
'tags': request.GET.get('tags'), 'tags': request.GET.get('tags'),
'search': request.GET.get('search'), 'search': request.GET.get('search'),
} }