add manager for programs.Diffusion + adapt; list_by_date's date urls; website's section Log algorithm

This commit is contained in:
bkfox 2016-07-18 18:29:24 +02:00
parent 6b7255112d
commit e0edd7fc7d
5 changed files with 127 additions and 113 deletions

View File

@ -1,3 +1,5 @@
import datetime
from django.db import models from django.db import models
from django.utils import timezone as tz from django.utils import timezone as tz
from django.conf.urls import url from django.conf.urls import url
@ -176,17 +178,13 @@ class DateRoute(Route):
] ]
@classmethod @classmethod
def get_queryset(cl, model, request, year, month, day, def get_queryset(cl, model, request, year, month, day, **kwargs):
attr='date', **kwargs):
""" """
* request: optional * request: optional
* attr: name of the attribute to check the date against * attr: name of the attribute to check the date against
""" """
return model.objects.filter(**{ date = datetime.date(int(year), int(month), int(day))
attr + '__year': int(year), return model.objects.filter(date__contains = date)
attr + '__month': int(month),
attr + '__day': int(day)
})
@classmethod @classmethod
def get_title(cl, model, request, year, month, day, **kwargs): def get_title(cl, model, request, year, month, day, **kwargs):

View File

@ -108,7 +108,7 @@ class Monitor:
.order_by('date').last() .order_by('date').last()
if not diff_log or \ if not diff_log or \
not diff_log.related.is_date_in_my_range(now): not diff_log.related.is_date_in_range(now):
return None, [] return None, []
# sound has switched? assume it has been (forced to) stopped # sound has switched? assume it has been (forced to) stopped
@ -138,10 +138,8 @@ class Monitor:
now = tz.make_aware(tz.datetime.now()) now = tz.make_aware(tz.datetime.now())
args = {'start__gt': diff.start } if diff else {} args = {'start__gt': diff.start } if diff else {}
diff = programs.Diffusion.get( diff = programs.Diffusion.objects.get_at(now).filter(
now, now = True,
type = programs.Diffusion.Type.normal, type = programs.Diffusion.Type.normal,
sound__type = programs.Sound.Type.archive, sound__type = programs.Sound.Type.archive,
sound__removed = False, sound__removed = False,
**args **args

View File

@ -27,7 +27,6 @@
- admin cms - admin cms
-> sections/actions and django decorator? -> sections/actions and django decorator?
-> enhance calendar with possible actions? -> enhance calendar with possible actions?
- sections id generator
- website: - website:
- diffusions: - diffusions:
@ -39,7 +38,6 @@
- remove from playing playlist -> stop - remove from playing playlist -> stop
- date_by_list: - date_by_list:
- sections' url - sections' url
- list of played diffusions and tracks when non-stop;
# Long term TODO # Long term TODO
- automatic cancel of passed diffusion based on logs? - automatic cancel of passed diffusion based on logs?

View File

@ -1,3 +1,4 @@
import datetime
import os import os
import shutil import shutil
import logging import logging
@ -36,7 +37,7 @@ def date_or_default(date, no_time = False):
Return date or default value (now) if not defined, and remove time info Return date or default value (now) if not defined, and remove time info
if date_only is True if date_only is True
""" """
date = date or tz.datetime.today() date = date or tz.now()
if not tz.is_aware(date): if not tz.is_aware(date):
date = tz.make_aware(date) date = tz.make_aware(date)
if no_time: if no_time:
@ -576,6 +577,49 @@ class Program(Nameable):
return qs[0] if qs else None return qs[0] if qs else None
class DiffusionManager(models.Manager):
def get_at(self, date = None):
"""
Return a queryset of diffusions that have the given date
in their range.
If date is a datetime.date object, check only against the
date.
"""
date = date or tz.now()
if issubclass(type(date), datetime.date):
return self.filter(
models.Q(start__contains = date) | \
models.Q(end__contains = date)
)
return self.filter(
models.Q(start__lte = date, end__gte = date) |
# FIXME: should not be here?
models.Q(start__gte = date),
).order_by('start')
def get_after(self, date = None):
"""
Return a queryset of diffusions that happen after the given
date.
"""
date = date_or_default(date)
return self.filter(
start__gte = date,
).order_by('start')
def get_before(self, date):
"""
Return a queryset of diffusions that finish before the given
date.
"""
date = date_or_default(date)
return self.filter(
end__lte = date,
).order_by('start')
class Diffusion(models.Model): class Diffusion(models.Model):
""" """
A Diffusion is an occurrence of a Program that is scheduled on the A Diffusion is an occurrence of a Program that is scheduled on the
@ -594,6 +638,8 @@ class Diffusion(models.Model):
- cancel: the diffusion has been canceled - cancel: the diffusion has been canceled
- stop: the diffusion has been manually stopped - stop: the diffusion has been manually stopped
""" """
objects = DiffusionManager()
class Type(IntEnum): class Type(IntEnum):
normal = 0x00 normal = 0x00
unconfirmed = 0x01 unconfirmed = 0x01
@ -642,52 +688,13 @@ class Diffusion(models.Model):
return sounds.filter(type = Sound.Type.archive, removed = False). \ return sounds.filter(type = Sound.Type.archive, removed = False). \
order_by('path') order_by('path')
@classmethod def is_date_in_range(self, date = None):
def get(cl, date = None,
now = False, next = False, prev = False,
queryset = None,
**filter_args):
"""
Return a queryset of diffusions, depending on value of now/next/prev
- now: that have date in their start-end range or start after
- 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)
date = date_or_default(date)
if queryset is None:
queryset = cl.objects
if now:
return queryset.filter(
models.Q(start__lte = date,
end__gte = date) |
models.Q(start__gte = date),
**filter_args
).order_by('start')
if next:
return queryset.filter(
start__gte = date,
**filter_args
).order_by('start')
if prev:
return queryset.filter(
end__lte = date,
**filter_args
).order_by('-start')
def is_date_in_my_range(self, date = None):
""" """
Return true if the given date is in the diffusion's start-end Return true if the given date is in the diffusion's start-end
range. range.
""" """
return self.start < date_or_default(date) < self.end date = date or tz.now()
return self.start < date < self.end
def get_conflicts(self): def get_conflicts(self):
""" """

View File

@ -1,9 +1,11 @@
import json import json
import datetime
from django.utils import timezone as tz from django.utils import timezone as tz
from django.utils.translation import ugettext as _, ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy
import aircox.programs.models as programs import aircox.programs.models as programs
import aircox.controllers.models as controllers
import aircox.cms.models as cms import aircox.cms.models as cms
import aircox.cms.routes as routes import aircox.cms.routes as routes
import aircox.cms.sections as sections import aircox.cms.sections as sections
@ -30,12 +32,12 @@ class Player(sections.Section):
@expose @expose
def on_air(cl, request): def on_air(cl, request):
qs = programs.Diffusion.get( now = tz.now()
now = True, qs = programs.Diffusion.objects.get_at(now).filter(
type = programs.Diffusion.Type.normal type = programs.Diffusion.Type.normal
) )
if not qs or not qs[0].is_date_in_my_range(): if not qs or not qs[0].is_date_in_range():
return {} return {}
qs = qs[0] qs = qs[0]
@ -214,7 +216,8 @@ class Sounds(sections.List):
class ListByDate(sections.List): class ListByDate(sections.List):
""" """
List that add a navigation by date in its header. List that add a navigation by date in its header. It aims to be
used with DateRoute.
""" """
template_name = 'aircox/website/list_by_date.html' template_name = 'aircox/website/list_by_date.html'
message_empty = '' message_empty = ''
@ -253,15 +256,19 @@ class ListByDate(sections.List):
return [ first + tz.timedelta(days=i) for i in range(0, self.nav_days) ] return [ first + tz.timedelta(days=i) for i in range(0, self.nav_days) ]
def date_or_default(self): def date_or_default(self):
"""
Return self.date or create a date if needed, using kwargs'
year, month, day attributes if exists (otherwise, use today)
"""
if self.date: if self.date:
return self.date return datetime.date(self.date)
elif self.kwargs and 'year' in self.kwargs: elif self.kwargs and 'year' in self.kwargs:
return tz.datetime(year = int(self.kwargs['year']), return datetime.date(
month = int(self.kwargs['month']), year = int(self.kwargs['year']),
day = int(self.kwargs['day']), month = int(self.kwargs['month']),
hour = 0, minute = 0, second = 0, day = int(self.kwargs['day'])
microsecond = 0) )
return tz.now() return datetime.date.today()
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
@ -270,6 +277,7 @@ class ListByDate(sections.List):
dates = [ (date, self.get_date_url(date)) dates = [ (date, self.get_date_url(date))
for date in self.nav_dates(date) ] for date in self.nav_dates(date) ]
# FIXME
next_week = dates[-1][0] + tz.timedelta(days=1) next_week = dates[-1][0] + tz.timedelta(days=1)
next_week = self.get_date_url(next_week) next_week = self.get_date_url(next_week)
@ -289,18 +297,22 @@ class ListByDate(sections.List):
@staticmethod @staticmethod
def get_date_url(date): def get_date_url(date):
""" """
return a url to the list for the given date return an url for the given date
""" """
return self.view.website.reverse(
model = self.model, route = routes.DateRoute,
year = date.year, month = date.month, day = date.day,
)
@property @property
def url(self): def url(self):
return None return None
class Schedule(Diffusions,ListByDate): class Schedule(Diffusions,ListByDate):
""" """
Render a list of diffusions in the form of a schedule Render a list of diffusions in the form of a schedule
""" """
model = models.Diffusion
fields = [ 'time', 'image', 'title', 'content', 'info', 'actions' ] fields = [ 'time', 'image', 'title', 'content', 'info', 'actions' ]
truncate = 30 truncate = 30
@ -310,10 +322,7 @@ class Schedule(Diffusions,ListByDate):
def get_object_list(self): def get_object_list(self):
date = self.date_or_default() date = self.date_or_default()
diffs = routes.DateRoute.get_queryset( diffs = programs.Diffusion.objects.get_at(date).order_by('start')
programs.Diffusion, None, date.year, date.month, date.day,
attr = 'start'
).order_by('start')
return models.Diffusion.objects.get_for(diffs, create = True) return models.Diffusion.objects.get_for(diffs, create = True)
@staticmethod @staticmethod
@ -329,54 +338,58 @@ class Schedule(Diffusions,ListByDate):
class Logs(ListByDate): class Logs(ListByDate):
""" """
Return a list of played stream sounds and diffusions. Print a list of played stream tracks and diffusions.
Note that for the moment we don't print if the track has been
partially hidden by a scheduled diffusion
""" """
model = controllers.Log
@staticmethod @staticmethod
def make_item(log): def make_item(item):
""" """
Return a list of items to add to the playlist. Return a list of items to add to the playlist.
Only support Log related to a Track and programs.Diffusion
""" """
if issubclass(type(log.related), programs.Diffusion): if issubclass(type(item), programs.Diffusion):
diff = log.related return models.Diffusion.objects.get_for(
post = models.Diffusion.objects.filter(related = diff).first() \ item, create = True, save = False
or models.Program.objects.filter(related = diff.program).first() \
or ListItem(title = diff.program.name)
post.date = diff.start
return post
if issubclass(type(log.related), programs.Track):
track = log.related
post = ListItem(
title = '{artist} &#8212; {name}'.format(
artist = track.artist,
name = track.name,
),
date = log.date,
content = track.info,
info = '',
) )
track = log.related
post = ListItem(
title = '{artist} &#8212; {name}'.format(
artist = track.artist,
name = track.name,
),
date = log.date,
content = track.info,
info = '',
)
return post return post
@staticmethod
def make_diff(diff):
pass
def get_object_list(self): def get_object_list(self):
return [] date = self.date_or_default()
station = self.view.website.station if date > datetime.date.today():
qs = station.get_played( return []
models = [ programs.Diffusion, programs.Track ],
).filter( logs = controllers.Log.get_for(model = programs.Track) \
date__year = int(year), date__month = int(month), .filter(date__contains = date) \
date__day = int(day) .order_by('date')
)
# TODO for each, exclude if there is a corresponding diffusion diffs = programs.Diffusion.objects.get_at(date) \
# (that has not been logged) .filter(type = programs.Diffusion.Type.normal)
# if diff and diff != last_diff:
# r.append(cl.make_item items = []
# return [ cl.make_item(log) for log in qs ] prev_diff = None
for diff in diffs:
logs_ = logs.filter(date__gt = prev_diff.end,
date__lt = diff.start) \
if prev_diff else \
logs.filter(date__lt = diff.start)
prev_diff = diff
items.extend(logs_)
items.append(diff)
return list(map(self.make_item, items))
@staticmethod
def get_date_url(date):
return 'TODO'