2
from sgmllib import SGMLParser
4
from django.contrib.auth.models import User
5
from django.contrib.sites.models import Site
6
from django.core.urlresolvers import reverse
7
from django.core.urlresolvers import NoReverseMatch
8
from django.utils.feedgenerator import Atom1Feed
9
from django.utils.translation import ugettext as _
10
from django.contrib.syndication.views import Feed
11
from django.shortcuts import get_object_or_404
13
from tagging.models import Tag
14
from tagging.models import TaggedItem
16
from zinnia.models import Entry
17
from zinnia.settings import COPYRIGHT
18
from zinnia.settings import PROTOCOL
19
from zinnia.settings import FEEDS_MAX_ITEMS
20
from zinnia.managers import entries_published
21
from zinnia.views.categories import get_category_or_404
24
class ImgParser(SGMLParser):
25
"""Parser for getting IMG markups"""
28
SGMLParser.__init__(self)
29
self.img_locations = []
31
def start_img(self, attr):
32
"""Save each image's location"""
34
if attr.get('src', ''):
35
self.img_locations.append(attr['src'])
40
title_template = 'feeds/entry_title.html'
41
description_template = 'feeds/entry_description.html'
42
feed_copyright = COPYRIGHT
45
self.site = Site.objects.get_current()
47
def item_pubdate(self, item):
48
"""Publication date of an entry"""
49
return item.creation_date
51
def item_categories(self, item):
52
"""Entry's categories"""
53
return [category.title for category in item.categories.all()]
55
def item_author_name(self, item):
56
"""Returns the first author of an entry"""
57
return item.authors.all()[0].username
59
def item_author_email(self, item):
60
"""Returns the first author's email"""
61
return item.authors.all()[0].email
63
def item_author_link(self, item):
64
"""Returns the author's URL"""
65
url = '%s://%s' % (PROTOCOL, self.site.domain)
67
author_url = reverse('zinnia_author_detail',
68
args=[item.authors.all()[0].username])
69
return url + author_url
70
except NoReverseMatch:
73
def item_enclosure_url(self, item):
74
"""Returns an image for enclosure"""
79
parser.feed(item.content)
80
except UnicodeEncodeError:
82
if len(parser.img_locations):
83
if self.site.domain in parser.img_locations[0]:
84
return parser.img_locations[0]
86
return '%s://%s%s' % (PROTOCOL,
88
parser.img_locations[0])
91
def item_enclosure_length(self, item):
92
"""Hardcoded enclosure length"""
95
def item_enclosure_mime_type(self, item):
96
"""Hardcoded enclosure mimetype"""
100
class LatestEntries(EntryFeed):
101
"""Feed for the latest entries"""
102
title = _('Latest entries')
105
"""URL of latest entries"""
106
return reverse('zinnia_entry_archive_index')
109
"""Items are published entries"""
110
return Entry.published.all()[:FEEDS_MAX_ITEMS]
112
def description(self, obj):
113
"""Description of the feed"""
114
return _('The latest entries for the site %s') % self.site.domain
117
class CategoryEntries(EntryFeed):
118
"""Feed filtered by a category"""
120
def get_object(self, request, path):
121
"""Retrieve the category by his path"""
122
return get_category_or_404(path)
124
def items(self, obj):
125
"""Items are the published entries of the category"""
126
return obj.entries_published_set()[:FEEDS_MAX_ITEMS]
129
"""URL of the category"""
130
return obj.get_absolute_url()
132
def title(self, obj):
133
"""Title of the feed"""
134
return _('Entries for the category %s') % obj.title
136
def description(self, obj):
137
"""Description of the feed"""
138
return _('The latest entries for the category %s') % obj.title
141
class AuthorEntries(EntryFeed):
142
"""Feed filtered by an author"""
144
def get_object(self, request, username):
145
"""Retrieve the author by his username"""
146
return get_object_or_404(User, username=username)
148
def items(self, obj):
149
"""Items are the published entries of the author"""
150
return entries_published(obj.entry_set)[:FEEDS_MAX_ITEMS]
153
"""URL of the author"""
154
return reverse('zinnia_author_detail', args=[obj.username])
156
def title(self, obj):
157
"""Title of the feed"""
158
return _('Entries for author %s') % obj.username
160
def description(self, obj):
161
"""Description of the feed"""
162
return _('The latest entries by %s') % obj.username
165
class TagEntries(EntryFeed):
166
"""Feed filtered by a tag"""
168
def get_object(self, request, slug):
169
"""Retrieve the tag by his name"""
170
return get_object_or_404(Tag, name=slug)
172
def items(self, obj):
173
"""Items are the published entries of the tag"""
174
return TaggedItem.objects.get_by_model(
175
Entry.published.all(), obj)[:FEEDS_MAX_ITEMS]
179
return reverse('zinnia_tag_detail', args=[obj.name])
181
def title(self, obj):
182
"""Title of the feed"""
183
return _('Entries for the tag %s') % obj.name
185
def description(self, obj):
186
"""Description of the feed"""
187
return _('The latest entries for the tag %s') % obj.name
190
class SearchEntries(EntryFeed):
191
"""Feed filtered by a search pattern"""
193
def get_object(self, request, slug):
194
"""The slug is the pattern to search"""
197
def items(self, obj):
198
"""Items are the published entries founds"""
199
return Entry.published.search(obj)[:FEEDS_MAX_ITEMS]
202
"""URL of the search request"""
203
return '%s?pattern=%s' % (reverse('zinnia_entry_search'), obj)
205
def title(self, obj):
206
"""Title of the feed"""
207
return _('Results of the search for %s') % obj
209
def description(self, obj):
210
"""Description of the feed"""
211
return _('The entries containing the pattern %s') % obj
214
class EntryDiscussions(Feed):
215
"""Feed for discussions in an entry"""
216
title_template = 'feeds/discussion_title.html'
217
description_template = 'feeds/discussion_description.html'
218
feed_copyright = COPYRIGHT
220
def get_object(self, request, slug):
221
"""Retrieve the discussions by entry's slug"""
222
return get_object_or_404(Entry, slug=slug)
224
def items(self, obj):
225
"""Items are the discussions on the entry"""
226
return obj.discussions[:FEEDS_MAX_ITEMS]
228
def item_pubdate(self, item):
229
"""Publication date of a discussion"""
230
return item.submit_date
232
def item_link(self, item):
233
"""URL of the discussion"""
234
return item.get_absolute_url()
237
"""URL of the entry"""
238
return obj.get_absolute_url()
240
def item_author_name(self, item):
241
"""Author of the discussion"""
242
return item.userinfo['name']
244
def item_author_email(self, item):
245
"""Author's email of the discussion"""
246
return item.userinfo['email']
248
def item_author_link(self, item):
249
"""Author's URL of the discussion"""
250
return item.userinfo['url']
252
def title(self, obj):
253
"""Title of the feed"""
254
return _('Discussions on %s') % obj.title
256
def description(self, obj):
257
"""Description of the feed"""
258
return _('The latest discussions for the entry %s') % obj.title
261
class EntryComments(EntryDiscussions):
262
"""Feed for comments in an entry"""
263
title_template = 'feeds/comment_title.html'
264
description_template = 'feeds/comment_description.html'
266
def items(self, obj):
267
"""Items are the comments on the entry"""
268
return obj.comments[:FEEDS_MAX_ITEMS]
270
def item_link(self, item):
271
"""URL of the comment"""
272
return item.get_absolute_url('#comment_%(id)s')
274
def title(self, obj):
275
"""Title of the feed"""
276
return _('Comments on %s') % obj.title
278
def description(self, obj):
279
"""Description of the feed"""
280
return _('The latest comments for the entry %s') % obj.title
283
class EntryPingbacks(EntryDiscussions):
284
"""Feed for pingbacks in an entry"""
285
title_template = 'feeds/pingback_title.html'
286
description_template = 'feeds/pingback_description.html'
288
def items(self, obj):
289
"""Items are the pingbacks on the entry"""
290
return obj.pingbacks[:FEEDS_MAX_ITEMS]
292
def item_link(self, item):
293
"""URL of the pingback"""
294
return item.get_absolute_url('#pingback_%(id)s')
296
def title(self, obj):
297
"""Title of the feed"""
298
return _('Pingbacks on %s') % obj.title
300
def description(self, obj):
301
"""Description of the feed"""
302
return _('The latest pingbacks for the entry %s') % obj.title
305
class EntryTrackbacks(EntryDiscussions):
306
"""Feed for trackbacks in an entry"""
307
title_template = 'feeds/trackback_title.html'
308
description_template = 'feeds/trackback_description.html'
310
def items(self, obj):
311
"""Items are the trackbacks on the entry"""
312
return obj.trackbacks[:FEEDS_MAX_ITEMS]
314
def item_link(self, item):
315
"""URL of the trackback"""
316
return item.get_absolute_url('#trackback_%(id)s')
318
def title(self, obj):
319
"""Title of the feed"""
320
return _('Trackbacks on %s') % obj.title
322
def description(self, obj):
323
"""Description of the feed"""
324
return _('The latest trackbacks for the entry %s') % obj.title
327
# Atom versions of the feeds
328
class AtomLatestEntries(LatestEntries):
329
"""Atom feed for the latest entries"""
330
feed_type = Atom1Feed
331
subtitle = LatestEntries.description
334
class AtomCategoryEntries(CategoryEntries):
335
"""Atom feed filtered by a category"""
336
feed_type = Atom1Feed
337
subtitle = CategoryEntries.description
340
class AtomAuthorEntries(AuthorEntries):
341
"""Atom feed filtered by an author"""
342
feed_type = Atom1Feed
343
subtitle = AuthorEntries.description
346
class AtomTagEntries(TagEntries):
347
"""Atom feed filtered by a tag"""
348
feed_type = Atom1Feed
349
subtitle = TagEntries.description
352
class AtomSearchEntries(SearchEntries):
353
"""Atom feed filtered by a search pattern"""
354
feed_type = Atom1Feed
355
subtitle = SearchEntries.description
358
class AtomEntryDiscussions(EntryDiscussions):
359
"""Atom feed for discussions in an entry"""
360
feed_type = Atom1Feed
361
subtitle = EntryDiscussions.description
364
class AtomEntryComments(EntryComments):
365
"""Atom feed for comments in an entry"""
366
feed_type = Atom1Feed
367
subtitle = EntryComments.description
370
class AtomEntryPingbacks(EntryPingbacks):
371
"""Atom feed for pingbacks in an entry"""
372
feed_type = Atom1Feed
373
subtitle = EntryPingbacks.description
376
class AtomEntryTrackbacks(EntryTrackbacks):
377
"""Atom feed for trackbacks in an entry"""
378
feed_type = Atom1Feed
379
subtitle = EntryTrackbacks.description