From 9ea2c2c9451f2c83a8674de5aafb758695d6e703 Mon Sep 17 00:00:00 2001 From: bkfox Date: Sun, 24 Jul 2016 23:40:10 +0200 Subject: [PATCH] add programs_to_cms commands to make syncs between programs and cms apps --- cms/management/commands/programs_to_cms.py | 87 ++++++++++++++++++++++ cms/models.py | 73 +++++++++++++----- cms/sections.py | 6 +- notes.md | 14 +--- programs/models.py | 5 -- 5 files changed, 149 insertions(+), 36 deletions(-) create mode 100644 cms/management/commands/programs_to_cms.py diff --git a/cms/management/commands/programs_to_cms.py b/cms/management/commands/programs_to_cms.py new file mode 100644 index 0000000..f14f481 --- /dev/null +++ b/cms/management/commands/programs_to_cms.py @@ -0,0 +1,87 @@ +""" +Create missing publications for diffusions and programs already existing. + +We limit the creation of diffusion to the elements to those that start at least +in the last 15 days, and to the future ones. + +The new publications are not published automatically. +""" +import logging +from argparse import RawTextHelpFormatter + +from django.core.management.base import BaseCommand, CommandError +from django.contrib.contenttypes.models import ContentType +from django.utils import timezone as tz + +from aircox.programs.models import Program, Diffusion +from aircox.cms.models import WebsiteSettings, ProgramPage, DiffusionPage + +logger = logging.getLogger('aircox.tools') + + +class Command (BaseCommand): + help= __doc__ + + def add_arguments (self, parser): + parser.formatter_class=RawTextHelpFormatter + + def handle (self, *args, **options): + for settings in WebsiteSettings.objects.all(): + logger.info('start sync for website {}'.format( + str(settings.site) + )) + + if not settings.auto_create: + logger.warning('auto_create disabled: skip') + continue + + if not settings.default_program_parent_page: + logger.warning('no default program page for this website: skip') + continue + + logger.info('start syncing programs...') + + parent = settings.default_program_parent_page + for program in Program.objects.all(): + if program.page.count(): + continue + + logger.info('- ' + program.name) + page = ProgramPage( + program = program, + title = program.name, + live = False + ) + parent.add_child(instance = page) + + logger.info('start syncing diffusions...') + + min_date = tz.now().date() - tz.timedelta(days = 20) + for diffusion in Diffusion.objects.filter(start__gt = min_date): + if diffusion.page.count() or diffusion.initial: + continue + + if not diffusion.program.page.count(): + if not hasattr(diffusion.program, '__logged_diff_error'): + logger.warning( + 'the program {} has no page; skip the creation of ' + 'page for its diffusions'.format( + diffusion.program.name + ) + ) + diffusion.program.__logged_diff_error = True + continue + + logger.info('- ' + str(diffusion)) + try: + page = DiffusionPage.from_diffusion(diffusion) + diffusion.program.page.first().add_child(instance = page) + except: + import sys + e = sys.exc_info()[0] + logger.error('Error saving', str(diffusion) + ':', e) + + logger.info('done') + + + diff --git a/cms/models.py b/cms/models.py index 8d4d285..53b0e42 100644 --- a/cms/models.py +++ b/cms/models.py @@ -36,6 +36,10 @@ from aircox.cms.sections import * @register_setting class WebsiteSettings(BaseSetting): + # TODO: #Station assign a website to a programs.model.station when it will + # exist. Update all dependent code such as signal handling + + # general website information logo = models.ForeignKey( 'wagtailimages.Image', verbose_name = _('logo'), @@ -51,6 +55,8 @@ class WebsiteSettings(BaseSetting): related_name='+', help_text = _('favicon for the website'), ) + + # comments accept_comments = models.BooleanField( default = True, help_text = _('publish comments automatically without verifying'), @@ -75,6 +81,31 @@ class WebsiteSettings(BaseSetting): help_text = _('message to display there is an error an incomplete form.'), ) + auto_create = models.BooleanField( + _('automatic publications'), + default = False, + help_text = _( + 'Create automatically new publications for new programs and ' + 'diffusions in the timetable. If set, please complete other ' + 'options of this panel' + ) + ) + default_program_parent_page = ParentalKey( + Page, + verbose_name = _('default program parent page'), + blank = True, null = True, + help_text = _( + 'Default parent page for program\'s pages. It is used to assign ' + 'a page to the publication of a newly created program and can ' + 'be changed later' + ), + limit_choices_to = lambda: { + 'show_in_menus': True, + 'publication__isnull': False, + }, + ) + + panels = [ ImageChooserPanel('logo'), ImageChooserPanel('favicon'), @@ -84,7 +115,11 @@ class WebsiteSettings(BaseSetting): FieldPanel('comment_success_message'), FieldPanel('comment_wait_message'), FieldPanel('comment_error_message'), - ], heading = _('Comments')) + ], heading = _('Comments')), + MultiFieldPanel([ + FieldPanel('auto_create'), + FieldPanel('default_program_parent_page'), + ], heading = _('Programs and controls')), ] class Meta: @@ -373,11 +408,6 @@ class DiffusionPage(Publication): related_name = 'page', on_delete=models.SET_NULL, null=True, - limit_choices_to = lambda: { - 'initial__isnull': True, - 'start__gt': tz.now() - tz.timedelta(days=10), - 'start__lt': tz.now() + tz.timedelta(days=10), - } ) class Meta: @@ -390,30 +420,39 @@ class DiffusionPage(Publication): InlinePanel('tracks', label=_('Tracks')) ] + + @classmethod + def from_diffusion(cl, diff, model = None, **kwargs): + model = model or cl + model_kwargs = { + 'diffusion': diff, + 'title': '{}, {}'.format( + diff.program.name, tz.localtime(diff.date).strftime('%d %B %Y') + ), + 'cover': (diff.program.page.count() and \ + diff.program.page.first().cover) or None, + 'date': diff.start, + } + model_kwargs.update(kwargs) + r = model(**model_kwargs) + return r + @classmethod def as_item(cl, diff): """ - Return a DiffusionPage or ListItem from a Diffusion + Return a DiffusionPage or ListItem from a Diffusion. """ if diff.page.all().count(): item = diff.page.all().first() else: - item = ListItem( - title = '{}, {}'.format( - diff.program.name, diff.date.strftime('%d %B %Y') - ), - cover = (diff.program.page.count() and \ - diff.program.page.first().cover) or '', - live = True, - date = diff.start, - ) + item = cl.from_diffusion(diff, ListItem) + item.live = True if diff.initial: item.info = _('Rerun of %(date)s') % { 'date': diff.initial.start.strftime('%A %d') } diff.css_class = 'diffusion' - return item def save(self, *args, **kwargs): diff --git a/cms/sections.py b/cms/sections.py index a92ecf9..3fdeb57 100644 --- a/cms/sections.py +++ b/cms/sections.py @@ -5,6 +5,7 @@ from enum import IntEnum from django.db import models from django.utils.translation import ugettext as _, ugettext_lazy from django.utils import timezone as tz +from django.utils.functional import cached_property from django.core.urlresolvers import reverse from django.template.loader import render_to_string from django.contrib.contenttypes.models import ContentType @@ -195,7 +196,7 @@ class ListBase(models.Model): reusable by other classes if needed. """ from aircox.cms.models import Publication - related = self.related and self.related.specific() + related = self.related and self.related.specific # model if self.model: @@ -487,7 +488,7 @@ class Section(ClusterableModel): def render(self, request, page = None, *args, **kwargs): return ''.join([ - place.item.specific().render(request, page, *args, **kwargs) + place.item.specific.render(request, page, *args, **kwargs) for place in self.places.all() ]) @@ -573,6 +574,7 @@ class SectionItem(models.Model,metaclass=SectionItemMeta): ], heading=_('General')), ] + @cached_property def specific(self): """ Return a downcasted version of the post if it is from another diff --git a/notes.md b/notes.md index 6ded820..afb5f7f 100644 --- a/notes.md +++ b/notes.md @@ -33,21 +33,11 @@ This file is used as a reminder, can be used as crappy documentation too. - config generation and sound diffusion - cms: - - update documentation: - - cms.script - - cms.exposure; make it right, see nomenclature, + docstring - - cms.actions; - - admin cms - -> sections/actions and django decorator? - -> enhance calendar with possible actions? - -- website: - - article list with the focus + - command to sync programs with cms's - player: - mixcloud - remove from playing playlist -> stop - - date_by_list: - - sections' url + - filter choices on DiffusionPage and ProgramPage related objects # Long term TODO - automatic cancel of passed diffusion based on logs? diff --git a/programs/models.py b/programs/models.py index 461c796..0a15419 100755 --- a/programs/models.py +++ b/programs/models.py @@ -510,11 +510,6 @@ class Program(Nameable): default = True, help_text = _('if not set this program is no longer active') ) - public = models.BooleanField( - _('public'), - default = True, - help_text = _('information are available to the public') - ) @property def path(self):