static pages

This commit is contained in:
bkfox 2020-05-26 16:51:09 +02:00
parent a59c4a3d5c
commit c4c1af2f2d
20 changed files with 145 additions and 124 deletions

View File

@ -91,16 +91,12 @@ class PageAdmin(BasePageAdmin):
@admin.register(StaticPage)
class StaticPageAdmin(BasePageAdmin):
list_display = BasePageAdmin.list_display + ('view','menu_title')
list_editable = BasePageAdmin.list_editable + ('menu_title',)
list_display = BasePageAdmin.list_display + ('attach_to',)
fieldsets = deepcopy(BasePageAdmin.fieldsets)
fieldsets[0][1]['fields'].insert(fieldsets[0][1]['fields'].index('slug') + 1, 'menu_title')
fieldsets[1][1]['fields'] += ('view',)
fieldsets[1][1]['fields'] += ('attach_to',)
class NavItemInline(SortableInlineAdminMixin, admin.TabularInline):
model = NavItem

View File

@ -152,6 +152,10 @@ class Page(BasePage):
_('allow comments'), default=True,
)
class Meta:
verbose_name = _('Publication')
verbose_name_plural = _('Publications')
def save(self, *args, **kwargs):
if self.is_published and self.pub_date is None:
self.pub_date = tz.now()
@ -160,43 +164,30 @@ class Page(BasePage):
super().save(*args, **kwargs)
class StaticPage(Page):
class StaticPage(BasePage):
""" Static page that eventually can be attached to a specific view. """
VIEW_HOME = 0x00
VIEW_SCHEDULE = 0x01
VIEW_LOG = 0x02
VIEW_PROGRAMS = 0x03
VIEW_EPISODES = 0x04
VIEW_ARTICLES = 0x05
detail_url_name = 'static-page-detail'
VIEW_CHOICES = (
(VIEW_HOME, _('Home Page')),
(VIEW_SCHEDULE, _('Schedule Page')),
(VIEW_LOG, _('Log Page')),
(VIEW_PROGRAMS, _('Programs list')),
(VIEW_EPISODES, _('Episodes list')),
(VIEW_ARTICLES, _('Articles list')),
ATTACH_TO_HOME = 0x00
ATTACH_TO_DIFFUSIONS = 0x01
ATTACH_TO_LOGS = 0x02
ATTACH_TO_PROGRAMS = 0x03
ATTACH_TO_EPISODES = 0x04
ATTACH_TO_ARTICLES = 0x05
ATTACH_TO_CHOICES = (
(ATTACH_TO_HOME, _('Home page')),
(ATTACH_TO_DIFFUSIONS, _('Diffusions page')),
(ATTACH_TO_LOGS, _('Logs page')),
(ATTACH_TO_PROGRAMS, _('Programs list')),
(ATTACH_TO_EPISODES, _('Episodes list')),
(ATTACH_TO_ARTICLES, _('Articles list')),
)
view = models.SmallIntegerField(
_('attach to'), choices=VIEW_CHOICES, blank=True, null=True,
attach_to = models.SmallIntegerField(
_('attach to'), choices=ATTACH_TO_CHOICES, blank=True, null=True,
help_text=_('display this page content to related element'),
)
menu_title = models.CharField(_('menu title'), max_length=64, blank=True, null=True)
is_active = False
def render_menu_item(self, request, css_class='', active_class=''):
if active_class and request.path.startswith(self.url):
css_class += ' ' + active_class
if not self.url:
return self.text
elif not css_class:
return format_html('<a href="{}">{}</a>', self.url, self.text)
else:
return format_html('<a href="{}" class="{}">{}</a>', self.url,
css_class, self.text)
class Comment(models.Model):
@ -218,6 +209,9 @@ class NavItem(models.Model):
order = models.PositiveSmallIntegerField(_('order'))
text = models.CharField(_('title'), max_length=64)
url = models.CharField(_('url'), max_length=256, blank=True, null=True)
page = models.ForeignKey(StaticPage, models.CASCADE,
verbose_name=_('page'), blank=True, null=True,
limit_choices_to={'attach_to__isnull': True})
#target_type = models.ForeignKey(
# ContentType, models.CASCADE, blank=True, null=True)
#target_id = models.PositiveSmallIntegerField(blank=True, null=True)
@ -227,12 +221,6 @@ class NavItem(models.Model):
verbose_name = _('Menu item')
ordering = ('order', 'pk')
is_active = False
def get_is_active(self, url):
""" Return True if navigation item is active for this url. """
return self.url and url.startswith(self.url)
def render(self, request, css_class='', active_class=''):
if active_class and request.path.startswith(self.url):
css_class += ' ' + active_class

View File

@ -1,3 +0,0 @@
{% extends "aircox/page_list.html" %}
{% comment %}List of articles{% endcomment %}

View File

@ -45,7 +45,11 @@ Blocks:
{% endblock %}
<title>
{% block head_title %}{{ station.name }}{% endblock %}
{% block head_title %}
{% if page and page.title %}{{ page.title }} &mdash; {{ station.name }}
{% else %}{{ station.name }}
{% endif %}
{% endblock %}
</title>
{% block head_extra %}{% endblock %}
@ -77,7 +81,13 @@ Blocks:
<main class="column page">
<header class="header">
{% block header %}
<h1 class="title is-1">{% block title %}{% endblock %}</h1>
<h1 class="title is-1">
{% block title %}
{% if page and page.title %}
{{ page.title }}
{% endif %}
{% endblock %}
</h1>
<h3 class="subtitle is-3">
{% block subtitle %}{% endblock %}
@ -96,6 +106,12 @@ Blocks:
</header>
{% block main %}
{% block content %}
{% if page and page.content %}
{{ page.content|safe }}
{% endif %}
{% endblock %}
{% if has_filters %}
{% comment %}Translators: extra toolbar displayed on the top of page lists {% endcomment %}
<nav class="navbar toolbar"
@ -103,6 +119,8 @@ Blocks:
{% block filters %}{% endblock %}
</nav>
{% endif %}
{% endblock main %}
</main>
@ -111,8 +129,8 @@ Blocks:
<aside class="column is-one-third-desktop">
{# FIXME: block cover into sidebar one #}
{% block cover %}
{% if cover is not None %}
<img class="cover" src="{{ cover.url }}" class="cover"/>
{% if page and page.cover %}
<img class="cover" src="{{ page.cover.url }}" class="cover"/>
{% endif %}
{% endblock %}

View File

@ -3,9 +3,13 @@
{% load i18n aircox humanize %}
{% block title %}
{% if not page or not page.title %}
{% with station.name as station %}
{% blocktrans %}Today on {{ station }}{% endblocktrans %}
{% blocktrans %}This week on {{ station }}{% endblocktrans %}
{% endwith %}
{% else %}
{{ block.super }}
{% endif %}
{% endblock %}
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}

View File

@ -1,3 +0,0 @@
{% extends "aircox/page_list.html" %}
{% comment %}List of episodes pages{% endcomment %}

View File

@ -1,17 +1,17 @@
{% extends "aircox/page_list.html" %}
{% comment %}
Context:
-
- main:
- focused
- nav to 'publications' view
{% endcomment %}
{% load i18n %}
{% block head_title %}{% block title %}{{ station.name }}{% endblock %}{% endblock %}
{% block head_title %}{{ station.name }}{% endblock %}
{% block main %}
{% block title %}
{% if not page or not page.title %}{{ station.name }}
{% else %}{{ block.super }}
{% endif %}
{% endblock %}
{% block pages_list %}
{% if page and page.content %}<hr/>{% endif %}
<div class="columns">
{% with render_card=True %}
{% for object in top_diffs %}

View File

@ -3,9 +3,13 @@
{% load i18n humanize aircox %}
{% block title %}
{% if not page or not page.title %}
{% with station.name as station %}
{% blocktrans %}That happened on {{ station }}{% endblocktrans %}
{% endwith %}
{% else %}
{{ block.super }}
{% endif %}
{% endblock %}

View File

@ -1,20 +1,12 @@
{% extends "aircox/base.html" %}
{% load static i18n thumbnail %}
{% comment %}
Base template to display pages (list, detail, whatever). By default extend to
this one instead of "base.html"
Context:
- cover: cover image
- title: title
- page: page
This template is only used in order to have correct page <title></title>,
otherwise use base.html
{% endcomment %}
{% block head_title %}
{% comment %}Hack to include the page title into the <title> tag.{% endcomment %}
{% block title %}{{ title }}{% endblock %}
{% block title %}{{ page.title }}{% endblock %}
&mdash;
{{ station.name }}
{% endblock %}

View File

@ -18,9 +18,7 @@ Context:
{% endblock %}
{% block main %}
{% block content %}
{{ object.content|default_if_none:''|safe }}
{% endblock %}
{{ block.super }}
{% block comments %}
{% if comments or comment_form %}

View File

@ -3,14 +3,17 @@
{% load i18n aircox %}
{% block title %}
{% if not parent %}{{ view.model|verbose_name:True|title }}
{% else %}
{% with parent.title as title %}
{% with model|default:"Publications"|verbose_name:True|capfirst as model %}
{% comment %}Translators: title when pages are filtered for a specific parent page, e.g.: Articles of My Incredible Show{% endcomment %}
{% blocktrans %}{{ model }} of {{ title }}{% endblocktrans %}
{% endwith %}
{% endwith %}
{% if not page or not page.title %}
{% if not parent %}{{ view.model|verbose_name:True|title }}
{% else %}
{% with parent.title as title %}
{% with model|default:"Publications"|verbose_name:True|capfirst as model %}
{% comment %}Translators: title when pages are filtered for a specific parent page, e.g.: Articles of My Incredible Show{% endcomment %}
{% blocktrans %}{{ model }} of {{ title }}{% endblocktrans %}
{% endwith %}
{% endwith %}
{% endif %}
{% else %}{{ block.super }}
{% endif %}
{% endblock %}
@ -61,14 +64,19 @@
{% block main %}{{ block.super }}
<section role="list">
{% block pages_list %}
{% with has_headline=True %}
{% for object in object_list %}
{% block list_object %}
{% include object.item_template_name|default:item_template_name %}
{% endblock %}
{% empty %}
{% blocktrans %}There is nothing published here...{% endblocktrans %}
{% endfor %}
{% endwith %}
{% endblock %}
</section>
{% if is_paginated %}

View File

@ -60,13 +60,20 @@ urls = [
path(_('publications/'),
views.PageListView.as_view(model=models.Page), name='page-list'),
path(_('pages/'),
views.PageListView.as_view(model=models.StaticPage), name='static-page-list'),
path(_('pages/'), views.PageListView.as_view(
model=models.StaticPage,
queryset=models.StaticPage.objects.filter(attach_to__isnull=True),
),
name='static-page-list'
),
path(_('pages/<slug:slug>/'), views.PageDetailView.as_view(
model=models.StaticPage,
queryset=models.StaticPage.objects.filter(attach_to__isnull=True),
),
name='static-page-detail'
),
path(_('pages/<slug:slug>/'),
views.PageDetailView.as_view(), name='page-detail'),
path(_('programs/'), views.ProgramListView.as_view(model=models.Program),
path(_('programs/'), views.ProgramListView.as_view(),
name='program-list'),
path(_('programs/<slug:slug>/'),
views.ProgramDetailView.as_view(), name='program-detail'),

View File

@ -1,5 +1,4 @@
from ..models import Article, Program
from .mixins import ParentMixin
from ..models import Article, Program, StaticPage
from .page import PageDetailView, PageListView
@ -17,12 +16,12 @@ class ArticleDetailView(PageDetailView):
return qs
class ArticleListView(ParentMixin, PageListView):
class ArticleListView(PageListView):
model = Article
template_name = 'aircox/article_list.html'
has_headline = True
is_static = False
parent_model = Program
attach_to_value = StaticPage.ATTACH_TO_ARTICLES
def get_queryset(self):
return super().get_queryset().filter(is_static=self.is_static)

View File

@ -12,11 +12,6 @@ __all__ = ['BaseView']
class BaseView(TemplateResponseMixin, ContextMixin):
title = None
""" Page title """
cover = None
""" Page cover """
has_sidebar = True
""" Show side navigation """
has_filters = False
@ -39,9 +34,12 @@ class BaseView(TemplateResponseMixin, ContextMixin):
def get_sidebar_url(self):
return reverse('page-list')
def get_page(self):
return None
def get_context_data(self, **kwargs):
kwargs.setdefault('station', self.station)
kwargs.setdefault('cover', self.cover)
kwargs.setdefault('page', self.get_page())
kwargs.setdefault('has_filters', self.has_filters)
has_sidebar = kwargs.setdefault('has_sidebar', self.has_sidebar)
@ -61,7 +59,6 @@ class BaseView(TemplateResponseMixin, ContextMixin):
type(self.object)
kwargs['model'] = model
return super().get_context_data(**kwargs)

View File

@ -4,11 +4,11 @@ import datetime
from django.views.generic import ListView
from django.utils.translation import gettext as _
from ..models import Diffusion, Episode, Program, Sound
from ..models import Diffusion, Episode, Program, StaticPage, Sound
from .base import BaseView
from .program import ProgramPageDetailView
from .page import PageListView
from .mixins import GetDateMixin, ParentMixin
from .mixins import AttachedToMixin, GetDateMixin, ParentMixin
__all__ = ['EpisodeDetailView', 'EpisodeListView', 'DiffusionListView']
@ -28,18 +28,20 @@ class EpisodeDetailView(ProgramPageDetailView):
return super().get_context_data(**kwargs)
class EpisodeListView(ParentMixin, PageListView):
class EpisodeListView(PageListView):
model = Episode
item_template_name = 'aircox/widgets/episode_item.html'
has_headline = True
parent_model = Program
attach_to_value = StaticPage.ATTACH_TO_EPISODES
class DiffusionListView(GetDateMixin, BaseView, ListView):
class DiffusionListView(GetDateMixin, AttachedToMixin, BaseView, ListView):
""" View for timetables """
model = Diffusion
has_filters = True
redirect_date_url = 'diffusion-list'
attach_to_value = StaticPage.ATTACH_TO_DIFFUSIONS
def get_date(self):
date = super().get_date()

View File

@ -3,9 +3,10 @@ import datetime
from django.utils.translation import gettext as _
from django.utils import timezone as tz
from ..models import Diffusion, Log, Page
from ..models import Diffusion, Log, Page, StaticPage
from .page import PageListView
class HomeView(PageListView):
template_name = 'aircox/home.html'
model = Page
@ -14,6 +15,7 @@ class HomeView(PageListView):
list_count = 40
logs_count = 5
has_filters = False
attach_to_value = StaticPage.ATTACH_TO_HOME
def get_logs(self):
today = datetime.date.today()

View File

@ -8,10 +8,10 @@ from rest_framework.generics import ListAPIView
from rest_framework import viewsets
from rest_framework.decorators import action
from ..models import Diffusion, Log
from ..models import Diffusion, Log, StaticPage
from ..serializers import LogInfo, LogInfoSerializer
from .base import BaseView, BaseAPIView
from .mixins import GetDateMixin
from .mixins import GetDateMixin, AttachedToMixin
__all__ = ['LogListMixin', 'LogListView']
@ -52,13 +52,14 @@ class LogListMixin(GetDateMixin):
return Log.merge_diffusions(logs, diffs)
class LogListView(BaseView, LogListMixin, ListView):
class LogListView(AttachedToMixin, BaseView, LogListMixin, ListView):
"""
Return list of logs for the provided date (from `kwargs` or
`request.GET`, defaults to today).
"""
redirect_date_url = 'log-list'
has_filters = True
attach_to_value = StaticPage.ATTACH_TO_LOGS
def get_date(self):
date = super().get_date()

View File

@ -2,9 +2,10 @@ from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from ..utils import str_to_date
from ..models import StaticPage
__all__ = ['GetDateMixin', 'ParentMixin']
__all__ = ['GetDateMixin', 'ParentMixin', 'AttachedToMixin']
class GetDateMixin:
@ -68,3 +69,14 @@ class ParentMixin:
return super().get_context_data(**kwargs)
class AttachedToMixin:
""" Mixin for views that can have a static page attached to it. """
attach_to_value = None
""" Value of StaticPage.attach_to """
def get_page(self):
if self.attach_to_value is not None:
return StaticPage.objects.filter(attach_to=self.attach_to_value) \
.published().first()
return super().get_page()

View File

@ -6,15 +6,16 @@ from django.views.generic import DetailView, ListView
from honeypot.decorators import check_honeypot
from ..forms import CommentForm
from ..models import Category, Comment, Page
from ..models import Category, Comment
from ..utils import Redirect
from .base import BaseView
from .mixins import AttachedToMixin, ParentMixin
__all__ = ['PageDetailView', 'PageListView']
class PageListView(BaseView, ListView):
class PageListView(AttachedToMixin, ParentMixin, BaseView, ListView):
template_name = 'aircox/page_list.html'
item_template_name = 'aircox/widgets/page_item.html'
has_sidebar = True
@ -81,14 +82,12 @@ class PageDetailView(BaseView, DetailView):
raise Http404('%s not found' % self.model._meta.verbose_name)
return obj
def get_context_data(self, **kwargs):
page = kwargs.setdefault('page', self.object)
kwargs.setdefault('title', page.title)
kwargs.setdefault('cover', page.cover)
def get_page(self):
return self.object
def get_context_data(self, **kwargs):
if self.object.allow_comments and not 'comment_form' in kwargs:
kwargs['comment_form'] = CommentForm()
kwargs['comments'] = Comment.objects.filter(page=self.object) \
.order_by('-date')
return super().get_context_data(**kwargs)
@ -112,5 +111,3 @@ class PageDetailView(BaseView, DetailView):

View File

@ -3,8 +3,8 @@ from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import get_object_or_404
from django.urls import reverse
from ..models import Episode, Program, Page
from .mixins import ParentMixin
from ..models import Episode, Program, Page, StaticPage
from .mixins import ParentMixin, AttachedToMixin
from .page import PageDetailView, PageListView
@ -34,8 +34,10 @@ class ProgramDetailView(BaseProgramMixin, PageDetailView):
class ProgramListView(PageListView):
model = Program
attach_to_value = StaticPage.ATTACH_TO_PROGRAMS
# FIXME: not used
class ProgramPageDetailView(BaseProgramMixin, ParentMixin, PageDetailView):
"""
Base view class for a page that is displayed as a program's child page.
@ -50,7 +52,7 @@ class ProgramPageDetailView(BaseProgramMixin, ParentMixin, PageDetailView):
return super().get_sidebar_queryset().filter(parent=self.program)
class ProgramPageListView(BaseProgramMixin, ParentMixin, PageListView):
class ProgramPageListView(BaseProgramMixin, PageListView):
model = Page
parent_model = Program
queryset = Page.objects.select_subclasses()