fix diff update/delete on schedule change; fix match algorithms
This commit is contained in:
		@ -527,7 +527,8 @@ class Schedule(models.Model):
 | 
			
		||||
        This is needed since datetime are stored as UTC date and we want
 | 
			
		||||
        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)
 | 
			
		||||
        return self._local_date
 | 
			
		||||
 | 
			
		||||
@ -549,7 +550,7 @@ class Schedule(models.Model):
 | 
			
		||||
    # initial cached data
 | 
			
		||||
    __initial = None
 | 
			
		||||
 | 
			
		||||
    def changed(self, fields = ['date','duration','frequency']):
 | 
			
		||||
    def changed(self, fields = ['date','duration','frequency','timezone']):
 | 
			
		||||
        initial = self._Schedule__initial
 | 
			
		||||
        if not initial:
 | 
			
		||||
            return
 | 
			
		||||
@ -573,9 +574,17 @@ class Schedule(models.Model):
 | 
			
		||||
        Return True if the given datetime matches the schedule
 | 
			
		||||
        """
 | 
			
		||||
        date = utils.date_or_default(date)
 | 
			
		||||
        if self.date.weekday() == date.weekday() and self.match_week(date):
 | 
			
		||||
            return self.date.time() == date.time() if check_time else True
 | 
			
		||||
        return False
 | 
			
		||||
        print('match...', date, self.date, self.match_week(date), self.date.weekday() == date.weekday())
 | 
			
		||||
        if self.date.weekday() != date.weekday() or not self.match_week(date):
 | 
			
		||||
            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):
 | 
			
		||||
        """
 | 
			
		||||
@ -601,13 +610,13 @@ class Schedule(models.Model):
 | 
			
		||||
        # weeks of month
 | 
			
		||||
        if week == 4:
 | 
			
		||||
            # fifth week: return if for every week
 | 
			
		||||
            return self.frequency == 0b1111
 | 
			
		||||
            return self.frequency == self.Frequency.every
 | 
			
		||||
        return (self.frequency & (0b0001 << week) > 0)
 | 
			
		||||
 | 
			
		||||
    def normalize(self, date):
 | 
			
		||||
        """
 | 
			
		||||
        Set the time of a datetime to the schedule's one
 | 
			
		||||
        Ensure timezone awareness.
 | 
			
		||||
        Return a new datetime with schedule time. Timezone is handled
 | 
			
		||||
        using `schedule.timezone`.
 | 
			
		||||
        """
 | 
			
		||||
        local_date = self.local_date
 | 
			
		||||
        date = tz.datetime(date.year, date.month, date.day,
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,12 @@
 | 
			
		||||
from django.db.models.signals import post_save, pre_save, pre_delete, m2m_changed
 | 
			
		||||
from django.contrib.auth.models import User, Group, Permission
 | 
			
		||||
import pytz
 | 
			
		||||
 | 
			
		||||
from django.dispatch import receiver
 | 
			
		||||
from django.utils.translation import ugettext as _, ugettext_lazy
 | 
			
		||||
from django.contrib.auth.models import User, Group, Permission
 | 
			
		||||
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.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
 | 
			
		||||
#        schedule_pre_delete
 | 
			
		||||
 | 
			
		||||
@receiver(post_save, sender=models.Schedule)
 | 
			
		||||
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:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
@ -46,29 +50,28 @@ def schedule_post_saved(sender, instance, created, *args, **kwargs):
 | 
			
		||||
    if not initial or not instance.changed(['date','duration', 'frequency']):
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    # old schedule and timedelta
 | 
			
		||||
    old_sched = models.Schedule(
 | 
			
		||||
        program = instance.program,
 | 
			
		||||
        date = initial['date'],
 | 
			
		||||
        duration = initial['duration'],
 | 
			
		||||
        frequency = initial['frequency'],
 | 
			
		||||
    )
 | 
			
		||||
    delta = instance.date - old_sched.date
 | 
			
		||||
    old = models.Schedule(**{ key: initial.get(key)
 | 
			
		||||
        for key in ('date','timezone','duration','frequency')
 | 
			
		||||
    })
 | 
			
		||||
    start_delta = instance.local_date - old.local_date
 | 
			
		||||
 | 
			
		||||
    # update diffusions...
 | 
			
		||||
    qs = models.Diffusion.objects.after(
 | 
			
		||||
    old.date = old.local_date.astimezone(pytz.UTC)
 | 
			
		||||
 | 
			
		||||
    qs = models.Diffusion.objects.station(
 | 
			
		||||
        instance.program.station,
 | 
			
		||||
        program = instance.program
 | 
			
		||||
    )
 | 
			
		||||
    for diff in qs:
 | 
			
		||||
        if not old_sched.match(diff.date):
 | 
			
		||||
            continue
 | 
			
		||||
        diff.start += delta
 | 
			
		||||
        diff.end = diff.start + utils.to_timedelta(instance.duration)
 | 
			
		||||
        diff.save()
 | 
			
		||||
 | 
			
		||||
    pks = [ item.pk for item in qs if old.match(item.date) ]
 | 
			
		||||
    qs.filter(pk__in = pks).update(
 | 
			
		||||
        start = F('start') + start_delta,
 | 
			
		||||
        end = F('start') + start_delta + utils.to_timedelta(instance.duration)
 | 
			
		||||
    )
 | 
			
		||||
    return
 | 
			
		||||
 | 
			
		||||
@receiver(pre_delete, sender=models.Schedule)
 | 
			
		||||
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']):
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    old_sched = models.Schedule(
 | 
			
		||||
        date = initial['date'],
 | 
			
		||||
        duration = initial['duration'],
 | 
			
		||||
        frequency = initial['frequency'],
 | 
			
		||||
    old = models.Schedule(**{ key: initial.get(key)
 | 
			
		||||
        for key in ('date','timezone','duration','frequency')
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    qs = models.Diffusion.objects.station(
 | 
			
		||||
        instance.program.station,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    qs = models.Diffusion.objects.after(instance.program.station).filter(
 | 
			
		||||
        program = instance.program
 | 
			
		||||
    )
 | 
			
		||||
    for diff in qs:
 | 
			
		||||
        if not old_sched.match(diff.date):
 | 
			
		||||
            continue
 | 
			
		||||
        diff.delete()
 | 
			
		||||
    pks = [ item.pk for item in qs if old.match(item.date) ]
 | 
			
		||||
    qs.filter(pk__in = pks).delete()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -277,13 +277,14 @@ class BaseList(models.Model):
 | 
			
		||||
 | 
			
		||||
    def __get_related(self, qs):
 | 
			
		||||
        related = self.related and self.related.specific
 | 
			
		||||
 | 
			
		||||
        filter = self.RelationFilter
 | 
			
		||||
 | 
			
		||||
        if self.relation in (filter.subpages, filter.subpages_or_siblings):
 | 
			
		||||
            qs =  qs.descendant_of(related)
 | 
			
		||||
            if not qs.count() and self.relation == filter.subpages_or_siblings:
 | 
			
		||||
                qs = qs.sibling_of(related)
 | 
			
		||||
            qs_ = qs.descendant_of(related)
 | 
			
		||||
            if self.relation == filter.subpages_or_siblings and \
 | 
			
		||||
                    not qs.count():
 | 
			
		||||
                qs_ = qs.sibling_of(related)
 | 
			
		||||
            qs = qs_
 | 
			
		||||
        else:
 | 
			
		||||
            qs = qs.sibling_of(related)
 | 
			
		||||
 | 
			
		||||
@ -393,7 +394,7 @@ class BaseList(models.Model):
 | 
			
		||||
            'asc': self.asc,
 | 
			
		||||
            'date_filter': self.get_date_filter_display(),
 | 
			
		||||
            'model': self.model and self.model.model,
 | 
			
		||||
            'relation': self.get_relation_display(),
 | 
			
		||||
            'relation': self.relation,
 | 
			
		||||
            'search': self.search,
 | 
			
		||||
            'tags': self.tags
 | 
			
		||||
        }
 | 
			
		||||
@ -437,7 +438,13 @@ class BaseList(models.Model):
 | 
			
		||||
        """
 | 
			
		||||
        date_filter = request.GET.get('date_filter')
 | 
			
		||||
        model = request.GET.get('model')
 | 
			
		||||
 | 
			
		||||
        relation = request.GET.get('relation')
 | 
			
		||||
        if relation is not None:
 | 
			
		||||
            try:
 | 
			
		||||
                relation = int(relation)
 | 
			
		||||
            except:
 | 
			
		||||
                relation = None
 | 
			
		||||
 | 
			
		||||
        related_= request.GET.get('related')
 | 
			
		||||
        if related_:
 | 
			
		||||
@ -459,10 +466,7 @@ class BaseList(models.Model):
 | 
			
		||||
                DiffusionPage if model == 'diffusion' else
 | 
			
		||||
                EventPage if model == 'event' else None,
 | 
			
		||||
            'related': related_,
 | 
			
		||||
            'relation':
 | 
			
		||||
                int(getattr(cl.RelationFilter, relation))
 | 
			
		||||
                if relation and hasattr(cl.RelationFilter, relation)
 | 
			
		||||
                else None,
 | 
			
		||||
            'relation': relation,
 | 
			
		||||
            'tags': request.GET.get('tags'),
 | 
			
		||||
            'search': request.GET.get('search'),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user