forked from rc/aircox
297 lines
9.9 KiB
Python
297 lines
9.9 KiB
Python
from collections import OrderedDict, deque
|
|
import datetime
|
|
|
|
from django.http import Http404
|
|
from django.shortcuts import get_object_or_404
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.generic import DetailView, ListView
|
|
from django.views.generic.base import TemplateResponseMixin, ContextMixin
|
|
|
|
from content_editor.contents import contents_for_item
|
|
|
|
from aircox import models as aircox
|
|
from .models import Site, Page, DiffusionPage, ProgramPage, \
|
|
get_diffusions_with_page
|
|
from .renderer import site_renderer, page_renderer
|
|
|
|
|
|
def route_page(request, path=None, *args, model=None, site=None, **kwargs):
|
|
"""
|
|
Route request to page of the provided path. If model is provided, uses
|
|
it.
|
|
"""
|
|
# TODO/FIXME: django site framework | site from request host
|
|
# TODO: extra page kwargs (as in pepr)
|
|
site = Site.objects.all().order_by('-default').first() \
|
|
if site is None else site
|
|
|
|
model = model if model is not None else Page
|
|
page = get_object_or_404(
|
|
model.objects.select_subclasses().live(),
|
|
path=path
|
|
)
|
|
kwargs['page'] = page
|
|
return page.view(request, *args, site=site, **kwargs)
|
|
|
|
|
|
class BaseView(TemplateResponseMixin, ContextMixin):
|
|
site = None
|
|
""" Current website """
|
|
nav_side = False
|
|
""" Show side navigation """
|
|
title = None
|
|
""" Page title """
|
|
cover = None
|
|
""" Page cover """
|
|
|
|
def dispatch(self, request, *args, site=None, **kwargs):
|
|
self.site = site if site is not None else \
|
|
Site.objects.all().order_by('-default').first()
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
if kwargs.get('site_regions') is None:
|
|
contents = contents_for_item(
|
|
self.site, site_renderer._renderers.keys())
|
|
kwargs['site_regions'] = contents.render_regions(site_renderer)
|
|
|
|
kwargs.setdefault('site', self.site)
|
|
kwargs.setdefault('cover', self.cover)
|
|
kwargs.setdefault('nav_side', self.nav_side)
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
class PageView(BaseView, DetailView):
|
|
""" Base view class for pages. """
|
|
template_name = 'aircox_web/page.html'
|
|
context_object_name = 'page'
|
|
page = None
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().live()
|
|
|
|
def get_context_data(self, **kwargs):
|
|
page = getattr(self, 'object', None)
|
|
if page is not None:
|
|
if kwargs.get('regions') is None:
|
|
contents = contents_for_item(
|
|
page, page_renderer._renderers.keys())
|
|
kwargs['regions'] = contents.render_regions(page_renderer)
|
|
|
|
kwargs.setdefault('title', page.title)
|
|
kwargs.setdefault('cover', page.cover)
|
|
kwargs.setdefault('page', page)
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
class BaseProgramView(PageView):
|
|
""" Base view class for programs and their sub-pages. """
|
|
nav_side = True
|
|
list_count=5
|
|
|
|
def get_diffusions_queryset(self, program, queryset=None):
|
|
qs = get_diffusions_with_page() if queryset is None else queryset
|
|
return qs.before().filter(program=program).order_by('-start')
|
|
|
|
def get_context_data(self, program, **kwargs):
|
|
if not hasattr(program, 'page') or not program.page.is_published:
|
|
raise Http404
|
|
|
|
if 'diffusions' not in kwargs:
|
|
diffs = self.get_diffusions_queryset(program)[:self.list_count]
|
|
kwargs['diffusions'] = diffs
|
|
return super().get_context_data(program=program, **kwargs)
|
|
|
|
|
|
class ProgramPageView(BaseProgramView):
|
|
template_name = 'aircox_web/program_page.html'
|
|
model = ProgramPage
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().select_related('program')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
kwargs.setdefault('program', self.object.program)
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
class DiffusionPageView(BaseProgramView):
|
|
template_name = 'aircox_web/program_base.html'
|
|
model = DiffusionPage
|
|
|
|
def get_podcasts(self, diffusion):
|
|
return aircox.Sound.objects.diffusion(diffusion).podcasts()
|
|
|
|
def get_context_data(self, **kwargs):
|
|
diffusion = self.object.diffusion
|
|
kwargs.setdefault('program', diffusion.program)
|
|
kwargs.setdefault('parent', getattr(kwargs['program'], 'page', None))
|
|
if not 'podcasts' in kwargs:
|
|
kwargs['podcasts'] = self.get_podcasts(diffusion)
|
|
print('get prodcasts...', kwargs['podcasts'], diffusion)
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
# TODO: pagination: in template, only a limited number of pages displayed
|
|
# DiffusionsView use diffusion instead of diffusion page for different reasons:
|
|
# more straightforward, it handles reruns
|
|
class DiffusionsView(BaseView, ListView):
|
|
template_name = 'aircox_web/diffusions.html'
|
|
model = aircox.Diffusion
|
|
paginate_by = 30
|
|
program = None
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
program_slug = kwargs.get('program_slug')
|
|
if program_slug:
|
|
self.program = get_object_or_404(
|
|
aircox.Program, slug=kwargs.get('program_slug'))
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
qs = get_diffusions_with_page(super().get_queryset()) \
|
|
.select_related('page', 'program')
|
|
if self.program:
|
|
qs = qs.filter(program=self.program)
|
|
return qs.order_by('-start')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
program = kwargs.setdefault('program', self.program)
|
|
if program is not None and hasattr(program, 'page'):
|
|
kwargs.setdefault('cover', program.page.cover)
|
|
kwargs.setdefault('parent', program.page)
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
class TimetableView(BaseView, ListView):
|
|
""" View for timetables """
|
|
template_name = 'aircox_web/timetable.html'
|
|
model = aircox.Diffusion
|
|
|
|
title = _('Timetable')
|
|
|
|
date = None
|
|
start = None
|
|
end = None
|
|
|
|
def get_queryset(self):
|
|
self.date = self.kwargs.get('date') or datetime.date.today()
|
|
self.start = self.date - datetime.timedelta(days=self.date.weekday())
|
|
self.end = self.start + datetime.timedelta(days=7)
|
|
return super().get_queryset().station(self.site.station) \
|
|
.range(self.start, self.end) \
|
|
.order_by('start')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
# regoup by dates
|
|
by_date = OrderedDict()
|
|
date = self.start
|
|
while date < self.end:
|
|
by_date[date] = []
|
|
date += datetime.timedelta(days=1)
|
|
|
|
for diffusion in self.object_list:
|
|
if not diffusion.date in by_date:
|
|
continue
|
|
by_date[diffusion.date].append(diffusion)
|
|
|
|
return super().get_context_data(
|
|
by_date=by_date,
|
|
date=self.date,
|
|
start=self.start,
|
|
end=self.end - datetime.timedelta(days=1),
|
|
prev_date=self.start - datetime.timedelta(days=1),
|
|
next_date=self.end + datetime.timedelta(days=1),
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class LogViewBase(ListView):
|
|
station = None
|
|
date = None
|
|
delta = None
|
|
|
|
def get_queryset(self):
|
|
# only get logs for tracks: log for diffusion will be retrieved
|
|
# by the diffusions' queryset.
|
|
return super().get_queryset().station(self.station).on_air() \
|
|
.at(self.date).filter(track__isnull=False)
|
|
|
|
def get_diffusions_queryset(self):
|
|
return aircox.Diffusion.objects.station(self.station).on_air() \
|
|
.at(self.date)
|
|
|
|
def get_object_list(self, queryset):
|
|
diffs = deque(self.get_diffusions_queryset().order_by('start'))
|
|
logs = list(queryset.order_by('date'))
|
|
if not len(diffs):
|
|
return logs
|
|
|
|
object_list = []
|
|
diff = diffs.popleft()
|
|
last_collision = None
|
|
|
|
# diff.start < log on first diff
|
|
# diff.end > log on last diff
|
|
|
|
for index, log in enumerate(logs):
|
|
# get next diff
|
|
if diff.end < log.date:
|
|
diff = diffs.popleft() if len(diffs) else None
|
|
|
|
# no more diff that can collide: return list
|
|
if diff is None:
|
|
return object_list + logs[index:]
|
|
|
|
# diff colliding with log
|
|
if diff.start <= log.date <= diff.end:
|
|
if object_list[-1] is not diff:
|
|
object_list.append(diff)
|
|
last_collision = log
|
|
else:
|
|
# add last colliding log: track
|
|
if last_collision is not None:
|
|
object_list.append(last_collision)
|
|
|
|
object_list.append(log)
|
|
last_collision = None
|
|
return object_list
|
|
|
|
|
|
class LogsView(BaseView, LogViewBase):
|
|
""" View for timetables """
|
|
template_name = 'aircox_web/logs.html'
|
|
model = aircox.Log
|
|
title = _('Logs')
|
|
|
|
date = None
|
|
max_age = 10
|
|
|
|
min_date = None
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
self.station = self.site.station
|
|
|
|
today = datetime.date.today()
|
|
self.min_date = today - datetime.timedelta(days=self.max_age)
|
|
self.date = min(max(self.min_date, self.kwargs['date']), today) \
|
|
if 'date' in self.kwargs else today
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
today = datetime.date.today()
|
|
max_date = min(max(self.date + datetime.timedelta(days=3),
|
|
self.min_date + datetime.timedelta(days=6)), today)
|
|
|
|
return super().get_context_data(
|
|
date=self.date,
|
|
min_date=self.min_date,
|
|
dates=(date for date in (
|
|
max_date - datetime.timedelta(days=i)
|
|
for i in range(0, 7)) if date >= self.min_date
|
|
),
|
|
object_list=self.get_object_list(self.object_list),
|
|
**kwargs
|
|
)
|
|
|