{% if item.url %}
{% endif %}
diff --git a/cms/templatetags/__init__.py b/cms/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cms/templatetags/aircox_cms.py b/cms/templatetags/aircox_cms.py
new file mode 100644
index 0000000..86f62ec
--- /dev/null
+++ b/cms/templatetags/aircox_cms.py
@@ -0,0 +1,23 @@
+from django import template
+from django.core.urlresolvers import reverse
+
+register = template.Library()
+
+
+@register.filter(name='threads')
+def threads (post, sep = '/'):
+ """
+ print a list of all parents, from top to bottom
+ """
+ posts = [post]
+ while posts[0].thread:
+ post = posts[0].thread
+ if post not in posts:
+ posts.insert(0, post)
+
+ return sep.join([
+ '{}'.format(post.detail_url(), post.title)
+ for post in posts if post.published
+ ])
+
+
diff --git a/cms/utils.py b/cms/utils.py
index 8f25573..413d8f6 100644
--- a/cms/utils.py
+++ b/cms/utils.py
@@ -2,7 +2,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
-def get_url (website, route, model, kwargs):
+def get_url(website, route, model, kwargs):
name = website.name_of_model(model)
if not name:
return
@@ -10,7 +10,7 @@ def get_url (website, route, model, kwargs):
return reverse(name, kwargs = kwargs)
-def filter_thread (qs, object):
+def filter_thread(qs, object):
model_type = ContentType.objects.get_for_model(object.__class__)
return qs.filter(
thread_pk = object.pk,
diff --git a/cms/views.py b/cms/views.py
index 5ac4678..a35a2e4 100644
--- a/cms/views.py
+++ b/cms/views.py
@@ -20,7 +20,7 @@ class PostBaseView:
embed = False # page is embed (if True, only post content is printed
classes = '' # extra classes for the content
- def get_base_context (self, **kwargs):
+ def get_base_context(self, **kwargs):
"""
Return a context with all attributes of this classe plus 'view' set
to self.
@@ -44,7 +44,7 @@ class PostBaseView:
return context
-class PostListView (PostBaseView, ListView):
+class PostListView(PostBaseView, ListView):
"""
List view for posts and children
"""
@@ -59,11 +59,11 @@ class PostListView (PostBaseView, ListView):
page = 1 # page number
q = None # query search
- def __init__ (self, query):
+ def __init__(self, query):
if query:
self.update(query)
- def update (self, query):
+ def update(self, query):
my_class = self.__class__
if type(query) is my_class:
self.__dict__.update(query.__dict__)
@@ -80,15 +80,15 @@ class PostListView (PostBaseView, ListView):
fields = [ 'date', 'time', 'image', 'title', 'content' ]
icon_size = '64x64'
- def __init__ (self, *args, **kwargs):
+ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.query = PostListView.Query(self.query)
- def dispatch (self, request, *args, **kwargs):
+ def dispatch(self, request, *args, **kwargs):
self.route = self.kwargs.get('route') or self.route
return super().dispatch(request, *args, **kwargs)
- def get_queryset (self):
+ def get_queryset(self):
if self.route:
qs = self.route.get_queryset(self.website, self.model, self.request,
**self.kwargs)
@@ -116,7 +116,7 @@ class PostListView (PostBaseView, ListView):
return qs
- def get_context_data (self, **kwargs):
+ def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(self.get_base_context(**kwargs))
context.update({
@@ -124,7 +124,7 @@ class PostListView (PostBaseView, ListView):
})
return context
- def get_title (self):
+ def get_title(self):
if self.title:
return self.title
@@ -132,14 +132,14 @@ class PostListView (PostBaseView, ListView):
**self.kwargs)
return title
- def get_url (self):
+ def get_url(self):
if self.route:
return utils.get_urls(self.website, self.route,
self.model, self.kwargs)
return ''
-class PostDetailView (DetailView, PostBaseView):
+class PostDetailView(DetailView, PostBaseView):
"""
Detail view for posts and children
"""
@@ -147,11 +147,11 @@ class PostDetailView (DetailView, PostBaseView):
sections = []
- def __init__ (self, sections = None, *args, **kwargs):
+ def __init__(self, sections = None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sections = sections or []
- def get_queryset (self):
+ def get_queryset(self):
if self.request.GET.get('embed'):
self.embed = True
@@ -159,14 +159,14 @@ class PostDetailView (DetailView, PostBaseView):
return super().get_queryset().filter(published = True)
return []
- def get_object (self, **kwargs):
+ def get_object(self, **kwargs):
if self.model:
object = super().get_object(**kwargs)
if object.published:
return object
return None
- def get_context_data (self, **kwargs):
+ def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(self.get_base_context())
context.update({
@@ -178,7 +178,7 @@ class PostDetailView (DetailView, PostBaseView):
return context
-class Menu (View):
+class Menu(View):
template_name = 'aircox/cms/menu.html'
name = ''
@@ -188,11 +188,11 @@ class Menu (View):
position = '' # top, left, bottom, right, header, footer, page_top, page_bottom
sections = None
- def __init__ (self, *args, **kwargs):
+ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = self.name or ('menu_' + self.position)
- def get_context_data (self, **kwargs):
+ def get_context_data(self, **kwargs):
return {
'name': self.name,
'tag': self.tag,
@@ -205,7 +205,7 @@ class Menu (View):
]
}
- def get (self, request, website, **kwargs):
+ def get(self, request, website, **kwargs):
self.request = request
self.website = website
context = self.get_context_data(**kwargs)
@@ -213,7 +213,7 @@ class Menu (View):
-class BaseSection (View):
+class BaseSection(View):
"""
Base class for sections. Sections are view that can be used in detail view
in order to have extra content about a post, or in menus.
@@ -227,7 +227,7 @@ class BaseSection (View):
visible = True # if false renders an empty string
- def get_context_data (self):
+ def get_context_data(self):
return {
'view': self,
'tag': self.tag,
@@ -237,7 +237,7 @@ class BaseSection (View):
'content': self.content,
}
- def get (self, request, website, **kwargs):
+ def get(self, request, website, **kwargs):
self.request = request
self.website = website
self.kwargs = kwargs
@@ -249,7 +249,7 @@ class BaseSection (View):
return ''
-class Section (BaseSection):
+class Section(BaseSection):
"""
A Section that can be related to an object.
"""
@@ -260,7 +260,7 @@ class Section (BaseSection):
header = ''
footer = ''
- def get_context_data (self):
+ def get_context_data(self):
context = super().get_context_data()
context.update({
'title': self.title,
@@ -269,7 +269,7 @@ class Section (BaseSection):
})
return context
- def get (self, request, object = None, **kwargs):
+ def get(self, request, object = None, **kwargs):
self.object = object or self.object
if self.object_required and not self.object:
raise ValueError('object is required by this Section but not given')
@@ -277,43 +277,43 @@ class Section (BaseSection):
class Sections:
- class Image (BaseSection):
+ class Image(BaseSection):
"""
Render an image with the given relative url.
"""
url = None
@property
- def content (self):
+ def content(self):
return ''.format(
static(self.url),
)
- class PostContent (Section):
+ class PostContent(Section):
"""
Render the content of the Post (format the text a bit and escape HTML
tags).
"""
@property
- def content (self):
+ def content(self):
content = escape(self.object.content)
content = re.sub(r'(^|\n\n)((\n?[^\n])+)', r'
\2
', content)
content = re.sub(r'\n', r' ', content)
return content
- class PostImage (Section):
+ class PostImage(Section):
"""
Render the image of the Post
"""
@property
- def content (self):
+ def content(self):
if not self.object.image:
return ''
return ''.format(
self.object.image.url
)
- class List (Section):
+ class List(Section):
"""
Section to render list. The context item 'object_list' is used as list of
items to render.
@@ -323,11 +323,13 @@ class Sections:
title = None
text = None
url = None
+ css = None
- def __init__ (self, icon, title = None, text = None, url = None):
+ def __init__(self, icon, title = None, text = None, url = None, css = None):
self.icon = icon
self.title = title
self.text = text
+ self.css = css
hide_empty = False # hides the section if the list is empty
use_icons = True # print icons
@@ -335,13 +337,13 @@ class Sections:
icon_size = '32x32' # icons size
template_name = 'aircox/cms/section_list.html'
- def get_object_list (self):
+ def get_object_list(self):
return []
- def get_context_data (self, **kwargs):
+ def get_context_data(self, **kwargs):
object_list = self.get_object_list()
self.visibility = True
- if not object_list and hide_empty:
+ if not object_list and self.hide_empty:
self.visibility = False
context = super().get_context_data(**kwargs)
@@ -353,14 +355,14 @@ class Sections:
})
return context
- class Urls (List):
+ class Urls(List):
"""
Render a list of urls of targets that are Posts
"""
classes = 'section_urls'
targets = None
- def get_object_list (self):
+ def get_object_list(self):
return [
List.Item(
target.image or None,
@@ -370,7 +372,7 @@ class Sections:
for target in self.targets
]
- class Posts (PostBaseView, Section):
+ class Posts(PostBaseView, Section):
"""
Render a list using PostListView's template.
"""
@@ -379,13 +381,13 @@ class Sections:
icon_size = '64x64'
fields = [ 'date', 'time', 'image', 'title', 'content' ]
- def get_url (self):
+ def get_url(self):
return ''
- def get_object_list (self):
+ def get_object_list(self):
return []
- def render_list (self):
+ def render_list(self):
self.embed = True
context = self.get_base_context(**self.kwargs)
context.update({
@@ -395,7 +397,7 @@ class Sections:
})
return render_to_string(PostListView.template_name, context)
- def get_context_data (self, **kwargs):
+ def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['content'] = self.render_list()
return context
diff --git a/cms/website.py b/cms/website.py
index a9de41b..e1f70ab 100644
--- a/cms/website.py
+++ b/cms/website.py
@@ -35,6 +35,7 @@ class Website:
raise ValueError('A model has yet been registered under "{}"'
.format(name))
self.registry[name] = model
+ model._website = self
return name
def register_detail (self, name, model, view = views.PostDetailView,
@@ -48,7 +49,7 @@ class Website:
model = model,
**view_kwargs,
)
- self.urls.append(routes.DetailRoute.as_url(name, model, view))
+ self.urls.append(routes.DetailRoute.as_url(name, view))
self.registry[name] = model
def register_list (self, name, model, view = views.PostListView,
@@ -62,7 +63,7 @@ class Website:
model = model,
**view_kwargs
)
- self.urls += [ route.as_url(name, model, view) for route in routes ]
+ self.urls += [ route.as_url(name, view) for route in routes ]
self.registry[name] = model
def register (self, name, model, sections = None, routes = None,
diff --git a/liquidsoap/management/commands/liquidsoap.py b/liquidsoap/management/commands/liquidsoap.py
index e6ca1b5..c68ef7d 100644
--- a/liquidsoap/management/commands/liquidsoap.py
+++ b/liquidsoap/management/commands/liquidsoap.py
@@ -97,7 +97,9 @@ class Monitor:
args = {'start__gt': prev_diff.start } if prev_diff else {}
next_diff = programs.Diffusion \
.get(controller.station, now, now = True,
- sounds__isnull = False, **args) \
+ type = programs.Diffusion.Type.normal,
+ sounds__isnull = False,
+ **args) \
.prefetch_related('sounds')
if next_diff:
next_diff = next_diff[0]
diff --git a/programs/admin.py b/programs/admin.py
index 163b8c3..7d49e4b 100755
--- a/programs/admin.py
+++ b/programs/admin.py
@@ -91,7 +91,7 @@ class DiffusionAdmin (admin.ModelAdmin):
return ', '.join(sounds) if sounds else ''
def conflicts (self, obj):
- if obj.type == Diffusion.Type['unconfirmed']:
+ if obj.type == Diffusion.Type.unconfirmed:
return ', '.join([ str(d) for d in obj.get_conflicts()])
return ''
@@ -115,9 +115,9 @@ class DiffusionAdmin (admin.ModelAdmin):
qs = super(DiffusionAdmin, self).get_queryset(request)
if '_changelist_filters' in request.GET or \
'type__exact' in request.GET and \
- str(Diffusion.Type['unconfirmed']) in request.GET['type__exact']:
+ str(Diffusion.Type.unconfirmed) in request.GET['type__exact']:
return qs
- return qs.exclude(type = Diffusion.Type['unconfirmed'])
+ return qs.exclude(type = Diffusion.Type.unconfirmed)
@admin.register(Log)
diff --git a/programs/management/commands/diffusions_monitor.py b/programs/management/commands/diffusions_monitor.py
index 78c48e0..5568092 100644
--- a/programs/management/commands/diffusions_monitor.py
+++ b/programs/management/commands/diffusions_monitor.py
@@ -46,15 +46,15 @@ class Actions:
continue
if conflict.pk in saved_items and \
- conflict.type != Diffusion.Type['unconfirmed']:
- conflict.type = Diffusion.Type['unconfirmed']
+ conflict.type != Diffusion.Type.unconfirmed:
+ conflict.type = Diffusion.Type.unconfirmed
conflict.save()
if not conflicts:
- item.type = Diffusion.Type['normal']
+ item.type = Diffusion.Type.normal
return 0
- item.type = Diffusion.Type['unconfirmed']
+ item.type = Diffusion.Type.unconfirmed
return len(conflicts)
@classmethod
@@ -93,14 +93,14 @@ class Actions:
@staticmethod
def clean (date):
- qs = Diffusion.objects.filter(type = Diffusion.Type['unconfirmed'],
+ qs = Diffusion.objects.filter(type = Diffusion.Type.unconfirmed,
start__lt = date)
logger.info('[clean] %d diffusions will be removed', qs.count())
qs.delete()
@staticmethod
def check (date):
- qs = Diffusion.objects.filter(type = Diffusion.Type['unconfirmed'],
+ qs = Diffusion.objects.filter(type = Diffusion.Type.unconfirmed,
start__gt = date)
items = []
for diffusion in qs:
diff --git a/programs/management/commands/sounds_monitor.py b/programs/management/commands/sounds_monitor.py
index 15240eb..b84bff7 100644
--- a/programs/management/commands/sounds_monitor.py
+++ b/programs/management/commands/sounds_monitor.py
@@ -162,9 +162,9 @@ class MonitorHandler (PatternMatchingEventHandler):
"""
self.subdir = subdir
if self.subdir == settings.AIRCOX_SOUND_ARCHIVES_SUBDIR:
- self.sound_kwargs = { 'type': Sound.Type['archive'] }
+ self.sound_kwargs = { 'type': Sound.Type.archive }
else:
- self.sound_kwargs = { 'type': Sound.Type['excerpt'] }
+ self.sound_kwargs = { 'type': Sound.Type.excerpt }
patterns = ['*/{}/*{}'.format(self.subdir, ext)
for ext in settings.AIRCOX_SOUND_FILE_EXT ]
@@ -264,11 +264,11 @@ class Command (BaseCommand):
logger.info('#%d %s', program.id, program.name)
self.scan_for_program(
program, settings.AIRCOX_SOUND_ARCHIVES_SUBDIR,
- type = Sound.Type['archive'],
+ type = Sound.Type.archive,
)
self.scan_for_program(
program, settings.AIRCOX_SOUND_EXCERPTS_SUBDIR,
- type = Sound.Type['excerpt'],
+ type = Sound.Type.excerpt,
)
def scan_for_program (self, program, subdir, **sound_kwargs):
diff --git a/programs/models.py b/programs/models.py
index 3140154..6165d2e 100755
--- a/programs/models.py
+++ b/programs/models.py
@@ -1,6 +1,7 @@
import os
import shutil
import logging
+from enum import Enum, IntEnum
from django.db import models
from django.template.defaultfilters import slugify
@@ -19,7 +20,7 @@ import aircox.programs.settings as settings
logger = logging.getLogger('aircox.core')
-def date_or_default (date, date_only = False):
+def date_or_default(date, date_only = False):
"""
Return date or default value (now) if not defined, and remove time info
if date_only is True
@@ -32,20 +33,20 @@ def date_or_default (date, date_only = False):
return date
-class Nameable (models.Model):
+class Nameable(models.Model):
name = models.CharField (
_('name'),
max_length = 128,
)
@property
- def slug (self):
+ def slug(self):
"""
Slug based on the name. We replace '-' by '_'
"""
return slugify(self.name).replace('-', '_')
- def __str__ (self):
+ def __str__(self):
#if self.pk:
# return '#{} {}'.format(self.pk, self.name)
return '{}'.format(self.name)
@@ -54,7 +55,7 @@ class Nameable (models.Model):
abstract = True
-class Track (Nameable):
+class Track(Nameable):
"""
Track of a playlist of a diffusion. The position can either be expressed
as the position in the playlist or as the moment in seconds it started.
@@ -87,7 +88,7 @@ class Track (Nameable):
verbose_name_plural = _('Tracks')
-class Sound (Nameable):
+class Sound(Nameable):
"""
A Sound is the representation of a sound file that can be either an excerpt
or a complete archive of the related diffusion.
@@ -95,17 +96,14 @@ class Sound (Nameable):
The podcasting and public access permissions of a Sound are managed through
the related program info.
"""
- Type = {
- 'other': 0x00,
- 'archive': 0x01,
- 'excerpt': 0x02,
- }
- for key, value in Type.items():
- ugettext_lazy(key)
+ class Type(IntEnum):
+ other = 0x00,
+ archive = 0x01,
+ excerpt = 0x02,
type = models.SmallIntegerField(
verbose_name = _('type'),
- choices = [ (y, x) for x,y in Type.items() ],
+ choices = [ (y, _(x)) for x,y in Type.__members__.items() ],
blank = True, null = True
)
path = models.FilePathField(
@@ -148,7 +146,7 @@ class Sound (Nameable):
help_text = _('sound\'s is accessible through the website')
)
- def get_mtime (self):
+ def get_mtime(self):
"""
Get the last modification date from file
"""
@@ -158,13 +156,13 @@ class Sound (Nameable):
mtime = mtime.replace(microsecond = 0)
return tz.make_aware(mtime, tz.get_current_timezone())
- def file_exists (self):
+ def file_exists(self):
"""
Return true if the file still exists
"""
return os.path.exists(self.path)
- def check_on_file (self):
+ def check_on_file(self):
"""
Check sound file info again'st self, and update informations if
needed (do not save). Return True if there was changes.
@@ -188,7 +186,7 @@ class Sound (Nameable):
return True
return old_removed != self.removed
- def save (self, check = True, *args, **kwargs):
+ def save(self, check = True, *args, **kwargs):
if check:
self.check_on_file()
@@ -198,7 +196,7 @@ class Sound (Nameable):
self.name = self.name.replace('_', ' ')
super().save(*args, **kwargs)
- def __str__ (self):
+ def __str__(self):
return '/'.join(self.path.split('/')[-3:])
class Meta:
@@ -206,7 +204,7 @@ class Sound (Nameable):
verbose_name_plural = _('Sounds')
-class Stream (models.Model):
+class Stream(models.Model):
"""
When there are no program scheduled, it is possible to play sounds
in order to avoid blanks. A Stream is a Program that plays this role,
@@ -238,7 +236,7 @@ class Stream (models.Model):
)
-class Schedule (models.Model):
+class Schedule(models.Model):
"""
A Schedule defines time slots of programs' diffusions. It can be an initial
run or a rerun (in such case it is linked to the related schedule).
@@ -282,7 +280,7 @@ class Schedule (models.Model):
help_text = 'this schedule is a rerun of this one',
)
- def match (self, date = None, check_time = True):
+ def match(self, date = None, check_time = True):
"""
Return True if the given datetime matches the schedule
"""
@@ -292,7 +290,7 @@ class Schedule (models.Model):
return self.date.time() == date.time() if check_time else True
return False
- def match_week (self, date = None):
+ def match_week(self, date = None):
"""
Return True if the given week number matches the schedule, False
otherwise.
@@ -313,13 +311,13 @@ class Schedule (models.Model):
return self.frequency == 0b1111
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 date.replace(hour = self.date.hour, minute = self.date.minute)
- def dates_of_month (self, date = None):
+ def dates_of_month(self, date = None):
"""
Return a list with all matching dates of date.month (=today)
"""
@@ -361,7 +359,7 @@ class Schedule (models.Model):
date += tz.timedelta(days = 7)
return [self.normalize(date) for date in dates]
- def diffusions_of_month (self, date, exclude_saved = False):
+ def diffusions_of_month(self, date, exclude_saved = False):
"""
Return a list of Diffusion instances, from month of the given date, that
can be not in the database.
@@ -394,19 +392,19 @@ class Schedule (models.Model):
else None
diffusions.append(Diffusion(
program = self.program,
- type = Diffusion.Type['unconfirmed'],
+ type = Diffusion.Type.unconfirmed,
initial = first_diffusion if self.initial else None,
start = date,
end = date + duration,
))
return diffusions
- def __str__ (self):
+ def __str__(self):
return ' | '.join([ '#' + str(self.id), self.program.name,
self.get_frequency_display(),
self.date.strftime('%a %H:%M') ])
- def save (self, *args, **kwargs):
+ def save(self, *args, **kwargs):
if self.initial:
self.program = self.initial.program
self.duration = self.initial.duration
@@ -418,7 +416,7 @@ class Schedule (models.Model):
verbose_name_plural = _('Schedules')
-class Station (Nameable):
+class Station(Nameable):
"""
A Station regroup one or more programs (stream and normal), and is the top
element used to generate streams outputs and configuration.
@@ -444,7 +442,7 @@ class Station (Nameable):
)
-class Program (Nameable):
+class Program(Nameable):
"""
A Program can either be a Streamed or a Scheduled program.
@@ -473,14 +471,14 @@ class Program (Nameable):
)
@property
- def path (self):
+ def path(self):
"""
Return the path to the programs directory
"""
return os.path.join(settings.AIRCOX_PROGRAMS_DIR,
self.slug + '_' + str(self.id) )
- def ensure_dir (self, subdir = None):
+ def ensure_dir(self, subdir = None):
"""
Make sur the program's dir exists (and optionally subdir). Return True
if the dir (or subdir) exists.
@@ -490,7 +488,7 @@ class Program (Nameable):
os.makedirs(path, exist_ok = True)
return os.path.exists(path)
- def find_schedule (self, date):
+ def find_schedule(self, date):
"""
Return the first schedule that matches a given date.
"""
@@ -499,12 +497,12 @@ class Program (Nameable):
if schedule.match(date, check_time = False):
return schedule
- def __init__ (self, *kargs, **kwargs):
+ def __init__(self, *kargs, **kwargs):
super().__init__(*kargs, **kwargs)
if self.name:
self.__original_path = self.path
- def save (self, *kargs, **kwargs):
+ def save(self, *kargs, **kwargs):
super().save(*kargs, **kwargs)
if hasattr(self, '__original_path') and \
self.__original_path != self.path and \
@@ -520,7 +518,7 @@ class Program (Nameable):
sound.save()
@classmethod
- def get_from_path (cl, path):
+ def get_from_path(cl, path):
"""
Return a Program from the given path. We assume the path has been
given in a previous time by this model (Program.path getter).
@@ -537,7 +535,7 @@ class Program (Nameable):
return qs[0] if qs else None
-class Diffusion (models.Model):
+class Diffusion(models.Model):
"""
A Diffusion is an occurrence of a Program that is scheduled on the
station's timetable. It can be a rerun of a previous diffusion. In such
@@ -555,13 +553,10 @@ class Diffusion (models.Model):
- cancel: the diffusion has been canceled
- stop: the diffusion has been manually stopped
"""
- Type = {
- 'normal': 0x00, # diffusion is planified
- 'unconfirmed': 0x01, # scheduled by the generator but not confirmed for diffusion
- 'cancel': 0x02, # diffusion canceled
- }
- for key, value in Type.items():
- ugettext_lazy(key)
+ class Type(IntEnum):
+ normal = 0x00
+ unconfirmed = 0x01
+ canceled = 0x02
# common
program = models.ForeignKey (
@@ -576,7 +571,7 @@ class Diffusion (models.Model):
# specific
type = models.SmallIntegerField(
verbose_name = _('type'),
- choices = [ (y, x) for x,y in Type.items() ],
+ choices = [ (y, _(x)) for x,y in Type.__members__.items() ],
)
initial = models.ForeignKey (
'self',
@@ -588,11 +583,11 @@ class Diffusion (models.Model):
end = models.DateTimeField( _('end of the diffusion') )
@property
- def duration (self):
+ def duration(self):
return self.end - self.start
@property
- def date (self):
+ def date(self):
return self.start
@property
@@ -604,29 +599,30 @@ class Diffusion (models.Model):
playlist.sort()
return playlist
- def archives_duration (self):
+ def archives_duration(self):
"""
Get total duration of the archives. May differ from the schedule
duration.
"""
sounds = self.initial.sounds if self.initial else self.sounds
r = [ sound.duration
- for sound in sounds.filter(type = Sound.Type['archive'])
+ for sound in sounds.filter(type = Sound.Type.archive)
if sound.duration ]
return utils.time_sum(r)
- def get_archives (self):
+ def get_archives(self):
"""
Return an ordered list of archives sounds for the given episode.
"""
sounds = self.initial.sounds if self.initial else self.sounds
r = [ sound for sound in sounds.all().order_by('path')
- if sound.type == Sound.Type['archive'] ]
+ if sound.type == Sound.Type.archive ]
return r
@classmethod
- def get (cl, station = None, date = None,
+ def get(cl, station = None, date = None,
now = False, next = False, prev = False,
+ queryset = None,
**filter_args):
"""
Return a queryset of diffusions, depending on value of now/next/prev
@@ -634,6 +630,8 @@ class Diffusion (models.Model):
- next: that start after date
- prev: that end before date
+ If queryset is not given, use self.objects.all
+
Diffusions are ordered by +start for now and next; -start for prev
"""
#FIXME: conflicts? ( + calling functions)
@@ -669,7 +667,7 @@ class Diffusion (models.Model):
"""
return self.start < date_or_default(date) < self.end
- def get_conflicts (self):
+ def get_conflicts(self):
"""
Return a list of conflictual diffusions, based on the scheduled duration.
"""
@@ -681,7 +679,7 @@ class Diffusion (models.Model):
)
return r
- def save (self, *args, **kwargs):
+ def save(self, *args, **kwargs):
if self.initial:
# force link to the top initial diffusion
if self.initial.initial:
@@ -689,7 +687,7 @@ class Diffusion (models.Model):
self.program = self.initial.program
super().save(*args, **kwargs)
- def __str__ (self):
+ def __str__(self):
return '{self.program.name} {date} #{self.pk}'.format(
self=self, date=self.date.strftime('%Y-%m-%d %H:%M')
)
@@ -702,7 +700,7 @@ class Diffusion (models.Model):
('programming', _('edit the diffusion\'s planification')),
)
-class Log (models.Model):
+class Log(models.Model):
"""
Log a played sound start and stop, or a single message
"""
@@ -733,14 +731,14 @@ class Log (models.Model):
@classmethod
- def get_for_related_model (cl, model):
+ def get_for_related_model(cl, model):
"""
Return a queryset that filter related_type to the given one.
"""
return cl.objects.filter(related_type__pk =
ContentType.objects.get_for_model(model).id)
- def print (self):
+ def print(self):
logger.info('log #%s: %s%s',
str(self),
self.comment or '',
@@ -748,7 +746,7 @@ class Log (models.Model):
if self.related_object else ''
)
- def __str__ (self):
+ def __str__(self):
return '#{} ({}, {})'.format(
self.id, self.date.strftime('%Y-%m-%d %H:%M'), self.source
)
diff --git a/programs/tests.py b/programs/tests.py
index cf833fa..ce26860 100755
--- a/programs/tests.py
+++ b/programs/tests.py
@@ -10,7 +10,7 @@ class Programs (TestCase):
def setUp (self):
stream = Stream.objects.get_or_create(
name = 'diffusions',
- defaults = { 'type': Stream.Type['schedule'] }
+ defaults = { 'type': Stream.Type.schedule }
)[0]
Program.objects.create(name = 'source', stream = stream)
Program.objects.create(name = 'microouvert', stream = stream)