Commit aa66f93e authored by Mathieu Bridon's avatar Mathieu Bridon

Add a "Listen to the radio" home card

This is all heavily based on the Ideascube mediacenter, with a few
adaptations.

A few things are still missing, as evidenced by the TODO comments.

Fixes #6
parent faa3fccc
......@@ -3,8 +3,11 @@ from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from ideascube.mediacenter import utils
from ideascube.mediacenter.forms import DocumentForm
from ideascube.mediacenter.models import Document
from ideascube.widgets import RichTextEntry
from ideascube.widgets import LangSelect, RichTextEntry
from .models import RadioShow
class MessageForm(forms.Form):
......@@ -25,7 +28,6 @@ class MessageForm(forms.Form):
('message',
_('I want to leave a message'))])
def clean(self):
cleaned_data = super().clean()
media = cleaned_data['media']
......@@ -46,3 +48,45 @@ class MessageForm(forms.Form):
)
return cleaned_data
class RadioForm(DocumentForm):
class Meta:
model = RadioShow
fields = '__all__'
widgets = {
'lang': LangSelect,
'summary': RichTextEntry,
'air_date': forms.DateInput(format='%Y-%m-%d'),
# Those won't be changed by users
'hidden': forms.HiddenInput,
'kind': forms.HiddenInput,
'tags': forms.HiddenInput,
}
exclude = [
'credits',
'package_id',
'preview',
]
def clean_tags(self):
# We absolutely want the "radio" tag here, because that's how we
# distinguish radio shows from usual medias.
# We do not want any other tag though, since they aren't displayed
# anywhere.
return ['radio']
def clean(self):
cleaned_data = super().clean()
if cleaned_data['kind'] != RadioShow.AUDIO:
self.add_error(
'original', ValidationError(_('Only audio files are allowed')))
return
# TODO: preview based on radio name and theme
# TODO: can we automatically guess the duration?
# TODO: we might have do some transcoding
return cleaned_data
......@@ -85,6 +85,9 @@ STAFF_HOME_CARDS = [
if card['url'] in ('user_list', 'server:settings')
]
CUSTOM_CARDS = [
{
'id': 'radio_listen',
},
{
'id': 'radio_news',
},
......
{% load i18n %}
<a href="{% url 'radio_index' %}" class="card tinted">
<i class="fa fa-music fa-3x"></i>
<h4>
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
<span class="theme discover">{% trans "discover" %}</span>
<span>
{% blocktrans with radio_name=radio_name %}Listen to {{ radio_name }}{% endblocktrans %}
</span>
</h4>
<p>
{% trans 'Your favourite radio shows.' %}
</p>
</a>
{% extends 'form-confirm-delete.html' %}
{% load i18n %}
{% block confirm_message %}
{% blocktrans %}
Are you sure you want to delete the radio show "{{ radioshow }}"?
{% endblocktrans %}
{% endblock %}
{% block cancel_url %}
{{ radioshow.get_absolute_url }}
{% endblock cancel_url %}
{% extends 'two-third-third.html' %}
{% load i18n ideascube_tags static %}
{% block extra_head %}
<link rel="stylesheet" type="text/css" href="{% static "mediacenter/mediacenter.css" %}">
{% endblock extra_head %}
{% block twothird %}
<h5><a href="{% url 'radio_index' %}">&lt; {% trans 'View all radio shows' %}</a></h5>
<h2><span class="theme discover">{{ radioshow.slug }}</span> {{ radioshow }}</h2>
<audio controls preload="none" width="100%">
<source src="{% media radioshow 'original' %}">
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
{% trans "Your web browser doesn't support this media type." %}
</audio>
<div class="text">{{ radioshow.summary|safe }}</div>
<div>
<a class="button" href="{% media radioshow 'original' %}"><span class="fa fa-download fa-fw"></span>
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
{% blocktrans with kind=radioshow.KIND_DICT|getitem:radioshow.kind %}
Download {{ kind }}
{% endblocktrans %}
</a>
</div>
{% endblock twothird %}
{% block third %}
{% if user.is_staff %}
<ul class="card tinted admin">
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
<li>{% fa 'pencil' 'fa-fw' %}<a href="{% url 'radio_update' pk=radioshow.pk %}">{% trans 'Edit' %}</a></li>
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
<li>{% fa 'trash' 'fa-fw' %}<a href="{% url 'radio_delete' pk=radioshow.pk %}">{% trans 'Delete' %}</a></li>
</ul>
{% endif %}
{% endblock third %}
{% extends 'form-sidebar.html' %}
{% load i18n static ideascube_tags %}
{% block heading %}
<h2>
{% if radioshow %}
{% trans "Edit radio show" %} "{{ radioshow }}"
{% else %}
{% trans "New radio show" %}
{% endif %}
</h2>
{% endblock heading %}
{% block form %}
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
<h3>{% trans 'Content' %}</h3>
{% form_field form.title %}
{% form_field form.original %}
{% form_field form.summary %}
{% endblock form %}
{% block sidebar %}
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
<h3>{% trans 'Metadatas' %}</h3>
{% form_field form.theme %}
{% form_field form.lang %}
{% form_field form.air_date %}
{% form_field form.duration %}
{% form_field form.hidden %}
{% form_field form.kind %}
{% form_field form.tags %}
{% endblock sidebar %}
{% block cancel_url %}
{% if radioshow %}
{{ radioshow.get_absolute_url }}
{% else %}
{% url 'radio_index' %}
{% endif %}
{% endblock cancel_url %}
{% block extra_foot %}
<script type="text/javascript">
ID.initEditors();
ID.initDatepicker('air_date');
</script>
{% endblock extra_foot %}
{% extends 'two-third-third.html' %}
{% load i18n ideascube_tags static %}
{% block extra_head %}
<link rel="stylesheet" type="text/css" href="{% static "mediacenter/mediacenter.css" %}">
{% endblock %}
{% block body_class %}mediacenter{% endblock %}
{% block twothird %}
{% block content_title %}
<h2>
{% comment %}Translators: Do not translate this, the translation is in Ideascube{% endcomment %}
<span class="theme discover">{% trans "discover" %}</span>
{% blocktrans with radio_name=radio_name %}Listen to {{ radio_name }}{% endblocktrans %}
</h2>
{% endblock %}
<div class="pure-g document-list card-container">
{% for document in radioshow_list %}
<div class="pure-u-1 pure-u-sm-1-2 pure-u-lg-1-3 pure-u-xl-1-4 pure-u">
{% include "mediacenter/document_card.html" %}
</div>
{% empty %}
<div class="pure-u-1">
{% trans "No radio show yet." %}
</div>
{% endfor %}
</div>
{% include "ideascube/pagination.html" %}
{% endblock twothird %}
{% block third %}
{% if user.is_staff %}
<div class="card tinted admin">
{% fa 'plus' 'fa-fw' %} <a href="{% url 'radio_create' %}">{% trans "Add a show" %}</a>
</div>
{% endif %}
{% url 'radio_index' as index %}
{% include 'search/filter_cloud.html' %}
{% include 'search/box.html' with action=index %}
{% include 'search/order_by.html' %}
{% include 'irfi/search/filter_by_theme.html' %}
{% include 'search/filter_by_lang.html' %}
{% endblock third %}
{% load i18n ideascube_tags %}
{% if available_themes %}
<div class="card tinted">
<h4><span class="theme discover">{% trans "browse" %}</span> {% trans 'by theme' %}</h4>
{% for theme, label in available_themes %}
{% is_in_qs 'theme' theme as in_qs %}
{% if in_qs %}
<a href="{% remove_qs theme=theme %}" class="flatlist active">{{ label|capfirst }}</a>
{% else %}
<a href="{% replace_qs theme=theme %}" class="flatlist">{{ label|capfirst }}</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
......@@ -8,8 +8,18 @@ from . import views
urlpatterns += i18n.i18n_patterns(
url(r'^irfi/serveradmin/radio/$', views.radio_name, name='server_radio'),
url(r'^rfi/message/new/$', views.message_create, name='message_create'),
url(r'^rfi/message/thank/$',
TemplateView.as_view(template_name='irfi/message_thank.html'),
name='message_thank'),
url(r'^rfi/radio/$', views.radio_index, name='radio_index'),
url(r'^rfi/radio/new/$', views.radio_create, name='radio_create'),
url(r'^rfi/radio/(?P<pk>[\d]+)/$', views.radio_detail,
name='radio_detail'),
url(r'^rfi/radio/(?P<pk>[\d]+)/edit/$', views.radio_update,
name='radio_update'),
url(r'^rfi/radio/(?P<pk>[\d]+)/delete/$', views.radio_delete,
name='radio_delete'),
)
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.db import IntegrityError
from django.db.models import F
from django.db.models.functions import Lower
from django.shortcuts import render
from django.utils import timezone
from django.utils.translation import get_language, ugettext_lazy as _
from django.views.generic import (
CreateView,
DeleteView,
DetailView,
FormView,
ListView,
UpdateView
)
from ideascube.configuration import set_config
from ideascube.decorators import staff_member_required
from ideascube.models import User
from ideascube.mediacenter.forms import DocumentForm
from ideascube.mediacenter.models import Document
from ideascube.blog.forms import ContentForm
from ideascube.blog.models import Content
from ideascube.mediacenter.forms import DocumentForm
from ideascube.mediacenter.models import Document
from ideascube.mixins import FilterableViewMixin, OrderableViewMixin
from .forms import MessageForm
from .forms import MessageForm, RadioForm
from .models import RadioShow
@staff_member_required
......@@ -161,4 +170,115 @@ class MessageCreate(FormView):
return super().form_valid(form)
class RadioQuerysetMixin:
def get_queryset(self):
qs = super().get_queryset()
qs = qs.filter(hidden=True)
qs = qs.search(tags=['radio'])
return qs
class RadioIndex(
RadioQuerysetMixin, FilterableViewMixin, OrderableViewMixin, ListView):
ORDERS = [
{
'key': 'air_date',
'label': _('Date'),
'expression': F('air_date'),
'sort': 'desc'
},
{
'key': 'title',
# Translators: Do not translate this, the translation is in Ideascube
'label': _('Title'),
'expression': Lower('title'), # Case insensitive.
'sort': 'asc'
}
]
model = RadioShow
paginate_by = 24
def _set_available_kinds(self, context):
# This is all audio files
context['available_kinds'] = []
def _set_available_tags(self, context):
# All the files are tagged as "radio" only, and we don't display the
# tag cloud in the UI
context['available_tags'] = []
def _set_available_themes(self, context):
# We can't use self.queryset() here, as that would filter on the
# query string
qs = RadioShow.objects.all()
qs = qs.filter(hidden=True)
qs = qs.search(tags=['radio'])
theme_slugs = qs.values_list('theme', flat=True).distinct()
context['available_themes'] = [
(slug, label) for (slug, label) in RadioShow.THEMES
if slug in theme_slugs
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# This tells the search system to only look at hidden documents
context['public'] = False
self._set_available_kinds(context)
self._set_available_langs(context)
self._set_available_tags(context)
self._set_available_themes(context)
return context
def get_queryset(self):
qs = super().get_queryset()
# The theme is added in irfi, as such it is not indexed by the
# Ideascube search system
theme = self.request.GET.get('theme')
if theme is not None:
qs = qs.filter(theme=theme)
return qs
class RadioDetail(RadioQuerysetMixin, DetailView):
model = RadioShow
class RadioCreate(CreateView):
model = RadioShow
form_class = RadioForm
initial = {
'hidden': True,
'lang': get_language(),
}
class RadioUpdate(RadioQuerysetMixin, UpdateView):
model = RadioShow
form_class = RadioForm
class RadioDelete(RadioQuerysetMixin, DeleteView):
model = RadioShow
def get_success_url(self):
return reverse('message_thank')
message_create = MessageCreate.as_view()
radio_index = RadioIndex.as_view()
radio_detail = RadioDetail.as_view()
radio_create = staff_member_required(RadioCreate.as_view())
radio_delete = staff_member_required(RadioDelete.as_view())
radio_update = staff_member_required(RadioUpdate.as_view())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment