]> git.0d.be Git - panikweb.git/blob - panikweb/paniktags/templatetags/paniktags.py
misc: don't crash error pages in metanav
[panikweb.git] / panikweb / paniktags / templatetags / paniktags.py
1 import email.utils
2 import datetime
3 import json
4 import re
5 import time
6 import uuid
7
8 from django import template
9 from django.conf import settings
10 from django.core.urlresolvers import reverse
11 from django.db.models.query import QuerySet
12 from django.utils.encoding import force_text
13 from django.utils.http import quote
14 from django.utils.six.moves.urllib import parse as urlparse
15
16 from datetime import datetime, timedelta
17
18 from emissions.models import Emission, Episode, NewsItem, SoundFile, Focus
19 from emissions.utils import period_program
20
21 from panikombo.models import Topik
22
23 from panikweb import utils
24 from panikweb import search
25
26 register = template.Library()
27
28 @register.filter(name='zip')
29 def zip_lists(a, b):
30     return zip(a, b)
31
32 @register.inclusion_tag('includes/audio.html', takes_context=True)
33 def audio(context, sound=None, embed=False, display_fragment_name=False):
34     return {
35         'episode': context.get('episode'),
36         'sound': sound,
37         'display_fragment_name': display_fragment_name,
38         'embed': embed,
39     }
40
41 @register.inclusion_tag('listen/nav.html', takes_context=True)
42 def listen_nav(context, date=None, klass=None):
43     return {
44         'class': klass,
45         'categories': context.get('categories'),
46     }
47
48 @register.inclusion_tag('news/nav.html', takes_context=True)
49 def news_nav(context, date=None, klass=None):
50     return {
51         'class': klass,
52         'newsitem': context.get('newsitem'),
53         'categories': context.get('categories'),
54         'news': context.get('news'),
55         'search_query': context.get('search_query'),
56     }
57
58 @register.inclusion_tag('emissions/nav.html', takes_context=True)
59 def emission_nav(context, date=None, klass=None):
60     return {
61         'class': klass,
62         'categories': context.get('categories'),
63         'episodes': context.get('episodes'),
64         'emission': context.get('emission'),
65         'episode': context.get('episode'),
66         'search_query': context.get('search_query'),
67     }
68
69 @register.inclusion_tag('episodes/inline.html', takes_context=True)
70 def episode_inline(context, date=None, model=None, klass=None):
71     return {
72         'class': klass,
73         'episode': context.get('episode'),
74         'date': date,
75     }
76 @register.inclusion_tag('episodes/resume.html', takes_context=True)
77 def episode_resume(context, date=None, model=None, klass=None):
78     return {
79         'model': model,
80         'class': klass,
81         'episode': context.get('episode'),
82         'date': date,
83     }
84
85 @register.inclusion_tag('episodes/detail.html', takes_context=True)
86 def episode_detail(context, date=None):
87     soundfiles = SoundFile.objects.select_related().filter(
88             fragment=True, podcastable=True, episode=context.get('episode'))
89     return {
90         'episode': context.get('episode'),
91         'emission': context.get('emission'),
92         'diffusions': context.get('diffusions'),
93         'soundfiles': soundfiles,
94         'date': date,
95         'topiks': context.get('topiks'),
96     }
97
98 @register.inclusion_tag('emissions/detail.html', takes_context=True)
99 def emission_detail(context, date=None):
100     return {
101         'emission': context.get('emission'),
102         'schedules': context.get('schedules'),
103     }
104
105 @register.inclusion_tag('emissions/resume.html', takes_context=True)
106 def emission_resume(context, date=None):
107     return {
108         'emission': context.get('emission'),
109         'schedules': context.get('schedules'),
110     }
111
112 @register.inclusion_tag('emissions/inline.html', takes_context=True)
113 def emission_inline(context, date=None):
114     return {
115         'emission': context.get('emission'),
116         'schedules': context.get('schedules'),
117     }
118
119 @register.inclusion_tag('soundfiles/resume.html')
120 def soundfile_resume(soundfile, date=None):
121     return {'soundfile': soundfile,
122             'date': date}
123
124 @register.inclusion_tag('includes/player.html', takes_context=True)
125 def player(context):
126
127     return {
128         'unique': uuid.uuid4(),
129         'soundfiles': context.get('soundfiles'),
130     }
131
132 @register.inclusion_tag('includes/metaNav.html', takes_context=True)
133 def metanav(context, active=None):
134     try:
135         request_path = context['request'].path
136     except KeyError:
137         # a context without 'requests' may happen when rendering error pages
138         request_path = 'xxx'
139     section = 'About'
140     if request_path == '/':
141         section = 'Home'
142     elif request_path.startswith('/actus/'):
143         section = 'News'
144     elif request_path.startswith('/sons/'):
145         section = 'Listen'
146     elif request_path.startswith('/topiks'):
147         section = 'Topiks'
148     elif request_path.startswith('/emissions') or request_path == '/grille' or request_path == '/programme/':
149         section = 'Emissions'
150     elif request_path == '/recherche/':
151         section = 'Search'
152     return {
153         'LANGUAGE_CODE': context.get('LANGUAGE_CODE'),
154         'sectionName': section,
155         }
156
157 @register.inclusion_tag('includes/week.html')
158 def weekview(year=None, week=None):
159     year = year if year else datetime.today().isocalendar()[0]
160     week = week if week else datetime.today().isocalendar()[1]
161
162     date = utils.tofirstdayinisoweek(year, week)
163     date = datetime(*date.timetuple()[:3])
164
165     program = period_program(date, date+timedelta(days=7))
166     days = []
167     for day in range(7):
168         days.append({'cells': [x for x in program if x.is_on_weekday(day+1)],
169                      'datetime': date+timedelta(days=day)})
170
171     return {
172         'days': days,
173         'week': week,
174         'year': year,
175     }
176
177 @register.inclusion_tag('includes/week-nav.html')
178 def weeknav(year=None, week=None, weekday=None):
179     year = year if year else datetime.today().isocalendar()[0]
180     week = week if week else datetime.today().isocalendar()[1]
181     weekday = weekday if weekday is not None else datetime.today().weekday()
182
183     date = utils.tofirstdayinisoweek(year, week)
184     date = datetime(*date.timetuple()[:3])
185
186     days = []
187     for day in range(7):
188         days.append({'datetime': date+timedelta(days=day)})
189
190     previous_week = date - timedelta(days=7)
191     previous_week_year, previous_week_no = previous_week.isocalendar()[:2]
192
193     next_week = date + timedelta(days=7)
194     next_week_year, next_week_no = next_week.isocalendar()[:2]
195
196     return {
197         'days': days,
198         'weekday': weekday,
199         'week': week,
200         'year': year,
201         'previous_week_year': previous_week_year,
202         'previous_week_no': previous_week_no,
203         'next_week_year': next_week_year,
204         'next_week_no': next_week_no,
205     }
206
207
208 @register.inclusion_tag('news/inline.html', takes_context=True)
209 def news_inline(context, klass=None, logo=None):
210     return {
211             'content': context.get('content'),
212             'class': klass,
213             'logo': logo
214     }
215
216 @register.inclusion_tag('news/roll.html')
217 def newsroll():
218     return {
219         'news': Focus.objects.filter(current=True).select_related('emission', 'newsitem',
220             'soundfile', 'episode', 'newsitem__category').order_by('?')[:3]
221     }
222
223
224 @register.filter
225 def jsonify(object):
226     if isinstance(object, QuerySet):
227         return serialize('json', object)
228     return json.dumps(object)
229
230 @register.filter
231 def strreplace ( string, args ): 
232     find  = args.split(',')[0]
233     replace = args.split(',')[1]
234     return string.replace(find,replace)
235
236 @register.filter
237 def replace ( string, args ): 
238     search  = args.split(args[0])[1]
239     replace = args.split(args[0])[2]
240
241     return re.sub( search, replace, string )
242
243
244 def remove_facet(facet_id, url, facet):
245     scheme, netloc, path, query, fragment = list(urlparse.urlsplit(str(url)))
246     facet = '%s_exact:%s' % (facet_id, facet.encode('utf-8'))
247     query_string = urlparse.parse_qsl(query)
248     query_string = [x for x in query_string if not (
249         x[0] == 'selected_facets' and x[1] == facet)]
250     query = '&'.join(['%s=%s' % x for x in query_string])
251     url = urlparse.urlunsplit([scheme, netloc, path, query, None])
252     return force_text(re.sub(r'&page=\d+', '', url), 'utf-8')
253
254 @register.filter
255 def remove_tag_facet(url, facet):
256     return remove_facet('tags', url, facet)
257
258 @register.filter
259 def remove_category_facet(url, facet):
260     return remove_facet('categories', url, facet)
261
262
263 @register.filter
264 def remove_news_category_facet(url, facet):
265     return remove_facet('news_categories', url, facet)
266
267 @register.filter
268 def remove_format_facet(url, facet):
269     return remove_facet('format', url, facet)
270
271
272 def append_facet(facet_id, url, facet):
273     facet = quote(facet.encode('utf-8'), safe='')
274     if not '?' in url:
275         url = url + '?'
276     return re.sub(r'&page=\d+', '', url + '&selected_facets=%s_exact:%s' % (facet_id, facet))
277
278 @register.filter
279 def append_tag_facet(url, facet):
280     return append_facet('tags', url, facet)
281
282 @register.filter
283 def append_category_facet(url, facet):
284     return append_facet('categories', url, facet)
285
286 @register.filter
287 def append_news_category_facet(url, facet):
288     return append_facet('news_categories', url, facet)
289
290 @register.filter
291 def append_format_facet(url, facet):
292     return append_facet('format', url, facet)
293
294
295 @register.tag
296 def search_result_template(parser, token):
297     try:
298         tag_name, result_str = token.split_contents()
299     except ValueError:
300         raise template.TemplateSyntaxError("%r tag requires exactly one argument" % token.contents.split()[0])
301     return FormatSearchResultNode(result_str)
302
303
304 class FormatSearchResultNode(template.Node):
305     def __init__(self, result_str):
306         self.result_var = template.Variable(result_str)
307
308     def render(self, context):
309         result = self.result_var.resolve(context)
310         dir_mapping = {
311             'newsitem': 'news',
312             'emission': 'emissions',
313             'episode': 'episodes'
314         }
315         t = template.loader.get_template('%s/search_result.html' % dir_mapping.get(result.model_name))
316         return t.render({'result': result})
317
318
319 @register.inclusion_tag('includes/piwik.html')
320 def piwik():
321     return {'enabled': settings.ENABLE_PIWIK}
322
323
324 @register.filter
325 def rfc822(datetime):
326     if datetime is None:
327         return ''
328     return email.utils.formatdate(time.mktime(datetime.timetuple()))
329
330 @register.inclusion_tag('includes/related.html', takes_context=False)
331 def related_objects(object):
332     sqs = search.MoreLikeThisSearchQuerySet().models(Emission, Episode, NewsItem)
333     return {'more_like_this': sqs.more_like_this(object)[:12]}
334
335 @register.inclusion_tag('includes/topik.html', takes_context=True)
336 def topik(context, topik):
337     return {'topik': topik}
338
339 @register.filter
340 def get_focus_url(object):
341     if object.newsitem:
342         return reverse('newsitem-view', kwargs={'slug': object.newsitem.slug})
343     if object.emission:
344         return reverse('emission-view', kwargs={'slug': object.emission.slug})
345     if object.episode:
346         return reverse('episode-view', kwargs={
347             'slug': object.episode.slug, 'emission_slug': object.episode.emission.slug})
348     if object.soundfile:
349         return reverse('episode-view', kwargs={
350             'slug': object.soundfile.episode.slug,
351             'emission_slug': object.soundfile.episode.emission.slug})
352     if object.page:
353         return object.page.get_online_url()
354     return ''
355
356 @register.filter
357 def facet_tag(tag):
358     return tag.name
359
360
361 @register.filter
362 def image_file(page):
363     try:
364         matching_topik = Topik.objects.get(page=page)
365         return matching_topik.image
366     except Topik.DoesNotExist:
367         pass
368     return None
369
370
371 @register.filter
372 def set_absolute_urls(text):
373     text = text.replace('src="/', 'src="%s' % settings.WEBSITE_BASE_URL)
374     text = text.replace('href="/', 'href="%s' % settings.WEBSITE_BASE_URL)
375     return text
376
377 @register.filter
378 def as_absolute_url(url):
379     if url.startswith('/'):
380         url = settings.WEBSITE_BASE_URL + url.lstrip('/')
381     return url