forked from rc/aircox
add programs_to_cms commands to make syncs between programs and cms apps
This commit is contained in:
parent
5716258d36
commit
9ea2c2c945
87
cms/management/commands/programs_to_cms.py
Normal file
87
cms/management/commands/programs_to_cms.py
Normal file
|
@ -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')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,10 @@ from aircox.cms.sections import *
|
||||||
|
|
||||||
@register_setting
|
@register_setting
|
||||||
class WebsiteSettings(BaseSetting):
|
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(
|
logo = models.ForeignKey(
|
||||||
'wagtailimages.Image',
|
'wagtailimages.Image',
|
||||||
verbose_name = _('logo'),
|
verbose_name = _('logo'),
|
||||||
|
@ -51,6 +55,8 @@ class WebsiteSettings(BaseSetting):
|
||||||
related_name='+',
|
related_name='+',
|
||||||
help_text = _('favicon for the website'),
|
help_text = _('favicon for the website'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# comments
|
||||||
accept_comments = models.BooleanField(
|
accept_comments = models.BooleanField(
|
||||||
default = True,
|
default = True,
|
||||||
help_text = _('publish comments automatically without verifying'),
|
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.'),
|
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 = [
|
panels = [
|
||||||
ImageChooserPanel('logo'),
|
ImageChooserPanel('logo'),
|
||||||
ImageChooserPanel('favicon'),
|
ImageChooserPanel('favicon'),
|
||||||
|
@ -84,7 +115,11 @@ class WebsiteSettings(BaseSetting):
|
||||||
FieldPanel('comment_success_message'),
|
FieldPanel('comment_success_message'),
|
||||||
FieldPanel('comment_wait_message'),
|
FieldPanel('comment_wait_message'),
|
||||||
FieldPanel('comment_error_message'),
|
FieldPanel('comment_error_message'),
|
||||||
], heading = _('Comments'))
|
], heading = _('Comments')),
|
||||||
|
MultiFieldPanel([
|
||||||
|
FieldPanel('auto_create'),
|
||||||
|
FieldPanel('default_program_parent_page'),
|
||||||
|
], heading = _('Programs and controls')),
|
||||||
]
|
]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -373,11 +408,6 @@ class DiffusionPage(Publication):
|
||||||
related_name = 'page',
|
related_name = 'page',
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
null=True,
|
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:
|
class Meta:
|
||||||
|
@ -390,30 +420,39 @@ class DiffusionPage(Publication):
|
||||||
InlinePanel('tracks', label=_('Tracks'))
|
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
|
@classmethod
|
||||||
def as_item(cl, diff):
|
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():
|
if diff.page.all().count():
|
||||||
item = diff.page.all().first()
|
item = diff.page.all().first()
|
||||||
else:
|
else:
|
||||||
item = ListItem(
|
item = cl.from_diffusion(diff, ListItem)
|
||||||
title = '{}, {}'.format(
|
item.live = True
|
||||||
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
if diff.initial:
|
if diff.initial:
|
||||||
item.info = _('Rerun of %(date)s') % {
|
item.info = _('Rerun of %(date)s') % {
|
||||||
'date': diff.initial.start.strftime('%A %d')
|
'date': diff.initial.start.strftime('%A %d')
|
||||||
}
|
}
|
||||||
diff.css_class = 'diffusion'
|
diff.css_class = 'diffusion'
|
||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
|
|
@ -5,6 +5,7 @@ from enum import IntEnum
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
from django.utils import timezone as tz
|
from django.utils import timezone as tz
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
@ -195,7 +196,7 @@ class ListBase(models.Model):
|
||||||
reusable by other classes if needed.
|
reusable by other classes if needed.
|
||||||
"""
|
"""
|
||||||
from aircox.cms.models import Publication
|
from aircox.cms.models import Publication
|
||||||
related = self.related and self.related.specific()
|
related = self.related and self.related.specific
|
||||||
|
|
||||||
# model
|
# model
|
||||||
if self.model:
|
if self.model:
|
||||||
|
@ -487,7 +488,7 @@ class Section(ClusterableModel):
|
||||||
|
|
||||||
def render(self, request, page = None, *args, **kwargs):
|
def render(self, request, page = None, *args, **kwargs):
|
||||||
return ''.join([
|
return ''.join([
|
||||||
place.item.specific().render(request, page, *args, **kwargs)
|
place.item.specific.render(request, page, *args, **kwargs)
|
||||||
for place in self.places.all()
|
for place in self.places.all()
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -573,6 +574,7 @@ class SectionItem(models.Model,metaclass=SectionItemMeta):
|
||||||
], heading=_('General')),
|
], heading=_('General')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
def specific(self):
|
def specific(self):
|
||||||
"""
|
"""
|
||||||
Return a downcasted version of the post if it is from another
|
Return a downcasted version of the post if it is from another
|
||||||
|
|
14
notes.md
14
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
|
- config generation and sound diffusion
|
||||||
|
|
||||||
- cms:
|
- cms:
|
||||||
- update documentation:
|
- command to sync programs with cms's
|
||||||
- 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
|
|
||||||
- player:
|
- player:
|
||||||
- mixcloud
|
- mixcloud
|
||||||
- remove from playing playlist -> stop
|
- remove from playing playlist -> stop
|
||||||
- date_by_list:
|
- filter choices on DiffusionPage and ProgramPage related objects
|
||||||
- sections' url
|
|
||||||
|
|
||||||
# Long term TODO
|
# Long term TODO
|
||||||
- automatic cancel of passed diffusion based on logs?
|
- automatic cancel of passed diffusion based on logs?
|
||||||
|
|
|
@ -510,11 +510,6 @@ class Program(Nameable):
|
||||||
default = True,
|
default = True,
|
||||||
help_text = _('if not set this program is no longer active')
|
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
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user