diff --git a/easyaudit/admin.py b/easyaudit/admin.py index 7e7764d7..2caaa993 100644 --- a/easyaudit/admin.py +++ b/easyaudit/admin.py @@ -1,31 +1,16 @@ import json from django.contrib import admin from django.core import urlresolvers -from django.contrib.auth import get_user_model from django.utils.safestring import mark_safe -from . import models, settings - - -def get_user_link(user): - """ - Helper to get admin url for given user - """ - if user is None: - return '-' - try: - user_model = get_user_model() - url = urlresolvers.reverse("admin:%s_%s_change" % ( - user_model._meta.app_label, - user_model._meta.model_name, - ), args=(user.id,)) - html = '%s' % (url, str(user)) - except: - html = str(user) - return html +from . import settings +from .models import CRUDEvent +from .models import LoginEvent +from .models import RequestEvent +from .admin_helpers import EasyAuditModelAdmin # CRUD events -class CRUDEventAdmin(admin.ModelAdmin): +class CRUDEventAdmin(EasyAuditModelAdmin): list_display = ['get_event_type_display', 'content_type', 'object_id', 'object_repr_link', 'user_link', 'datetime'] date_hierarchy = 'datetime' list_filter = ['event_type', 'content_type', 'user', 'datetime', ] @@ -34,7 +19,7 @@ class CRUDEventAdmin(admin.ModelAdmin): 'object_json_repr_prettified', 'object_json_repr', 'user', 'user_pk_as_string', 'datetime', ] def object_repr_link(self, obj): - if obj.event_type == models.CRUDEvent.DELETE: + if obj.event_type == CRUDEvent.DELETE: html = obj.object_repr else: try: @@ -48,10 +33,6 @@ def object_repr_link(self, obj): return mark_safe(html) object_repr_link.short_description = 'object repr' - def user_link(self, obj): - return mark_safe(get_user_link(obj.user)) - user_link.short_description = 'user' - def object_json_repr_prettified(self, obj): try: data = json.loads(obj.object_json_repr) @@ -63,38 +44,30 @@ def object_json_repr_prettified(self, obj): if settings.ADMIN_SHOW_MODEL_EVENTS: - admin.site.register(models.CRUDEvent, CRUDEventAdmin) + admin.site.register(CRUDEvent, CRUDEventAdmin) # Login events -class LoginEventAdmin(admin.ModelAdmin): +class LoginEventAdmin(EasyAuditModelAdmin): list_display = ['datetime', 'get_login_type_display', 'user_link', 'username', 'remote_ip'] date_hierarchy = 'datetime' list_filter = ['login_type', 'user', 'datetime', ] search_fields = ['=remote_ip', 'username', ] readonly_fields = ['login_type', 'username', 'user', 'remote_ip', 'datetime', ] - def user_link(self, obj): - return mark_safe(get_user_link(obj.user)) - user_link.short_description = 'user' - if settings.ADMIN_SHOW_AUTH_EVENTS: - admin.site.register(models.LoginEvent, LoginEventAdmin) + admin.site.register(LoginEvent, LoginEventAdmin) # Request events -class RequestEventAdmin(admin.ModelAdmin): +class RequestEventAdmin(EasyAuditModelAdmin): list_display = ['datetime', 'user_link', 'method', 'url', 'remote_ip'] date_hierarchy = 'datetime' list_filter = ['method', 'user', 'datetime', ] search_fields = ['=remote_ip', 'username', 'url', 'query_string', ] readonly_fields = ['url', 'method', 'query_string', 'user', 'remote_ip', 'datetime', ] - def user_link(self, obj): - return mark_safe(get_user_link(obj.user)) - user_link.short_description = 'user' - if settings.ADMIN_SHOW_REQUEST_EVENTS: - admin.site.register(models.RequestEvent, RequestEventAdmin) + admin.site.register(RequestEvent, RequestEventAdmin) diff --git a/easyaudit/admin_helpers.py b/easyaudit/admin_helpers.py new file mode 100644 index 00000000..dff7007f --- /dev/null +++ b/easyaudit/admin_helpers.py @@ -0,0 +1,87 @@ +from django.contrib import admin +from django.core import urlresolvers +from django.core.exceptions import PermissionDenied +from django.contrib.auth import get_user_model +from django.shortcuts import render +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.utils.translation import ugettext_lazy as _ +from django.contrib import messages +from django.conf.urls import url +from django.utils.safestring import mark_safe + + +class EasyAuditModelAdmin(admin.ModelAdmin): + + def user_link(self, obj): + #return mark_safe(get_user_link(obj.user)) + user = obj.user + if user is None: + return '-' + try: + user_model = get_user_model() + url = urlresolvers.reverse("admin:%s_%s_change" % ( + user_model._meta.app_label, + user_model._meta.model_name, + ), args=(user.id,)) + html = '%s' % (url, str(user)) + except: + html = str(user) + return mark_safe(html) + user_link.short_description = 'user' + + def has_add_permission(self, request, obj=None): + return False + + def get_urls(self): + info = self.model._meta.app_label, self.model._meta.model_name + urls = super(EasyAuditModelAdmin, self).get_urls() + my_urls = [ + url(r'^purge/$', self.admin_site.admin_view(self.purge), {}, name="%s_%s_purge" % info), + ] + return my_urls + urls + + def purge(self, request): + return self.purge_objects(request) + + # Helper view to remove all rows in a table + def purge_objects(self, request): + """ + Removes all objects in this table. + This action first displays a confirmation page; + next, it deletes all objects and redirects back to the change list. + """ + modeladmin = self + opts = modeladmin.model._meta + + # Check that the user has delete permission for the actual model + if not request.user.is_superuser: + raise PermissionDenied + if not modeladmin.has_delete_permission(request): + raise PermissionDenied + + # If the user has already confirmed or cancelled the deletion, + # (eventually) do the deletion and return to the change list view again. + if request.method == 'POST': + if 'btn-confirm' in request.POST: + try: + modeladmin.model.objects.all().delete() + modeladmin.message_user(request, _("Successfully removed all objects"), messages.SUCCESS); + except Exception as e: + modeladmin.message_user(request, _(u'ERROR') + ': %r' % e, messages.ERROR) + else: + modeladmin.message_user(request, _("Action cancelled by user"), messages.SUCCESS); + return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name))) + + context = { + "title": _("Purge all %s ... are you sure?") % opts.verbose_name_plural, + "opts": opts, + "app_label": opts.app_label, + } + + # Display the confirmation page + return render( + request, + 'admin/easyaudit/purge_confirmation.html', + context + ) diff --git a/easyaudit/templates/admin/easyaudit/change_list.html b/easyaudit/templates/admin/easyaudit/change_list.html new file mode 100644 index 00000000..4b95da42 --- /dev/null +++ b/easyaudit/templates/admin/easyaudit/change_list.html @@ -0,0 +1,15 @@ +{% extends "admin/change_list.html" %} +{% load i18n %} + +{% block object-tools-items %} + {{ block.super }} + {% if request.user.is_superuser %} +
  • + {% with purge_url='admin:'|add:cl.opts.app_label|add:'_'|add:cl.opts.model_name|add:'_purge' %} + + {% blocktrans with cl.opts.verbose_name_plural as name %}Purge {{ name }}{% endblocktrans %} + + {% endwith %} +
  • + {% endif %} +{% endblock %} diff --git a/easyaudit/templates/admin/easyaudit/purge_confirmation.html b/easyaudit/templates/admin/easyaudit/purge_confirmation.html new file mode 100644 index 00000000..74a64e05 --- /dev/null +++ b/easyaudit/templates/admin/easyaudit/purge_confirmation.html @@ -0,0 +1,31 @@ +{% extends "admin/base_site.html" %} +{% load i18n admin_urls static admin_list %} + + +{% block breadcrumbs %} + +{% endblock %} + + +{% block content %} + +
    {% csrf_token %} +
    +

    {% trans 'Please confirm deletion' %}.

    +

    {% blocktrans %}This operation is destructive, cannot be undone and may require some minutes.{% endblocktrans %}

    +

    {% blocktrans %}Are you sure you want to permanently remove all objects ?{% endblocktrans %}

    +
    + +
    + + +
    +
    +
    + +{% endblock %}