Skip to content
Snippets Groups Projects
admin.py 10.7 KiB
Newer Older
Olivier Le Brouster's avatar
Olivier Le Brouster committed
# -*- 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