issue #1: synchronise programs' schedules and later diffusions (update, delete); fix signal import in apps
This commit is contained in:
parent
bdd351d6d9
commit
3ab373097b
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
default_app_config = 'aircox.apps.AircoxConfig'
|
||||||
|
|
|
@ -81,9 +81,8 @@ class ProgramAdmin(NameableAdmin):
|
||||||
schedule.boolean = True
|
schedule.boolean = True
|
||||||
schedule.short_description = _("Schedule")
|
schedule.short_description = _("Schedule")
|
||||||
|
|
||||||
list_display = ('id', 'name', 'active', 'schedule')
|
list_display = ('id', 'name', 'active', 'schedule', 'sync')
|
||||||
fields = NameableAdmin.fields + [ 'active', 'station' ]
|
fields = NameableAdmin.fields + [ 'active', 'station','sync' ]
|
||||||
# TODO list_display
|
|
||||||
inlines = [ ScheduleInline, StreamInline ]
|
inlines = [ ScheduleInline, StreamInline ]
|
||||||
|
|
||||||
# SO#8074161
|
# SO#8074161
|
||||||
|
|
10
aircox/apps.py
Normal file
10
aircox/apps.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AircoxConfig(AppConfig):
|
||||||
|
name = 'aircox'
|
||||||
|
verbose_name = 'Aircox'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import aircox.signals
|
||||||
|
|
|
@ -128,16 +128,18 @@ class Command (BaseCommand):
|
||||||
'--update', action='store_true',
|
'--update', action='store_true',
|
||||||
help='generate (unconfirmed) diffusions for the given month. '
|
help='generate (unconfirmed) diffusions for the given month. '
|
||||||
'These diffusions must be confirmed manually by changing '
|
'These diffusions must be confirmed manually by changing '
|
||||||
'their type to "normal"')
|
'their type to "normal"'
|
||||||
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
'--clean', action='store_true',
|
'--clean', action='store_true',
|
||||||
help='remove unconfirmed diffusions older than the given month')
|
help='remove unconfirmed diffusions older than the given month'
|
||||||
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
'--check', action='store_true',
|
'--check', action='store_true',
|
||||||
help='check future unconfirmed diffusions from the given date '
|
help='check unconfirmed later diffusions from the given '
|
||||||
'agains\'t schedules and remove it if that do not match any '
|
'date again'\'t schedule. If no schedule is found, remove '
|
||||||
'schedule')
|
'it.'
|
||||||
|
)
|
||||||
|
|
||||||
group = parser.add_argument_group('date')
|
group = parser.add_argument_group('date')
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
|
@ -161,7 +163,6 @@ class Command (BaseCommand):
|
||||||
'diffusions except those that conflicts with others'
|
'diffusions except those that conflicts with others'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def handle (self, *args, **options):
|
def handle (self, *args, **options):
|
||||||
date = tz.datetime(year = options.get('year'),
|
date = tz.datetime(year = options.get('year'),
|
||||||
month = options.get('month'),
|
month = options.get('month'),
|
||||||
|
|
|
@ -294,6 +294,11 @@ class Program(Nameable):
|
||||||
default = True,
|
default = True,
|
||||||
help_text = _('if not checked this program is no longer active')
|
help_text = _('if not checked this program is no longer active')
|
||||||
)
|
)
|
||||||
|
sync = models.BooleanField(
|
||||||
|
_('syncronise'),
|
||||||
|
default = True,
|
||||||
|
help_text = _('update later diffusions according to schedule changes')
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
|
@ -503,6 +508,24 @@ class Schedule(models.Model):
|
||||||
help_text = 'this schedule is a rerun of this one',
|
help_text = 'this schedule is a rerun of this one',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# initial cached data
|
||||||
|
__initial = None
|
||||||
|
|
||||||
|
def changed(self, fields = ['date','duration','frequency']):
|
||||||
|
initial = self._Schedule__initial
|
||||||
|
if not initial:
|
||||||
|
return
|
||||||
|
|
||||||
|
before, now = self.__initial, self.__dict__
|
||||||
|
before, now = {
|
||||||
|
f: getattr(before, f) for f in fields
|
||||||
|
if hasattr(before, f)
|
||||||
|
}, {
|
||||||
|
f: getattr(now, f) for f in fields
|
||||||
|
if hasattr(now, f)
|
||||||
|
}
|
||||||
|
return before == now
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def end(self):
|
def end(self):
|
||||||
return self.date + utils.to_timedelta(self.duration)
|
return self.date + utils.to_timedelta(self.duration)
|
||||||
|
@ -627,6 +650,10 @@ class Schedule(models.Model):
|
||||||
]
|
]
|
||||||
return diffusions
|
return diffusions
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.__initial = self.__dict__.copy()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ' | '.join([ '#' + str(self.id), self.program.name,
|
return ' | '.join([ '#' + str(self.id), self.program.name,
|
||||||
self.get_frequency_display(),
|
self.get_frequency_display(),
|
||||||
|
|
63
aircox/signals.py
Normal file
63
aircox/signals.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
from django.db.models.signals import post_save, pre_delete
|
||||||
|
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
|
import aircox.models as models
|
||||||
|
import aircox.utils as utils
|
||||||
|
|
||||||
|
# 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):
|
||||||
|
if not instance.program.sync:
|
||||||
|
return
|
||||||
|
|
||||||
|
initial = instance._Schedule__initial
|
||||||
|
if not initial or not instance.changed(['date','duration', 'frequency']):
|
||||||
|
return
|
||||||
|
|
||||||
|
# old schedule and timedelta
|
||||||
|
old_sched = models.Schedule(
|
||||||
|
date = initial['date'],
|
||||||
|
duration = initial['duration'],
|
||||||
|
frequency = initial['frequency'],
|
||||||
|
)
|
||||||
|
delta = instance.date - old_sched.date
|
||||||
|
|
||||||
|
# update diffusions...
|
||||||
|
qs = models.Diffusion.objects.get_after().filter(
|
||||||
|
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()
|
||||||
|
|
||||||
|
@receiver(pre_delete, sender=models.Schedule)
|
||||||
|
def schedule_pre_delete(sender, instance, *args, **kwargs):
|
||||||
|
if not instance.program.sync:
|
||||||
|
return
|
||||||
|
|
||||||
|
initial = instance._Schedule__initial
|
||||||
|
if not initial or not instance.changed(['date','duration', 'frequency']):
|
||||||
|
return
|
||||||
|
|
||||||
|
old_sched = models.Schedule(
|
||||||
|
date = initial['date'],
|
||||||
|
duration = initial['duration'],
|
||||||
|
frequency = initial['frequency'],
|
||||||
|
)
|
||||||
|
|
||||||
|
qs = models.Diffusion.objects.get_after().filter(
|
||||||
|
program = instance.program
|
||||||
|
)
|
||||||
|
for diff in qs:
|
||||||
|
if not old_sched.match(diff.date):
|
||||||
|
continue
|
||||||
|
diff.delete()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
default_app_config = 'aircox_cms.apps.AircoxCMSConfig'
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class AircoxCMSConfig(AppConfig):
|
||||||
|
name = 'aircox_cms'
|
||||||
|
verbose_name = 'Aircox CMS'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import aircox_cms.signals
|
||||||
|
|
||||||
class CmsConfig(AppConfig):
|
|
||||||
name = 'cms'
|
|
||||||
|
|
|
@ -33,8 +33,6 @@ import aircox_cms.settings as settings
|
||||||
from aircox_cms.utils import image_url
|
from aircox_cms.utils import image_url
|
||||||
from aircox_cms.sections import *
|
from aircox_cms.sections import *
|
||||||
|
|
||||||
import aircox_cms.signals
|
|
||||||
|
|
||||||
|
|
||||||
@register_setting
|
@register_setting
|
||||||
class WebsiteSettings(BaseSetting):
|
class WebsiteSettings(BaseSetting):
|
||||||
|
|
|
@ -6,6 +6,8 @@ from django.contrib.contenttypes.models import ContentType
|
||||||
from wagtail.wagtailcore.models import Page, Site
|
from wagtail.wagtailcore.models import Page, Site
|
||||||
|
|
||||||
import aircox.models as aircox
|
import aircox.models as aircox
|
||||||
|
import aircox_cms.models as models
|
||||||
|
import aircox_cms.sections as sections
|
||||||
import aircox_cms.utils as utils
|
import aircox_cms.utils as utils
|
||||||
|
|
||||||
# on a new diffusion
|
# on a new diffusion
|
||||||
|
@ -16,16 +18,12 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
Create the basis for the website: set up settings and pages
|
Create the basis for the website: set up settings and pages
|
||||||
that are common.
|
that are common.
|
||||||
"""
|
"""
|
||||||
from aircox_cms.models import \
|
|
||||||
WebsiteSettings, Publication, ProgramPage, \
|
|
||||||
TimetablePage, DynamicListPage, LogsPage
|
|
||||||
import aircox_cms.sections as sections
|
|
||||||
if not created:
|
if not created:
|
||||||
return
|
return
|
||||||
|
|
||||||
root_page = Page.objects.get(id=1)
|
root_page = Page.objects.get(id=1)
|
||||||
|
|
||||||
homepage = Publication(
|
homepage = models.Publication(
|
||||||
title = instance.name,
|
title = instance.name,
|
||||||
slug = instance.slug,
|
slug = instance.slug,
|
||||||
body = _(
|
body = _(
|
||||||
|
@ -46,7 +44,7 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
site.save()
|
site.save()
|
||||||
|
|
||||||
# settings
|
# settings
|
||||||
website_settings = WebsiteSettings(
|
website_settings = models.WebsiteSettings(
|
||||||
site = site,
|
site = site,
|
||||||
station = instance,
|
station = instance,
|
||||||
description = _("The website of the {name} radio").format(
|
description = _("The website of the {name} radio").format(
|
||||||
|
@ -57,13 +55,13 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
)
|
)
|
||||||
|
|
||||||
# timetable
|
# timetable
|
||||||
timetable = TimetablePage(
|
timetable = models.TimetablePage(
|
||||||
title = _('Timetable'),
|
title = _('Timetable'),
|
||||||
)
|
)
|
||||||
homepage.add_child(instance = timetable)
|
homepage.add_child(instance = timetable)
|
||||||
|
|
||||||
# list page (search, terms)
|
# list page (search, terms)
|
||||||
list_page = DynamicListPage(
|
list_page = models.DynamicListPage(
|
||||||
# title is dynamic: no need to specify
|
# title is dynamic: no need to specify
|
||||||
title = _('Search'),
|
title = _('Search'),
|
||||||
)
|
)
|
||||||
|
@ -71,7 +69,7 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
website_settings.list_page = list_page
|
website_settings.list_page = list_page
|
||||||
|
|
||||||
# programs' page: list of programs in a section
|
# programs' page: list of programs in a section
|
||||||
programs = Publication(
|
programs = models.Publication(
|
||||||
title = _('Programs'),
|
title = _('Programs'),
|
||||||
)
|
)
|
||||||
homepage.add_child(instance = programs)
|
homepage.add_child(instance = programs)
|
||||||
|
@ -93,7 +91,7 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
website_settings.sync = True
|
website_settings.sync = True
|
||||||
|
|
||||||
# logs (because it is a cool feature)
|
# logs (because it is a cool feature)
|
||||||
logs = LogsPage(
|
logs = models.LogsPage(
|
||||||
title = _('Previously on air'),
|
title = _('Previously on air'),
|
||||||
station = instance,
|
station = instance,
|
||||||
)
|
)
|
||||||
|
@ -106,7 +104,6 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
|
|
||||||
@receiver(post_save, sender=aircox.Program)
|
@receiver(post_save, sender=aircox.Program)
|
||||||
def program_post_saved(sender, instance, created, *args, **kwargs):
|
def program_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
import aircox_cms.models as models
|
|
||||||
if not created or instance.page.count():
|
if not created or instance.page.count():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -131,10 +128,11 @@ def program_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
)
|
)
|
||||||
parent.add_child(instance = page)
|
parent.add_child(instance = page)
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_delete, sender=aircox.Program)
|
@receiver(pre_delete, sender=aircox.Program)
|
||||||
def program_post_deleted(sender, instance, *args, **kwargs):
|
def program_post_deleted(sender, instance, *args, **kwargs):
|
||||||
if not instance.page or (
|
if not instance.page.count() or (
|
||||||
instance.page.first().body or
|
instance.page.first().specific.body or
|
||||||
Page.objects.descendant_of(instance).count()
|
Page.objects.descendant_of(instance).count()
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
@ -143,9 +141,6 @@ def program_post_deleted(sender, instance, *args, **kwargs):
|
||||||
|
|
||||||
@receiver(post_save, sender=aircox.Diffusion)
|
@receiver(post_save, sender=aircox.Diffusion)
|
||||||
def diffusion_post_saved(sender, instance, created, *args, **kwargs):
|
def diffusion_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
import aircox_cms.models as models
|
|
||||||
# TODO/FIXME: what about confirmed/unconfirmed;
|
|
||||||
# what about delete when not confirmed?
|
|
||||||
if not created or instance.page.count():
|
if not created or instance.page.count():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -158,7 +153,7 @@ def diffusion_post_saved(sender, instance, created, *args, **kwargs):
|
||||||
|
|
||||||
@receiver(pre_delete, sender=aircox.Program)
|
@receiver(pre_delete, sender=aircox.Program)
|
||||||
def diffusion_post_deleted(sender, instance, *args, **kwargs):
|
def diffusion_post_deleted(sender, instance, *args, **kwargs):
|
||||||
if not instance.page or instance.page.first().body:
|
if not instance.page.count() or instance.page.first().specific.body:
|
||||||
return
|
return
|
||||||
instance.page.delete()
|
instance.page.delete()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user