forked from rc/aircox
website
This commit is contained in:
7
aircox/views/__init__.py
Normal file
7
aircox/views/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
from .article import ArticleListView
|
||||
from .base import BaseView
|
||||
from .episode import EpisodeDetailView, EpisodeListView, TimetableView
|
||||
from .log import LogListView
|
||||
from .page import PageDetailView, PageListView
|
||||
from .program import ProgramDetailView
|
||||
|
14
aircox/views/article.py
Normal file
14
aircox/views/article.py
Normal file
@ -0,0 +1,14 @@
|
||||
from ..models import Article
|
||||
from .page import PageListView
|
||||
|
||||
|
||||
__all__ = ['ArticleListView']
|
||||
|
||||
|
||||
class ArticleListView(PageListView):
|
||||
model = Article
|
||||
is_static = False
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset(is_static=self.is_static)
|
||||
|
32
aircox/views/base.py
Normal file
32
aircox/views/base.py
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
from django.http import Http404
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.base import TemplateResponseMixin, ContextMixin
|
||||
|
||||
from ..utils import Redirect
|
||||
|
||||
|
||||
__all__ = ['BaseView', 'PageView']
|
||||
|
||||
|
||||
class BaseView(TemplateResponseMixin, ContextMixin):
|
||||
show_side_nav = False
|
||||
""" Show side navigation """
|
||||
title = None
|
||||
""" Page title """
|
||||
cover = None
|
||||
""" Page cover """
|
||||
|
||||
@property
|
||||
def station(self):
|
||||
return self.request.station
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().station(self.station)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.setdefault('station', self.station)
|
||||
kwargs.setdefault('cover', self.cover)
|
||||
kwargs.setdefault('show_side_nav', self.show_side_nav)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
99
aircox/views/episode.py
Normal file
99
aircox/views/episode.py
Normal file
@ -0,0 +1,99 @@
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
|
||||
from django.db.models import OuterRef, Subquery
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.generic import ListView
|
||||
|
||||
from ..models import Diffusion, Episode, Page, Program, Sound
|
||||
from .base import BaseView
|
||||
from .page import PageListView
|
||||
from .program import ProgramPageDetailView
|
||||
|
||||
|
||||
__all__ = ['EpisodeDetailView', 'DiffusionListView', 'TimetableView']
|
||||
|
||||
|
||||
class EpisodeDetailView(ProgramPageDetailView):
|
||||
model = Episode
|
||||
|
||||
def get_podcasts(self, diffusion):
|
||||
return Sound.objects.diffusion(diffusion).podcasts()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.setdefault('program', self.object.program)
|
||||
kwargs.setdefault('parent', kwargs['program'])
|
||||
if not 'podcasts' in kwargs:
|
||||
kwargs['podcasts'] = self.object.sound_set.podcasts()
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
# TODO: pagination: in template, only a limited number of pages displayed
|
||||
class EpisodeListView(PageListView):
|
||||
model = Episode
|
||||
item_template_name = 'aircox/episode_item.html'
|
||||
show_headline = True
|
||||
template_name = 'aircox/diffusion_list.html'
|
||||
program = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
program_slug = kwargs.get('program_slug')
|
||||
if program_slug:
|
||||
self.program = get_object_or_404(Program, slug=program_slug)
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
if self.program:
|
||||
qs = qs.filter(program=self.program)
|
||||
return qs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
program = kwargs.setdefault('program', self.program)
|
||||
if program is not None:
|
||||
kwargs.setdefault('cover', program.cover)
|
||||
kwargs.setdefault('parent', program)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class TimetableView(BaseView, ListView):
|
||||
""" View for timetables """
|
||||
template_name_suffix = '_timetable'
|
||||
model = Diffusion
|
||||
# ordering = ('start',)
|
||||
|
||||
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().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 diffusion.date not 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
|
||||
)
|
||||
|
||||
|
96
aircox/views/log.py
Normal file
96
aircox/views/log.py
Normal file
@ -0,0 +1,96 @@
|
||||
from collections import deque
|
||||
import datetime
|
||||
|
||||
from django.views.generic import ListView
|
||||
|
||||
from ..models import Diffusion, Log
|
||||
from .base import BaseView
|
||||
|
||||
|
||||
__all__ = ['BaseLogView', 'LogListView']
|
||||
|
||||
|
||||
class BaseLogView(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 Diffusion.objects.station(self.station).on_air() \
|
||||
.today(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 = None
|
||||
last_collision = None
|
||||
|
||||
# TODO/FIXME: multiple diffs at once - recheck the whole algorithm in
|
||||
# detail -- however I barely see cases except when there are diff
|
||||
# collision or the streamer is not working
|
||||
for index, log in enumerate(logs):
|
||||
# get next diff
|
||||
if diff is None or diff.end < log.date:
|
||||
diff = diffs.popleft() if len(diffs) else None
|
||||
|
||||
# no more diff that can collide: return list
|
||||
if diff is None:
|
||||
if last_collision and not object_list or \
|
||||
object_list[-1] is not last_collision:
|
||||
object_list.append(last_collision)
|
||||
return object_list + logs[index:]
|
||||
|
||||
# diff colliding with log
|
||||
if diff.start <= log.date:
|
||||
if not object_list or object_list[-1] is not diff:
|
||||
object_list.append(diff)
|
||||
if log.date <= diff.end:
|
||||
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 LogListView(BaseView, BaseLogView):
|
||||
model = Log
|
||||
|
||||
date = None
|
||||
max_age = 10
|
||||
min_date = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
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
|
||||
)
|
84
aircox/views/page.py
Normal file
84
aircox/views/page.py
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
from django.http import Http404
|
||||
from django.views.generic import DetailView, ListView
|
||||
|
||||
from ..models import Category
|
||||
from ..utils import Redirect
|
||||
from .base import BaseView
|
||||
|
||||
|
||||
__all__ = ['PageDetailView', 'PageListView']
|
||||
|
||||
|
||||
class PageDetailView(BaseView, DetailView):
|
||||
""" Base view class for pages. """
|
||||
context_object_name = 'page'
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().select_related('cover', 'category')
|
||||
|
||||
# This should not exists: it allows mapping not published pages
|
||||
# or it should be only used for trashed pages.
|
||||
def not_published_redirect(self, page):
|
||||
"""
|
||||
When a page is not published, redirect to the returned url instead
|
||||
of an HTTP 404 code. """
|
||||
return None
|
||||
|
||||
def get_object(self):
|
||||
obj = super().get_object()
|
||||
if not obj.is_published:
|
||||
redirect_url = self.not_published_redirect(obj)
|
||||
if redirect_url:
|
||||
raise Redirect(redirect_url)
|
||||
raise Http404('%s not found' % self.model._meta.verbose_name)
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
#if kwargs.get('regions') is None:
|
||||
# contents = contents_for_item(
|
||||
# page, page_renderer._renderers.keys())
|
||||
# kwargs['regions'] = contents.render_regions(page_renderer)
|
||||
page = kwargs.setdefault('page', self.object)
|
||||
kwargs.setdefault('title', page.title)
|
||||
kwargs.setdefault('cover', page.cover)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class PageListView(BaseView, ListView):
|
||||
template_name = 'aircox/page_list.html'
|
||||
item_template_name = 'aircox/page_item.html'
|
||||
paginate_by = 10
|
||||
show_headline = True
|
||||
show_side_nav = True
|
||||
categories = None
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
self.categories = set(self.request.GET.getlist('categories'))
|
||||
return super().get(*args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset().published() \
|
||||
.select_related('cover', 'category')
|
||||
|
||||
# category can be filtered based on request.GET['categories']
|
||||
# (by id)
|
||||
if self.categories:
|
||||
qs = qs.filter(category__slug__in=self.categories)
|
||||
return qs.order_by('-date')
|
||||
|
||||
def get_categories_queryset(self):
|
||||
# TODO: use generic reverse field lookup
|
||||
categories = self.model.objects.published() \
|
||||
.filter(category__isnull=False) \
|
||||
.values_list('category', flat=True)
|
||||
return Category.objects.filter(id__in=categories)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.setdefault('item_template_name', self.item_template_name)
|
||||
kwargs.setdefault('filter_categories', self.get_categories_queryset())
|
||||
kwargs.setdefault('categories', self.categories)
|
||||
kwargs.setdefault('show_headline', self.show_headline)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
29
aircox/views/program.py
Normal file
29
aircox/views/program.py
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
from aircox.models import Episode, Program
|
||||
from .page import PageDetailView
|
||||
|
||||
|
||||
__all__ = ['ProgramPageDetailView', 'ProgramDetailView']
|
||||
|
||||
|
||||
class ProgramPageDetailView(PageDetailView):
|
||||
""" Base view class for rendering content of a specific programs. """
|
||||
show_side_nav = True
|
||||
list_count=5
|
||||
|
||||
def get_episodes_queryset(self, program):
|
||||
return program.episode_set.published().order_by('-date')
|
||||
|
||||
def get_context_data(self, program, episodes=None, **kwargs):
|
||||
if episodes is None:
|
||||
episodes = self.get_episodes_queryset(program)
|
||||
return super().get_context_data(
|
||||
program=program, episodes=episodes[:self.list_count], **kwargs)
|
||||
|
||||
|
||||
class ProgramDetailView(ProgramPageDetailView):
|
||||
model = Program
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.setdefault('program', self.object)
|
||||
return super().get_context_data(**kwargs)
|
Reference in New Issue
Block a user