diff --git a/passbook/admin/templates/administration/audit/list.html b/passbook/admin/templates/administration/audit/list.html new file mode 100644 index 000000000..68a3703a8 --- /dev/null +++ b/passbook/admin/templates/administration/audit/list.html @@ -0,0 +1,84 @@ +{% extends "administration/base.html" %} + +{% load i18n %} +{% load utils %} + +{% block title %} +{% title %} +{% endblock %} + +{% block content %} +<div class="container"> + <h1>{% trans "Audit Log" %}</h1> + <div id="pf-list-standard" class="list-group list-view-pf list-view-pf-view"> + {% for entry in object_list %} + <div class="list-group-item"> + <div class="list-view-pf-main-info"> + <div class="list-view-pf-left"> + <span class="fa fa-plane list-view-pf-icon-sm"></span> + </div> + <div class="list-view-pf-body"> + <div class="list-view-pf-description"> + <div class="list-group-item-heading"> + {{ entry.action }} + </div> + <div class="list-group-item-text"> + </div> + </div> + <div class="list-view-pf-additional-info"> + <div class="list-view-pf-additional-info-item"> + <span class="pficon pficon-user"></span> + <strong>{{ entry.user }}</strong> + </div> + <div class="list-view-pf-additional-info-item"> + <span class="pficon pficon-screen"></span> + <strong>{{ entry.request_ip }}</strong> + </div> + <div class="list-view-pf-additional-info-item"> + <span class="pficon pficon-cluster"></span> + <strong>{{ entry.app|default:'-' }}</strong> + </div> + </div> + </div> + </div> + </div> + {% endfor %} + </div> + <script> + $(document).ready(function () { + // Row Checkbox Selection + $("#pf-list-standard input[type='checkbox']").change(function (e) { + if ($(this).is(":checked")) { + $(this).closest('.list-group-item').addClass("active"); + } else { + $(this).closest('.list-group-item').removeClass("active"); + } + }); + // toggle dropdown menu + $('#pf-list-standard .list-view-pf-actions').on('show.bs.dropdown', function () { + var $this = $(this); + var $dropdown = $this.find('.dropdown'); + var space = $(window).height() - $dropdown[0].getBoundingClientRect().top - $this.find('.dropdown-menu').outerHeight(true); + $dropdown.toggleClass('dropup', space < 10); + }); + // allow users to select multiple list items with shift key + $('#pf-list-standard .list-group').on('click', '.list-view-pf-checkbox>input', function (event) { + var $list = $('.list-group'); + var prevIndex = $list.data('preIndex'); + var $listItems = $list.children('.list-group-item'); + var $currentItem = $(this).closest('.list-group-item'); + if (event.shiftKey && prevIndex > -1 && this.checked) { + var currentIndex = $listItems.index($currentItem); + var $selectScope = currentIndex - prevIndex > 0 + ? $currentItem.prevAll().not($listItems.eq(prevIndex).prevAll().addBack()) + : $listItems.eq(prevIndex).prevAll().not($currentItem.prevAll().addBack()); + $selectScope.addClass('active').find('.list-view-pf-checkbox').children('input').prop('checked', true); + } + $list.data('preIndex', this.checked ? $listItems.index($currentItem) : -1); + }); + + }); + </script> + {% include 'partials/pagination.html' %} +</div> +{% endblock %} diff --git a/passbook/admin/templates/administration/base.html b/passbook/admin/templates/administration/base.html index 420dd02f6..60d783f6a 100644 --- a/passbook/admin/templates/administration/base.html +++ b/passbook/admin/templates/administration/base.html @@ -26,6 +26,9 @@ <li> <a href="#">{% trans 'Users' %}</a> </li> + <li class="{% is_active 'passbook_admin:audit-log' %}"> + <a href="{% url 'passbook_admin:audit-log' %}">{% trans 'Audit Log' %}</a> + </li> <li class="{% is_active_app 'admin' %}"> <a href="{% url 'admin:index' %}">{% trans 'Django' %}</a> </li> diff --git a/passbook/admin/urls.py b/passbook/admin/urls.py index 7853ea20b..b34db5b76 100644 --- a/passbook/admin/urls.py +++ b/passbook/admin/urls.py @@ -1,7 +1,7 @@ """passbook URL Configuration""" from django.urls import path -from passbook.admin.views import (applications, invitations, overview, +from passbook.admin.views import (applications, audit, invitations, overview, providers, rules, sources) urlpatterns = [ @@ -40,5 +40,7 @@ urlpatterns = [ invitations.InvitationCreateView.as_view(), name='invitation-create'), path('invitations/<uuid:pk>/delete/', invitations.InvitationDeleteView.as_view(), name='invitation-delete'), + # Audit Log + path('audit/', audit.AuditEntryListView.as_view(), name='audit-log'), # path('api/v1/', include('passbook.admin.api.v1.urls')) ] diff --git a/passbook/admin/views/audit.py b/passbook/admin/views/audit.py new file mode 100644 index 000000000..a7705550b --- /dev/null +++ b/passbook/admin/views/audit.py @@ -0,0 +1,16 @@ +"""passbook AuditEntry administration""" +from django.views.generic import ListView + +from passbook.admin.mixins import AdminRequiredMixin +from passbook.audit.models import AuditEntry + + +class AuditEntryListView(AdminRequiredMixin, ListView): + """Show list of all invitations""" + + model = AuditEntry + template_name = 'administration/audit/list.html' + paginate_by = 10 + + def get_queryset(self): + return AuditEntry.objects.all().order_by('-created') diff --git a/passbook/core/templates/partials/pagination.html b/passbook/core/templates/partials/pagination.html new file mode 100644 index 000000000..9b1209269 --- /dev/null +++ b/passbook/core/templates/partials/pagination.html @@ -0,0 +1,22 @@ +{% load i18n %} + +<div class="btn-group"> + {% with param=get_param|default:'page' %} + {% if page_obj.has_previous %} + <a class="btn btn-default" href="?{{ param }}={{ page_obj.previous_page_number }}"><span class="fa fa-angle-left"></span></a> + {% else %} + <a class="btn btn-default disabled" href=""><span class="fa fa-angle-left"></span></a> + {% endif %} + <span class="btn btn-default"> + {% blocktrans with current=page_obj.number total=page_obj.paginator.num_pages %} + Page {{ current }} of {{ total }} + {% endblocktrans %} + </span> + {% if page_obj.has_next %} + <a class="btn btn-default" href="?{{ param }}={{ page_obj.next_page_number }}"><span class="fa fa-angle-right"></span></a> + {% else %} + <a class="btn btn-default disabled" href=""><span class="fa fa-angle-right"></span></a> + {% endif %} + {% endwith %} +</div> +<hr>