# -*- coding: utf-8 -*- from __future__ import unicode_literals import copy from django.conf.urls import url, patterns 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 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 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, default_fieldset_classes=None, 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) def changestatus_link(obj): if obj.newsbox_published: 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') return '<a href="%s" title="%s"><img src="%s" alt="%s" /></a>' % ( reverse('admin:admin_newsbox_%s_change_status' % ( six.text_type(obj._meta.verbose_name)), args=[obj.pk, ]), title, icon_url, obj.newsbox_published) changestatus_link.allow_tags = True changestatus_link.admin_order_field = 'newsbox_published' changestatus_link.short_description = _('published') class NewsboxBaseAdmin(admin.ModelAdmin): list_filter = ('newsbox_publication_start_date', 'newsbox_published', ) list_display = ['get_newsbox_title', 'newsbox_date', 'get_newsbox_slug', changestatus_link] list_display_links = ('get_newsbox_title',) fieldsets = [ (None, { 'fields': ['newsbox_title', 'newsbox_slug', 'newsbox_date', 'newsbox_published', ], }), (_('Content'), { 'fields': ['newsbox_summary', 'newsbox_body'], }), ] actions = ['publish', 'unpublish'] save_as = True def __init__(self, *args, **kwargs): # This is a workaround for prepopulated_fields with hvad self.prepopulated_fields = {"newsbox_slug": ("newsbox_title",)} super(NewsboxBaseAdmin, self).__init__(*args, **kwargs) 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_newsbox_slug(self, obj): return obj.newsbox_slug get_newsbox_slug.short_description = _('Slug') def get_urls(self): urls = super(NewsboxBaseAdmin, self).get_urls() my_urls = patterns('', url( r'^([0-9]+)/change-status/$', self.admin_site.admin_view(self.change_status), name='admin_newsbox_%s_change_status' % ( six.text_type(self.model._meta.verbose_name),))) return my_urls + urls def change_status(self, request, news_id): """ Switch the status of a news """ news = get_object_or_404(self.model, pk=news_id) if not news.has_publish_permission(request): return HttpResponseForbidden( _('You do not have permission to publish this %s') % (six.text_type(self.model._meta.verbose_name),)) news.newsbox_published = not news.newsbox_published news.save() if news.newsbox_published: messages.info( request, _( 'The %(objtype)s "%(objtitle)s" was ' 'successfully published' ) % { 'objtype': six.text_type(self.model._meta.verbose_name), 'objtitle': news} ) else: messages.info( request, _( 'The %(objtype)s "%(objtitle)s" was ' 'successfully unpublished' ) % { 'objtype': six.text_type(self.model._meta.verbose_name), 'objtitle': news} ) 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(news), action_flag=CHANGE, ) return HttpResponseRedirect('../../') def publish(self, request, queryset): """ Marks selected news items as published """ ok = 0 for news in queryset: if news.newsbox_published: continue if not news.has_publish_permission(request): 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': news } ) continue news.newsbox_published = True news.save() ok += 1 messages.success(request, ungettext_lazy( '%(nb)d %(objtype)s was published', '%(nb)d %(objtype)s were published', ok) % {'nb': ok, 'objtype': self.model._meta.verbose_name}) publish.short_description = _('Publish selected %(verbose_name_plural)s') def unpublish(self, request, queryset): """ Marks selected news items as unpublished """ ok = 0 for news in queryset: if not news.newsbox_published: continue if not news.has_publish_permission(request): 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': news } ) continue news.newsbox_published = False news.save() ok += 1 messages.success(request, ungettext_lazy( '%(nb)d %(objtype)s was unpublished', '%(nb)d %(objtype)s were unpublished', ok) % { 'nb': ok, 'objtype': self.model._meta.verbose_name, } ) unpublish.short_description = _( 'Unpublish selected %(verbose_name_plural)s') class NewsboxAdmin(NewsboxBaseAdmin): pass class NewsboxExpiredAdmin(NewsboxBaseAdmin): def get_fieldsets(self, request, obj=None): fieldsets = super(NewsboxExpiredAdmin, self).get_fieldsets(request, obj) remove_field_from_fieldsets('newsbox_published', fieldsets) add_fields_to_fieldset( ['newsbox_published', 'newsbox_publication_start_date', 'newsbox_publication_end_date', ], fieldsets, default_fieldset_name=_('Publication'), default_fieldset_position=1) return fieldsets def get_list_display(self, request): list_display = super(NewsboxExpiredAdmin, self).get_list_display(request) list_display = list_display[:2] +\ ['newsbox_publication_end_date',] + list_display[2:] return list_display 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