1 """EntryAdmin for Zinnia"""
2 from datetime import datetime
3
4 from django.forms import Media
5 from django.contrib import admin
6 from django.contrib.auth.models import User
7 from django.utils.html import strip_tags
8 from django.utils.text import truncate_words
9 from django.conf.urls.defaults import url
10 from django.conf.urls.defaults import patterns
11 from django.utils.translation import ugettext_lazy as _
12 from django.core.urlresolvers import reverse, NoReverseMatch
13
14 from tagging.models import Tag
15
16 from zinnia import settings
17 from zinnia.managers import HIDDEN
18 from zinnia.managers import PUBLISHED
19 from zinnia.ping import DirectoryPinger
20 from zinnia.admin.forms import EntryAdminForm
21
22
23 -class EntryAdmin(admin.ModelAdmin):
24 """Admin for Entry model"""
25 form = EntryAdminForm
26 date_hierarchy = 'creation_date'
27 fieldsets = ((_('Content'), {'fields': ('title', 'content',
28 'image', 'status')}),
29 (_('Options'), {'fields': ('featured', 'excerpt', 'template',
30 'related', 'authors',
31 'creation_date', 'start_publication',
32 'end_publication'),
33 'classes': ('collapse', 'collapse-closed')}),
34 (_('Privacy'), {'fields': ('password', 'login_required',),
35 'classes': ('collapse', 'collapse-closed')}),
36 (_('Discussion'), {'fields': ('comment_enabled',
37 'pingback_enabled')}),
38 (_('Publication'), {'fields': ('categories', 'tags',
39 'sites', 'slug')}))
40 list_filter = ('categories', 'authors', 'status', 'featured',
41 'login_required', 'comment_enabled', 'pingback_enabled',
42 'creation_date', 'start_publication',
43 'end_publication', 'sites')
44 list_display = ('get_title', 'get_authors', 'get_categories',
45 'get_tags', 'get_sites',
46 'comment_enabled', 'pingback_enabled',
47 'get_is_actual', 'get_is_visible', 'get_link',
48 'get_short_url', 'creation_date')
49 radio_fields = {'template': admin.VERTICAL}
50 filter_horizontal = ('categories', 'authors', 'related')
51 prepopulated_fields = {'slug': ('title', )}
52 search_fields = ('title', 'excerpt', 'content', 'tags')
53 actions = ['make_mine', 'make_published', 'make_hidden',
54 'close_comments', 'close_pingbacks',
55 'ping_directories', 'make_tweet', 'put_on_top']
56 actions_on_top = True
57 actions_on_bottom = True
58
59 - def __init__(self, model, admin_site):
62
63
64 - def get_title(self, entry):
65 """Return the title with word count and number of comments"""
66 title = _('%(title)s (%(word_count)i words)') % \
67 {'title': entry.title, 'word_count': entry.word_count}
68 comments = entry.comments.count()
69 if comments:
70 return _('%(title)s (%(comments)i comments)') % \
71 {'title': title, 'comments': comments}
72 return title
73 get_title.short_description = _('title')
74
75 - def get_authors(self, entry):
76 """Return the authors in HTML"""
77 try:
78 authors = ['<a href="%s" target="blank">%s</a>' %
79 (reverse('zinnia_author_detail',
80 args=[author.username]),
81 author.username) for author in entry.authors.all()]
82 except NoReverseMatch:
83 authors = [author.username for author in entry.authors.all()]
84 return ', '.join(authors)
85 get_authors.allow_tags = True
86 get_authors.short_description = _('author(s)')
87
88 - def get_categories(self, entry):
89 """Return the categories linked in HTML"""
90 try:
91 categories = ['<a href="%s" target="blank">%s</a>' %
92 (category.get_absolute_url(), category.title)
93 for category in entry.categories.all()]
94 except NoReverseMatch:
95 categories = [category.title for category in
96 entry.categories.all()]
97 return ', '.join(categories)
98 get_categories.allow_tags = True
99 get_categories.short_description = _('category(s)')
100
102 """Return the tags linked in HTML"""
103 try:
104 return ', '.join(['<a href="%s" target="blank">%s</a>' %
105 (reverse('zinnia_tag_detail',
106 args=[tag.name]), tag.name)
107 for tag in Tag.objects.get_for_object(entry)])
108 except NoReverseMatch:
109 return entry.tags
110 get_tags.allow_tags = True
111 get_tags.short_description = _('tag(s)')
112
113 - def get_sites(self, entry):
114 """Return the sites linked in HTML"""
115 return ', '.join(['<a href="http://%(domain)s" target="blank">%(name)s</a>' %
116 site.__dict__ for site in entry.sites.all()])
117 get_sites.allow_tags = True
118 get_sites.short_description = _('site(s)')
119
120 - def get_is_actual(self, entry):
121 """Admin wrapper for entry.is_actual"""
122 return entry.is_actual
123 get_is_actual.boolean = True
124 get_is_actual.short_description = _('is actual')
125
126 - def get_is_visible(self, entry):
127 """Admin wrapper for entry.is_visible"""
128 return entry.is_visible
129 get_is_visible.boolean = True
130 get_is_visible.short_description = _('is visible')
131
132 - def get_link(self, entry):
133 """Return a formated link to the entry"""
134 return _('<a href="%s" target="blank">View</a>') % \
135 entry.get_absolute_url()
136 get_link.allow_tags = True
137 get_link.short_description = _('View on site')
138
139 - def get_short_url(self, entry):
140 """Return the short url in HTML"""
141 short_url = entry.short_url
142 if not short_url:
143 return _('Unavailable')
144 return '<a href="%(url)s" target="blank">%(url)s</a>' % \
145 {'url': short_url}
146 get_short_url.allow_tags = True
147 get_short_url.short_description = _('short url')
148
149
150 - def save_model(self, request, entry, form, change):
151 """Save the authors, update time, make an excerpt"""
152 if not form.cleaned_data.get('excerpt') and entry.status == PUBLISHED:
153 entry.excerpt = truncate_words(strip_tags(entry.content), 50)
154
155 if entry.pk and not request.user.has_perm('zinnia.can_change_author'):
156 form.cleaned_data['authors'] = entry.authors.all()
157
158 if not form.cleaned_data.get('authors'):
159 form.cleaned_data['authors'].append(request.user)
160
161 entry.last_update = datetime.now()
162 entry.save()
163
164 - def queryset(self, request):
165 """Make special filtering by user permissions"""
166 queryset = super(EntryAdmin, self).queryset(request)
167 if request.user.has_perm('zinnia.can_view_all'):
168 return queryset
169 return request.user.entry_set.all()
170
172 """Filters the disposable authors"""
173 if db_field.name == 'authors':
174 if request.user.has_perm('zinnia.can_change_author'):
175 kwargs['queryset'] = User.objects.filter(is_staff=True)
176 else:
177 kwargs['queryset'] = User.objects.filter(pk=request.user.pk)
178
179 return super(EntryAdmin, self).formfield_for_manytomany(
180 db_field, request, **kwargs)
181
182 - def get_actions(self, request):
183 """Define user actions by permissions"""
184 actions = super(EntryAdmin, self).get_actions(request)
185 if not request.user.has_perm('zinnia.can_change_author') \
186 or not request.user.has_perm('zinnia.can_view_all'):
187 del actions['make_mine']
188 if not settings.PING_DIRECTORIES:
189 del actions['ping_directories']
190 if not settings.USE_TWITTER or not settings.USE_BITLY:
191 del actions['make_tweet']
192
193 return actions
194
195
196 - def make_mine(self, request, queryset):
197 """Set the entries to the user"""
198 for entry in queryset:
199 if request.user not in entry.authors.all():
200 entry.authors.add(request.user)
201 make_mine.short_description = _('Set the entries to the user')
202
203 - def make_published(self, request, queryset):
204 """Set entries selected as published"""
205 queryset.update(status=PUBLISHED)
206 make_published.short_description = _('Set entries selected as published')
207
208 - def make_hidden(self, request, queryset):
209 """Set entries selected as hidden"""
210 queryset.update(status=HIDDEN)
211 make_hidden.short_description = _('Set entries selected as hidden')
212
214 """Post an update on Twitter"""
215 import tweepy
216 auth = tweepy.OAuthHandler(settings.TWITTER_CONSUMER_KEY,
217 settings.TWITTER_CONSUMER_SECRET)
218 auth.set_access_token(settings.TWITTER_ACCESS_KEY,
219 settings.TWITTER_ACCESS_SECRET)
220 api = tweepy.API(auth)
221 for entry in queryset:
222 message = '%s %s' % (entry.title[:119], entry.short_url)
223 api.update_status(message)
224 make_tweet.short_description = _('Tweet entries selected')
225
229 close_comments.short_description = _('Close the comments for '\
230 'selected entries')
231
232 - def close_pingbacks(self, request, queryset):
233 """Close the pingbacks for selected entries"""
234 queryset.update(pingback_enabled=False)
235 close_pingbacks.short_description = _('Close the linkbacks for selected entries')
236
237 - def put_on_top(self, request, queryset):
238 """Put the selected entries on top at the current date"""
239 queryset.update(creation_date=datetime.now())
240 put_on_top.short_description = _('Put the selected entries on top at the current date')
241
242 - def ping_directories(self, request, queryset):
243 """Ping Directories for selected entries"""
244 for directory in settings.PING_DIRECTORIES:
245 pinger = DirectoryPinger(directory, queryset)
246 pinger.join()
247 success = 0
248 for result in pinger.results:
249 if not result.get('flerror', True):
250 success += 1
251 else:
252 self.message_user(request, '%s : %s' % (directory,
253 result['message']))
254 if success:
255 self.message_user(request,
256 _('%(directory)s directory succesfully ' \
257 'pinged %(success)d entries.') %
258 {'directory': directory, 'success': success})
259 ping_directories.short_description = _('Ping Directories for ' \
260 'selected entries')
261
262 - def get_urls(self):
263 entry_admin_urls = super(EntryAdmin, self).get_urls()
264 urls = patterns('django.views.generic.simple',
265 url(r'^autocomplete_tags/$', 'direct_to_template',
266 {'template': 'admin/zinnia/entry/autocomplete_tags.js',
267 'mimetype': 'application/javascript'},
268 name='zinnia_entry_autocomplete_tags'),
269 url(r'^wymeditor/$', 'direct_to_template',
270 {'template': 'admin/zinnia/entry/wymeditor.js',
271 'mimetype': 'application/javascript'},
272 name='zinnia_entry_wymeditor'),)
273 return urls + entry_admin_urls
274
276 MEDIA_URL = settings.MEDIA_URL
277 media = super(EntryAdmin, self).media + \
278 Media(css={'all': ('%scss/jquery.autocomplete.css' % MEDIA_URL,)},
279 js=('%sjs/jquery.js' % MEDIA_URL,
280 '%sjs/jquery.bgiframe.js' % MEDIA_URL,
281 '%sjs/jquery.autocomplete.js' % MEDIA_URL,
282 reverse('admin:zinnia_entry_autocomplete_tags'),))
283
284 if settings.WYSIWYG == 'wymeditor':
285 media += Media(js=('%sjs/wymeditor/jquery.wymeditor.pack.js' % MEDIA_URL,
286 reverse('admin:zinnia_entry_wymeditor')))
287 elif settings.WYSIWYG == 'tinymce':
288 from tinymce.widgets import TinyMCE
289 media += TinyMCE().media + Media(
290 js=(reverse('tinymce-js', args=('admin/zinnia/entry',)),))
291 return media
292 media = property(_media)
293