Commit 44016a34 authored by fred's avatar fred

switch to standalone emissions app

parent 62eec5e6
......@@ -4,7 +4,7 @@ from django.contrib.auth.models import AbstractUser
from django.core import validators
from django.db import models
from ..emissions.models import Emission
from emissions.models import Emission
class User(AbstractUser):
emissions = models.ManyToManyField(Emission)
......
from django.contrib import admin
from .models import Emission, Episode, Category, Schedule, \
SoundFile, NewsItem, NewsCategory, Nonstop
class EmissionAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Emission, EmissionAdmin)
class EpisodeAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Episode, EpisodeAdmin)
class CategoryAdmin(admin.ModelAdmin):
pass
admin.site.register(Category, CategoryAdmin)
class ScheduleAdmin(admin.ModelAdmin):
pass
admin.site.register(Schedule, ScheduleAdmin)
class NewsCategoryAdmin(admin.ModelAdmin):
pass
admin.site.register(NewsCategory, NewsCategoryAdmin)
class NewsItemAdmin(admin.ModelAdmin):
pass
admin.site.register(NewsItem, NewsItemAdmin)
class SoundFileAdmin(admin.ModelAdmin):
pass
admin.site.register(SoundFile, SoundFileAdmin)
class NonstopAdmin(admin.ModelAdmin):
pass
admin.site.register(Nonstop, NonstopAdmin)
[
{
"fields": {
"end": "02:00:00",
"start": "22:00:00",
"title": "Biodiversit\u00e9"
},
"model": "emissions.nonstop",
"pk": 1
},
{
"fields": {
"end": "05:00:00",
"start": "02:00:00",
"title": "R\u00eaveries"
},
"model": "emissions.nonstop",
"pk": 2
},
{
"fields": {
"end": "07:30:00",
"start": "05:00:00",
"title": "La Panique"
},
"model": "emissions.nonstop",
"pk": 3
},
{
"fields": {
"end": "10:00:00",
"start": "07:30:00",
"title": "Matin tranquille"
},
"model": "emissions.nonstop",
"pk": 4
},
{
"fields": {
"end": "12:00:00",
"start": "10:00:00",
"title": "Up Beat Tempo"
},
"model": "emissions.nonstop",
"pk": 5
},
{
"fields": {
"end": "13:00:00",
"start": "12:00:00",
"title": "L'heure de pointe"
},
"model": "emissions.nonstop",
"pk": 6
},
{
"fields": {
"end": "16:00:00",
"start": "13:00:00",
"title": "Le Mange Disque"
},
"model": "emissions.nonstop",
"pk": 7
},
{
"fields": {
"end": "19:00:00",
"start": "16:00:00",
"title": "Hop Bop and co"
},
"model": "emissions.nonstop",
"pk": 8
},
{
"fields": {
"end": "22:00:00",
"start": "19:00:00",
"title": "Acouph\u00e8ne"
},
"model": "emissions.nonstop",
"pk": 9
}
]
import datetime
import re
import unicodedata
import os
import uuid
from django import forms
from django.forms import fields
from django.core.files.storage import DefaultStorage
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.conf import settings
from django.template.loader import render_to_string
from taggit.forms import TagWidget
import datetimewidget.widgets
from .models import Emission, Episode, Diffusion, Schedule, SoundFile
DATETIME_OPTIONS = {
'format': 'dd/mm/yyyy hh:ii',
'language': 'fr',
'weekStart': '1',
'autoclose': 'true',
}
class DateTimeWidget(datetimewidget.widgets.DateTimeWidget):
def __init__(self, *args, **kwargs):
super(DateTimeWidget, self).__init__(*args, options=DATETIME_OPTIONS, **kwargs)
def slugify(s):
s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').lower()
return re.sub(r'\W+', '-', s)
class DayAndHourWidget(forms.MultiWidget):
def __init__(self, attrs=None):
WEEKDAYS = [u'Lundi', u'Mardi', u'Mercredi', u'Jeudi', u'Vendredi', u'Samedi', u'Dimanche']
widgets = (
forms.Select(attrs=attrs, choices=([(weekday, WEEKDAYS[weekday]) for weekday in range(7)])),
forms.Select(attrs=attrs, choices=([(hour, hour) for hour in range(24)])),
forms.Select(attrs=attrs, choices=([(minute, str(minute).zfill(2)) for minute in range(60)])),
)
super(DayAndHourWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
return [value.weekday(), value.hour, value.minute]
return [None, None, None]
def value_from_datadict(self, data, files, name):
# we only care about day/hour/minutes, but we conveniently use a
# datetime value to store that; we pick 2007 as reference year as
# it had its January 1st on a Monday.
data_list = [
widget.value_from_datadict(data, files, name + '_%s' % i)
for i, widget in enumerate(self.widgets)]
if data_list:
return datetime.datetime(2007, 1, int(data_list[0])+1, int(data_list[1]), int(data_list[2]))
return None
class JqueryFileUploadFileInput(forms.FileInput):
def render(self, name, value, attrs=None):
output = render_to_string('emissions/upload.html', {
'upload_url': self.url,
'files': self.files,
'name': name,
'STATIC_URL': settings.STATIC_URL})
return mark_safe(output)
class JqueryFileUploadInput(forms.MultiWidget):
needs_multipart_form = True
upload_id_re = re.compile(r'^[a-z0-9A-Z-]+$')
upload_id = None
def __init__(self, attrs=None, choices=[], max_filename_length=None):
self.max_filename_length = max_filename_length
widget_list = (forms.HiddenInput(attrs=attrs),
JqueryFileUploadFileInput(attrs=attrs))
super(JqueryFileUploadInput, self).__init__(widget_list, attrs)
def decompress(self, value):
# map python value to widget contents
if self.upload_id:
pass
elif isinstance(value, (list, tuple)) and value and value[0] is not None:
self.upload_id = str(value[0])
else:
self.upload_id = str(uuid.uuid4())
return [self.upload_id, None]
def get_files_for_id(self, upload_id):
storage = DefaultStorage()
path = os.path.join('upload', upload_id)
if not storage.exists(path):
return
for filepath in storage.listdir(path)[1]:
name = os.path.basename(filepath)
yield storage.open(os.path.join(path, name))
def value_from_datadict(self, data, files, name):
'''
If some file was submitted, that's the value,
If a regular hidden_id is present, use it to find uploaded files,
otherwise return an empty list
'''
upload_id, file_input = super(JqueryFileUploadInput, self).value_from_datadict(data, files, name)
if file_input:
pass
elif JqueryFileUploadInput.upload_id_re.match(upload_id):
file_input = list(self.get_files_for_id(upload_id))
else:
file_input = []
return file_input[0]
def render(self, name, value, attrs=None):
self.decompress(value)
self.widgets[1].url = '/upload/%s/' % self.upload_id
self.widgets[1].url = reverse('upload', kwargs={'transaction_id': self.upload_id})
if self.max_filename_length:
self.widgets[1].url += '?max_filename_length=%d' % self.max_filename_length
self.widgets[1].files = '/upload/%s/' % self.get_files_for_id(self.upload_id)
output = super(JqueryFileUploadInput, self).render(name, value,
attrs)
fileinput_id = '%s_%s' % (attrs['id'], '1')
return output
class EmissionForm(forms.ModelForm):
class Meta:
model = Emission
exclude = ('slug',)
def save(self, commit=True):
if not self.instance.slug:
self.instance.slug = slugify(self.instance.title)
return super(EmissionForm, self).save(commit=commit)
class EpisodeForm(forms.ModelForm):
class Meta:
model = Episode
exclude = ('slug',)
widgets = {'emission': forms.HiddenInput(),
'tags': TagWidget()}
def save(self, commit=True):
if not self.instance.slug:
self.instance.slug = slugify(self.instance.title)
return super(EpisodeForm, self).save(commit=commit)
class EpisodeNewForm(EpisodeForm):
diffusion = forms.DateTimeField(label='First Diffusion',
widget=DateTimeWidget)
def save(self, commit=True):
episode = super(EpisodeNewForm, self).save(commit=commit)
diffusion = Diffusion()
diffusion.episode_id = episode.id
diffusion.datetime = self.cleaned_data.get('diffusion')
diffusion.save()
return episode
class ScheduleForm(forms.ModelForm):
class Meta:
model = Schedule
widgets = {
'emission': forms.HiddenInput(),
'datetime': DayAndHourWidget(),
}
class SoundFileForm(forms.ModelForm):
class Meta:
model = SoundFile
widgets = {
'episode': forms.HiddenInput(),
'file': JqueryFileUploadInput(),
}
class DiffusionForm(forms.ModelForm):
class Meta:
model = Diffusion
widgets = {
'episode': forms.HiddenInput(),
'datetime': DateTimeWidget(),
}
# -*- coding: utf-8 -*-
#
# Code scavenged from Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import re
import sys
_non_id_chars = re.compile('[^a-z0-9]+')
_non_id_at_ends = re.compile('^[-0-9]+|-+$')
def enhanceTypo(s):
# typographic junkie
# idea from: http://daringfireball.net/projects/smartypants/
s = s.replace('...', '&#8230;') # ellipsis (...)
s = s.replace(' -- ', ' &#8212; ') # em-dash
s = s.replace('(c)', '&copy; ') # copyright symbol
return s
def parseSpipLink(link):
link = link.replace('\n', ' ')
matchObject = re.match(
r'(?P<role>alias|art(icle)?|atom|book|card|election|file|'\
'grade|group|heading|im(g|age)?|person(ne)?|rubri(c|que)'\
') *(?P<localId>\S+) *(?P<option>\S+)?', link)
if matchObject is None:
name = link
for prefix in [ 'http://', 'https://', 'ftp://', 'mailto:' ]:
if name.startswith(prefix):
if not '/' in name[len(prefix):]:
name = name[len(prefix):]
break
else:
name = ''
return name, link
role = matchObject.group('role')
localId = matchObject.group('localId')
option = matchObject.group('option') and \
':%s' % matchObject.group('option') or ''
return ('XXX', '#')
class Formatter:
def close(self, **keywords):
return ''
def list(self, list):
def getListIndent(stack):
if len(stack) == 0:
return -1
else:
return stack[-1][0]
stack = []
result = ''
for line in list:
indent, type, text = line
while indent < getListIndent(stack):
result += self.listEnd(len(stack), stack[-1][1])
del stack[-1]
if indent > getListIndent(stack):
stack.append((indent, type))
result += self.listBegin(len(stack) - 1, type)
result += self.listItem(len(stack), text)
while stack:
result += self.listEnd(len(stack) - 1, stack[-1][1])
del stack[-1]
return result
def open(self, **keywords):
return ''
def prescaleImage(self):
return 1
def table(self, table, hasHeader):
result = ''
rows = len(table)
cols = max(map(len, table))
result += self.tableBegin(rows, cols)
for i in range(len(table)):
row = table[i]
rowNumber = i
if hasHeader:
rowNumber -= 1
result += self.tableLineBegin(rowNumber,
isHeader = i == 0 and hasHeader)
j = 0
for cell in row:
if type(cell) in (str, unicode) and cell.strip() == '###':
cell = rowNumber + 1
result += self.tableCell(cell, rowNumber, j,
isHeader = i == 0 and hasHeader)
j += 1
result += self.tableLineEnd(i, isHeader = i == 0 and hasHeader)
result += self.tableEnd(isHeader = len(table) == 1 and hasHeader)
return result
def text(self, text):
return text
class FormatterHtml(Formatter):
def __init__(self):
self.states = [ '' ]
def intertitle(self, text, sublevel = 0):
nameText = re.sub('<.*?>', '', text).strip()
# from docutils/nodes.py, def make_id(string)
nameText = _non_id_chars.sub('-', ' '.join(nameText.lower().split()))
nameText = _non_id_at_ends.sub('', nameText)
return '<h%(sectionLevel)d id="%(nameText)s">%(text)s'\
'</h%(sectionLevel)d>\n\n' % {
'text': text.strip(),
'sectionLevel': self.sectionLevel + sublevel,
'nameText': nameText,
}
def lineBreak(self):
return '<br />\n'
def list(self, list):
# FIXME: the Formatter.list method doesn't work for sub-lists, so it is
# rewritten here. Maybe this method should also be used by
# Formatter.list
def getListIndent(stack):
if len(stack) == 0:
return -1
else:
return stack[-1][0]
self.states.append('blockLevel')
stack = []
result = ''
for line in list:
indent, type, text = line
while indent < getListIndent(stack):
result += self.listItemEnd()
result += self.listEnd(len(stack), stack[-1][1])
del stack[-1]
if indent > getListIndent(stack):
stack.append((indent, type))
result += '\n'
result += self.listBegin(len(stack) - 1, type)
else:
result += self.listItemEnd()
result += self.listItemBegin(len(stack), text)
while stack:
result += self.listItemEnd()
result += self.listEnd(len(stack) - 1, stack[-1][1])
del stack[-1]
return result
def listBegin(self, indent, type):
if type:
type = 'ol'
else:
type = 'ul'
return '%(indent)s<%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
def listEnd(self, indent, type):
if type:
type = 'ol'
else:
type = 'ul'
return '%(indent)s</%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
def listItemBegin(self, indent, item):
return '%(indent)s<li>%(item)s' % {
'indent': ' ' * indent,
'item': item.strip('*'),
}
def listItemEnd(self):
return '</li>\n'
def nonBreakingSpace(self):
return '&nbsp;'
def open(self, **keywords):
self.sectionLevel = 2
if keywords.has_key('sectionLevel'):
self.sectionLevel = int(keywords['sectionLevel'])
return ''
def paragraph(self, text):
# turn URL into links
def repl(match):
m = match.group(0)
if m[0] == '"' and m[-1] == '"':
return m
if m[0] in '>' and m[-1] == '<':
return m
m = m.rstrip('<').lstrip('>')
return '<a href="%s">%s</a>' % (m, m)
t1 = text
text = re.sub(r'([">]?http[s]?://[a-zA-Z0-9\.\/-]*[<"]?)', repl, text, re.DOTALL)
if self.states[-1] == 'blockLevel':
self.states.pop()
return text
def line80(text):
t = []
i = 0
while 1:
val = text[i+70:].find(' ')
if val == -1:
t.append(text[i:])
break
part = text[i:i+70+val+1]
t.append(part)
i += len(part)
return '\n'.join(t)
text = enhanceTypo(text.strip())
text = line80(text.replace('\n', ' '))
text = text.replace('\n_ ', '\n<br/>\n')
if not text:
return self.lineBreak()
return '<p>%(text)s</p>\n\n' % {
'text': text,
}
def preformatted(self, text):
if not text:
return ''
## text = self.text(text)
self.states.append('blockLevel')
return '<pre>%(text)s</pre>' % {
'text': text,
}
def preformattedInline(self, text):
if not text:
return ''
text = self.text(text)
return '<code>%(text)s</code>' % {
'text': text,
}
def punctuationAndSpace(self, punctuation):
return {
u'« ': u'«&nbsp;',
}[punctuation]
def spaceAndPunctuation(self, punctuation):
return {
u' :': u'&nbsp;:',
u' ;': u'&nbsp;;',
u' !': u'&nbsp;!',
u' ?': u'&nbsp;?',
u' »': u'&nbsp;»',
u' %': u'&nbsp;%',
u' ...': u'&nbsp;...',
}[punctuation]
def tableBegin(self, rows, cols):
self.states.append('blockLevel')
return '<table>\n'
def tableCell(self, cell, row, col, isHeader):
if not cell:
cell = '&nbsp;'
if isHeader:
tag = 'th'
attrtag = ' scope="col"'
else:
tag = 'td'
attrtag = ''
return ' <%(tag)s%(attrtag)s>%(cell)s</%(tag)s>\n' % {
'tag': tag,
'cell': cell.strip(),
'attrtag': attrtag,
}
def tableEnd(self, isHeader = 0):
return '</table>\n'
def tableLineBegin(self, tableLineCount, isHeader = 0):
if isHeader:
return ' <tr>\n'
elif (tableLineCount + 1) % 2 == 0:
return ' <tr class="even">\n'
else:
return ' <tr class="odd">\n'
def tableLineEnd(self, tableLineCount, isHeader = 0):
return ' </tr>\n'
def text(self, text):
if not text:
return ''
text = text.replace('&', '&amp;')
text = text.replace('<', '&lt;')
#text = text.replace('\x85', '&#8230;') # ellipsis (...)