1 """Template tags and filters for Zinnia"""
2 try:
3 from hashlib import md5
4 except ImportError:
5 from md5 import new as md5
6
7 from random import sample
8 from urllib import urlencode
9 from datetime import datetime
10
11 from django.db import connection
12 from django.template import Library
13 from django.contrib.comments.models import Comment
14 from django.contrib.contenttypes.models import ContentType
15 from django.utils.encoding import smart_unicode
16
17 from zinnia.models import Entry
18 from zinnia.models import Author
19 from zinnia.models import Category
20 from zinnia.comparison import VectorBuilder
21 from zinnia.comparison import pearson_score
22 from zinnia.templatetags.zbreadcrumbs import retrieve_breadcrumbs
23
24 register = Library()
25
26 VECTORS = None
27 VECTORS_FACTORY = lambda: VectorBuilder({'queryset': Entry.published.all(),
28 'fields': ['title', 'excerpt',
29 'content']})
30 CACHE_ENTRIES_RELATED = {}
31
32
33 @register.inclusion_tag('zinnia/tags/dummy.html')
34 -def get_categories(template='zinnia/tags/categories.html'):
35 """Return the categories"""
36 return {'template': template,
37 'categories': Category.tree.all()}
38
39
40 @register.inclusion_tag('zinnia/tags/dummy.html')
41 -def get_authors(template='zinnia/tags/authors.html'):
45
46
47 @register.inclusion_tag('zinnia/tags/dummy.html')
48 -def get_recent_entries(number=5, template='zinnia/tags/recent_entries.html'):
49 """Return the most recent entries"""
50 return {'template': template,
51 'entries': Entry.published.all()[:number]}
52
53
54 @register.inclusion_tag('zinnia/tags/dummy.html')
55 -def get_featured_entries(number=5, template='zinnia/tags/featured_entries.html'):
59
60
61 @register.inclusion_tag('zinnia/tags/dummy.html')
62 -def get_random_entries(number=5, template='zinnia/tags/random_entries.html'):
69
70
71 @register.inclusion_tag('zinnia/tags/dummy.html')
72 -def get_popular_entries(number=5, template='zinnia/tags/popular_entries.html'):
73 """Return popular entries"""
74 ctype = ContentType.objects.get_for_model(Entry)
75 query = """SELECT object_pk, COUNT(*) AS score
76 FROM %s
77 WHERE content_type_id = %%s
78 AND is_public = '1'
79 GROUP BY object_pk
80 ORDER BY score DESC""" % Comment._meta.db_table
81
82 cursor = connection.cursor()
83 cursor.execute(query, [ctype.id])
84 object_ids = [int(row[0]) for row in cursor.fetchall()]
85
86
87
88 object_dict = Entry.published.in_bulk(object_ids)
89
90 return {'template': template,
91 'entries': [object_dict[object_id]
92 for object_id in object_ids
93 if object_id in object_dict][:number]}
94
95
96 @register.inclusion_tag('zinnia/tags/dummy.html', takes_context=True)
97 -def get_similar_entries(context, number=5,
98 template='zinnia/tags/similar_entries.html',
99 flush=False):
127
128 object_id = context['object'].pk
129 columns, dataset = VECTORS()
130 key = '%s-%s' % (object_id, VECTORS.key)
131 if not key in CACHE_ENTRIES_RELATED.keys():
132 CACHE_ENTRIES_RELATED[key] = compute_related(object_id, dataset)
133
134 entries = CACHE_ENTRIES_RELATED[key][:number]
135 return {'template': template,
136 'entries': entries}
137
138
139 @register.inclusion_tag('zinnia/tags/dummy.html')
140 -def get_archives_entries(template='zinnia/tags/archives_entries.html'):
141 """Return archives entries"""
142 return {'template': template,
143 'archives': Entry.published.dates('creation_date', 'month',
144 order='DESC')}
145
146
147 @register.inclusion_tag('zinnia/tags/dummy.html')
148 -def get_archives_entries_tree(
149 template='zinnia/tags/archives_entries_tree.html'):
150 """Return archives entries as a Tree"""
151 return {'template': template,
152 'archives': Entry.published.dates('creation_date', 'day',
153 order='ASC')}
154
155
156 @register.inclusion_tag('zinnia/tags/dummy.html', takes_context=True)
157 -def get_calendar_entries(context, year=None, month=None,
158 template='zinnia/tags/calendar.html'):
159 """Return an HTML calendar of entries"""
160 if not year or not month:
161 date_month = context.get('month') or context.get('day') or \
162 getattr(context.get('object'), 'creation_date', None) or \
163 datetime.today()
164 year, month = date_month.timetuple()[:2]
165
166 try:
167 from zinnia.templatetags.zcalendar import ZinniaCalendar
168 except ImportError:
169 return {'calendar':
170 '<p class="notice">Calendar is unavailable for Python<2.5.</p>'}
171
172 calendar = ZinniaCalendar()
173 current_month = datetime(year, month, 1)
174
175 dates = list(Entry.published.dates('creation_date', 'month'))
176
177 if not current_month in dates:
178 dates.append(current_month)
179 dates.sort()
180 index = dates.index(current_month)
181
182 previous_month = index > 0 and dates[index - 1] or None
183 next_month = index != len(dates) - 1 and dates[index + 1] or None
184
185 return {'template': template,
186 'next_month': next_month,
187 'previous_month': previous_month,
188 'calendar': calendar.formatmonth(year, month)}
189
207
208
209 @register.inclusion_tag('zinnia/tags/dummy.html')
210 -def get_recent_linkbacks(number=5,
211 template='zinnia/tags/recent_linkbacks.html'):
212 """Return the most recent linkbacks"""
213 entry_published_pks = map(smart_unicode,
214 Entry.published.values_list('id', flat=True))
215 content_type = ContentType.objects.get_for_model(Entry)
216
217 linkbacks = Comment.objects.filter(
218 content_type=content_type,
219 object_pk__in=entry_published_pks,
220 flags__flag__in=['pingback', 'trackback'],
221 is_public=True).order_by(
222 '-submit_date')[:number]
223
224 return {'template': template,
225 'linkbacks': linkbacks}
226
227
228 @register.inclusion_tag('zinnia/tags/dummy.html', takes_context=True)
229 -def zinnia_breadcrumbs(context, separator='/', root_name='Blog',
230 template='zinnia/tags/breadcrumbs.html',):
231 """Return a breadcrumb for the application"""
232 path = context['request'].path
233 page_object = context.get('object') or context.get('category') or \
234 context.get('tag') or context.get('author')
235 breadcrumbs = retrieve_breadcrumbs(path, page_object, root_name)
236
237 return {'template': template,
238 'separator': separator,
239 'breadcrumbs': breadcrumbs}
240
241
242 @register.simple_tag
243 -def get_gravatar(email, size=80, rating='g', default=None):
244 """Return url for a Gravatar"""
245 url = 'http://www.gravatar.com/avatar/%s.jpg' % \
246 md5(email.strip().lower()).hexdigest()
247 options = {'s': size, 'r': rating}
248 if default:
249 options['d'] = default
250
251 url = '%s?%s' % (url, urlencode(options))
252 return url.replace('&', '&')
253