Newer
Older
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import copy
from django.contrib import messages, admin
from django.contrib.admin.models import LogEntry, CHANGE
from django.contrib.admin.templatetags.admin_static import static
from django.contrib.contenttypes.models import ContentType
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _, ungettext_lazy
from django.utils import six, formats
from django.utils.html import format_html
def get_fieldset_by_field(name, fieldsets):
"""
Return fieldset containing a field given by name
"""
for fieldset in fieldsets:
options = fieldset[1]
if name in options.get('fields', {}):
return fieldset
return None
def remove_field_from_fieldsets(name, fieldsets, remove_empty_fieldset=True):
"""
Remove a field from all fieldset in fieldsets.
"""
while True:
fieldset = get_fieldset_by_field(name, fieldsets)
if fieldset:
fieldset[1]['fields'].remove(name)
if remove_empty_fieldset and len(fieldset[1]['fields']) == 0:
fieldsets.remove(fieldset)
else:
break
def add_fields_to_fieldset(
fields,
fieldsets,
after_field=None,
same_fieldset_as=None,
default_fieldset_name=None,

Dylann Cordel
committed
default_fieldset_classes=[],
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
default_fieldset_position=None,
replace_existing_field=False,
remove_empty_fieldset=False,
):
"""
Add fields in a fieldsets attribute
Try to find a fieldset containing same_fieldset_as value in fields. If not
found a new fieldset is created with name `default_fieldset_name`, position
`default_fieldset_position` and classes `default_fieldset_classes`.
Fields are inserted just after after_field. If not found, they are inserted
at the end.
If replace_existing_field is True, existing fields in fieldsets with same
name are removed.
"""
if same_fieldset_as is None and after_field:
same_fieldset_as = after_field
# Find fieldset
fieldset = get_fieldset_by_field(same_fieldset_as, fieldsets)
if fieldset is None:
fieldset = (default_fieldset_name, {
'fields': [],
'classes': default_fieldset_classes,
})
allready_inserted = False
else:
allready_inserted = True
# Insert fields
index = None
if after_field:
index = fieldset[1]['fields'].index(after_field) + 1
index = index or len(fieldset[1]['fields'])
for field in fields:
if replace_existing_field:
remove_field_from_fieldsets(
field, fieldsets,
remove_empty_fieldset=remove_empty_fieldset)
elif get_fieldset_by_field(field, fieldsets) is not None:
continue
fieldset[1]['fields'].insert(index, field)
index += 1
# Insert fieldset if needed.
if not allready_inserted and len(fieldset[1]['fields']) > 0:
if default_fieldset_position is not None:
fieldsets.insert(default_fieldset_position, fieldset)
else:
fieldsets.append(fieldset)
class NewsboxBaseAdmin(admin.ModelAdmin):
list_filter = ('newsbox_publication_start_date', 'newsbox_status', )
list_display_links = ('get_newsbox_title',)
fieldsets = [
(None, {
'fields': ['newsbox_title', 'newsbox_slug', 'newsbox_date', 'newsbox_status', ], }),
(_('Content'), {
'fields': ['newsbox_summary', 'newsbox_body'], }), ]
actions = ['publish', 'unpublish']
save_as = True
def get_list_display(self, request):
if not getattr(self.__class__, 'list_display', None):
self.list_display = ['get_newsbox_title', 'newsbox_date_short', 'changestatus_link']
return super(NewsboxBaseAdmin, self).get_list_display(request)
def get_prepopulated_fields(self, request, object=None):
pfields = super(NewsboxBaseAdmin, self).get_prepopulated_fields(request, object) or {}
pfields.update({'newsbox_slug': ('newsbox_title',)})
return pfields
def changestatus_link(self, obj):
title = _('Unpublish this %s') % six.text_type(
obj._meta.verbose_name)
icon_url = static('admin/img/icon-yes.gif')
else:
title = _('Publish this %s') % six.text_type(
obj._meta.verbose_name)
icon_url = static('admin/img/icon-no.gif')
url_name = '%s_%s_change_status' % (self.model._meta.model_name,
self.model._meta.app_label)
return format_html('<a href="%s" title="%s"><img src="%s" alt="%s" /></a>',
reverse('admin:%s' % url_name, args=[obj.pk, ]),
title, icon_url, obj.get_newsbox_status_display())
changestatus_link.admin_order_field = 'newsbox_status'
changestatus_link.short_description = _('published')
def newsbox_date_short(self, obj):
return format_html('<span title="%s">%s</span>',
formats.date_format(obj.newsbox_publication_start_date, 'DATETIME_FORMAT'),
formats.date_format(obj.newsbox_publication_start_date, 'SHORT_DATE_FORMAT')
)
newsbox_date_short.short_description = _('pub. date')
def get_fieldsets(self, request, obj=None):
"""
Prevent anoying modification of fieldsets class attribute.
"""
fieldsets = super(NewsboxBaseAdmin, self).get_fieldsets(request, obj)
return copy.deepcopy(fieldsets)
def get_newsbox_title(self, obj):
return obj.newsbox_title
get_newsbox_title.short_description = _('Title')
def get_urls(self):
url_prefix = '%s_%s_' % (self.model._meta.model_name, self.model._meta.app_label)
url(r'^([0-9]+)/change-status/$',
self.admin_site.admin_view(self.change_status),
name='%schange_status' % url_prefix,),
url(r'^([0-9]+)/publish/$',
self.admin_site.admin_view(self.publish_one),
name='%spublish_one' % url_prefix,),
url(r'^([0-9]+)/unpublish/$',
self.admin_site.admin_view(self.unpublish_one),
name='%sunpublish_one' % url_prefix,)
] + super(NewsboxBaseAdmin, self).get_urls()
def change_status(self, request, news_id):
"""
Switch the status of a news
"""
obj = get_object_or_404(self.model, pk=news_id)
if not obj.has_publish_permission(request.user):
return HttpResponseForbidden(
_('You do not have permission to publish this %s')
% (six.text_type(self.model._meta.verbose_name),))
old_status = obj.newsbox_status
if obj.newsbox_status == obj.STATUS_PUBLISHED:
obj.newsbox_status = obj.STATUS_ARCHIVED
else:
obj.newsbox_status = obj.STATUS_PUBLISHED
obj.save()
log_msg = _('publication status changed from %(old)s to %(new)s') % {
'old': old_status,
}
if obj.newsbox_status == obj.STATUS_PUBLISHED:
msg = _('The %(objtype)s "%(objtitle)s" has been successfully published')
msg = _('The %(objtype)s "%(objtitle)s" has been successfully unpublished')
messages.info(request, msg % {'objtype': six.text_type(self.model._meta.verbose_name),
'objtitle': six.text_type(obj)})
LogEntry.objects.log_action(
user_id=request.user.id,
content_type_id=ContentType.objects.get_for_model(self.model).pk,
object_id=news_id,
object_repr=six.text_type(obj),
change_message=log_msg,
return HttpResponseRedirect(request.GET.get('next', '../../'))
def publish_one(self, request, news_id):
obj = get_object_or_404(self.model, pk=news_id)
if not obj.has_publish_permission(request.user):
return HttpResponseForbidden(
_('You do not have permission to publish this %s')
% (six.text_type(self.model._meta.verbose_name),))
self.publish(request, self.model.objects.filter(pk=news_id))
return HttpResponseRedirect(request.GET.get('next', '../../'))
def unpublish_one(self, request, news_id):
obj = get_object_or_404(self.model, pk=news_id)
if not obj.has_publish_permission(request.user):
return HttpResponseForbidden(
_('You do not have permission to publish this %s')
% (six.text_type(self.model._meta.verbose_name),))
self.unpublish(request, self.model.objects.filter(pk=news_id))
return HttpResponseRedirect(request.GET.get('next', '../../'))
def publish(self, request, queryset):
"""
Marks selected news items as published
"""
ok = 0
content_type_id = ContentType.objects.get_for_model(self.model).pk
for obj in queryset:
if obj.is_published:
if not obj.has_publish_permission(request.user):
messages.error(
request,
_(
'You do not have permission to publish the '
'%(objtype)s "%(objtitle)s"'
) % {
'objtype': six.text_type(self.model._meta.verbose_name),
'objtitle': six.text_type(obj)
obj.publish()
LogEntry.objects.log_action(user_id=request.user.id, content_type_id=content_type_id,
object_id=obj.pk, object_repr=six.text_type(obj),
action_flag=CHANGE, change_message=_('Published'),)
last_obj_ok = obj
if ok == 1:
messages.success(request, _('The %(objtype)s "%(objtitle)s" has been published') % {
'objtype': self.model._meta.verbose_name,
'objtitle': last_obj_ok, })
else:
messages.success(request, ungettext_lazy(
'%(nb)d %(objtype)s has been published',
'%(nb)d %(objtype)s have been published',
ok) % {'nb': ok,
'objtype': self.model._meta.verbose_name_plural,})
publish.short_description = _('Publish selected %(verbose_name_plural)s')
def unpublish(self, request, queryset):
"""
Marks selected news items as unpublished
"""
ok = 0
content_type_id = ContentType.objects.get_for_model(self.model).pk
for obj in queryset:
if not obj.is_published:
if not obj.has_publish_permission(request.user):
messages.error(
request,
_(
'You do not have permission to unpublish the '
'%(objtype)s "%(objtitle)s"'
) % {
'objtype': six.text_type(self.model._meta.verbose_name),
'objtitle': six.text_type(obj)
obj.unpublish()
LogEntry.objects.log_action(user_id=request.user.id, content_type_id=content_type_id,
object_id=obj.pk, object_repr=six.text_type(obj),
action_flag=CHANGE, change_message=_('Unpublished'),)
last_obj_ok = obj
if ok == 1:
messages.success(request, _('The %(objtype)s "%(objtitle)s" has been unpublished') % {
'objtitle': last_obj_ok, })
else:
messages.success(request, ungettext_lazy(
'%(nb)d %(objtype)s has been unpublished',
'%(nb)d %(objtype)s have been unpublished',
ok) % {'nb': ok,
'objtype': self.model._meta.verbose_name_plural})
unpublish.short_description = _('Archive selected %(verbose_name_plural)s')
def ensure_slug_uniq_queryset(self, request, obj, slug):
y, m, d = (obj.newsbox_publication_start_date.year,
obj.newsbox_publication_start_date.month,
obj.newsbox_publication_start_date.day)
queryset = type(obj).objects.filter(newsbox_publication_start_date__year=y,
newsbox_publication_start_date__month=m,
newsbox_publication_start_date__day=d,
newsbox_slug=slug)
if obj.pk:
queryset = queryset.exclude(pk=obj.pk)
return queryset
def ensure_slug_uniq(self, request, obj):
max_length = 50
slug = obj.newsbox_slug
for x in itertools.count(1):
if not self.ensure_slug_uniq_queryset(request, obj, slug).count():
break
suffix = "-%d" % x
slug = "%s%s" % (obj.newsbox_slug[:max_length-len(suffix)], suffix)
obj.newsbox_slug = slug
def save_model(self, request, obj, form, change):
self.ensure_slug_uniq(request, obj)
return super(NewsboxBaseAdmin, self).save_model(request, obj, form, change)
class NewsboxAdmin(NewsboxBaseAdmin):
pass
class NewsboxExpiredAdmin(NewsboxBaseAdmin):
def newsbox_publication_dates_short(self, obj):
output = []
title = []
css_class = []
title.append(formats.date_format(obj.newsbox_publication_start_date,
'DATETIME_FORMAT'))
output.append('<span class="from">%s</span>' %
formats.date_format(obj.newsbox_publication_start_date,
'SHORT_DATE_FORMAT'))
css_class.append('from')
if not obj.newsbox_publication_end_date:
title.append(_('never'))
else:
title.append(
formats.date_format(obj.newsbox_publication_end_date, 'DATETIME_FORMAT'))
output.append('<span class="to">%s</span>' %
formats.date_format(obj.newsbox_publication_end_date,
'SHORT_DATE_FORMAT'))
css_class.append('to')
css_class = '_'.join(css_class)
title = _('from %(from)s to %(to)s') % {'from': title[0], 'to': title[1]}
output = ('<span> %s </span>' % _('to')).join(output)
return format_html('<abbr class="newsbox_pub_dates %s" title="%s">%s</abbr>' % (
newsbox_publication_dates_short.short_description = _('publication')
def get_fieldsets(self, request, obj=None):
fieldsets = super(NewsboxExpiredAdmin, self).get_fieldsets(request, obj)
for fieldset in fieldsets:
if 'newsbox_publication_end_date' in fieldset[1]['fields']:
return fieldsets
remove_field_from_fieldsets('newsbox_status', fieldsets)
'newsbox_publication_start_date',
'newsbox_publication_end_date', ],
fieldsets,
default_fieldset_name=_('Publication settings'),
default_fieldset_position=1)
return fieldsets
def get_list_display(self, request):
list_display = list(super(NewsboxExpiredAdmin, self).get_list_display(request))
if 'newsbox_publication_dates_short' not in list_display:
try:
index = list_display.index('newsbox_date_short')
list_display[index] = 'newsbox_publication_dates_short'
except ValueError:
list_display.append('newsbox_publication_dates_short')
class NewsboxSEOAdmin(NewsboxBaseAdmin):
def get_fieldsets(self, request, obj=None):
fieldsets = super(NewsboxSEOAdmin, self).get_fieldsets(request, obj)
add_fields_to_fieldset(
['newsbox_indexed',
'newsbox_meta_description',
'newsbox_meta_keywords', ],
fieldsets,
default_fieldset_name=_('SEO Settings'),
default_fieldset_classes=('collapse',),
)
return fieldsets
def get_list_display(self, request):
list_display = super(NewsboxSEOAdmin, self).get_list_display(request)
return list_display